cinnamon-cli 0.2.29__tar.gz → 0.2.31__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 (35) hide show
  1. {cinnamon_cli-0.2.29/cinnamon_cli.egg-info → cinnamon_cli-0.2.31}/PKG-INFO +1 -1
  2. cinnamon_cli-0.2.31/cinnamon/__init__.py +1 -0
  3. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/player.py +27 -21
  4. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/scrapers/webstream.py +22 -14
  5. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31/cinnamon_cli.egg-info}/PKG-INFO +1 -1
  6. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/pyproject.toml +1 -1
  7. cinnamon_cli-0.2.29/cinnamon/__init__.py +0 -1
  8. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/LICENSE +0 -0
  9. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/README.md +0 -0
  10. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/anilist.py +0 -0
  11. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/cli.py +0 -0
  12. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/config.py +0 -0
  13. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/downloads.py +0 -0
  14. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/errors.py +0 -0
  15. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/history.py +0 -0
  16. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/scrapers/__init__.py +0 -0
  17. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/scrapers/anime.py +0 -0
  18. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/scrapers/base.py +0 -0
  19. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/scrapers/torrentio.py +0 -0
  20. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/scrapers/vidsrc.py +0 -0
  21. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/tmdb.py +0 -0
  22. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon/tui.py +0 -0
  23. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon_cli.egg-info/SOURCES.txt +0 -0
  24. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon_cli.egg-info/dependency_links.txt +0 -0
  25. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon_cli.egg-info/entry_points.txt +0 -0
  26. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon_cli.egg-info/requires.txt +0 -0
  27. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/cinnamon_cli.egg-info/top_level.txt +0 -0
  28. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/setup.cfg +0 -0
  29. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/tests/test_directstream.py +0 -0
  30. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/tests/test_directstream2.py +0 -0
  31. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/tests/test_directstream3.py +0 -0
  32. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/tests/test_directstream4.py +0 -0
  33. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/tests/test_directstream5.py +0 -0
  34. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/tests/test_directstream6.py +0 -0
  35. {cinnamon_cli-0.2.29 → cinnamon_cli-0.2.31}/tests/test_ui_smoke.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cinnamon-cli
3
- Version: 0.2.29
3
+ Version: 0.2.31
4
4
  Summary: CLI to search TV shows, movies & anime via TMDB/AniList, scrape m3u8 links, and play in VLC/mpv
5
5
  Author: pizza-droid
6
6
  License: CC BY-NC 4.0
@@ -0,0 +1 @@
1
+ __version__ = "0.2.31"
@@ -489,28 +489,31 @@ def download_video(url, title="", referer=None, output_dir=".", track_id=None):
489
489
 
490
490
  import re
491
491
  last_pct = -1
492
+ last_error = ""
492
493
  try:
493
494
  for line in proc.stdout:
494
- if "[download]" not in line:
495
- continue
496
- m = re.search(r"(\d+\.?\d*)%\s+of\s+~?\s*([\d.]+)(\w+).*ETA\s+(\S+)", line)
497
- if not m:
498
- m = re.search(r"(\d+\.?\d*)%\s+of\s+~?\s*([\d.]+)(\w+)", line)
499
- if m:
500
- pct = float(m.group(1))
501
- if int(pct) == last_pct:
502
- continue
503
- last_pct = int(pct)
504
- size_val = float(m.group(2))
505
- unit = m.group(3)
506
- eta = m.group(4) if m.lastindex >= 4 else ""
507
- bar_width = 25
508
- filled = int(bar_width * pct / 100)
509
- bar = "" * filled + "" * (bar_width - filled)
510
- eta_str = f" ETA {eta}" if eta else ""
511
- print(f"\r {bar} {pct:>5.1f}% {size_val:.1f}{unit}{eta_str} ", end="", file=sys.stderr, flush=True)
512
- else:
513
- print(f"\r {line.rstrip():<50}", file=sys.stderr, flush=True)
495
+ if "[download]" in line:
496
+ m = re.search(r"(\d+\.?\d*)%\s+of\s+~?\s*([\d.]+)(\w+).*ETA\s+(\S+)", line)
497
+ if not m:
498
+ m = re.search(r"(\d+\.?\d*)%\s+of\s+~?\s*([\d.]+)(\w+)", line)
499
+ if m:
500
+ pct = float(m.group(1))
501
+ if int(pct) == last_pct:
502
+ continue
503
+ last_pct = int(pct)
504
+ size_val = float(m.group(2))
505
+ unit = m.group(3)
506
+ eta = m.group(4) if m.lastindex >= 4 else ""
507
+ bar_width = 25
508
+ filled = int(bar_width * pct / 100)
509
+ bar = "█" * filled + "░" * (bar_width - filled)
510
+ eta_str = f" ETA {eta}" if eta else ""
511
+ print(f"\r {bar} {pct:>5.1f}% {size_val:.1f}{unit}{eta_str} ", end="", file=sys.stderr, flush=True)
512
+ else:
513
+ print(f"\r {line.rstrip():<50}", file=sys.stderr, flush=True)
514
+ elif "ERROR:" in line or "WARNING:" in line:
515
+ last_error = line.strip()
516
+ print(f" {line.rstrip()}", file=sys.stderr, flush=True)
514
517
 
