@bzenky/spoti 0.1.0 → 0.3.0

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 (80) hide show
  1. package/README.md +144 -4
  2. package/dist/app.d.ts +27 -1
  3. package/dist/app.js +514 -16
  4. package/dist/app.js.map +1 -1
  5. package/dist/auth/config.d.ts +1 -1
  6. package/dist/auth/config.js +3 -3
  7. package/dist/auth/config.js.map +1 -1
  8. package/dist/auth/spotify-auth-client.d.ts +1 -0
  9. package/dist/auth/spotify-auth-client.js +4 -0
  10. package/dist/auth/spotify-auth-client.js.map +1 -1
  11. package/dist/cli.js +61 -1
  12. package/dist/cli.js.map +1 -1
  13. package/dist/services/auth.service.d.ts +1 -1
  14. package/dist/services/auth.service.js +17 -4
  15. package/dist/services/auth.service.js.map +1 -1
  16. package/dist/services/catalog.service.d.ts +9 -0
  17. package/dist/services/catalog.service.js +22 -0
  18. package/dist/services/catalog.service.js.map +1 -0
  19. package/dist/services/device.service.d.ts +20 -0
  20. package/dist/services/device.service.js +81 -0
  21. package/dist/services/device.service.js.map +1 -0
  22. package/dist/services/library.service.d.ts +13 -0
  23. package/dist/services/library.service.js +46 -0
  24. package/dist/services/library.service.js.map +1 -0
  25. package/dist/services/mappers.d.ts +10 -0
  26. package/dist/services/mappers.js +104 -0
  27. package/dist/services/mappers.js.map +1 -0
  28. package/dist/services/models.d.ts +45 -0
  29. package/dist/services/player.service.d.ts +12 -2
  30. package/dist/services/player.service.js +80 -15
  31. package/dist/services/player.service.js.map +1 -1
  32. package/dist/services/playlist.service.d.ts +9 -0
  33. package/dist/services/playlist.service.js +33 -0
  34. package/dist/services/playlist.service.js.map +1 -0
  35. package/dist/services/queue.service.d.ts +18 -0
  36. package/dist/services/queue.service.js +43 -0
  37. package/dist/services/queue.service.js.map +1 -0
  38. package/dist/services/recent.service.d.ts +7 -0
  39. package/dist/services/recent.service.js +24 -0
  40. package/dist/services/recent.service.js.map +1 -0
  41. package/dist/services/search.service.d.ts +5 -1
  42. package/dist/services/search.service.js +32 -17
  43. package/dist/services/search.service.js.map +1 -1
  44. package/dist/services/update.service.d.ts +57 -0
  45. package/dist/services/update.service.js +313 -0
  46. package/dist/services/update.service.js.map +1 -0
  47. package/dist/spotify/client.js +14 -1
  48. package/dist/spotify/client.js.map +1 -1
  49. package/dist/spotify/scopes.d.ts +2 -1
  50. package/dist/spotify/scopes.js +9 -1
  51. package/dist/spotify/scopes.js.map +1 -1
  52. package/dist/spotify/types.d.ts +112 -8
  53. package/dist/storage/config.d.ts +30 -0
  54. package/dist/storage/config.js +128 -0
  55. package/dist/storage/config.js.map +1 -0
  56. package/dist/storage/credentials.d.ts +1 -0
  57. package/dist/storage/credentials.js +1 -0
  58. package/dist/storage/credentials.js.map +1 -1
  59. package/dist/storage/index.d.ts +2 -0
  60. package/dist/storage/index.js +1 -0
  61. package/dist/storage/index.js.map +1 -1
  62. package/dist/storage/update-cache.d.ts +29 -0
  63. package/dist/storage/update-cache.js +135 -0
  64. package/dist/storage/update-cache.js.map +1 -0
  65. package/dist/ui/output.d.ts +10 -1
  66. package/dist/ui/output.js +60 -0
  67. package/dist/ui/output.js.map +1 -1
  68. package/dist/ui/prompts.d.ts +12 -1
  69. package/dist/ui/prompts.js +73 -6
  70. package/dist/ui/prompts.js.map +1 -1
  71. package/dist/ui/watch.d.ts +7 -0
  72. package/dist/ui/watch.js +44 -0
  73. package/dist/ui/watch.js.map +1 -0
  74. package/dist/update-worker.d.ts +9 -0
  75. package/dist/update-worker.js +91 -0
  76. package/dist/update-worker.js.map +1 -0
  77. package/dist/version.d.ts +2 -0
  78. package/dist/version.js +11 -0
  79. package/dist/version.js.map +1 -0
  80. package/package.json +1 -1
