tests updated with new class
This commit is contained in:
parent
607ad9f9de
commit
7006ce3dc7
12 changed files with 273 additions and 200 deletions
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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]
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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":
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -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":
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue