├── .gitignore ├── LICENSE ├── README.md ├── facebook-dl.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.mp4 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Siddharth Dushantha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # facebook-dl 2 |

3 | Very minimal Facebook downloader written in 28 lines of Python code (not including comments and blank spaces) 4 |

5 | 6 |

7 | 8 |

9 | 10 | [![Support me!](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/XoJfSVI) 11 | 12 | ## Installation 13 | 14 | ```bash 15 | # clone the repo 16 | $ git clone https://github.com/sdushantha/facebook-dl.git 17 | 18 | # install the requirements 19 | $ pip3 install -r requirements.txt 20 | ``` 21 | 22 | ## Usage 23 | ``` 24 | usage: facebook-dl.py [-h] url [resolution] 25 | ``` 26 | 27 | --- 28 | Download video in High Definition. 29 | ```bash 30 | $ python3 facebook-dl.py https://www.facebook.com/McLaren.Racing/videos/10155088130291413 hd 31 | ``` 32 | OR 33 | ```bash 34 | # Without mentioning the resolution will also download in HD 35 | $ python3 facebook-dl.py https://www.facebook.com/McLaren.Racing/videos/10155088130291413 36 | ``` 37 | Download video in Standard Definition. 38 | ```bash 39 | $ python3 facebook-dl.py https://www.facebook.com/McLaren.Racing/videos/10155088130291413 sd 40 | ``` 41 | 42 | ## License 43 | MIT License 44 | 45 | Copyright (c) 2018 Siddharth Dushantha 46 | -------------------------------------------------------------------------------- /facebook-dl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # pylint: disable=missing-docstring,trailing-whitespace,invalid-name 4 | # 5 | # By Siddharth Dushantha (sdushantha) 2020 6 | # 7 | # Notice: If you are on Windows, the output of this script might 8 | # look a little messy and that is because command prompt 9 | # does not support escape sequences. 10 | # 11 | 12 | import re 13 | import sys 14 | import argparse 15 | import requests 16 | 17 | # This magic spell lets me erase the current line. 18 | # I can use this to show for example "Downloading..." 19 | # and then "Downloaded" on the line where 20 | # "Downloading..." was. 21 | ERASE_LINE = '\e[2K' 22 | 23 | def main(): 24 | parser = argparse.ArgumentParser(description="Download videos from facebook from your terminal") 25 | 26 | parser.add_argument('url', action="store") 27 | parser.add_argument('resolution', action="store", nargs="?") 28 | 29 | args = parser.parse_args() 30 | 31 | print("Fetching source code...", end="\r", flush=True) 32 | request = requests.get(args.url) 33 | print(ERASE_LINE, end="\r", flush=True) 34 | 35 | print("\033[92m✔\033[0m Fetched source code") 36 | 37 | # Create the file name by extracting the video ID from html and then add 38 | # "hd" or "sd" depending on the quality of the resolution that is being downloaded. 39 | # 40 | # To decide whether to use "hd or "sd" we are using an if-then-else 41 | # one-liner statement. It might look a little confusing at first, but it 42 | # makes a lot of sense once you get an understanding of it. 43 | # Read this if you are a little confused: https://stackoverflow.com/a/2802748/9215267 44 | file_name = str(re.findall(r"videos\/(.+?)\"", request.text)[-1].replace("/", "")) + f"_{'sd' if args.resolution == 'sd' else 'hd'}.mp4" 45 | 46 | print("Downloading video...", end="\r", flush=True) 47 | 48 | try: 49 | request = requests.get(re.findall(f"{'sd_src' if args.resolution == 'sd' else 'hd_src'}:\"(.+?)\"", request.text)[0]) 50 | except IndexError: 51 | print(ERASE_LINE, end="\r", flush=True) 52 | print("\e[91m✘\e[0m Video could not be downloaded") 53 | sys.exit() 54 | 55 | # Write the content to the file 56 | with open(file_name, "wb") as f: 57 | f.write(request.content) 58 | 59 | print(ERASE_LINE, end="\r", flush=True) 60 | 61 | print(f"\033[92m✔\033[0m Video downloaded: {file_name}") 62 | 63 | if __name__ == "__main__": 64 | main() 65 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | --------------------------------------------------------------------------------