ytdl-sub 2025.10.23__py3-none-any.whl → 2025.11.7.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__ = "2025.10.23";__local_version__ = "2025.10.23+a5dd438"
1
+ __pypi_version__ = "2025.11.07.post1";__local_version__ = "2025.11.07+e507e6e"
@@ -12,6 +12,7 @@ from yt_dlp.utils import sanitize_filename
12
12
  from ytdl_sub.cli.output_summary import output_summary
13
13
  from ytdl_sub.cli.output_transaction_log import _maybe_validate_transaction_log_file
14
14
  from ytdl_sub.cli.output_transaction_log import output_transaction_log
15
+ from ytdl_sub.cli.parsers.cli_to_sub import print_cli_to_sub
15
16
  from ytdl_sub.cli.parsers.dl import DownloadArgsParser
16
17
  from ytdl_sub.cli.parsers.main import DEFAULT_CONFIG_FILE_NAME
17
18
  from ytdl_sub.cli.parsers.main import parser
@@ -206,6 +207,10 @@ def main() -> List[Subscription]:
206
207
 
207
208
  args, extra_args = parser.parse_known_args()
208
209
 
210
+ if args.subparser == "cli-to-sub":
211
+ print_cli_to_sub(args=extra_args)
212
+ return []
213
+
209
214
  # Load the config
210
215
  if args.config:
211
216
  config = ConfigFile.from_file_path(args.config)
@@ -263,7 +268,7 @@ def main() -> List[Subscription]:
263
268
  _view_url_from_cli(config=config, url=args.url, split_chapters=args.split_chapters)
264
269
  )
265
270
  else:
266
- raise ValidationException("Must provide one of the commands: sub, dl, view")
271
+ raise ValidationException("Must provide one of the commands: sub, dl, view, cli-to-sub")
267
272
 
268
273
  if not args.suppress_transaction_log:
