├── LICENSE ├── README.md └── redgifs.py /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2021-present boobfuck 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > # Checkout this [redgifs](https://github.com/scrazzz/redgifs) library, it has even more features and is up-to-date. 2 | 3 | ## redgifs-dl 4 | A command line tool to download videos from redgifs.com 5 | 6 | # Installation 7 | 8 | ```shell 9 | git clone https://github.com/boobfuck/redgifs-dl/blob/main/redgifs.py 10 | chmod +x redgifs.py 11 | ./redgifs 12 | ``` 13 | ```console 14 | usage: redgifs.py [-h] [-f] [-q | -w | -ns] 15 | [url] 16 | 17 | Download videos from redgifs.com 18 | Version: 1.2.0 19 | 20 | positional arguments: 21 | url The gif URL. If you want 22 | to use [--file] flag then 23 | this is can be omitted. 24 | 25 | optional arguments: 26 | -h, --help show this help message and 27 | exit 28 | -f , --file File path of the URLs to 29 | download. A file need to 30 | be passed when using this 31 | flag. 32 | -q, --quite No verbose outputs. 33 | -w, --wait Wait for some seconds 34 | between each request 35 | (while using -f). Default: 36 | 6.9 37 | -ns, --no-save Don't save the video, just 38 | return the MP4 URL. 39 | ``` 40 | 41 | ## Quick tutorial 42 | 43 | To download a single video using its URL. 44 | ```console 45 | $ ./redgifs.py [url] 46 | ``` 47 | 48 | Example: 49 | ```console 50 | $ ./redgifs.py https://redgifs.com/TheFooBars 51 | ``` 52 | 53 | ### `--file ` 54 | 55 | To download multiple videos, the URLs should be added to a file. 56 | 57 | ----- 58 | - File: `urls.txt` 59 | ``` 60 | https://redgifs.com/TheFooBars 61 | https://www.redgifs.com/PythonGoodJavaBad 62 | ... 63 | ``` 64 | ----- 65 | 66 | Then use the `--file` flag and specify the file. 67 | 68 | Example: 69 | ```console 70 | $ ./redgifs.py --file urls.txt 71 | ``` 72 | 73 | ### `--wait ` 74 | By default, the script waits for 6.9 seconds between each request to the URLs when using `--file`. If you want to change this, use this flag. 75 | 76 | Example: 77 | ```console 78 | $ # to wait for 4.20 seconds between each requests 79 | $ ./redgifs.py --file urls.txt --wait 4.20 80 | ``` 81 | 82 | ### `--no-save` 83 | When `--no-save` flag is used it returns the MP4 URL of the video/videos instead of downloading it. 84 | 85 | ### `--quite` 86 | Using this flag does not show verbose outputs. 87 | -------------------------------------------------------------------------------- /redgifs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | The MIT License (MIT) 5 | Copyright (c) 2021-present boobfuck 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | import re 27 | import sys 28 | import time 29 | import argparse 30 | import textwrap 31 | from urllib.parse import urlparse, urlencode 32 | from urllib.request import Request, urlopen 33 | 34 | __version__ = '1.2.0' 35 | 36 | parser = argparse.ArgumentParser( 37 | formatter_class=argparse.RawDescriptionHelpFormatter, 38 | description='Download videos from redgifs.com\nVersion: {}'.format(__version__)) 39 | parser.add_argument( 40 | 'url', 41 | default=None, 42 | nargs='?', 43 | help='The gif URL. If you want to use [--file] flag then this is can be omitted.') 44 | parser.add_argument( 45 | '-f', '--file', 46 | metavar='', 47 | help='File path of the URLs to download. A file need to be passed when using this flag.') 48 | group = parser.add_mutually_exclusive_group() 49 | group.add_argument( 50 | '-q', '--quite', 51 | action='store_true', 52 | help='No verbose outputs.') 53 | group.add_argument( 54 | '-w', '--wait', 55 | type=int, 56 | default=6.9, 57 | metavar='', 58 | help='Wait for some seconds between each request (while using -f). Default: 6.9') 59 | group.add_argument( 60 | '-ns', '--no-save', 61 | action='store_true', 62 | help='Don\'t save the video, just return the MP4 URL.') 63 | args = parser.parse_args() 64 | 65 | # for verbose printing 66 | vprint = print if not args.quite else lambda *a, **k: None 67 | 68 | def check_url(url): 69 | o = urlparse(url) 70 | if o.scheme not in ['http', 'https']: 71 | return TypeError('URL must be of scheme HTTP or HTTPS') 72 | 73 | if 'redgifs' not in o.netloc: 74 | return TypeError('Invalid URL: %s', o.geturl()) 75 | 76 | return o.geturl() 77 | 78 | def get_content(url, no_save): 79 | """Steps in-order. 80 | 81 | * check url 82 | * request html 83 | * get content 84 | """ 85 | url = check_url(url) 86 | headers = {'User-Agent': 'Mozilla/5.0'} 87 | request_url = Request(url, headers=headers) 88 | CONTENT_RE = re.compile(r'https:\/\/[a-z0-9]+.redgifs.com\/\w+.mp4') 89 | 90 | vprint('\n[v] Sending request to', url) 91 | with urlopen(request_url) as response: 92 | 93 | vprint('[v] Reading and Decoding HTML') 94 | html = response.read().decode('utf-8') 95 | 96 | content = re.search(CONTENT_RE, html).group(0) 97 | vprint('[v] Got video data') 98 | 99 | if no_save: 100 | return content 101 | 102 | req = Request(content, headers=headers) 103 | filename = content.split('/')[::-1][0] 104 | with urlopen(req) as downloaded: 105 | vprint('[v] Downloading file..') 106 | with open(filename, 'wb') as f: 107 | f.write(downloaded.read()) 108 | vprint('[*] Downloaded:', filename) 109 | 110 | def get_from_file(file, wait, no_save): 111 | """Steps in-order 112 | 113 | * opens file 114 | * get urls from file 115 | * get_content from urls 116 | """ 117 | with open(file) as f: 118 | urls = [line.strip('\n') for line in f] 119 | 120 | contents = [] 121 | for url in urls: 122 | content = get_content(url, no_save) 123 | contents.append(content) 124 | time.sleep(wait) 125 | 126 | return contents 127 | 128 | if __name__ == '__main__': 129 | try: 130 | if args.url is not None: 131 | mp4 = get_content(args.url, args.no_save) 132 | if args.no_save: 133 | print(mp4) 134 | 135 | if args.url is None: 136 | if args.file: 137 | mp4s = get_from_file(args.file, args.wait, args.no_save) 138 | 139 | if args.no_save: 140 | print('\n' + '\n'.join([mp4 for mp4 in mp4s])) 141 | else: 142 | print('\nDownload complete.') 143 | else: 144 | parser.print_help(sys.stderr) 145 | exit(1) 146 | 147 | except KeyboardInterrupt: 148 | print('\n[!] Keyboard Interrupt\n') 149 | --------------------------------------------------------------------------------