ytdl-sub 2025.12.8__tar.gz → 2025.12.31.post1__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-2025.12.31.post1}/PKG-INFO +1 -1
- ytdl_sub-2025.12.31.post1/src/ytdl_sub/__init__.py +1 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/overrides.py +39 -13
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/preset_plugins.py +33 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/preset.py +36 -8
- ytdl_sub-2025.12.31.post1/src/ytdl_sub/config/validators/variable_validation.py +91 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/url/validators.py +2 -2
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/variables/override_variables.py +1 -4
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/download_deletion_options.yaml +1 -2
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/parser.py +5 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/script.py +109 -43
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/variable_dependency.py +12 -1
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/name_validation.py +21 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/base_subscription.py +21 -3
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/script.py +19 -2
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/string_formatter_validators.py +63 -31
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/validators.py +3 -13
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/PKG-INFO +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 → ytdl_sub-2025.12.31.post1}/LICENSE +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/README.md +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/pyproject.toml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/setup.cfg +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/entrypoint.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/output_summary.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/output_transaction_log.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/parsers/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/parsers/cli_to_sub.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/parsers/dl.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/parsers/main.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/config_file.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/config_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/defaults.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/plugin.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/plugin_mapping.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/plugin_operation.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/preset_options.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/validators/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/validators/options.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/info_json/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/info_json/info_json_downloader.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/source_plugin.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/url/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/url/downloader.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/ytdl_options_builder.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/ytdlp.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/base_entry.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/entry.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/entry_parent.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/script/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/script/custom_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/script/function_scripts.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/script/variable_definitions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/script/variable_types.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/variables/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/main.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/audio_extract.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/chapters.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/date_range.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/embed_thumbnail.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/file_convert.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/filter_exclude.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/filter_include.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/format.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/internal/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/internal/view.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/match_filters.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/music_tags.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/nfo_tags.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/output_directory_nfo_tags.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/split_by_chapters.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/square_thumbnail.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/static_nfo_tags.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/subtitles.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/throttle_protection.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/video_tags.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/filter_duration.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/filter_keywords.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/media_quality.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/players.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/throttle_protection.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/url.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/url_bilateral.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/internal/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/internal/view.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music/albums_from_chapters.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music/albums_from_playlists.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music/singles.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music/soundcloud.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music_videos/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music_videos/music_video_base.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music_videos/music_video_extras.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music_videos/music_videos.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/tv_show/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/tv_show/episode.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/tv_show/tv_show.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_by_date.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/array_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/boolean_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/conditional_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/date_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/error_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/json_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/map_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/numeric_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/print_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/regex_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/string_functions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/script_output.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/array.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/function.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/map.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/resolvable.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/syntax_tree.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/variable.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/exception_formatters.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/exceptions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/type_checking.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/subscription.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/subscription_download.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/subscription_validators.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/subscription_ytdl_options.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/thread/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/thread/log_entries_downloaded_listener.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/chapters.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/datetime.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/exceptions.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/ffmpeg.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/file_handler.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/file_lock.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/file_path.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/logger.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/retry.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/scriptable.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/subtitles.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/system.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/thumbnail.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/xml.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/yaml.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/audo_codec_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/file_path_validators.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/nfo_validators.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/regex_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/source_variable_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/strict_dict_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/string_datetime.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/string_select_validator.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/ytdl_additions/__init__.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/ytdl_additions/enhanced_download_archive.py +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/SOURCES.txt +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/dependency_links.txt +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/entry_points.txt +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/requires.txt +0 -0
- {ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__pypi_version__ = "2025.12.31.post1";__local_version__ = "2025.12.31+d373935"
|
|
@@ -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
|
)
|
{ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/preset_plugins.py
RENAMED
|
@@ -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,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:
|
|
@@ -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
|
|
@@ -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
|
|
|
@@ -307,10 +292,9 @@ class Script:
|
|
|
307
292
|
|
|
308
293
|
def _get_unresolved_output_filter(
|
|
309
294
|
self,
|
|
310
|
-
unresolved: Dict[Variable, SyntaxTree],
|
|
311
295
|
output_filter: Set[str],
|
|
312
296
|
unresolvable: Set[Variable],
|
|
313
|
-
) ->
|
|
297
|
+
) -> Set[str]:
|
|
314
298
|
"""
|
|
315
299
|
When an output filter is applied, only a subset of variables that the filter
|
|
316
300
|
depends on need to be resolved.
|
|
@@ -331,7 +315,7 @@ class Script:
|
|
|
331
315
|
unresolvable=unresolvable,
|
|
332
316
|
)
|
|
333
317
|
|
|
334
|
-
return
|
|
318
|
+
return subset_to_resolve
|
|
335
319
|
|
|
336
320
|
def _resolve(
|
|
337
321
|
self,
|
|
@@ -367,18 +351,21 @@ class Script:
|
|
|
367
351
|
|
|
368
352
|
unresolvable: Set[Variable] = {Variable(name) for name in (unresolvable or {})}
|
|
369
353
|
unresolved_filter = set(resolved.keys()).union(unresolvable)
|
|
370
|
-
unresolved: Dict[Variable, SyntaxTree] = {
|
|
371
|
-
Variable(name): ast
|
|
372
|
-
for name, ast in self._variables.items()
|
|
373
|
-
if Variable(name) not in unresolved_filter
|
|
374
|
-
}
|
|
375
354
|
|
|
376
355
|
if output_filter:
|
|
377
|
-
unresolved =
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
356
|
+
unresolved = {
|
|
357
|
+
Variable(name): self._variables[name]
|
|
358
|
+
for name in self._get_unresolved_output_filter(
|
|
359
|
+
output_filter=output_filter,
|
|
360
|
+
unresolvable=unresolvable,
|
|
361
|
+
)
|
|
362
|
+
}
|
|
363
|
+
else:
|
|
364
|
+
unresolved = {
|
|
365
|
+
Variable(name): ast
|
|
366
|
+
for name, ast in self._variables.items()
|
|
367
|
+
if Variable(name) not in unresolved_filter
|
|
368
|
+
}
|
|
382
369
|
|
|
383
370
|
while unresolved:
|
|
384
371
|
unresolved_count: int = len(unresolved)
|
|
@@ -483,12 +470,12 @@ class Script:
|
|
|
483
470
|
added_variables_to_validate: Set[str] = set()
|
|
484
471
|
|
|
485
472
|
functions_to_add = {
|
|
486
|
-
|
|
473
|
+
to_function_name(name): definition
|
|
487
474
|
for name, definition in variables.items()
|
|
488
|
-
if
|
|
475
|
+
if is_function(name)
|
|
489
476
|
}
|
|
490
477
|
variables_to_add = {
|
|
491
|
-
name: definition for name, definition in variables.items() if not
|
|
478
|
+
name: definition for name, definition in variables.items() if not is_function(name)
|
|
492
479
|
}
|
|
493
480
|
|
|
494
481
|
custom_function_names = set(self._functions.keys()) | functions_to_add.keys()
|
|
@@ -518,6 +505,46 @@ class Script:
|
|
|
518
505
|
|
|
519
506
|
return self
|
|
520
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
|
+
|
|
521
548
|
def resolve_once(
|
|
522
549
|
self,
|
|
523
550
|
variable_definitions: Dict[str, str],
|
|
@@ -556,8 +583,47 @@ class Script:
|
|
|
556
583
|
).output
|
|
557
584
|
finally:
|
|
558
585
|
for name in variable_definitions.keys():
|
|
559
|
-
|
|
560
|
-
|
|
586
|
+
self._variables.pop(name, None)
|
|
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)
|
|
561
627
|
|
|
562
628
|
def get(self, variable_name: str) -> Resolvable:
|
|
563
629
|
"""
|
|
@@ -604,4 +670,4 @@ class Script:
|
|
|
604
670
|
Set[str]
|
|
605
671
|
Names of all functions within the Script.
|
|
606
672
|
"""
|
|
607
|
-
return set(
|
|
673
|
+
return set(to_function_definition_name(name) for name in self._functions.keys())
|
{ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/variable_dependency.py
RENAMED
|
@@ -114,6 +114,7 @@ class VariableDependency(ABC):
|
|
|
114
114
|
output.add(ParsedCustomFunction(name=arg.name, num_input_args=len(arg.args)))
|
|
115
115
|
if isinstance(arg, VariableDependency):
|
|
116
116
|
output.update(arg.custom_functions)
|
|
117
|
+
# if isinstance(arg, Lambda)
|
|
117
118
|
|
|
118
119
|
return output
|
|
119
120
|
|
|
@@ -189,7 +190,17 @@ class VariableDependency(ABC):
|
|
|
189
190
|
-------
|
|
190
191
|
True if it contains any of the input variables. False otherwise.
|
|
191
192
|
"""
|
|
192
|
-
|
|
193
|
+
# If there are lambdas, see if they are custom functions. If so, check them
|
|
194
|
+
custom_functions_to_check = self.custom_functions
|
|
195
|
+
for lambda_func in self.lambdas:
|
|
196
|
+
if lambda_func.value in custom_function_definitions:
|
|
197
|
+
custom_functions_to_check.add(
|
|
198
|
+
ParsedCustomFunction(
|
|
199
|
+
name=lambda_func.value, num_input_args=lambda_func.num_input_args()
|
|
200
|
+
)
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
for custom_function in custom_functions_to_check:
|
|
193
204
|
if custom_function_definitions[custom_function.name].contains(
|
|
194
205
|
variables=variables, custom_function_definitions=custom_function_definitions
|
|
195
206
|
):
|
{ytdl_sub-2025.12.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/name_validation.py
RENAMED
|
@@ -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}"
|