Extract file naming

This commit is contained in:
Ivan Habunek 2024-08-28 10:32:40 +02:00
parent 91e0447681
commit 29d3f7fec2
No known key found for this signature in database
GPG Key ID: 01DB3DD0D824504C
4 changed files with 78 additions and 66 deletions

View File

@ -8,6 +8,7 @@ import click
from twitchdl import __version__ from twitchdl import __version__
from twitchdl.entities import DownloadOptions from twitchdl.entities import DownloadOptions
from twitchdl.naming import DEFAULT_OUTPUT_TEMPLATE
from twitchdl.twitch import ClipsPeriod, VideosSort, VideosType from twitchdl.twitch import ClipsPeriod, VideosSort, VideosType
# Tweak the Click context # Tweak the Click context
@ -229,7 +230,7 @@ def clips(
"-o", "-o",
"--output", "--output",
help="Output file name template. See docs for details.", help="Output file name template. See docs for details.",
default="{date}_{id}_{channel_login}_{title_slug}.{format}", default=DEFAULT_OUTPUT_TEMPLATE,
) )
@click.option( @click.option(
"-q", "-q",

View File

@ -7,7 +7,7 @@ import subprocess
import tempfile import tempfile
from os import path from os import path
from pathlib import Path from pathlib import Path
from typing import Dict, List, Optional from typing import List, Optional
from urllib.parse import urlencode, urlparse from urllib.parse import urlencode, urlparse
import click import click
@ -18,6 +18,7 @@ from twitchdl.download import download_file
from twitchdl.entities import DownloadOptions from twitchdl.entities import DownloadOptions
from twitchdl.exceptions import ConsoleError from twitchdl.exceptions import ConsoleError
from twitchdl.http import download_all from twitchdl.http import download_all
from twitchdl.naming import clip_filename, video_filename
from twitchdl.output import blue, bold, green, print_log, yellow from twitchdl.output import blue, bold, green, print_log, yellow
from twitchdl.playlists import ( from twitchdl.playlists import (
enumerate_vods, enumerate_vods,
@ -26,7 +27,7 @@ from twitchdl.playlists import (
parse_playlists, parse_playlists,
select_playlist, select_playlist,
) )
from twitchdl.twitch import Chapter, Clip, ClipAccessToken, Video from twitchdl.twitch import Chapter, ClipAccessToken, Video
def download(ids: List[str], args: DownloadOptions): def download(ids: List[str], args: DownloadOptions):
@ -93,65 +94,6 @@ def _concat_vods(vod_paths: List[str], target: str):
raise ConsoleError(f"Joining files failed: {result.stderr}") raise ConsoleError(f"Joining files failed: {result.stderr}")
def get_video_placeholders(video: Video, format: str) -> Dict[str, str]:
date, time = video["publishedAt"].split("T")
game = video["game"]["name"] if video["game"] else "Unknown"
return {
"channel": video["creator"]["displayName"],
"channel_login": video["creator"]["login"],
"date": date,
"datetime": video["publishedAt"],
"format": format,
"game": game,
"game_slug": utils.slugify(game),
"id": video["id"],
"time": time,
"title": utils.titlify(video["title"]),
"title_slug": utils.slugify(video["title"]),
}
def _video_target_filename(video: Video, args: DownloadOptions):
subs = get_video_placeholders(video, args.format)
try:
return args.output.format(**subs)
except KeyError as e:
supported = ", ".join(subs.keys())
raise ConsoleError(f"Invalid key {e} used in --output. Supported keys are: {supported}")
def _clip_target_filename(clip: Clip, args: DownloadOptions):
date, time = clip["createdAt"].split("T")
game = clip["game"]["name"] if clip["game"] else "Unknown"
url = clip["videoQualities"][0]["sourceURL"]
_, ext = path.splitext(url)
ext = ext.lstrip(".")
subs = {
"channel": clip["broadcaster"]["displayName"],
"channel_login": clip["broadcaster"]["login"],
"date": date,
"datetime": clip["createdAt"],
"format": ext,
"game": game,
"game_slug": utils.slugify(game),
"id": clip["id"],
"slug": clip["slug"],
"time": time,
"title": utils.titlify(clip["title"]),
"title_slug": utils.slugify(clip["title"]),
}
try:
return args.output.format(**subs)
except KeyError as e:
supported = ", ".join(subs.keys())
raise ConsoleError(f"Invalid key {e} used in --output. Supported keys are: {supported}")
def _crete_temp_dir(base_uri: str) -> str: def _crete_temp_dir(base_uri: str) -> str:
"""Create a temp dir to store downloads if it doesn't exist.""" """Create a temp dir to store downloads if it doesn't exist."""
path = urlparse(base_uri).path.lstrip("/") path = urlparse(base_uri).path.lstrip("/")
@ -220,7 +162,7 @@ def _download_clip(slug: str, args: DownloadOptions) -> None:
duration = utils.format_duration(clip["durationSeconds"]) duration = utils.format_duration(clip["durationSeconds"])
click.echo(f"Found: {green(title)} by {yellow(user)}, playing {blue(game)} ({duration})") click.echo(f"Found: {green(title)} by {yellow(user)}, playing {blue(game)} ({duration})")
target = _clip_target_filename(clip, args) target = clip_filename(clip, args.output)
click.echo(f"Target: {blue(target)}") click.echo(f"Target: {blue(target)}")
if not args.overwrite and path.exists(target): if not args.overwrite and path.exists(target):
@ -252,7 +194,7 @@ def _download_video(video_id: str, args: DownloadOptions) -> None:
click.echo(f"Found: {blue(video['title'])} by {yellow(video['creator']['displayName'])}") click.echo(f"Found: {blue(video['title'])} by {yellow(video['creator']['displayName'])}")
target = _video_target_filename(video, args) target = video_filename(video, args.format, args.output)
click.echo(f"Output: {blue(target)}") click.echo(f"Output: {blue(target)}")
if not args.overwrite and path.exists(target): if not args.overwrite and path.exists(target):

View File

@ -4,8 +4,8 @@ import click
import m3u8 import m3u8
from twitchdl import twitch, utils from twitchdl import twitch, utils
from twitchdl.commands.download import get_video_placeholders
from twitchdl.exceptions import ConsoleError from twitchdl.exceptions import ConsoleError
from twitchdl.naming import video_placeholders
from twitchdl.output import bold, print_clip, print_json, print_log, print_table, print_video from twitchdl.output import bold, print_clip, print_json, print_log, print_table, print_video
from twitchdl.playlists import parse_playlists from twitchdl.playlists import parse_playlists
from twitchdl.twitch import Chapter, Clip, Video from twitchdl.twitch import Chapter, Clip, Video
@ -67,7 +67,7 @@ def video_info(video: Video, playlists: str, chapters: List[Chapter]):
duration = utils.format_time(chapter["durationMilliseconds"] // 1000) duration = utils.format_time(chapter["durationMilliseconds"] // 1000)
click.echo(f'{start} {bold(chapter["description"])} ({duration})') click.echo(f'{start} {bold(chapter["description"])} ({duration})')
placeholders = get_video_placeholders(video, format="mkv") placeholders = video_placeholders(video, format="mkv")
placeholders = [[f"{{{k}}}", v] for k, v in placeholders.items()] placeholders = [[f"{{{k}}}", v] for k, v in placeholders.items()]
click.echo("") click.echo("")
print_table(["Placeholder", "Value"], placeholders) print_table(["Placeholder", "Value"], placeholders)

69
twitchdl/naming.py Normal file
View File

@ -0,0 +1,69 @@
import os
from typing import Dict
from twitchdl import utils
from twitchdl.entities import Clip, Video
from twitchdl.exceptions import ConsoleError
DEFAULT_OUTPUT_TEMPLATE = "{date}_{id}_{channel_login}_{title_slug}.{format}"
def video_filename(video: Video, format: str, output: str) -> str:
subs = video_placeholders(video, format)
return _format(output, subs)
def video_placeholders(video: Video, format: str) -> Dict[str, str]:
date, time = video["publishedAt"].split("T")
game = video["game"]["name"] if video["game"] else "Unknown"
return {
"channel": video["creator"]["displayName"],
"channel_login": video["creator"]["login"],
"date": date,
"datetime": video["publishedAt"],
"format": format,
"game": game,
"game_slug": utils.slugify(game),
"id": video["id"],
"time": time,
"title": utils.titlify(video["title"]),
"title_slug": utils.slugify(video["title"]),
}
def clip_filename(clip: Clip, output: str):
subs = clip_placeholders(clip)
return _format(output, subs)
def clip_placeholders(clip: Clip) -> Dict[str, str]:
date, time = clip["createdAt"].split("T")
game = clip["game"]["name"] if clip["game"] else "Unknown"
url = clip["videoQualities"][0]["sourceURL"]
_, ext = os.path.splitext(url)
ext = ext.lstrip(".")
return {
"channel": clip["broadcaster"]["displayName"],
"channel_login": clip["broadcaster"]["login"],
"date": date,
"datetime": clip["createdAt"],
"format": ext,
"game": game,
"game_slug": utils.slugify(game),
"id": clip["id"],
"slug": clip["slug"],
"time": time,
"title": utils.titlify(clip["title"]),
"title_slug": utils.slugify(clip["title"]),
}
def _format(output: str, subs: Dict[str, str]) -> str:
try:
return output.format(**subs)
except KeyError as e:
supported = ", ".join(subs.keys())
raise ConsoleError(f"Invalid key {e} used in --output. Supported keys are: {supported}")