ytdl-sub 2025.12.8__tar.gz → 2026.1.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/PKG-INFO +2 -2
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/pyproject.toml +1 -1
- ytdl_sub-2026.1.11/src/ytdl_sub/__init__.py +1 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/overrides.py +47 -16
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/plugin/preset_plugins.py +33 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/preset.py +36 -8
- ytdl_sub-2026.1.11/src/ytdl_sub/config/validators/variable_validation.py +94 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/downloaders/url/downloader.py +20 -12
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/downloaders/url/validators.py +16 -3
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/script/variable_types.py +1 -9
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/variables/override_variables.py +1 -4
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/helpers/download_deletion_options.yaml +1 -2
- ytdl_sub-2026.1.11/src/ytdl_sub/prebuilt_presets/helpers/url.yaml +177 -0
- ytdl_sub-2026.1.11/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml +111 -0
- ytdl_sub-2026.1.11/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml +1327 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/numeric_functions.py +17 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/parser.py +5 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/script.py +133 -43
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/types/resolvable.py +8 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/types/variable_dependency.py +29 -2
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/utils/name_validation.py +21 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/subscriptions/base_subscription.py +21 -3
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/script.py +36 -3
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/string_formatter_validators.py +77 -31
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/validators.py +3 -13
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub.egg-info/PKG-INFO +2 -2
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub.egg-info/requires.txt +1 -1
- ytdl_sub-2025.12.8/src/ytdl_sub/__init__.py +0 -1
- ytdl_sub-2025.12.8/src/ytdl_sub/config/validators/variable_validation.py +0 -215
- ytdl_sub-2025.12.8/src/ytdl_sub/prebuilt_presets/helpers/url.yaml +0 -1049
- ytdl_sub-2025.12.8/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml +0 -210
- ytdl_sub-2025.12.8/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml +0 -5693
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/LICENSE +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/README.md +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/setup.cfg +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/cli/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/cli/entrypoint.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/cli/output_summary.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/cli/output_transaction_log.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/cli/parsers/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/cli/parsers/cli_to_sub.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/cli/parsers/dl.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/cli/parsers/main.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/config_file.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/config_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/defaults.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/plugin/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/plugin/plugin.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/plugin/plugin_mapping.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/plugin/plugin_operation.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/preset_options.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/validators/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/config/validators/options.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/downloaders/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/downloaders/info_json/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/downloaders/info_json/info_json_downloader.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/downloaders/source_plugin.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/downloaders/url/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/downloaders/ytdl_options_builder.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/downloaders/ytdlp.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/base_entry.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/entry.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/entry_parent.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/script/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/script/custom_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/script/function_scripts.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/script/variable_definitions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/variables/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/main.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/audio_extract.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/chapters.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/date_range.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/embed_thumbnail.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/file_convert.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/filter_exclude.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/filter_include.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/format.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/internal/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/internal/view.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/match_filters.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/music_tags.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/nfo_tags.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/output_directory_nfo_tags.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/split_by_chapters.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/square_thumbnail.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/static_nfo_tags.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/subtitles.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/throttle_protection.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/plugins/video_tags.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/helpers/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/helpers/filter_duration.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/helpers/filter_keywords.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/helpers/media_quality.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/helpers/players.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/helpers/throttle_protection.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/helpers/url_bilateral.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/internal/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/internal/view.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/music/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/music/albums_from_chapters.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/music/albums_from_playlists.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/music/singles.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/music/soundcloud.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/music_videos/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/music_videos/music_video_base.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/music_videos/music_video_extras.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/music_videos/music_videos.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/tv_show/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/tv_show/episode.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/tv_show/tv_show.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_by_date.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/array_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/boolean_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/conditional_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/date_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/error_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/json_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/map_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/print_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/regex_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/functions/string_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/script_output.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/types/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/types/array.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/types/function.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/types/map.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/types/syntax_tree.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/types/variable.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/utils/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/utils/exception_formatters.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/utils/exceptions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/script/utils/type_checking.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/subscriptions/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/subscriptions/subscription.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/subscriptions/subscription_download.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/subscriptions/subscription_validators.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/subscriptions/subscription_ytdl_options.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/thread/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/thread/log_entries_downloaded_listener.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/chapters.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/datetime.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/exceptions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/ffmpeg.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/file_handler.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/file_lock.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/file_path.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/logger.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/retry.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/scriptable.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/subtitles.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/system.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/thumbnail.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/xml.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/utils/yaml.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/audo_codec_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/file_path_validators.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/nfo_validators.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/regex_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/source_variable_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/strict_dict_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/string_datetime.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/validators/string_select_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/ytdl_additions/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/ytdl_additions/enhanced_download_archive.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub.egg-info/SOURCES.txt +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub.egg-info/dependency_links.txt +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub.egg-info/entry_points.txt +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ytdl-sub
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2026.1.11
|
|
4
4
|
Summary: Automate downloading metadata generation with YoutubeDL
|
|
5
5
|
Author: Jesse Bannon
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -703,7 +703,7 @@ Requires-Dist: black==24.10.0; extra == "lint"
|
|
|
703
703
|
Requires-Dist: isort==7.0.0; extra == "lint"
|
|
704
704
|
Requires-Dist: pylint==4.0.1; extra == "lint"
|
|
705
705
|
Provides-Extra: docs
|
|
706
|
-
Requires-Dist: sphinx<
|
|
706
|
+
Requires-Dist: sphinx<10,>=7; extra == "docs"
|
|
707
707
|
Requires-Dist: sphinx-rtd-theme<4,>=2; extra == "docs"
|
|
708
708
|
Requires-Dist: sphinx-book-theme~=1.0; extra == "docs"
|
|
709
709
|
Requires-Dist: sphinx-copybutton~=0.5; extra == "docs"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__pypi_version__ = "2026.01.11";__local_version__ = "2026.01.11+41a5bf6"
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
from typing import Dict
|
|
3
|
+
from typing import Iterable
|
|
3
4
|
from typing import Optional
|
|
4
5
|
from typing import Set
|
|
5
6
|
|
|
6
|
-
import mergedeep
|
|
7
|
-
|
|
8
7
|
from ytdl_sub.entries.entry import Entry
|
|
9
8
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
|
10
9
|
from ytdl_sub.entries.variables.override_variables import REQUIRED_OVERRIDE_VARIABLE_NAMES
|
|
11
10
|
from ytdl_sub.entries.variables.override_variables import OverrideHelpers
|
|
12
11
|
from ytdl_sub.script.parser import parse
|
|
13
12
|
from ytdl_sub.script.script import Script
|
|
13
|
+
from ytdl_sub.script.types.function import BuiltInFunction
|
|
14
14
|
from ytdl_sub.script.types.resolvable import Resolvable
|
|
15
|
+
from ytdl_sub.script.types.resolvable import String
|
|
16
|
+
from ytdl_sub.script.types.syntax_tree import SyntaxTree
|
|
15
17
|
from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved
|
|
16
18
|
from ytdl_sub.utils.exceptions import InvalidVariableNameException
|
|
17
19
|
from ytdl_sub.utils.exceptions import StringFormattingException
|
|
@@ -88,6 +90,24 @@ class Overrides(UnstructuredDictFormatterValidator, Scriptable):
|
|
|
88
90
|
|
|
89
91
|
return True
|
|
90
92
|
|
|
93
|
+
def ensure_variable_names_not_a_plugin(self, plugin_names: Iterable[str]) -> None:
|
|
94
|
+
"""
|
|
95
|
+
Throws an error if an override variable or function has the same name as a
|
|
96
|
+
preset key. This is to avoid confusion when accidentally defining things in
|
|
97
|
+
overrides that are meant to be in the preset.
|
|
98
|
+
"""
|
|
99
|
+
for name in self.keys:
|
|
100
|
+
if name.startswith("%"):
|
|
101
|
+
name = name[1:]
|
|
102
|
+
|
|
103
|
+
if name in plugin_names:
|
|
104
|
+
raise self._validation_exception(
|
|
105
|
+
f"Override variable with name {name} cannot be used since it is"
|
|
106
|
+
" the name of a plugin. Perhaps you meant to define it as a plugin? If so,"
|
|
107
|
+
" indent it left to make it at the same level as overrides.",
|
|
108
|
+
exception_class=InvalidVariableNameException,
|
|
109
|
+
)
|
|
110
|
+
|
|
91
111
|
def ensure_variable_name_valid(self, name: str) -> None:
|
|
92
112
|
"""
|
|
93
113
|
Ensures the variable name does not collide with any entry variables or built-in functions.
|
|
@@ -115,29 +135,35 @@ class Overrides(UnstructuredDictFormatterValidator, Scriptable):
|
|
|
115
135
|
)
|
|
116
136
|
|
|
117
137
|
def initial_variables(
|
|
118
|
-
self, unresolved_variables: Optional[Dict[str,
|
|
119
|
-
) -> Dict[str,
|
|
138
|
+
self, unresolved_variables: Optional[Dict[str, SyntaxTree]] = None
|
|
139
|
+
) -> Dict[str, SyntaxTree]:
|
|
120
140
|
"""
|
|
121
141
|
Returns
|
|
122
142
|
-------
|
|
123
143
|
Variables and format strings for all Override variables + additional variables (Optional)
|
|
124
144
|
"""
|
|
125
|
-
initial_variables: Dict[str,
|
|
126
|
-
|
|
127
|
-
initial_variables
|
|
128
|
-
|
|
129
|
-
unresolved_variables if unresolved_variables else {},
|
|
130
|
-
)
|
|
131
|
-
return ScriptUtils.add_sanitized_variables(initial_variables)
|
|
145
|
+
initial_variables: Dict[str, SyntaxTree] = self.dict_with_parsed_format_strings
|
|
146
|
+
if unresolved_variables:
|
|
147
|
+
initial_variables |= unresolved_variables
|
|
148
|
+
return ScriptUtils.add_sanitized_parsed_variables(initial_variables)
|
|
132
149
|
|
|
133
150
|
def initialize_script(self, unresolved_variables: Set[str]) -> "Overrides":
|
|
134
151
|
"""
|
|
135
152
|
Initialize the override script with any unresolved variables
|
|
136
153
|
"""
|
|
137
|
-
self.script.
|
|
154
|
+
self.script.add_parsed(
|
|
138
155
|
self.initial_variables(
|
|
139
156
|
unresolved_variables={
|
|
140
|
-
var_name:
|
|
157
|
+
var_name: SyntaxTree(
|
|
158
|
+
ast=[
|
|
159
|
+
BuiltInFunction(
|
|
160
|
+
name="throw",
|
|
161
|
+
args=[
|
|
162
|
+
String(f"Plugin variable {var_name} has not been created yet")
|
|
163
|
+
],
|
|
164
|
+
)
|
|
165
|
+
]
|
|
166
|
+
)
|
|
141
167
|
for var_name in unresolved_variables
|
|
142
168
|
}
|
|
143
169
|
)
|
|
@@ -212,20 +238,25 @@ class Overrides(UnstructuredDictFormatterValidator, Scriptable):
|
|
|
212
238
|
def apply_overrides_formatter_to_native(
|
|
213
239
|
self,
|
|
214
240
|
formatter: OverridesStringFormatterValidator,
|
|
241
|
+
function_overrides: Optional[Dict[str, str]] = None,
|
|
215
242
|
) -> Any:
|
|
216
243
|
"""
|
|
217
244
|
Parameters
|
|
218
245
|
----------
|
|
219
246
|
formatter
|
|
220
247
|
Overrides formatter to apply
|
|
248
|
+
function_overrides
|
|
249
|
+
Optional. Explicit values to override the overrides themselves and source variables
|
|
221
250
|
|
|
222
251
|
Returns
|
|
223
252
|
-------
|
|
224
253
|
The native python form of the resolved variable
|
|
225
254
|
"""
|
|
226
|
-
return
|
|
227
|
-
|
|
228
|
-
|
|
255
|
+
return formatter.post_process_native(
|
|
256
|
+
self._apply_to_resolvable(
|
|
257
|
+
formatter=formatter, entry=None, function_overrides=function_overrides
|
|
258
|
+
).native
|
|
259
|
+
)
|
|
229
260
|
|
|
230
261
|
def evaluate_boolean(
|
|
231
262
|
self, formatter: StringFormatterValidator, entry: Optional[Entry] = None
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
from typing import Iterable
|
|
1
2
|
from typing import List
|
|
2
3
|
from typing import Optional
|
|
4
|
+
from typing import Set
|
|
3
5
|
from typing import Tuple
|
|
4
6
|
from typing import Type
|
|
5
7
|
|
|
@@ -44,3 +46,34 @@ class PresetPlugins:
|
|
|
44
46
|
if plugin_type in plugin_option_types:
|
|
45
47
|
return self.plugin_options[plugin_option_types.index(plugin_type)]
|
|
46
48
|
return None
|
|
49
|
+
|
|
50
|
+
def get_added_and_modified_variables(
|
|
51
|
+
self, additional_options: List[OptionsValidator]
|
|
52
|
+
) -> Iterable[Tuple[OptionsValidator, Set[str], Set[str]]]:
|
|
53
|
+
"""
|
|
54
|
+
Iterates and returns the plugin options, added variables, modified variables
|
|
55
|
+
"""
|
|
56
|
+
for plugin_options in self.plugin_options + additional_options:
|
|
57
|
+
added_variables: Set[str] = set()
|
|
58
|
+
modified_variables: Set[str] = set()
|
|
59
|
+
|
|
60
|
+
for plugin_added_variables in plugin_options.added_variables(
|
|
61
|
+
unresolved_variables=set(),
|
|
62
|
+
).values():
|
|
63
|
+
added_variables |= set(plugin_added_variables)
|
|
64
|
+
|
|
65
|
+
for plugin_modified_variables in plugin_options.modified_variables().values():
|
|
66
|
+
modified_variables = plugin_modified_variables
|
|
67
|
+
|
|
68
|
+
yield plugin_options, added_variables, modified_variables
|
|
69
|
+
|
|
70
|
+
def get_all_variables(self, additional_options: List[OptionsValidator]) -> Set[str]:
|
|
71
|
+
"""
|
|
72
|
+
Returns set of all added and modified variables' names.
|
|
73
|
+
"""
|
|
74
|
+
all_variables: Set[str] = set()
|
|
75
|
+
for _, added, modified in self.get_added_and_modified_variables(additional_options):
|
|
76
|
+
all_variables.update(added)
|
|
77
|
+
all_variables.update(modified)
|
|
78
|
+
|
|
79
|
+
return all_variables
|
|
@@ -2,6 +2,7 @@ import copy
|
|
|
2
2
|
from typing import Any
|
|
3
3
|
from typing import Dict
|
|
4
4
|
from typing import List
|
|
5
|
+
from typing import Set
|
|
5
6
|
|
|
6
7
|
from mergedeep import mergedeep
|
|
7
8
|
|
|
@@ -11,7 +12,6 @@ from ytdl_sub.config.plugin.plugin_mapping import PluginMapping
|
|
|
11
12
|
from ytdl_sub.config.plugin.preset_plugins import PresetPlugins
|
|
12
13
|
from ytdl_sub.config.preset_options import OutputOptions
|
|
13
14
|
from ytdl_sub.config.preset_options import YTDLOptions
|
|
14
|
-
from ytdl_sub.config.validators.variable_validation import VariableValidation
|
|
15
15
|
from ytdl_sub.downloaders.url.validators import MultiUrlValidator
|
|
16
16
|
from ytdl_sub.prebuilt_presets import PREBUILT_PRESET_NAMES
|
|
17
17
|
from ytdl_sub.prebuilt_presets import PUBLISHED_PRESET_NAMES
|
|
@@ -172,6 +172,37 @@ class Preset(_PresetShell):
|
|
|
172
172
|
mergedeep.merge({}, *reversed(presets_to_merge), strategy=mergedeep.Strategy.ADDITIVE)
|
|
173
173
|
)
|
|
174
174
|
|
|
175
|
+
def _initialize_overrides_script(self, overrides: Overrides) -> Overrides:
|
|
176
|
+
"""
|
|
177
|
+
Do some gymnastics to initialize the Overrides script.
|
|
178
|
+
"""
|
|
179
|
+
unresolved_variables: Set[str] = set()
|
|
180
|
+
|
|
181
|
+
for (
|
|
182
|
+
plugin_options,
|
|
183
|
+
added_variables,
|
|
184
|
+
modified_variables,
|
|
185
|
+
) in self.plugins.get_added_and_modified_variables(
|
|
186
|
+
additional_options=[self.downloader_options, self.output_options]
|
|
187
|
+
):
|
|
188
|
+
for added_variable in added_variables:
|
|
189
|
+
if not overrides.ensure_added_plugin_variable_valid(added_variable=added_variable):
|
|
190
|
+
# pylint: disable=protected-access
|
|
191
|
+
raise plugin_options._validation_exception(
|
|
192
|
+
f"Cannot use the variable name {added_variable} because it exists as a"
|
|
193
|
+
" built-in ytdl-sub variable name."
|
|
194
|
+
)
|
|
195
|
+
# pylint: enable=protected-access
|
|
196
|
+
|
|
197
|
+
# Set unresolved as variables that are added but do not exist as
|
|
198
|
+
# entry/override variables since they are created at run-time
|
|
199
|
+
unresolved_variables |= added_variables | modified_variables
|
|
200
|
+
|
|
201
|
+
# Initialize overrides with unresolved variables + modified variables to throw an error.
|
|
202
|
+
# For modified variables, this is to prevent a resolve(update=True) to setting any
|
|
203
|
+
# dependencies until it has been explicitly added
|
|
204
|
+
return overrides.initialize_script(unresolved_variables=unresolved_variables)
|
|
205
|
+
|
|
175
206
|
def __init__(self, config: ConfigValidator, name: str, value: Any):
|
|
176
207
|
super().__init__(name=name, value=value)
|
|
177
208
|
|
|
@@ -192,13 +223,10 @@ class Preset(_PresetShell):
|
|
|
192
223
|
)
|
|
193
224
|
|
|
194
225
|
self.plugins: PresetPlugins = self._validate_and_get_plugins()
|
|
195
|
-
self.overrides = self.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
output_options=self.output_options,
|
|
200
|
-
plugins=self.plugins,
|
|
201
|
-
).initialize_preset_overrides(overrides=self.overrides).ensure_proper_usage()
|
|
226
|
+
self.overrides = self._initialize_overrides_script(
|
|
227
|
+
overrides=self._validate_key(key="overrides", validator=Overrides, default={})
|
|
228
|
+
)
|
|
229
|
+
self.overrides.ensure_variable_names_not_a_plugin(plugin_names=PRESET_KEYS)
|
|
202
230
|
|
|
203
231
|
@property
|
|
204
232
|
def name(self) -> str:
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from typing import Dict
|
|
2
|
+
|
|
3
|
+
from ytdl_sub.config.overrides import Overrides
|
|
4
|
+
from ytdl_sub.config.plugin.plugin_mapping import PluginMapping
|
|
5
|
+
from ytdl_sub.config.plugin.plugin_operation import PluginOperation
|
|
6
|
+
from ytdl_sub.config.plugin.preset_plugins import PresetPlugins
|
|
7
|
+
from ytdl_sub.config.preset_options import OutputOptions
|
|
8
|
+
from ytdl_sub.config.validators.options import OptionsValidator
|
|
9
|
+
from ytdl_sub.downloaders.url.validators import MultiUrlValidator
|
|
10
|
+
from ytdl_sub.validators.string_formatter_validators import validate_formatters
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class VariableValidation:
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
overrides: Overrides,
|
|
17
|
+
downloader_options: MultiUrlValidator,
|
|
18
|
+
output_options: OutputOptions,
|
|
19
|
+
plugins: PresetPlugins,
|
|
20
|
+
):
|
|
21
|
+
self.overrides = overrides
|
|
22
|
+
self.downloader_options = downloader_options
|
|
23
|
+
self.output_options = output_options
|
|
24
|
+
self.plugins = plugins
|
|
25
|
+
|
|
26
|
+
self.script = self.overrides.script
|
|
27
|
+
self.unresolved_variables = self.plugins.get_all_variables(
|
|
28
|
+
additional_options=[self.output_options, self.downloader_options]
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def _add_variables(self, plugin_op: PluginOperation, options: OptionsValidator) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Add dummy variables for script validation
|
|
34
|
+
"""
|
|
35
|
+
added_variables = options.added_variables(
|
|
36
|
+
unresolved_variables=self.unresolved_variables,
|
|
37
|
+
).get(plugin_op, set())
|
|
38
|
+
modified_variables = options.modified_variables().get(plugin_op, set())
|
|
39
|
+
|
|
40
|
+
self.unresolved_variables -= added_variables | modified_variables
|
|
41
|
+
|
|
42
|
+
def ensure_proper_usage(self) -> Dict:
|
|
43
|
+
"""
|
|
44
|
+
Validate variables resolve as plugins are executed, and return
|
|
45
|
+
a mock script which contains actualized added variables from the plugins
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
resolved_subscription: Dict = {}
|
|
49
|
+
|
|
50
|
+
self._add_variables(PluginOperation.DOWNLOADER, options=self.downloader_options)
|
|
51
|
+
|
|
52
|
+
# Always add output options first
|
|
53
|
+
self._add_variables(PluginOperation.MODIFY_ENTRY_METADATA, options=self.output_options)
|
|
54
|
+
|
|
55
|
+
# Metadata variables to be added
|
|
56
|
+
for plugin_options in PluginMapping.order_options_by(
|
|
57
|
+
self.plugins.zipped(), PluginOperation.MODIFY_ENTRY_METADATA
|
|
58
|
+
):
|
|
59
|
+
self._add_variables(PluginOperation.MODIFY_ENTRY_METADATA, options=plugin_options)
|
|
60
|
+
|
|
61
|
+
for plugin_options in PluginMapping.order_options_by(
|
|
62
|
+
self.plugins.zipped(), PluginOperation.MODIFY_ENTRY
|
|
63
|
+
):
|
|
64
|
+
self._add_variables(PluginOperation.MODIFY_ENTRY, options=plugin_options)
|
|
65
|
+
|
|
66
|
+
# Validate that any formatter in the plugin options can resolve
|
|
67
|
+
resolved_subscription |= validate_formatters(
|
|
68
|
+
script=self.script,
|
|
69
|
+
unresolved_variables=self.unresolved_variables,
|
|
70
|
+
validator=plugin_options,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
resolved_subscription |= validate_formatters(
|
|
74
|
+
script=self.script,
|
|
75
|
+
unresolved_variables=self.unresolved_variables,
|
|
76
|
+
validator=self.output_options,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# TODO: make this a function
|
|
80
|
+
raw_download_output = validate_formatters(
|
|
81
|
+
script=self.script,
|
|
82
|
+
unresolved_variables=self.unresolved_variables,
|
|
83
|
+
validator=self.downloader_options.urls,
|
|
84
|
+
)
|
|
85
|
+
resolved_subscription["download"] = []
|
|
86
|
+
for url_output in raw_download_output["download"]:
|
|
87
|
+
if isinstance(url_output["url"], list):
|
|
88
|
+
url_output["url"] = [url for url in url_output["url"] if bool(url)]
|
|
89
|
+
|
|
90
|
+
if url_output["url"]:
|
|
91
|
+
resolved_subscription["download"].append(url_output)
|
|
92
|
+
|
|
93
|
+
assert not self.unresolved_variables
|
|
94
|
+
return resolved_subscription
|
|
@@ -52,12 +52,12 @@ class UrlDownloaderBasePluginExtension(SourcePluginExtension[MultiUrlValidator])
|
|
|
52
52
|
|
|
53
53
|
if 0 <= input_url_idx < len(self.plugin_options.urls.list):
|
|
54
54
|
validator = self.plugin_options.urls.list[input_url_idx]
|
|
55
|
-
if self.overrides.
|
|
55
|
+
if entry_input_url in self.overrides.apply_overrides_formatter_to_native(validator.url):
|
|
56
56
|
return validator
|
|
57
57
|
|
|
58
58
|
# Match the first validator based on the URL, if one exists
|
|
59
59
|
for validator in self.plugin_options.urls.list:
|
|
60
|
-
if self.overrides.
|
|
60
|
+
if entry_input_url in self.overrides.apply_overrides_formatter_to_native(validator.url):
|
|
61
61
|
return validator
|
|
62
62
|
|
|
63
63
|
# Return the first validator if none exist
|
|
@@ -487,19 +487,27 @@ class MultiUrlDownloader(SourcePlugin[MultiUrlValidator]):
|
|
|
487
487
|
# download the bottom-most urls first since they are top-priority
|
|
488
488
|
for idx, url_validator in reversed(list(enumerate(self.collection.urls.list))):
|
|
489
489
|
# URLs can be empty. If they are, then skip
|
|
490
|
-
if not (
|
|
490
|
+
if not (urls := self.overrides.apply_overrides_formatter_to_native(url_validator.url)):
|
|
491
491
|
continue
|
|
492
492
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
493
|
+
assert isinstance(urls, list)
|
|
494
|
+
|
|
495
|
+
for url in reversed(urls):
|
|
496
|
+
assert isinstance(url, str)
|
|
497
|
+
|
|
498
|
+
if not url:
|
|
499
|
+
continue
|
|
500
|
+
|
|
501
|
+
for entry in self._download_metadata(url=url, validator=url_validator):
|
|
502
|
+
entry.initialize_script(self.overrides).add(
|
|
503
|
+
{
|
|
504
|
+
v.ytdl_sub_input_url: url,
|
|
505
|
+
v.ytdl_sub_input_url_index: idx,
|
|
506
|
+
v.ytdl_sub_input_url_count: len(self.collection.urls.list),
|
|
507
|
+
}
|
|
508
|
+
)
|
|
501
509
|
|
|
502
|
-
|
|
510
|
+
yield entry
|
|
503
511
|
|
|
504
512
|
def download(self, entry: Entry) -> Optional[Entry]:
|
|
505
513
|
"""
|
|
@@ -21,7 +21,7 @@ class UrlThumbnailValidator(StrictDictValidator):
|
|
|
21
21
|
def __init__(self, name, value):
|
|
22
22
|
super().__init__(name, value)
|
|
23
23
|
|
|
24
|
-
self.
|
|
24
|
+
self._thumb_name = self._validate_key(key="name", validator=StringFormatterValidator)
|
|
25
25
|
self._uid = self._validate_key(key="uid", validator=OverridesStringFormatterValidator)
|
|
26
26
|
|
|
27
27
|
@property
|
|
@@ -29,7 +29,7 @@ class UrlThumbnailValidator(StrictDictValidator):
|
|
|
29
29
|
"""
|
|
30
30
|
File name for the thumbnail
|
|
31
31
|
"""
|
|
32
|
-
return self.
|
|
32
|
+
return self._thumb_name
|
|
33
33
|
|
|
34
34
|
@property
|
|
35
35
|
def uid(self) -> OverridesStringFormatterValidator:
|
|
@@ -43,6 +43,19 @@ class UrlThumbnailListValidator(ListValidator[UrlThumbnailValidator]):
|
|
|
43
43
|
_inner_list_type = UrlThumbnailValidator
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
class OverridesOneOrManyUrlValidator(OverridesStringFormatterValidator):
|
|
47
|
+
def post_process_native(self, resolved: Any) -> Any:
|
|
48
|
+
if isinstance(resolved, str):
|
|
49
|
+
return [resolved]
|
|
50
|
+
if isinstance(resolved, list):
|
|
51
|
+
for value in resolved:
|
|
52
|
+
if not isinstance(value, str):
|
|
53
|
+
raise self._validation_exception("Must be a string or an array of strings.")
|
|
54
|
+
return resolved
|
|
55
|
+
|
|
56
|
+
raise self._validation_exception("Must be a string or an array of strings.")
|
|
57
|
+
|
|
58
|
+
|
|
46
59
|
class UrlValidator(StrictDictValidator):
|
|
47
60
|
_required_keys = {"url"}
|
|
48
61
|
_optional_keys = {
|
|
@@ -68,7 +81,7 @@ class UrlValidator(StrictDictValidator):
|
|
|
68
81
|
super().__init__(name, value)
|
|
69
82
|
|
|
70
83
|
# TODO: url validate using yt-dlp IE
|
|
71
|
-
self._url = self._validate_key(key="url", validator=
|
|
84
|
+
self._url = self._validate_key(key="url", validator=OverridesOneOrManyUrlValidator)
|
|
72
85
|
self._variables = self._validate_key_if_present(
|
|
73
86
|
key="variables", validator=DictFormatterValidator, default={}
|
|
74
87
|
)
|
|
@@ -22,7 +22,6 @@ VariableT = TypeVar("VariableT", bound="Variable")
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def _get(
|
|
25
|
-
cast: str,
|
|
26
25
|
metadata_variable_name: str,
|
|
27
26
|
metadata_key: str,
|
|
28
27
|
variable_name: Optional[str],
|
|
@@ -47,7 +46,7 @@ def _get(
|
|
|
47
46
|
return as_type(
|
|
48
47
|
variable_name=variable_name or metadata_key,
|
|
49
48
|
metadata_key=metadata_key,
|
|
50
|
-
definition=f"{{
|
|
49
|
+
definition=f"{{ {out} }}",
|
|
51
50
|
)
|
|
52
51
|
|
|
53
52
|
|
|
@@ -182,7 +181,6 @@ class MapMetadataVariable(MetadataVariable, MapVariable):
|
|
|
182
181
|
Creates a map variable from entry metadata
|
|
183
182
|
"""
|
|
184
183
|
return _get(
|
|
185
|
-
"map",
|
|
186
184
|
metadata_variable_name=ENTRY_METADATA_VARIABLE_NAME,
|
|
187
185
|
metadata_key=metadata_key,
|
|
188
186
|
variable_name=variable_name,
|
|
@@ -204,7 +202,6 @@ class ArrayMetadataVariable(MetadataVariable, ArrayVariable):
|
|
|
204
202
|
Creates an array variable from entry metadata
|
|
205
203
|
"""
|
|
206
204
|
return _get(
|
|
207
|
-
"array",
|
|
208
205
|
metadata_variable_name=ENTRY_METADATA_VARIABLE_NAME,
|
|
209
206
|
metadata_key=metadata_key,
|
|
210
207
|
variable_name=variable_name,
|
|
@@ -226,7 +223,6 @@ class StringMetadataVariable(MetadataVariable, StringVariable):
|
|
|
226
223
|
Creates a string variable from entry metadata
|
|
227
224
|
"""
|
|
228
225
|
return _get(
|
|
229
|
-
"string",
|
|
230
226
|
metadata_variable_name=ENTRY_METADATA_VARIABLE_NAME,
|
|
231
227
|
metadata_key=metadata_key,
|
|
232
228
|
variable_name=variable_name,
|
|
@@ -245,7 +241,6 @@ class StringMetadataVariable(MetadataVariable, StringVariable):
|
|
|
245
241
|
Creates a string variable from playlist metadata
|
|
246
242
|
"""
|
|
247
243
|
return _get(
|
|
248
|
-
"string",
|
|
249
244
|
metadata_variable_name=PLAYLIST_METADATA_VARIABLE_NAME,
|
|
250
245
|
metadata_key=metadata_key,
|
|
251
246
|
variable_name=variable_name,
|
|
@@ -264,7 +259,6 @@ class StringMetadataVariable(MetadataVariable, StringVariable):
|
|
|
264
259
|
Creates a string variable from source metadata
|
|
265
260
|
"""
|
|
266
261
|
return _get(
|
|
267
|
-
"string",
|
|
268
262
|
metadata_variable_name=SOURCE_METADATA_VARIABLE_NAME,
|
|
269
263
|
metadata_key=metadata_key,
|
|
270
264
|
variable_name=variable_name,
|
|
@@ -301,7 +295,6 @@ class IntegerMetadataVariable(MetadataVariable, IntegerVariable):
|
|
|
301
295
|
Creates an int variable from entry metadata
|
|
302
296
|
"""
|
|
303
297
|
return _get(
|
|
304
|
-
"int",
|
|
305
298
|
metadata_variable_name=ENTRY_METADATA_VARIABLE_NAME,
|
|
306
299
|
metadata_key=metadata_key,
|
|
307
300
|
variable_name=variable_name,
|
|
@@ -320,7 +313,6 @@ class IntegerMetadataVariable(MetadataVariable, IntegerVariable):
|
|
|
320
313
|
Creates an int variable from playlist metadata
|
|
321
314
|
"""
|
|
322
315
|
return _get(
|
|
323
|
-
"int",
|
|
324
316
|
metadata_variable_name=PLAYLIST_METADATA_VARIABLE_NAME,
|
|
325
317
|
metadata_key=metadata_key,
|
|
326
318
|
variable_name=variable_name,
|
{ytdl_sub-2025.12.8 → ytdl_sub-2026.1.11}/src/ytdl_sub/entries/variables/override_variables.py
RENAMED
|
@@ -11,9 +11,6 @@ from ytdl_sub.entries.script.variable_types import Variable
|
|
|
11
11
|
from ytdl_sub.script.functions import Functions
|
|
12
12
|
from ytdl_sub.script.utils.name_validation import is_valid_name
|
|
13
13
|
|
|
14
|
-
# TODO: use this
|
|
15
|
-
SUBSCRIPTION_ARRAY = "subscription_array"
|
|
16
|
-
|
|
17
14
|
|
|
18
15
|
class SubscriptionVariables:
|
|
19
16
|
@staticmethod
|
|
@@ -163,7 +160,7 @@ class OverrideHelpers:
|
|
|
163
160
|
True if the override name itself is valid. False otherwise.
|
|
164
161
|
"""
|
|
165
162
|
if name.startswith("%"):
|
|
166
|
-
|
|
163
|
+
name = name[1:]
|
|
167
164
|
|
|
168
165
|
return is_valid_name(name=name)
|
|
169
166
|
|
|
@@ -11,8 +11,7 @@ presets:
|
|
|
11
11
|
|
|
12
12
|
# Set the default date_range to 2 months
|
|
13
13
|
overrides:
|
|
14
|
-
|
|
15
|
-
only_recent_date_range: "{date_range}"
|
|
14
|
+
only_recent_date_range: "2months"
|
|
16
15
|
|
|
17
16
|
#############################################################################
|
|
18
17
|
# Only Recent
|