ytm-cli 0.7.2__tar.gz → 0.7.3__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.
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/PKG-INFO +7 -3
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/README.md +1 -1
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/pyproject.toml +7 -3
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/__init__.py +1 -1
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/dislikes.py +1 -1
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/ffmpeg_player.py +1 -1
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/hybrid_player.py +1 -1
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/main.py +4 -4
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/player.py +4 -4
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/playlists.py +1 -1
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/spectrum.py +1 -1
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/ui.py +2 -2
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli.egg-info/PKG-INFO +7 -3
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/LICENSE +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/setup.cfg +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_cache.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_config.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_dislikes.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_ffmpeg_player.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_hybrid_player.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_integration.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_lyrics_service.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_main.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_playlists.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_runner.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_spectrum.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_ui.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/tests/test_utils.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/__main__.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/cache.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/config.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/demo.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/llm_client.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/lyrics_service.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/utils.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli/verbose_logger.py +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli.egg-info/SOURCES.txt +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli.egg-info/dependency_links.txt +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli.egg-info/entry_points.txt +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli.egg-info/requires.txt +0 -0
- {ytm_cli-0.7.2 → ytm_cli-0.7.3}/ytm_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ytm-cli
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.3
|
|
4
4
|
Summary: YouTube Music CLI tool with interactive terminal interface
|
|
5
5
|
Author-email: thieuluan <thieuluan.dark@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -14,9 +14,13 @@ Classifier: Intended Audience :: End Users/Desktop
|
|
|
14
14
|
Classifier: Operating System :: POSIX :: Linux
|
|
15
15
|
Classifier: Operating System :: MacOS
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
21
|
Classifier: Programming Language :: Python :: 3.14
|
|
18
22
|
Classifier: Topic :: Multimedia :: Sound/Audio :: Players
|
|
19
|
-
Requires-Python: >=3.
|
|
23
|
+
Requires-Python: >=3.10
|
|
20
24
|
Description-Content-Type: text/markdown
|
|
21
25
|
License-File: LICENSE
|
|
22
26
|
Requires-Dist: ytmusicapi
|
|
@@ -60,7 +64,7 @@ Stream music directly from YouTube Music in your terminal with intuitive control
|
|
|
60
64
|
|
|
61
65
|
### Requirements
|
|
62
66
|
|
|
63
|
-
- Python **3.
|
|
67
|
+
- Python **3.10+** (set in `pyproject.toml`)
|
|
64
68
|
- [mpv media player](https://mpv.io/installation/) (must be installed system-wide)
|
|
65
69
|
- [`ffmpeg`](https://ffmpeg.org/) on `PATH` for the real-time spectrum visualizer (optional — falls back to a stereo oscilloscope if missing)
|
|
66
70
|
|
|
@@ -31,7 +31,7 @@ Stream music directly from YouTube Music in your terminal with intuitive control
|
|
|
31
31
|
|
|
32
32
|
### Requirements
|
|
33
33
|
|
|
34
|
-
- Python **3.
|
|
34
|
+
- Python **3.10+** (set in `pyproject.toml`)
|
|
35
35
|
- [mpv media player](https://mpv.io/installation/) (must be installed system-wide)
|
|
36
36
|
- [`ffmpeg`](https://ffmpeg.org/) on `PATH` for the real-time spectrum visualizer (optional — falls back to a stereo oscilloscope if missing)
|
|
37
37
|
|
|
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ytm-cli"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.3"
|
|
8
8
|
description = "YouTube Music CLI tool with interactive terminal interface"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
11
|
-
requires-python = ">=3.
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
12
|
authors = [
|
|
13
13
|
{ name = "thieuluan", email = "thieuluan.dark@gmail.com" },
|
|
14
14
|
]
|
|
@@ -20,6 +20,10 @@ classifiers = [
|
|
|
20
20
|
"Operating System :: POSIX :: Linux",
|
|
21
21
|
"Operating System :: MacOS",
|
|
22
22
|
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
23
27
|
"Programming Language :: Python :: 3.14",
|
|
24
28
|
"Topic :: Multimedia :: Sound/Audio :: Players",
|
|
25
29
|
]
|
|
@@ -56,7 +60,7 @@ include = ["ytm_cli*"]
|
|
|
56
60
|
[tool.ruff]
|
|
57
61
|
# Set line length to match pylint (100 characters)
|
|
58
62
|
line-length = 100
|
|
59
|
-
target-version = "
|
|
63
|
+
target-version = "py310"
|
|
60
64
|
|
|
61
65
|
[tool.ruff.lint]
|
|
62
66
|
# Enable flake8 rules and other important checks
|
|
@@ -72,7 +72,7 @@ class DislikeManager:
|
|
|
72
72
|
with open(self.dislikes_file, encoding="utf-8") as f:
|
|
73
73
|
data = json.load(f)
|
|
74
74
|
existing_songs = data.get("songs", [])
|
|
75
|
-
except json.JSONDecodeError, FileNotFoundError:
|
|
75
|
+
except (json.JSONDecodeError, FileNotFoundError):
|
|
76
76
|
pass
|
|
77
77
|
|
|
78
78
|
# Create dislike entry
|
|
@@ -50,7 +50,7 @@ class FFmpegPlayerService:
|
|
|
50
50
|
["ffplay", "-version"], capture_output=True, text=True, timeout=5
|
|
51
51
|
)
|
|
52
52
|
return result.returncode == 0
|
|
53
|
-
except subprocess.TimeoutExpired, subprocess.SubprocessError, FileNotFoundError:
|
|
53
|
+
except (subprocess.TimeoutExpired, subprocess.SubprocessError, FileNotFoundError):
|
|
54
54
|
return False
|
|
55
55
|
|
|
56
56
|
def play(self, video_id: str, title: str = "") -> bool:
|
|
@@ -170,7 +170,7 @@ class CLIHybridPlayerService:
|
|
|
170
170
|
parsed = json.loads(line)
|
|
171
171
|
if "event" not in parsed and parsed.get("error") == "success":
|
|
172
172
|
return parsed.get("data")
|
|
173
|
-
except OSError, json.JSONDecodeError, UnicodeDecodeError:
|
|
173
|
+
except (OSError, json.JSONDecodeError, UnicodeDecodeError):
|
|
174
174
|
pass
|
|
175
175
|
return None
|
|
176
176
|
|
|
@@ -120,7 +120,7 @@ def search_and_play(query=None, auto_select=None):
|
|
|
120
120
|
if selected_index < 0 or selected_index >= len(results[:songs_to_display]):
|
|
121
121
|
print("[red]Invalid selection.[/red]")
|
|
122
122
|
return
|
|
123
|
-
except ValueError, KeyboardInterrupt:
|
|
123
|
+
except (ValueError, KeyboardInterrupt):
|
|
124
124
|
return
|
|
125
125
|
|
|
126
126
|
if selected_index is None:
|
|
@@ -242,7 +242,7 @@ def playlist_show_command(name):
|
|
|
242
242
|
return
|
|
243
243
|
else:
|
|
244
244
|
name = choice
|
|
245
|
-
except ValueError, KeyboardInterrupt:
|
|
245
|
+
except (ValueError, KeyboardInterrupt):
|
|
246
246
|
return
|
|
247
247
|
|
|
248
248
|
playlist = playlist_manager.get_playlist(name)
|
|
@@ -306,7 +306,7 @@ def playlist_play_command(name):
|
|
|
306
306
|
return
|
|
307
307
|
else:
|
|
308
308
|
name = choice
|
|
309
|
-
except ValueError, KeyboardInterrupt:
|
|
309
|
+
except (ValueError, KeyboardInterrupt):
|
|
310
310
|
return
|
|
311
311
|
|
|
312
312
|
playlist = playlist_manager.get_playlist(name)
|
|
@@ -376,7 +376,7 @@ def playlist_delete_command(name):
|
|
|
376
376
|
return
|
|
377
377
|
else:
|
|
378
378
|
name = choice
|
|
379
|
-
except ValueError, KeyboardInterrupt:
|
|
379
|
+
except (ValueError, KeyboardInterrupt):
|
|
380
380
|
return
|
|
381
381
|
|
|
382
382
|
# Confirm deletion
|
|
@@ -72,7 +72,7 @@ class CavaVisualizer:
|
|
|
72
72
|
values = [int(v) for v in last_line.split(";") if v.strip()]
|
|
73
73
|
if values:
|
|
74
74
|
self.bars = values
|
|
75
|
-
except BlockingIOError, ValueError:
|
|
75
|
+
except (BlockingIOError, ValueError):
|
|
76
76
|
pass
|
|
77
77
|
return self.bars
|
|
78
78
|
|
|
@@ -115,7 +115,7 @@ def _mpv_ipc(socket_path, command, expect_response=False):
|
|
|
115
115
|
continue
|
|
116
116
|
try:
|
|
117
117
|
data = json.loads(line.decode())
|
|
118
|
-
except json.JSONDecodeError, UnicodeDecodeError:
|
|
118
|
+
except (json.JSONDecodeError, UnicodeDecodeError):
|
|
119
119
|
continue
|
|
120
120
|
if "event" in data:
|
|
121
121
|
continue
|
|
@@ -127,7 +127,7 @@ def _mpv_ipc(socket_path, command, expect_response=False):
|
|
|
127
127
|
sock.close()
|
|
128
128
|
return None
|
|
129
129
|
sock.close()
|
|
130
|
-
except OSError, json.JSONDecodeError, UnicodeDecodeError, TimeoutError:
|
|
130
|
+
except (OSError, json.JSONDecodeError, UnicodeDecodeError, TimeoutError):
|
|
131
131
|
return None
|
|
132
132
|
|
|
133
133
|
|
|
@@ -190,7 +190,7 @@ def get_mpv_audio_levels(socket_path):
|
|
|
190
190
|
return None
|
|
191
191
|
try:
|
|
192
192
|
db = float(raw)
|
|
193
|
-
except ValueError, TypeError:
|
|
193
|
+
except (ValueError, TypeError):
|
|
194
194
|
return None
|
|
195
195
|
if db != db or db <= floor_db: # NaN or -inf / silence
|
|
196
196
|
return 0.0
|
|
@@ -263,7 +263,7 @@ class PlaylistManager:
|
|
|
263
263
|
data = json.load(f)
|
|
264
264
|
if data.get("name", "").lower() == playlist_name.lower():
|
|
265
265
|
return filepath
|
|
266
|
-
except json.JSONDecodeError, FileNotFoundError:
|
|
266
|
+
except (json.JSONDecodeError, FileNotFoundError):
|
|
267
267
|
continue
|
|
268
268
|
except OSError:
|
|
269
269
|
pass
|
|
@@ -387,7 +387,7 @@ def add_song_to_playlist_ui(stdscr, song):
|
|
|
387
387
|
try:
|
|
388
388
|
input_bytes = stdscr.getstr(current_line, 4, max_x - 6)
|
|
389
389
|
input_str = input_bytes.decode("utf-8").strip()
|
|
390
|
-
except curses.error, UnicodeDecodeError:
|
|
390
|
+
except (curses.error, UnicodeDecodeError):
|
|
391
391
|
input_str = ""
|
|
392
392
|
finally:
|
|
393
393
|
curses.noecho()
|
|
@@ -403,7 +403,7 @@ def add_song_to_playlist_ui(stdscr, song):
|
|
|
403
403
|
if 0 <= playlist_index < len(playlists):
|
|
404
404
|
playlist_name = playlists[playlist_index]
|
|
405
405
|
return playlist_manager.add_song_to_playlist(playlist_name, song)
|
|
406
|
-
except ValueError, IndexError:
|
|
406
|
+
except (ValueError, IndexError):
|
|
407
407
|
pass
|
|
408
408
|
|
|
409
409
|
# Treat as new playlist name
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ytm-cli
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.3
|
|
4
4
|
Summary: YouTube Music CLI tool with interactive terminal interface
|
|
5
5
|
Author-email: thieuluan <thieuluan.dark@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -14,9 +14,13 @@ Classifier: Intended Audience :: End Users/Desktop
|
|
|
14
14
|
Classifier: Operating System :: POSIX :: Linux
|
|
15
15
|
Classifier: Operating System :: MacOS
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
21
|
Classifier: Programming Language :: Python :: 3.14
|
|
18
22
|
Classifier: Topic :: Multimedia :: Sound/Audio :: Players
|
|
19
|
-
Requires-Python: >=3.
|
|
23
|
+
Requires-Python: >=3.10
|
|
20
24
|
Description-Content-Type: text/markdown
|
|
21
25
|
License-File: LICENSE
|
|
22
26
|
Requires-Dist: ytmusicapi
|
|
@@ -60,7 +64,7 @@ Stream music directly from YouTube Music in your terminal with intuitive control
|
|
|
60
64
|
|
|
61
65
|
### Requirements
|
|
62
66
|
|
|
63
|
-
- Python **3.
|
|
67
|
+
- Python **3.10+** (set in `pyproject.toml`)
|
|
64
68
|
- [mpv media player](https://mpv.io/installation/) (must be installed system-wide)
|
|
65
69
|
- [`ffmpeg`](https://ffmpeg.org/) on `PATH` for the real-time spectrum visualizer (optional — falls back to a stereo oscilloscope if missing)
|
|
66
70
|
|
|
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
|