yt-dlp: print the absolute path, not the relative path
- ID
96e65c9- date
2025-10-05 07:06:26+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
5ad14de- message
yt-dlp: print the absolute path, not the relative path- changed files
4 files, 86 additions, 14 deletions
Changed files
dev_requirements.in (26) → dev_requirements.in (33)
diff --git a/dev_requirements.in b/dev_requirements.in
index 1d7e062..368464a 100644
--- a/dev_requirements.in
+++ b/dev_requirements.in
@@ -1,3 +1,4 @@
-r requirements.txt
+pytest
ruff
dev_requirements.txt (761) → dev_requirements.txt (940)
diff --git a/dev_requirements.txt b/dev_requirements.txt
index 2c8efa7..6f2f120 100644
--- a/dev_requirements.txt
+++ b/dev_requirements.txt
@@ -14,10 +14,20 @@ idna==3.10
# via
# -r requirements.txt
# requests
+iniconfig==2.1.0
+ # via pytest
mutagen==1.47.0
# via -r requirements.txt
+packaging==25.0
+ # via pytest
+pluggy==1.6.0
+ # via pytest
pycryptodomex==3.23.0
# via -r requirements.txt
+pygments==2.19.2
+ # via pytest
+pytest==8.4.2
+ # via -r dev_requirements.in
requests==2.32.5
# via -r requirements.txt
ruff==0.13.3
tests/test_yt-dlp_alexwlchan.py (0) → tests/test_yt-dlp_alexwlchan.py (667)
diff --git a/tests/test_yt-dlp_alexwlchan.py b/tests/test_yt-dlp_alexwlchan.py
new file mode 100644
index 0000000..1e516a0
--- /dev/null
+++ b/tests/test_yt-dlp_alexwlchan.py
@@ -0,0 +1,25 @@
+import json
+import os
+import subprocess
+
+
+def test_public_domain_video() -> None:
+ """
+ Download a public domain video and check we get the expected output.
+ """
+ output = subprocess.check_output(
+ [
+ "python3",
+ "yt-dlp_alexwlchan.py",
+ "https://www.youtube.com/watch?v=TUQaGhPdlxs",
+ ]
+ )
+ video_info = json.loads(output)
+
+ assert (
+ video_info["title"]
+ == '"new york city, manhattan, people" - Free Public Domain Video'
+ )
+ assert os.path.exists(video_info["video_path"])
+ assert os.path.exists(video_info["thumbnail_path"])
+ assert video_info["subtitle_path"] is None
yt-dlp_alexwlchan.py (2772) → yt-dlp_alexwlchan.py (3497)
diff --git a/yt-dlp_alexwlchan.py b/yt-dlp_alexwlchan.py
index f9284f4..5a7b173 100755
--- a/yt-dlp_alexwlchan.py
+++ b/yt-dlp_alexwlchan.py
@@ -1,9 +1,10 @@
#!/usr/bin/env python3
import json
-import os
+from pathlib import Path
import sys
import tempfile
+from typing import TypedDict
from yt_dlp import YoutubeDL
@@ -61,25 +62,35 @@ def get_avatar_url(channel_url: str) -> str:
return best_thumbnail["url"]
-if __name__ == "__main__":
- try:
- url = sys.argv[1]
- except IndexError:
- sys.exit(f"Usage: {__file__} URL")
+class ChannelInfo(TypedDict):
+ id: str
+ name: str
+ url: str
+ avatar_url: str
+
- tmp_dir = tempfile.mkdtemp()
+class VideoInfo(TypedDict):
+ url: str
+ title: str
+ description: str
+ video_path: Path
+ thumbnail_path: Path
+ subtitle_path: Path
+ channel: ChannelInfo
- os.chdir(tmp_dir)
+
+def download_video(url: str) -> VideoInfo:
+ tmp_dir = Path(tempfile.mkdtemp())
+
+ ydl_opts["outtmpl"] = str(tmp_dir / "%(title)s.%(ext)s")
with YoutubeDL(ydl_opts) as ydl:
video_info = ydl.extract_info(url)
- downloaded_files = os.listdir(tmp_dir)
-
- video_path = next(p for p in downloaded_files if p.endswith(".mp4"))
- thumbnail_path = next(p for p in downloaded_files if p.endswith(".jpg"))
+ video_path = next(p for p in tmp_dir.iterdir() if p.suffix == ".mp4")
+ thumbnail_path = next(p for p in tmp_dir.iterdir() if p.suffix == ".jpg")
try:
- subtitle_path = next(p for p in downloaded_files if p.endswith(".vtt"))
+ subtitle_path = next(p for p in tmp_dir.iterdir() if p.suffix == ".vtt")
except StopIteration:
subtitle_path = None
@@ -100,4 +111,29 @@ if __name__ == "__main__":
"channel": channel,
}
- print(json.dumps(result, indent=2))
+ return result
+
+
+class PathEncoder(json.JSONEncoder):
+ """
+ Custom JSON encoder that encodes paths as a string.
+ """
+
+ def default(self, o):
+ if isinstance(o, Path):
+ return str(o.absolute())
+ else:
+ return super().default(o)
+
+
+if __name__ == "__main__":
+ try:
+ url = sys.argv[1]
+ except IndexError:
+ sys.exit(f"Usage: {__file__} URL")
+
+ video_info = download_video(url)
+
+ json_string = json.dumps(video_info, indent=2, cls=PathEncoder)
+
+ print(json_string)