evo-cli 0.14.2__tar.gz → 0.14.4__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 (107) hide show
  1. {evo_cli-0.14.2 → evo_cli-0.14.4}/PKG-INFO +1 -1
  2. evo_cli-0.14.4/evo_cli/VERSION +1 -0
  3. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/download.py +208 -52
  4. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/gdrive.py +7 -11
  5. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/localproxy.py +80 -53
  6. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/netcheck.py +1 -4
  7. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/opencode.py +1 -4
  8. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/plantuml.py +108 -47
  9. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/wifi.py +22 -16
  10. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli.egg-info/PKG-INFO +1 -1
  11. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_console.py +13 -7
  12. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_download.py +31 -10
  13. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_gh.py +3 -1
  14. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_wifi.py +7 -3
  15. evo_cli-0.14.2/evo_cli/VERSION +0 -1
  16. {evo_cli-0.14.2 → evo_cli-0.14.4}/Containerfile +0 -0
  17. {evo_cli-0.14.2 → evo_cli-0.14.4}/HISTORY.md +0 -0
  18. {evo_cli-0.14.2 → evo_cli-0.14.4}/LICENSE +0 -0
  19. {evo_cli-0.14.2 → evo_cli-0.14.4}/MANIFEST.in +0 -0
  20. {evo_cli-0.14.2 → evo_cli-0.14.4}/README.md +0 -0
  21. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/__init__.py +0 -0
  22. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/__main__.py +0 -0
  23. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/base.py +0 -0
  24. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/cli.py +0 -0
  25. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/__init__.py +0 -0
  26. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/claude_code.py +0 -0
  27. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/cloudflare.py +0 -0
  28. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/cred.py +0 -0
  29. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/fix_claude.py +0 -0
  30. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/gh.py +0 -0
  31. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/__init__.py +0 -0
  32. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/_dag.py +0 -0
  33. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/_git.py +0 -0
  34. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/_model.py +0 -0
  35. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/_mutate.py +0 -0
  36. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/_paths.py +0 -0
  37. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/_render.py +0 -0
  38. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/_server.py +0 -0
  39. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/check.py +0 -0
  40. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/edit.py +0 -0
  41. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/pull.py +0 -0
  42. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/serve.py +0 -0
  43. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/show.py +0 -0
  44. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/views.py +0 -0
  45. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/index-BpeLRwRd.js +0 -0
  46. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/index-CiUsumT3.css +0 -0
  47. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  48. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  49. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  50. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  51. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  52. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  53. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  54. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  55. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  56. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  57. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  58. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  59. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/harness/web/index.html +0 -0
  60. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/hwid.py +0 -0
  61. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/hwid_reset.py +0 -0
  62. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/mcp.py +0 -0
  63. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/miniconda.py +0 -0
  64. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/site2s.py +0 -0
  65. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/ssh.py +0 -0
  66. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/sysmon.py +0 -0
  67. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/tts.py +0 -0
  68. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/commands/update.py +0 -0
  69. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/console.py +0 -0
  70. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/credentials/__init__.py +0 -0
  71. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/credentials/doctor.py +0 -0
  72. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/credentials/google_oauth.py +0 -0
  73. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/credentials/migrate.py +0 -0
  74. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/credentials/oauth_flow.py +0 -0
  75. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/credentials/registry.py +0 -0
  76. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/credentials/store.py +0 -0
  77. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/credentials/sync.py +0 -0
  78. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/mcp_registry.py +0 -0
  79. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/tts/__init__.py +0 -0
  80. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/tts/chunking.py +0 -0
  81. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/tts/core.py +0 -0
  82. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/tts/creds.py +0 -0
  83. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/tts/errors.py +0 -0
  84. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/tts/http.py +0 -0
  85. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/tts/openai.py +0 -0
  86. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/tts/player.py +0 -0
  87. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli/tts/vbee.py +0 -0
  88. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli.egg-info/SOURCES.txt +0 -0
  89. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli.egg-info/dependency_links.txt +0 -0
  90. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli.egg-info/entry_points.txt +0 -0
  91. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli.egg-info/requires.txt +0 -0
  92. {evo_cli-0.14.2 → evo_cli-0.14.4}/evo_cli.egg-info/top_level.txt +0 -0
  93. {evo_cli-0.14.2 → evo_cli-0.14.4}/pyproject.toml +0 -0
  94. {evo_cli-0.14.2 → evo_cli-0.14.4}/setup.cfg +0 -0
  95. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/__init__.py +0 -0
  96. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_claude_code.py +0 -0
  97. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_cli.py +0 -0
  98. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_cred.py +0 -0
  99. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_fix_claude.py +0 -0
  100. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_harness.py +0 -0
  101. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_harness_dag.py +0 -0
  102. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_mcp.py +0 -0
  103. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_opencode.py +0 -0
  104. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_plantuml.py +0 -0
  105. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_sysmon.py +0 -0
  106. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_tts.py +0 -0
  107. {evo_cli-0.14.2 → evo_cli-0.14.4}/tests/test_update.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evo_cli
