cloudspin 0.1.0__tar.gz → 0.2.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.
- cloudspin-0.2.0/.github/workflows/ci.yml +52 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/PKG-INFO +76 -42
- {cloudspin-0.1.0 → cloudspin-0.2.0}/README.md +73 -41
- {cloudspin-0.1.0 → cloudspin-0.2.0}/packaging/aur/PKGBUILD +3 -4
- {cloudspin-0.1.0 → cloudspin-0.2.0}/packaging/npm/package.json +1 -1
- {cloudspin-0.1.0 → cloudspin-0.2.0}/pyproject.toml +2 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/__init__.py +1 -1
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/app.py +89 -15
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/cli.py +62 -14
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/config.py +4 -0
- cloudspin-0.2.0/src/cloudspin/links.py +166 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/mood.py +91 -34
- cloudspin-0.2.0/src/cloudspin/mpvget.py +119 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/player.py +87 -14
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/screens.py +2 -2
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/widgets.py +3 -2
- cloudspin-0.2.0/tests/conftest.py +13 -0
- cloudspin-0.2.0/tests/test_links.py +75 -0
- cloudspin-0.2.0/tests/test_network.py +40 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/tests/test_player.py +2 -2
- cloudspin-0.2.0/tests/test_real_mpv.py +113 -0
- cloudspin-0.1.0/.github/workflows/ci.yml +0 -23
- cloudspin-0.1.0/tests/conftest.py +0 -6
- {cloudspin-0.1.0 → cloudspin-0.2.0}/.github/workflows/release.yml +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/.gitignore +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/LICENSE +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/docs/evening.png +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/docs/night.png +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/docs/storm.png +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/packaging/npm/README.md +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/packaging/npm/bin/cloudspin.js +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/scripts/screenshot.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/__main__.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/canvas.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/color.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/library.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/sky.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/songlook.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/spectrum.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/themes.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/vinyl.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/src/cloudspin/weather.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/tests/fake_mpv.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/tests/fixtures/forecast.json +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/tests/synth.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/tests/test_app.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/tests/test_mood.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/tests/test_sky.py +0 -0
- {cloudspin-0.1.0 → cloudspin-0.2.0}/tests/test_weather.py +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ${{ matrix.os }}
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
os: [ubuntu-latest]
|
|
15
|
+
python: ["3.11", "3.12", "3.13"]
|
|
16
|
+
include:
|
|
17
|
+
- os: windows-latest
|
|
18
|
+
python: "3.12"
|
|
19
|
+
- os: macos-latest
|
|
20
|
+
python: "3.12"
|
|
21
|
+
env:
|
|
22
|
+
# On Windows the tests download mpv the same way a first run does.
|
|
23
|
+
CLOUDSPIN_TEST_DOWNLOAD: "1"
|
|
24
|
+
PYTHONUTF8: "1"
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
- uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version: ${{ matrix.python }}
|
|
30
|
+
- name: Install mpv and ffmpeg (Linux)
|
|
31
|
+
if: runner.os == 'Linux'
|
|
32
|
+
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends mpv ffmpeg
|
|
33
|
+
- name: Install mpv and ffmpeg (macOS)
|
|
34
|
+
if: runner.os == 'macOS'
|
|
35
|
+
run: brew install mpv ffmpeg
|
|
36
|
+
- run: pip install -e ".[dev]"
|
|
37
|
+
- run: pytest -q -rs
|
|
38
|
+
|
|
39
|
+
network:
|
|
40
|
+
# Real Spotify and YouTube. Informational: their servers can refuse CI machines.
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
continue-on-error: true
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v4
|
|
45
|
+
- uses: actions/setup-python@v5
|
|
46
|
+
with:
|
|
47
|
+
python-version: "3.12"
|
|
48
|
+
- run: sudo apt-get update && sudo apt-get install -y --no-install-recommends mpv
|
|
49
|
+
- run: pip install -e ".[dev]"
|
|
50
|
+
- run: pytest -q -rs -s tests/test_network.py
|
|
51
|
+
env:
|
|
52
|
+
CLOUDSPIN_TEST_NETWORK: "1"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cloudspin
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A terminal music player that lives under a living sky: spinning vinyl, real weather, animated scenes.
|
|
5
5
|
Project-URL: Homepage, https://github.com/itsHarshDabas/Cloudspin
|
|
6
6
|
Project-URL: Issues, https://github.com/itsHarshDabas/Cloudspin/issues
|
|
@@ -12,6 +12,7 @@ Classifier: Development Status :: 3 - Alpha
|
|
|
12
12
|
Classifier: Environment :: Console
|
|
13
13
|
Classifier: Intended Audience :: End Users/Desktop
|
|
14
14
|
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
16
|
Classifier: Operating System :: POSIX :: Linux
|
|
16
17
|
Classifier: Programming Language :: Python :: 3
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -22,6 +23,7 @@ Requires-Python: >=3.11
|
|
|
22
23
|
Requires-Dist: mutagen>=1.47
|
|
23
24
|
Requires-Dist: pillow>=10.0
|
|
24
25
|
Requires-Dist: textual>=8.0
|
|
26
|
+
Requires-Dist: yt-dlp
|
|
25
27
|
Provides-Extra: dev
|
|
26
28
|
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
27
29
|
Requires-Dist: pytest>=8; extra == 'dev'
|
|
@@ -43,7 +45,8 @@ synthwave turns the stars on.
|
|
|
43
45
|
## What it does
|
|
44
46
|
|
|
45
47
|
- Plays local files, folders, radio streams and links through `mpv`.
|
|
46
|
-
-
|
|
48
|
+
- Opens YouTube, YouTube Music and Spotify playlists as a queue.
|
|
49
|
+
- Paste a link or a playlist while it's running (press `o`) and it starts playing.
|
|
47
50
|
- Shows live weather and a six-day forecast from [Open-Meteo](https://open-meteo.com) (free, no API key).
|
|
48
51
|
- Draws an animated sky: sun, moon with the real phase, stars, drifting clouds, rain, snow, fog and lightning.
|
|
49
52
|
- Picks the sky to suit the song, or follows the real weather, or stays on a scene you pin.
|
|
@@ -53,26 +56,28 @@ synthwave turns the stars on.
|
|
|
53
56
|
|
|
54
57
|
## Install
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
Pick whichever you already have:
|
|
57
60
|
|
|
58
61
|
```sh
|
|
59
|
-
pipx install
|
|
60
|
-
#
|
|
61
|
-
uv
|
|
62
|
+
pipx install cloudspin # Python
|
|
63
|
+
uv tool install cloudspin # uv
|
|
64
|
+
npm install -g cloudspin # npm (a launcher; it runs the Python app through uv or pipx)
|
|
62
65
|
```
|
|
63
66
|
|
|
64
|
-
|
|
67
|
+
Or try it without installing: `uvx cloudspin --demo` or `npx cloudspin --demo`.
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
Works on Linux, macOS and Windows, with Python 3.11 or newer and a truecolor
|
|
70
|
+
terminal (Windows Terminal, kitty, foot, Alacritty, WezTerm, Ghostty, iTerm2
|
|
71
|
+
and most others).
|
|
72
|
+
|
|
73
|
+
### What comes with it
|
|
71
74
|
|
|
72
|
-
|
|
75
|
+
| Tool | What it's for | How you get it |
|
|
76
|
+
| --- | --- | --- |
|
|
77
|
+
| `yt-dlp` | YouTube, SoundCloud and similar links | Installed with Cloudspin |
|
|
78
|
+
| `mpv` | Plays the sound | **Windows:** downloaded automatically the first time you start Cloudspin (about 30 MB, kept in its cache folder). **Linux and macOS:** from your package manager, e.g. `sudo pacman -S mpv`, `sudo apt install mpv`, `brew install mpv` |
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
(kitty, foot, Alacritty, WezTerm, Ghostty, iTerm2 and most others).
|
|
80
|
+
Without mpv Cloudspin still runs, silently, and tells you the command to install it.
|
|
76
81
|
|
|
77
82
|
## Use
|
|
78
83
|
|
|
@@ -81,10 +86,14 @@ cloudspin # plays ~/Music
|
|
|
81
86
|
cloudspin ~/Music/phonk # a folder
|
|
82
87
|
cloudspin song.flac other.mp3 # files
|
|
83
88
|
cloudspin https://example.com/stream.mp3 # a link
|
|
89
|
+
cloudspin "https://music.youtube.com/playlist?list=..." # a YouTube Music playlist
|
|
90
|
+
cloudspin "https://open.spotify.com/playlist/..." # a Spotify playlist
|
|
84
91
|
cloudspin --city "New Delhi" # set the city once; it is remembered
|
|
85
92
|
cloudspin --demo # look around without any music or sound
|
|
86
93
|
```
|
|
87
94
|
|
|
95
|
+
No music folder? Start `cloudspin`, press `o` and paste a link.
|
|
96
|
+
|
|
88
97
|
### Keys
|
|
89
98
|
|
|
90
99
|
| Key | Does |
|
|
@@ -103,24 +112,43 @@ cloudspin --demo # look around without any music or sound
|
|
|
103
112
|
| `?` | Show the keys |
|
|
104
113
|
| `q` | Quit |
|
|
105
114
|
|
|
115
|
+
## Playlists
|
|
116
|
+
|
|
117
|
+
Paste a playlist link with `o`, pass it on the command line, or set it as
|
|
118
|
+
`music` in the settings so Cloudspin opens with it every time.
|
|
119
|
+
|
|
120
|
+
- **YouTube, YouTube Music, SoundCloud** and other sites yt-dlp knows play
|
|
121
|
+
straight from the site.
|
|
122
|
+
- **Spotify** works differently. Spotify's audio only plays inside its own
|
|
123
|
+
apps, so Cloudspin reads the list of songs from the public playlist page and
|
|
124
|
+
plays each one from the closest match on YouTube. Usually that is the same
|
|
125
|
+
recording; now and then it is a live or alternate version. The playlist has
|
|
126
|
+
to be public, and long ones are read up to the first 50 to 100 songs.
|
|
127
|
+
|
|
106
128
|
## How the sky picks a scene
|
|
107
129
|
|
|
108
|
-
With the sky set to follow the song (the default), Cloudspin
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
evening
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
With the sky set to follow the song (the default), Cloudspin decides like this:
|
|
131
|
+
|
|
132
|
+
1. **Your rules.** Words you map to scenes in the config file always win.
|
|
133
|
+
2. **How the song sounds.** Thirty seconds are decoded in the background and
|
|
134
|
+
measured for rhythm (attacks per second, tempo), brightness, bass weight
|
|
135
|
+
and loudness. Busy, bright and bass-heavy becomes a storm; slow and soft
|
|
136
|
+
becomes evening or night. This works for links as well as files, and each
|
|
137
|
+
song is only measured once.
|
|
138
|
+
3. **The words**, as a first guess while the listening happens and as the
|
|
139
|
+
answer when listening isn't possible: the genre tag, then sky words in the
|
|
140
|
+
title or album. `phonk`, `hoodtrap` and `metal` storm; `lofi` and `jazz`
|
|
141
|
+
get the evening; `synthwave` gets the night; "Midnight Rain" needs no tag.
|
|
120
142
|
4. **The real weather**, if nothing above says anything.
|
|
121
143
|
|
|
122
144
|
The caption in the top right corner of the sky always says which scene is
|
|
123
|
-
showing and why, for example `Thunderstorm,
|
|
145
|
+
showing and why, for example `Thunderstorm, hard-hitting and heavy on bass`.
|
|
146
|
+
|
|
147
|
+
To see what Cloudspin hears in a song, and report one it gets wrong:
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
cloudspin --listen "song.mp3"
|
|
151
|
+
```
|
|
124
152
|
|
|
125
153
|
The scenes are `storm`, `rain`, `evening`, `night`, `day`, `dawn`, `snow`,
|
|
126
154
|
`fog` and `overcast`.
|
|
@@ -134,9 +162,10 @@ city = "New Delhi"
|
|
|
134
162
|
units = "metric" # or "imperial"
|
|
135
163
|
sky = "song" # "song", "weather", or a scene name to pin
|
|
136
164
|
colors = "sky" # "sky", "cover", a built-in theme, or one of yours
|
|
137
|
-
music = "~/Music"
|
|
165
|
+
music = "~/Music" # a folder, or a playlist link
|
|
138
166
|
volume = 70
|
|
139
167
|
fps = 24 # lower this on a slow terminal or over SSH
|
|
168
|
+
listen = true # false: choose the sky from tags and titles only
|
|
140
169
|
|
|
141
170
|
# Send particular artists, albums or words to a scene.
|
|
142
171
|
[moods]
|
|
@@ -158,26 +187,29 @@ Built-in themes: `sky`, `cover`, `amber`, `orchid`, `lagoon`, `moss`, `rose`, `m
|
|
|
158
187
|
|
|
159
188
|
- **The bars are generative.** The spectrum moves with the play state, the
|
|
160
189
|
volume and a tempo chosen per song. It is not a live analysis of the audio.
|
|
161
|
-
- **The
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
- **
|
|
190
|
+
- **The listening is a rule of thumb.** It has been checked against synthetic
|
|
191
|
+
test audio, not a real music library, so expect some wrong skies. Use
|
|
192
|
+
`[moods]` to pin an artist or word to a scene, and `cloudspin --listen` to
|
|
193
|
+
see the numbers behind a choice.
|
|
194
|
+
- **Links** play through mpv, with the bundled yt-dlp handling sites like
|
|
195
|
+
YouTube. Sites change often; if a link stops working, update with
|
|
196
|
+
`pipx upgrade cloudspin` (or `uv tool upgrade cloudspin`) to get a newer yt-dlp.
|
|
197
|
+
- **Windows** uses the mpv that Cloudspin downloads for itself unless `mpv` is
|
|
198
|
+
already on your PATH.
|
|
199
|
+
- **MPRIS** (media keys, `playerctl`, Waybar) works on Linux if you have the
|
|
169
200
|
`mpv-mpris` plugin installed for mpv; Cloudspin loads your normal mpv config.
|
|
170
201
|
|
|
171
|
-
##
|
|
202
|
+
## Releases
|
|
172
203
|
|
|
173
204
|
| Channel | Status |
|
|
174
205
|
| --- | --- |
|
|
175
|
-
|
|
|
176
|
-
|
|
|
177
|
-
| AUR | `packaging/aur/PKGBUILD` is written
|
|
206
|
+
| [PyPI](https://pypi.org/project/cloudspin/) | Published |
|
|
207
|
+
| [npm](https://www.npmjs.com/package/cloudspin) | Published (launcher for the Python app) |
|
|
208
|
+
| AUR | `packaging/aur/PKGBUILD` is written, not submitted yet |
|
|
178
209
|
| Homebrew | Not started |
|
|
179
210
|
|
|
180
|
-
|
|
211
|
+
Pushing a `v*` tag runs `.github/workflows/release.yml`, which tests, then
|
|
212
|
+
publishes to PyPI and npm.
|
|
181
213
|
|
|
182
214
|
## Develop
|
|
183
215
|
|
|
@@ -199,6 +231,8 @@ The code is small and split by job:
|
|
|
199
231
|
| `mood.py` | Choosing a scene for a song |
|
|
200
232
|
| `weather.py` | Open-Meteo and sun and moon maths |
|
|
201
233
|
| `player.py` | mpv control and the queue |
|
|
234
|
+
| `links.py` | Reading YouTube and Spotify playlists |
|
|
235
|
+
| `mpvget.py` | Finding mpv and yt-dlp; the Windows mpv download |
|
|
202
236
|
| `widgets.py`, `app.py` | The interface |
|
|
203
237
|
|
|
204
238
|
## Licence
|
|
@@ -14,7 +14,8 @@ synthwave turns the stars on.
|
|
|
14
14
|
## What it does
|
|
15
15
|
|
|
16
16
|
- Plays local files, folders, radio streams and links through `mpv`.
|
|
17
|
-
-
|
|
17
|
+
- Opens YouTube, YouTube Music and Spotify playlists as a queue.
|
|
18
|
+
- Paste a link or a playlist while it's running (press `o`) and it starts playing.
|
|
18
19
|
- Shows live weather and a six-day forecast from [Open-Meteo](https://open-meteo.com) (free, no API key).
|
|
19
20
|
- Draws an animated sky: sun, moon with the real phase, stars, drifting clouds, rain, snow, fog and lightning.
|
|
20
21
|
- Picks the sky to suit the song, or follows the real weather, or stays on a scene you pin.
|
|
@@ -24,26 +25,28 @@ synthwave turns the stars on.
|
|
|
24
25
|
|
|
25
26
|
## Install
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
Pick whichever you already have:
|
|
28
29
|
|
|
29
30
|
```sh
|
|
30
|
-
pipx install
|
|
31
|
-
#
|
|
32
|
-
uv
|
|
31
|
+
pipx install cloudspin # Python
|
|
32
|
+
uv tool install cloudspin # uv
|
|
33
|
+
npm install -g cloudspin # npm (a launcher; it runs the Python app through uv or pipx)
|
|
33
34
|
```
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
Or try it without installing: `uvx cloudspin --demo` or `npx cloudspin --demo`.
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
Works on Linux, macOS and Windows, with Python 3.11 or newer and a truecolor
|
|
39
|
+
terminal (Windows Terminal, kitty, foot, Alacritty, WezTerm, Ghostty, iTerm2
|
|
40
|
+
and most others).
|
|
41
|
+
|
|
42
|
+
### What comes with it
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
| Tool | What it's for | How you get it |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| `yt-dlp` | YouTube, SoundCloud and similar links | Installed with Cloudspin |
|
|
47
|
+
| `mpv` | Plays the sound | **Windows:** downloaded automatically the first time you start Cloudspin (about 30 MB, kept in its cache folder). **Linux and macOS:** from your package manager, e.g. `sudo pacman -S mpv`, `sudo apt install mpv`, `brew install mpv` |
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
(kitty, foot, Alacritty, WezTerm, Ghostty, iTerm2 and most others).
|
|
49
|
+
Without mpv Cloudspin still runs, silently, and tells you the command to install it.
|
|
47
50
|
|
|
48
51
|
## Use
|
|
49
52
|
|
|
@@ -52,10 +55,14 @@ cloudspin # plays ~/Music
|
|
|
52
55
|
cloudspin ~/Music/phonk # a folder
|
|
53
56
|
cloudspin song.flac other.mp3 # files
|
|
54
57
|
cloudspin https://example.com/stream.mp3 # a link
|
|
58
|
+
cloudspin "https://music.youtube.com/playlist?list=..." # a YouTube Music playlist
|
|
59
|
+
cloudspin "https://open.spotify.com/playlist/..." # a Spotify playlist
|
|
55
60
|
cloudspin --city "New Delhi" # set the city once; it is remembered
|
|
56
61
|
cloudspin --demo # look around without any music or sound
|
|
57
62
|
```
|
|
58
63
|
|
|
64
|
+
No music folder? Start `cloudspin`, press `o` and paste a link.
|
|
65
|
+
|
|
59
66
|
### Keys
|
|
60
67
|
|
|
61
68
|
| Key | Does |
|
|
@@ -74,24 +81,43 @@ cloudspin --demo # look around without any music or sound
|
|
|
74
81
|
| `?` | Show the keys |
|
|
75
82
|
| `q` | Quit |
|
|
76
83
|
|
|
84
|
+
## Playlists
|
|
85
|
+
|
|
86
|
+
Paste a playlist link with `o`, pass it on the command line, or set it as
|
|
87
|
+
`music` in the settings so Cloudspin opens with it every time.
|
|
88
|
+
|
|
89
|
+
- **YouTube, YouTube Music, SoundCloud** and other sites yt-dlp knows play
|
|
90
|
+
straight from the site.
|
|
91
|
+
- **Spotify** works differently. Spotify's audio only plays inside its own
|
|
92
|
+
apps, so Cloudspin reads the list of songs from the public playlist page and
|
|
93
|
+
plays each one from the closest match on YouTube. Usually that is the same
|
|
94
|
+
recording; now and then it is a live or alternate version. The playlist has
|
|
95
|
+
to be public, and long ones are read up to the first 50 to 100 songs.
|
|
96
|
+
|
|
77
97
|
## How the sky picks a scene
|
|
78
98
|
|
|
79
|
-
With the sky set to follow the song (the default), Cloudspin
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
evening
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
With the sky set to follow the song (the default), Cloudspin decides like this:
|
|
100
|
+
|
|
101
|
+
1. **Your rules.** Words you map to scenes in the config file always win.
|
|
102
|
+
2. **How the song sounds.** Thirty seconds are decoded in the background and
|
|
103
|
+
measured for rhythm (attacks per second, tempo), brightness, bass weight
|
|
104
|
+
and loudness. Busy, bright and bass-heavy becomes a storm; slow and soft
|
|
105
|
+
becomes evening or night. This works for links as well as files, and each
|
|
106
|
+
song is only measured once.
|
|
107
|
+
3. **The words**, as a first guess while the listening happens and as the
|
|
108
|
+
answer when listening isn't possible: the genre tag, then sky words in the
|
|
109
|
+
title or album. `phonk`, `hoodtrap` and `metal` storm; `lofi` and `jazz`
|
|
110
|
+
get the evening; `synthwave` gets the night; "Midnight Rain" needs no tag.
|
|
91
111
|
4. **The real weather**, if nothing above says anything.
|
|
92
112
|
|
|
93
113
|
The caption in the top right corner of the sky always says which scene is
|
|
94
|
-
showing and why, for example `Thunderstorm,
|
|
114
|
+
showing and why, for example `Thunderstorm, hard-hitting and heavy on bass`.
|
|
115
|
+
|
|
116
|
+
To see what Cloudspin hears in a song, and report one it gets wrong:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
cloudspin --listen "song.mp3"
|
|
120
|
+
```
|
|
95
121
|
|
|
96
122
|
The scenes are `storm`, `rain`, `evening`, `night`, `day`, `dawn`, `snow`,
|
|
97
123
|
`fog` and `overcast`.
|
|
@@ -105,9 +131,10 @@ city = "New Delhi"
|
|
|
105
131
|
units = "metric" # or "imperial"
|
|
106
132
|
sky = "song" # "song", "weather", or a scene name to pin
|
|
107
133
|
colors = "sky" # "sky", "cover", a built-in theme, or one of yours
|
|
108
|
-
music = "~/Music"
|
|
134
|
+
music = "~/Music" # a folder, or a playlist link
|
|
109
135
|
volume = 70
|
|
110
136
|
fps = 24 # lower this on a slow terminal or over SSH
|
|
137
|
+
listen = true # false: choose the sky from tags and titles only
|
|
111
138
|
|
|
112
139
|
# Send particular artists, albums or words to a scene.
|
|
113
140
|
[moods]
|
|
@@ -129,26 +156,29 @@ Built-in themes: `sky`, `cover`, `amber`, `orchid`, `lagoon`, `moss`, `rose`, `m
|
|
|
129
156
|
|
|
130
157
|
- **The bars are generative.** The spectrum moves with the play state, the
|
|
131
158
|
volume and a tempo chosen per song. It is not a live analysis of the audio.
|
|
132
|
-
- **The
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
- **
|
|
159
|
+
- **The listening is a rule of thumb.** It has been checked against synthetic
|
|
160
|
+
test audio, not a real music library, so expect some wrong skies. Use
|
|
161
|
+
`[moods]` to pin an artist or word to a scene, and `cloudspin --listen` to
|
|
162
|
+
see the numbers behind a choice.
|
|
163
|
+
- **Links** play through mpv, with the bundled yt-dlp handling sites like
|
|
164
|
+
YouTube. Sites change often; if a link stops working, update with
|
|
165
|
+
`pipx upgrade cloudspin` (or `uv tool upgrade cloudspin`) to get a newer yt-dlp.
|
|
166
|
+
- **Windows** uses the mpv that Cloudspin downloads for itself unless `mpv` is
|
|
167
|
+
already on your PATH.
|
|
168
|
+
- **MPRIS** (media keys, `playerctl`, Waybar) works on Linux if you have the
|
|
140
169
|
`mpv-mpris` plugin installed for mpv; Cloudspin loads your normal mpv config.
|
|
141
170
|
|
|
142
|
-
##
|
|
171
|
+
## Releases
|
|
143
172
|
|
|
144
173
|
| Channel | Status |
|
|
145
174
|
| --- | --- |
|
|
146
|
-
|
|
|
147
|
-
|
|
|
148
|
-
| AUR | `packaging/aur/PKGBUILD` is written
|
|
175
|
+
| [PyPI](https://pypi.org/project/cloudspin/) | Published |
|
|
176
|
+
| [npm](https://www.npmjs.com/package/cloudspin) | Published (launcher for the Python app) |
|
|
177
|
+
| AUR | `packaging/aur/PKGBUILD` is written, not submitted yet |
|
|
149
178
|
| Homebrew | Not started |
|
|
150
179
|
|
|
151
|
-
|
|
180
|
+
Pushing a `v*` tag runs `.github/workflows/release.yml`, which tests, then
|
|
181
|
+
publishes to PyPI and npm.
|
|
152
182
|
|
|
153
183
|
## Develop
|
|
154
184
|
|
|
@@ -170,6 +200,8 @@ The code is small and split by job:
|
|
|
170
200
|
| `mood.py` | Choosing a scene for a song |
|
|
171
201
|
| `weather.py` | Open-Meteo and sun and moon maths |
|
|
172
202
|
| `player.py` | mpv control and the queue |
|
|
203
|
+
| `links.py` | Reading YouTube and Spotify playlists |
|
|
204
|
+
| `mpvget.py` | Finding mpv and yt-dlp; the Windows mpv download |
|
|
173
205
|
| `widgets.py`, `app.py` | The interface |
|
|
174
206
|
|
|
175
207
|
## Licence
|
|
@@ -3,15 +3,14 @@
|
|
|
3
3
|
# Not on the AUR yet. This builds from the PyPI release, so publish to PyPI
|
|
4
4
|
# first, then run `updpkgsums` here to fill in the checksum.
|
|
5
5
|
pkgname=cloudspin
|
|
6
|
-
pkgver=0.
|
|
6
|
+
pkgver=0.2.0
|
|
7
7
|
pkgrel=1
|
|
8
8
|
pkgdesc="A terminal music player under a living sky: spinning vinyl, real weather, scenes that follow the song"
|
|
9
9
|
arch=('any')
|
|
10
10
|
url="https://github.com/itsHarshDabas/Cloudspin"
|
|
11
11
|
license=('MIT')
|
|
12
|
-
depends=('python' 'python-textual' 'python-mutagen' 'python-pillow' 'mpv')
|
|
13
|
-
optdepends=('ffmpeg: guess a sky for songs with no genre tag'
|
|
14
|
-
'yt-dlp: play YouTube and similar links')
|
|
12
|
+
depends=('python' 'python-textual' 'python-mutagen' 'python-pillow' 'yt-dlp' 'mpv')
|
|
13
|
+
optdepends=('ffmpeg: guess a sky for songs with no genre tag')
|
|
15
14
|
makedepends=('python-build' 'python-installer' 'python-hatchling')
|
|
16
15
|
source=("https://files.pythonhosted.org/packages/source/c/cloudspin/cloudspin-$pkgver.tar.gz")
|
|
17
16
|
sha256sums=('SKIP')
|
|
@@ -18,6 +18,7 @@ classifiers = [
|
|
|
18
18
|
"Intended Audience :: End Users/Desktop",
|
|
19
19
|
"Operating System :: POSIX :: Linux",
|
|
20
20
|
"Operating System :: MacOS",
|
|
21
|
+
"Operating System :: Microsoft :: Windows",
|
|
21
22
|
"Programming Language :: Python :: 3",
|
|
22
23
|
"Programming Language :: Python :: 3.11",
|
|
23
24
|
"Programming Language :: Python :: 3.12",
|
|
@@ -28,6 +29,7 @@ dependencies = [
|
|
|
28
29
|
"textual>=8.0",
|
|
29
30
|
"mutagen>=1.47",
|
|
30
31
|
"pillow>=10.0",
|
|
32
|
+
"yt-dlp",
|
|
31
33
|
]
|
|
32
34
|
|
|
33
35
|
[project.optional-dependencies]
|