diff --git a/src/ytdl_sub/entries/base_entry.py b/src/ytdl_sub/entries/base_entry.py index 7a714961..67d4af07 100644 --- a/src/ytdl_sub/entries/base_entry.py +++ b/src/ytdl_sub/entries/base_entry.py @@ -24,6 +24,34 @@ from ytdl_sub.entries.variables.kwargs import WEBPAGE_URL # pylint: disable=no-member +def _sanitize_plex(string: str) -> str: + out = '' + for char in string: + match char: + case '0': + out += '0' + case '1': + out += '1' + case '2': + out += '2' + case '3': + out += '3' + case '4': + out += '4' + case '5': + out += '5' + case '6': + out += '6' + case '7': + out += '7' + case '8': + out += '8' + case '9': + out += '9' + case _: + out += char + return out + class BaseEntryVariables: """ Source variables are ``{variables}`` that contain metadata from downloaded media. @@ -53,6 +81,17 @@ class BaseEntryVariables: """ return sanitize_filename(self.uid) + @property + def uid_sanitized_plex(self: "BaseEntry") -> str: + """ + Returns + ------- + str + The sanitized uid with additional sanitizing for Plex. Replaces numbers with + fixed-width numbers so Plex does not recognize them as season or episode numbers. + """ + return _sanitize_plex(self.uid_sanitized) + @property def extractor(self: "BaseEntry") -> str: """ @@ -113,6 +152,17 @@ class BaseEntryVariables: """ return sanitize_filename(self.title) + @property + def title_sanitized_plex(self) -> str: + """ + Returns + ------- + str + The sanitized title with additional sanitizing for Plex. Replaces numbers with + fixed-width numbers so Plex does not recognize them as season or episode numbers. + """ + return _sanitize_plex(self.title_sanitized) + @property def webpage_url(self: "BaseEntry") -> str: """ diff --git a/src/ytdl_sub/prebuilt_presets/helpers/players.yaml b/src/ytdl_sub/prebuilt_presets/helpers/players.yaml index 62a67fa8..a0d62694 100644 --- a/src/ytdl_sub/prebuilt_presets/helpers/players.yaml +++ b/src/ytdl_sub/prebuilt_presets/helpers/players.yaml @@ -1,7 +1,21 @@ presets: + _base: + overrides: + file_uid: "{uid_sanitized}" + file_title: "{title_sanitized}" + _kodi_base: + preset: + - "_base" nfo_tags: kodi_safe: True output_directory_nfo_tags: kodi_safe: True + + _plex_base: + preset: + - "_base" + overrides: + file_uid: "{uid_sanitized_plex}" + file_title: "{title_sanitized_plex}" diff --git a/src/ytdl_sub/prebuilt_presets/tv_show/episode.yaml b/src/ytdl_sub/prebuilt_presets/tv_show/episode.yaml index 6125a032..ccf2316e 100644 --- a/src/ytdl_sub/prebuilt_presets/tv_show/episode.yaml +++ b/src/ytdl_sub/prebuilt_presets/tv_show/episode.yaml @@ -30,7 +30,7 @@ presets: episode_plot: "{webpage_url}\n\n{description}" episode_year: "{upload_year}" episode_date_standardized: "{upload_date_standardized}" - episode_file_name: "s{season_number_padded}.e{episode_number_padded} - {uid_sanitized}" + episode_file_name: "s{season_number_padded}.e{episode_number_padded} - {file_uid}" episode_file_path: "Season {season_number_padded}/{episode_file_name}" _episode_video_tags: @@ -82,7 +82,6 @@ presets: season_by_year_month__episode_by_day: preset: - - "_episode_base" - "_season_by_year_month" overrides: episode_number: "{upload_day}{upload_date_index_padded}" @@ -90,7 +89,6 @@ presets: season_by_year__episode_by_month_day: preset: - - "_episode_base" - "_season_by_year" overrides: episode_number: "{upload_month}{upload_day_padded}{upload_date_index_padded}" @@ -98,7 +96,6 @@ presets: season_by_year__episode_by_month_day_reversed: preset: - - "_episode_base" - "_season_by_year" overrides: episode_number: "{upload_day_of_year_reversed}{upload_date_index_reversed_padded}" @@ -106,7 +103,6 @@ presets: season_by_year__episode_by_download_index: preset: - - "_episode_base" - "_season_by_year" overrides: episode_number: "{download_index}" @@ -115,29 +111,21 @@ presets: ############### season_by_collection__episode_by_year_month_day: - preset: - - "_episode_base" overrides: episode_number: "{upload_year_truncated}{upload_month_padded}{upload_day_padded}{upload_date_index_padded}" episode_number_padded: "{episode_number}" season_by_collection__episode_by_year_month_day_reversed: - preset: - - "_episode_base" overrides: episode_number: "{upload_year_truncated_reversed}{upload_month_reversed_padded}{upload_day_reversed_padded}{upload_date_index_reversed_padded}" episode_number_padded: "{episode_number}" season_by_collection__episode_by_playlist_index: - preset: - - "_episode_base" overrides: episode_number: "{playlist_index}" episode_number_padded: "{playlist_index_padded6}" season_by_collection__episode_by_playlist_index_reversed: - preset: - - "_episode_base" overrides: episode_number: "{playlist_index_reversed}" episode_number_padded: "{playlist_index_reversed_padded6}" diff --git a/src/ytdl_sub/prebuilt_presets/tv_show/tv_show.yaml b/src/ytdl_sub/prebuilt_presets/tv_show/tv_show.yaml index f94db67b..316d09bc 100644 --- a/src/ytdl_sub/prebuilt_presets/tv_show/tv_show.yaml +++ b/src/ytdl_sub/prebuilt_presets/tv_show/tv_show.yaml @@ -2,6 +2,8 @@ presets: _plex_tv_show: preset: + - "_plex_base" + - "_episode_base" - "_episode_video_tags" ytdl_options: format: "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" @@ -14,6 +16,8 @@ presets: _jellyfin_tv_show: preset: + - "_base" + - "_episode_base" - "_episode_video_tags" - "_episode_nfo_tags" overrides: diff --git a/tests/unit/entries/conftest.py b/tests/unit/entries/conftest.py index 6f003ebe..0f5c83bb 100644 --- a/tests/unit/entries/conftest.py +++ b/tests/unit/entries/conftest.py @@ -130,6 +130,8 @@ def mock_entry_to_dict( "source_uploader": "abc123", "source_uploader_id": "abc123", "source_uploader_url": "https://yourname.here", + "uid_sanitized_plex": "abc123", + "title_sanitized_plex": "entry {title}", }