cinnamon-cli 0.2.30__tar.gz → 0.2.32__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.
- {cinnamon_cli-0.2.30/cinnamon_cli.egg-info → cinnamon_cli-0.2.32}/PKG-INFO +1 -1
- cinnamon_cli-0.2.32/cinnamon/__init__.py +1 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/player.py +31 -21
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/scrapers/webstream.py +9 -21
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32/cinnamon_cli.egg-info}/PKG-INFO +1 -1
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/pyproject.toml +1 -1
- cinnamon_cli-0.2.30/cinnamon/__init__.py +0 -1
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/LICENSE +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/README.md +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/anilist.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/cli.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/config.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/downloads.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/errors.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/history.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/scrapers/__init__.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/scrapers/anime.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/scrapers/base.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/scrapers/torrentio.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/scrapers/vidsrc.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/tmdb.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon/tui.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon_cli.egg-info/SOURCES.txt +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon_cli.egg-info/dependency_links.txt +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon_cli.egg-info/entry_points.txt +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon_cli.egg-info/requires.txt +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/cinnamon_cli.egg-info/top_level.txt +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/setup.cfg +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/tests/test_directstream.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/tests/test_directstream2.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/tests/test_directstream3.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/tests/test_directstream4.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/tests/test_directstream5.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/tests/test_directstream6.py +0 -0
- {cinnamon_cli-0.2.30 → cinnamon_cli-0.2.32}/tests/test_ui_smoke.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.32"
|
|
@@ -472,6 +472,10 @@ def download_video(url, title="", referer=None, output_dir=".", track_id=None):
|
|
|
472
472
|
|
|
473
473
|
cmd = [
|
|
474
474
|
exe, "--no-mtime", "--no-warnings", "-o", outtmpl,
|
|
475
|
+
"--retries", "10",
|
|
476
|
+
"--fragment-retries", "10",
|
|
477
|
+
"--retry-sleep", "2",
|
|
478
|
+
"--socket-timeout", "60",
|
|
475
479
|
]
|
|
476
480
|
if referer:
|
|
477
481
|
cmd += ["--referer", referer]
|
|
@@ -489,28 +493,31 @@ def download_video(url, title="", referer=None, output_dir=".", track_id=None):
|
|
|
489
493
|
|
|
490
494
|
import re
|
|
491
495
|
last_pct = -1
|
|
496
|
+
last_error = ""
|
|
492
497
|
try:
|
|
493
498
|
for line in proc.stdout:
|
|
494
|
-
if "[download]"
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
m
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
499
|
+
if "[download]" in line:
|
|
500
|
+
m = re.search(r"(\d+\.?\d*)%\s+of\s+~?\s*([\d.]+)(\w+).*ETA\s+(\S+)", line)
|
|
501
|
+
if not m:
|
|
502
|
+
m = re.search(r"(\d+\.?\d*)%\s+of\s+~?\s*([\d.]+)(\w+)", line)
|
|
503
|
+
if m:
|
|
504
|
+
pct = float(m.group(1))
|
|
505
|
+
if int(pct) == last_pct:
|
|
506
|
+
continue
|
|
507
|
+
last_pct = int(pct)
|
|
508
|
+
size_val = float(m.group(2))
|
|
509
|
+
unit = m.group(3)
|
|
510
|
+
eta = m.group(4) if m.lastindex >= 4 else ""
|
|
511
|
+
bar_width = 25
|
|
512
|
+
filled = int(bar_width * pct / 100)
|
|
513
|
+
bar = "█" * filled + "░" * (bar_width - filled)
|
|
514
|
+
eta_str = f" ETA {eta}" if eta else ""
|
|
515
|
+
print(f"\r {bar} {pct:>5.1f}% {size_val:.1f}{unit}{eta_str} ", end="", file=sys.stderr, flush=True)
|
|
516
|
+
else:
|
|
517
|
+
print(f"\r {line.rstrip():<50}", file=sys.stderr, flush=True)
|
|
518
|
+
elif "ERROR:" in line or "WARNING:" in line:
|
|
519
|
+
last_error = line.strip()
|
|
520
|
+
print(f" {line.rstrip()}", file=sys.stderr, flush=True)
|
|
514
521
|
|
|
515
522
|
proc.wait()
|
|
516
523
|
print(file=sys.stderr)
|
|
@@ -520,7 +527,10 @@ def download_video(url, title="", referer=None, output_dir=".", track_id=None):
|
|
|
520
527
|
_track_update(track_id, status="completed")
|
|
521
528
|
print(f" Done — {safe}", file=sys.stderr)
|
|
522
529
|
else:
|
|
523
|
-
|
|
530
|
+
detail = last_error or f"exit code {proc.returncode}"
|
|
531
|
+
if track_id:
|
|
532
|
+
_track_update(track_id, status="error")
|
|
533
|
+
raise PlayerLaunchError("yt-dlp", detail)
|
|
524
534
|
|
|
525
535
|
except KeyboardInterrupt:
|
|
526
536
|
print(file=sys.stderr)
|
|
@@ -42,9 +42,9 @@ class WebStreamScraper(BaseScraper):
|
|
|
42
42
|
season = episode_info.get("season", 1)
|
|
43
43
|
episode = episode_info.get("episode", 1)
|
|
44
44
|
quality = episode_info.get("quality", "")
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
|
|
45
|
+
# vixsrc first (sequential HLS that yt-dlp handles reliably); vidlink is the
|
|
46
|
+
# fallback. vidlink's .mp4 CDN (bcdn/stormvv) rate-limits aggressively (HTTP
|
|
47
|
+
# 429), so it is not preferred for downloads.
|
|
48
48
|
|
|
49
49
|
if not tmdb_id:
|
|
50
50
|
raise ScraperParseError(self.name, "Missing tmdb_id/movie_id/tv_id in episode_info")
|
|
@@ -52,16 +52,10 @@ class WebStreamScraper(BaseScraper):
|
|
|
52
52
|
deadline = _time.time() + 30
|
|
53
53
|
|
|
54
54
|
if media_type == "movie":
|
|
55
|
-
|
|
56
|
-
vixsrc_fn, vidlink_fn = _try_vidlink_movie, _try_vixsrc_movie
|
|
57
|
-
vixsrc_ref = f"https://vixsrc.to/embed/movie/{tmdb_id}"
|
|
58
|
-
else:
|
|
59
|
-
vixsrc_fn, vidlink_fn = _try_vixsrc_movie, _try_vidlink_movie
|
|
60
|
-
vixsrc_ref = f"https://vixsrc.to/embed/movie/{tmdb_id}"
|
|
61
|
-
|
|
55
|
+
vixsrc_ref = f"https://vixsrc.to/embed/movie/{tmdb_id}"
|
|
62
56
|
if _time.time() < deadline:
|
|
63
57
|
try:
|
|
64
|
-
result =
|
|
58
|
+
result = _try_vixsrc_movie(tmdb_id, quality)
|
|
65
59
|
if result:
|
|
66
60
|
label = quality.upper() if quality else "Auto"
|
|
67
61
|
return ScraperResult(
|
|
@@ -75,7 +69,7 @@ class WebStreamScraper(BaseScraper):
|
|
|
75
69
|
|
|
76
70
|
if _time.time() < deadline:
|
|
77
71
|
try:
|
|
78
|
-
result =
|
|
72
|
+
result = _try_vidlink_movie(tmdb_id, quality)
|
|
79
73
|
if result:
|
|
80
74
|
label = quality.upper() if quality else "Auto"
|
|
81
75
|
return ScraperResult(
|
|
@@ -90,16 +84,10 @@ class WebStreamScraper(BaseScraper):
|
|
|
90
84
|
raise ScraperNoStreamError(self.name, f"No HTTP stream found for {show}")
|
|
91
85
|
|
|
92
86
|
# TV
|
|
93
|
-
|
|
94
|
-
vixsrc_fn, vidlink_fn = _try_vidlink, _try_vixsrc
|
|
95
|
-
vixsrc_ref = f"https://vixsrc.to/embed/tv/{tmdb_id}/{season}/{episode}"
|
|
96
|
-
else:
|
|
97
|
-
vixsrc_fn, vidlink_fn = _try_vixsrc, _try_vidlink
|
|
98
|
-
vixsrc_ref = f"https://vixsrc.to/embed/tv/{tmdb_id}/{season}/{episode}"
|
|
99
|
-
|
|
87
|
+
vixsrc_ref = f"https://vixsrc.to/embed/tv/{tmdb_id}/{season}/{episode}"
|
|
100
88
|
if _time.time() < deadline:
|
|
101
89
|
try:
|
|
102
|
-
result =
|
|
90
|
+
result = _try_vixsrc(tmdb_id, season, episode, quality)
|
|
103
91
|
if result:
|
|
104
92
|
label = quality.upper() if quality else "Auto"
|
|
105
93
|
return ScraperResult(
|
|
@@ -113,7 +101,7 @@ class WebStreamScraper(BaseScraper):
|
|
|
113
101
|
|
|
114
102
|
if _time.time() < deadline:
|
|
115
103
|
try:
|
|
116
|
-
result =
|
|
104
|
+
result = _try_vidlink(tmdb_id, season, episode, quality)
|
|
117
105
|
if result:
|
|
118
106
|
label = quality.upper() if quality else "Auto"
|
|
119
107
|
return ScraperResult(
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cinnamon-cli"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.32"
|
|
8
8
|
description = "CLI to search TV shows, movies & anime via TMDB/AniList, scrape m3u8 links, and play in VLC/mpv"
|
|
9
9
|
license = { text = "CC BY-NC 4.0" }
|
|
10
10
|
readme = "README.md"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.30"
|
|
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
|