feat: add download_playlists.py for downloading playlists/videos with yt-dlp
This commit is contained in:
@@ -48,6 +48,13 @@ jobs:
|
|||||||
for file in $files; do
|
for file in $files; do
|
||||||
echo "Testing execution of $file..."
|
echo "Testing execution of $file..."
|
||||||
|
|
||||||
|
# Compile-only: do not execute this script in CI smoke tests
|
||||||
|
if [ "$file" = "download_playlists.py" ]; then
|
||||||
|
echo "Skipping execution for $file; running compile-only check"
|
||||||
|
python -m py_compile "$file"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
# Special-case: run `batch.py` and watch its output for the marker
|
# Special-case: run `batch.py` and watch its output for the marker
|
||||||
if [ "$file" = "batch.py" ]; then
|
if [ "$file" = "batch.py" ]; then
|
||||||
tmp=$(mktemp)
|
tmp=$(mktemp)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Lightweight helpers for using `yt-dlp` to download media from Patreon posts you
|
|||||||
## Requirements
|
## Requirements
|
||||||
- Python 3.8+ and `pip`.
|
- Python 3.8+ and `pip`.
|
||||||
- `yt-dlp` installed and available on PATH (or configure via environment variables).
|
- `yt-dlp` installed and available on PATH (or configure via environment variables).
|
||||||
|
- `ffmpeg` installed and available on PATH (required by `yt-dlp` for merge/remux operations).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
1. Clone the repository:
|
1. Clone the repository:
|
||||||
|
|||||||
104
download_playlists.py
Normal file
104
download_playlists.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import argparse
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_FORMAT = (
|
||||||
|
"bestvideo[height=1080][ext=mp4]+bestaudio[ext=m4a]/"
|
||||||
|
"bestvideo[height=1080]+bestaudio"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Download a playlist/video with yt-dlp using configurable options."
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"url",
|
||||||
|
help="Playlist or video URL to download.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--yt-dlp",
|
||||||
|
dest="ytdlp",
|
||||||
|
default="yt-dlp",
|
||||||
|
help="Path to yt-dlp executable (default: yt-dlp from PATH).",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--format",
|
||||||
|
default=DEFAULT_FORMAT,
|
||||||
|
help="yt-dlp format selector.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--output",
|
||||||
|
default="tip2tip/%(title)s/%(title)s.%(ext)s",
|
||||||
|
help="Output template path used by yt-dlp.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--merge-output-format",
|
||||||
|
default="mp4",
|
||||||
|
help="Container to merge media into (default: mp4).",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-embed-thumbnail",
|
||||||
|
action="store_true",
|
||||||
|
help="Disable embedding thumbnail in output media.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-embed-metadata",
|
||||||
|
action="store_true",
|
||||||
|
help="Disable embedding metadata in output media.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-write-thumbnail",
|
||||||
|
action="store_true",
|
||||||
|
help="Disable writing thumbnail sidecar file.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--print-cmd",
|
||||||
|
action="store_true",
|
||||||
|
help="Print the final yt-dlp command before running.",
|
||||||
|
)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def build_command(args: argparse.Namespace) -> list[str]:
|
||||||
|
cmd = [
|
||||||
|
args.ytdlp,
|
||||||
|
"-f",
|
||||||
|
args.format,
|
||||||
|
"--merge-output-format",
|
||||||
|
args.merge_output_format,
|
||||||
|
"-o",
|
||||||
|
args.output,
|
||||||
|
]
|
||||||
|
|
||||||
|
if not args.no_embed_thumbnail:
|
||||||
|
cmd.append("--embed-thumbnail")
|
||||||
|
if not args.no_embed_metadata:
|
||||||
|
cmd.append("--embed-metadata")
|
||||||
|
if not args.no_write_thumbnail:
|
||||||
|
cmd.append("--write-thumbnail")
|
||||||
|
|
||||||
|
cmd.append(args.url)
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
args = parse_args()
|
||||||
|
cmd = build_command(args)
|
||||||
|
|
||||||
|
print(f"Downloading with output template: {args.output}")
|
||||||
|
if args.print_cmd:
|
||||||
|
print("Command:", " ".join(cmd))
|
||||||
|
|
||||||
|
result = subprocess.run(cmd, check=False)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f"\n[!] yt-dlp exited with code {result.returncode}")
|
||||||
|
return result.returncode
|
||||||
|
|
||||||
|
print("\n[+] All done!")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
Reference in New Issue
Block a user