From be69e79b28569db9b75c42171d7fad665e9fb112 Mon Sep 17 00:00:00 2001 From: Ivan Habunek Date: Wed, 3 Apr 2024 08:52:51 +0200 Subject: [PATCH] Add Chapter typed dict --- twitchdl/commands/download.py | 6 +++--- twitchdl/twitch.py | 23 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/twitchdl/commands/download.py b/twitchdl/commands/download.py index 94dd6d7..b61152c 100644 --- a/twitchdl/commands/download.py +++ b/twitchdl/commands/download.py @@ -20,7 +20,7 @@ from twitchdl.entities import DownloadOptions from twitchdl.exceptions import ConsoleError from twitchdl.http import download_all from twitchdl.output import blue, bold, dim, green, print_log, yellow -from twitchdl.twitch import Clip, Video +from twitchdl.twitch import Chapter, Clip, Video def download(ids: list[str], args: DownloadOptions): @@ -375,7 +375,7 @@ def _download_video(video_id, args: DownloadOptions) -> None: click.echo(f"\nDownloaded: {green(target)}") -def _determine_time_range(video_id, args: DownloadOptions): +def _determine_time_range(video_id: str, args: DownloadOptions): if args.start or args.end: return args.start, args.end @@ -402,7 +402,7 @@ def _determine_time_range(video_id, args: DownloadOptions): return None, None -def _choose_chapter_interactive(chapters): +def _choose_chapter_interactive(chapters: list[Chapter]): click.echo("\nChapters:") for index, chapter in enumerate(chapters): duration = utils.format_time(chapter["durationMilliseconds"] // 1000) diff --git a/twitchdl/twitch.py b/twitchdl/twitch.py index 21e5206..0107c21 100644 --- a/twitchdl/twitch.py +++ b/twitchdl/twitch.py @@ -62,6 +62,17 @@ class Video(TypedDict): creator: User +class Chapter(TypedDict): + id: str + durationMilliseconds: int + positionMilliseconds: int + type: str + description: str + subDescription: str + thumbnailURL: str + game: Game + + class GQLError(click.ClickException): def __init__(self, errors: list[str]): message = "GraphQL query failed." @@ -71,7 +82,7 @@ class GQLError(click.ClickException): def authenticated_post(url, data=None, json=None, headers={}): - headers['Client-ID'] = CLIENT_ID + headers["Client-ID"] = CLIENT_ID response = httpx.post(url, data=data, json=json, headers=headers) if response.status_code == 400: @@ -400,7 +411,7 @@ def get_playlists(video_id: str, access_token: AccessToken): "player": "twitchweb", }) response.raise_for_status() - return response.content.decode('utf-8') + return response.content.decode("utf-8") def get_game_id(name: str): @@ -418,7 +429,7 @@ def get_game_id(name: str): return game["id"] -def get_video_chapters(video_id: str): +def get_video_chapters(video_id: str) -> list[Chapter]: query = { "operationName": "VideoPlayer_ChapterSelectButtonVideo", "variables": @@ -440,8 +451,10 @@ def get_video_chapters(video_id: str): return list(_chapter_nodes(response["data"]["video"]["moments"])) -def _chapter_nodes(collection): - for edge in collection["edges"]: +def _chapter_nodes(moments: Data) -> Generator[Chapter, None, None]: + for edge in moments["edges"]: node = edge["node"] + node["game"] = node["details"]["game"] + del node["details"] del node["moments"] yield node