tests updated with new class

This commit is contained in:
jbannon 2022-07-03 06:30:26 +00:00
parent 607ad9f9de
commit 7006ce3dc7
12 changed files with 273 additions and 200 deletions

View file

@ -8,6 +8,7 @@ from typing import Dict
from typing import Generic from typing import Generic
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Tuple
from typing import Type from typing import Type
from typing import TypeVar 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.config.preset_options import Overrides
from ytdl_sub.entries.base_entry import BaseEntry from ytdl_sub.entries.base_entry import BaseEntry
from ytdl_sub.entries.entry import Entry 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.utils.logger import Logger
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
from ytdl_sub.ytdl_additions.enhanced_download_archive import DownloadArchiver 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() return self._get_entry_dicts_from_info_json_files()
@abc.abstractmethod @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""" """The function to perform the download of all media entries"""
def post_download(self, overrides: Overrides): def post_download(self, overrides: Overrides):

View file

@ -1,6 +1,7 @@
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Tuple
from ytdl_sub.downloaders.youtube.abc import YoutubeDownloader from ytdl_sub.downloaders.youtube.abc import YoutubeDownloader
from ytdl_sub.downloaders.youtube.playlist import YoutubePlaylistDownloaderOptions 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 Chapters
from ytdl_sub.utils.chapters import Timestamp from ytdl_sub.utils.chapters import Timestamp
from ytdl_sub.utils.ffmpeg import add_ffmpeg_metadata from ytdl_sub.utils.ffmpeg import add_ffmpeg_metadata
from ytdl_sub.utils.file_handler import FileMetadata
from ytdl_sub.validators.validators import BoolValidator 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] = [] titles: List[str] = []
timestamps: List[Timestamp] = [] timestamps: List[Timestamp] = []
@ -111,14 +113,17 @@ class YoutubeMergePlaylistDownloader(
current_timestamp_sec += video_entry["duration"] current_timestamp_sec += video_entry["duration"]
# TODO: return chapter metadata here chapters = Chapters(timestamps=timestamps, titles=titles)
if not self.is_dry_run:
if not self.is_dry_run and add_chapters:
add_ffmpeg_metadata( add_ffmpeg_metadata(
file_path=merged_video.get_download_file_path(), file_path=merged_video.get_download_file_path(),
chapters=Chapters(timestamps=timestamps, titles=titles), chapters=chapters,
file_duration_sec=merged_video.kwargs("duration"), 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: 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 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) 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""" """Download a single Youtube video, then split it into multiple videos"""
merged_video = self._to_merged_video( merged_video = self._to_merged_video(
entry_dict=self.extract_info(url=self.download_options.playlist_url) entry_dict=self.extract_info(url=self.download_options.playlist_url)
) )
merged_video_metadata = self._get_chapters(
if self.download_options.add_chapters: merged_video=merged_video, add_chapters=self.download_options.add_chapters
self._add_chapters(merged_video=merged_video) )
return [(merged_video, merged_video_metadata)]
return [merged_video]

View file

@ -3,6 +3,7 @@ import re
from pathlib import Path from pathlib import Path
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Tuple
from ytdl_sub.downloaders.youtube.abc import YoutubeDownloader from ytdl_sub.downloaders.youtube.abc import YoutubeDownloader
from ytdl_sub.downloaders.youtube.video import YoutubeVideoDownloaderOptions from ytdl_sub.downloaders.youtube.video import YoutubeVideoDownloaderOptions
@ -19,6 +20,7 @@ from ytdl_sub.utils.ffmpeg import FFMPEG
# 01:00:00 title # 01:00:00 title
# where capture group 1 and 2 are the timestamp and title, respectively # 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 FileHandler
from ytdl_sub.utils.file_handler import FileMetadata
from ytdl_sub.utils.thumbnail import convert_download_thumbnail from ytdl_sub.utils.thumbnail import convert_download_thumbnail
from ytdl_sub.validators.validators import StringValidator 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( def _split_video_ffmpeg_cmd(
input_file: str, output_file: str, timestamps: List[Timestamp], idx: int input_file: str, output_file: str, timestamps: List[Timestamp], idx: int
) -> List[str]: ) -> List[str]:
timestamp_begin = timestamps[idx].timestamp_str timestamp_begin = timestamps[idx].standardized_str
timestamp_end = timestamps[idx + 1].timestamp_str if idx + 1 < len(timestamps) else "" timestamp_end = timestamps[idx + 1].standardized_str if idx + 1 < len(timestamps) else ""
cmd = ["-i", input_file, "-ss", timestamp_begin] cmd = ["-i", input_file, "-ss", timestamp_begin]
if timestamp_end: if timestamp_end:
@ -121,15 +123,15 @@ class YoutubeSplitVideoDownloader(
) )
def _create_split_video_entry( def _create_split_video_entry(
self, source_entry_dict: Dict, title: str, idx: int, split_video_count: int self, source_entry_dict: Dict, title: str, idx: int, chapters: Chapters
) -> YoutubePlaylistVideo: ) -> Tuple[YoutubePlaylistVideo, FileMetadata]:
""" """
Runs ffmpeg to create the split video Runs ffmpeg to create the split video
""" """
entry_dict = copy.deepcopy(source_entry_dict) entry_dict = copy.deepcopy(source_entry_dict)
entry_dict["title"] = title entry_dict["title"] = title
entry_dict["playlist_index"] = idx + 1 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) entry_dict["id"] = _split_video_uid(source_uid=entry_dict["id"], idx=idx)
# Remove track and artist since its now split # Remove track and artist since its now split
@ -138,11 +140,20 @@ class YoutubeSplitVideoDownloader(
if "artist" in entry_dict: if "artist" in entry_dict:
del entry_dict["artist"] 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""" """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) chapters = Chapters.from_file(chapters_file_path=self.download_options.split_timestamps)
entry_dict = self.extract_info(url=self.download_options.video_url) entry_dict = self.extract_info(url=self.download_options.video_url)
@ -178,13 +189,10 @@ class YoutubeSplitVideoDownloader(
) )
# Format the split video as a YoutubePlaylistVideo # Format the split video as a YoutubePlaylistVideo
split_videos.append( split_videos_and_metadata.append(
self._create_split_video_entry( self._create_split_video_entry(
source_entry_dict=entry_dict, source_entry_dict=entry_dict, title=title, idx=idx, chapters=chapters
title=title,
idx=idx,
split_video_count=len(chapters.timestamps),
) )
) )
return split_videos return split_videos_and_metadata

View file

@ -267,8 +267,10 @@ class Subscription:
) )
for entry in downloader.download(): for entry in downloader.download():
# TODO: Add entry metadata from the downloader.download function
entry_metadata = FileMetadata() entry_metadata = FileMetadata()
if isinstance(entry, tuple):
entry, entry_metadata = entry
for plugin in plugins: for plugin in plugins:
entry_metadata.extend(plugin.post_process_entry(entry)) entry_metadata.extend(plugin.post_process_entry(entry))

View file

@ -1,8 +1,11 @@
import os import os
import re import re
from typing import List from typing import List
from typing import Optional
from typing import Tuple
from ytdl_sub.utils.exceptions import ValidationException from ytdl_sub.utils.exceptions import ValidationException
from ytdl_sub.utils.file_handler import FileMetadata
class Timestamp: class Timestamp:
@ -48,12 +51,7 @@ class Timestamp:
return self._timestamp_sec return self._timestamp_sec
@property @property
def timestamp_str(self) -> str: def _hours_minutes_seconds(self) -> Tuple[int, int, int]:
"""
Returns
-------
The timestamp in 'HH:MM:SS' format
"""
seconds = self.timestamp_sec seconds = self.timestamp_sec
hours = int(seconds / 3600) hours = int(seconds / 3600)
@ -62,6 +60,30 @@ class Timestamp:
minutes = int(seconds / 60) minutes = int(seconds / 60)
seconds -= minutes * 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)}" return f"{str(hours).zfill(2)}:{str(minutes).zfill(2)}:{str(seconds).zfill(2)}"
@classmethod @classmethod
@ -125,6 +147,22 @@ class Chapters:
""" """
return self.timestamps[0].timestamp_sec == 0 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 @classmethod
def from_file(cls, chapters_file_path: str) -> "Chapters": def from_file(cls, chapters_file_path: str) -> "Chapters":
""" """

View file

@ -14,8 +14,12 @@ class FileMetadata:
Stores pretty-printed information about a file. Each line in the metadata represents a newline Stores pretty-printed information about a file. Each line in the metadata represents a newline
""" """
def __init__(self, metadata: Optional[List[str]] = None): def __init__(self, metadata: Optional[Union[str, List[str]]] = None):
self.metadata: List[str] = metadata if metadata else [] self.metadata = []
if isinstance(metadata, str):
self.metadata = [metadata]
elif isinstance(metadata, list):
self.metadata = metadata
def append(self, line: str) -> "FileMetadata": def append(self, line: str) -> "FileMetadata":
""" """

View file

@ -1,15 +1,23 @@
import hashlib import hashlib
import os.path import os.path
from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Union from typing import Union
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog 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 To test ytdl-sub downloads work, we compare each downloaded file's md5 hash to an
expected md5 hash defined in this class. 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). 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]]]]): def __init__(self, expected_downloads: List[ExpectedDownloadFile]):
self.expected_md5_file_hashes = expected_md5_file_hashes self.expected_downloads = expected_downloads
@property @property
def file_count(self) -> int: 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): def assert_files_exist(self, relative_directory: Path):
""" """
@ -35,29 +46,30 @@ class ExpectedDownload:
num_files += 1 num_files += 1
relative_path = Path(*path.parts[3:]) relative_path = Path(*path.parts[3:])
assert ( assert self.contains(
relative_path in self.expected_md5_file_hashes relative_path
), f"File {relative_path} was created but not expected" ), f"File {relative_path} was created but not expected"
assert num_files == self.file_count, "Mismatch in number of created files" 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(): for expected_download in self.expected_downloads:
full_path = Path(relative_directory) / relative_path full_path = Path(relative_directory) / expected_download.path
assert os.path.isfile( assert os.path.isfile(
full_path 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 continue
with open(full_path, "rb") as file: with open(full_path, "rb") as file:
md5_hash = hashlib.md5(file.read()).hexdigest() md5_hash = hashlib.md5(file.read()).hexdigest()
if isinstance(expected_md5_hash, str): expected_md5_hash = expected_download.md5
expected_md5_hash = [expected_md5_hash] if isinstance(expected_download.md5, str):
expected_md5_hash = [expected_download.md5]
assert md5_hash in expected_md5_hash, ( 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}" f"{md5_hash} != {expected_md5_hash}"
) )
@ -66,7 +78,8 @@ class ExpectedDownload:
len(transaction_log.files_created) == self.file_count len(transaction_log.files_created) == self.file_count
), "Mismatch in number of created files" ), "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 ( assert (
str(relative_path) in transaction_log.files_created expected_path in transaction_log.files_created
), f"Expected {str(relative_path)} to be a file but it is not" ), f"Expected {expected_path} to be a file but it is not"

