Skip to content

Commit

Permalink
- rewrite of the CLI
Browse files Browse the repository at this point in the history
- removed click dependency
- updated docs for CLI (kinda)
- fixed #67 (hopefully)
  • Loading branch information
EchterAlsFake committed Nov 14, 2024
1 parent 41b2871 commit 3739c0b
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 61 deletions.
29 changes: 10 additions & 19 deletions docs/source/guides/cli-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,26 @@ CLI Usage

PHUB comes with a built-in CLI for downloading videos.

It uses the `click`_ dependency.

.. _click: https://pypi.org/project/click/

.. code-block:: bash
$ phub
.. code-block:: bash
Usage: phub [OPTIONS] INPUT
Usage: phub [OPTIONS]
Options:
--output TEXT Output file or directory
--quality TEXT Video quality
--downloader TEXT Video downloader (default, FFMPEG or threaded)
--help Show this message and exit.
Input
can be a video URL or a file containing multiple URLs.

Output
Output video file or directory. If you are downloading multiple
videos at once, make sure it's a directory.
-output TEXT Output file or directory
-quality TEXT Video quality
-downloader TEXT Video downloader (default, ffmpeg or threaded)
-url TEXT Video URL
-model TEXT Model URL
-file TEXT Path to a file containing URLs of Video (separated with new lines)
-video_limit Number Limits how many videos of a model will be downloaded (default: all)
--help Show this message and exit.
Quality
The desired video quality. Usually 'best', 'half' or 'worst'.
If an integer is specified, the nearest quality to that number
will be picked.
The desired video quality. Choose between 'best', 'half' or 'worst'.

Downloader
The backend used to download the video. Possible values:
Expand Down
4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "phub"
version = "4.7.2"
version = "4.7.3"
description = "An API for Pornhub"
authors = [
{name = 'Egsagon', email = "[email protected]"},
Expand All @@ -16,8 +16,6 @@ classifiers = [
dependencies = ["httpx[brotli,socks]", "ffmpeg-progress-yield"]
requires-python = ">=3.9"

[project.optional-dependencies]
cli = ["click"]

[project.scripts]
phub = "phub.__main__:main"
Expand Down
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
httpx[brotli,socks]>=0.27.0
click>=8.0.4
ffmpeg-progress-yield>=0.7.8
136 changes: 98 additions & 38 deletions src/phub/__main__.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,110 @@
'''
"""
PHUB built-in CLI.
'''
"""

import os
import phub
import argparse

from phub import Client, Video
from phub.modules.download import threaded, FFMPEG, default

try:
import click

except (ModuleNotFoundError, ImportError):
print("The CLI needs 'click' in order to work. Please do: 'pip install click'")
exit()
def text_progress_bar(downloaded, total, title=False):
"""Thanks, ChatGPT, I still suck at math <3"""
bar_length = 50
filled_length = int(round(bar_length * downloaded / float(total)))
percents = round(100.0 * downloaded / float(total), 1)
bar = '#' * filled_length + '-' * (bar_length - filled_length)
if title is False:
print(f"\r[{bar}] {percents}%", end='')

else:
print(f"\r | {title} | -->: [{bar}] {percents}%", end='')


@click.command()
@click.argument('input')
@click.option('--output', help = 'Output file or directory', default = './')
@click.option('--quality', help = 'Video quality', default = 'best')
@click.option('--downloader', help = 'Video downloader (default, FFMPEG or threaded)', default = 'FFMPEG')
def main(input: str, output: str, quality: str, downloader: str) -> None:

downloader = getattr(phub.download, downloader.strip())

if os.path.isfile(input):
with open(input, encoding = 'utf-8') as file:
urls = phub.consts.re.get_urls(file.read())
def download_video(client: Client, url: [str, Video], output: str, quality: str, downloader: str):
if not isinstance(url, Video):
video = client.get(url)


elif isinstance(url, Video):
video = url

else:
urls = [input]

if len(urls) > 1 and os.path.isfile(output):
raise Exception('Must specify directory when downloading multiple videos.')

client = phub.Client(delay = .02)

for url in urls:
raise "Some error happened here, please report on GitHub, thank you :) "

title = video.title
final_output_path = os.path.join(output, title + ".mp4")

print(f"Downloading: {title} to: {final_output_path}")
video.download(path=final_output_path, quality=quality, downloader=downloader, display=text_progress_bar)
print(f"Successfully downloaded: {title}")

def resolve_threading_mode(mode, workers=10, timeout=10):
"""Resolve the appropriate threading mode based on input."""
return {
"threaded": threaded(max_workers=workers, timeout=timeout),
"ffmpeg": FFMPEG,
"default": default
}.get(mode, default)


def main():
parser = argparse.ArgumentParser(description="PHUB built-in CLI")
group = parser.add_mutually_exclusive_group(required=True) # Makes sure only URL, or model, or a file can be given as an input
group.add_argument("-url", type=str, help="a PornHub Video URL", default="")
group.add_argument("-model", type=str, help="a Pornhub Model URL", default="")
parser.add_argument("-video_limit", type=int, help="the maximum number of videos to download from a model (Default: all)", default=100000)
group.add_argument("-file", type=str, help="List to a file with Video URLs (separated by new lines)", default="")
parser.add_argument("-downloader", type=str, help="The threading (download backend) to use", choices=[
"threaded", "default", "ffmpeg"], default="threaded")

parser.add_argument("-quality", type=str, help="The video quality", choices=["best", "half", "worst"],
default="best")

parser.add_argument("-output", type=str, help="The output path", default="./")

args = parser.parse_args()
quality = args.quality
output = args.output
downloader = resolve_threading_mode(mode=args.downloader)
url = args.url
model = args.model
video_limit = args.video_limit
file = args.file

client = Client()

if len(url) >= 3: # Comparison with not == "" doesn't work, don't ask me why I have no fucking idea...
download_video(client=client, url=url, output=output, quality=quality, downloader=downloader)

elif len(model) >= 3:
model_videos = client.get_user(model).videos
idx = 0

for video in model_videos:
if idx >= video_limit:
break

download_video(client=client, url=video, output=output, quality=quality, downloader=downloader)
idx += 1

elif len(file) >= 1:
try:
video = client.get(url.strip())
video.download(
path = output,
quality = quality,
downloader = downloader,
display = phub.display.bar(f'Downloading {video.key}')
)

except Exception as err:
print(f'\x1b[91mError: {err}\x1b[0m')
with open(file, "r") as f:
urls = f.read().splitlines()

except PermissionError:
raise "You do not have the necessary permissions to read the file!"

except FileNotFoundError:
raise f"The file does not exist at your given location: {file}"


for idx, url in enumerate(urls, start=1):
print(f"[{idx}|{len(urls)}] Downloading: {url}")
download_video(client=client, url=url, output=output, quality=quality, downloader=downloader)


if __name__ == '__main__':
main()
Expand Down

0 comments on commit 3739c0b

Please sign in to comment.