269
274
  output_transaction_log(
@@ -0,0 +1,64 @@
1
+ from typing import List
2
+
3
+ import yt_dlp
4
+ import yt_dlp.options
5
+
6
+ from ytdl_sub.utils.logger import Logger
7
+ from ytdl_sub.utils.yaml import dump_yaml
8
+
9
+ logger = Logger.get()
10
+
11
+ # pylint: disable=missing-function-docstring
12
+
13
+ ##############################################################
14
+ # --- BEGIN ----
15
+ # Copy of https://github.com/yt-dlp/yt-dlp/blob/master/devscripts/cli_to_api.py
16
+
17
+ create_parser = yt_dlp.options.create_parser
18
+
19
+
20
+ def parse_patched_options(opts):
21
+
22
+ patched_parser = create_parser()
23
+ patched_parser.defaults.update(
24
+ {
25
+ "ignoreerrors": False,
26
+ "retries": 0,
27
+ "fragment_retries": 0,
28
+ "extract_flat": False,
29
+ "concat_playlist": "never",
30
+ "update_self": False,
31
+ }
32
+ )
33
+ yt_dlp.options.create_parser = lambda: patched_parser
34
+ try:
35
+ return yt_dlp.parse_options(opts)
36
+ finally:
37
+ yt_dlp.options.create_parser = create_parser
38
+
39
+
40
+ default_opts = parse_patched_options([]).ydl_opts
41
+
42
+
43
+ def cli_to_api(opts, cli_defaults=False):
44
+ opts = (yt_dlp.parse_options if cli_defaults else parse_patched_options)(opts).ydl_opts
45
+
46
+ diff = {k: v for k, v in opts.items() if default_opts[k] != v}
47
+ if "postprocessors" in diff:
48
+ diff["postprocessors"] = [
49
+ pp for pp in diff["postprocessors"] if pp not in default_opts["postprocessors"]
50
+ ]
51
+ return diff
52
+
53
+
54
+ # --- END ----
55
+ ##############################################################
56
+
57
+
58
+ def print_cli_to_sub(args: List[str]) -> None:
59
+ api_args = cli_to_api(args)
60
+ if not api_args:
61
+ logger.info("Does not resolve to any yt-dlp args")
62
+ return
63
+
64
+ print(dump_yaml({"ytdl_options": api_args}))
@@ -221,3 +221,7 @@ view_parser.add_argument(
221
221
  help="View source variables after splitting by chapters",
222
222
  )
223
223
  view_parser.add_argument("url", help="URL to view source variables for")
224
+
225
+ ###################################################################################################
226
+ # CLI-TO-SUB PARSER
227
+ cli_to_sub_parser = subparsers.add_parser("cli-to-sub")
@@ -2,6 +2,8 @@ import os
2
2
 
3
3
  from ytdl_sub.utils.system import IS_WINDOWS
4
4
 
5
+ # pylint: disable=invalid-name
6
+
5
7
 
6
8
  def _existing_path(*paths: str) -> str:
7
9
  """
@@ -2,6 +2,7 @@
2
2
  import inspect
3
3
  from dataclasses import dataclass
4
4
  from inspect import FullArgSpec
5
+ from types import NoneType
5
6
  from typing import Callable
6
7
  from typing import List
7
8
  from typing import Optional
@@ -50,7 +51,7 @@ def get_optional_type(optional_type: Type) -> Type[NamedType]:
50
51
  -------
51
52
  Type within the Optional[Type]
52
53
  """
53
- return [arg for arg in optional_type.__args__ if arg != type(None)][0]
54
+ return [arg for arg in optional_type.__args__ if not isinstance(arg, NoneType)][0]
54
55
 
55
56
 
56
57
  def _is_union_compatible(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ytdl-sub
3
- Version: 2025.10.23
3
+ Version: 2025.11.7.post1
4
4
  Summary: Automate downloading metadata generation with YoutubeDL
5
5
  Author: Jesse Bannon
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -700,8 +700,8 @@ Requires-Dist: pytest<9.0,>=7.2; extra == "test"
700
700
  Requires-Dist: pytest-rerunfailures<17,>=14; extra == "test"
701
701
  Provides-Extra: lint
702
702
  Requires-Dist: black==24.10.0; extra == "lint"
703
- Requires-Dist: isort==6.1.0; extra == "lint"
704
- Requires-Dist: pylint==3.3.8; extra == "lint"
703
+ Requires-Dist: isort==7.0.0; extra == "lint"
704
+ Requires-Dist: pylint==4.0.1; extra == "lint"
705
705
  Provides-Extra: docs
706
706
  Requires-Dist: sphinx<9,>=7; extra == "docs"
707
707
  Requires-Dist: sphinx-rtd-theme<4,>=2; extra == "docs"
@@ -1,16 +1,17 @@
1
- ytdl_sub/__init__.py,sha256=o-wbq-83XymgUDhl81xEJrx9elPVLfw83HAuRVFEeTE,73
1
+ ytdl_sub/__init__.py,sha256=w95MUH9KOfQ-q3JwsigomE2IvT84fBJq1_QDHRxUNXI,79
2
2
  ytdl_sub/main.py,sha256=4Rf9wXxSKW7IPnWqG5YtTZ814PjP1n9WtoFDivaainE,1004
3
3
  ytdl_sub/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- ytdl_sub/cli/entrypoint.py,sha256=5g9IThnOrilAAcsDBBjOqyvB1lpANGqBOFsfHQMYWls,9323
4
+ ytdl_sub/cli/entrypoint.py,sha256=XXjUH4HiOP_BB2ZA_bNcyt5-o6YLAdZmj0EP3xtOtD8,9496
5
5
  ytdl_sub/cli/output_summary.py,sha256=5iHO0k2XZSjR5N72jSjECNxI5h1NXaprDofxyGmJRp0,4318
6
6
  ytdl_sub/cli/output_transaction_log.py,sha256=bJo4z8tmlIFbQU4Wb3uz_g2uAfiHA31hbLqpEWszivQ,1863
7
7
  ytdl_sub/cli/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ ytdl_sub/cli/parsers/cli_to_sub.py,sha256=CTwTzmvM03csc_dLXLREDWNs7HgiBd6huyctTgOyfGE,1684
8
9
  ytdl_sub/cli/parsers/dl.py,sha256=Fzc9nstJ8QXGhCOzSW1_v3cZHfSiVV2coFq3L1eTHtQ,9012
9
- ytdl_sub/cli/parsers/main.py,sha256=dWnu6JKCerWqnzv1F_EUDrSf-z4dXFXz2Zo6pZPHIUU,7068
10
+ ytdl_sub/cli/parsers/main.py,sha256=-H4A9DPARVWe2tCH3rOJiybevlmH3VYhS10yz3683zk,7245
10
11
  ytdl_sub/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
12
  ytdl_sub/config/config_file.py,sha256=SQtVrMIUq2z3WwJVOed4y84JBMQ8aa4pbiBB0Y-YY4M,2781
12
13
  ytdl_sub/config/config_validator.py,sha256=NWPoCb6qjOom-YQamjho4UAIMSC43LRIT28W0rriXds,9424
13
- ytdl_sub/config/defaults.py,sha256=ILHmX46QEuplxHaKwIt0E9H-GdFOApCsNxZLzL4LmeM,1120
14
+ ytdl_sub/config/defaults.py,sha256=NTwzlKDkks1LDGNjFMxh91fw5E6T6d_zGsCwODNYJxo,1152
14
15
  ytdl_sub/config/overrides.py,sha256=WjfKnT8z5dth4uqMC53KrVzitGAPbKGaNN_25C35dUM,8704
15
16
  ytdl_sub/config/preset.py,sha256=cp_oCyR78pHqYIakUNvNnwuFfFUq1YzitvIav5QW3Jw,8517
16
17
  ytdl_sub/config/preset_options.py,sha256=NkkM2m0XCKyYYfe8Vh393AHH9pkvLbkYOmgRNt7G3X8,12958
@@ -118,7 +119,7 @@ ytdl_sub/script/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
118
119
  ytdl_sub/script/utils/exception_formatters.py,sha256=hZDX2w90vU4lY2xiEM-qxQofQz2dmqPwhkSeWaJRsQ4,4645
119
120
  ytdl_sub/script/utils/exceptions.py,sha256=cag5ZLM6as1w-RsrOwO-oe4YFpwlFu_8U0QNGv_jQ68,2774
120
121
  ytdl_sub/script/utils/name_validation.py,sha256=ckTZqzeC-PTJRfAJbFLTNEgKchPA6YqLMS9Z280WUeQ,1830
121
- ytdl_sub/script/utils/type_checking.py,sha256=dQMKnZosnhdaMrsAiMlIfEC_EZ_uR6p3VUkFhRHqu0E,10354
122
+ ytdl_sub/script/utils/type_checking.py,sha256=9EKWE1mWPOlmXWiWTZw-bCRV0FlYk22tNKlgEM6wU_0,10393
122
123
  ytdl_sub/subscriptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
124
  ytdl_sub/subscriptions/base_subscription.py,sha256=-zq4WgpsOq493fEHal8XmC6mLQiA3tvaeuFRyRW_7Es,6803
124
125
  ytdl_sub/subscriptions/subscription.py,sha256=wfzOYVkzmsSH1KYbAMRi6Nhrb2pRaXdhILle7H0hcas,5127
@@ -157,9 +158,9 @@ ytdl_sub/validators/string_select_validator.py,sha256=KFXNKWX2J80WGt08m5gVYphPMH
157
158
  ytdl_sub/validators/validators.py,sha256=X9AkECdngEXcME_C25njHaOjtqbfEJMED2eG9Qy3UPs,9352
158
159
  ytdl_sub/ytdl_additions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
159
160
  ytdl_sub/ytdl_additions/enhanced_download_archive.py,sha256=3skvdZb42TfYmdfm3AebzuT3mr154NmkduaCXx-HlzE,23844
160
- ytdl_sub-2025.10.23.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
161
- ytdl_sub-2025.10.23.dist-info/METADATA,sha256=kd3KQ9bJP0OnYApeZ3VFtvINJeVYcn_DuNqnv9eL8Rw,51421
162
- ytdl_sub-2025.10.23.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
163
- ytdl_sub-2025.10.23.dist-info/entry_points.txt,sha256=K3T5235NlAI-WLmHCg5tzLZHqc33OLN5IY5fOGc9t10,48
164
- ytdl_sub-2025.10.23.dist-info/top_level.txt,sha256=6z-JWazl6jXspC2DNyxOnGnEqYyGzVbgcBDoXfbkUhI,9
165
- ytdl_sub-2025.10.23.dist-info/RECORD,,
161
+ ytdl_sub-2025.11.7.post1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
162
+ ytdl_sub-2025.11.7.post1.dist-info/METADATA,sha256=8MwGOo6Ck7pHLcQ_9EtJW00uxIvehW6NvotZ4h7XtBA,51426
163
+ ytdl_sub-2025.11.7.post1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
164
+ ytdl_sub-2025.11.7.post1.dist-info/entry_points.txt,sha256=K3T5235NlAI-WLmHCg5tzLZHqc33OLN5IY5fOGc9t10,48
165
+ ytdl_sub-2025.11.7.post1.dist-info/top_level.txt,sha256=6z-JWazl6jXspC2DNyxOnGnEqYyGzVbgcBDoXfbkUhI,9
166
+ ytdl_sub-2025.11.7.post1.dist-info/RECORD,,