515
518
  proc.wait()
516
519
  print(file=sys.stderr)
@@ -520,7 +523,10 @@ def download_video(url, title="", referer=None, output_dir=".", track_id=None):
520
523
  _track_update(track_id, status="completed")
521
524
  print(f" Done — {safe}", file=sys.stderr)
522
525
  else:
523
- raise PlayerLaunchError("yt-dlp", f"exit code {proc.returncode}")
526
+ detail = last_error or f"exit code {proc.returncode}"
527
+ if track_id:
528
+ _track_update(track_id, status="error")
529
+ raise PlayerLaunchError("yt-dlp", detail)
524
530
 
525
531
  except KeyboardInterrupt:
526
532
  print(file=sys.stderr)
@@ -75,7 +75,7 @@ class WebStreamScraper(BaseScraper):
75
75
 
76
76
  if _time.time() < deadline:
77
77
  try:
78
- result = vidlink_fn(tmdb_id)
78
+ result = vidlink_fn(tmdb_id, quality)
79
79
  if result:
80
80
  label = quality.upper() if quality else "Auto"
81
81
  return ScraperResult(
@@ -113,7 +113,7 @@ class WebStreamScraper(BaseScraper):
113
113
 
114
114
  if _time.time() < deadline:
115
115
  try:
116
- result = vidlink_fn(tmdb_id, season, episode)
116
+ result = vidlink_fn(tmdb_id, season, episode, quality)
117
117
  if result:
118
118
  label = quality.upper() if quality else "Auto"
119
119
  return ScraperResult(
@@ -194,7 +194,23 @@ def _try_vixsrc(tmdb_id, season, episode, quality="") -> Optional[str]:
194
194
  return match[1]
195
195
 
196
196
 
197
- def _try_vidlink(tmdb_id, season, episode) -> Optional[str]:
197
+ def _vidlink_quality_url(data, quality=""):
198
+ """vidlink returns direct mp4 URLs per resolution under stream.qualities."""
199
+ qualities = data.get("stream", {}).get("qualities", {})
200
+ if not qualities:
201
+ raise ScraperNetworkError("vidlink", "No qualities in stream response")
202
+ if quality and quality not in ("best", "worst"):
203
+ target = quality.replace("p", "")
204
+ if target in qualities:
205
+ return qualities[target]["url"]
206
+ if quality == "worst":
207
+ res = min(qualities, key=lambda r: int(r))
208
+ else:
209
+ res = max(qualities, key=lambda r: int(r))
210
+ return qualities[res]["url"]
211
+
212
+
213
+ def _try_vidlink(tmdb_id, season, episode, quality="") -> Optional[str]:
198
214
  session = requests.Session()
199
215
  session.headers.update({"User-Agent": UA})
200
216
 
@@ -222,11 +238,7 @@ def _try_vidlink(tmdb_id, season, episode) -> Optional[str]:
222
238
  data = stream_resp.json()
223
239
  except ValueError:
224
240
  raise ScraperNetworkError("vidlink", "Non-JSON response from stream API")
225
- playlist = data.get("stream", {}).get("playlist")
226
- if not playlist:
227
- raise ScraperNetworkError("vidlink", "No playlist in stream response")
228
-
229
- return playlist
241
+ return _vidlink_quality_url(data, quality)
230
242
 
231
243
 
232
244
  def _try_vixsrc_movie(tmdb_id, quality="") -> Optional[str]:
@@ -291,7 +303,7 @@ def _try_vixsrc_movie(tmdb_id, quality="") -> Optional[str]:
291
303
  return match[1]
292
304
 
293
305
 
294
- def _try_vidlink_movie(tmdb_id) -> Optional[str]:
306
+ def _try_vidlink_movie(tmdb_id, quality="") -> Optional[str]:
295
307
  session = requests.Session()
296
308
  session.headers.update({"User-Agent": UA})
297
309
 
@@ -319,8 +331,4 @@ def _try_vidlink_movie(tmdb_id) -> Optional[str]:
319
331
  data = stream_resp.json()
320
332
  except ValueError:
321
333
  raise ScraperNetworkError("vidlink", "Non-JSON response from stream API")
322
- playlist = data.get("stream", {}).get("playlist")
323
- if not playlist:
324
- raise ScraperNetworkError("vidlink", "No playlist in stream response")
325
-
326
- return playlist
334
+ return _vidlink_quality_url(data, quality)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cinnamon-cli
3
- Version: 0.2.29
3
+ Version: 0.2.31
4
4
  Summary: CLI to search TV shows, movies & anime via TMDB/AniList, scrape m3u8 links, and play in VLC/mpv
5
5
  Author: pizza-droid
6
6
  License: CC BY-NC 4.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cinnamon-cli"
7
- version = "0.2.29"
7
+ version = "0.2.31"
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.29"
File without changes
File without changes
File without changes