From 7006ce3dc752cc23b801f6920a455fcddc0d2ca4 Mon Sep 17 00:00:00 2001 From: jbannon Date: Sun, 3 Jul 2022 06:30:26 +0000 Subject: [PATCH] tests updated with new class --- src/ytdl_sub/downloaders/downloader.py | 4 +- .../downloaders/youtube/merge_playlist.py | 24 +-- .../downloaders/youtube/split_video.py | 36 +++-- src/ytdl_sub/subscriptions/subscription.py | 4 +- src/ytdl_sub/utils/chapters.py | 50 +++++- src/ytdl_sub/utils/file_handler.py | 8 +- tests/e2e/expected_download.py | 47 ++++-- .../soundcloud/test_soundcloud_discography.py | 45 +++--- .../youtube/test_channel_as_kodi_tv_show.py | 149 +++++++++--------- tests/e2e/youtube/test_merge_playlist.py | 20 +-- .../test_playlist_as_kodi_music_videos.py | 41 ++--- tests/e2e/youtube/test_split_video.py | 45 +++--- 12 files changed, 273 insertions(+), 200 deletions(-) diff --git a/src/ytdl_sub/downloaders/downloader.py b/src/ytdl_sub/downloaders/downloader.py index d44a9d62..a2743121 100644 --- a/src/ytdl_sub/downloaders/downloader.py +++ b/src/ytdl_sub/downloaders/downloader.py @@ -8,6 +8,7 @@ from typing import Dict from typing import Generic from typing import List from typing import Optional +from typing import Tuple from typing import Type from typing import TypeVar @@ -18,6 +19,7 @@ from yt_dlp.utils import RejectedVideoReached from ytdl_sub.config.preset_options import Overrides from ytdl_sub.entries.base_entry import BaseEntry from ytdl_sub.entries.entry import Entry +from ytdl_sub.utils.file_handler import FileMetadata from ytdl_sub.utils.logger import Logger from ytdl_sub.validators.strict_dict_validator import StrictDictValidator from ytdl_sub.ytdl_additions.enhanced_download_archive import DownloadArchiver @@ -197,7 +199,7 @@ class Downloader(DownloadArchiver, Generic[DownloaderOptionsT, DownloaderEntryT] return self._get_entry_dicts_from_info_json_files() @abc.abstractmethod - def download(self) -> List[DownloaderEntryT]: + def download(self) -> List[DownloaderEntryT] | List[Tuple[DownloaderEntryT, FileMetadata]]: """The function to perform the download of all media entries""" def post_download(self, overrides: Overrides): diff --git a/src/ytdl_sub/downloaders/youtube/merge_playlist.py b/src/ytdl_sub/downloaders/youtube/merge_playlist.py index ff43ef9f..9aec32bd 100644 --- a/src/ytdl_sub/downloaders/youtube/merge_playlist.py +++ b/src/ytdl_sub/downloaders/youtube/merge_playlist.py @@ -1,6 +1,7 @@ from typing import Dict from typing import List from typing import Optional +from typing import Tuple from ytdl_sub.downloaders.youtube.abc import YoutubeDownloader from ytdl_sub.downloaders.youtube.playlist import YoutubePlaylistDownloaderOptions @@ -8,6 +9,7 @@ from ytdl_sub.entries.youtube import YoutubeVideo from ytdl_sub.utils.chapters import Chapters from ytdl_sub.utils.chapters import Timestamp from ytdl_sub.utils.ffmpeg import add_ffmpeg_metadata +from ytdl_sub.utils.file_handler import FileMetadata from ytdl_sub.validators.validators import BoolValidator @@ -100,7 +102,7 @@ class YoutubeMergePlaylistDownloader( }, ) - def _add_chapters(self, merged_video: YoutubeVideo) -> None: + def _get_chapters(self, merged_video: YoutubeVideo, add_chapters: bool) -> FileMetadata: titles: List[str] = [] timestamps: List[Timestamp] = [] @@ -111,14 +113,17 @@ class YoutubeMergePlaylistDownloader( current_timestamp_sec += video_entry["duration"] - # TODO: return chapter metadata here - if not self.is_dry_run: + chapters = Chapters(timestamps=timestamps, titles=titles) + + if not self.is_dry_run and add_chapters: add_ffmpeg_metadata( file_path=merged_video.get_download_file_path(), - chapters=Chapters(timestamps=timestamps, titles=titles), + chapters=chapters, file_duration_sec=merged_video.kwargs("duration"), ) + return chapters.to_file_metadata(title="Timestamps of playlist videos in the merged file:") + def _to_merged_video(self, entry_dict: Dict) -> YoutubeVideo: """ Adds a few entries not included in a playlist entry to make it look like a merged video @@ -138,13 +143,12 @@ class YoutubeMergePlaylistDownloader( ) return YoutubeVideo(entry_dict=entry_dict, working_directory=self.working_directory) - def download(self) -> List[YoutubeVideo]: + def download(self) -> List[Tuple[YoutubeVideo, FileMetadata]]: """Download a single Youtube video, then split it into multiple videos""" merged_video = self._to_merged_video( entry_dict=self.extract_info(url=self.download_options.playlist_url) ) - - if self.download_options.add_chapters: - self._add_chapters(merged_video=merged_video) - - return [merged_video] + merged_video_metadata = self._get_chapters( + merged_video=merged_video, add_chapters=self.download_options.add_chapters + ) + return [(merged_video, merged_video_metadata)] diff --git a/src/ytdl_sub/downloaders/youtube/split_video.py b/src/ytdl_sub/downloaders/youtube/split_video.py index 45bd4511..5a2e545d 100644 --- a/src/ytdl_sub/downloaders/youtube/split_video.py +++ b/src/ytdl_sub/downloaders/youtube/split_video.py @@ -3,6 +3,7 @@ import re from pathlib import Path from typing import Dict from typing import List +from typing import Tuple from ytdl_sub.downloaders.youtube.abc import YoutubeDownloader from ytdl_sub.downloaders.youtube.video import YoutubeVideoDownloaderOptions @@ -19,6 +20,7 @@ from ytdl_sub.utils.ffmpeg import FFMPEG # 01:00:00 title # where capture group 1 and 2 are the timestamp and title, respectively from ytdl_sub.utils.file_handler import FileHandler +from ytdl_sub.utils.file_handler import FileMetadata from ytdl_sub.utils.thumbnail import convert_download_thumbnail from ytdl_sub.validators.validators import StringValidator @@ -32,8 +34,8 @@ def _split_video_uid(source_uid: str, idx: int) -> str: def _split_video_ffmpeg_cmd( input_file: str, output_file: str, timestamps: List[Timestamp], idx: int ) -> List[str]: - timestamp_begin = timestamps[idx].timestamp_str - timestamp_end = timestamps[idx + 1].timestamp_str if idx + 1 < len(timestamps) else "" + timestamp_begin = timestamps[idx].standardized_str + timestamp_end = timestamps[idx + 1].standardized_str if idx + 1 < len(timestamps) else "" cmd = ["-i", input_file, "-ss", timestamp_begin] if timestamp_end: @@ -121,15 +123,15 @@ class YoutubeSplitVideoDownloader( ) def _create_split_video_entry( - self, source_entry_dict: Dict, title: str, idx: int, split_video_count: int - ) -> YoutubePlaylistVideo: + self, source_entry_dict: Dict, title: str, idx: int, chapters: Chapters + ) -> Tuple[YoutubePlaylistVideo, FileMetadata]: """ Runs ffmpeg to create the split video """ entry_dict = copy.deepcopy(source_entry_dict) entry_dict["title"] = title entry_dict["playlist_index"] = idx + 1 - entry_dict["playlist_count"] = split_video_count + entry_dict["playlist_count"] = len(chapters.timestamps) entry_dict["id"] = _split_video_uid(source_uid=entry_dict["id"], idx=idx) # Remove track and artist since its now split @@ -138,11 +140,20 @@ class YoutubeSplitVideoDownloader( if "artist" in entry_dict: del entry_dict["artist"] - return YoutubePlaylistVideo(entry_dict=entry_dict, working_directory=self.working_directory) + timestamp_begin = chapters.timestamps[idx].readable_str + timestamp_end = Timestamp(source_entry_dict["duration"]).readable_str + if idx + 1 < len(chapters.timestamps): + timestamp_end = chapters.timestamps[idx + 1].readable_str - def download(self) -> List[YoutubePlaylistVideo]: + metadata = FileMetadata(metadata=f"{timestamp_begin} - {timestamp_end}") + return ( + YoutubePlaylistVideo(entry_dict=entry_dict, working_directory=self.working_directory), + metadata, + ) + + def download(self) -> List[Tuple[YoutubePlaylistVideo, FileMetadata]]: """Download a single Youtube video, then split it into multiple videos""" - split_videos: List[YoutubePlaylistVideo] = [] + split_videos_and_metadata: List[Tuple[YoutubePlaylistVideo, FileMetadata]] = [] chapters = Chapters.from_file(chapters_file_path=self.download_options.split_timestamps) entry_dict = self.extract_info(url=self.download_options.video_url) @@ -178,13 +189,10 @@ class YoutubeSplitVideoDownloader( ) # Format the split video as a YoutubePlaylistVideo - split_videos.append( + split_videos_and_metadata.append( self._create_split_video_entry( - source_entry_dict=entry_dict, - title=title, - idx=idx, - split_video_count=len(chapters.timestamps), + source_entry_dict=entry_dict, title=title, idx=idx, chapters=chapters ) ) - return split_videos + return split_videos_and_metadata diff --git a/src/ytdl_sub/subscriptions/subscription.py b/src/ytdl_sub/subscriptions/subscription.py index 5601674c..c7e9647a 100644 --- a/src/ytdl_sub/subscriptions/subscription.py +++ b/src/ytdl_sub/subscriptions/subscription.py @@ -267,8 +267,10 @@ class Subscription: ) for entry in downloader.download(): - # TODO: Add entry metadata from the downloader.download function entry_metadata = FileMetadata() + if isinstance(entry, tuple): + entry, entry_metadata = entry + for plugin in plugins: entry_metadata.extend(plugin.post_process_entry(entry)) diff --git a/src/ytdl_sub/utils/chapters.py b/src/ytdl_sub/utils/chapters.py index ccb5164f..8bb6ecbc 100644 --- a/src/ytdl_sub/utils/chapters.py +++ b/src/ytdl_sub/utils/chapters.py @@ -1,8 +1,11 @@ import os import re from typing import List +from typing import Optional +from typing import Tuple from ytdl_sub.utils.exceptions import ValidationException +from ytdl_sub.utils.file_handler import FileMetadata class Timestamp: @@ -48,12 +51,7 @@ class Timestamp: return self._timestamp_sec @property - def timestamp_str(self) -> str: - """ - Returns - ------- - The timestamp in 'HH:MM:SS' format - """ + def _hours_minutes_seconds(self) -> Tuple[int, int, int]: seconds = self.timestamp_sec hours = int(seconds / 3600) @@ -62,6 +60,30 @@ class Timestamp: minutes = int(seconds / 60) seconds -= minutes * 60 + return hours, minutes, seconds + + @property + def readable_str(self) -> str: + """ + Returns + ------- + The timestamp in '0:SS' format (min trim). + """ + hours, minutes, seconds = self._hours_minutes_seconds + if hours: + return f"{str(hours)}:{str(minutes).zfill(2)}:{str(seconds).zfill(2)}" + if minutes: + return f"{str(minutes)}:{str(seconds).zfill(2)}" + return f"0:{str(seconds).zfill(2)}" + + @property + def standardized_str(self) -> str: + """ + Returns + ------- + The timestamp in 'HH:MM:SS' format + """ + hours, minutes, seconds = self._hours_minutes_seconds return f"{str(hours).zfill(2)}:{str(minutes).zfill(2)}:{str(seconds).zfill(2)}" @classmethod @@ -125,6 +147,22 @@ class Chapters: """ return self.timestamps[0].timestamp_sec == 0 + def to_file_metadata(self, title: Optional[str] = None) -> FileMetadata: + """ + Parameters + ---------- + title + Optional title + + Returns + ------- + Chapter metadata in the format of { readable_timestamp_str: title } + """ + return FileMetadata.from_dict( + value_dict={ts.readable_str: title for ts, title in zip(self.timestamps, self.titles)}, + title=title, + ) + @classmethod def from_file(cls, chapters_file_path: str) -> "Chapters": """ diff --git a/src/ytdl_sub/utils/file_handler.py b/src/ytdl_sub/utils/file_handler.py index 2ef61724..e298c730 100644 --- a/src/ytdl_sub/utils/file_handler.py +++ b/src/ytdl_sub/utils/file_handler.py @@ -14,8 +14,12 @@ class FileMetadata: Stores pretty-printed information about a file. Each line in the metadata represents a newline """ - def __init__(self, metadata: Optional[List[str]] = None): - self.metadata: List[str] = metadata if metadata else [] + def __init__(self, metadata: Optional[Union[str, List[str]]] = None): + self.metadata = [] + if isinstance(metadata, str): + self.metadata = [metadata] + elif isinstance(metadata, list): + self.metadata = metadata def append(self, line: str) -> "FileMetadata": """ diff --git a/tests/e2e/expected_download.py b/tests/e2e/expected_download.py index ffc5dde3..7894c847 100644 --- a/tests/e2e/expected_download.py +++ b/tests/e2e/expected_download.py @@ -1,15 +1,23 @@ import hashlib import os.path +from dataclasses import dataclass from pathlib import Path -from typing import Dict from typing import List from typing import Optional from typing import Union from ytdl_sub.utils.file_handler import FileHandlerTransactionLog +from ytdl_sub.utils.file_handler import FileMetadata -class ExpectedDownload: +@dataclass +class ExpectedDownloadFile: + path: Path + md5: Optional[Union[str, List[str]]] = None + metadata: Optional[FileMetadata] = None + + +class ExpectedDownloads: """ To test ytdl-sub downloads work, we compare each downloaded file's md5 hash to an expected md5 hash defined in this class. @@ -18,12 +26,15 @@ class ExpectedDownload: try all the hashes (used in case the GitHub env produces different deterministic value). """ - def __init__(self, expected_md5_file_hashes: Dict[Path, Optional[Union[str, List[str]]]]): - self.expected_md5_file_hashes = expected_md5_file_hashes + def __init__(self, expected_downloads: List[ExpectedDownloadFile]): + self.expected_downloads = expected_downloads @property def file_count(self) -> int: - return len(self.expected_md5_file_hashes) + return len(self.expected_downloads) + + def contains(self, relative_path: Path) -> bool: + return sum(relative_path == download.path for download in self.expected_downloads) == 1 def assert_files_exist(self, relative_directory: Path): """ @@ -35,29 +46,30 @@ class ExpectedDownload: num_files += 1 relative_path = Path(*path.parts[3:]) - assert ( - relative_path in self.expected_md5_file_hashes + assert self.contains( + relative_path ), f"File {relative_path} was created but not expected" assert num_files == self.file_count, "Mismatch in number of created files" - for relative_path, expected_md5_hash in self.expected_md5_file_hashes.items(): - full_path = Path(relative_directory) / relative_path + for expected_download in self.expected_downloads: + full_path = Path(relative_directory) / expected_download.path assert os.path.isfile( full_path - ), f"Expected {str(relative_path)} to be a file but it is not" + ), f"Expected {str(expected_download.path)} to be a file but it is not" - if expected_md5_hash is None: + if expected_download.md5 is None: continue with open(full_path, "rb") as file: md5_hash = hashlib.md5(file.read()).hexdigest() - if isinstance(expected_md5_hash, str): - expected_md5_hash = [expected_md5_hash] + expected_md5_hash = expected_download.md5 + if isinstance(expected_download.md5, str): + expected_md5_hash = [expected_download.md5] assert md5_hash in expected_md5_hash, ( - f"MD5 hash for {str(relative_path)} does not match: " + f"MD5 hash for {str(expected_download.path)} does not match: " f"{md5_hash} != {expected_md5_hash}" ) @@ -66,7 +78,8 @@ class ExpectedDownload: len(transaction_log.files_created) == self.file_count ), "Mismatch in number of created files" - for relative_path in self.expected_md5_file_hashes.keys(): + for expected_download in self.expected_downloads: + expected_path = str(expected_download.path) assert ( - str(relative_path) in transaction_log.files_created - ), f"Expected {str(relative_path)} to be a file but it is not" + expected_path in transaction_log.files_created + ), f"Expected {expected_path} to be a file but it is not" diff --git a/tests/e2e/soundcloud/test_soundcloud_discography.py b/tests/e2e/soundcloud/test_soundcloud_discography.py index 488c5505..4e567003 100644 --- a/tests/e2e/soundcloud/test_soundcloud_discography.py +++ b/tests/e2e/soundcloud/test_soundcloud_discography.py @@ -1,7 +1,8 @@ from pathlib import Path import pytest -from e2e.expected_download import ExpectedDownload +from e2e.expected_download import ExpectedDownloadFile +from e2e.expected_download import ExpectedDownloads from ytdl_sub.config.config_file import ConfigFile from ytdl_sub.config.preset import Preset @@ -56,34 +57,32 @@ def discography_subscription(config, subscription_name, subscription_dict): def expected_discography_download(): # turn off black formatter here for readability # fmt: off - return ExpectedDownload( - expected_md5_file_hashes={ + return ExpectedDownloads( + expected_downloads=[ # Download mapping - Path(".ytdl-sub-jb-download-archive.json"): "1a99156e9ece62539fb2608416a07200", + ExpectedDownloadFile(path=Path(".ytdl-sub-jb-download-archive.json"), md5="1a99156e9ece62539fb2608416a07200"), # Entry files (singles) - Path("j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3"): "bffbd558e12c6a9e029dc136a88342c4", - Path("j_b/[2021] Baby Santana's Dorian Groove/folder.jpg"): "511c43d7e939c70953cf2cd3cd437072", + ExpectedDownloadFile(path=Path("j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3"), md5="bffbd558e12c6a9e029dc136a88342c4"), + ExpectedDownloadFile(path=Path("j_b/[2021] Baby Santana's Dorian Groove/folder.jpg"), md5="511c43d7e939c70953cf2cd3cd437072"), - Path("j_b/[2021] Purple Clouds/01 - Purple Clouds.mp3"): "038db58aebe2ba875b733932b42a94d6", - Path("j_b/[2021] Purple Clouds/folder.jpg"): "511c43d7e939c70953cf2cd3cd437072", + ExpectedDownloadFile(path=Path("j_b/[2021] Purple Clouds/01 - Purple Clouds.mp3"), md5="038db58aebe2ba875b733932b42a94d6"), + ExpectedDownloadFile(path=Path("j_b/[2021] Purple Clouds/folder.jpg"), md5="511c43d7e939c70953cf2cd3cd437072"), # Entry files (albums) - Path("j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3"): "e145f0a2f6012768280c38655ca58065", - Path("j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3"): "60c8b8817a197a13e4bb90903af612c5", - Path("j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3"): "8265b7e4f79878af877bc6ecd9757efe", - Path("j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3"): "accf46b76891d2954b893d0f91d82816", - Path("j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3"): "e1f584f523336160d5c1104a61de77f3", - Path("j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3"): "f6885b25901177f0357649afe97328cc", - Path("j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3"): "fa057f221cbe4cf2442cd2fdb960743e", - Path("j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3"): "7794ae812c64580e2ac8fc457d5cc85f", - Path("j_b/[2022] Acoustic Treats/09 - Finding Home.mp3"): "adbf02eddb2090c008eb497d13ff84b9", - Path("j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3"): "65bb10c84366c71498161734f953e93d", - Path("j_b/[2022] Acoustic Treats/11 - Untold History.mp3"): "6904b2918e5dc38d9a9f72d967eb74bf", - Path("j_b/[2022] Acoustic Treats/folder.jpg"): "511c43d7e939c70953cf2cd3cd437072", - - - } + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3"), md5="e145f0a2f6012768280c38655ca58065"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3"), md5="60c8b8817a197a13e4bb90903af612c5"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3"), md5="8265b7e4f79878af877bc6ecd9757efe"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3"), md5="accf46b76891d2954b893d0f91d82816"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3"), md5="e1f584f523336160d5c1104a61de77f3"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3"), md5="f6885b25901177f0357649afe97328cc"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3"), md5="fa057f221cbe4cf2442cd2fdb960743e"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3"), md5="7794ae812c64580e2ac8fc457d5cc85f"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/09 - Finding Home.mp3"), md5="adbf02eddb2090c008eb497d13ff84b9"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3"), md5="65bb10c84366c71498161734f953e93d"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/11 - Untold History.mp3"), md5="6904b2918e5dc38d9a9f72d967eb74bf"), + ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/folder.jpg"), md5="511c43d7e939c70953cf2cd3cd437072"), + ] ) # fmt: on diff --git a/tests/e2e/youtube/test_channel_as_kodi_tv_show.py b/tests/e2e/youtube/test_channel_as_kodi_tv_show.py index fcaeb4eb..f5efa6ca 100644 --- a/tests/e2e/youtube/test_channel_as_kodi_tv_show.py +++ b/tests/e2e/youtube/test_channel_as_kodi_tv_show.py @@ -3,7 +3,8 @@ from pathlib import Path import mergedeep import pytest from conftest import assert_debug_log -from e2e.expected_download import ExpectedDownload +from e2e.expected_download import ExpectedDownloadFile +from e2e.expected_download import ExpectedDownloads import ytdl_sub.downloaders.downloader from ytdl_sub.config.config_file import ConfigFile @@ -65,65 +66,65 @@ def full_channel_subscription(config, subscription_name, subscription_dict): def expected_full_channel_download(): # turn off black formatter here for readability # fmt: off - return ExpectedDownload( - expected_md5_file_hashes={ + return ExpectedDownloads( + expected_downloads=[ # Download mapping - Path(".ytdl-sub-pz-download-archive.json"): "b7e7c19d2cf0277e4e42453a64fbaa90", + ExpectedDownloadFile(path=Path(".ytdl-sub-pz-download-archive.json"), md5="b7e7c19d2cf0277e4e42453a64fbaa90"), # Output directory files - Path("fanart.jpg"): "e6e323373c8902568e96e374817179cf", - Path("poster.jpg"): "a14c593bcc75bb8d2c7145de4767ad01", - Path("tvshow.nfo"): "83c7db96081ac5bdf289fcf396bec157", + ExpectedDownloadFile(path=Path("fanart.jpg"), md5="e6e323373c8902568e96e374817179cf"), + ExpectedDownloadFile(path=Path("poster.jpg"), md5="a14c593bcc75bb8d2c7145de4767ad01"), + ExpectedDownloadFile(path=Path("tvshow.nfo"), md5="83c7db96081ac5bdf289fcf396bec157"), # Entry files - Path("Season 2010/s2010.e0813 - Oblivion Mod 'Falcor' p.1.jpg"): "b58377dfe7c39527e1990a24b36bbd77", - Path("Season 2010/s2010.e0813 - Oblivion Mod 'Falcor' p.1.mp4"): "931a705864c57d21d6fedebed4af6bbc", - Path("Season 2010/s2010.e0813 - Oblivion Mod 'Falcor' p.1.nfo"): "67d8d71d048039080acbba3bce4febaa", + ExpectedDownloadFile(path=Path("Season 2010/s2010.e0813 - Oblivion Mod 'Falcor' p.1.jpg"), md5="b58377dfe7c39527e1990a24b36bbd77"), + ExpectedDownloadFile(path=Path("Season 2010/s2010.e0813 - Oblivion Mod 'Falcor' p.1.mp4"), md5="931a705864c57d21d6fedebed4af6bbc"), + ExpectedDownloadFile(path=Path("Season 2010/s2010.e0813 - Oblivion Mod 'Falcor' p.1.nfo"), md5="67d8d71d048039080acbba3bce4febaa"), - Path("Season 2010/s2010.e1202 - Oblivion Mod 'Falcor' p.2.jpg"): "a5ee6247c8dce255aec79c9a51d49da4", - Path("Season 2010/s2010.e1202 - Oblivion Mod 'Falcor' p.2.mp4"): "d3469b4dca7139cb3dbc38712b6796bf", - Path("Season 2010/s2010.e1202 - Oblivion Mod 'Falcor' p.2.nfo"): "d81f49cedbd7edaee987521e89b37904", + ExpectedDownloadFile(path=Path("Season 2010/s2010.e1202 - Oblivion Mod 'Falcor' p.2.jpg"), md5="a5ee6247c8dce255aec79c9a51d49da4"), + ExpectedDownloadFile(path=Path("Season 2010/s2010.e1202 - Oblivion Mod 'Falcor' p.2.mp4"), md5="d3469b4dca7139cb3dbc38712b6796bf"), + ExpectedDownloadFile(path=Path("Season 2010/s2010.e1202 - Oblivion Mod 'Falcor' p.2.nfo"), md5="d81f49cedbd7edaee987521e89b37904"), - Path("Season 2011/s2011.e0201 - Jesse's Minecraft Server [Trailer - Feb.1].jpg"): "048a19cf0f674437351872c3f312ebf1", - Path("Season 2011/s2011.e0201 - Jesse's Minecraft Server [Trailer - Feb.1].mp4"): "e66287b9832277b6a4d1554e29d9fdcc", - Path("Season 2011/s2011.e0201 - Jesse's Minecraft Server [Trailer - Feb.1].nfo"): "f7c0de89038f8c491bded8a3968720a2", + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0201 - Jesse's Minecraft Server [Trailer - Feb.1].jpg"), md5="048a19cf0f674437351872c3f312ebf1"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0201 - Jesse's Minecraft Server [Trailer - Feb.1].mp4"), md5="e66287b9832277b6a4d1554e29d9fdcc"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0201 - Jesse's Minecraft Server [Trailer - Feb.1].nfo"), md5="f7c0de89038f8c491bded8a3968720a2"), - Path("Season 2011/s2011.e0227 - Jesse's Minecraft Server [Trailer - Feb.27].jpg"): None, - Path("Season 2011/s2011.e0227 - Jesse's Minecraft Server [Trailer - Feb.27].mp4"): "04ab5cb3cc12325d0c96a7cd04a8b91d", - Path("Season 2011/s2011.e0227 - Jesse's Minecraft Server [Trailer - Feb.27].nfo"): "ee1eda78fa0980bc703e602b5012dd1f", + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0227 - Jesse's Minecraft Server [Trailer - Feb.27].jpg"), md5=None), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0227 - Jesse's Minecraft Server [Trailer - Feb.27].mp4"), md5="04ab5cb3cc12325d0c96a7cd04a8b91d"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0227 - Jesse's Minecraft Server [Trailer - Feb.27].nfo"), md5="ee1eda78fa0980bc703e602b5012dd1f"), - Path("Season 2011/s2011.e0321 - Jesse's Minecraft Server [Trailer - Mar.21].jpg"): "9baaddc6b62f5b9ae3781eb4eef0e3b3", - Path("Season 2011/s2011.e0321 - Jesse's Minecraft Server [Trailer - Mar.21].mp4"): "025de6099a5c98e6397153c7a62d517d", - Path("Season 2011/s2011.e0321 - Jesse's Minecraft Server [Trailer - Mar.21].nfo"): "61eb6369430da0ab6134d78829a7621b", + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0321 - Jesse's Minecraft Server [Trailer - Mar.21].jpg"), md5="9baaddc6b62f5b9ae3781eb4eef0e3b3"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0321 - Jesse's Minecraft Server [Trailer - Mar.21].mp4"), md5="025de6099a5c98e6397153c7a62d517d"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0321 - Jesse's Minecraft Server [Trailer - Mar.21].nfo"), md5="61eb6369430da0ab6134d78829a7621b"), - Path("Season 2011/s2011.e0529 - Project Zombie _Official Trailer_ (IP - mc.projectzombie.beastnode.net).jpg"): "ce1df7f623fffaefe04606ecbafcfec6", - Path("Season 2011/s2011.e0529 - Project Zombie _Official Trailer_ (IP - mc.projectzombie.beastnode.net).mp4"): "3d9c19835b03355d6fd5d00cd59dbe5b", - Path("Season 2011/s2011.e0529 - Project Zombie _Official Trailer_ (IP - mc.projectzombie.beastnode.net).nfo"): "60f72b99f5c69f9e03a071a12160928f", + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0529 - Project Zombie _Official Trailer_ (IP - mc.projectzombie.beastnode.net).jpg"), md5="ce1df7f623fffaefe04606ecbafcfec6"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0529 - Project Zombie _Official Trailer_ (IP - mc.projectzombie.beastnode.net).mp4"), md5="3d9c19835b03355d6fd5d00cd59dbe5b"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0529 - Project Zombie _Official Trailer_ (IP - mc.projectzombie.beastnode.net).nfo"), md5="60f72b99f5c69f9e03a071a12160928f"), - Path("Season 2011/s2011.e0630 - Project Zombie _Fin.jpg"): "bc3f511915869720c37617a7de706b2b", - Path("Season 2011/s2011.e0630 - Project Zombie _Fin.mp4"): "4971cb2d4fa29460361031f3fa8e1ea9", - Path("Season 2011/s2011.e0630 - Project Zombie _Fin.nfo"): "a7b5d9e57d20852f5daf360a1373bb7a", + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0630 - Project Zombie _Fin.jpg"), md5="bc3f511915869720c37617a7de706b2b"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0630 - Project Zombie _Fin.mp4"), md5="4971cb2d4fa29460361031f3fa8e1ea9"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e0630 - Project Zombie _Fin.nfo"), md5="a7b5d9e57d20852f5daf360a1373bb7a"), - Path("Season 2011/s2011.e1121 - Skyrim 'Ultra HD w_Mods' [PC].jpg"): "12babdb3b86cd868b90b60d013295f66", - Path("Season 2011/s2011.e1121 - Skyrim 'Ultra HD w_Mods' [PC].mp4"): "55e9b0add08c48c9c66105da0def2426", - Path("Season 2011/s2011.e1121 - Skyrim 'Ultra HD w_Mods' [PC].nfo"): "fe60e2b6b564f9316b6c7c183e1cf300", + ExpectedDownloadFile(path=Path("Season 2011/s2011.e1121 - Skyrim 'Ultra HD w_Mods' [PC].jpg"), md5="12babdb3b86cd868b90b60d013295f66"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e1121 - Skyrim 'Ultra HD w_Mods' [PC].mp4"), md5="55e9b0add08c48c9c66105da0def2426"), + ExpectedDownloadFile(path=Path("Season 2011/s2011.e1121 - Skyrim 'Ultra HD w_Mods' [PC].nfo"), md5="fe60e2b6b564f9316b6c7c183e1cf300"), - Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.jpg"): "82d303e16aba75acdde30b15c4154231", - Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.mp4"): "65e4ce53ed5ec4139995469f99477a50", - Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.nfo"): "c8900adcca83c473c79a4afbc7ad2de1", + ExpectedDownloadFile(path=Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.jpg"), md5="82d303e16aba75acdde30b15c4154231"), + ExpectedDownloadFile(path=Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.mp4"), md5="65e4ce53ed5ec4139995469f99477a50"), + ExpectedDownloadFile(path=Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.nfo"), md5="c8900adcca83c473c79a4afbc7ad2de1"), - Path("Season 2013/s2013.e0719 - Project Zombie Rewind _Trailer.jpg"): "83b1af4c3614d262b2ad419586fff730", - Path("Season 2013/s2013.e0719 - Project Zombie Rewind _Trailer.mp4"): "18620a8257a686beda65e54add4d4cd1", - Path("Season 2013/s2013.e0719 - Project Zombie Rewind _Trailer.nfo"): "1c993c41d4308a6049333154d0adee16", + ExpectedDownloadFile(path=Path("Season 2013/s2013.e0719 - Project Zombie Rewind _Trailer.jpg"), md5="83b1af4c3614d262b2ad419586fff730"), + ExpectedDownloadFile(path=Path("Season 2013/s2013.e0719 - Project Zombie Rewind _Trailer.mp4"), md5="18620a8257a686beda65e54add4d4cd1"), + ExpectedDownloadFile(path=Path("Season 2013/s2013.e0719 - Project Zombie Rewind _Trailer.nfo"), md5="1c993c41d4308a6049333154d0adee16"), - Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.jpg"): "2a24de903059f48c7d0df0476046c975", - Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.mp4"): "82f6ee7253e1dbb83ae7215af08ffacc", - Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.nfo"): "cc7886aae3af6b7b0facd82f95390242", + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.jpg"), md5="2a24de903059f48c7d0df0476046c975"), + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.mp4"), md5="82f6ee7253e1dbb83ae7215af08ffacc"), + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.nfo"), md5="cc7886aae3af6b7b0facd82f95390242"), - Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"): "c8baea83b9edeb081657f1130a1031f7", - Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"): "e733b4cc385b953b08c8eb0f47e03c1e", - Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.nfo"): "2b3ccb3f1ef81ee49fe1afb88f275a09", - } + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"), md5="c8baea83b9edeb081657f1130a1031f7"), + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"), md5="e733b4cc385b953b08c8eb0f47e03c1e"), + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.nfo"), md5="2b3ccb3f1ef81ee49fe1afb88f275a09"), + ] ) # fmt: on @@ -161,25 +162,25 @@ def recent_channel_subscription(config, subscription_name, recent_channel_subscr def expected_recent_channel_download(): # turn off black formatter here for readability # fmt: off - return ExpectedDownload( - expected_md5_file_hashes={ + return ExpectedDownloads( + expected_downloads=[ # Download mapping - Path(".ytdl-sub-pz-download-archive.json"): "b1675ca4d9f0d4b9c2102b6749e4cdfd", + ExpectedDownloadFile(path=Path(".ytdl-sub-pz-download-archive.json"), md5="b1675ca4d9f0d4b9c2102b6749e4cdfd"), # Output directory files - Path("fanart.jpg"): "e6e323373c8902568e96e374817179cf", - Path("poster.jpg"): "a14c593bcc75bb8d2c7145de4767ad01", - Path("tvshow.nfo"): "83c7db96081ac5bdf289fcf396bec157", + ExpectedDownloadFile(path=Path("fanart.jpg"), md5="e6e323373c8902568e96e374817179cf"), + ExpectedDownloadFile(path=Path("poster.jpg"), md5="a14c593bcc75bb8d2c7145de4767ad01"), + ExpectedDownloadFile(path=Path("tvshow.nfo"), md5="83c7db96081ac5bdf289fcf396bec157"), # Recent Entry files - Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.jpg"): "2a24de903059f48c7d0df0476046c975", - Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.mp4"): "82f6ee7253e1dbb83ae7215af08ffacc", - Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.nfo"): "cc7886aae3af6b7b0facd82f95390242", + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.jpg"), md5="2a24de903059f48c7d0df0476046c975"), + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.mp4"), md5="82f6ee7253e1dbb83ae7215af08ffacc"), + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.nfo"), md5="cc7886aae3af6b7b0facd82f95390242"), - Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"): "c8baea83b9edeb081657f1130a1031f7", - Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"): "e733b4cc385b953b08c8eb0f47e03c1e", - Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.nfo"): "2b3ccb3f1ef81ee49fe1afb88f275a09", - } + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"), md5="c8baea83b9edeb081657f1130a1031f7"), + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"), md5="e733b4cc385b953b08c8eb0f47e03c1e"), + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.nfo"), md5="2b3ccb3f1ef81ee49fe1afb88f275a09"), + ] ) # fmt: on @@ -219,16 +220,16 @@ def recent_channel_no_vids_in_range_subscription( def expected_recent_channel_no_vids_in_range_download(): # turn off black formatter here for readability # fmt: off - return ExpectedDownload( - expected_md5_file_hashes={ + return ExpectedDownloads( + expected_downloads=[ # Download mapping - Path(".ytdl-sub-pz-download-archive.json"): "99914b932bd37a50b983c5e7c90ae93b", + ExpectedDownloadFile(path=Path(".ytdl-sub-pz-download-archive.json"), md5="99914b932bd37a50b983c5e7c90ae93b"), # Output directory files - Path("fanart.jpg"): "e6e323373c8902568e96e374817179cf", - Path("poster.jpg"): "a14c593bcc75bb8d2c7145de4767ad01", - Path("tvshow.nfo"): "83c7db96081ac5bdf289fcf396bec157", - } + ExpectedDownloadFile(path=Path("fanart.jpg"), md5="e6e323373c8902568e96e374817179cf"), + ExpectedDownloadFile(path=Path("poster.jpg"), md5="a14c593bcc75bb8d2c7145de4767ad01"), + ExpectedDownloadFile(path=Path("tvshow.nfo"), md5="83c7db96081ac5bdf289fcf396bec157"), + ] ) # fmt: on @@ -266,21 +267,21 @@ def rolling_recent_channel_subscription( def expected_rolling_recent_channel_download(): # turn off black formatter here for readability # fmt: off - return ExpectedDownload( - expected_md5_file_hashes={ + return ExpectedDownloads( + expected_downloads=[ # Download mapping - Path(".ytdl-sub-pz-download-archive.json"): "9ae3463bd2dc39830003aba68a276df4", + ExpectedDownloadFile(path=Path(".ytdl-sub-pz-download-archive.json"), md5="9ae3463bd2dc39830003aba68a276df4"), # Output directory files - Path("fanart.jpg"): "e6e323373c8902568e96e374817179cf", - Path("poster.jpg"): "a14c593bcc75bb8d2c7145de4767ad01", - Path("tvshow.nfo"): "83c7db96081ac5bdf289fcf396bec157", + ExpectedDownloadFile(path=Path("fanart.jpg"), md5="e6e323373c8902568e96e374817179cf"), + ExpectedDownloadFile(path=Path("poster.jpg"), md5="a14c593bcc75bb8d2c7145de4767ad01"), + ExpectedDownloadFile(path=Path("tvshow.nfo"), md5="83c7db96081ac5bdf289fcf396bec157"), # Rolling Recent Entry files - Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"): "c8baea83b9edeb081657f1130a1031f7", - Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"): "e733b4cc385b953b08c8eb0f47e03c1e", - Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.nfo"): "2b3ccb3f1ef81ee49fe1afb88f275a09", - } + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"), md5="c8baea83b9edeb081657f1130a1031f7"), + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"), md5="e733b4cc385b953b08c8eb0f47e03c1e"), + ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.nfo"), md5="2b3ccb3f1ef81ee49fe1afb88f275a09"), + ] ) # fmt: on diff --git a/tests/e2e/youtube/test_merge_playlist.py b/tests/e2e/youtube/test_merge_playlist.py index e9bade9b..b1265875 100644 --- a/tests/e2e/youtube/test_merge_playlist.py +++ b/tests/e2e/youtube/test_merge_playlist.py @@ -1,7 +1,8 @@ from pathlib import Path import pytest -from e2e.expected_download import ExpectedDownload +from e2e.expected_download import ExpectedDownloadFile +from e2e.expected_download import ExpectedDownloads from ytdl_sub.config.config_file import ConfigFile from ytdl_sub.config.preset import Preset @@ -63,16 +64,15 @@ def playlist_subscription(config, subscription_name, subscription_dict): @pytest.fixture def expected_playlist_download(): - return ExpectedDownload( - expected_md5_file_hashes={ - Path("JMC - Jesse's Minecraft Server.jpg"): "348e3007fc590d0b1e2f6682501b0b5f", - Path("JMC - Jesse's Minecraft Server.mkv"): [ - "6053c47a8690519b0a33c13fa4b01ac0", - "3ab42b3e6be0a44deb3a9a28e6ebaf16", - ], - Path("JMC - Jesse's Minecraft Server.nfo"): "10df5dcdb65ab18ecf21b3503c77e48b", - } + # fmt: off + return ExpectedDownloads( + expected_downloads=[ + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server.jpg"), md5="348e3007fc590d0b1e2f6682501b0b5f"), + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server.mkv"), md5=["6053c47a8690519b0a33c13fa4b01ac0", "3ab42b3e6be0a44deb3a9a28e6ebaf16"]), + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server.nfo"), md5="10df5dcdb65ab18ecf21b3503c77e48b") + ] ) + # fmt: on class TestYoutubeMergePlaylist: diff --git a/tests/e2e/youtube/test_playlist_as_kodi_music_videos.py b/tests/e2e/youtube/test_playlist_as_kodi_music_videos.py index f8f09699..f0434226 100644 --- a/tests/e2e/youtube/test_playlist_as_kodi_music_videos.py +++ b/tests/e2e/youtube/test_playlist_as_kodi_music_videos.py @@ -3,7 +3,8 @@ from pathlib import Path import mergedeep import pytest from conftest import assert_debug_log -from e2e.expected_download import ExpectedDownload +from e2e.expected_download import ExpectedDownloadFile +from e2e.expected_download import ExpectedDownloads import ytdl_sub.downloaders.downloader from ytdl_sub.config.config_file import ConfigFile @@ -63,24 +64,24 @@ def playlist_subscription(config, subscription_name, subscription_dict): def expected_playlist_download(): # turn off black formatter here for readability # fmt: off - return ExpectedDownload( - expected_md5_file_hashes={ + return ExpectedDownloads( + expected_downloads=[ # Download mapping - Path(".ytdl-sub-jmc-download-archive.json"): "d8e784353c7c3006cb755a034c965160", + ExpectedDownloadFile(path=Path(".ytdl-sub-jmc-download-archive.json"), md5="d8e784353c7c3006cb755a034c965160"), # Entry files - Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].jpg"): None, - Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].mp4"): "e66287b9832277b6a4d1554e29d9fdcc", - Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].nfo"): "3d272fe58487b6011ad049b6000b046f", + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].jpg"), md5=None), + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].mp4"), md5="e66287b9832277b6a4d1554e29d9fdcc"), + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].nfo"), md5="3d272fe58487b6011ad049b6000b046f"), - Path("JMC - Jesse's Minecraft Server [Trailer - Feb.27].jpg"): None, - Path("JMC - Jesse's Minecraft Server [Trailer - Feb.27].mp4"): "04ab5cb3cc12325d0c96a7cd04a8b91d", - Path("JMC - Jesse's Minecraft Server [Trailer - Feb.27].nfo"): "6f99af10bef67276a507d1d9770c5e92", + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Feb.27].jpg"), md5=None), + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Feb.27].mp4"), md5="04ab5cb3cc12325d0c96a7cd04a8b91d"), + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Feb.27].nfo"), md5="6f99af10bef67276a507d1d9770c5e92"), - Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].jpg"): None, - Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].mp4"): "025de6099a5c98e6397153c7a62d517d", - Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].nfo"): "beec3c1326654bd8c858cecf4e40977a", - } + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].jpg"), md5=None), + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].mp4"), md5="025de6099a5c98e6397153c7a62d517d"), + ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].nfo"), md5="beec3c1326654bd8c858cecf4e40977a"), + ] ) # fmt: on @@ -118,12 +119,12 @@ def single_video_subscription(config, subscription_name, single_video_subscripti def expected_single_video_download(): # turn off black formatter here for readability # fmt: off - return ExpectedDownload( - expected_md5_file_hashes={ - Path("JMC - Oblivion Mod 'Falcor' p.1.jpg"): None, - Path("JMC - Oblivion Mod 'Falcor' p.1.mp4"): "931a705864c57d21d6fedebed4af6bbc", - Path("JMC - Oblivion Mod 'Falcor' p.1.nfo"): "89f509a8a3d9003e22a9091abeeae5dc", - } + return ExpectedDownloads( + expected_downloads=[ + ExpectedDownloadFile(path=Path("JMC - Oblivion Mod 'Falcor' p.1.jpg"), md5=None), + ExpectedDownloadFile(path=Path("JMC - Oblivion Mod 'Falcor' p.1.mp4"), md5="931a705864c57d21d6fedebed4af6bbc"), + ExpectedDownloadFile(path=Path("JMC - Oblivion Mod 'Falcor' p.1.nfo"), md5="89f509a8a3d9003e22a9091abeeae5dc"), + ] ) # fmt: on diff --git a/tests/e2e/youtube/test_split_video.py b/tests/e2e/youtube/test_split_video.py index d0602fa5..30771d59 100644 --- a/tests/e2e/youtube/test_split_video.py +++ b/tests/e2e/youtube/test_split_video.py @@ -4,7 +4,8 @@ from tempfile import NamedTemporaryFile import mergedeep import pytest from conftest import assert_debug_log -from e2e.expected_download import ExpectedDownload +from e2e.expected_download import ExpectedDownloadFile +from e2e.expected_download import ExpectedDownloads import ytdl_sub.downloaders.downloader from ytdl_sub.config.config_file import ConfigFile @@ -88,27 +89,27 @@ def single_video_subscription(config, subscription_name, subscription_dict): def expected_single_video_download(): # turn off black formatter here for readability # fmt: off - return ExpectedDownload( - expected_md5_file_hashes={ - Path('Project Zombie - 1-6.Intro.mp4'): "eaec6f50f364b13ef1a201e736ec9c05", - Path('Project Zombie - 2-6.Part 1.mp4'): "5850b19acb250cc13db36f80fa1bba5a", - Path('Project Zombie - 3-6.Part 2.mp4'): "445d95eba437db6df284df7e1ab633e8", - Path('Project Zombie - 4-6.Part 3.mp4'): "2b6e7532d515c9e64ed2a33d850cf199", - Path('Project Zombie - 5-6.Part 4.mp4'): "842bf3c4d1fcc4c5ab110635935dac66", - Path('Project Zombie - 6-6.Part 5.mp4'): "238de99f00f829ab72f042b79da9a33a", - Path('Project Zombie - Intro.jpg'): "e87282e4115baa8b5c727fb4de15316d", - Path('Project Zombie - Intro.nfo'): "ded59ac906f579312cc3cf98a57e7ea3", - Path('Project Zombie - Part 1.jpg'): "e87282e4115baa8b5c727fb4de15316d", - Path('Project Zombie - Part 1.nfo'): "70ff5cd0092b8bc22dc4db93a824789b", - Path('Project Zombie - Part 2.jpg'): "e87282e4115baa8b5c727fb4de15316d", - Path('Project Zombie - Part 2.nfo'): "54450c18a2cbb9d6d2ee5d0a1fb3f279", - Path('Project Zombie - Part 3.jpg'): "e87282e4115baa8b5c727fb4de15316d", - Path('Project Zombie - Part 3.nfo'): "0effb13fc4039363a95969d1048dde57", - Path('Project Zombie - Part 4.jpg'): "e87282e4115baa8b5c727fb4de15316d", - Path('Project Zombie - Part 4.nfo'): "74bd0d7c12105469838768a0cc323a8c", - Path('Project Zombie - Part 5.jpg'): "e87282e4115baa8b5c727fb4de15316d", - Path('Project Zombie - Part 5.nfo'): "a8cf2e77721335ea7c18e22734e7996c", - } + return ExpectedDownloads( + expected_downloads=[ + ExpectedDownloadFile(path=Path('Project Zombie - 1-6.Intro.mp4'), md5="eaec6f50f364b13ef1a201e736ec9c05"), + ExpectedDownloadFile(path=Path('Project Zombie - 2-6.Part 1.mp4'), md5="5850b19acb250cc13db36f80fa1bba5a"), + ExpectedDownloadFile(path=Path('Project Zombie - 3-6.Part 2.mp4'), md5="445d95eba437db6df284df7e1ab633e8"), + ExpectedDownloadFile(path=Path('Project Zombie - 4-6.Part 3.mp4'), md5="2b6e7532d515c9e64ed2a33d850cf199"), + ExpectedDownloadFile(path=Path('Project Zombie - 5-6.Part 4.mp4'), md5="842bf3c4d1fcc4c5ab110635935dac66"), + ExpectedDownloadFile(path=Path('Project Zombie - 6-6.Part 5.mp4'), md5="238de99f00f829ab72f042b79da9a33a"), + ExpectedDownloadFile(path=Path('Project Zombie - Intro.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"), + ExpectedDownloadFile(path=Path('Project Zombie - Intro.nfo'), md5="ded59ac906f579312cc3cf98a57e7ea3"), + ExpectedDownloadFile(path=Path('Project Zombie - Part 1.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"), + ExpectedDownloadFile(path=Path('Project Zombie - Part 1.nfo'), md5="70ff5cd0092b8bc22dc4db93a824789b"), + ExpectedDownloadFile(path=Path('Project Zombie - Part 2.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"), + ExpectedDownloadFile(path=Path('Project Zombie - Part 2.nfo'), md5="54450c18a2cbb9d6d2ee5d0a1fb3f279"), + ExpectedDownloadFile(path=Path('Project Zombie - Part 3.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"), + ExpectedDownloadFile(path=Path('Project Zombie - Part 3.nfo'), md5="0effb13fc4039363a95969d1048dde57"), + ExpectedDownloadFile(path=Path('Project Zombie - Part 4.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"), + ExpectedDownloadFile(path=Path('Project Zombie - Part 4.nfo'), md5="74bd0d7c12105469838768a0cc323a8c"), + ExpectedDownloadFile(path=Path('Project Zombie - Part 5.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"), + ExpectedDownloadFile(path=Path('Project Zombie - Part 5.nfo'), md5="a8cf2e77721335ea7c18e22734e7996c"), + ] ) # fmt: on