View file

@ -1,7 +1,8 @@
from pathlib import Path from pathlib import Path
import pytest 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.config_file import ConfigFile
from ytdl_sub.config.preset import Preset from ytdl_sub.config.preset import Preset
@ -56,34 +57,32 @@ def discography_subscription(config, subscription_name, subscription_dict):
def expected_discography_download(): def expected_discography_download():
# turn off black formatter here for readability # turn off black formatter here for readability
# fmt: off # fmt: off
return ExpectedDownload( return ExpectedDownloads(
expected_md5_file_hashes={ expected_downloads=[
# Download mapping # Download mapping
Path(".ytdl-sub-jb-download-archive.json"): "1a99156e9ece62539fb2608416a07200", ExpectedDownloadFile(path=Path(".ytdl-sub-jb-download-archive.json"), md5="1a99156e9ece62539fb2608416a07200"),
# Entry files (singles) # Entry files (singles)
Path("j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3"): "bffbd558e12c6a9e029dc136a88342c4", ExpectedDownloadFile(path=Path("j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3"), md5="bffbd558e12c6a9e029dc136a88342c4"),
Path("j_b/[2021] Baby Santana's Dorian Groove/folder.jpg"): "511c43d7e939c70953cf2cd3cd437072", 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", ExpectedDownloadFile(path=Path("j_b/[2021] Purple Clouds/01 - Purple Clouds.mp3"), md5="038db58aebe2ba875b733932b42a94d6"),
Path("j_b/[2021] Purple Clouds/folder.jpg"): "511c43d7e939c70953cf2cd3cd437072", ExpectedDownloadFile(path=Path("j_b/[2021] Purple Clouds/folder.jpg"), md5="511c43d7e939c70953cf2cd3cd437072"),
# Entry files (albums) # Entry files (albums)
Path("j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3"): "e145f0a2f6012768280c38655ca58065", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3"), md5="e145f0a2f6012768280c38655ca58065"),
Path("j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3"): "60c8b8817a197a13e4bb90903af612c5", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3"), md5="60c8b8817a197a13e4bb90903af612c5"),
Path("j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3"): "8265b7e4f79878af877bc6ecd9757efe", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3"), md5="8265b7e4f79878af877bc6ecd9757efe"),
Path("j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3"): "accf46b76891d2954b893d0f91d82816", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3"), md5="accf46b76891d2954b893d0f91d82816"),
Path("j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3"): "e1f584f523336160d5c1104a61de77f3", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3"), md5="e1f584f523336160d5c1104a61de77f3"),
Path("j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3"): "f6885b25901177f0357649afe97328cc", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3"), md5="f6885b25901177f0357649afe97328cc"),
Path("j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3"): "fa057f221cbe4cf2442cd2fdb960743e", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3"), md5="fa057f221cbe4cf2442cd2fdb960743e"),
Path("j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3"): "7794ae812c64580e2ac8fc457d5cc85f", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3"), md5="7794ae812c64580e2ac8fc457d5cc85f"),
Path("j_b/[2022] Acoustic Treats/09 - Finding Home.mp3"): "adbf02eddb2090c008eb497d13ff84b9", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/09 - Finding Home.mp3"), md5="adbf02eddb2090c008eb497d13ff84b9"),
Path("j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3"): "65bb10c84366c71498161734f953e93d", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3"), md5="65bb10c84366c71498161734f953e93d"),
Path("j_b/[2022] Acoustic Treats/11 - Untold History.mp3"): "6904b2918e5dc38d9a9f72d967eb74bf", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/11 - Untold History.mp3"), md5="6904b2918e5dc38d9a9f72d967eb74bf"),
Path("j_b/[2022] Acoustic Treats/folder.jpg"): "511c43d7e939c70953cf2cd3cd437072", ExpectedDownloadFile(path=Path("j_b/[2022] Acoustic Treats/folder.jpg"), md5="511c43d7e939c70953cf2cd3cd437072"),
]
}
) )
# fmt: on # fmt: on

View file

