ytdl-sub 2025.12.30__tar.gz → 2025.12.31__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.30 → ytdl_sub-2025.12.31}/PKG-INFO +1 -1
- ytdl_sub-2025.12.31/src/ytdl_sub/__init__.py +1 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/overrides.py +20 -13
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/plugin/preset_plugins.py +33 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/preset.py +35 -9
- ytdl_sub-2025.12.31/src/ytdl_sub/config/validators/variable_validation.py +91 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/downloaders/url/validators.py +2 -2
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/parser.py +5 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/script.py +93 -28
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/utils/name_validation.py +21 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/subscriptions/base_subscription.py +21 -3
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/script.py +19 -2
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/string_formatter_validators.py +63 -31
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/validators.py +3 -13
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub.egg-info/PKG-INFO +1 -1
- ytdl_sub-2025.12.30/src/ytdl_sub/__init__.py +0 -1
- ytdl_sub-2025.12.30/src/ytdl_sub/config/validators/variable_validation.py +0 -215
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/LICENSE +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/README.md +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/pyproject.toml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/setup.cfg +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/cli/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/cli/entrypoint.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/cli/output_summary.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/cli/output_transaction_log.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/cli/parsers/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/cli/parsers/cli_to_sub.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/cli/parsers/dl.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/cli/parsers/main.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/config_file.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/config_validator.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/defaults.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/plugin/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/plugin/plugin.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/plugin/plugin_mapping.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/plugin/plugin_operation.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/preset_options.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/validators/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/config/validators/options.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/downloaders/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/downloaders/info_json/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/downloaders/info_json/info_json_downloader.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/downloaders/source_plugin.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/downloaders/url/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/downloaders/url/downloader.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/downloaders/ytdl_options_builder.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/downloaders/ytdlp.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/base_entry.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/entry.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/entry_parent.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/script/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/script/custom_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/script/function_scripts.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/script/variable_definitions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/script/variable_types.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/variables/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/entries/variables/override_variables.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/main.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/audio_extract.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/chapters.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/date_range.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/embed_thumbnail.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/file_convert.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/filter_exclude.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/filter_include.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/format.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/internal/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/internal/view.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/match_filters.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/music_tags.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/nfo_tags.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/output_directory_nfo_tags.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/split_by_chapters.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/square_thumbnail.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/static_nfo_tags.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/subtitles.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/throttle_protection.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/plugins/video_tags.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/helpers/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/helpers/download_deletion_options.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/helpers/filter_duration.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/helpers/filter_keywords.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/helpers/media_quality.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/helpers/players.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/helpers/throttle_protection.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/helpers/url.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/helpers/url_bilateral.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/internal/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/internal/view.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/music/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/music/albums_from_chapters.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/music/albums_from_playlists.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/music/singles.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/music/soundcloud.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/music_videos/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/music_videos/music_video_base.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/music_videos/music_video_extras.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/music_videos/music_videos.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/tv_show/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/tv_show/episode.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/tv_show/tv_show.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_by_date.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/array_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/boolean_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/conditional_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/date_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/error_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/json_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/map_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/numeric_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/print_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/regex_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/functions/string_functions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/script_output.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/types/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/types/array.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/types/function.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/types/map.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/types/resolvable.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/types/syntax_tree.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/types/variable.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/types/variable_dependency.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/utils/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/utils/exception_formatters.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/utils/exceptions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/script/utils/type_checking.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/subscriptions/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/subscriptions/subscription.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/subscriptions/subscription_download.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/subscriptions/subscription_validators.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/subscriptions/subscription_ytdl_options.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/thread/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/thread/log_entries_downloaded_listener.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/chapters.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/datetime.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/exceptions.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/ffmpeg.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/file_handler.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/file_lock.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/file_path.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/logger.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/retry.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/scriptable.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/subtitles.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/system.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/thumbnail.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/xml.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/utils/yaml.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/audo_codec_validator.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/file_path_validators.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/nfo_validators.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/regex_validator.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/source_variable_validator.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/strict_dict_validator.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/string_datetime.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/validators/string_select_validator.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/ytdl_additions/__init__.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub/ytdl_additions/enhanced_download_archive.py +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub.egg-info/SOURCES.txt +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub.egg-info/dependency_links.txt +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub.egg-info/entry_points.txt +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub.egg-info/requires.txt +0 -0
- {ytdl_sub-2025.12.30 → ytdl_sub-2025.12.31}/src/ytdl_sub.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__pypi_version__ = "2025.12.31";__local_version__ = "2025.12.31+1abe2a4"
|
|
@@ -4,15 +4,16 @@ from typing import Iterable
|
|
|
4
4
|
from typing import Optional
|
|
5
5
|
from typing import Set
|
|
6
6
|
|
|
7
|
-
import mergedeep
|
|
8
|
-
|
|
9
7
|
from ytdl_sub.entries.entry import Entry
|
|
10
8
|
from ytdl_sub.entries.script.variable_definitions import VARIABLES
|
|
11
9
|
from ytdl_sub.entries.variables.override_variables import REQUIRED_OVERRIDE_VARIABLE_NAMES
|
|
12
10
|
from ytdl_sub.entries.variables.override_variables import OverrideHelpers
|
|
13
11
|
from ytdl_sub.script.parser import parse
|
|
14
12
|
from ytdl_sub.script.script import Script
|
|
13
|
+
from ytdl_sub.script.types.function import BuiltInFunction
|
|
15
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
|
|
16
17
|
from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved
|
|
17
18
|
from ytdl_sub.utils.exceptions import InvalidVariableNameException
|
|
18
19
|
from ytdl_sub.utils.exceptions import StringFormattingException
|
|
@@ -134,29 +135,35 @@ class Overrides(UnstructuredDictFormatterValidator, Scriptable):
|
|
|
134
135
|
)
|
|
135
136
|
|
|
136
137
|
def initial_variables(
|
|
137
|
-
self, unresolved_variables: Optional[Dict[str,
|
|
138
|
-
) -> Dict[str,
|
|
138
|
+
self, unresolved_variables: Optional[Dict[str, SyntaxTree]] = None
|
|
139
|
+
) -> Dict[str, SyntaxTree]:
|
|
139
140
|
"""
|
|
140
141
|
Returns
|
|
141
142
|
-------
|
|
142
143
|
Variables and format strings for all Override variables + additional variables (Optional)
|
|
143
144
|
"""
|
|
144
|
-
initial_variables: Dict[str,
|
|
145
|
-
|
|
146
|
-
initial_variables
|
|
147
|
-
|
|
148
|
-
unresolved_variables if unresolved_variables else {},
|
|
149
|
-
)
|
|
150
|
-
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)
|
|
151
149
|
|
|
152
150
|
def initialize_script(self, unresolved_variables: Set[str]) -> "Overrides":
|
|
153
151
|
"""
|
|
154
152
|
Initialize the override script with any unresolved variables
|
|
155
153
|
"""
|
|
156
|
-
self.script.
|
|
154
|
+
self.script.add_parsed(
|
|
157
155
|
self.initial_variables(
|
|
158
156
|
unresolved_variables={
|
|
159
|
-
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
|
+
)
|
|
160
167
|
for var_name in unresolved_variables
|
|
161
168
|
}
|
|
162
169
|
)
|
|
@@ -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,16 +223,11 @@ class Preset(_PresetShell):
|
|
|
192
223
|
)
|
|
193
224
|
|
|
194
225
|
self.plugins: PresetPlugins = self._validate_and_get_plugins()
|
|
195
|
-
self.overrides = self.
|
|
196
|
-
|
|
226
|
+
self.overrides = self._initialize_overrides_script(
|
|
227
|
+
overrides=self._validate_key(key="overrides", validator=Overrides, default={})
|
|
228
|
+
)
|
|
197
229
|
self.overrides.ensure_variable_names_not_a_plugin(plugin_names=PRESET_KEYS)
|
|
198
230
|
|
|
199
|
-
VariableValidation(
|
|
200
|
-
downloader_options=self.downloader_options,
|
|
201
|
-
output_options=self.output_options,
|
|
202
|
-
plugins=self.plugins,
|
|
203
|
-
).initialize_preset_overrides(overrides=self.overrides).ensure_proper_usage()
|
|
204
|
-
|
|
205
231
|
@property
|
|
206
232
|
def name(self) -> str:
|
|
207
233
|
"""
|
|
@@ -0,0 +1,91 @@
|
|
|
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 url_output["url"]:
|
|
88
|
+
resolved_subscription["download"].append(url_output)
|
|
89
|
+
|
|
90
|
+
assert not self.unresolved_variables
|
|
91
|
+
return resolved_subscription
|
|
@@ -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:
|
|
@@ -31,6 +31,8 @@ from ytdl_sub.script.utils.exceptions import InvalidSyntaxException
|
|
|
31
31
|
from ytdl_sub.script.utils.exceptions import InvalidVariableName
|
|
32
32
|
from ytdl_sub.script.utils.exceptions import UserException
|
|
33
33
|
from ytdl_sub.script.utils.exceptions import VariableDoesNotExist
|
|
34
|
+
from ytdl_sub.script.utils.name_validation import is_function
|
|
35
|
+
from ytdl_sub.script.utils.name_validation import to_function_name
|
|
34
36
|
from ytdl_sub.script.utils.name_validation import validate_variable_name
|
|
35
37
|
|
|
36
38
|
# pylint: disable=invalid-name
|
|
@@ -144,6 +146,9 @@ class _Parser:
|
|
|
144
146
|
):
|
|
145
147
|
self._text = text
|
|
146
148
|
self._name = name
|
|
149
|
+
if name and is_function(name):
|
|
150
|
+
self._name = to_function_name(name)
|
|
151
|
+
|
|
147
152
|
self._custom_function_names = custom_function_names
|
|
148
153
|
self._variable_names = variable_names
|
|
149
154
|
self._pos = 0
|
|
@@ -20,28 +20,13 @@ from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments
|
|
|
20
20
|
from ytdl_sub.script.utils.exceptions import InvalidCustomFunctionArguments
|
|
21
21
|
from ytdl_sub.script.utils.exceptions import RuntimeException
|
|
22
22
|
from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved
|
|
23
|
+
from ytdl_sub.script.utils.name_validation import is_function
|
|
24
|
+
from ytdl_sub.script.utils.name_validation import to_function_definition_name
|
|
25
|
+
from ytdl_sub.script.utils.name_validation import to_function_name
|
|
23
26
|
from ytdl_sub.script.utils.name_validation import validate_variable_name
|
|
24
27
|
from ytdl_sub.script.utils.type_checking import FunctionSpec
|
|
25
28
|
|
|
26
29
|
|
|
27
|
-
def _is_function(override_name: str):
|
|
28
|
-
return override_name.startswith("%")
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def _function_name(function_key: str) -> str:
|
|
32
|
-
"""
|
|
33
|
-
Drop the % in %custom_function
|
|
34
|
-
"""
|
|
35
|
-
return function_key[1:]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _to_function_definition_name(function_key: str) -> str:
|
|
39
|
-
"""
|
|
40
|
-
Add % in %custom_function
|
|
41
|
-
"""
|
|
42
|
-
return f"%{function_key}"
|
|
43
|
-
|
|
44
|
-
|
|
45
30
|
class Script:
|
|
46
31
|
"""
|
|
47
32
|
Takes a dictionary of both
|
|
@@ -241,23 +226,23 @@ class Script:
|
|
|
241
226
|
|
|
242
227
|
def __init__(self, script: Dict[str, str]):
|
|
243
228
|
function_names: Set[str] = {
|
|
244
|
-
|
|
229
|
+
to_function_name(name) for name in script.keys() if is_function(name)
|
|
245
230
|
}
|
|
246
231
|
variable_names: Set[str] = {
|
|
247
|
-
validate_variable_name(name) for name in script.keys() if not
|
|
232
|
+
validate_variable_name(name) for name in script.keys() if not is_function(name)
|
|
248
233
|
}
|
|
249
234
|
|
|
250
235
|
self._functions: Dict[str, SyntaxTree] = {
|
|
251
236
|
# custom_function_name must be passed to properly type custom function
|
|
252
237
|
# arguments uniquely if they're nested (i.e. $0 to $custom_func___0)
|
|
253
|
-
|
|
238
|
+
to_function_name(function_key): parse(
|
|
254
239
|
text=function_value,
|
|
255
|
-
name=
|
|
240
|
+
name=to_function_name(function_key),
|
|
256
241
|
custom_function_names=function_names,
|
|
257
242
|
variable_names=variable_names,
|
|
258
243
|
)
|
|
259
244
|
for function_key, function_value in script.items()
|
|
260
|
-
if
|
|
245
|
+
if is_function(function_key)
|
|
261
246
|
}
|
|
262
247
|
|
|
263
248
|
self._variables: Dict[str, SyntaxTree] = {
|
|
@@ -268,7 +253,7 @@ class Script:
|
|
|
268
253
|
variable_names=variable_names,
|
|
269
254
|
)
|
|
270
255
|
for variable_key, variable_value in script.items()
|
|
271
|
-
if not
|
|
256
|
+
if not is_function(variable_key)
|
|
272
257
|
}
|
|
273
258
|
self._validate()
|
|
274
259
|
|
|
@@ -485,12 +470,12 @@ class Script:
|
|
|
485
470
|
added_variables_to_validate: Set[str] = set()
|
|
486
471
|
|
|
487
472
|
functions_to_add = {
|
|
488
|
-
|
|
473
|
+
to_function_name(name): definition
|
|
489
474
|
for name, definition in variables.items()
|
|
490
|
-
if
|
|
475
|
+
if is_function(name)
|
|
491
476
|
}
|
|
492
477
|
variables_to_add = {
|
|
493
|
-
name: definition for name, definition in variables.items() if not
|
|
478
|
+
name: definition for name, definition in variables.items() if not is_function(name)
|
|
494
479
|
}
|
|
495
480
|
|
|
496
481
|
custom_function_names = set(self._functions.keys()) | functions_to_add.keys()
|
|
@@ -520,6 +505,46 @@ class Script:
|
|
|
520
505
|
|
|
521
506
|
return self
|
|
522
507
|
|
|
508
|
+
def add_parsed(self, variables: Dict[str, SyntaxTree]) -> "Script":
|
|
509
|
+
"""
|
|
510
|
+
Adds already parsed, new variables to the script.
|
|
511
|
+
|
|
512
|
+
Parameters
|
|
513
|
+
----------
|
|
514
|
+
variables
|
|
515
|
+
Mapping containing variable name to definition.
|
|
516
|
+
|
|
517
|
+
Returns
|
|
518
|
+
-------
|
|
519
|
+
Script
|
|
520
|
+
self
|
|
521
|
+
"""
|
|
522
|
+
added_variables_to_validate: Set[str] = set()
|
|
523
|
+
|
|
524
|
+
functions_to_add = {
|
|
525
|
+
to_function_name(name): definition
|
|
526
|
+
for name, definition in variables.items()
|
|
527
|
+
if is_function(name)
|
|
528
|
+
}
|
|
529
|
+
variables_to_add = {
|
|
530
|
+
name: definition for name, definition in variables.items() if not is_function(name)
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
for definitions in [functions_to_add, variables_to_add]:
|
|
534
|
+
for name, parsed in definitions.items():
|
|
535
|
+
if parsed.maybe_resolvable is None:
|
|
536
|
+
added_variables_to_validate.add(name)
|
|
537
|
+
|
|
538
|
+
if name in functions_to_add:
|
|
539
|
+
self._functions[name] = parsed
|
|
540
|
+
else:
|
|
541
|
+
self._variables[name] = parsed
|
|
542
|
+
|
|
543
|
+
if added_variables_to_validate:
|
|
544
|
+
self._validate(added_variables=added_variables_to_validate)
|
|
545
|
+
|
|
546
|
+
return self
|
|
547
|
+
|
|
523
548
|
def resolve_once(
|
|
524
549
|
self,
|
|
525
550
|
variable_definitions: Dict[str, str],
|
|
@@ -560,6 +585,46 @@ class Script:
|
|
|
560
585
|
for name in variable_definitions.keys():
|
|
561
586
|
self._variables.pop(name, None)
|
|
562
587
|
|
|
588
|
+
def resolve_once_parsed(
|
|
589
|
+
self,
|
|
590
|
+
variable_definitions: Dict[str, SyntaxTree],
|
|
591
|
+
resolved: Optional[Dict[str, Resolvable]] = None,
|
|
592
|
+
unresolvable: Optional[Set[str]] = None,
|
|
593
|
+
update: bool = False,
|
|
594
|
+
) -> Dict[str, Resolvable]:
|
|
595
|
+
"""
|
|
596
|
+
Given a new set of variable definitions, resolve them using the Script, but do not
|
|
597
|
+
add them to the Script itself.
|
|
598
|
+
|
|
599
|
+
Parameters
|
|
600
|
+
----------
|
|
601
|
+
variable_definitions
|
|
602
|
+
Variables to resolve, but not store in the Script
|
|
603
|
+
resolved
|
|
604
|
+
Optional. Pre-resolved variables that should be used instead of what is in the script.
|
|
605
|
+
unresolvable
|
|
606
|
+
Optional. Unresolvable variables that will be ignored in resolution, including all
|
|
607
|
+
variables with a dependency to them.
|
|
608
|
+
update
|
|
609
|
+
Whether to update the script's state with resolved variables. Defaults to False.
|
|
610
|
+
|
|
611
|
+
Returns
|
|
612
|
+
-------
|
|
613
|
+
Dict[str, Resolvable]
|
|
614
|
+
Dict containing the variable names to their resolved values.
|
|
615
|
+
"""
|
|
616
|
+
try:
|
|
617
|
+
self.add_parsed(variable_definitions)
|
|
618
|
+
return self._resolve(
|
|
619
|
+
pre_resolved=resolved,
|
|
620
|
+
unresolvable=unresolvable,
|
|
621
|
+
output_filter=set(list(variable_definitions.keys())),
|
|
622
|
+
update=update,
|
|
623
|
+
).output
|
|
624
|
+
finally:
|
|
625
|
+
for name in variable_definitions.keys():
|
|
626
|
+
self._variables.pop(name, None)
|
|
627
|
+
|
|
563
628
|
def get(self, variable_name: str) -> Resolvable:
|
|
564
629
|
"""
|
|
565
630
|
Parameters
|
|
@@ -605,4 +670,4 @@ class Script:
|
|
|
605
670
|
Set[str]
|
|
606
671
|
Names of all functions within the Script.
|
|
607
672
|
"""
|
|
608
|
-
return set(
|
|
673
|
+
return set(to_function_definition_name(name) for name in self._functions.keys())
|
|
@@ -58,3 +58,24 @@ def validate_custom_function_name(custom_function_name: str) -> None:
|
|
|
58
58
|
f"Custom function name '%{custom_function_name}' is invalid:"
|
|
59
59
|
" The name is used by a built-in function and cannot be overwritten."
|
|
60
60
|
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def is_function(override_name: str):
|
|
64
|
+
"""
|
|
65
|
+
Whether the definition is a function or not.
|
|
66
|
+
"""
|
|
67
|
+
return override_name.startswith("%")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def to_function_name(function_key: str) -> str:
|
|
71
|
+
"""
|
|
72
|
+
Drop the % in %custom_function
|
|
73
|
+
"""
|
|
74
|
+
return function_key[1:]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def to_function_definition_name(function_key: str) -> str:
|
|
78
|
+
"""
|
|
79
|
+
Add % in %custom_function
|
|
80
|
+
"""
|
|
81
|
+
return f"%{function_key}"
|
|
@@ -8,12 +8,14 @@ from ytdl_sub.config.plugin.preset_plugins import PresetPlugins
|
|
|
8
8
|
from ytdl_sub.config.preset import Preset
|
|
9
9
|
from ytdl_sub.config.preset_options import OutputOptions
|
|
10
10
|
from ytdl_sub.config.preset_options import YTDLOptions
|
|
11
|
+
from ytdl_sub.config.validators.variable_validation import VariableValidation
|
|
11
12
|
from ytdl_sub.downloaders.url.validators import MultiUrlValidator
|
|
12
13
|
from ytdl_sub.entries.variables.override_variables import SubscriptionVariables
|
|
13
14
|
from ytdl_sub.utils.exceptions import SubscriptionPermissionError
|
|
14
15
|
from ytdl_sub.utils.file_handler import FileHandler
|
|
15
16
|
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
|
16
17
|
from ytdl_sub.utils.logger import Logger
|
|
18
|
+
from ytdl_sub.utils.yaml import dump_yaml
|
|
17
19
|
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
|
|
18
20
|
|
|
19
21
|
logger = Logger.get("subscription")
|
|
@@ -76,6 +78,14 @@ class BaseSubscription(ABC):
|
|
|
76
78
|
}
|
|
77
79
|
)
|
|
78
80
|
|
|
81
|
+
# Validate after adding the subscription name
|
|
82
|
+
self._validated_dict = VariableValidation(
|
|
83
|
+
overrides=self.overrides,
|
|
84
|
+
downloader_options=self.downloader_options,
|
|
85
|
+
output_options=self.output_options,
|
|
86
|
+
plugins=self.plugins,
|
|
87
|
+
).ensure_proper_usage()
|
|
88
|
+
|
|
79
89
|
self._enhanced_download_archive: Optional[EnhancedDownloadArchive] = (
|
|
80
90
|
_initialize_download_archive(
|
|
81
91
|
output_options=self.output_options,
|
|
@@ -88,9 +98,9 @@ class BaseSubscription(ABC):
|
|
|
88
98
|
# Add post-archive variables
|
|
89
99
|
self.overrides.add(
|
|
90
100
|
{
|
|
91
|
-
SubscriptionVariables.subscription_has_download_archive():
|
|
92
|
-
|
|
93
|
-
|
|
101
|
+
SubscriptionVariables.subscription_has_download_archive(): (
|
|
102
|
+
f"{{%bool({self.download_archive.num_entries > 0})}}"
|
|
103
|
+
),
|
|
94
104
|
}
|
|
95
105
|
)
|
|
96
106
|
|
|
@@ -245,3 +255,11 @@ class BaseSubscription(ABC):
|
|
|
245
255
|
Subscription in yaml format
|
|
246
256
|
"""
|
|
247
257
|
return self._preset_options.yaml
|
|
258
|
+
|
|
259
|
+
def resolved_yaml(self) -> str:
|
|
260
|
+
"""
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
Human-readable, condensed YAML definition of the subscription.
|
|
264
|
+
"""
|
|
265
|
+
return dump_yaml(self._validated_dict)
|
|
@@ -4,7 +4,6 @@ from typing import Any
|
|
|
4
4
|
from typing import Dict
|
|
5
5
|
|
|
6
6
|
from ytdl_sub.script.parser import parse
|
|
7
|
-
from ytdl_sub.script.script import _is_function
|
|
8
7
|
from ytdl_sub.script.types.array import UnresolvedArray
|
|
9
8
|
from ytdl_sub.script.types.function import BuiltInFunction
|
|
10
9
|
from ytdl_sub.script.types.function import Function
|
|
@@ -15,8 +14,10 @@ from ytdl_sub.script.types.resolvable import Float
|
|
|
15
14
|
from ytdl_sub.script.types.resolvable import Integer
|
|
16
15
|
from ytdl_sub.script.types.resolvable import Lambda
|
|
17
16
|
from ytdl_sub.script.types.resolvable import String
|
|
17
|
+
from ytdl_sub.script.types.syntax_tree import SyntaxTree
|
|
18
18
|
from ytdl_sub.script.types.variable import Variable
|
|
19
19
|
from ytdl_sub.script.utils.exceptions import UNREACHABLE
|
|
20
|
+
from ytdl_sub.script.utils.name_validation import is_function
|
|
20
21
|
|
|
21
22
|
# pylint: disable=too-many-return-statements
|
|
22
23
|
|
|
@@ -30,10 +31,26 @@ class ScriptUtils:
|
|
|
30
31
|
sanitized_variables = {
|
|
31
32
|
f"{name}_sanitized": f"{{%sanitize({name})}}"
|
|
32
33
|
for name in variables.keys()
|
|
33
|
-
if not
|
|
34
|
+
if not is_function(name)
|
|
34
35
|
}
|
|
35
36
|
return dict(variables, **sanitized_variables)
|
|
36
37
|
|
|
38
|
+
@classmethod
|
|
39
|
+
def add_sanitized_parsed_variables(
|
|
40
|
+
cls, variables: Dict[str, SyntaxTree]
|
|
41
|
+
) -> Dict[str, SyntaxTree]:
|
|
42
|
+
"""
|
|
43
|
+
Helper to add sanitized variables to a Script
|
|
44
|
+
"""
|
|
45
|
+
sanitized_variables = {
|
|
46
|
+
f"{name}_sanitized": SyntaxTree(
|
|
47
|
+
ast=[BuiltInFunction(name="sanitize", args=[Variable(name)])]
|
|
48
|
+
)
|
|
49
|
+
for name in variables.keys()
|
|
50
|
+
if not is_function(name)
|
|
51
|
+
}
|
|
52
|
+
return variables | sanitized_variables
|
|
53
|
+
|
|
37
54
|
@classmethod
|
|
38
55
|
def to_script(cls, value: Any, sort_keys: bool = True) -> str:
|
|
39
56
|
"""
|