ytdl-sub 2025.11.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.
Files changed (174) hide show
  1. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/PKG-INFO +2 -2
  2. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/pyproject.toml +1 -1
  3. ytdl_sub-2025.12.31.post1/src/ytdl_sub/__init__.py +1 -0
  4. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/config_validator.py +8 -0
  5. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/overrides.py +44 -13
  6. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/preset_plugins.py +33 -0
  7. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/preset.py +36 -8
  8. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/preset_options.py +33 -2
  9. ytdl_sub-2025.12.31.post1/src/ytdl_sub/config/validators/variable_validation.py +91 -0
  10. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/url/validators.py +2 -2
  11. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/variables/override_variables.py +1 -4
  12. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/download_deletion_options.yaml +1 -2
  13. ytdl_sub-2025.12.31.post1/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml +5693 -0
  14. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/parser.py +6 -1
  15. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/script.py +117 -46
  16. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/function.py +11 -6
  17. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/syntax_tree.py +28 -2
  18. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/variable_dependency.py +16 -5
  19. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/name_validation.py +21 -0
  20. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/base_subscription.py +29 -3
  21. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/subscription_download.py +3 -0
  22. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/exceptions.py +4 -0
  23. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/file_handler.py +49 -0
  24. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/script.py +19 -2
  25. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/string_formatter_validators.py +63 -30
  26. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/validators.py +3 -13
  27. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/ytdl_additions/enhanced_download_archive.py +20 -0
  28. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/PKG-INFO +2 -2
  29. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/requires.txt +1 -1
  30. ytdl_sub-2025.11.8/src/ytdl_sub/__init__.py +0 -1
  31. ytdl_sub-2025.11.8/src/ytdl_sub/config/validators/variable_validation.py +0 -215
  32. ytdl_sub-2025.11.8/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml +0 -1131
  33. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/LICENSE +0 -0
  34. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/README.md +0 -0
  35. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/setup.cfg +0 -0
  36. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/__init__.py +0 -0
  37. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/entrypoint.py +0 -0
  38. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/output_summary.py +0 -0
  39. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/output_transaction_log.py +0 -0
  40. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/parsers/__init__.py +0 -0
  41. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/parsers/cli_to_sub.py +0 -0
  42. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/parsers/dl.py +0 -0
  43. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/cli/parsers/main.py +0 -0
  44. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/__init__.py +0 -0
  45. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/config_file.py +0 -0
  46. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/defaults.py +0 -0
  47. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/__init__.py +0 -0
  48. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/plugin.py +0 -0
  49. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/plugin_mapping.py +0 -0
  50. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/plugin/plugin_operation.py +0 -0
  51. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/validators/__init__.py +0 -0
  52. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/config/validators/options.py +0 -0
  53. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/__init__.py +0 -0
  54. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/info_json/__init__.py +0 -0
  55. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/info_json/info_json_downloader.py +0 -0
  56. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/source_plugin.py +0 -0
  57. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/url/__init__.py +0 -0
  58. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/url/downloader.py +0 -0
  59. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/ytdl_options_builder.py +0 -0
  60. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/downloaders/ytdlp.py +0 -0
  61. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/__init__.py +0 -0
  62. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/base_entry.py +0 -0
  63. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/entry.py +0 -0
  64. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/entry_parent.py +0 -0
  65. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/script/__init__.py +0 -0
  66. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/script/custom_functions.py +0 -0
  67. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/script/function_scripts.py +0 -0
  68. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/script/variable_definitions.py +0 -0
  69. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/script/variable_types.py +0 -0
  70. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/entries/variables/__init__.py +0 -0
  71. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/main.py +0 -0
  72. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/__init__.py +0 -0
  73. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/audio_extract.py +0 -0
  74. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/chapters.py +0 -0
  75. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/date_range.py +0 -0
  76. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/embed_thumbnail.py +0 -0
  77. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/file_convert.py +0 -0
  78. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/filter_exclude.py +0 -0
  79. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/filter_include.py +0 -0
  80. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/format.py +0 -0
  81. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/internal/__init__.py +0 -0
  82. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/internal/view.py +0 -0
  83. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/match_filters.py +0 -0
  84. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/music_tags.py +0 -0
  85. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/nfo_tags.py +0 -0
  86. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/output_directory_nfo_tags.py +0 -0
  87. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/split_by_chapters.py +0 -0
  88. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/square_thumbnail.py +0 -0
  89. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/static_nfo_tags.py +0 -0
  90. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/subtitles.py +0 -0
  91. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/throttle_protection.py +0 -0
  92. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/plugins/video_tags.py +0 -0
  93. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/__init__.py +0 -0
  94. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/__init__.py +0 -0
  95. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/filter_duration.yaml +0 -0
  96. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/filter_keywords.yaml +0 -0
  97. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/media_quality.yaml +0 -0
  98. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/players.yaml +0 -0
  99. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/throttle_protection.yaml +0 -0
  100. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/url.yaml +0 -0
  101. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/url_bilateral.yaml +0 -0
  102. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml +0 -0
  103. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/internal/__init__.py +0 -0
  104. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/internal/view.yaml +0 -0
  105. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music/__init__.py +0 -0
  106. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music/albums_from_chapters.yaml +0 -0
  107. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music/albums_from_playlists.yaml +0 -0
  108. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music/singles.yaml +0 -0
  109. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music/soundcloud.yaml +0 -0
  110. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music_videos/__init__.py +0 -0
  111. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music_videos/music_video_base.yaml +0 -0
  112. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music_videos/music_video_extras.yaml +0 -0
  113. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/music_videos/music_videos.yaml +0 -0
  114. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/tv_show/__init__.py +0 -0
  115. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/tv_show/episode.yaml +0 -0
  116. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/tv_show/tv_show.yaml +0 -0
  117. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/prebuilt_presets/tv_show/tv_show_by_date.yaml +0 -0
  118. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/__init__.py +0 -0
  119. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/__init__.py +0 -0
  120. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/array_functions.py +0 -0
  121. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/boolean_functions.py +0 -0
  122. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/conditional_functions.py +0 -0
  123. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/date_functions.py +0 -0
  124. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/error_functions.py +0 -0
  125. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/json_functions.py +0 -0
  126. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/map_functions.py +0 -0
  127. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/numeric_functions.py +0 -0
  128. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/print_functions.py +0 -0
  129. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/regex_functions.py +0 -0
  130. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/functions/string_functions.py +0 -0
  131. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/script_output.py +0 -0
  132. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/__init__.py +0 -0
  133. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/array.py +0 -0
  134. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/map.py +0 -0
  135. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/resolvable.py +0 -0
  136. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/types/variable.py +0 -0
  137. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/__init__.py +0 -0
  138. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/exception_formatters.py +0 -0
  139. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/exceptions.py +0 -0
  140. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/script/utils/type_checking.py +0 -0
  141. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/__init__.py +0 -0
  142. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/subscription.py +0 -0
  143. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/subscription_validators.py +0 -0
  144. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/subscriptions/subscription_ytdl_options.py +0 -0
  145. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/thread/__init__.py +0 -0
  146. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/thread/log_entries_downloaded_listener.py +0 -0
  147. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/__init__.py +0 -0
  148. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/chapters.py +0 -0
  149. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/datetime.py +0 -0
  150. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/ffmpeg.py +0 -0
  151. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/file_lock.py +0 -0
  152. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/file_path.py +0 -0
  153. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/logger.py +0 -0
  154. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/retry.py +0 -0
  155. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/scriptable.py +0 -0
  156. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/subtitles.py +0 -0
  157. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/system.py +0 -0
  158. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/thumbnail.py +0 -0
  159. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/xml.py +0 -0
  160. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/utils/yaml.py +0 -0
  161. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/__init__.py +0 -0
  162. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/audo_codec_validator.py +0 -0
  163. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/file_path_validators.py +0 -0
  164. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/nfo_validators.py +0 -0
  165. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/regex_validator.py +0 -0
  166. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/source_variable_validator.py +0 -0
  167. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/strict_dict_validator.py +0 -0
  168. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/string_datetime.py +0 -0
  169. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/validators/string_select_validator.py +0 -0
  170. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub/ytdl_additions/__init__.py +0 -0
  171. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/SOURCES.txt +0 -0
  172. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/dependency_links.txt +0 -0
  173. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/src/ytdl_sub.egg-info/entry_points.txt +0 -0
  174. {ytdl_sub-2025.11.8 → ytdl_sub-2025.12.31.post1}/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: 2025.11.8
