singsalot/functions/lib/index.js

132 lines
5.5 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.recalculateTopPlayed = exports.updateTopPlayedOnHistoryChange = void 0;
const functions = require("firebase-functions");
const admin = require("firebase-admin");
// Initialize Firebase Admin
admin.initializeApp();
// Database reference
const db = admin.database();
/**
* Cloud Function that triggers when a song is added to history
* This function aggregates all history items to create/update the topPlayed collection
* based on unique combinations of artist and title (not path)
*/
exports.updateTopPlayedOnHistoryChange = functions.database
.ref('/controllers/{controllerName}/history/{historyId}')
.onCreate(async (snapshot, context) => {
const { controllerName } = context.params;
console.log(`TopPlayed update triggered for controller: ${controllerName}`);
try {
// Get the controller reference
const controllerRef = db.ref(`/controllers/${controllerName}`);
// Get all history items for this controller
const historySnapshot = await controllerRef.child('history').once('value');
const historyData = historySnapshot.val();
if (!historyData) {
console.log('No history data found, skipping TopPlayed update');
return;
}
// Aggregate history items by path
const aggregation = {};
Object.values(historyData).forEach((song) => {
const historySong = song;
if (historySong && historySong.path) {
const path = historySong.path;
if (aggregation[path]) {
aggregation[path].count += historySong.count || 1;
}
else {
aggregation[path] = {
artist: historySong.artist,
title: historySong.title,
path: historySong.path,
count: historySong.count || 1
};
}
}
});
// Convert aggregation to array, sort by count (descending), and take top 100
const sortedSongs = Object.entries(aggregation)
.map(([, songData]) => ({
artist: songData.artist,
title: songData.title,
path: songData.path,
count: songData.count
}))
.sort((a, b) => b.count - a.count)
.slice(0, 100);
// Write as an array so Firebase uses numeric keys
await controllerRef.child('topPlayed').set(sortedSongs);
console.log(`Successfully updated TopPlayed for controller ${controllerName} with ${sortedSongs.length} unique songs (by path)`);
}
catch (error) {
console.error('Error updating TopPlayed:', error);
throw error;
}
});
/**
* Alternative function that can be called manually to recalculate TopPlayed
* This is useful for initial setup or data migration
*/
exports.recalculateTopPlayed = functions.https.onCall(async (data) => {
const { controllerName } = data;
if (!controllerName) {
throw new functions.https.HttpsError('invalid-argument', 'controllerName is required');
}
console.log(`Manual TopPlayed recalculation requested for controller: ${controllerName}`);
try {
// Get the controller reference
const controllerRef = db.ref(`/controllers/${controllerName}`);
// Get all history items for this controller
const historySnapshot = await controllerRef.child('history').once('value');
const historyData = historySnapshot.val();
if (!historyData) {
console.log('No history data found, returning empty TopPlayed');
await controllerRef.child('topPlayed').set({});
return { success: true, message: 'No history data found, TopPlayed cleared' };
}
// Aggregate history items by path
const aggregation = {};
Object.values(historyData).forEach((song) => {
const historySong = song;
if (historySong && historySong.path) {
const path = historySong.path;
if (aggregation[path]) {
aggregation[path].count += historySong.count || 1;
}
else {
aggregation[path] = {
artist: historySong.artist,
title: historySong.title,
path: historySong.path,
count: historySong.count || 1
};
}
}
});
// Convert aggregation to array, sort by count (descending), and take top 100
const sortedSongs = Object.entries(aggregation)
.map(([, songData]) => ({
artist: songData.artist,
title: songData.title,
path: songData.path,
count: songData.count
}))
.sort((a, b) => b.count - a.count)
.slice(0, 100);
// Write as an array so Firebase uses numeric keys
await controllerRef.child('topPlayed').set(sortedSongs);
console.log(`Successfully recalculated TopPlayed for controller ${controllerName} with ${sortedSongs.length} unique songs (by path)`);
return {
success: true,
message: `TopPlayed recalculated successfully`,
songCount: sortedSongs.length
};
}
catch (error) {
console.error('Error recalculating TopPlayed:', error);
throw new functions.https.HttpsError('internal', 'Failed to recalculate TopPlayed');
}
});
//# sourceMappingURL=index.js.map