evo-cli 0.19.0__tar.gz → 0.20.0__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.
- {evo_cli-0.19.0 → evo_cli-0.20.0}/PKG-INFO +1 -1
- evo_cli-0.20.0/evo_cli/VERSION +1 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/download.py +51 -6
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli.egg-info/PKG-INFO +1 -1
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_download.py +58 -0
- evo_cli-0.19.0/evo_cli/VERSION +0 -1
- {evo_cli-0.19.0 → evo_cli-0.20.0}/Containerfile +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/HISTORY.md +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/LICENSE +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/MANIFEST.in +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/README.md +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/__init__.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/__main__.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/base.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/cli.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/__init__.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/agent_toy.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/claude_code.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/cloudflare.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/cred.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/fix_claude.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/gdrive.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/gh.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/__init__.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/_dag.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/_git.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/_model.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/_mutate.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/_paths.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/_render.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/_server.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/check.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/clone.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/edit.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/pull.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/serve.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/show.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/views.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/index-CsALFg16.css +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/index-DwEXL5pV.js +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/harness/web/index.html +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/hwid.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/hwid_reset.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/localproxy.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/mcp.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/miniconda.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/netcheck.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/opencode.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/plantuml.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/serp.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/site2s.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/ssh.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/sysmon.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/tts.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/update.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/commands/wifi.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/console.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/credentials/__init__.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/credentials/doctor.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/credentials/google_oauth.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/credentials/migrate.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/credentials/oauth_flow.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/credentials/registry.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/credentials/store.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/credentials/sync.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/mcp_registry.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/serp/__init__.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/serp/client.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/serp/creds.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/serp/errors.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/serp/install.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/serp/render.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/tts/__init__.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/tts/chunking.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/tts/core.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/tts/creds.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/tts/errors.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/tts/http.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/tts/openai.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/tts/player.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli/tts/vbee.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli.egg-info/SOURCES.txt +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli.egg-info/dependency_links.txt +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli.egg-info/entry_points.txt +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli.egg-info/requires.txt +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/evo_cli.egg-info/top_level.txt +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/pyproject.toml +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/setup.cfg +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/__init__.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_agent_toy.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_claude_code.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_cli.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_console.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_cred.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_fix_claude.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_gh.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_harness.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_harness_clone.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_harness_dag.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_mcp.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_opencode.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_plantuml.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_serp.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_sysmon.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_tts.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_update.py +0 -0
- {evo_cli-0.19.0 → evo_cli-0.20.0}/tests/test_wifi.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.20.0
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import datetime
|
|
1
2
|
import importlib.util
|
|
2
3
|
import os
|
|
3
4
|
import shutil
|
|
@@ -26,6 +27,7 @@ AUDIO_FORMATS = ["mp3", "m4a", "opus", "flac", "wav", "aac", "vorbis", "best"]
|
|
|
26
27
|
CONTAINERS = ["mp4", "mkv", "webm", "auto"]
|
|
27
28
|
BROWSERS = ["chrome", "edge", "firefox", "brave", "chromium", "opera", "vivaldi", "safari"]
|
|
28
29
|
JS_RUNTIMES = ["deno", "bun", "node"]
|
|
30
|
+
YTDLP_STALE_DAYS = 60
|
|
29
31
|
|
|
30
32
|
DIRECT_EXTS = {
|
|
31
33
|
".7z",
|
|
@@ -137,6 +139,38 @@ def ytdlp_version():
|
|
|
137
139
|
return (result.stdout or "").strip() or None
|
|
138
140
|
|
|
139
141
|
|
|
142
|
+
def ytdlp_stale_age(version=None):
|
|
143
|
+
"""Days since the installed build was released, or None if it is recent enough.
|
|
144
|
+
|
|
145
|
+
Sites like YouTube change their streaming setup every few months, so an old
|
|
146
|
+
yt-dlp fails with 403s that look like a bug in this command.
|
|
147
|
+
"""
|
|
148
|
+
if version is None:
|
|
149
|
+
version = ytdlp_version()
|
|
150
|
+
if not version:
|
|
151
|
+
return None
|
|
152
|
+
parts = version.split(".")[:3]
|
|
153
|
+
if len(parts) < 3:
|
|
154
|
+
return None
|
|
155
|
+
try:
|
|
156
|
+
released = datetime.date(int(parts[0]), int(parts[1]), int(parts[2]))
|
|
157
|
+
except ValueError:
|
|
158
|
+
return None
|
|
159
|
+
age = (datetime.date.today() - released).days
|
|
160
|
+
return age if age >= YTDLP_STALE_DAYS else None
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def warn_if_stale(version=None):
|
|
164
|
+
if version is None:
|
|
165
|
+
version = ytdlp_version()
|
|
166
|
+
age = ytdlp_stale_age(version)
|
|
167
|
+
if age is None:
|
|
168
|
+
return False
|
|
169
|
+
warning(f"yt-dlp {version} is {age} days old: sites change often and old builds start failing with 403s.")
|
|
170
|
+
info("Update it with `evo download install`.")
|
|
171
|
+
return True
|
|
172
|
+
|
|
173
|
+
|
|
140
174
|
def find_ffmpeg():
|
|
141
175
|
return shutil.which("ffmpeg")
|
|
142
176
|
|
|
@@ -197,6 +231,7 @@ def install_ffmpeg(assume_yes):
|
|
|
197
231
|
def ensure_ytdlp(assume_yes=False):
|
|
198
232
|
cmd = ytdlp_command()
|
|
199
233
|
if cmd:
|
|
234
|
+
warn_if_stale()
|
|
200
235
|
return cmd
|
|
201
236
|
warning("yt-dlp is not installed.")
|
|
202
237
|
if not assume_yes and not click.confirm("Install yt-dlp now with pip?", default=True):
|
|
@@ -295,11 +330,15 @@ def report_environment():
|
|
|
295
330
|
table.add_column("Component", style="info", no_wrap=True)
|
|
296
331
|
table.add_column("Status", no_wrap=True)
|
|
297
332
|
table.add_column("Detail", style="dim")
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
333
|
+
age = ytdlp_stale_age(version)
|
|
334
|
+
if not version:
|
|
335
|
+
ytdlp_status, ytdlp_detail = "[error]missing[/error]", "run `evo download install`"
|
|
336
|
+
elif age is not None:
|
|
337
|
+
ytdlp_status = "[warning]stale[/warning]"
|
|
338
|
+
ytdlp_detail = f"{version} ({age} days old) - run `evo download install`"
|
|
339
|
+
else:
|
|
340
|
+
ytdlp_status, ytdlp_detail = "[success]ok[/success]", version
|
|
341
|
+
table.add_row("yt-dlp", ytdlp_status, ytdlp_detail)
|
|
303
342
|
table.add_row(
|
|
304
343
|
"ffmpeg",
|
|
305
344
|
"[success]ok[/success]" if ffmpeg else "[error]missing[/error]",
|
|
@@ -356,6 +395,10 @@ def do_get(urls, opts, assume_yes):
|
|
|
356
395
|
|
|
357
396
|
result = run_command(cmd, check=False)
|
|
358
397
|
if result.returncode != 0:
|
|
398
|
+
if ytdlp_stale_age() is not None:
|
|
399
|
+
raise click.ClickException(
|
|
400
|
+
"yt-dlp failed and the installed build is stale. Run `evo download install`, then try again."
|
|
401
|
+
)
|
|
359
402
|
raise click.ClickException("yt-dlp failed. Try `evo download formats <url>` to inspect the source.")
|
|
360
403
|
if not opts["list_formats"]:
|
|
361
404
|
success(f"Saved to [accent]{outdir}[/accent]")
|
|
@@ -675,8 +718,10 @@ def install_cmd(with_deps, assume_yes):
|
|
|
675
718
|
def check_cmd():
|
|
676
719
|
step("evo download check")
|
|
677
720
|
report_environment()
|
|
678
|
-
|
|
721
|
+
version = ytdlp_version()
|
|
722
|
+
if not version:
|
|
679
723
|
raise click.ClickException("yt-dlp is missing. Run `evo download install`.")
|
|
724
|
+
warn_if_stale(version)
|
|
680
725
|
if not find_ffmpeg():
|
|
681
726
|
warning("ffmpeg missing: merging and audio conversion will not work.")
|
|
682
727
|
info("Fix it with `evo download install --with-deps`.")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import datetime
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
|
|
3
4
|
import pytest
|
|
@@ -231,3 +232,60 @@ def test_check_fails_without_ytdlp(monkeypatch):
|
|
|
231
232
|
monkeypatch.setattr(dl, "ytdlp_version", lambda: None)
|
|
232
233
|
result = CliRunner().invoke(cli, ["download", "check"])
|
|
233
234
|
assert result.exit_code != 0
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def version_released_days_ago(days):
|
|
238
|
+
released = datetime.date.today() - datetime.timedelta(days=days)
|
|
239
|
+
return f"{released.year}.{released.month:02d}.{released.day:02d}"
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def test_recent_ytdlp_is_not_stale():
|
|
243
|
+
assert dl.ytdlp_stale_age(version_released_days_ago(3)) is None
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def test_old_ytdlp_reports_its_age():
|
|
247
|
+
assert dl.ytdlp_stale_age(version_released_days_ago(200)) == 200
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def test_nightly_ytdlp_build_still_parses():
|
|
251
|
+
assert dl.ytdlp_stale_age(version_released_days_ago(90) + ".232919") == 90
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@pytest.mark.parametrize("version", [None, "", "2026", "2026.13.99", "unknown"])
|
|
255
|
+
def test_unparsable_ytdlp_version_is_not_stale(version):
|
|
256
|
+
assert dl.ytdlp_stale_age(version) is None
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def test_check_warns_when_ytdlp_is_stale(monkeypatch):
|
|
260
|
+
monkeypatch.setattr(dl, "ytdlp_version", lambda: version_released_days_ago(200))
|
|
261
|
+
monkeypatch.setattr(dl, "find_ffmpeg", lambda: "/usr/bin/ffmpeg")
|
|
262
|
+
monkeypatch.setattr(dl, "find_js_runtime", lambda: ("node", "/usr/bin/node"))
|
|
263
|
+
result = CliRunner().invoke(cli, ["download", "check"])
|
|
264
|
+
assert result.exit_code == 0
|
|
265
|
+
assert "200 days old" in result.output.replace("\n", "")
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def test_failure_on_stale_ytdlp_points_at_the_update(monkeypatch, tmp_path):
|
|
269
|
+
class Failed:
|
|
270
|
+
returncode = 1
|
|
271
|
+
|
|
272
|
+
monkeypatch.setattr(dl, "ensure_ytdlp", lambda assume_yes=False: ["yt-dlp"])
|
|
273
|
+
monkeypatch.setattr(dl, "find_ffmpeg", lambda: "/usr/bin/ffmpeg")
|
|
274
|
+
monkeypatch.setattr(dl, "ytdlp_version", lambda: version_released_days_ago(200))
|
|
275
|
+
monkeypatch.setattr(dl, "run_command", lambda *a, **kw: Failed())
|
|
276
|
+
result = CliRunner().invoke(cli, ["download", YOUTUBE, "-o", str(tmp_path)])
|
|
277
|
+
assert result.exit_code != 0
|
|
278
|
+
assert "evo download install" in result.output.replace("\n", "")
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def test_failure_on_fresh_ytdlp_keeps_the_formats_hint(monkeypatch, tmp_path):
|
|
282
|
+
class Failed:
|
|
283
|
+
returncode = 1
|
|
284
|
+
|
|
285
|
+
monkeypatch.setattr(dl, "ensure_ytdlp", lambda assume_yes=False: ["yt-dlp"])
|
|
286
|
+
monkeypatch.setattr(dl, "find_ffmpeg", lambda: "/usr/bin/ffmpeg")
|
|
287
|
+
monkeypatch.setattr(dl, "ytdlp_version", lambda: version_released_days_ago(3))
|
|
288
|
+
monkeypatch.setattr(dl, "run_command", lambda *a, **kw: Failed())
|
|
289
|
+
result = CliRunner().invoke(cli, ["download", YOUTUBE, "-o", str(tmp_path)])
|
|
290
|
+
assert result.exit_code != 0
|
|
291
|
+
assert "evo download formats" in result.output.replace("\n", "")
|
evo_cli-0.19.0/evo_cli/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.19.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|