3
+ Version: 2025.12.31.post1
4
4
  Summary: Automate downloading metadata generation with YoutubeDL
5
5
  Author: Jesse Bannon
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -689,7 +689,7 @@ Classifier: Programming Language :: Python :: 3.11
689
689
  Requires-Python: >=3.10
690
690
  Description-Content-Type: text/markdown
691
691
  License-File: LICENSE
692
- Requires-Dist: yt-dlp[default]==2025.10.22
692
+ Requires-Dist: yt-dlp[default]==2025.12.8
693
693
  Requires-Dist: colorama~=0.4
694
694
  Requires-Dist: mergedeep~=1.3
695
695
  Requires-Dist: mediafile~=0.12
@@ -15,7 +15,7 @@ classifiers = [
15
15
  "Programming Language :: Python :: 3.11",
16
16
  ]
17
17
  dependencies = [
18
- "yt-dlp[default]==2025.10.22",
18
+ "yt-dlp[default]==2025.12.8",
19
19
  "colorama~=0.4",
20
20
  "mergedeep~=1.3",
21
21
  "mediafile~=0.12",
@@ -0,0 +1 @@
1
+ __pypi_version__ = "2025.12.31.post1";__local_version__ = "2025.12.31+d373935"
@@ -12,6 +12,8 @@ from ytdl_sub.config.defaults import DEFAULT_FFPROBE_PATH
12
12
  from ytdl_sub.config.defaults import DEFAULT_LOCK_DIRECTORY
13
13
  from ytdl_sub.config.defaults import MAX_FILE_NAME_BYTES
14
14
  from ytdl_sub.prebuilt_presets import PREBUILT_PRESETS
15
+ from ytdl_sub.utils.exceptions import SubscriptionPermissionError
16
+ from ytdl_sub.utils.file_handler import FileHandler
15
17
  from ytdl_sub.validators.file_path_validators import FFmpegFileValidator
16
18
  from ytdl_sub.validators.file_path_validators import FFprobeFileValidator
17
19
  from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
@@ -147,6 +149,12 @@ class ConfigOptions(StrictDictValidator):
147
149
  key="file_name_max_bytes", validator=IntValidator, default=MAX_FILE_NAME_BYTES
148
150
  )
