diff --git a/Makefile b/Makefile index 39d8939d..6bdc1e1a 100644 --- a/Makefile +++ b/Makefile @@ -14,9 +14,9 @@ else endif lint: - @-isort . - @-black . - @-pylint src/ + python3 -m isort . && \ + python3 -m black . && \ + python3 -m pylint src check_lint: isort . --check-only --diff \ && black . --check \ diff --git a/docker/root/custom-cont-init.d/defaults b/docker/root/custom-cont-init.d/defaults index e07ed6a8..cfbc0776 100644 --- a/docker/root/custom-cont-init.d/defaults +++ b/docker/root/custom-cont-init.d/defaults @@ -21,6 +21,9 @@ echo "Starting ytdl-sub..." chown -R ${PUID:-abc}:${PGID:-abc} \ /config +# always create empty cron log file on start +echo "" > "$LOGS_TO_STDOUT" + # set up cron if [ "$CRON_SCHEDULE" != "" ] ; then [[ ! -e "$CRON_SCRIPT" ]] && \ @@ -51,19 +54,15 @@ if [ "$CRON_SCHEDULE" != "" ] ; then echo "Cron enabled with schedule $CRON_SCHEDULE_CLEAN" if [ "$CRON_RUN_ON_START" = true ] ; then - echo "Running cron script on start" - . "$CRON_WRAPPER_SCRIPT" + echo "Running cron script on start in the background" + # ensure it runs as abc to respect puid/guid with delay for tail to start + su -s "/bin/bash" -c "sleep 5 && . '$CRON_WRAPPER_SCRIPT'" abc > /dev/null 2>&1 & fi else echo "Error in CRON_SCHEDULE definition, disabling cron." exit 1 fi else - echo "CRON_SCHEDULE not specified, disabling cron." - echo "# min hour day month weekday command" > /config/crontabs/abc - echo "" >> /config/crontabs/abc + echo "CRON_SCHEDULE not specified, leaving crontabs as-is. Current configuration in /config/crontabs/abc" + cat /config/crontabs/abc fi - -# always create cron log file, after cron runs -# on start to not tail it again -echo "" > "$LOGS_TO_STDOUT" diff --git a/pyproject.toml b/pyproject.toml index 80d73970..91092da8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", ] dependencies = [ - "yt-dlp[default]==2025.3.31", + "yt-dlp[default]==2025.4.30", "colorama~=0.4", "mergedeep~=1.3", "mediafile~=0.12", diff --git a/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_by_date.yaml b/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_by_date.yaml index e676ec82..bca76405 100644 --- a/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_by_date.yaml +++ b/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_by_date.yaml @@ -35,11 +35,29 @@ presets: # TV show from one or more sources. Uses {url}'s avatar and banner as poster and fanart _tv_show_by_date: - preset: "_multi_url_bilateral" + preset: + - "_multi_url_bilateral" + - "_tv_show_by_date_asserts" overrides: avatar_uncropped_thumbnail_file_name: "{tv_show_poster_file_name}" banner_uncropped_thumbnail_file_name: "{tv_show_fanart_file_name}" + _tv_show_by_date_asserts: + overrides: + s01_url: "" + s01_name: "" + assert_not_collection: >- + { + %assert( + %and( + %not( %bool(s01_url) ), + %not( %bool(s01_name) ) + ), + "Provided `s01_url` or `s01_name` variable to TV Show by Date preset when it expects `url`. Perhaps you meant to use the `TV Show Collection` preset?" + ) + } + + #################################################################################################### _season_by_year: diff --git a/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml b/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml index 888068d1..accdd395 100644 --- a/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml +++ b/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml @@ -62,6 +62,7 @@ presets: _tv_show_collection: preset: - "_tv_show_collection_bilateral" + - "_tv_show_collection_asserts" download: - url: "{collection_season_1_url}" @@ -1015,6 +1016,16 @@ presets: ytdl_options: playlist_items: "-1:0:-1" + _tv_show_collection_asserts: + overrides: + url: "" + assert_not_by_date: >- + { + %assert( + %not( %bool(url) ), + "Provided `url` to TV Show Collection preset when it expects `s01_url`. Perhaps you meant to use the `TV Show by Date` preset?" + ) + } #################################################################################################### # DEPRECATED SEASON PRESETS diff --git a/tests/unit/prebuilt_presets/__init__.py b/tests/unit/prebuilt_presets/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/prebuilt_presets/test_tv_show_by_date.py b/tests/unit/prebuilt_presets/test_tv_show_by_date.py new file mode 100644 index 00000000..f8da99a7 --- /dev/null +++ b/tests/unit/prebuilt_presets/test_tv_show_by_date.py @@ -0,0 +1,26 @@ +import re + +import pytest + +from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError +from ytdl_sub.subscriptions.subscription import Subscription + + +class TestTvShowByDatePreset: + + def test_s01_error_thrown(self, default_config): + with pytest.raises( + UserThrownRuntimeError, + match=re.escape( + "Provided `s01_url` or `s01_name` variable to TV Show by Date preset when it " + "expects `url`. Perhaps you meant to use the `TV Show Collection` preset?" + ), + ): + _ = Subscription.from_dict( + config=default_config, + preset_name="test", + preset_dict={ + "preset": "Jellyfin TV Show by Date", + "overrides": {"tv_show_directory": "abc", "s01_url": "test"}, + }, + ) diff --git a/tests/unit/prebuilt_presets/test_tv_show_collection.py b/tests/unit/prebuilt_presets/test_tv_show_collection.py new file mode 100644 index 00000000..3621f3cb --- /dev/null +++ b/tests/unit/prebuilt_presets/test_tv_show_collection.py @@ -0,0 +1,26 @@ +import re + +import pytest + +from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError +from ytdl_sub.subscriptions.subscription import Subscription + + +class TestTvShowCollectionPreset: + + def test_url_error_thrown(self, default_config): + with pytest.raises( + UserThrownRuntimeError, + match=re.escape( + "Provided `url` to TV Show Collection preset when it expects `s01_url`. " + "Perhaps you meant to use the `TV Show by Date` preset?" + ), + ): + _ = Subscription.from_dict( + config=default_config, + preset_name="test", + preset_dict={ + "preset": "Jellyfin TV Show Collection", + "overrides": {"tv_show_directory": "abc", "url": "test"}, + }, + ) diff --git a/tests/unit/validators/test_file_path_validators.py b/tests/unit/validators/test_file_path_validators.py index 467f7b80..e66a11c2 100644 --- a/tests/unit/validators/test_file_path_validators.py +++ b/tests/unit/validators/test_file_path_validators.py @@ -1,3 +1,4 @@ +import os import tempfile from pathlib import Path @@ -34,7 +35,8 @@ class TestStringFormatterFilePathValidator: Script({"file_name": formatter.format_string}).resolve().get_str("file_name") ) - assert truncated_file_path.count(".") == ext.count(".") + _, truncated_file_name = os.path.split(truncated_file_path) + assert truncated_file_name.count(".") == ext.count(".") assert str(Path(temp_dir)) in truncated_file_path assert ext in truncated_file_path