@ -3,7 +3,8 @@ from pathlib import Path
import mergedeep import mergedeep
import pytest import pytest
from conftest import assert_debug_log 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 import ytdl_sub.downloaders.downloader
from ytdl_sub.config.config_file import ConfigFile 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(): def expected_full_channel_download():
# turn off black formatter here for readability # turn off black formatter here for readability
# fmt: off # fmt: off
return ExpectedDownload( return ExpectedDownloads(
expected_md5_file_hashes={ expected_downloads=[
# Download mapping # Download mapping
Path(".ytdl-sub-pz-download-archive.json"): "b7e7c19d2cf0277e4e42453a64fbaa90", ExpectedDownloadFile(path=Path(".ytdl-sub-pz-download-archive.json"), md5="b7e7c19d2cf0277e4e42453a64fbaa90"),
# Output directory files # Output directory files
Path("fanart.jpg"): "e6e323373c8902568e96e374817179cf", ExpectedDownloadFile(path=Path("fanart.jpg"), md5="e6e323373c8902568e96e374817179cf"),
Path("poster.jpg"): "a14c593bcc75bb8d2c7145de4767ad01", ExpectedDownloadFile(path=Path("poster.jpg"), md5="a14c593bcc75bb8d2c7145de4767ad01"),
Path("tvshow.nfo"): "83c7db96081ac5bdf289fcf396bec157", ExpectedDownloadFile(path=Path("tvshow.nfo"), md5="83c7db96081ac5bdf289fcf396bec157"),
# Entry files # Entry files
Path("Season 2010/s2010.e0813 - Oblivion Mod 'Falcor' p.1.jpg"): "b58377dfe7c39527e1990a24b36bbd77", ExpectedDownloadFile(path=Path("Season 2010/s2010.e0813 - Oblivion Mod 'Falcor' p.1.jpg"), md5="b58377dfe7c39527e1990a24b36bbd77"),
Path("Season 2010/s2010.e0813 - Oblivion Mod 'Falcor' p.1.mp4"): "931a705864c57d21d6fedebed4af6bbc", ExpectedDownloadFile(path=Path("Season 2010/s2010.e0813 - Oblivion Mod 'Falcor' p.1.mp4"), md5="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.nfo"), md5="67d8d71d048039080acbba3bce4febaa"),
Path("Season 2010/s2010.e1202 - Oblivion Mod 'Falcor' p.2.jpg"): "a5ee6247c8dce255aec79c9a51d49da4", ExpectedDownloadFile(path=Path("Season 2010/s2010.e1202 - Oblivion Mod 'Falcor' p.2.jpg"), md5="a5ee6247c8dce255aec79c9a51d49da4"),
Path("Season 2010/s2010.e1202 - Oblivion Mod 'Falcor' p.2.mp4"): "d3469b4dca7139cb3dbc38712b6796bf", ExpectedDownloadFile(path=Path("Season 2010/s2010.e1202 - Oblivion Mod 'Falcor' p.2.mp4"), md5="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.nfo"), md5="d81f49cedbd7edaee987521e89b37904"),
Path("Season 2011/s2011.e0201 - Jesse's Minecraft Server [Trailer - Feb.1].jpg"): "048a19cf0f674437351872c3f312ebf1", ExpectedDownloadFile(path=Path("Season 2011/s2011.e0201 - Jesse's Minecraft Server [Trailer - Feb.1].jpg"), md5="048a19cf0f674437351872c3f312ebf1"),
Path("Season 2011/s2011.e0201 - Jesse's Minecraft Server [Trailer - Feb.1].mp4"): "e66287b9832277b6a4d1554e29d9fdcc", ExpectedDownloadFile(path=Path("Season 2011/s2011.e0201 - Jesse's Minecraft Server [Trailer - Feb.1].mp4"), md5="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].nfo"), md5="f7c0de89038f8c491bded8a3968720a2"),
Path("Season 2011/s2011.e0227 - Jesse's Minecraft Server [Trailer - Feb.27].jpg"): None, ExpectedDownloadFile(path=Path("Season 2011/s2011.e0227 - Jesse's Minecraft Server [Trailer - Feb.27].jpg"), md5=None),
Path("Season 2011/s2011.e0227 - Jesse's Minecraft Server [Trailer - Feb.27].mp4"): "04ab5cb3cc12325d0c96a7cd04a8b91d", ExpectedDownloadFile(path=Path("Season 2011/s2011.e0227 - Jesse's Minecraft Server [Trailer - Feb.27].mp4"), md5="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].nfo"), md5="ee1eda78fa0980bc703e602b5012dd1f"),
Path("Season 2011/s2011.e0321 - Jesse's Minecraft Server [Trailer - Mar.21].jpg"): "9baaddc6b62f5b9ae3781eb4eef0e3b3", ExpectedDownloadFile(path=Path("Season 2011/s2011.e0321 - Jesse's Minecraft Server [Trailer - Mar.21].jpg"), md5="9baaddc6b62f5b9ae3781eb4eef0e3b3"),
Path("Season 2011/s2011.e0321 - Jesse's Minecraft Server [Trailer - Mar.21].mp4"): "025de6099a5c98e6397153c7a62d517d", ExpectedDownloadFile(path=Path("Season 2011/s2011.e0321 - Jesse's Minecraft Server [Trailer - Mar.21].mp4"), md5="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].nfo"), md5="61eb6369430da0ab6134d78829a7621b"),
Path("Season 2011/s2011.e0529 - Project Zombie _Official Trailer_ (IP - mc.projectzombie.beastnode.net).jpg"): "ce1df7f623fffaefe04606ecbafcfec6", ExpectedDownloadFile(path=Path("Season 2011/s2011.e0529 - Project Zombie _Official Trailer_ (IP - mc.projectzombie.beastnode.net).jpg"), md5="ce1df7f623fffaefe04606ecbafcfec6"),
Path("Season 2011/s2011.e0529 - Project Zombie _Official Trailer_ (IP - mc.projectzombie.beastnode.net).mp4"): "3d9c19835b03355d6fd5d00cd59dbe5b", ExpectedDownloadFile(path=Path("Season 2011/s2011.e0529 - Project Zombie _Official Trailer_ (IP - mc.projectzombie.beastnode.net).mp4"), md5="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).nfo"), md5="60f72b99f5c69f9e03a071a12160928f"),
Path("Season 2011/s2011.e0630 - Project Zombie _Fin.jpg"): "bc3f511915869720c37617a7de706b2b", ExpectedDownloadFile(path=Path("Season 2011/s2011.e0630 - Project Zombie _Fin.jpg"), md5="bc3f511915869720c37617a7de706b2b"),
Path("Season 2011/s2011.e0630 - Project Zombie _Fin.mp4"): "4971cb2d4fa29460361031f3fa8e1ea9", ExpectedDownloadFile(path=Path("Season 2011/s2011.e0630 - Project Zombie _Fin.mp4"), md5="4971cb2d4fa29460361031f3fa8e1ea9"),
Path("Season 2011/s2011.e0630 - Project Zombie _Fin.nfo"): "a7b5d9e57d20852f5daf360a1373bb7a", 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", ExpectedDownloadFile(path=Path("Season 2011/s2011.e1121 - Skyrim 'Ultra HD w_Mods' [PC].jpg"), md5="12babdb3b86cd868b90b60d013295f66"),
Path("Season 2011/s2011.e1121 - Skyrim 'Ultra HD w_Mods' [PC].mp4"): "55e9b0add08c48c9c66105da0def2426", ExpectedDownloadFile(path=Path("Season 2011/s2011.e1121 - Skyrim 'Ultra HD w_Mods' [PC].mp4"), md5="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].nfo"), md5="fe60e2b6b564f9316b6c7c183e1cf300"),
Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.jpg"): "82d303e16aba75acdde30b15c4154231", ExpectedDownloadFile(path=Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.jpg"), md5="82d303e16aba75acdde30b15c4154231"),
Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.mp4"): "65e4ce53ed5ec4139995469f99477a50", ExpectedDownloadFile(path=Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.mp4"), md5="65e4ce53ed5ec4139995469f99477a50"),
Path("Season 2012/s2012.e0123 - Project Zombie _Map Trailer.nfo"): "c8900adcca83c473c79a4afbc7ad2de1", 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", ExpectedDownloadFile(path=Path("Season 2013/s2013.e0719 - Project Zombie Rewind _Trailer.jpg"), md5="83b1af4c3614d262b2ad419586fff730"),
Path("Season 2013/s2013.e0719 - Project Zombie Rewind _Trailer.mp4"): "18620a8257a686beda65e54add4d4cd1", ExpectedDownloadFile(path=Path("Season 2013/s2013.e0719 - Project Zombie Rewind _Trailer.mp4"), md5="18620a8257a686beda65e54add4d4cd1"),
Path("Season 2013/s2013.e0719 - Project Zombie Rewind _Trailer.nfo"): "1c993c41d4308a6049333154d0adee16", 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", ExpectedDownloadFile(path=Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.jpg"), md5="2a24de903059f48c7d0df0476046c975"),
Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.mp4"): "82f6ee7253e1dbb83ae7215af08ffacc", ExpectedDownloadFile(path=Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.mp4"), md5="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.nfo"), md5="cc7886aae3af6b7b0facd82f95390242"),
Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"): "c8baea83b9edeb081657f1130a1031f7", ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"), md5="c8baea83b9edeb081657f1130a1031f7"),
Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"): "e733b4cc385b953b08c8eb0f47e03c1e", ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"), md5="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.nfo"), md5="2b3ccb3f1ef81ee49fe1afb88f275a09"),
} ]
) )
# fmt: on # fmt: on
@ -161,25 +162,25 @@ def recent_channel_subscription(config, subscription_name, recent_channel_subscr
def expected_recent_channel_download(): def expected_recent_channel_download():
# turn off black formatter here for readability # turn off black formatter here for readability
# fmt: off # fmt: off
return ExpectedDownload( return ExpectedDownloads(
expected_md5_file_hashes={ expected_downloads=[
# Download mapping # Download mapping
Path(".ytdl-sub-pz-download-archive.json"): "b1675ca4d9f0d4b9c2102b6749e4cdfd", ExpectedDownloadFile(path=Path(".ytdl-sub-pz-download-archive.json"), md5="b1675ca4d9f0d4b9c2102b6749e4cdfd"),
# Output directory files # Output directory files
Path("fanart.jpg"): "e6e323373c8902568e96e374817179cf", ExpectedDownloadFile(path=Path("fanart.jpg"), md5="e6e323373c8902568e96e374817179cf"),
Path("poster.jpg"): "a14c593bcc75bb8d2c7145de4767ad01", ExpectedDownloadFile(path=Path("poster.jpg"), md5="a14c593bcc75bb8d2c7145de4767ad01"),
Path("tvshow.nfo"): "83c7db96081ac5bdf289fcf396bec157", ExpectedDownloadFile(path=Path("tvshow.nfo"), md5="83c7db96081ac5bdf289fcf396bec157"),
# Recent Entry files # Recent Entry files
Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.jpg"): "2a24de903059f48c7d0df0476046c975", ExpectedDownloadFile(path=Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.jpg"), md5="2a24de903059f48c7d0df0476046c975"),
Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.mp4"): "82f6ee7253e1dbb83ae7215af08ffacc", ExpectedDownloadFile(path=Path("Season 2018/s2018.e1029 - Jesse's Minecraft Server _ Teaser Trailer.mp4"), md5="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.nfo"), md5="cc7886aae3af6b7b0facd82f95390242"),
Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"): "c8baea83b9edeb081657f1130a1031f7", ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"), md5="c8baea83b9edeb081657f1130a1031f7"),
Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"): "e733b4cc385b953b08c8eb0f47e03c1e", ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"), md5="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.nfo"), md5="2b3ccb3f1ef81ee49fe1afb88f275a09"),
} ]
) )
# fmt: on # fmt: on
@ -219,16 +220,16 @@ def recent_channel_no_vids_in_range_subscription(
def expected_recent_channel_no_vids_in_range_download(): def expected_recent_channel_no_vids_in_range_download():
# turn off black formatter here for readability # turn off black formatter here for readability
# fmt: off # fmt: off
return ExpectedDownload( return ExpectedDownloads(
expected_md5_file_hashes={ expected_downloads=[
# Download mapping # Download mapping
Path(".ytdl-sub-pz-download-archive.json"): "99914b932bd37a50b983c5e7c90ae93b", ExpectedDownloadFile(path=Path(".ytdl-sub-pz-download-archive.json"), md5="99914b932bd37a50b983c5e7c90ae93b"),
# Output directory files # Output directory files
Path("fanart.jpg"): "e6e323373c8902568e96e374817179cf", ExpectedDownloadFile(path=Path("fanart.jpg"), md5="e6e323373c8902568e96e374817179cf"),
Path("poster.jpg"): "a14c593bcc75bb8d2c7145de4767ad01", ExpectedDownloadFile(path=Path("poster.jpg"), md5="a14c593bcc75bb8d2c7145de4767ad01"),
Path("tvshow.nfo"): "83c7db96081ac5bdf289fcf396bec157", ExpectedDownloadFile(path=Path("tvshow.nfo"), md5="83c7db96081ac5bdf289fcf396bec157"),
} ]
) )
# fmt: on # fmt: on
@ -266,21 +267,21 @@ def rolling_recent_channel_subscription(
def expected_rolling_recent_channel_download(): def expected_rolling_recent_channel_download():
# turn off black formatter here for readability # turn off black formatter here for readability
# fmt: off # fmt: off
return ExpectedDownload( return ExpectedDownloads(
expected_md5_file_hashes={ expected_downloads=[
# Download mapping # Download mapping
Path(".ytdl-sub-pz-download-archive.json"): "9ae3463bd2dc39830003aba68a276df4", ExpectedDownloadFile(path=Path(".ytdl-sub-pz-download-archive.json"), md5="9ae3463bd2dc39830003aba68a276df4"),
# Output directory files # Output directory files
Path("fanart.jpg"): "e6e323373c8902568e96e374817179cf", ExpectedDownloadFile(path=Path("fanart.jpg"), md5="e6e323373c8902568e96e374817179cf"),
Path("poster.jpg"): "a14c593bcc75bb8d2c7145de4767ad01", ExpectedDownloadFile(path=Path("poster.jpg"), md5="a14c593bcc75bb8d2c7145de4767ad01"),
Path("tvshow.nfo"): "83c7db96081ac5bdf289fcf396bec157", ExpectedDownloadFile(path=Path("tvshow.nfo"), md5="83c7db96081ac5bdf289fcf396bec157"),
# Rolling Recent Entry files # Rolling Recent Entry files
Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"): "c8baea83b9edeb081657f1130a1031f7", ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.jpg"), md5="c8baea83b9edeb081657f1130a1031f7"),
Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"): "e733b4cc385b953b08c8eb0f47e03c1e", ExpectedDownloadFile(path=Path("Season 2018/s2018.e1102 - Jesse's Minecraft Server _ IP mc.jesse.id.mp4"), md5="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.nfo"), md5="2b3ccb3f1ef81ee49fe1afb88f275a09"),
} ]
) )
# fmt: on # fmt: on