149
151
 
152
+ if not FileHandler.is_path_writable(self.working_directory):
153
+ raise SubscriptionPermissionError(
154
+ "ytdl-sub does not have permissions to the working directory: "
155
+ f"{self.working_directory}"
156
+ )
157
+
150
158
  @property
151
159
  def working_directory(self) -> str:
152
160
  """
@@ -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, str]] = None
119
- ) -> Dict[str, 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, str] = {}
126
- mergedeep.merge(
127
- initial_variables,
128
- self.dict_with_format_strings,
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.add(
154
+ self.script.add_parsed(
138
155
  self.initial_variables(
139
156
  unresolved_variables={
140
- var_name: f"{{%throw('Plugin variable {var_name} has not been created yet')}}"
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
  )
@@ -158,10 +184,15 @@ class Overrides(UnstructuredDictFormatterValidator, Scriptable):
158
184
  script = entry.script
159
185
  unresolvable = entry.unresolvable
160
186
 
187
+ # Update the script internally so long as we are not supplying overrides
188
+ # that could alter the script with one-off state
189
+ update = function_overrides is None
190
+
161
191
  try:
162
192
  return script.resolve_once(
163
193
  dict({"tmp_var": formatter.format_string}, **(function_overrides or {})),
164
194
  unresolvable=unresolvable,
195
+ update=update,
165
196
  )["tmp_var"]
166
197
  except ScriptVariableNotResolved as exc:
167
198
  raise StringFormattingException(
@@ -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._validate_key(key="overrides", validator=Overrides, default={})
196
-
197
- VariableValidation(
198
- downloader_options=self.downloader_options,
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:
@@ -8,6 +8,9 @@ from ytdl_sub.config.overrides import Overrides
8
8
  from ytdl_sub.config.plugin.plugin_operation import PluginOperation
9
9
  from ytdl_sub.config.validators.options import OptionsDictValidator
10
10
  from ytdl_sub.entries.script.variable_definitions import VARIABLES as v
11
+ from ytdl_sub.utils.exceptions import SubscriptionPermissionError
12
+ from ytdl_sub.utils.exceptions import ValidationException
13
+ from ytdl_sub.utils.file_handler import FileHandler
11
14
  from ytdl_sub.validators.file_path_validators import OverridesStringFormatterFilePathValidator
12
15
  from ytdl_sub.validators.file_path_validators import StringFormatterFileNameValidator
13
16
  from ytdl_sub.validators.string_datetime import StringDatetimeValidator
@@ -57,12 +60,24 @@ class YTDLOptions(UnstructuredOverridesDictFormatterValidator):
57
60
  def to_native_dict(self, overrides: Overrides) -> Dict:
58
61
  """