3
- Version: 0.14.2
3
+ Version: 0.14.4
4
4
  Summary: Evolution CLI - a developer toolbox for setting up dev machines
5
5
  Author: maycuatroi
6
6
  Project-URL: Homepage, https://github.com/maycuatroi/evo-cli
@@ -0,0 +1 @@
1
+ 0.14.4
@@ -28,10 +28,38 @@ BROWSERS = ["chrome", "edge", "firefox", "brave", "chromium", "opera", "vivaldi"
28
28
  JS_RUNTIMES = ["deno", "bun", "node"]
29
29
 
30
30
  DIRECT_EXTS = {
31
- ".7z", ".apk", ".appimage", ".bin", ".bz2", ".csv", ".deb", ".dmg", ".doc", ".docx",
32
- ".epub", ".exe", ".gz", ".img", ".iso", ".jar", ".json", ".msi", ".pdf", ".ppt",
33
- ".pptx", ".rar", ".rpm", ".tar", ".tgz", ".txt", ".whl", ".xls", ".xlsx", ".xz",
34
- ".zip", ".zst",
31
+ ".7z",
32
+ ".apk",
33
+ ".appimage",
34
+ ".bin",
35
+ ".bz2",
36
+ ".csv",
37
+ ".deb",
38
+ ".dmg",
39
+ ".doc",
40
+ ".docx",
41
+ ".epub",
42
+ ".exe",
43
+ ".gz",
44
+ ".img",
45
+ ".iso",
46
+ ".jar",
47
+ ".json",
48
+ ".msi",
49
+ ".pdf",
50
+ ".ppt",
51
+ ".pptx",
52
+ ".rar",
53
+ ".rpm",
54
+ ".tar",
55
+ ".tgz",
56
+ ".txt",
57
+ ".whl",
58
+ ".xls",
59
+ ".xlsx",
60
+ ".xz",
61
+ ".zip",
62
+ ".zst",
35
63
  }
36
64
 
37
65
  SITES = [
@@ -317,9 +345,7 @@ def do_get(urls, opts, assume_yes):
317
345
  has_ffmpeg = bool(find_ffmpeg())
318
346
  if not has_ffmpeg:
319
347
  if opts["audio_only"]:
320
- raise click.ClickException(
321
- "ffmpeg is required to extract audio. Run `evo download install --with-deps`."
322
- )
348
+ raise click.ClickException("ffmpeg is required to extract audio. Run `evo download install --with-deps`.")
323
349
  warning("ffmpeg not found: falling back to single-file streams (lower quality).")
324
350
  info("Install it with `evo download install --with-deps` for the best quality.")
325
351
 
@@ -361,37 +387,65 @@ def download():
361
387
 
362
388
  def get_options(func):
363
389
  options = [
364
- click.option("-o", "--output", "outdir", type=click.Path(file_okay=False),
365
- default=None, help="Output folder. Default: `~/Downloads` (or `$EVO_DOWNLOAD_DIR`)."),
366
- click.option("-q", "--quality", type=click.Choice(QUALITIES), default="best",
367
- show_default=True, help="Cap the video resolution."),
368
- click.option("-c", "--container", type=click.Choice(CONTAINERS), default="mp4",
369
- show_default=True, help="Container to merge into. `auto` keeps whatever the site serves."),
390
+ click.option(
391
+ "-o",
392
+ "--output",
393
+ "outdir",
394
+ type=click.Path(file_okay=False),
395
+ default=None,
396
+ help="Output folder. Default: `~/Downloads` (or `$EVO_DOWNLOAD_DIR`).",
397
+ ),
398
+ click.option(
399
+ "-q",
400
+ "--quality",
401
+ type=click.Choice(QUALITIES),
402
+ default="best",
403
+ show_default=True,
404
+ help="Cap the video resolution.",
405
+ ),
406
+ click.option(
407
+ "-c",
408
+ "--container",
409
+ type=click.Choice(CONTAINERS),
410
+ default="mp4",
411
+ show_default=True,
412
+ help="Container to merge into. `auto` keeps whatever the site serves.",
413
+ ),
370
414
  click.option("-a", "--audio-only", is_flag=True, help="Grab the audio track only."),
371
- click.option("--audio-format", type=click.Choice(AUDIO_FORMATS), default="mp3",
372
- show_default=True, help="Audio codec to convert to with `-a`."),
373
- click.option("-f", "--format", "fmt", default=None,
374
- help="Raw yt-dlp format selector, overrides `-q` / `-a`."),
375
- click.option("-p", "--playlist", is_flag=True,
376
- help="Download the whole playlist / channel, not just the one video."),
377
- click.option("-s", "--subs", default=None, metavar="LANGS",
378
- help="Download and embed subtitles, e.g. `en,vi` or `all`."),
415
+ click.option(
416
+ "--audio-format",
417
+ type=click.Choice(AUDIO_FORMATS),
418
+ default="mp3",
419
+ show_default=True,
420
+ help="Audio codec to convert to with `-a`.",
421
+ ),
422
+ click.option("-f", "--format", "fmt", default=None, help="Raw yt-dlp format selector, overrides `-q` / `-a`."),
423
+ click.option(
424
+ "-p", "--playlist", is_flag=True, help="Download the whole playlist / channel, not just the one video."
425
+ ),
426
+ click.option(
427
+ "-s", "--subs", default=None, metavar="LANGS", help="Download and embed subtitles, e.g. `en,vi` or `all`."
428
+ ),
379
429
  click.option("--thumbnail", is_flag=True, help="Embed the thumbnail as cover art."),
380
430
  click.option("--sponsorblock", is_flag=True, help="Cut sponsor segments out (YouTube)."),
381
- click.option("--cookies", type=click.Choice(BROWSERS), default=None,
382
- help="Load cookies from a browser for private / age-gated / member-only media."),
383
- click.option("--archive", is_flag=True,
384
- help="Record what was downloaded and skip it next time."),
385
- click.option("--section", default=None, metavar="RANGE",
386
- help="Download only a time range, e.g. `10:00-15:00`."),
387
- click.option("--ascii", "ascii_names", is_flag=True,
388
- help="Restrict filenames to ASCII (no spaces or diacritics)."),
389
- click.option("-N", "--concurrent", type=int, default=4, show_default=True,
390
- help="Fragments to download in parallel."),
391
- click.option("-r", "--limit-rate", default=None, metavar="RATE",
392
- help="Cap the download speed, e.g. `2M`."),
393
- click.option("--name", default=None, metavar="TEMPLATE",
394
- help="yt-dlp output template, e.g. `%(id)s.%(ext)s`."),
431
+ click.option(
432
+ "--cookies",
433
+ type=click.Choice(BROWSERS),
434
+ default=None,
435
+ help="Load cookies from a browser for private / age-gated / member-only media.",
436
+ ),
437
+ click.option("--archive", is_flag=True, help="Record what was downloaded and skip it next time."),
438
+ click.option(
439
+ "--section", default=None, metavar="RANGE", help="Download only a time range, e.g. `10:00-15:00`."
440
+ ),
441
+ click.option(
442
+ "--ascii", "ascii_names", is_flag=True, help="Restrict filenames to ASCII (no spaces or diacritics)."
443
+ ),
444
+ click.option(
445
+ "-N", "--concurrent", type=int, default=4, show_default=True, help="Fragments to download in parallel."
446
+ ),
447
+ click.option("-r", "--limit-rate", default=None, metavar="RATE", help="Cap the download speed, e.g. `2M`."),
448
+ click.option("--name", default=None, metavar="TEMPLATE", help="yt-dlp output template, e.g. `%(id)s.%(ext)s`."),
395
449
  click.option("-y", "--yes", "assume_yes", is_flag=True, help="Assume yes for install prompts."),
396
450
  click.option("--dry-run", is_flag=True, help="Print the yt-dlp command instead of running it."),
397
451
  ]
@@ -400,9 +454,27 @@ def get_options(func):
400
454
  return func
401
455
 
402
456
 
403
- def collect_opts(outdir, quality, container, audio_only, audio_format, fmt, playlist, subs,
404
- thumbnail, sponsorblock, cookies, archive, section, ascii_names, concurrent,
405
- limit_rate, name, dry_run, list_formats=False):
457
+ def collect_opts(
458
+ outdir,
459
+ quality,
460
+ container,
461
+ audio_only,
462
+ audio_format,
463
+ fmt,
464
+ playlist,
465
+ subs,
466
+ thumbnail,
467
+ sponsorblock,
468
+ cookies,
469
+ archive,
470
+ section,
471
+ ascii_names,
472
+ concurrent,
473
+ limit_rate,
474
+ name,
475
+ dry_run,
476
+ list_formats=False,
477
+ ):
406
478
  return {
407
479
  "outdir": Path(outdir) if outdir else default_output_dir(),
408
480
  "quality": quality,
@@ -439,13 +511,49 @@ def collect_opts(outdir, quality, container, audio_only, audio_format, fmt, play
439
511
  )
440
512
  @click.argument("urls", nargs=-1, required=True, metavar="URLS...")
441
513
  @get_options
442
- def get_cmd(urls, outdir, quality, container, audio_only, audio_format, fmt, playlist, subs,
443
- thumbnail, sponsorblock, cookies, archive, section, ascii_names, concurrent,
444
- limit_rate, name, assume_yes, dry_run):
514
+ def get_cmd(
515
+ urls,
516
+ outdir,
517
+ quality,
518
+ container,
519
+ audio_only,
520
+ audio_format,
521
+ fmt,
522
+ playlist,
523
+ subs,
524
+ thumbnail,
525
+ sponsorblock,
526
+ cookies,
527
+ archive,
528
+ section,
529
+ ascii_names,
530
+ concurrent,
531
+ limit_rate,
532
+ name,
533
+ assume_yes,
534
+ dry_run,
535
+ ):
445
536
  step("evo download")
446
- opts = collect_opts(outdir, quality, container, audio_only, audio_format, fmt, playlist,
447
- subs, thumbnail, sponsorblock, cookies, archive, section, ascii_names,
448
- concurrent, limit_rate, name, dry_run)
537
+ opts = collect_opts(
538
+ outdir,
539
+ quality,
540
+ container,
541
+ audio_only,
542
+ audio_format,
543
+ fmt,
544
+ playlist,
545
+ subs,
546
+ thumbnail,
547
+ sponsorblock,
548
+ cookies,
549
+ archive,
550
+ section,
551
+ ascii_names,
552
+ concurrent,
553
+ limit_rate,
554
+ name,
555
+ dry_run,
556
+ )
449
557
  do_get(list(urls), opts, assume_yes)
450
558
 
451
559
 
@@ -456,18 +564,47 @@ def get_cmd(urls, outdir, quality, container, audio_only, audio_format, fmt, pla
456
564
  help="Download `URLS` as audio only. Shortcut for `evo download get -a`.",
457
565
  )
458
566
  @click.argument("urls", nargs=-1, required=True, metavar="URLS...")
459
- @click.option("-o", "--output", "outdir", type=click.Path(file_okay=False), default=None,
460
- help="Output folder. Default: `~/Downloads`.")
461
- @click.option("--audio-format", type=click.Choice(AUDIO_FORMATS), default="mp3",
462
- show_default=True, help="Audio codec to convert to.")
567
+ @click.option(
568
+ "-o",
569
+ "--output",
570
+ "outdir",
571
+ type=click.Path(file_okay=False),
572
+ default=None,
573
+ help="Output folder. Default: `~/Downloads`.",
574
+ )
575
+ @click.option(
576
+ "--audio-format",
577
+ type=click.Choice(AUDIO_FORMATS),
578
+ default="mp3",
579
+ show_default=True,
580
+ help="Audio codec to convert to.",
581
+ )
463
582
  @click.option("-p", "--playlist", is_flag=True, help="Download the whole playlist.")
464
583
  @click.option("--thumbnail", is_flag=True, help="Embed the thumbnail as cover art.")
465
584
  @click.option("--cookies", type=click.Choice(BROWSERS), default=None, help="Load cookies from a browser.")
466
585
  @click.option("-y", "--yes", "assume_yes", is_flag=True, help="Assume yes for install prompts.")
467
586
  def audio_cmd(urls, outdir, audio_format, playlist, thumbnail, cookies, assume_yes):
468
587
  step("evo download audio")
469
- opts = collect_opts(outdir, "best", "auto", True, audio_format, None, playlist, None,
470
- thumbnail, False, cookies, False, None, False, 4, None, None, False)
588
+ opts = collect_opts(
589
+ outdir,
590
+ "best",
591
+ "auto",
592
+ True,
593
+ audio_format,
594
+ None,
595
+ playlist,
596
+ None,
597
+ thumbnail,
598
+ False,
599
+ cookies,
600
+ False,
601
+ None,
602
+ False,
603
+ 4,
604
+ None,
605
+ None,
606
+ False,
607
+ )
471
608
  do_get(list(urls), opts, assume_yes)
472
609
 
473
610
 
@@ -481,8 +618,27 @@ def audio_cmd(urls, outdir, audio_format, playlist, thumbnail, cookies, assume_y
481
618
  @click.option("-y", "--yes", "assume_yes", is_flag=True, help="Assume yes for install prompts.")
482
619
  def formats_cmd(url, cookies, assume_yes):
483
620
  step("evo download formats")
484
- opts = collect_opts(None, "best", "auto", False, "mp3", None, False, None, False, False,
485
- cookies, False, None, False, 4, None, None, False, list_formats=True)
621
+ opts = collect_opts(
622
+ None,
623
+ "best",
624
+ "auto",
625
+ False,
626
+ "mp3",
627
+ None,
628
+ False,
629
+ None,
630
+ False,
631
+ False,
632
+ cookies,
633
+ False,
634
+ None,
635
+ False,
636
+ 4,
637
+ None,
638
+ None,
639
+ False,
640
+ list_formats=True,
641
+ )
486
642
  do_get([url], opts, assume_yes)
487
643
 
488
644
 
@@ -148,8 +148,10 @@ def download_image(url, dest_path, token=None):
148
148
 
149
149
 
150
150
  def fetch_file_metadata(file_id, token):
151
- url = DRIVE_FILE_API.format(file_id=file_id) + "?" + urllib.parse.urlencode(
152
- {"fields": "id,name,mimeType,modifiedTime"}
151
+ url = (
152
+ DRIVE_FILE_API.format(file_id=file_id)
153
+ + "?"
154
+ + urllib.parse.urlencode({"fields": "id,name,mimeType,modifiedTime"})
153
155
  )
154
156
  body, _ = http_get(url, token=token)
155
157
  return json.loads(body.decode("utf-8"))
@@ -275,9 +277,7 @@ def render_table(table, inline_objects, list_props_by_id, image_resolver):
275
277
  for element in cell.get("content") or []:
276
278
  if "paragraph" in element:
277
279
  cell_parts.append(
278
- render_paragraph(
279
- element["paragraph"], inline_objects, list_props_by_id, image_resolver
280
- ).strip()
280
+ render_paragraph(element["paragraph"], inline_objects, list_props_by_id, image_resolver).strip()
281
281
  )
282
282
  rendered_cells.append(" ".join(p for p in cell_parts if p).replace("|", "\\|"))
283
283
  rendered_rows.append("| " + " | ".join(rendered_cells) + " |")
@@ -292,9 +292,7 @@ def document_to_markdown(document, image_resolver):
292
292
  body = document.get("body") or {}
293
293
  content = body.get("content") or []
294
294
  inline_objects = document.get("inlineObjects") or {}
295
- list_props_by_id = {
296
- lid: lst.get("listProperties") or {} for lid, lst in (document.get("lists") or {}).items()
297
- }
295
+ list_props_by_id = {lid: lst.get("listProperties") or {} for lid, lst in (document.get("lists") or {}).items()}
298
296
  title = document.get("title") or "Document"
299
297
  out_parts = [f"# {title}\n"]
300
298
  for element in content:
@@ -425,9 +423,7 @@ def run_doc_read(target, out_dir, no_images, raw, via_docs_api):
425
423
  info(f"Title: [accent]{title}[/accent]")
426
424
  info(f"Output: [accent]{target_dir}[/accent]")
427
425
  if raw:
428
- (target_dir / "raw.json").write_text(
429
- json.dumps(document, indent=2, ensure_ascii=False), encoding="utf-8"
430
- )
426
+ (target_dir / "raw.json").write_text(json.dumps(document, indent=2, ensure_ascii=False), encoding="utf-8")
431
427
  info(f"Wrote raw API response to [accent]{target_dir / 'raw.json'}[/accent]")
432
428
  resolver = build_image_resolver(document.get("inlineObjects") or {}, target_dir, no_images)
433
429
  markdown = document_to_markdown(document, resolver)