View file

@ -1,7 +1,8 @@
from pathlib import Path from pathlib import Path
import pytest 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.config_file import ConfigFile
from ytdl_sub.config.preset import Preset from ytdl_sub.config.preset import Preset
@ -63,16 +64,15 @@ def playlist_subscription(config, subscription_name, subscription_dict):
@pytest.fixture @pytest.fixture
def expected_playlist_download(): def expected_playlist_download():
return ExpectedDownload( # fmt: off
expected_md5_file_hashes={ return ExpectedDownloads(
Path("JMC - Jesse's Minecraft Server.jpg"): "348e3007fc590d0b1e2f6682501b0b5f", expected_downloads=[
Path("JMC - Jesse's Minecraft Server.mkv"): [ ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server.jpg"), md5="348e3007fc590d0b1e2f6682501b0b5f"),
"6053c47a8690519b0a33c13fa4b01ac0", ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server.mkv"), md5=["6053c47a8690519b0a33c13fa4b01ac0", "3ab42b3e6be0a44deb3a9a28e6ebaf16"]),
"3ab42b3e6be0a44deb3a9a28e6ebaf16", ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server.nfo"), md5="10df5dcdb65ab18ecf21b3503c77e48b")
], ]
Path("JMC - Jesse's Minecraft Server.nfo"): "10df5dcdb65ab18ecf21b3503c77e48b",
}
) )
# fmt: on
class TestYoutubeMergePlaylist: class TestYoutubeMergePlaylist:

View file

@ -3,7 +3,8 @@ from pathlib import Path
import mergedeep import mergedeep
import pytest import pytest
from conftest import assert_debug_log 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 import ytdl_sub.downloaders.downloader
from ytdl_sub.config.config_file import ConfigFile from ytdl_sub.config.config_file import ConfigFile
@ -63,24 +64,24 @@ def playlist_subscription(config, subscription_name, subscription_dict):
def expected_playlist_download(): def expected_playlist_download():
# turn off black formatter here for readability # turn off black formatter here for readability
# fmt: off # fmt: off
return ExpectedDownload( return ExpectedDownloads(
expected_md5_file_hashes={ expected_downloads=[
# Download mapping # Download mapping
Path(".ytdl-sub-jmc-download-archive.json"): "d8e784353c7c3006cb755a034c965160", ExpectedDownloadFile(path=Path(".ytdl-sub-jmc-download-archive.json"), md5="d8e784353c7c3006cb755a034c965160"),
# Entry files # Entry files
Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].jpg"): None, ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].jpg"), md5=None),
Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].mp4"): "e66287b9832277b6a4d1554e29d9fdcc", ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].mp4"), md5="e66287b9832277b6a4d1554e29d9fdcc"),
Path("JMC - Jesse's Minecraft Server [Trailer - Feb.1].nfo"): "3d272fe58487b6011ad049b6000b046f", 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, ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Feb.27].jpg"), md5=None),
Path("JMC - Jesse's Minecraft Server [Trailer - Feb.27].mp4"): "04ab5cb3cc12325d0c96a7cd04a8b91d", ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Feb.27].mp4"), md5="04ab5cb3cc12325d0c96a7cd04a8b91d"),
Path("JMC - Jesse's Minecraft Server [Trailer - Feb.27].nfo"): "6f99af10bef67276a507d1d9770c5e92", 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, ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].jpg"), md5=None),
Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].mp4"): "025de6099a5c98e6397153c7a62d517d", ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].mp4"), md5="025de6099a5c98e6397153c7a62d517d"),
Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].nfo"): "beec3c1326654bd8c858cecf4e40977a", ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server [Trailer - Mar.21].nfo"), md5="beec3c1326654bd8c858cecf4e40977a"),
} ]
) )
# fmt: on # fmt: on
@ -118,12 +119,12 @@ def single_video_subscription(config, subscription_name, single_video_subscripti
def expected_single_video_download(): def expected_single_video_download():
# turn off black formatter here for readability # turn off black formatter here for readability
# fmt: off # fmt: off
return ExpectedDownload( return ExpectedDownloads(
expected_md5_file_hashes={ expected_downloads=[
Path("JMC - Oblivion Mod 'Falcor' p.1.jpg"): None, ExpectedDownloadFile(path=Path("JMC - Oblivion Mod 'Falcor' p.1.jpg"), md5=None),
Path("JMC - Oblivion Mod 'Falcor' p.1.mp4"): "931a705864c57d21d6fedebed4af6bbc", ExpectedDownloadFile(path=Path("JMC - Oblivion Mod 'Falcor' p.1.mp4"), md5="931a705864c57d21d6fedebed4af6bbc"),
Path("JMC - Oblivion Mod 'Falcor' p.1.nfo"): "89f509a8a3d9003e22a9091abeeae5dc", ExpectedDownloadFile(path=Path("JMC - Oblivion Mod 'Falcor' p.1.nfo"), md5="89f509a8a3d9003e22a9091abeeae5dc"),
} ]
) )
# fmt: on # fmt: on

View file

@ -4,7 +4,8 @@ from tempfile import NamedTemporaryFile
import mergedeep import mergedeep
import pytest import pytest
from conftest import assert_debug_log 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 import ytdl_sub.downloaders.downloader
from ytdl_sub.config.config_file import ConfigFile 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(): def expected_single_video_download():
# turn off black formatter here for readability # turn off black formatter here for readability
# fmt: off # fmt: off
return ExpectedDownload( return ExpectedDownloads(
expected_md5_file_hashes={ expected_downloads=[
Path('Project Zombie - 1-6.Intro.mp4'): "eaec6f50f364b13ef1a201e736ec9c05", ExpectedDownloadFile(path=Path('Project Zombie - 1-6.Intro.mp4'), md5="eaec6f50f364b13ef1a201e736ec9c05"),
Path('Project Zombie - 2-6.Part 1.mp4'): "5850b19acb250cc13db36f80fa1bba5a", ExpectedDownloadFile(path=Path('Project Zombie - 2-6.Part 1.mp4'), md5="5850b19acb250cc13db36f80fa1bba5a"),
Path('Project Zombie - 3-6.Part 2.mp4'): "445d95eba437db6df284df7e1ab633e8", ExpectedDownloadFile(path=Path('Project Zombie - 3-6.Part 2.mp4'), md5="445d95eba437db6df284df7e1ab633e8"),
Path('Project Zombie - 4-6.Part 3.mp4'): "2b6e7532d515c9e64ed2a33d850cf199", ExpectedDownloadFile(path=Path('Project Zombie - 4-6.Part 3.mp4'), md5="2b6e7532d515c9e64ed2a33d850cf199"),
Path('Project Zombie - 5-6.Part 4.mp4'): "842bf3c4d1fcc4c5ab110635935dac66", ExpectedDownloadFile(path=Path('Project Zombie - 5-6.Part 4.mp4'), md5="842bf3c4d1fcc4c5ab110635935dac66"),
Path('Project Zombie - 6-6.Part 5.mp4'): "238de99f00f829ab72f042b79da9a33a", ExpectedDownloadFile(path=Path('Project Zombie - 6-6.Part 5.mp4'), md5="238de99f00f829ab72f042b79da9a33a"),
Path('Project Zombie - Intro.jpg'): "e87282e4115baa8b5c727fb4de15316d", ExpectedDownloadFile(path=Path('Project Zombie - Intro.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"),
Path('Project Zombie - Intro.nfo'): "ded59ac906f579312cc3cf98a57e7ea3", ExpectedDownloadFile(path=Path('Project Zombie - Intro.nfo'), md5="ded59ac906f579312cc3cf98a57e7ea3"),
Path('Project Zombie - Part 1.jpg'): "e87282e4115baa8b5c727fb4de15316d", ExpectedDownloadFile(path=Path('Project Zombie - Part 1.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"),
Path('Project Zombie - Part 1.nfo'): "70ff5cd0092b8bc22dc4db93a824789b", ExpectedDownloadFile(path=Path('Project Zombie - Part 1.nfo'), md5="70ff5cd0092b8bc22dc4db93a824789b"),
Path('Project Zombie - Part 2.jpg'): "e87282e4115baa8b5c727fb4de15316d", ExpectedDownloadFile(path=Path('Project Zombie - Part 2.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"),
Path('Project Zombie - Part 2.nfo'): "54450c18a2cbb9d6d2ee5d0a1fb3f279", ExpectedDownloadFile(path=Path('Project Zombie - Part 2.nfo'), md5="54450c18a2cbb9d6d2ee5d0a1fb3f279"),
Path('Project Zombie - Part 3.jpg'): "e87282e4115baa8b5c727fb4de15316d", ExpectedDownloadFile(path=Path('Project Zombie - Part 3.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"),
Path('Project Zombie - Part 3.nfo'): "0effb13fc4039363a95969d1048dde57", ExpectedDownloadFile(path=Path('Project Zombie - Part 3.nfo'), md5="0effb13fc4039363a95969d1048dde57"),
Path('Project Zombie - Part 4.jpg'): "e87282e4115baa8b5c727fb4de15316d", ExpectedDownloadFile(path=Path('Project Zombie - Part 4.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"),
Path('Project Zombie - Part 4.nfo'): "74bd0d7c12105469838768a0cc323a8c", ExpectedDownloadFile(path=Path('Project Zombie - Part 4.nfo'), md5="74bd0d7c12105469838768a0cc323a8c"),
Path('Project Zombie - Part 5.jpg'): "e87282e4115baa8b5c727fb4de15316d", ExpectedDownloadFile(path=Path('Project Zombie - Part 5.jpg'), md5="e87282e4115baa8b5c727fb4de15316d"),
Path('Project Zombie - Part 5.nfo'): "a8cf2e77721335ea7c18e22734e7996c", ExpectedDownloadFile(path=Path('Project Zombie - Part 5.nfo'), md5="a8cf2e77721335ea7c18e22734e7996c"),
} ]
) )
# fmt: on # fmt: on