├── .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 | [](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 |
--------------------------------------------------------------------------------