simpleplay 0.1.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.
- simpleplay-0.1.0/LICENSE +21 -0
- simpleplay-0.1.0/PKG-INFO +148 -0
- simpleplay-0.1.0/README.md +123 -0
- simpleplay-0.1.0/pyproject.toml +40 -0
- simpleplay-0.1.0/setup.cfg +4 -0
- simpleplay-0.1.0/simpleplay/__init__.py +5 -0
- simpleplay-0.1.0/simpleplay/__main__.py +35 -0
- simpleplay-0.1.0/simpleplay/app.py +1058 -0
- simpleplay-0.1.0/simpleplay/models.py +52 -0
- simpleplay-0.1.0/simpleplay/player.py +211 -0
- simpleplay-0.1.0/simpleplay/youtube.py +484 -0
- simpleplay-0.1.0/simpleplay.egg-info/PKG-INFO +148 -0
- simpleplay-0.1.0/simpleplay.egg-info/SOURCES.txt +21 -0
- simpleplay-0.1.0/simpleplay.egg-info/dependency_links.txt +1 -0
- simpleplay-0.1.0/simpleplay.egg-info/entry_points.txt +2 -0
- simpleplay-0.1.0/simpleplay.egg-info/requires.txt +1 -0
- simpleplay-0.1.0/simpleplay.egg-info/top_level.txt +1 -0
- simpleplay-0.1.0/tests/test_app.py +126 -0
- simpleplay-0.1.0/tests/test_models.py +33 -0
- simpleplay-0.1.0/tests/test_player.py +56 -0
- simpleplay-0.1.0/tests/test_playlist_sync.py +33 -0
- simpleplay-0.1.0/tests/test_queue_view.py +33 -0
- simpleplay-0.1.0/tests/test_youtube.py +157 -0
simpleplay-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Geet
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simpleplay
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Terminal YouTube music player with vim-like bindings
|
|
5
|
+
Author: Geet
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/geetrakala/simpleplay
|
|
8
|
+
Project-URL: Repository, https://github.com/geetrakala/simpleplay
|
|
9
|
+
Project-URL: Issues, https://github.com/geetrakala/simpleplay/issues
|
|
10
|
+
Keywords: terminal,music,youtube,mpv,player
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Players
|
|
19
|
+
Classifier: Topic :: Utilities
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: yt-dlp
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# simpleplay
|
|
27
|
+
|
|
28
|
+
`simpleplay` is a terminal YouTube music player. It searches YouTube in a low-latency mode, plays audio-only through `mpv`, stops cleanly on `Ctrl+C`, keeps autoplaying similar songs from the current track's YouTube mix, and mirrors the queue into `mpv`'s internal playlist so next/previous controls stay in sync.
|
|
29
|
+
|
|
30
|
+
## Caveat
|
|
31
|
+
The entire thing is vibe-coded. Use at your own risk.
|
|
32
|
+
|
|
33
|
+
## Dependencies
|
|
34
|
+
|
|
35
|
+
- `python3` 3.11+
|
|
36
|
+
- `mpv`
|
|
37
|
+
|
|
38
|
+
Optional:
|
|
39
|
+
|
|
40
|
+
- `ffmpeg` is not required for normal playback, but it is useful for local media debugging.
|
|
41
|
+
- A supported JavaScript runtime such as `node` may help `yt-dlp` on some YouTube videos.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
From PyPI:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install simpleplay
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`pip` installs the Python `yt-dlp` dependency automatically. `mpv` is still a separate system binary, so `pip` cannot install it for you.
|
|
52
|
+
|
|
53
|
+
- `mpv`
|
|
54
|
+
|
|
55
|
+
Install `mpv` with your OS package manager:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# macOS
|
|
59
|
+
brew install mpv
|
|
60
|
+
|
|
61
|
+
# Debian / Ubuntu
|
|
62
|
+
sudo apt install mpv
|
|
63
|
+
|
|
64
|
+
# Fedora
|
|
65
|
+
sudo dnf install mpv
|
|
66
|
+
|
|
67
|
+
# Arch
|
|
68
|
+
sudo pacman -S mpv
|
|
69
|
+
|
|
70
|
+
# Windows
|
|
71
|
+
winget search mpv
|
|
72
|
+
winget install <mpv-package-id>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
More options: <https://mpv.io/installation>
|
|
76
|
+
|
|
77
|
+
From this repo:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
python3 -m venv .venv
|
|
81
|
+
source .venv/bin/activate
|
|
82
|
+
pip install -e .
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
If you do not want an editable install, you can still run the app directly with `python3 -m simpleplay`.
|
|
86
|
+
|
|
87
|
+
## Run
|
|
88
|
+
|
|
89
|
+
Start the UI with no query:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
simpleplay
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Start with an initial search:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
simpleplay "daft punk"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Without installing:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
python3 -m simpleplay "khruangbin"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Keybindings
|
|
108
|
+
|
|
109
|
+
- `/` enter search mode with a fresh empty query
|
|
110
|
+
- typing in search mode starts a debounced live search automatically
|
|
111
|
+
- `Enter` leave search mode and keep the current results
|
|
112
|
+
- `Esc` leave search mode
|
|
113
|
+
- `j` / `k` move through the current list
|
|
114
|
+
- `Enter` on a search result starts playback
|
|
115
|
+
- after playback starts, the main list becomes `Up Next`, and `Enter` on a queued item jumps to it
|
|
116
|
+
- `space` or `p` pause or resume
|
|
117
|
+
- `h` / `l` seek backward or forward 10 seconds
|
|
118
|
+
- `n` play the next queued or similar track
|
|
119
|
+
- `b` go to the previous track, or restart the current track if more than 5 seconds in
|
|
120
|
+
- `r` cycle loop mode: `off` -> `all` -> `one`
|
|
121
|
+
- `g` / `G` jump to the top or bottom of the results list
|
|
122
|
+
- `q` quit
|
|
123
|
+
- `Ctrl+C` stop playback and exit cleanly
|
|
124
|
+
|
|
125
|
+
## How autoplay works
|
|
126
|
+
|
|
127
|
+
When a track starts, `simpleplay` immediately seeds `Up Next` from the current search results so the queue is usable right away. In parallel, it asks YouTube for the current video's mix playlist (`list=RD<video_id>`). Those related tracks are added to the in-memory queue, shown in the `Up Next` list, and the next few are prefetched for faster transitions.
|
|
128
|
+
|
|
129
|
+
## Notes
|
|
130
|
+
|
|
131
|
+
- The only non-Python runtime dependency is `mpv`. `yt-dlp` is installed automatically as a Python package dependency.
|
|
132
|
+
- `mpv` is kept alive as one long-running process and controlled over its IPC socket for better responsiveness.
|
|
133
|
+
- The app keeps its queue mirrored into `mpv`'s internal playlist, so `mpv`'s own next/previous controls can move through the same queue.
|
|
134
|
+
- Search uses a fast YouTube page parser first, with the bundled `yt-dlp` Python package as fallback when needed.
|
|
135
|
+
- Direct audio stream URLs are cached briefly in memory because YouTube stream URLs expire.
|
|
136
|
+
- The first few search results and queued tracks are prefetched in the background so selecting them is more likely to start from a cached direct audio URL.
|
|
137
|
+
- Playback start prefers a prefetched direct audio URL for a short grace window, then falls back to `mpv` loading the YouTube watch URL directly if the resolver is not ready yet.
|
|
138
|
+
- If `yt-dlp` starts failing on some videos due to YouTube extractor changes, update it first.
|
|
139
|
+
|
|
140
|
+
## Commands
|
|
141
|
+
|
|
142
|
+
Run tests:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
python3 -m unittest discover -s tests -v
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Format or linting commands are not included because this project is stdlib-only and does not ship a formatter config yet.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# simpleplay
|
|
2
|
+
|
|
3
|
+
`simpleplay` is a terminal YouTube music player. It searches YouTube in a low-latency mode, plays audio-only through `mpv`, stops cleanly on `Ctrl+C`, keeps autoplaying similar songs from the current track's YouTube mix, and mirrors the queue into `mpv`'s internal playlist so next/previous controls stay in sync.
|
|
4
|
+
|
|
5
|
+
## Caveat
|
|
6
|
+
The entire thing is vibe-coded. Use at your own risk.
|
|
7
|
+
|
|
8
|
+
## Dependencies
|
|
9
|
+
|
|
10
|
+
- `python3` 3.11+
|
|
11
|
+
- `mpv`
|
|
12
|
+
|
|
13
|
+
Optional:
|
|
14
|
+
|
|
15
|
+
- `ffmpeg` is not required for normal playback, but it is useful for local media debugging.
|
|
16
|
+
- A supported JavaScript runtime such as `node` may help `yt-dlp` on some YouTube videos.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
From PyPI:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install simpleplay
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`pip` installs the Python `yt-dlp` dependency automatically. `mpv` is still a separate system binary, so `pip` cannot install it for you.
|
|
27
|
+
|
|
28
|
+
- `mpv`
|
|
29
|
+
|
|
30
|
+
Install `mpv` with your OS package manager:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# macOS
|
|
34
|
+
brew install mpv
|
|
35
|
+
|
|
36
|
+
# Debian / Ubuntu
|
|
37
|
+
sudo apt install mpv
|
|
38
|
+
|
|
39
|
+
# Fedora
|
|
40
|
+
sudo dnf install mpv
|
|
41
|
+
|
|
42
|
+
# Arch
|
|
43
|
+
sudo pacman -S mpv
|
|
44
|
+
|
|
45
|
+
# Windows
|
|
46
|
+
winget search mpv
|
|
47
|
+
winget install <mpv-package-id>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
More options: <https://mpv.io/installation>
|
|
51
|
+
|
|
52
|
+
From this repo:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
python3 -m venv .venv
|
|
56
|
+
source .venv/bin/activate
|
|
57
|
+
pip install -e .
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If you do not want an editable install, you can still run the app directly with `python3 -m simpleplay`.
|
|
61
|
+
|
|
62
|
+
## Run
|
|
63
|
+
|
|
64
|
+
Start the UI with no query:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
simpleplay
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Start with an initial search:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
simpleplay "daft punk"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Without installing:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
python3 -m simpleplay "khruangbin"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Keybindings
|
|
83
|
+
|
|
84
|
+
- `/` enter search mode with a fresh empty query
|
|
85
|
+
- typing in search mode starts a debounced live search automatically
|
|
86
|
+
- `Enter` leave search mode and keep the current results
|
|
87
|
+
- `Esc` leave search mode
|
|
88
|
+
- `j` / `k` move through the current list
|
|
89
|
+
- `Enter` on a search result starts playback
|
|
90
|
+
- after playback starts, the main list becomes `Up Next`, and `Enter` on a queued item jumps to it
|
|
91
|
+
- `space` or `p` pause or resume
|
|
92
|
+
- `h` / `l` seek backward or forward 10 seconds
|
|
93
|
+
- `n` play the next queued or similar track
|
|
94
|
+
- `b` go to the previous track, or restart the current track if more than 5 seconds in
|
|
95
|
+
- `r` cycle loop mode: `off` -> `all` -> `one`
|
|
96
|
+
- `g` / `G` jump to the top or bottom of the results list
|
|
97
|
+
- `q` quit
|
|
98
|
+
- `Ctrl+C` stop playback and exit cleanly
|
|
99
|
+
|
|
100
|
+
## How autoplay works
|
|
101
|
+
|
|
102
|
+
When a track starts, `simpleplay` immediately seeds `Up Next` from the current search results so the queue is usable right away. In parallel, it asks YouTube for the current video's mix playlist (`list=RD<video_id>`). Those related tracks are added to the in-memory queue, shown in the `Up Next` list, and the next few are prefetched for faster transitions.
|
|
103
|
+
|
|
104
|
+
## Notes
|
|
105
|
+
|
|
106
|
+
- The only non-Python runtime dependency is `mpv`. `yt-dlp` is installed automatically as a Python package dependency.
|
|
107
|
+
- `mpv` is kept alive as one long-running process and controlled over its IPC socket for better responsiveness.
|
|
108
|
+
- The app keeps its queue mirrored into `mpv`'s internal playlist, so `mpv`'s own next/previous controls can move through the same queue.
|
|
109
|
+
- Search uses a fast YouTube page parser first, with the bundled `yt-dlp` Python package as fallback when needed.
|
|
110
|
+
- Direct audio stream URLs are cached briefly in memory because YouTube stream URLs expire.
|
|
111
|
+
- The first few search results and queued tracks are prefetched in the background so selecting them is more likely to start from a cached direct audio URL.
|
|
112
|
+
- Playback start prefers a prefetched direct audio URL for a short grace window, then falls back to `mpv` loading the YouTube watch URL directly if the resolver is not ready yet.
|
|
113
|
+
- If `yt-dlp` starts failing on some videos due to YouTube extractor changes, update it first.
|
|
114
|
+
|
|
115
|
+
## Commands
|
|
116
|
+
|
|
117
|
+
Run tests:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
python3 -m unittest discover -s tests -v
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Format or linting commands are not included because this project is stdlib-only and does not ship a formatter config yet.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "simpleplay"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Terminal YouTube music player with vim-like bindings"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
dependencies = ["yt-dlp"]
|
|
14
|
+
authors = [{ name = "Geet" }]
|
|
15
|
+
keywords = ["terminal", "music", "youtube", "mpv", "player"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: End Users/Desktop",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Multimedia :: Sound/Audio :: Players",
|
|
25
|
+
"Topic :: Utilities",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/geetrakala/simpleplay"
|
|
30
|
+
Repository = "https://github.com/geetrakala/simpleplay"
|
|
31
|
+
Issues = "https://github.com/geetrakala/simpleplay/issues"
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
simpleplay = "simpleplay.__main__:main"
|
|
35
|
+
|
|
36
|
+
[tool.setuptools]
|
|
37
|
+
packages = ["simpleplay"]
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.dynamic]
|
|
40
|
+
version = { attr = "simpleplay.__version__" }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from .app import SimplePlayApp
|
|
7
|
+
from .player import PlayerError
|
|
8
|
+
from .youtube import YouTubeError, require_binary
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
12
|
+
parser = argparse.ArgumentParser(description="Search and play YouTube music from the terminal.")
|
|
13
|
+
parser.add_argument("query", nargs="*", help="Optional initial search query")
|
|
14
|
+
return parser
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main() -> int:
|
|
18
|
+
parser = build_parser()
|
|
19
|
+
args = parser.parse_args()
|
|
20
|
+
initial_query = " ".join(args.query).strip()
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
require_binary("mpv")
|
|
24
|
+
app = SimplePlayApp(initial_query=initial_query)
|
|
25
|
+
app.run()
|
|
26
|
+
except KeyboardInterrupt:
|
|
27
|
+
return 0
|
|
28
|
+
except (YouTubeError, PlayerError) as exc:
|
|
29
|
+
print(f"simpleplay: {exc}", file=sys.stderr)
|
|
30
|
+
return 1
|
|
31
|
+
return 0
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
if __name__ == "__main__":
|
|
35
|
+
raise SystemExit(main())
|