Skip to content

Commit f8db44a

Browse files
committed
expanded api
1 parent 4a94fe5 commit f8db44a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+15670
-825
lines changed

.env

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
REACT_APP_API_BASE_URL = "http://localhost:3678"
2-
REACT_APP_WS_URL = "ws://localhost:3678/events"
1+
REACT_APP_API_BASE_URL = "http://apollo:3678"
2+
REACT_APP_WS_URL = "ws://apollo:3678/events"
33
REACT_APP_KIOSK_MODE = "false"
44
REACT_APP_HIDE_ON_DISCONNECT = "false"
5-
REACT_APP_LAYOUT = "auto"
5+
REACT_APP_LAYOUT = "auto"

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
node_modules
22
package-lock.json
3-
dist
3+
dist
4+
.notes
5+
build
6+
.claude

README.md

Lines changed: 107 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,87 +6,133 @@
66
[![GitHub License](https://img.shields.io/github/license/stronk-dev/react-librespot-controller)](https://github.com/stronk-dev/react-librespot-controller/blob/master/LICENSE)
77
[![Dependabot Updates](https://github.com/stronk-dev/react-librespot-controller/actions/workflows/dependabot/dependabot-updates/badge.svg)](https://github.com/stronk-dev/react-librespot-controller/actions/workflows/dependabot/dependabot-updates)
88

9-
> [`go-librespot`](https://github.com/devgianlu/go-librespot) squeezebox-alike web frontend for small touchscreens
10-
11-
Can be deployed standalone or imported as a NPM module.
9+
A squeezebox-alike React frontend for controlling [`go-librespot`](https://github.com/devgianlu/go-librespot).
10+
11+
Use it as:
12+
- a standalone page for touchscreens
13+
- an embedded component in internal dashboards
14+
15+
## UI Scope
16+
- Layout modes: `auto`, `default`, `widescreen`, `portrait`
17+
- Views: `Info`, `Playlists`, `Queue`, `Settings`
18+
- Interactive album art card: tap to browse the current album, playlist, or show
19+
- In-app navigation from now playing metadata to album, artist, and show details
20+
- Browse playlists: view tracks with lazy-loaded metadata, play individual tracks
21+
- Browse artists: portrait image, biography, top tracks, albums, singles, related artists
22+
- Browse albums: tracklist with durations, explicit badges, clickable artist links
23+
- Browse shows: episodes with durations and publish dates
24+
- Playlist cards with cover art, name, description, owner, track count
25+
- Paginated playlist loading with infinite scroll
26+
- Client-side image URL normalization for Spotify CDN compatibility
27+
- Comes with a set of preset themes and sleep timer
28+
- Podcast controls include skip back 15s and skip forward 30s
29+
30+
## Backend Requirements
31+
This UI needs a [`go-librespot`](https://github.com/devgianlu/go-librespot) instance with:
32+
- HTTP API: player controls, metadata endpoints (`/metadata/rootlist`, `/metadata/playlist/{id}`, `/metadata/track/{id}`, `/metadata/album/{id}`, `/metadata/artist/{id}`, `/metadata/show/{id}`, `/metadata/episode/{id}`)
33+
- WebSocket event stream at `/events`
34+
- All metadata is fetched via Spotify's native Mercury/protobuf protocols (no Spotify Web API keys needed)
35+
36+
## Standalone Setup
37+
Create a `.env` file:
38+
39+
```env
40+
REACT_APP_API_BASE_URL=http://apollo:3678
41+
REACT_APP_WS_URL=ws://apollo:3678/events
42+
REACT_APP_KIOSK_MODE=false
43+
REACT_APP_HIDE_ON_DISCONNECT=false
44+
REACT_APP_LAYOUT=auto
45+
```
1246

13-
The player is styled in the [Tokyo Night](https://github.com/tokyo-night/tokyo-night-vscode-theme) colour scheme except for the album image, which emits an ambilight effect based on the colours in the image.
47+
Install and run:
1448

15-
## Install `go-librespot`
16-
TODO: refer to OG source instructions + explain `systemd` script
17-
```
18-
[Unit]
19-
Description=Spotify daemon
20-
Documentation=https://github.com/devgianlu/go-librespot
21-
Wants=sound.target
22-
After=sound.target
23-
Wants=network-online.target
24-
After=network-online.target
25-
26-
[Service]
27-
WorkingDirectory=/home/pulseaudio/go-librespot
28-
ExecStart=/usr/local/go/bin/go run /home/pulseaudio/go-librespot/cmd/daemon
29-
Restart=always
30-
RestartSec=12
31-
32-
[Install]
33-
WantedBy=default.target
49+
```bash
50+
npm install
51+
npm run test
52+
npm run static
53+
npm run build
3454
```
3555

36-
## Config `go-librespot`
37-
TODO: instructions to enable the API
56+
Commands:
57+
- `npm run test`: starts the local demo app
58+
- `npm run static`: creates the static app build
59+
- `npm run build`: builds the npm package output in `dist/`
3860

39-
Make sure to mention the bind address.
61+
## Module Setup
62+
Install:
4063

41-
## Standalone
42-
43-
Create a `.env` file and fill in you API endpoints
44-
```
45-
REACT_APP_API_BASE_URL=http://apollo:3678
46-
REACT_APP_WS_URL=ws://apollo:3678/events
64+
```bash
65+
npm install --save @stronk-tech/react-librespot-controller
4766
```
4867

49-
Run `npm run test` for local debugging.
50-
Run `npm run static` to generate the build folder.
68+
Use:
5169

52-
TODO: build instructions
53-
54-
TODO: nginx instructions. Include HTTPS instructions with local IP whitelist (+hairpin nat)
70+
```jsx
71+
import MediaPlayer from "@stronk-tech/react-librespot-controller";
5572

56-
TODO: OS instructions (auto-login, open browser, etc)
73+
<MediaPlayer
74+
websocketUrl="ws://apollo:3678/events"
75+
apiBaseUrl="http://apollo:3678"
76+
hideOnDisconnect={false}
77+
kioskMode={false}
78+
layout="auto"
79+
maxHeight="70vh"
80+
mobileBreakpoint={768}
81+
theme="tokyo-night"
82+
/>;
83+
```
5784

85+
### Embedding
5886

59-
## Module
87+
The player sizes itself automatically via CSS `aspect-ratio`. Height is derived from available width per layout mode — tab content scrolls internally and never resizes the outer card.
6088

61-
First install the dependency:
62-
```
63-
npm install --save `@stronk-tech/react-librespot-controller`
89+
```jsx
90+
<div style={{ width: "100%", overflow: "hidden" }}>
91+
<MediaPlayer websocketUrl="ws://apollo:3678/events" apiBaseUrl="http://apollo:3678" />
92+
</div>
6493
```
6594

66-
Then import the component and fill in your API endpoints:
67-
```
68-
import MediaPlayer from "@stronk-tech/react-librespot-controller";
69-
<MediaPlayer websocketUrl={"ws://apollo:3678/events"} apiBaseUrl={"http://apollo:3678"} hideOnDisconnect={false} />
95+
Override the max-height cap or panel scroll height with CSS vars:
96+
97+
```css
98+
.my-wrapper {
99+
--spotify-player-max-height: 70vh;
100+
--spotify-player-panel-max-height: 48vh;
101+
}
70102
```
71103

72104
### Props
105+
- `websocketUrl`: WebSocket URL for `go-librespot` events
106+
- `apiBaseUrl`: HTTP API base URL for `go-librespot`
107+
- `hideOnDisconnect`: hides the component when API connection is down
108+
- `kioskMode`: uses full-screen behavior
109+
- `autoDetectKiosk`: auto-enables kiosk mode when card fills most of viewport (default `false`)
110+
- `layout`: `auto`, `default`, `widescreen`, `portrait`
111+
- `maxHeight`: maximum component height cap (CSS value, default `100vh`)
112+
- `panelMaxHeight`: maximum height for scrollable content panels like playlists/details (default `60vh`)
113+
- `mobileBreakpoint`: when `layout="auto"`, force portrait at or below this viewport width (default `768`)
114+
- `theme`: optional preset name; if omitted, saved theme is used, default is `tokyo-night`
115+
116+
### Theme Presets
117+
`tokyo-night`, `tokyo-night-light`, `dracula`, `nord`, `catppuccin`, `catppuccin-light`, `gruvbox`, `gruvbox-light`, `one-dark`, `github-dark`, `rose-pine`, `solarized`, `solarized-light`, `ayu-mirage`
118+
119+
### Preview
120+
![Browse Flow](screenshots/browse-flow.gif)
121+
122+
### Default view / Kiosk mode
123+
![Default](screenshots/default-info.png)
73124

74-
- `hideOnDisconnect`: When `true`, the entire component will hide itself when there is no connection to the API endpoint. Otherwise it will display an error state.
75-
- `websocketUrl`: Full URL to the WebSocket endpoint of the `go-librespot` client.
76-
- `apiBaseUrl`: Full URL to the HTTP API endpoint of the `go-librespot` client.
77-
- `kioskMode`: When `true`, the component will fill the entire screen. Otherwise it will fill the available width and base the layout on the width only. It is recommended to leave this option `false` when importing the module into an existing webpage and to `true` when you are running the player standalone on a touch screen.
78-
- `layout`: Can be `auto`, `default`, `widescreen`, `portrait`. See the screenshots for how the layouts look like.
125+
### Widescreen
126+
![Widescreen](screenshots/widescreen-info.png)
79127

80-
# Screen shots
81-
The player arranges itself based on the screen dimensions, with three possible layouts:
128+
### Portrait
129+
![Portrait](screenshots/portrait-info.png)
82130

83-
### Default layout
84-
![Default](screenshots/default.png)
131+
### Queue
132+
![Queue](screenshots/queue-tab.png)
85133

86-
### Widescreen
87-
![Wide1](screenshots/widescreen.png)
88-
![Wide2](screenshots/widescreen_lib.png)
89-
![Wide3](screenshots/widescreen_library.png)
134+
### Settings
135+
![Settings](screenshots/settings-tab.png)
90136

91-
### Portrait
92-
![Portrait](screenshots/portrait.png)
137+
### Browse
138+
![Browse Artist](screenshots/browse-artist.png)

package.json

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,42 @@
11
{
22
"name": "@stronk-tech/react-librespot-controller",
33
"description": "`go-librespot` squeezebox-alike web frontend for small touchscreens",
4-
"version": "0.1.10",
4+
"version": "0.2.2",
5+
"type": "module",
56
"main": "dist/index.cjs.js",
67
"module": "dist/index.esm.js",
8+
"exports": {
9+
".": {
10+
"import": "./dist/index.esm.js",
11+
"require": "./dist/index.cjs.js"
12+
}
13+
},
714
"files": [
815
"dist"
916
],
1017
"dependencies": {
1118
"prop-types": "^15.8.1",
12-
"react-icons": "^5.4.0"
19+
"react-icons": "^5.5.0"
1320
},
1421
"devDependencies": {
15-
"@babel/preset-env": "^7.26.0",
16-
"@babel/preset-react": "^7.26.3",
17-
"@rollup/plugin-babel": "^6.0.4",
18-
"@rollup/plugin-commonjs": "^28.0.1",
22+
"@babel/preset-env": "^7.29.0",
23+
"@babel/preset-react": "^7.28.5",
24+
"@rollup/plugin-babel": "^6.1.0",
25+
"@rollup/plugin-commonjs": "^29.0.0",
1926
"@rollup/plugin-image": "^3.0.3",
2027
"@rollup/plugin-json": "^6.1.0",
21-
"@rollup/plugin-node-resolve": "^15.3.0",
22-
"@rollup/plugin-replace": "^6.0.1",
28+
"@rollup/plugin-node-resolve": "^16.0.3",
29+
"@rollup/plugin-replace": "^6.0.3",
2330
"@rollup/plugin-terser": "^0.4.4",
2431
"@rollup/plugin-url": "^8.0.2",
25-
"dotenv": "^16.4.7",
26-
"eslint": "^8.57.0",
32+
"dotenv": "^17.3.1",
33+
"eslint": "^8.57.1",
2734
"eslint-config-react-app": "^7.0.1",
28-
"react": "^19.0.0",
29-
"react-dom": "^19.0.0",
35+
"react": "^19.2.4",
36+
"react-dom": "^19.2.4",
3037
"react-scripts": "^5.0.1",
31-
"rollup": "^4.28.1",
32-
"rollup-plugin-import-css": "^3.5.7",
38+
"rollup": "^4.59.0",
39+
"rollup-plugin-import-css": "^4.2.0",
3340
"rollup-plugin-peer-deps-external": "^2.2.4"
3441
},
3542
"babel": {
@@ -39,11 +46,8 @@
3946
]
4047
},
4148
"peerDependencies": {
42-
"react": "^17.0.0 || ^18.0.0",
43-
"react-dom": "^17.0.0 || ^18.0.0"
44-
},
45-
"eslintConfig": {
46-
"extends": "react-app"
49+
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
50+
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
4751
},
4852
"scripts": {
4953
"start": "NODE_ENV=development rollup -c --watch",

0 commit comments

Comments
 (0)