wrkmon 1.0.1__py3-none-any.whl → 1.2.0__py3-none-any.whl

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.
@@ -0,0 +1,311 @@
1
+ """Version checker and updater for wrkmon."""
2
+
3
+ import asyncio
4
+ import json
5
+ import logging
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ import urllib.request
10
+ from dataclasses import dataclass
11
+ from pathlib import Path
12
+ from typing import Optional
13
+ from packaging import version
14
+
15
+ from wrkmon import __version__
16
+
17
+ logger = logging.getLogger("wrkmon.updater")
18
+
19
+ PYPI_URL = "https://pypi.org/pypi/wrkmon/json"
20
+ CHECK_INTERVAL_HOURS = 24
21
+
22
+
23
+ @dataclass
24
+ class UpdateInfo:
25
+ """Information about an available update."""
26
+
27
+ current_version: str
28
+ latest_version: str
29
+ is_update_available: bool
30
+ release_url: str = "https://pypi.org/project/wrkmon/"
31
+
32
+ @property
33
+ def update_command(self) -> str:
34
+ """Get the command to update wrkmon."""
35
+ return "pip install --upgrade wrkmon"
36
+
37
+
38
+ def get_current_version() -> str:
39
+ """Get the current installed version."""
40
+ return __version__
41
+
42
+
43
+ def check_pypi_version() -> Optional[str]:
44
+ """
45
+ Check PyPI for the latest version of wrkmon.
46
+
47
+ Returns:
48
+ The latest version string, or None if check failed.
49
+ """
50
+ try:
51
+ req = urllib.request.Request(
52
+ PYPI_URL,
53
+ headers={"Accept": "application/json", "User-Agent": "wrkmon-updater"}
54
+ )
55
+ with urllib.request.urlopen(req, timeout=5) as response:
56
+ data = json.loads(response.read().decode())
57
+ return data.get("info", {}).get("version")
58
+ except Exception as e:
59
+ logger.debug(f"Failed to check PyPI version: {e}")
60
+ return None
61
+
62
+
63
+ async def check_pypi_version_async() -> Optional[str]:
64
+ """Async wrapper for checking PyPI version."""
65
+ return await asyncio.to_thread(check_pypi_version)
66
+
67
+
68
+ def compare_versions(current: str, latest: str) -> bool:
69
+ """
70
+ Check if an update is available.
71
+
72
+ Returns:
73
+ True if latest > current (update available).
74
+ """
75
+ try:
76
+ return version.parse(latest) > version.parse(current)
77
+ except Exception:
78
+ # Fallback to string comparison
79
+ return latest != current and latest > current
80
+
81
+
82
+ def check_for_updates() -> Optional[UpdateInfo]:
83
+ """
84
+ Check if a newer version is available on PyPI.
85
+
86
+ Returns:
87
+ UpdateInfo if check succeeded, None if check failed.
88
+ """
89
+ current = get_current_version()
90
+ latest = check_pypi_version()
91
+
92
+ if latest is None:
93
+ return None
94
+
95
+ return UpdateInfo(
96
+ current_version=current,
97
+ latest_version=latest,
98
+ is_update_available=compare_versions(current, latest),
99
+ )
100
+
101
+
102
+ async def check_for_updates_async() -> Optional[UpdateInfo]:
103
+ """Async version of check_for_updates."""
104
+ return await asyncio.to_thread(check_for_updates)
105
+
106
+
107
+ def perform_update() -> tuple[bool, str]:
108
+ """
109
+ Attempt to update wrkmon using pip.
110
+
111
+ Returns:
112
+ tuple: (success, message)
113
+ """
114
+ try:
115
+ result = subprocess.run(
116
+ [sys.executable, "-m", "pip", "install", "--upgrade", "wrkmon"],
117
+ capture_output=True,
118
+ text=True,
119
+ timeout=120,
120
+ )
121
+
122
+ if result.returncode == 0:
123
+ return True, "Update successful! Please restart wrkmon."
124
+ else:
125
+ return False, f"Update failed: {result.stderr}"
126
+ except subprocess.TimeoutExpired:
127
+ return False, "Update timed out. Try manually: pip install --upgrade wrkmon"
128
+ except Exception as e:
129
+ return False, f"Update error: {e}"
130
+
131
+
132
+ async def perform_update_async() -> tuple[bool, str]:
133
+ """Async version of perform_update."""
134
+ return await asyncio.to_thread(perform_update)
135
+
136
+
137
+ # ============================================================
138
+ # Dependency checkers for better compatibility
139
+ # ============================================================
140
+
141
+ def is_deno_installed() -> bool:
142
+ """Check if deno is installed."""
143
+ return shutil.which("deno") is not None
144
+
145
+
146
+ def is_nodejs_installed() -> bool:
147
+ """Check if Node.js is installed."""
148
+ return shutil.which("node") is not None
149
+
150
+
151
+ def get_js_runtime() -> Optional[str]:
152
+ """Get the available JavaScript runtime for yt-dlp."""
153
+ if is_deno_installed():
154
+ return "deno"
155
+ if is_nodejs_installed():
156
+ return "nodejs"
157
+ return None
158
+
159
+
160
+ def get_deno_install_command() -> str:
161
+ """Get the command to install deno for the current platform."""
162
+ if sys.platform == "win32":
163
+ return "irm https://deno.land/install.ps1 | iex"
164
+ else:
165
+ return "curl -fsSL https://deno.land/install.sh | sh"
166
+
167
+
168
+ def install_deno() -> tuple[bool, str]:
169
+ """
170
+ Attempt to install deno.
171
+
172
+ Returns:
173
+ tuple: (success, message)
174
+ """
175
+ if is_deno_installed():
176
+ return True, "deno is already installed"
177
+
178
+ try:
179
+ if sys.platform == "win32":
180
+ # Try winget first
181
+ try:
182
+ result = subprocess.run(
183
+ ["winget", "install", "--id", "DenoLand.Deno", "-e", "--silent"],
184
+ capture_output=True,
185
+ timeout=300,
186
+ )
187
+ if result.returncode == 0:
188
+ return True, "deno installed via winget"
189
+ except Exception:
190
+ pass
191
+
192
+ # Try scoop
193
+ try:
194
+ result = subprocess.run(
195
+ ["scoop", "install", "deno"],
196
+ capture_output=True,
197
+ timeout=300,
198
+ )
199
+ if result.returncode == 0:
200
+ return True, "deno installed via scoop"
201
+ except Exception:
202
+ pass
203
+
204
+ # Try chocolatey
205
+ try:
206
+ result = subprocess.run(
207
+ ["choco", "install", "deno", "-y"],
208
+ capture_output=True,
209
+ timeout=300,
210
+ )
211
+ if result.returncode == 0:
212
+ return True, "deno installed via chocolatey"
213
+ except Exception:
214
+ pass
215
+
216
+ return False, f"Please install deno manually:\n{get_deno_install_command()}"
217
+
218
+ else:
219
+ # Unix - try package managers first
220
+ if sys.platform == "darwin":
221
+ # macOS - try brew
222
+ try:
223
+ result = subprocess.run(
224
+ ["brew", "install", "deno"],
225
+ capture_output=True,
226
+ timeout=300,
227
+ )
228
+ if result.returncode == 0:
229
+ return True, "deno installed via homebrew"
230
+ except Exception:
231
+ pass
232
+ else:
233
+ # Linux - try snap
234
+ try:
235
+ result = subprocess.run(
236
+ ["snap", "install", "deno"],
237
+ capture_output=True,
238
+ timeout=300,
239
+ )
240
+ if result.returncode == 0:
241
+ return True, "deno installed via snap"
242
+ except Exception:
243
+ pass
244
+
245
+ # Try the official install script
246
+ try:
247
+ result = subprocess.run(
248
+ ["sh", "-c", "curl -fsSL https://deno.land/install.sh | sh"],
249
+ capture_output=True,
250
+ timeout=300,
251
+ )
252
+ if result.returncode == 0:
253
+ return True, "deno installed via official script"
254
+ except Exception:
255
+ pass
256
+
257
+ return False, f"Please install deno manually:\n{get_deno_install_command()}"
258
+
259
+ except Exception as e:
260
+ return False, f"Installation failed: {e}"
261
+
262
+
263
+ async def install_deno_async() -> tuple[bool, str]:
264
+ """Async version of install_deno."""
265
+ return await asyncio.to_thread(install_deno)
266
+
267
+
268
+ def check_dependencies() -> dict:
269
+ """
270
+ Check all optional dependencies for optimal functionality.
271
+
272
+ Returns:
273
+ dict with dependency status.
274
+ """
275
+ from wrkmon.utils.mpv_installer import is_mpv_installed
276
+
277
+ return {
278
+ "mpv": {
279
+ "installed": is_mpv_installed(),
280
+ "required": True,
281
+ "description": "Media player for audio playback",
282
+ },
283
+ "deno": {
284
+ "installed": is_deno_installed(),
285
+ "required": False,
286
+ "description": "JavaScript runtime for better YouTube compatibility",
287
+ },
288
+ "nodejs": {
289
+ "installed": is_nodejs_installed(),
290
+ "required": False,
291
+ "description": "Alternative JavaScript runtime",
292
+ },
293
+ "js_runtime": {
294
+ "installed": get_js_runtime() is not None,
295
+ "required": False,
296
+ "description": "JavaScript runtime (deno or nodejs) for full YouTube support",
297
+ },
298
+ }
299
+
300
+
301
+ def get_missing_dependencies() -> list[str]:
302
+ """Get list of missing recommended dependencies."""
303
+ deps = check_dependencies()
304
+ missing = []
305
+
306
+ if not deps["mpv"]["installed"]:
307
+ missing.append("mpv")
308
+ if not deps["js_runtime"]["installed"]:
309
+ missing.append("deno (recommended for YouTube)")
310
+
311
+ return missing
@@ -1,166 +1,170 @@
1
- Metadata-Version: 2.4
2
- Name: wrkmon
3
- Version: 1.0.1
4
- Summary: Stealth TUI YouTube audio player - stream music while looking productive
5
- Author-email: Umar Khan Yousafzai <umerfarooqkhan325@gmail.com>
6
- License-Expression: MIT
7
- Project-URL: Homepage, https://github.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube
8
- Project-URL: Documentation, https://github.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube#readme
9
- Project-URL: Repository, https://github.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube
10
- Project-URL: Issues, https://github.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube/issues
11
- Keywords: youtube,audio,player,tui,music,stealth,productivity,terminal
12
- Classifier: Development Status :: 4 - Beta
13
- Classifier: Environment :: Console
14
- Classifier: Intended Audience :: Developers
15
- Classifier: Intended Audience :: End Users/Desktop
16
- Classifier: Operating System :: OS Independent
17
- Classifier: Operating System :: Microsoft :: Windows
18
- Classifier: Operating System :: POSIX :: Linux
19
- Classifier: Operating System :: MacOS
20
- Classifier: Programming Language :: Python :: 3
21
- Classifier: Programming Language :: Python :: 3.10
22
- Classifier: Programming Language :: Python :: 3.11
23
- Classifier: Programming Language :: Python :: 3.12
24
- Classifier: Topic :: Multimedia :: Sound/Audio :: Players
25
- Requires-Python: >=3.10
26
- Description-Content-Type: text/markdown
27
- License-File: LICENSE
28
- Requires-Dist: textual>=0.50.0
29
- Requires-Dist: typer>=0.9.0
30
- Requires-Dist: yt-dlp>=2024.0.0
31
- Requires-Dist: rich>=13.0.0
32
- Requires-Dist: pywin32>=306; sys_platform == "win32"
33
- Provides-Extra: dev
34
- Requires-Dist: pytest>=8.0.0; extra == "dev"
35
- Requires-Dist: ruff>=0.3.0; extra == "dev"
36
- Dynamic: license-file
37
-
38
- # wrkmon
39
-
40
- **Terminal-based YouTube Music Player** - Listen to music right from your terminal!
41
-
42
- A beautiful TUI (Terminal User Interface) for streaming YouTube audio. No browser needed, just your terminal.
43
-
44
- ![License](https://img.shields.io/badge/license-MIT-blue.svg)
45
- ![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)
46
- ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)
47
- ![PyPI](https://img.shields.io/pypi/v/wrkmon.svg)
48
-
49
- ## Features
50
-
51
- - Search and stream YouTube audio
52
- - Beautiful terminal interface
53
- - Queue management with shuffle/repeat
54
- - Play history and playlists
55
- - Keyboard-driven controls
56
- - Cross-platform (Windows, macOS, Linux)
57
-
58
- ## Installation
59
-
60
- ### pip (Recommended)
61
-
62
- ```bash
63
- pip install wrkmon
64
- ```
65
-
66
- > **Note:** You also need mpv installed:
67
- > - Windows: `winget install mpv`
68
- > - macOS: `brew install mpv`
69
- > - Linux: `sudo apt install mpv`
70
-
71
- ### Quick Install Scripts
72
-
73
- **Windows (PowerShell):**
74
- ```powershell
75
- irm https://raw.githubusercontent.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube/main/install.ps1 | iex
76
- ```
77
-
78
- **macOS / Linux:**
79
- ```bash
80
- curl -sSL https://raw.githubusercontent.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube/main/install.sh | bash
81
- ```
82
-
83
- ### Package Managers
84
-
85
- ```powershell
86
- # Windows (Chocolatey)
87
- choco install wrkmon
88
-
89
- # macOS (Homebrew) - coming soon
90
- brew install wrkmon
91
-
92
- # Linux (Snap) - coming soon
93
- sudo snap install wrkmon
94
- ```
95
-
96
- ## Usage
97
-
98
- ```bash
99
- wrkmon # Launch the TUI
100
- wrkmon search "q" # Quick search
101
- wrkmon play <id> # Play a video
102
- wrkmon history # View history
103
- ```
104
-
105
- ## Keyboard Controls
106
-
107
- | Key | Action |
108
- |-----|--------|
109
- | `F1` | Search view |
110
- | `F2` | Queue view |
111
- | `F3` | History view |
112
- | `F4` | Playlists view |
113
- | `F5` | Play / Pause |
114
- | `F6` | Volume down |
115
- | `F7` | Volume up |
116
- | `F8` | Next track |
117
- | `F9` | Stop |
118
- | `F10` | Add to queue |
119
- | `/` | Focus search |
120
- | `Enter` | Play selected |
121
- | `a` | Add to queue |
122
- | `Ctrl+C` | Quit |
123
-
124
- ## Screenshots
125
-
126
- ```
127
- ┌─────────────────────────────────────────────────────────┐
128
- │ wrkmon [Search] │
129
- ├─────────────────────────────────────────────────────────┤
130
- │ Search: lofi beats │
131
- ├─────────────────────────────────────────────────────────┤
132
- # Title Channel Duration
133
- │ 1 Lofi Hip Hop Radio ChilledCow 3:24:15│
134
- 2 Jazz Lofi Beats Lofi Girl 2:45:00
135
- │ 3 Study Music Playlist Study 1:30:22│
136
- ├─────────────────────────────────────────────────────────┤
137
- Now Playing: Lofi Beats advancement █████░░░░░ 1:23:45
138
- F1 Search F2 Queue F5 Play/Pause F9 Stop
139
- └─────────────────────────────────────────────────────────┘
140
- ```
141
-
142
- ## Requirements
143
-
144
- - Python 3.10+
145
- - mpv media player
146
-
147
- ## Development
148
-
149
- ```bash
150
- git clone https://github.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube.git
151
- cd Wrkmon-TUI-Youtube
152
- pip install -e ".[dev]"
153
- pytest
154
- ```
155
-
156
- ## License
157
-
158
- MIT License - see [LICENSE](LICENSE) for details.
159
-
160
- ## Author
161
-
162
- **Umar Khan Yousafzai**
163
-
164
- ---
165
-
166
- *Enjoy your music!*
1
+ Metadata-Version: 2.4
2
+ Name: wrkmon
3
+ Version: 1.2.0
4
+ Summary: Stealth TUI YouTube audio player - stream music while looking productive
5
+ Author-email: Umar Khan Yousafzai <umerfarooqkhan325@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube
8
+ Project-URL: Documentation, https://github.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube#readme
9
+ Project-URL: Repository, https://github.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube
10
+ Project-URL: Issues, https://github.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube/issues
11
+ Keywords: youtube,audio,player,tui,music,stealth,productivity,terminal
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: End Users/Desktop
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Operating System :: Microsoft :: Windows
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Operating System :: MacOS
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Players
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: textual>=0.50.0
29
+ Requires-Dist: typer>=0.9.0
30
+ Requires-Dist: yt-dlp>=2025.1.0
31
+ Requires-Dist: rich>=13.0.0
32
+ Requires-Dist: packaging>=21.0
33
+ Requires-Dist: Pillow>=9.0.0
34
+ Requires-Dist: pywin32>=306; sys_platform == "win32"
35
+ Requires-Dist: dbus-next>=0.2.3; sys_platform == "linux"
36
+ Requires-Dist: pynput>=1.7.6; sys_platform == "win32" or sys_platform == "darwin"
37
+ Provides-Extra: dev
38
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
39
+ Requires-Dist: ruff>=0.3.0; extra == "dev"
40
+ Dynamic: license-file
41
+
42
+ # wrkmon
43
+
44
+ **Terminal-based YouTube Music Player** - Listen to music right from your terminal!
45
+
46
+ A beautiful TUI (Terminal User Interface) for streaming YouTube audio. No browser needed, just your terminal.
47
+
48
+ ![License](https://img.shields.io/badge/license-MIT-blue.svg)
49
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)
50
+ ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)
51
+ ![PyPI](https://img.shields.io/pypi/v/wrkmon.svg)
52
+
53
+ ## Features
54
+
55
+ - Search and stream YouTube audio
56
+ - Beautiful terminal interface
57
+ - Queue management with shuffle/repeat
58
+ - Play history and playlists
59
+ - Keyboard-driven controls
60
+ - Cross-platform (Windows, macOS, Linux)
61
+
62
+ ## Installation
63
+
64
+ ### pip (Recommended)
65
+
66
+ ```bash
67
+ pip install wrkmon
68
+ ```
69
+
70
+ > **Note:** You also need mpv installed:
71
+ > - Windows: `winget install mpv`
72
+ > - macOS: `brew install mpv`
73
+ > - Linux: `sudo apt install mpv`
74
+
75
+ ### Quick Install Scripts
76
+
77
+ **Windows (PowerShell):**
78
+ ```powershell
79
+ irm https://raw.githubusercontent.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube/main/install.ps1 | iex
80
+ ```
81
+
82
+ **macOS / Linux:**
83
+ ```bash
84
+ curl -sSL https://raw.githubusercontent.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube/main/install.sh | bash
85
+ ```
86
+
87
+ ### Package Managers
88
+
89
+ ```powershell
90
+ # Windows (Chocolatey)
91
+ choco install wrkmon
92
+
93
+ # macOS (Homebrew) - coming soon
94
+ brew install wrkmon
95
+
96
+ # Linux (Snap) - coming soon
97
+ sudo snap install wrkmon
98
+ ```
99
+
100
+ ## Usage
101
+
102
+ ```bash
103
+ wrkmon # Launch the TUI
104
+ wrkmon search "q" # Quick search
105
+ wrkmon play <id> # Play a video
106
+ wrkmon history # View history
107
+ ```
108
+
109
+ ## Keyboard Controls
110
+
111
+ | Key | Action |
112
+ |-----|--------|
113
+ | `F1` | Search view |
114
+ | `F2` | Queue view |
115
+ | `F3` | History view |
116
+ | `F4` | Playlists view |
117
+ | `F5` | Play / Pause |
118
+ | `F6` | Volume down |
119
+ | `F7` | Volume up |
120
+ | `F8` | Next track |
121
+ | `F9` | Stop |
122
+ | `F10` | Add to queue |
123
+ | `/` | Focus search |
124
+ | `Enter` | Play selected |
125
+ | `a` | Add to queue |
126
+ | `Ctrl+C` | Quit |
127
+
128
+ ## Screenshots
129
+
130
+ ```
131
+ ┌─────────────────────────────────────────────────────────┐
132
+ wrkmon [Search]
133
+ ├─────────────────────────────────────────────────────────┤
134
+ Search: lofi beats
135
+ ├─────────────────────────────────────────────────────────┤
136
+ │ # Title Channel Duration│
137
+ 1 Lofi Hip Hop Radio ChilledCow 3:24:15
138
+ 2 Jazz Lofi Beats Lofi Girl 2:45:00
139
+ │ 3 Study Music Playlist Study 1:30:22│
140
+ ├─────────────────────────────────────────────────────────┤
141
+ │ ▶ Now Playing: Lofi Beats advancement █████░░░░░ 1:23:45 │
142
+ │ F1 Search F2 Queue F5 Play/Pause F9 Stop │
143
+ └─────────────────────────────────────────────────────────┘
144
+ ```
145
+
146
+ ## Requirements
147
+
148
+ - Python 3.10+
149
+ - mpv media player
150
+
151
+ ## Development
152
+
153
+ ```bash
154
+ git clone https://github.com/Umar-Khan-Yousafzai/Wrkmon-TUI-Youtube.git
155
+ cd Wrkmon-TUI-Youtube
156
+ pip install -e ".[dev]"
157
+ pytest
158
+ ```
159
+
160
+ ## License
161
+
162
+ MIT License - see [LICENSE](LICENSE) for details.
163
+
164
+ ## Author
165
+
166
+ **Umar Khan Yousafzai**
167
+
168
+ ---
169
+
170
+ *Enjoy your music!*