diff --git a/src/ytdl_sub/plugins/chapters.py b/src/ytdl_sub/plugins/chapters.py index 3c9bc01d..dbd756e8 100644 --- a/src/ytdl_sub/plugins/chapters.py +++ b/src/ytdl_sub/plugins/chapters.py @@ -18,7 +18,6 @@ from ytdl_sub.validators.regex_validator import RegexListValidator from ytdl_sub.validators.string_select_validator import StringSelectValidator from ytdl_sub.validators.validators import BoolValidator from ytdl_sub.validators.validators import ListValidator -from ytdl_sub.validators.validators import StringValidator SPONSORBLOCK_HIGHLIGHT_CATEGORIES: Set[str] = {"poi_highlight"} SPONSORBLOCK_CATEGORIES: Set[str] = SPONSORBLOCK_HIGHLIGHT_CATEGORIES | { @@ -95,7 +94,6 @@ class ChaptersOptions(PluginOptions): _optional_keys = { "embed_chapters", "allow_chapters_from_comments", - "embed_chapter_timestamps", "sponsorblock_categories", "remove_sponsorblock_categories", "remove_chapters_regex", @@ -119,9 +117,6 @@ class ChaptersOptions(PluginOptions): self._force_key_frames = self._validate_key_if_present( key="force_key_frames", validator=BoolValidator, default=False ).value - self._embed_chapter_timestamps = self._validate_key_if_present( - "embed_chapter_timestamps", StringValidator - ) self._allow_chapters_from_comments = self._validate_key_if_present( key="allow_chapters_from_comments", validator=BoolValidator, default=False ).value @@ -136,11 +131,6 @@ class ChaptersOptions(PluginOptions): "Cannot remove sponsorblock categories and embed chapters from comments" ) - if self._embed_chapters and self._embed_chapter_timestamps: - raise self._validation_exception( - "Cannot embed chapters from the source and from a timestamp file" - ) - @property def embed_chapters(self) -> Optional[bool]: """ @@ -197,27 +187,6 @@ class ChaptersOptions(PluginOptions): """ return self._force_key_frames - @property - def embed_chapter_timestamps(self) -> Optional[str]: - """ - Optional. The path to the file containing the timestamps to embed into the file as - chapters. Should be formatted as: - - .. code-block:: markdown - - 0:00 Intro - 0:24 Blackwater Park - 10:23 Bleak - 16:39 Jokes - 1:02:23 Ending - - This should only be used with single entity download strategies. Otherwise, an entire - playlist or channel would all the same embedded chapters. - """ - if self._embed_chapter_timestamps: - return self._embed_chapter_timestamps.value - return None - @property def allow_chapters_from_comments(self) -> bool: """ @@ -333,11 +302,6 @@ class ChaptersPlugin(Plugin[ChaptersOptions]): """ chapters = Chapters.from_empty() - if self.plugin_options.embed_chapter_timestamps and not self.is_dry_run: - chapters = Chapters.from_timestamps_file( - chapters_file_path=self.plugin_options.embed_chapter_timestamps - ) - if not _contains_any_chapters(entry) and self.plugin_options.allow_chapters_from_comments: for comment in entry.kwargs_get(COMMENTS, []): chapters = Chapters.from_string(comment.get("text", "")) @@ -368,14 +332,7 @@ class ChaptersPlugin(Plugin[ChaptersOptions]): FileMetadata outlining which chapters/SponsorBlock segments got removed """ if custom_chapters_metadata := entry.kwargs_get(YTDL_SUB_CUSTOM_CHAPTERS): - title: str = "" - - if self.plugin_options.embed_chapter_timestamps: - title = "Chapters embedded from timestamp file" - elif self.plugin_options.allow_chapters_from_comments: - title = "Chapters from comments" - - assert title, "title should not be empty" + title: str = "Chapters from comments" return FileMetadata.from_dict( value_dict=custom_chapters_metadata, title=title, diff --git a/src/ytdl_sub/utils/chapters.py b/src/ytdl_sub/utils/chapters.py index ace4393d..48ab2753 100644 --- a/src/ytdl_sub/utils/chapters.py +++ b/src/ytdl_sub/utils/chapters.py @@ -1,5 +1,4 @@ import json -import os import re import subprocess from typing import Dict @@ -8,7 +7,6 @@ from typing import Optional from typing import Tuple from ytdl_sub.entries.entry import Entry -from ytdl_sub.utils.exceptions import ValidationException from ytdl_sub.utils.file_handler import FileMetadata @@ -184,50 +182,6 @@ class Chapters: sort_dict=False, # timestamps + titles are already sorted ) - @classmethod - def from_timestamps_file(cls, chapters_file_path: str) -> "Chapters": - """ - Parameters - ---------- - chapters_file_path - Path to file containing chapters - - Raises - ------ - ValidationException - File path does not exist or contains invalid formatting - """ - if not os.path.isfile(chapters_file_path): - raise ValidationException( - f"chapter/timestamp file path '{chapters_file_path}' does not exist." - ) - - with open(chapters_file_path, "r", encoding="utf-8") as file: - lines = file.readlines() - - timestamps: List[Timestamp] = [] - titles: List[str] = [] - - for idx, line in enumerate(lines): - line_split = line.strip().split(maxsplit=1) - - # Allow the last line to be blank - if idx == len(lines) - 1 and not line.strip(): - break - - if len(line_split) != 2: - raise ValidationException( - f"Chapter/Timestamp file '{chapters_file_path}' could not parse '{line}': " - f"must be in the format of 'HH:MM:SS title" - ) - - timestamp_str, title = tuple(x for x in line_split) - - timestamps.append(Timestamp.from_str(timestamp_str)) - titles.append(title) - - return cls(timestamps=timestamps, titles=titles) - @classmethod def from_string(cls, input_str: str) -> "Chapters": """ diff --git a/tests/e2e/plugins/test_chapters.py b/tests/e2e/plugins/test_chapters.py index 95149c02..69d5fe29 100644 --- a/tests/e2e/plugins/test_chapters.py +++ b/tests/e2e/plugins/test_chapters.py @@ -86,45 +86,6 @@ class TestChapters: ], ) - @pytest.mark.parametrize("dry_run", [True, False]) - def test_chapters_from_timestamp_file_with_subs( - self, - music_video_config, - sponsorblock_and_subs_preset_dict, - timestamps_file_path, - output_directory, - dry_run, - ): - # Test chapters and video tags, throw in a video tag with special chars while we are at it - sponsorblock_and_subs_preset_dict["chapters"] = { - "embed_chapters": False, - "embed_chapter_timestamps": timestamps_file_path, - } - sponsorblock_and_subs_preset_dict["video_tags"] = { - "tags": {"description": "🎸 / ' \" \n newline?"} - } - - subscription = Subscription.from_dict( - config=music_video_config, - preset_name="chapters_from_timestamps_with_subs", - preset_dict=sponsorblock_and_subs_preset_dict, - ) - - transaction_log = subscription.download(dry_run=dry_run) - assert_transaction_log_matches( - output_directory=output_directory, - transaction_log=transaction_log, - transaction_log_summary_file_name="plugins/test_chapters_from_ts_with_subs.txt", - ) - assert_expected_downloads( - output_directory=output_directory, - dry_run=dry_run, - expected_download_summary_file_name="plugins/test_chapters_from_ts_with_subs.json", - ignore_md5_hashes_for=[ - "JMC/JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.mp4" - ], - ) - @pytest.mark.parametrize("dry_run", [True, False]) def test_chapters_from_comments( self,