59
62
  Materializes the entire ytdl-options dict from OverrideStringFormatters into
60
- native python
63
+ native python.
61
64
  """
62
- return {
65
+ out = {
63
66
  key: overrides.apply_overrides_formatter_to_native(val)
64
67
  for key, val in self.dict.items()
65
68
  }
69
+ if "cookiefile" in out:
70
+ if not FileHandler.is_file_existent(out["cookiefile"]):
71
+ raise ValidationException(
72
+ f"Specified cookiefile {out['cookiefile']} but it does not exist as a file."
73
+ )
74
+
75
+ if not FileHandler.is_file_readable(out["cookiefile"]):
76
+ raise SubscriptionPermissionError(
77
+ f"Cannot read cookiefile {out['cookiefile']} due to permissions issue."
78
+ )
79
+
80
+ return out
66
81
 
67
82
 
68
83
  # Disable for proper docstring formatting
@@ -107,6 +122,7 @@ class OutputOptions(OptionsDictValidator):
107
122
  "keep_max_files",
108
123
  "download_archive_standardized_date",
109
124
  "keep_files_date_eval",
125
+ "preserve_mtime",
110
126
  }
111
127
 
112
128
  @classmethod
@@ -170,6 +186,10 @@ class OutputOptions(OptionsDictValidator):
170
186
  default=f"{{{v.upload_date_standardized.variable_name}}}",
171
187
  )
172
188
 
189
+ self._preserve_mtime = self._validate_key_if_present(
190
+ key="preserve_mtime", validator=BoolValidator, default=False
191
+ )
192
+
173
193
  if (
174
194
  self._keep_files_before or self._keep_files_after or self._keep_max_files
175
195
  ) and not self.maintain_download_archive:
@@ -309,6 +329,17 @@ class OutputOptions(OptionsDictValidator):
309
329
  """
310
330
  return self._keep_max_files
311
331
 
332
+ @property
333
+ def preserve_mtime(self) -> bool:
334
+ """
335
+ :expected type: Optional[Boolean]
336
+ :description:
337
+ Preserve the video's original upload time as the file modification time.
338
+ When True, sets the file's mtime to match the video's upload_date from
339
+ yt-dlp metadata. Defaults to False.
340
+ """
341
+ return self._preserve_mtime.value
342
+
312
343
  def added_variables(self, unresolved_variables: Set[str]) -> Dict[PluginOperation, Set[str]]:
313
344
  return {
314
345
  # PluginOperation.MODIFY_ENTRY_METADATA: {
@@ -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._name = self._validate_key(key="name", validator=StringFormatterValidator)
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._name
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
- return is_valid_name(name=name[1:])
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
- date_range: "2months" # keep for legacy-reasons
15
- only_recent_date_range: "{date_range}"
14
+ only_recent_date_range: "2months"
16
15
 
17
16
  #############################################################################
18
17
  # Only Recent