@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.
@@ -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
- if (!db) {
89
- return response.status(500).json({ error: "Database not available" });
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
- if (!db) {
126
- return response.status(500).json({ error: "Database not available" });
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
- const days = Math.min(parseInt(request.query.days) || 30, 90);
130
- const trends = await getListeningTrends(db, days);
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({ trends, days });
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
- return syncListenings(db, client);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-funkwhale",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Funkwhale listening activity endpoint for Indiekit. Display listening history, favorites, and statistics.",
5
5
  "keywords": [
6
6
  "indiekit",