unreleased-cli 0.0.0-stage → 0.1.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.
- package/LICENSE +31 -0
- package/README.md +200 -3
- package/dist/unreleased.mjs +5565 -0
- package/package.json +45 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 leanwrldd
|
|
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.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
NOTE: The MIT license above applies to the source code of this project
|
|
26
|
+
("unreleased"). Binary distributions (desktop installers) bundle third-party
|
|
27
|
+
components under their own licenses - including FFmpeg, which is licensed under
|
|
28
|
+
the GNU General Public License v3.0. See THIRD-PARTY-NOTICES.md for details and
|
|
29
|
+
obligations. This project is a fan-made client and is not affiliated with,
|
|
30
|
+
endorsed by, or connected to Juice WRLD, his estate, or any associated party;
|
|
31
|
+
all music, artwork, names, and trademarks belong to their respective owners.
|
package/README.md
CHANGED
|
@@ -1,3 +1,200 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# unreleased-cli
|
|
2
|
+
|
|
3
|
+
The site's terminal as a command-line shell. You can browse the Files tab's channels as a folder tree, read text files, search, and download straight to disk. It uses the same API as the site.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
guest@unreleased:~/files/comp$ ls
|
|
7
|
+
<dir> Compilation/
|
|
8
|
+
<dir> Snippets/
|
|
9
|
+
...
|
|
10
|
+
guest@unreleased:~/files/comp$ get -o covers "Compilation/4. Cover Art"
|
|
11
|
+
saved 44 files (25.9 MB) to covers
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
From npm (any OS, Node 20 or newer):
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
npm install -g unreleased-cli
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
On Ubuntu (PPA, Node 18 or newer):
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
sudo add-apt-repository ppa:leanwrldd/unreleased-cli
|
|
26
|
+
sudo apt install unreleased-cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
From source:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
npm install
|
|
33
|
+
npm run build
|
|
34
|
+
npm link # puts `unreleased` on your PATH
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
You can also run it without linking: `node dist/unreleased.mjs`. It needs Node 20 or newer and has no runtime dependencies. Playback also needs [mpv](https://mpv.io) (`winget install shinchiro.mpv`, `brew install mpv`, or your package manager).
|
|
38
|
+
|
|
39
|
+
## Use
|
|
40
|
+
|
|
41
|
+
| | |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `unreleased` | Open the interactive shell. |
|
|
44
|
+
| `unreleased ls Snippets` | Run one command and exit. The exit code is 1 if the command failed. A single quoted argument is a whole line: `unreleased "ls \| head 2"`. |
|
|
45
|
+
| `unreleased < script.txt` | Run each line of a file. Lines starting with `#` are comments. |
|
|
46
|
+
|
|
47
|
+
The shell starts in the main channel (`comp`). `cd /` lists every channel, and `cd` on its own takes you back.
|
|
48
|
+
|
|
49
|
+
Commands (type `help <command>` in the shell for the details of each one):
|
|
50
|
+
|
|
51
|
+
- **Files:** `cd`, `ls`, `pwd`, `lcd`, `get`, `cat`, `head`, `tail`, `wc`, `grep`, `locate`, `tree`, `du`
|
|
52
|
+
- **Library:** `find`, `song`, `like`, `unlike`, `liked`, `playlists`, `playlist`, `stats`
|
|
53
|
+
- **Player:** `play`, `pause`, `toggle`, `next`, `prev`, `seek`, `volume`, `speed`, `shuffle`, `repeat`, `queue`, `status`, `sleep`, `stop`
|
|
54
|
+
- **People:** `user`, `lookup`
|
|
55
|
+
- **Admin** (administrators only): `pending`, `proposals`, `comps`, `applications`, `inspect`, `approve`, `reject`, `reverse`, `users`, `sitebans`, `siteunban`
|
|
56
|
+
- **Fun:** `neofetch`, `fortune`, `juicesay`, `matrix`, `visualizer`, `wordle`, `heardle`
|
|
57
|
+
- **Settings:** `set`, `settings`, `termtheme`
|
|
58
|
+
- **Shell:** `source`, `alias`, `unalias`, `history`, `echo`, `watch`, `full`, `date`, `clear`, `exit`, `help`
|
|
59
|
+
- **Account:** `login`, `logout`, `whoami`, `version`
|
|
60
|
+
|
|
61
|
+
Things that work the same as on the site:
|
|
62
|
+
|
|
63
|
+
- Pipe output into `grep`, `head`, `tail`, `wc`, `sort`, `uniq` or `juicesay`. A `|` inside quotes stays part of the argument.
|
|
64
|
+
- `!!`, `!N` and `!text` re-run earlier commands.
|
|
65
|
+
- Ctrl+R searches your history, as in bash:
|
|
66
|
+
- Type to find the newest match, and press Ctrl+R again for older ones.
|
|
67
|
+
- Enter runs the match. Esc or an arrow key puts it on the line to edit.
|
|
68
|
+
- Ctrl+C gives up and leaves the line as it was.
|
|
69
|
+
- `cd -` goes back to the previous folder.
|
|
70
|
+
- `alias` saves shortcuts.
|
|
71
|
+
- Tab completes command names and paths.
|
|
72
|
+
- Ctrl+C cancels the running command.
|
|
73
|
+
- `watch [-n seconds] <command>` re-runs a command on a refreshing screen, every 2 seconds unless `-n` says otherwise. Quote it if it has a pipe: `watch -n 5 "pending | head 3"`. `q` leaves.
|
|
74
|
+
|
|
75
|
+
`get` saves into the current local folder. Use `lcd` to change that folder, or `get -o <dir>` for a single download. A folder keeps its structure on disk where the site would hand you a ZIP. Files that already exist are skipped unless you pass `-f`.
|
|
76
|
+
|
|
77
|
+
## Library
|
|
78
|
+
|
|
79
|
+
`find <title>` searches the songs and numbers the results. `liked` and `playlist show` number theirs too. A number then stands for that row in the next command: `song 2`, `like 2`, `playlist add Chill -- 2`.
|
|
80
|
+
|
|
81
|
+
- `song <title | N>` shows a song's era, credits and dates, plus the `get` command that downloads its file.
|
|
82
|
+
- `playlist` can show, create, delete, add and remove. A playlist can be named by a few letters of its title or by its number in `playlists`. Deleting asks first, or takes `-y`. Playing a playlist is left to the site, since the CLI has no player.
|
|
83
|
+
- `stats [all | 7 | 30] [N]` charts your listening history the way the site does. It needs the whole song catalog (about 11 MB), so a slim copy is kept in `~/.unreleased/cache` for a day. `-r` reloads it.
|
|
84
|
+
- `user <id>` works for anyone. `user <name>` needs an administrator account, because it searches the admin account list. The site finds people through chat, which the CLI doesn't have.
|
|
85
|
+
- `lookup <text>` searches songs, your playlists, channels, commands and (for administrators) people at once.
|
|
86
|
+
|
|
87
|
+
Playlists, likes and stats need you to be signed in.
|
|
88
|
+
|
|
89
|
+
## Playback
|
|
90
|
+
|
|
91
|
+
Music plays through a hidden mpv that the interactive shell starts the first time you play something.
|
|
92
|
+
|
|
93
|
+
- `play <title | N>` plays a song by title, or by its number from the last list.
|
|
94
|
+
- `play <file | folder>` plays something from the file tree. A folder queues the audio files directly inside it, and `play .` plays the folder you're in.
|
|
95
|
+
- `playlist play <name>`, `playlist shuffle <name>`, `liked play` and `shuffle <era> [count]` replace the queue.
|
|
96
|
+
- `queue add` and `queue next` add to it. `queue` lists it, and `remove N` / `jump N` change it.
|
|
97
|
+
- Shuffle, repeat, previous and the end of the queue behave as they do on the site.
|
|
98
|
+
- `status` (or `now`) shows the song, a progress bar, the settings and the queue.
|
|
99
|
+
- `like` and `unlike` with no song act on the one playing.
|
|
100
|
+
|
|
101
|
+
The music stops when you leave the shell, so `unreleased play …` on its own says to open the shell instead. If the shell is killed without a chance to stop mpv (for example the terminal window is closed), mpv quits by itself within about 10 seconds.
|
|
102
|
+
|
|
103
|
+
The CLI looks for mpv on PATH and then in the usual install folders. Set `UNRELEASED_MPV` to its path if it lives somewhere else. mpv reads your own `mpv.conf`, so settings like the audio device carry over.
|
|
104
|
+
|
|
105
|
+
When you're signed in, a song counts as played once you've listened to it: 30 seconds in, or halfway through anything shorter, the same rule as the site's player. The play is added to your listening history on the site (`POST /accounts/account/me/listening-plays/`), so it shows up in `stats`, Home and your profile. Skipping through a queue doesn't count, and a song you restart or seek back to the start of can count again. Files played from the tree have no song id and never count. If the server refuses a play, the shell says so once.
|
|
106
|
+
|
|
107
|
+
The song's play counter in your profile goes up by one as well. The server has no increment for it (the counters are one JSON blob the client replaces whole), so the CLI reads the blob, adds the plays and writes it back, keeping every other field as it was. That write waits a few seconds so a run of plays becomes one write, and the shell sends any that are left when you exit. If the shell is killed instead (the terminal window is closed), the last few seconds of counts are lost, but the history entries are not. The site merges counters with max(), so a count raised here isn't undone by a stale copy there.
|
|
108
|
+
|
|
109
|
+
## Admin
|
|
110
|
+
|
|
111
|
+
These cover the Admin page's review queues and site moderation, using the same endpoints. They only appear in `help` for an administrator account, and they stop any other account before a request is sent. If your role changed since you logged in, run `whoami` to refresh it.
|
|
112
|
+
|
|
113
|
+
- `pending` shows how much is waiting in each queue.
|
|
114
|
+
- `proposals`, `comps` and `applications` list a queue. Each takes a status: pending (the default), approved, rejected, or reversed.
|
|
115
|
+
- `inspect [song|comp|app] <id>` shows one item in full. For a song edit, that's every field it changes.
|
|
116
|
+
- `approve` and `reject` take `[song|comp|app] <id> [note]`. Song edits are the default kind, so `approve 12` and `reject 12 no source` work as they are.
|
|
117
|
+
- `reverse [song|comp] <id>` undoes an approved proposal.
|
|
118
|
+
- `users [role] [filter]` lists accounts. `user <name>` shows one person.
|
|
119
|
+
- `sitebans` lists active site-wide bans, mutes and timeouts. `siteunban <user | #id>` lifts them.
|
|
120
|
+
|
|
121
|
+
`reverse` and `siteunban` ask before they act. Outside the interactive shell, such as in one-shot use or a script, they need `-y` instead.
|
|
122
|
+
|
|
123
|
+
## Fun
|
|
124
|
+
|
|
125
|
+
- `neofetch` shows system info with a logo.
|
|
126
|
+
- `fortune` prints a random lyric line from a random song. Try `fortune | juicesay`.
|
|
127
|
+
- `juicesay [text]` has a juice box say it.
|
|
128
|
+
- `matrix` is digital rain. Any key leaves.
|
|
129
|
+
- `visualizer` (or `viz`) is a live spectrum of the song that's playing. Any key leaves. mpv can't hand its audio over, so a second mpv decodes the same stream to a temp file and the bars come from that, which means the song is downloaded a second time while the screen is open.
|
|
130
|
+
- `wordle [daily | unlimited]` is the song-title Wordle, using the site's own puzzle logic, so the daily puzzle is the same one. Type a title and press Enter. Esc leaves, and your progress is saved.
|
|
131
|
+
- `heardle` gives practice rounds: Tab plays the clip, Enter guesses (an empty Enter skips), and ↑↓ picks a suggestion. The clip plays through its own mpv. Music that was playing gets paused, and `play` resumes it.
|
|
132
|
+
|
|
133
|
+
`matrix`, `visualizer`, `wordle`, `heardle` and `watch` take over the whole terminal, then hand it back as it was. They need an interactive terminal, so they won't run from a pipe or a script.
|
|
134
|
+
|
|
135
|
+
Wordle and Heardle keep their progress, streaks and song lists in `~/.unreleased/storage.json`. That's separate from your browser's, the same way two browsers are separate. They use the default game settings, because the settings you change on the site are stored in your browser.
|
|
136
|
+
|
|
137
|
+
## Settings
|
|
138
|
+
|
|
139
|
+
`settings` lists what you can change, and `set <setting> [value]` shows or changes one (`set volume 40`, `set shuffle toggle`; Tab completes the names and choices). They're kept in `~/.unreleased/settings.json`, so they carry over to the next session, and without the shell (`unreleased set volume 40`) the value is saved for next time. The site's Settings screen is mostly look and layout, so only the parts a command line has are here:
|
|
140
|
+
|
|
141
|
+
| Setting | |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `theme` | The terminal colour scheme, the same as `termtheme` |
|
|
144
|
+
| `color` | Colour in the output (`NO_COLOR` turns it off too) |
|
|
145
|
+
| `volume`, `speed`, `repeat`, `shuffle` | The player's modes. The `volume`, `speed`, `repeat` and `shuffle` commands change the same values, and they now stay put between sessions, as on the site |
|
|
146
|
+
| `pitch-shift` | Let the pitch follow the speed (off keeps the pitch where it was) |
|
|
147
|
+
|
|
148
|
+
`termtheme [name]` lists the colour schemes (the site's own list, so a new one there turns up here after the next sync and build) or switches to one. A scheme colours the prompt, messages, rain and visualizer in truecolor, and the default one uses your terminal's own palette. It can't change the terminal's background.
|
|
149
|
+
|
|
150
|
+
`full` asks the terminal window to go fullscreen, and to leave again. It sends the xterm request for that, which many terminals ignore (Windows Terminal does), so F11 is the fallback.
|
|
151
|
+
|
|
152
|
+
## Signing in
|
|
153
|
+
|
|
154
|
+
You can browse the files without an account. To sign in:
|
|
155
|
+
|
|
156
|
+
- `login` asks for your API token. On the site, open the terminal and type `token copy` to get it.
|
|
157
|
+
- `login <username>` signs in with a username and password, and asks for a 2FA code if the account has one.
|
|
158
|
+
|
|
159
|
+
`logout` only forgets the token on this computer. The token itself keeps working on the site.
|
|
160
|
+
|
|
161
|
+
## API base and route rules
|
|
162
|
+
|
|
163
|
+
`api` shows the current base. `api set <url>` moves everything to another API instance, and `api reset` goes back to the default.
|
|
164
|
+
|
|
165
|
+
Route rules send one path prefix somewhere else on top of that, like the site's Settings: `api rule /cdn https://cdn.example.com/juicewrld`. The longest matching prefix wins. `api unrule /cdn` removes one. `UNRELEASED_API` still overrides the base.
|
|
166
|
+
|
|
167
|
+
## Files and environment
|
|
168
|
+
|
|
169
|
+
Everything is kept in `~/.unreleased`. Set `UNRELEASED_HOME` to use another folder.
|
|
170
|
+
|
|
171
|
+
| File | Contents |
|
|
172
|
+
|---|---|
|
|
173
|
+
| `config.json` | The token and account name (owner-only permissions where the OS supports it), plus an optional `"api"` base URL and `"rules"` route rules (set both with the `api` command) |
|
|
174
|
+
| `history` | Typed commands. Start a line with a space and it won't be saved. |
|
|
175
|
+
| `aliases.json` | Your aliases |
|
|
176
|
+
| `settings.json` | What `set` and `termtheme` change: theme, colour, volume, speed, repeat, shuffle, pitch-shift |
|
|
177
|
+
| `storage.json` | Wordle and Heardle progress, streaks and their cached song lists |
|
|
178
|
+
| `cache/catalog.json` | The song catalog `stats` and `shuffle <era>` use, refreshed daily |
|
|
179
|
+
| `rc` | Commands run each time the interactive shell starts |
|
|
180
|
+
|
|
181
|
+
| Environment variable | Effect |
|
|
182
|
+
|---|---|
|
|
183
|
+
| `UNRELEASED_TOKEN` | Use this token instead of the saved one |
|
|
184
|
+
| `UNRELEASED_API` | Use another API base (the default is `https://juicewrldapi.com/juicewrld`) |
|
|
185
|
+
| `UNRELEASED_MPV` | The mpv executable to play through |
|
|
186
|
+
| `NO_COLOR` | Turn off colours |
|
|
187
|
+
|
|
188
|
+
Git Bash on Windows rewrites a bare `/` argument into its own install path, so `unreleased ls /` lists the wrong place there. Run it from inside the shell, or set `MSYS_NO_PATHCONV=1`.
|
|
189
|
+
|
|
190
|
+
## How it's built
|
|
191
|
+
|
|
192
|
+
Some of the CLI is the site's own code, compiled in by `build.mjs`. That code lives in `site/`, a copy of the files from the site repo (kept in the same folder layout, so their imports still resolve). `site/SYNCED_FROM.json` says which site commit it was taken from, and `site-modules.mjs` lists which modules are used and which of their imports are swapped for a Node version:
|
|
193
|
+
|
|
194
|
+
- `cat`, `head`, `tail`, `wc`, `grep`, `locate`, `tree` and `du` come from `src/renderer/src/lib/terminalFileTools.ts`. Its imports point at `src/files.ts`, the Node version of the site's `terminalFiles.ts`.
|
|
195
|
+
- The `stats` maths comes from `lib/listeningStats.ts`. Its two helpers from `juicewrldApi.ts` are swapped for `src/shims/juicewrldApi.ts`.
|
|
196
|
+
- Playlist name matching comes from `lib/terminal/types.ts`.
|
|
197
|
+
- The `termtheme` colour schemes come from `lib/terminal/themeStore.ts` (its `react` import is swapped for a stub).
|
|
198
|
+
- The Wordle and Heardle logic comes from `lib/wordle.ts`, `lib/heardle.ts` and `lib/versionsApi.ts`. That covers the daily pick, grading, title search and version matching. Their request helpers are swapped for shims in `src/shims/`, and `localStorage` for `src/shims/localStorage.ts`.
|
|
199
|
+
|
|
200
|
+
A change to those on the site reaches the CLI when you run `npm run sync` (it copies the files from the site checkout next to this repo, `../music-player-web`; pass another path with `npm run sync -- <path>` or `UNRELEASED_SITE`) and then `npm run build`. The sync works out the file list itself by bundling against the checkout, so a new import in one of those modules is picked up without editing anything. The declarations in `src/site.d.ts` have to stay in step with their signatures. The other commands are ports, because their site versions read the app's stores.
|