@rmdes/indiekit-endpoint-funkwhale 1.0.6 → 1.0.8
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/README.md +59 -34
- package/lib/controllers/dashboard.js +4 -6
- package/package.json +1 -1
- package/views/funkwhale.njk +4 -4
package/README.md
CHANGED
|
@@ -1,50 +1,54 @@
|
|
|
1
1
|
# @rmdes/indiekit-endpoint-funkwhale
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@rmdes/indiekit-endpoint-funkwhale)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
3
6
|
Funkwhale listening activity endpoint for [Indiekit](https://getindiekit.com/).
|
|
4
7
|
|
|
5
8
|
Display your Funkwhale listening history, favorite tracks, and listening statistics on your IndieWeb site.
|
|
6
9
|
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
Install from npm:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @rmdes/indiekit-endpoint-funkwhale
|
|
16
|
+
```
|
|
17
|
+
|
|
7
18
|
## Features
|
|
8
19
|
|
|
20
|
+
- **Admin Dashboard** - Overview of your listening activity in Indiekit's admin UI
|
|
9
21
|
- **Now Playing Widget** - Shows currently playing or recently played tracks
|
|
10
22
|
- **Listening History** - Browse your listening history with album art
|
|
11
23
|
- **Favorites** - Display your favorite tracks
|
|
12
|
-
- **Statistics** - View listening stats
|
|
13
|
-
|
|
14
|
-
- Top Artists and Albums
|
|
15
|
-
- Listening trend charts
|
|
24
|
+
- **Statistics** - View listening stats (plays, unique tracks, unique artists)
|
|
25
|
+
- **Background Sync** - Automatically syncs listening data to MongoDB
|
|
16
26
|
- **Public JSON API** - For integration with static site generators like Eleventy
|
|
17
27
|
|
|
18
|
-
## Installation
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install @rmdes/indiekit-endpoint-funkwhale
|
|
22
|
-
```
|
|
23
|
-
|
|
24
28
|
## Configuration
|
|
25
29
|
|
|
26
30
|
Add to your `indiekit.config.js`:
|
|
27
31
|
|
|
28
32
|
```javascript
|
|
33
|
+
import FunkwhaleEndpoint from "@rmdes/indiekit-endpoint-funkwhale";
|
|
34
|
+
|
|
29
35
|
export default {
|
|
30
36
|
plugins: [
|
|
31
|
-
|
|
37
|
+
new FunkwhaleEndpoint({
|
|
38
|
+
mountPath: "/funkwhale",
|
|
39
|
+
instanceUrl: process.env.FUNKWHALE_INSTANCE,
|
|
40
|
+
username: process.env.FUNKWHALE_USERNAME,
|
|
41
|
+
token: process.env.FUNKWHALE_TOKEN,
|
|
42
|
+
cacheTtl: 900_000, // 15 minutes
|
|
43
|
+
syncInterval: 300_000, // 5 minutes
|
|
44
|
+
limits: {
|
|
45
|
+
listenings: 20,
|
|
46
|
+
favorites: 20,
|
|
47
|
+
topArtists: 10,
|
|
48
|
+
topAlbums: 10
|
|
49
|
+
}
|
|
50
|
+
}),
|
|
32
51
|
],
|
|
33
|
-
|
|
34
|
-
"@rmdes/indiekit-endpoint-funkwhale": {
|
|
35
|
-
mountPath: "/funkwhale",
|
|
36
|
-
instanceUrl: process.env.FUNKWHALE_INSTANCE,
|
|
37
|
-
username: process.env.FUNKWHALE_USERNAME,
|
|
38
|
-
token: process.env.FUNKWHALE_TOKEN,
|
|
39
|
-
cacheTtl: 900_000, // 15 minutes
|
|
40
|
-
syncInterval: 300_000, // 5 minutes
|
|
41
|
-
limits: {
|
|
42
|
-
listenings: 20,
|
|
43
|
-
favorites: 20,
|
|
44
|
-
topArtists: 10,
|
|
45
|
-
topAlbums: 10
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
52
|
};
|
|
49
53
|
```
|
|
50
54
|
|
|
@@ -65,24 +69,45 @@ export default {
|
|
|
65
69
|
|
|
66
70
|
## Routes
|
|
67
71
|
|
|
68
|
-
###
|
|
72
|
+
### Admin Routes (require authentication)
|
|
69
73
|
|
|
70
74
|
| Route | Description |
|
|
71
75
|
|-------|-------------|
|
|
72
|
-
| `GET /funkwhale/` | Dashboard with
|
|
73
|
-
| `
|
|
74
|
-
| `GET /funkwhale/favorites` | Favorite tracks |
|
|
75
|
-
| `GET /funkwhale/stats` | Statistics with tabs |
|
|
76
|
+
| `GET /funkwhale/` | Dashboard overview with stats, recent plays, favorites |
|
|
77
|
+
| `POST /funkwhale/sync` | Trigger manual sync |
|
|
76
78
|
|
|
77
79
|
### Public API Routes (JSON)
|
|
78
80
|
|
|
81
|
+
These endpoints are publicly accessible and can be used by static site generators like Eleventy to display listening activity on your site.
|
|
82
|
+
|
|
79
83
|
| Route | Description |
|
|
80
84
|
|-------|-------------|
|
|
81
85
|
| `GET /funkwhale/api/now-playing` | Current/recent track |
|
|
82
86
|
| `GET /funkwhale/api/listenings` | Recent listenings |
|
|
83
87
|
| `GET /funkwhale/api/favorites` | Favorites list |
|
|
84
|
-
| `GET /funkwhale/api/stats` | All statistics |
|
|
85
|
-
| `GET /funkwhale/api/stats/trends` | Trend data for charts |
|
|
88
|
+
| `GET /funkwhale/api/stats` | All statistics (summary, top artists, top albums) |
|
|
89
|
+
| `GET /funkwhale/api/stats/trends` | Trend data for charts (30 days) |
|
|
90
|
+
|
|
91
|
+
### Example: Eleventy Integration
|
|
92
|
+
|
|
93
|
+
Fetch data from the public API in your Eleventy `_data` file:
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
// _data/funkwhale.js
|
|
97
|
+
import EleventyFetch from "@11ty/eleventy-fetch";
|
|
98
|
+
|
|
99
|
+
export default async function() {
|
|
100
|
+
const baseUrl = process.env.SITE_URL || "https://example.com";
|
|
101
|
+
|
|
102
|
+
const [nowPlaying, listenings, stats] = await Promise.all([
|
|
103
|
+
EleventyFetch(`${baseUrl}/funkwhale/api/now-playing`, { duration: "15m", type: "json" }),
|
|
104
|
+
EleventyFetch(`${baseUrl}/funkwhale/api/listenings`, { duration: "15m", type: "json" }),
|
|
105
|
+
EleventyFetch(`${baseUrl}/funkwhale/api/stats`, { duration: "15m", type: "json" }),
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
return { nowPlaying, listenings, stats };
|
|
109
|
+
}
|
|
110
|
+
```
|
|
86
111
|
|
|
87
112
|
## Options
|
|
88
113
|
|
|
@@ -108,7 +133,7 @@ export default {
|
|
|
108
133
|
## Requirements
|
|
109
134
|
|
|
110
135
|
- Indiekit >= 1.0.0-beta.25
|
|
111
|
-
- MongoDB (for statistics aggregation)
|
|
136
|
+
- MongoDB (for statistics aggregation and sync)
|
|
112
137
|
- Funkwhale instance with API v2
|
|
113
138
|
|
|
114
139
|
## License
|
|
@@ -66,21 +66,16 @@ export const dashboardController = {
|
|
|
66
66
|
// Get stats from cache (same source as public API)
|
|
67
67
|
// If cache is empty, try to refresh it from database
|
|
68
68
|
let cachedStats = getCachedStats();
|
|
69
|
-
console.log("[Funkwhale Dashboard] cachedStats:", cachedStats ? "exists" : "null");
|
|
70
69
|
if (!cachedStats) {
|
|
71
70
|
const getDb = request.app.locals.application.getFunkwhaleDb;
|
|
72
|
-
console.log("[Funkwhale Dashboard] getFunkwhaleDb:", getDb ? "exists" : "null");
|
|
73
71
|
if (getDb) {
|
|
74
72
|
const db = getDb();
|
|
75
|
-
console.log("[Funkwhale Dashboard] db:", db ? "exists" : "null");
|
|
76
73
|
if (db) {
|
|
77
74
|
cachedStats = await refreshStatsCache(db, limits);
|
|
78
|
-
console.log("[Funkwhale Dashboard] after refresh:", cachedStats ? "exists" : "null");
|
|
79
75
|
}
|
|
80
76
|
}
|
|
81
77
|
}
|
|
82
78
|
const summary = cachedStats?.summary?.all || null;
|
|
83
|
-
console.log("[Funkwhale Dashboard] summary:", JSON.stringify(summary));
|
|
84
79
|
|
|
85
80
|
// Determine public frontend URL (strip 'api' from mount path)
|
|
86
81
|
// e.g., /funkwhaleapi -> /funkwhale
|
|
@@ -91,7 +86,10 @@ export const dashboardController = {
|
|
|
91
86
|
nowPlaying,
|
|
92
87
|
listenings: listenings.slice(0, 5),
|
|
93
88
|
favorites: favorites.slice(0, 5),
|
|
94
|
-
summary,
|
|
89
|
+
totalPlays: summary?.totalPlays || 0,
|
|
90
|
+
uniqueTracks: summary?.uniqueTracks || 0,
|
|
91
|
+
uniqueArtists: summary?.uniqueArtists || 0,
|
|
92
|
+
hasStats: !!summary,
|
|
95
93
|
publicUrl,
|
|
96
94
|
mountPath: request.baseUrl,
|
|
97
95
|
});
|
package/package.json
CHANGED
package/views/funkwhale.njk
CHANGED
|
@@ -193,20 +193,20 @@
|
|
|
193
193
|
{% endif %}
|
|
194
194
|
|
|
195
195
|
{# Quick Stats Summary #}
|
|
196
|
-
{% if
|
|
196
|
+
{% if hasStats %}
|
|
197
197
|
<section class="fw-section">
|
|
198
198
|
<h2>{{ __("funkwhale.stats") }}</h2>
|
|
199
199
|
<div class="fw-stats-grid">
|
|
200
200
|
<div class="fw-stat">
|
|
201
|
-
<span class="fw-stat-value">{{
|
|
201
|
+
<span class="fw-stat-value">{{ totalPlays }}</span>
|
|
202
202
|
<span class="fw-stat-label">{{ __("funkwhale.plays") }}</span>
|
|
203
203
|
</div>
|
|
204
204
|
<div class="fw-stat">
|
|
205
|
-
<span class="fw-stat-value">{{
|
|
205
|
+
<span class="fw-stat-value">{{ uniqueTracks }}</span>
|
|
206
206
|
<span class="fw-stat-label">{{ __("funkwhale.tracks") }}</span>
|
|
207
207
|
</div>
|
|
208
208
|
<div class="fw-stat">
|
|
209
|
-
<span class="fw-stat-value">{{
|
|
209
|
+
<span class="fw-stat-value">{{ uniqueArtists }}</span>
|
|
210
210
|
<span class="fw-stat-label">{{ __("funkwhale.artists") }}</span>
|
|
211
211
|
</div>
|
|
212
212
|
</div>
|