From 19892acde9af66d8e467bc65a84f97c80326cead Mon Sep 17 00:00:00 2001 From: Ivan Habunek Date: Wed, 24 Apr 2024 07:55:43 +0200 Subject: [PATCH] Add testing on github --- .github/workflows/test.yml | 30 ++++++ pyproject.toml | 5 + twitchdl/commands/info.py | 9 +- twitchdl/playlists.py | 6 +- video_before.json | 203 +++++++++++++++++++++++++++++++++++++ 5 files changed, 248 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 video_before.json diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..9f8351e --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,30 @@ +name: Run tests + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-22.04 + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e ".[test]" + - name: Run tests + run: | + pytest + - name: Validate minimum required version + run: | + vermin --no-tips . twitchdl + - name: Check style + run: | + flake8 diff --git a/pyproject.toml b/pyproject.toml index b186a85..f866263 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,11 @@ dev = [ "vermin", ] +test = [ + "pytest", + "vermin", +] + [project.urls] "Homepage" = "https://twitch-dl.bezdomni.net/" "Source" = "https://github.com/ihabunek/twitch-dl" diff --git a/twitchdl/commands/info.py b/twitchdl/commands/info.py index 9b44cf7..f4f3a15 100644 --- a/twitchdl/commands/info.py +++ b/twitchdl/commands/info.py @@ -7,6 +7,7 @@ from twitchdl.commands.download import get_video_placeholders from twitchdl.exceptions import ConsoleError from twitchdl.output import bold, print_clip, print_json, print_log, print_table, print_video +from twitchdl.playlists import parse_playlists from twitchdl.twitch import Chapter, Clip, Video @@ -50,13 +51,13 @@ def info(id: str, *, json: bool = False): raise ConsoleError(f"Invalid input: {id}") -def video_info(video: Video, playlists, chapters: List[Chapter]): +def video_info(video: Video, playlists: str, chapters: List[Chapter]): click.echo() print_video(video) click.echo("Playlists:") - for p in m3u8.loads(playlists).playlists: - click.echo(f"{bold(p.stream_info.video)} {p.uri}") + for p in parse_playlists(playlists): + click.echo(f"{bold(p.name)} {p.url}") if chapters: click.echo() @@ -72,7 +73,7 @@ def video_info(video: Video, playlists, chapters: List[Chapter]): print_table(["Placeholder", "Value"], placeholders) -def video_json(video, playlists, chapters): +def video_json(video: Video, playlists: str, chapters: List[Chapter]): playlists = m3u8.loads(playlists).playlists video["playlists"] = [ diff --git a/twitchdl/playlists.py b/twitchdl/playlists.py index 84b3a44..f83c3bf 100644 --- a/twitchdl/playlists.py +++ b/twitchdl/playlists.py @@ -29,11 +29,15 @@ class Vod: """Segment duration in seconds""" -def parse_playlists(playlists_m3u8: str): +def parse_playlists(playlists_m3u8: str) -> List[Playlist]: def _parse(source: str) -> Generator[Playlist, None, None]: document = load_m3u8(source) for p in document.playlists: + from pprint import pp + + pp(p.__dict__) + pp(p.stream_info.__dict__) if p.stream_info.resolution: name = p.media[0].name resolution = "x".join(str(r) for r in p.stream_info.resolution) diff --git a/video_before.json b/video_before.json new file mode 100644 index 0000000..45c4a99 --- /dev/null +++ b/video_before.json @@ -0,0 +1,203 @@ +{ + "id": "2115833882", + "title": "Games I Feel Like Speedrun Marathon !newyt !Slender !Merch", + "description": null, + "publishedAt": "2024-04-10T05:01:12Z", + "broadcastType": "ARCHIVE", + "lengthSeconds": 30163, + "game": { + "id": "21063", + "name": "Saw" + }, + "creator": { + "login": "ecdycis", + "displayName": "Ecdycis" + }, + "playlists": [ + { + "bandwidth": 6395968, + "resolution": [ + 1920, + 1080 + ], + "codecs": "avc1.64002A,mp4a.40.2", + "video": "chunked", + "uri": "https://d2nvs31859zcd8.cloudfront.net/3104d817048588f268fa_ecdycis_43996750059_1712725267/chunked/index-muted-GKGIUOE29B.m3u8" + }, + { + "bandwidth": 3430341, + "resolution": [ + 1280, + 720 + ], + "codecs": "avc1.4D0020,mp4a.40.2", + "video": "720p60", + "uri": "https://d2nvs31859zcd8.cloudfront.net/3104d817048588f268fa_ecdycis_43996750059_1712725267/720p60/index-muted-GKGIUOE29B.m3u8" + }, + { + "bandwidth": 1448243, + "resolution": [ + 852, + 480 + ], + "codecs": "avc1.4D001F,mp4a.40.2", + "video": "480p30", + "uri": "https://d2nvs31859zcd8.cloudfront.net/3104d817048588f268fa_ecdycis_43996750059_1712725267/480p30/index-muted-GKGIUOE29B.m3u8" + }, + { + "bandwidth": 215544, + "resolution": null, + "codecs": "mp4a.40.2", + "video": "audio_only", + "uri": "https://d2nvs31859zcd8.cloudfront.net/3104d817048588f268fa_ecdycis_43996750059_1712725267/audio_only/index-muted-GKGIUOE29B.m3u8" + }, + { + "bandwidth": 709051, + "resolution": [ + 640, + 360 + ], + "codecs": "avc1.4D001E,mp4a.40.2", + "video": "360p30", + "uri": "https://d2nvs31859zcd8.cloudfront.net/3104d817048588f268fa_ecdycis_43996750059_1712725267/360p30/index-muted-GKGIUOE29B.m3u8" + }, + { + "bandwidth": 288844, + "resolution": [ + 284, + 160 + ], + "codecs": "avc1.4D000C,mp4a.40.2", + "video": "160p30", + "uri": "https://d2nvs31859zcd8.cloudfront.net/3104d817048588f268fa_ecdycis_43996750059_1712725267/160p30/index-muted-GKGIUOE29B.m3u8" + } + ], + "chapters": [ + { + "id": "6049e803f47a0b9cf64ce95adcf3d96d", + "durationMilliseconds": 4891000, + "positionMilliseconds": 0, + "type": "GAME_CHANGE", + "description": "Saw", + "subDescription": "", + "thumbnailURL": "", + "video": { + "id": "2115833882", + "lengthSeconds": 30163, + "__typename": "Video" + }, + "__typename": "VideoMoment", + "game": { + "id": "21063", + "displayName": "Saw", + "boxArtURL": "https://static-cdn.jtvnw.net/ttv-boxart/21063_IGDB-40x53.jpg", + "__typename": "Game" + } + }, + { + "id": "c3be4ce5a7bae802d7a6df02baf62a85", + "durationMilliseconds": 6235000, + "positionMilliseconds": 4891000, + "type": "GAME_CHANGE", + "description": "Resident Evil 7: Biohazard", + "subDescription": "", + "thumbnailURL": "", + "video": { + "id": "2115833882", + "lengthSeconds": 30163, + "__typename": "Video" + }, + "__typename": "VideoMoment", + "game": { + "id": "492934", + "displayName": "Resident Evil 7: Biohazard", + "boxArtURL": "https://static-cdn.jtvnw.net/ttv-boxart/492934_IGDB-40x53.jpg", + "__typename": "Game" + } + }, + { + "id": "bd584f17bc1f91fc11ed14dcec5e4742", + "durationMilliseconds": 3401000, + "positionMilliseconds": 11126000, + "type": "GAME_CHANGE", + "description": "Silent Hill: Homecoming", + "subDescription": "", + "thumbnailURL": "", + "video": { + "id": "2115833882", + "lengthSeconds": 30163, + "__typename": "Video" + }, + "__typename": "VideoMoment", + "game": { + "id": "18864", + "displayName": "Silent Hill: Homecoming", + "boxArtURL": "https://static-cdn.jtvnw.net/ttv-boxart/18864_IGDB-40x53.jpg", + "__typename": "Game" + } + }, + { + "id": "9f4be8bc7b5bf398213bc602a4b39c4d", + "durationMilliseconds": 3490000, + "positionMilliseconds": 14527000, + "type": "GAME_CHANGE", + "description": "Silent Hill 2", + "subDescription": "", + "thumbnailURL": "", + "video": { + "id": "2115833882", + "lengthSeconds": 30163, + "__typename": "Video" + }, + "__typename": "VideoMoment", + "game": { + "id": "9891", + "displayName": "Silent Hill 2", + "boxArtURL": "https://static-cdn.jtvnw.net/ttv-boxart/9891_IGDB-40x53.jpg", + "__typename": "Game" + } + }, + { + "id": "7a42d537681decc10660c33f9071a37f", + "durationMilliseconds": 7241000, + "positionMilliseconds": 18017000, + "type": "GAME_CHANGE", + "description": "The Darkness", + "subDescription": "", + "thumbnailURL": "", + "video": { + "id": "2115833882", + "lengthSeconds": 30163, + "__typename": "Video" + }, + "__typename": "VideoMoment", + "game": { + "id": "8448", + "displayName": "The Darkness", + "boxArtURL": "https://static-cdn.jtvnw.net/ttv-boxart/8448_IGDB-40x53.jpg", + "__typename": "Game" + } + }, + { + "id": "64418186f436d80b1359d2e6686222ef", + "durationMilliseconds": 4905000, + "positionMilliseconds": 25258000, + "type": "GAME_CHANGE", + "description": "Silent Hill 4: The Room", + "subDescription": "", + "thumbnailURL": "", + "video": { + "id": "2115833882", + "lengthSeconds": 30163, + "__typename": "Video" + }, + "__typename": "VideoMoment", + "game": { + "id": "5804", + "displayName": "Silent Hill 4: The Room", + "boxArtURL": "https://static-cdn.jtvnw.net/ttv-boxart/5804_IGDB-40x53.jpg", + "__typename": "Game" + } + } + ] +}