Refactored for pypi

This commit is contained in:
Richard Mwewa
2022-10-08 10:44:14 +02:00
parent 2bad245ae7
commit 751f4bba62
11 changed files with 174 additions and 274 deletions

129
.gitignore vendored
View File

@@ -1,129 +0,0 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

View File

@@ -1,62 +1,70 @@
# Facebook-Downloader
A program for downloading Facebook videos
A program for downloading Facebook videos, given a video url
# Installation
**1. Clone the project**
**Install from PyPI**
```
git clone https://github.com/rly0nheart/Facebook-Downloader.git
pip install facebook-downloader
```
**2. Move to Facebook-Downloader directory**
### Note
> In order to run the program, You will need to have the FireFox browser installed on your pc
> The program is dependent on selenium, so in order to run it, you will have to download and properly setup geckodriver (setup instructions available below)
>>
# Geckodriver setup
## Linux
**1. Go to the geckodriver [releases page](https://github.com/mozilla/geckodriver/releases/). Find the latest version of the driver for your platform and download it**
**2. Extract the downloaded file**
```
cd Facebook-Downloader
tar -xvzf geckodriver*
```
**3. Install dependencies**
## Note
> *This will install tqdm, selenium, and requests*
> > *You will need to have Firefox installed to run the program*
> > > *For user convenience, the program will come with a geckodriver.exe binary*
**3. Make it executable**
```
pip install -r requirements.txt
chmod +x geckodriver
```
**4. Add geckodriver to your system path**
```
export PATH=$PATH:/path/to/downloaded/geckodriver
```
### Note
> If you encounter issues with the above commands, then you should run them as root (with sudo)
## Windows
**1. Go to the geckodriver [releases page](https://github.com/mozilla/geckodriver/releases/). Find the geckodriver.exe binary for your platform and download it**
**2. Move the downloaded executable to** *C:\Users\yourusername\AppData\Local\Programs\Python\Python310*
### Note
> The numbers on the directory 'Python310' will depend on the version of Python you have
## Mac OS
* [Set up Selenium & GeckoDriver (Mac)](https://medium.com/dropout-analytics/selenium-and-geckodriver-on-mac-b411dbfe61bc)
# Usage
```
python downloader.py <facebook-url>
facebook_downloader <video-url>
```
> *Alternatively, you could grant execution permission to the downloader and run it as shown below*
**1. Grant execution permission**
```
chmod +x downloader.py
```
**2. Run downloader**
```
./downloader.py <facebook-url>
```
## Example
```
python downloader.py https://www.facebook.com/PageName/videos/VideoID
```
## Note
> Upon run, the downloader will first check for updates. If found, users will be prompted to download the updates
### Note
> Upon run, the program will first check for updates. If found, users will be notified about the update
# Optional Arguments
| Flag | Description |
|---------|:-----------:|
| *-A/--audio* | download audio only (coming soon) |
| *-o/--output* | output filename |
| *-v/--version* | show program's version number and exit |
| *-a/--audio* | download file as audio |
| *-o/--output* | output file name |
# Donations
If you would like to donate, you could Buy A Coffee for the developer using the button below
<a href="https://www.buymeacoffee.com/189381184" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>
Your support will be much appreciated!
Your support will be much appreciated!

View File

@@ -1,100 +0,0 @@
import time
import logging
import argparse
import requests
from tqdm import tqdm
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
option = webdriver.FirefoxOptions()
option.add_argument('--headless')
driver = webdriver.Firefox(options=option)
program_version_number = "2022.1.0.0"
downloading_url = "https://getfvid.com"
update_check_endpoint = "https://api.github.com/repos/rly0nheart/facebook-downloader/releases/latest"
def notice():
notice_msg = f"""
facebook-downloader {program_version_number} Copyright (C) 2022 Richard Mwewa
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
"""
print(notice_msg)
def check_and_get_updates():
notice()
response = requests.get(update_check_endpoint).json()
if response['tag_name'] == program_version_number:
"""Ignore if the program is up to date"""
pass
else:
update_prompt = input(f"[?] A new release is available ({response['tag_name']}). Would you like to install it? (y/n) ")
if update_prompt.lower() == "y":
files_to_update = ['downloader.py', 'geckodriver.exe', 'README.md', 'requirements.txt']
for file in tqdm(files_to_update, desc=f'Updating'):
data = requests.get(f'https://raw.githubusercontent.com/rly0nheart/facebook-downloader/master/{file}')
with open(file, "wb") as f:
f.write(data.content)
f.close()
print("Updated: Re-run program.")
else:
pass
def download_video(url, output):
driver.get(downloading_url) # Opening getfvid.com, a website that downloads facebook videos
url_entry_field = driver.find_element(By.NAME, "url") # Find the url entry field
url_entry_field.send_keys(url) # write facebook url in the entry field
url_entry_field.send_keys(Keys.ENTER) # press enter
print('Please standby (20 seconds)...')
time.sleep(20) # Sleep for at least 20 seconds to wait for the next page to load
driver.refresh
"""
HD: "/html/body/div[2]/div/div/div[1]/div/div[2]/div/div[3]/p[1]/a"
SD: "/html/body/div[2]/div/div/div[1]/div/div[2]/div/div[3]/p[2]/a"
Audio: "/html/body/div[2]/div/div/div[1]/div/div[2]/div/div[3]/p[3]/a"
"""
download_btn = WebDriverWait(driver, 20).until(expected_conditions.presence_of_element_located((By.XPATH, '/html/body/div[2]/div/div/div[1]/div/div[2]/div/div[3]/p[1]/a'))) # Find the download button (this clicks the first button which returns a video in hd)
download_url = download_btn.get_attribute('href')
with requests.get(download_url, stream=True) as response:
response.raise_for_status()
with open(f'downloads/{output}.mp4', 'wb') as file:
for chunk in tqdm(response.iter_content(chunk_size=8192), desc=f'Downloading: {output}.mp4'):
file.write(chunk)
print(f'Downloaded: {file.name}')
driver.close()
parser = argparse.ArgumentParser(description='facebook-downloader — by Richard Mwewa')
parser.add_argument('url', help='facebook video url (eg. https://www.facebook.com/PageName/videos/VideoID')
parser.add_argument('-A', '--audio', help=argparse.SUPPRESS, action='store_true')
parser.add_argument('-o', '--output', help='output filename')
parser.add_argument('-v', '--version', version='2022.1.0.0', action='version')
args = parser.parse_args()
url = args.url
output = args.output
if __name__ == "__main__":
try:
check_and_get_updates()
download_video(url, output)
except KeyboardInterrupt:
print('Process interrupted with Ctrl+C.')
except Exception as e:
print('An error occured:', e)

View File

@@ -1 +0,0 @@

View File

View File

@@ -0,0 +1,88 @@
import os
import argparse
import requests
from tqdm import tqdm
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
class FacebookDownloader:
def __init__(self):
parser = argparse.ArgumentParser(description='facebook-downloader — by Richard Mwewa')
parser.add_argument('url', help='facebook video url (eg. https://www.facebook.com/PageName/videos/VideoID')
parser.add_argument('-a', '--audio', help='download file as audio', action='store_true')
parser.add_argument('-o', '--output', help='output filename')
self.args = parser.parse_args()
option = webdriver.FirefoxOptions()
option.add_argument('--headless')
self.driver = webdriver.Firefox(options=option)
self.program_version_number = "2022.1.0.0"
self.downloading_url = "https://getfvid.com"
self.update_check_endpoint = "https://api.github.com/repos/rly0nheart/facebook-downloader/releases/latest"
def notice(self):
notice_msg = f"""
facebook-downloader {self.program_version_number} Copyright (C) 2022 Richard Mwewa
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
"""
print(notice_msg)
def check_updates(self):
self.notice()
response = requests.get(self.update_check_endpoint).json()
if response['tag_name'] == self.program_version_number:
"""Ignore if the program is up to date"""
pass
else:
print(f"[!] A new release is available ({response['tag_name']}). Run 'pip install --upgrade facebook-downloader' to get the updates.")
def download_type(self):
if self.args.audio:
download_type_element = "/html/body/div[2]/div/div/div[1]/div/div[2]/div/div[3]/p[3]/a"
else:
download_type_element = "/html/body/div[2]/div/div/div[1]/div/div[2]/div/div[3]/p[1]/a"
return download_type_element
def path_finder(self):
directory_list = [os.path.join('downloads', 'videos'), os.path.join('downloads', 'audio')]
for directory in directory_list:
os.makedirs(directory, exist_ok=True)
def download_video(self):
self.path_finder()
self.check_updates()
self.driver.get(self.downloading_url) # Opening getfvid.com, a website that downloads facebook videos
url_entry_field = self.driver.find_element(By.NAME, "url") # Find the url entry field
url_entry_field.send_keys(self.args.url) # write facebook url in the entry field
url_entry_field.send_keys(Keys.ENTER) # press enter
print('Please standby (20 seconds)...')
self.driver.refresh
"""
HD: "/html/body/div[2]/div/div/div[1]/div/div[2]/div/div[3]/p[1]/a"
SD: "/html/body/div[2]/div/div/div[1]/div/div[2]/div/div[3]/p[2]/a"
Audio: "/html/body/div[2]/div/div/div[1]/div/div[2]/div/div[3]/p[3]/a"
"""
download_btn = WebDriverWait(self.driver, 20).until(expected_conditions.presence_of_element_located((By.XPATH, self.download_type()))) # Find the download button (this clicks the first button which returns a video in hd)
download_url = download_btn.get_attribute('href')
with requests.get(download_url, stream=True) as response:
response.raise_for_status()
with open(os.path.join('downloads', 'videos', f'{self.args.output}.mp4'), 'wb') as file:
for chunk in tqdm(response.iter_content(chunk_size=8192), desc=f'Downloading: {self.args.output}.mp4'):
file.write(chunk)
print(f'Downloaded: {file.name}')
self.driver.close()

View File

@@ -0,0 +1,12 @@
from facebook_downloader.downloader import FacebookDownloader
def main():
try:
start = FacebookDownloader()
start.download_video()
except KeyboardInterrupt:
print('Process interrupted with Ctrl+C.')
except Exception as e:
print('An error occured:', e)

Binary file not shown.

View File

@@ -1,3 +0,0 @@
tqdm
selenium
requests

31
setup.py Normal file
View File

@@ -0,0 +1,31 @@
import setuptools
with open('README.md', 'r', encoding='utf-8') as file:
long_description = file.read()
setuptools.setup(
name='facebook-downloader',
version='2022.1.0.0',
author='Richard Mwewa',
author_email='rly0nheart@duck.com',
packages=['facebook_downloader'],
description='Facebook video downloader',
long_description=long_description,
long_description_content_type='text/markdown',
url='https://github.com/rly0nheart/facebook-downloader',
license='GNU General Public License v3 (GPLv3)',
install_requires=['requests', 'selenium', 'tqdm'],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Information Technology',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Operating System :: OS Independent',
'Natural Language :: English',
'Programming Language :: Python :: 3'
],
entry_points={
'console_scripts': [
'facebook_downloader=facebook_downloader.main:main',
]
},
)

View File

@@ -1,6 +0,0 @@
from downloader import download_video
def test_download_video():
# I find this video very interesting, enjoy! ;)
url = 'https://www.facebook.com/VICE/videos/663211078474482'
download_video(url, output='test_video_making-a-weed-smoothie')