package/README.md CHANGED
@@ -21,13 +21,27 @@ Create an application in the [Spotify Developer Dashboard](https://developer.spo
21
21
  http://127.0.0.1:43821/callback
22
22
  ```
23
23
 
24
- Export the application's client ID before running authentication:
24
+ After installing `spoti`, save the application's client ID once:
25
+
26
+ ```bash
27
+ spoti setup
28
+ spoti login
29
+ ```
30
+
31
+ When developing from source, use:
32
+
33
+ ```bash
34
+ npm run dev -- setup
35
+ npm run dev -- login
36
+ ```
37
+
38
+ The setup command stores the public client ID in your local `spoti` configuration. For temporary sessions, CI, or an explicit override, you can still use:
25
39
 
26
40
  ```bash
27
41
  export SPOTIFY_CLIENT_ID="your-client-id"
28
42
  ```
29
43
 
30
- To use a different local callback, register it in the same Spotify application and set:
44
+ The environment variable takes precedence over the stored value. To use a different local callback, register it in the same Spotify application and set:
31
45
 
32
46
  ```bash
33
47
  export SPOTIFY_REDIRECT_URI="http://127.0.0.1:5000/callback"
@@ -78,12 +92,51 @@ Control playback:
78
92
 
79
93
  ```bash
80
94
  spoti now
95
+ spoti now --watch
81
96
  spoti play "Numb"
82
97
  spoti play "Numb" --first
98
+ spoti play "Numb" --watch
99
+ spoti play "Numb" --no-watch
83
100
  spoti pause
84
101
  spoti resume
85
102
  spoti next
86
103
  spoti previous
104
+ spoti volume 50
105
+ spoti volume +10
106
+ spoti volume -10
107
+ spoti shuffle on
108
+ spoti shuffle off
109
+ spoti repeat off
110
+ spoti repeat track
111
+ spoti repeat context
112
+ ```
113
+
114
+ Manage playback devices:
115
+
116
+ ```bash
117
+ spoti devices
118
+ spoti device 2
119
+ spoti device "My Computer"
120
+ ```
121
+
122
+ Use the displayed one-based number, exact device name, or Spotify device ID.
123
+
124
+ When playback has no active device, `spoti play` and `spoti resume` automatically target it if exactly one controllable device is available.
125
+
126
+ Seek within the current track:
127
+
128
+ ```bash
129
+ spoti seek 1:30
130
+ spoti seek +30
131
+ spoti seek -10
132
+ ```
133
+
134
+ View the queue or search for a track to add:
135
+
136
+ ```bash
137
+ spoti queue
138
+ spoti queue "Faint"
139
+ spoti queue "Faint" --first
87
140
  ```
88
141
 
89
142
  Search without starting playback:
@@ -93,6 +146,49 @@ spoti search "Breaking the Habit"
93
146
  spoti search "Breaking the Habit" --limit 5
94
147
  ```
95
148
 
149
+ Search, inspect, and play Spotify contexts:
150
+
151
+ ```bash
152
+ spoti album "Meteora"
153
+ spoti artist "Linkin Park"
154
+ spoti playlists
155
+ spoti playlist 1
156
+ spoti playlist "Workout"
157
+ spoti play track "Numb"
158
+ spoti play album "Meteora"
159
+ spoti play artist "Linkin Park"
160
+ spoti play playlist "Workout"
161
+ spoti play playlist 1
162
+ ```
163
+
164
+ User playlists are sorted consistently by name, so the displayed number can be reused with `spoti playlist <number>` or `spoti play playlist <number>`.
165
+
166
+ In an interactive terminal, `spoti album` can play the entire album or a selected track after showing its details. `spoti artist` can play the artist context or let you select one of the artist’s albums, and `spoti playlist` can start the selected playlist. Non-interactive runs remain display-only and never start playback implicitly.
167
+
168
+ `spoti play <query>` remains shorthand for track playback. The words `track`, `album`, `artist`, and `playlist` are treated as explicit types when followed by another argument. For a track query that starts with one of those reserved words, use `spoti play track <query>` (or quote the complete query as one shell argument). Context commands support `--first` to skip interactive selection.
169
+
170
+ Manage and inspect your Spotify library:
171
+
172
+ ```bash
173
+ spoti liked
174
+ spoti liked --limit 10
175
+ spoti like
176
+ spoti unlike
177
+ spoti recent
178
+ spoti recent --limit 10
179
+ ```
180
+
181
+ `spoti like` and `spoti unlike` operate on the currently playing track. Episodes, advertisements, local files, and unavailable items are ignored safely.
182
+
183
+ Check for updates or install the latest npm release:
184
+
185
+ ```bash
186
+ spoti update --check
187
+ spoti update
188
+ ```
189
+
190
+ `spoti update` asks for confirmation before installing the exact version returned by the update check. It never installs an update silently. Normal commands use a cached update result and refresh it in a detached process at most once every 24 hours, so npm availability does not delay or break Spotify controls.
191
+
96
192
  Remove local credentials:
97
193
 
98
194
  ```bash
@@ -101,6 +197,37 @@ spoti logout
101
197
 
102
198
  When attached to an interactive terminal, `spoti play <query>` asks you to select a result. In non-interactive usage it chooses the first result automatically; `--first` makes that behavior explicit.
103
199
 
200
+ Watch mode continuously refreshes the current track and progress until `Ctrl+C` is pressed. `--watch` enables it for one command, while `--no-watch` overrides a saved preference.
201
+
202
+ ## Configuration
203
+
204
+ View all settings:
205
+
206
+ ```bash
207
+ spoti config
208
+ ```
209
+
210
+ Read, update, or reset settings:
211
+
212
+ ```bash
213
+ spoti config get spotifyClientId
214
+ spoti config set spotifyClientId "your-client-id"
215
+ spoti config get watchAfterPlay
216
+ spoti config set watchAfterPlay true
217
+ spoti config set refreshIntervalMs 2000
218
+ spoti config reset
219
+ ```
220
+
221
+ Available settings:
222
+
223
+ | Setting | Default | Description |
224
+ | --- | ---: | --- |
225
+ | `spotifyClientId` | `null` | Public Spotify application client ID saved by `spoti setup`. |
226
+ | `watchAfterPlay` | `false` | Keep `spoti play` open in watch mode after playback starts. |
227
+ | `refreshIntervalMs` | `1000` | Watch refresh interval from `1000` to `30000` milliseconds. |
228
+
229
+ Command flags take precedence over saved configuration. Application preferences are stored in `$XDG_CONFIG_HOME/spoti/config.json`, or `~/.config/spoti/config.json` when `XDG_CONFIG_HOME` is not set.
230
+
104
231
  ## Credentials
105
232
 
106
233
  Credentials are stored locally in:
@@ -115,7 +242,7 @@ or, when `XDG_CONFIG_HOME` is not set:
115
242
  ~/.config/spoti/credentials.json
116
243
  ```
117
244
 
118
- The credentials file is created with user-only permissions (`0600`). Access tokens refresh automatically. Keep `SPOTIFY_CLIENT_ID` available in the environment because Spotify requires it during token refresh. Never provide or store a Spotify client secret in `spoti`.
245
+ The credentials file is created with user-only permissions (`0600`). Access tokens refresh automatically using the environment client ID when present, otherwise the client ID saved by `spoti setup`. Version `0.3.0` adds minimum permissions for private playlist listing, liked-track access, library modification, and recently played tracks. Existing installations will be asked to run `spoti login` once after upgrading. Never provide or store a Spotify client secret in `spoti`.
119
246
 
120
247
  ## Spotify API policy
121
248
 
@@ -132,6 +259,19 @@ npm test
132
259
  npm run build
133
260
  ```
134
261
 
262
+ ## Releases
263
+
264
+ GitHub Releases are created automatically when a version tag is pushed. The tag must match the version in `package.json`:
265
+
266
+ ```bash
267
+ npm version patch
268
+ npm run verify
269
+ git push origin main
270
+ git push origin v0.1.1
271
+ ```
272
+
273
+ The release workflow attaches the npm package tarball and a `SHA256SUMS` file, and generates release notes from the Git history. Publishing to npm remains a separate explicit step.
274
+
135
275
  ## Current scope
136
276
 
137
- Version `0.1.0` supports authentication, current playback, track search, direct track playback, pause/resume, and next/previous controls. Queue, volume, seek, shuffle, repeat, device switching, library features, JSON output, and a TUI are planned for later releases.
277
+ Version `0.3.0` supports authentication and persistent client-ID setup; track, album, artist, and playlist discovery and playback; guided playback actions; current playback and watch mode; pause/resume and next/previous; volume, seek, shuffle, and repeat; queue and library management; recently played tracks; deterministic numeric device and playlist selection; and cached update notifications with explicit update commands. JSON output and a TUI remain planned for later releases.
package/dist/app.d.ts CHANGED
@@ -1,14 +1,40 @@
1
1
  import { Command } from 'commander';
2
2
  import type { AuthService } from './services/auth.service.js';
3
+ import type { CatalogService } from './services/catalog.service.js';
4
+ import type { DeviceService } from './services/device.service.js';
5
+ import type { LibraryService } from './services/library.service.js';
3
6
  import type { PlayerService } from './services/player.service.js';
7
+ import type { PlaylistService } from './services/playlist.service.js';
8
+ import type { QueueService } from './services/queue.service.js';
9
+ import type { RecentService } from './services/recent.service.js';
4
10
  import type { SearchService } from './services/search.service.js';
11
+ import { type UpdateService } from './services/update.service.js';
12
+ import { type ConfigStore } from './storage/config.js';
5
13
  import { type Output } from './ui/output.js';
6
- import { selectTrack } from './ui/prompts.js';
14
+ import { confirmUpdate, promptSpotifyClientId, selectAlbum, selectAlbumAction, selectArtist, selectArtistAction, selectPlaylist, selectPlaylistAction, selectTrack } from './ui/prompts.js';
15
+ import { type PlaybackWatcher } from './ui/watch.js';
7
16
  export interface AppDependencies {
8
17
  auth: AuthService;
18
+ catalog: CatalogService;
9
19
  player: PlayerService;
10
20
  search: SearchService;
21
+ playlist: PlaylistService;
22
+ library: LibraryService;
23
+ recent: RecentService;
24
+ device: DeviceService;
25
+ queue: QueueService;
26
+ update: UpdateService;
27
+ config: ConfigStore;
11
28
  output: Output;
12
29
  chooseTrack?: typeof selectTrack;
30
+ chooseAlbum?: typeof selectAlbum;
31
+ chooseArtist?: typeof selectArtist;
32
+ choosePlaylist?: typeof selectPlaylist;
33
+ chooseAlbumAction?: typeof selectAlbumAction;
34
+ chooseArtistAction?: typeof selectArtistAction;
35
+ choosePlaylistAction?: typeof selectPlaylistAction;
36
+ requestSpotifyClientId?: typeof promptSpotifyClientId;
37
+ confirmUpdate?: typeof confirmUpdate;
38
+ watchPlayback?: PlaybackWatcher;
13
39
  }
14
40
  export declare function createProgram(dependencies: AppDependencies): Command;