@rmdes/indiekit-endpoint-funkwhale 1.0.0 → 1.0.1
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/lib/controllers/stats.js +29 -9
- package/lib/sync.js +39 -1
- package/package.json +1 -1
package/lib/controllers/stats.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getAllStats, getListeningTrends } from "../stats.js";
|
|
2
|
+
import { getCachedStats } from "../sync.js";
|
|
2
3
|
import { formatTotalTime } from "../utils.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -84,13 +85,23 @@ export const statsController = {
|
|
|
84
85
|
return response.status(500).json({ error: "Not configured" });
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
// Try database first, fall back to cache for public routes
|
|
87
89
|
const db = request.app.locals.database;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
let stats;
|
|
91
|
+
|
|
92
|
+
if (db) {
|
|
93
|
+
stats = await getAllStats(db, funkwhaleConfig.limits);
|
|
94
|
+
} else {
|
|
95
|
+
// Public routes don't have DB access, use cached stats
|
|
96
|
+
stats = getCachedStats();
|
|
97
|
+
if (!stats) {
|
|
98
|
+
return response.status(503).json({
|
|
99
|
+
error: "Stats not available yet",
|
|
100
|
+
message: "Stats are computed during background sync. Please try again shortly.",
|
|
101
|
+
});
|
|
102
|
+
}
|
|
90
103
|
}
|
|
91
104
|
|
|
92
|
-
const stats = await getAllStats(db, funkwhaleConfig.limits);
|
|
93
|
-
|
|
94
105
|
// Add formatted durations
|
|
95
106
|
stats.summary.all.totalDurationFormatted = formatTotalTime(
|
|
96
107
|
stats.summary.all.totalDuration
|
|
@@ -122,14 +133,23 @@ export const statsController = {
|
|
|
122
133
|
}
|
|
123
134
|
|
|
124
135
|
const db = request.app.locals.database;
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
const days = Math.min(parseInt(request.query.days) || 30, 90);
|
|
137
|
+
|
|
138
|
+
if (db) {
|
|
139
|
+
const trends = await getListeningTrends(db, days);
|
|
140
|
+
return response.json({ trends, days });
|
|
127
141
|
}
|
|
128
142
|
|
|
129
|
-
|
|
130
|
-
const
|
|
143
|
+
// Fall back to cached stats for public routes
|
|
144
|
+
const cachedStats = getCachedStats();
|
|
145
|
+
if (cachedStats?.trends) {
|
|
146
|
+
return response.json({ trends: cachedStats.trends, days: 30 });
|
|
147
|
+
}
|
|
131
148
|
|
|
132
|
-
response.json({
|
|
149
|
+
return response.status(503).json({
|
|
150
|
+
error: "Trends not available yet",
|
|
151
|
+
message: "Trends are computed during background sync. Please try again shortly.",
|
|
152
|
+
});
|
|
133
153
|
} catch (error) {
|
|
134
154
|
console.error("[Funkwhale] Trends API error:", error);
|
|
135
155
|
response.status(500).json({ error: error.message });
|
package/lib/sync.js
CHANGED
|
@@ -1,8 +1,35 @@
|
|
|
1
1
|
import { FunkwhaleClient } from "./funkwhale-client.js";
|
|
2
2
|
import { getCoverUrl, getArtistName } from "./utils.js";
|
|
3
|
+
import { getAllStats, getListeningTrends } from "./stats.js";
|
|
3
4
|
|
|
4
5
|
let syncInterval = null;
|
|
5
6
|
|
|
7
|
+
// In-memory cache for stats (accessible to public routes)
|
|
8
|
+
let cachedStats = null;
|
|
9
|
+
let cachedStatsTime = null;
|
|
10
|
+
const STATS_CACHE_TTL = 300_000; // 5 minutes
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get cached stats (for public API routes that can't access DB)
|
|
14
|
+
* @returns {object|null} - Cached stats or null
|
|
15
|
+
*/
|
|
16
|
+
export function getCachedStats() {
|
|
17
|
+
if (!cachedStats) return null;
|
|
18
|
+
if (cachedStatsTime && Date.now() - cachedStatsTime > STATS_CACHE_TTL) {
|
|
19
|
+
return cachedStats; // Return stale cache, sync will refresh
|
|
20
|
+
}
|
|
21
|
+
return cachedStats;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Update stats cache
|
|
26
|
+
* @param {object} stats - Stats to cache
|
|
27
|
+
*/
|
|
28
|
+
export function setCachedStats(stats) {
|
|
29
|
+
cachedStats = stats;
|
|
30
|
+
cachedStatsTime = Date.now();
|
|
31
|
+
}
|
|
32
|
+
|
|
6
33
|
/**
|
|
7
34
|
* Start background sync process
|
|
8
35
|
* @param {object} Indiekit - Indiekit instance
|
|
@@ -61,7 +88,18 @@ export async function runSync(Indiekit, options) {
|
|
|
61
88
|
cacheTtl: 60_000, // Short cache for sync
|
|
62
89
|
});
|
|
63
90
|
|
|
64
|
-
|
|
91
|
+
const result = await syncListenings(db, client);
|
|
92
|
+
|
|
93
|
+
// Update stats cache after sync
|
|
94
|
+
try {
|
|
95
|
+
const stats = await getAllStats(db, options.limits || {});
|
|
96
|
+
setCachedStats(stats);
|
|
97
|
+
console.log("[Funkwhale] Stats cache updated");
|
|
98
|
+
} catch (err) {
|
|
99
|
+
console.error("[Funkwhale] Failed to cache stats:", err.message);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return result;
|
|
65
103
|
}
|
|
66
104
|
|
|
67
105
|
/**
|
package/package.json
CHANGED