ytdl-sub 2026.1.16.post1__py3-none-any.whl → 2026.1.23.post1__py3-none-any.whl

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/__init__.py CHANGED
@@ -1 +1 @@
1
- __pypi_version__ = "2026.01.16.post1";__local_version__ = "2026.01.16+97df4da"
1
+ __pypi_version__ = "2026.01.23.post1";__local_version__ = "2026.01.23+264e458"
@@ -8,7 +8,7 @@ presets:
8
8
  urls:
9
9
  # The first URL will be all the artist's tracks.
10
10
  # Treat these as singles - an album with a single track
11
- - url: "{url}/tracks"
11
+ - url: "{url}"
12
12
  include_sibling_metadata: False
13
13
  variables:
14
14
  sc_track_album: "{title}"
ytdl_sub/script/script.py CHANGED
@@ -1,5 +1,6 @@
1
1
  # pylint: disable=missing-raises-doc
2
2
  import copy
3
+ from collections import defaultdict
3
4
  from typing import Dict
4
5
  from typing import List
5
6
  from typing import Optional
@@ -38,59 +39,71 @@ class Script:
38
39
  ``{ %custom_function: syntax }``
39
40
  """
40
41
 
41
- def _ensure_no_cycle(
42
+ def _throw_cycle_error(
42
43
  self, name: str, dep: str, deps: List[str], definitions: Dict[str, SyntaxTree]
43
44
  ):
44
- if dep not in definitions:
45
- return # does not exist, will throw downstream in parser
46
-
47
- if name in deps + [dep]:
48
- type_name, pre = (
49
- ("custom functions", "%") if definitions is self._functions else ("variables", "")
50
- )
51
- cycle_deps = [name] + deps + [dep]
52
- cycle_deps_str = " -> ".join([f"{pre}{name}" for name in cycle_deps])
45
+ type_name, pre = (
46
+ ("custom functions", "%") if definitions is self._functions else ("variables", "")
47
+ )
48
+ cycle_deps = [name] + deps + [dep]
49
+ cycle_deps_str = " -> ".join([f"{pre}{name}" for name in cycle_deps])
53
50
 
54
- raise CycleDetected(f"Cycle detected within these {type_name}: {cycle_deps_str}")
51
+ raise CycleDetected(f"Cycle detected within these {type_name}: {cycle_deps_str}")
55
52
 
56
53
  def _traverse_variable_dependencies(
57
54
  self,
58
55
  variable_name: str,
59
56
  variable_dependency: SyntaxTree,
60
57
  deps: List[str],
58
+ ensured: Dict[str, Set[str]],
61
59
  ) -> None:
62
60
  for dep in variable_dependency.variables:
63
- self._ensure_no_cycle(
64
- name=variable_name, dep=dep.name, deps=deps, definitions=self._variables
65
- )
61
+ if variable_name == dep.name:
62
+ self._throw_cycle_error(
63
+ name=variable_name, dep=dep.name, deps=deps, definitions=self._variables
64
+ )
65
+
66
+ if dep.name in ensured[variable_name]:
67
+ continue
68
+
66
69
  self._traverse_variable_dependencies(
67
70
  variable_name=variable_name,
68
71
  variable_dependency=self._variables[dep.name],
69
72
  deps=deps + [dep.name],
73
+ ensured=ensured,
70
74
  )
75
+ ensured[variable_name].add(dep.name)
71
76
 
72
77
  for custom_func in variable_dependency.custom_function_dependencies(
73
78
  custom_function_definitions=self._functions
74
79
  ):
75
80
  for dep in self._functions[custom_func.name].variables:
76
- self._ensure_no_cycle(
77
- name=variable_name,
78
- dep=dep.name,
79
- deps=deps + [custom_func.definition_name()],
80
- definitions=self._variables,
81
- )
81
+ if variable_name == dep.name:
82
+ self._throw_cycle_error(
83
+ name=variable_name,
84
+ dep=dep.name,
85
+ deps=deps + [custom_func.definition_name()],
86
+ definitions=self._variables,
87
+ )
88
+ if dep.name in ensured[variable_name]:
89
+ continue
90
+
82
91
  self._traverse_variable_dependencies(
83
92
  variable_name=variable_name,
84
93
  variable_dependency=self._variables[dep.name],
85
94
  deps=deps + [custom_func.definition_name(), dep.name],
95
+ ensured=ensured,
86
96
  )
97
+ ensured[variable_name].add(dep.name)
87
98
 
88
99
  def _ensure_no_variable_cycles(self, variables: Dict[str, SyntaxTree]):
100
+ ensured: Dict[str, Set[str]] = defaultdict(set)
89
101
  for variable_name, variable_definition in variables.items():
90
102
  self._traverse_variable_dependencies(
91
103
  variable_name=variable_name,
92
104
  variable_dependency=variable_definition,
93
105
  deps=[],
106
+ ensured=ensured,
94
107
  )
95
108
 
96
109
  def _traverse_custom_function_dependencies(
@@ -100,9 +113,10 @@ class Script:
100
113
  deps: List[str],
101
114
  ) -> None:
102
115
  for dep in custom_function_dependency.custom_functions:
103
- self._ensure_no_cycle(
104
- name=custom_function_name, dep=dep.name, deps=deps, definitions=self._functions
105
- )
116
+ if custom_function_name == dep.name:
117
+ self._throw_cycle_error(
118
+ name=custom_function_name, dep=dep.name, deps=deps, definitions=self._functions
119
+ )
106
120
  self._traverse_custom_function_dependencies(
107
121
  custom_function_name=custom_function_name,
108
122
  custom_function_dependency=self._functions[dep.name],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ytdl-sub
3
- Version: 2026.1.16.post1
3
+ Version: 2026.1.23.post1
4
4
  Summary: Automate downloading metadata generation with YoutubeDL
5
5
  Author: Jesse Bannon
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -1,4 +1,4 @@
1
- ytdl_sub/__init__.py,sha256=2-KRZ1DEByYOGijD0n5BrJAPAcFYZ4mD4o-MVnboVCk,79
1
+ ytdl_sub/__init__.py,sha256=X-mG0iHeHchpdmnmdqyZ5dExltrJMCVVKIKT2GLsAeI,79
2
2
  ytdl_sub/main.py,sha256=4Rf9wXxSKW7IPnWqG5YtTZ814PjP1n9WtoFDivaainE,1004
3
3
  ytdl_sub/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  ytdl_sub/cli/entrypoint.py,sha256=XXjUH4HiOP_BB2ZA_bNcyt5-o6YLAdZmj0EP3xtOtD8,9496
@@ -81,7 +81,7 @@ ytdl_sub/prebuilt_presets/music/__init__.py,sha256=SZkVAFSEt9gTKjyseaebh7l2uMsMl
81
81
  ytdl_sub/prebuilt_presets/music/albums_from_chapters.yaml,sha256=8I8vi4L5LEZV0ZZucnUOIGwC6DT9PvZUyFG9ugvbV2k,658
82
82
  ytdl_sub/prebuilt_presets/music/albums_from_playlists.yaml,sha256=AKMyOxD_4KMa40Cb5OZop8v_NXapuFV-LEbFGfjfouc,874
83
83
  ytdl_sub/prebuilt_presets/music/singles.yaml,sha256=mrTswAUr-Jgdv0_WuwMgG-kr8zpQU-A0jct25Drj5m0,1943
84
- ytdl_sub/prebuilt_presets/music/soundcloud.yaml,sha256=-V65VC902A3GbgvCJyBh4WjCcvPYx07yg8-jZkIVtLQ,1391
84
+ ytdl_sub/prebuilt_presets/music/soundcloud.yaml,sha256=llbPQE5pvGZ1uWDhyMglz_Vxt0-ZM58FktvTyIyh9Jg,1384
85
85
  ytdl_sub/prebuilt_presets/music_videos/__init__.py,sha256=eX9FbPh4thWqpfnLtlY1J1OQdfTmiUZqSBnz1dJ44Ws,595
86
86
  ytdl_sub/prebuilt_presets/music_videos/music_video_base.yaml,sha256=BEv3SnPzI0UJTi3tOHN2HE2Tang2FwWCGHEEIjKiVZA,2016
87
87
  ytdl_sub/prebuilt_presets/music_videos/music_video_extras.yaml,sha256=1XImnNGcCH63E-GbJj_YKDHFXzW9hRokJsuO0zi1Pv8,1255
@@ -93,7 +93,7 @@ ytdl_sub/prebuilt_presets/tv_show/tv_show_by_date.yaml,sha256=0OgIOzxSPNVqwcZnL6
93
93
  ytdl_sub/prebuilt_presets/tv_show/tv_show_collection.yaml,sha256=MRAxKnh_MvQFJTisRYGsbsUlDmHNLMuV5tlK6iczmqs,49826
94
94
  ytdl_sub/script/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
95
95
  ytdl_sub/script/parser.py,sha256=LUvmUIxg346njE8-uDx06nOW6ZDX5QS6aUtp4lsgwpk,22115
96
- ytdl_sub/script/script.py,sha256=r5QJOt0Dw1GE9qy8hHr5-bjr2HWs1rv9g-dsHrSBZrc,29998
96
+ ytdl_sub/script/script.py,sha256=frzZNxx42dIcpB6QGyAAb2uE2fI-pmywEBiYJQVXZG4,30526
97
97
  ytdl_sub/script/script_output.py,sha256=5SIamnI-1D3xMA0qQzjf9xrIy8j6BVhGCKrl_Q1d2M8,1381
98
98
  ytdl_sub/script/functions/__init__.py,sha256=rzl6O5G0IEqFYHQECIM9bRvcuQj-ytC_p-Xl2TTa6j0,2932
99
99
  ytdl_sub/script/functions/array_functions.py,sha256=yg9rcZP67-aVzhu4oZZzUu3-AHiHltbQDWEs8GW1DJ4,7193
@@ -158,9 +158,9 @@ ytdl_sub/validators/string_select_validator.py,sha256=KFXNKWX2J80WGt08m5gVYphPMH
158
158
  ytdl_sub/validators/validators.py,sha256=JC3-c9fSrozFADUY5jqZEhXpM2q3sfserlooQxT2DK8,9133
159
159
  ytdl_sub/ytdl_additions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
160
160
  ytdl_sub/ytdl_additions/enhanced_download_archive.py,sha256=Lsc0wjHdx9d8dYJCskZYAUGDAQ_QzQ-_xbQlyrBSzfk,24884
161
- ytdl_sub-2026.1.16.post1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
162
- ytdl_sub-2026.1.16.post1.dist-info/METADATA,sha256=u3uun6tUQ6QcrljVD1vj4d1o16X0L1BN8Jf7tZ4i1RM,51426
163
- ytdl_sub-2026.1.16.post1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
164
- ytdl_sub-2026.1.16.post1.dist-info/entry_points.txt,sha256=K3T5235NlAI-WLmHCg5tzLZHqc33OLN5IY5fOGc9t10,48
165
- ytdl_sub-2026.1.16.post1.dist-info/top_level.txt,sha256=6z-JWazl6jXspC2DNyxOnGnEqYyGzVbgcBDoXfbkUhI,9
166
- ytdl_sub-2026.1.16.post1.dist-info/RECORD,,
161
+ ytdl_sub-2026.1.23.post1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
162
+ ytdl_sub-2026.1.23.post1.dist-info/METADATA,sha256=e3n2uBTGvriWWwqXTx9p7WR09foC58MqUMm_GhtxX0s,51426
163
+ ytdl_sub-2026.1.23.post1.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
164
+ ytdl_sub-2026.1.23.post1.dist-info/entry_points.txt,sha256=K3T5235NlAI-WLmHCg5tzLZHqc33OLN5IY5fOGc9t10,48
165
+ ytdl_sub-2026.1.23.post1.dist-info/top_level.txt,sha256=6z-JWazl6jXspC2DNyxOnGnEqYyGzVbgcBDoXfbkUhI,9
166
+ ytdl_sub-2026.1.23.post1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5