Signed-off-by: mbrucedogs <mbrucedogs@gmail.com>
This commit is contained in:
parent
b6aa7da1bf
commit
58669a0abc
4
functions/execute-samples.txt
Normal file
4
functions/execute-samples.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Invoke-WebRequest -Uri "https://us-central1-firebase-herse.cloudfunctions.net/recalculateTopPlayed" `
|
||||||
|
>> -Method POST `
|
||||||
|
>> -Headers @{"Content-Type"="application/json"} `
|
||||||
|
>> -Body '{"data": {"controllerName": "bsully5150"}}'
|
||||||
@ -27,25 +27,20 @@ exports.updateTopPlayedOnHistoryChange = functions.database
|
|||||||
console.log('No history data found, skipping TopPlayed update');
|
console.log('No history data found, skipping TopPlayed update');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Aggregate history items by artist + title combination
|
// Aggregate history items by path
|
||||||
const aggregation = {};
|
const aggregation = {};
|
||||||
Object.values(historyData).forEach((song) => {
|
Object.values(historyData).forEach((song) => {
|
||||||
const historySong = song;
|
const historySong = song;
|
||||||
if (historySong && historySong.artist && historySong.title) {
|
if (historySong && historySong.path) {
|
||||||
// Create a unique key based on artist and title (case-insensitive)
|
const path = historySong.path;
|
||||||
// Replace invalid Firebase key characters with underscores
|
if (aggregation[path]) {
|
||||||
const sanitizedArtist = String(historySong.artist || '').toLowerCase().trim().replace(/[.#$/[\]]/g, '_');
|
aggregation[path].count += historySong.count || 1;
|
||||||
const sanitizedTitle = String(historySong.title || '').toLowerCase().trim().replace(/[.#$/[\]]/g, '_');
|
|
||||||
const key = `${sanitizedArtist}_${sanitizedTitle}`;
|
|
||||||
if (aggregation[key]) {
|
|
||||||
// Increment count for existing song
|
|
||||||
aggregation[key].count += historySong.count || 1;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Create new entry
|
aggregation[path] = {
|
||||||
aggregation[key] = {
|
|
||||||
artist: historySong.artist,
|
artist: historySong.artist,
|
||||||
title: historySong.title,
|
title: historySong.title,
|
||||||
|
path: historySong.path,
|
||||||
count: historySong.count || 1
|
count: historySong.count || 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -53,26 +48,17 @@ exports.updateTopPlayedOnHistoryChange = functions.database
|
|||||||
});
|
});
|
||||||
// Convert aggregation to array, sort by count (descending), and take top 100
|
// Convert aggregation to array, sort by count (descending), and take top 100
|
||||||
const sortedSongs = Object.entries(aggregation)
|
const sortedSongs = Object.entries(aggregation)
|
||||||
.map(([key, songData]) => ({
|
.map(([, songData]) => ({
|
||||||
key,
|
|
||||||
artist: songData.artist,
|
artist: songData.artist,
|
||||||
title: songData.title,
|
title: songData.title,
|
||||||
|
path: songData.path,
|
||||||
count: songData.count
|
count: songData.count
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => b.count - a.count) // Sort by count descending
|
.sort((a, b) => b.count - a.count)
|
||||||
.slice(0, 100); // Take only top 100
|
.slice(0, 100);
|
||||||
// Convert back to object format for Firebase
|
// Write as an array so Firebase uses numeric keys
|
||||||
const topPlayedData = {};
|
await controllerRef.child('topPlayed').set(sortedSongs);
|
||||||
sortedSongs.forEach((song) => {
|
console.log(`Successfully updated TopPlayed for controller ${controllerName} with ${sortedSongs.length} unique songs (by path)`);
|
||||||
topPlayedData[song.key] = {
|
|
||||||
artist: song.artist,
|
|
||||||
title: song.title,
|
|
||||||
count: song.count
|
|
||||||
};
|
|
||||||
});
|
|
||||||
// Update the topPlayed collection
|
|
||||||
await controllerRef.child('topPlayed').set(topPlayedData);
|
|
||||||
console.log(`Successfully updated TopPlayed for controller ${controllerName} with ${Object.keys(topPlayedData).length} unique songs`);
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('Error updating TopPlayed:', error);
|
console.error('Error updating TopPlayed:', error);
|
||||||
@ -83,7 +69,7 @@ exports.updateTopPlayedOnHistoryChange = functions.database
|
|||||||
* Alternative function that can be called manually to recalculate TopPlayed
|
* Alternative function that can be called manually to recalculate TopPlayed
|
||||||
* This is useful for initial setup or data migration
|
* This is useful for initial setup or data migration
|
||||||
*/
|
*/
|
||||||
exports.recalculateTopPlayed = functions.https.onCall(async (data, context) => {
|
exports.recalculateTopPlayed = functions.https.onCall(async (data) => {
|
||||||
const { controllerName } = data;
|
const { controllerName } = data;
|
||||||
if (!controllerName) {
|
if (!controllerName) {
|
||||||
throw new functions.https.HttpsError('invalid-argument', 'controllerName is required');
|
throw new functions.https.HttpsError('invalid-argument', 'controllerName is required');
|
||||||
@ -100,25 +86,20 @@ exports.recalculateTopPlayed = functions.https.onCall(async (data, context) => {
|
|||||||
await controllerRef.child('topPlayed').set({});
|
await controllerRef.child('topPlayed').set({});
|
||||||
return { success: true, message: 'No history data found, TopPlayed cleared' };
|
return { success: true, message: 'No history data found, TopPlayed cleared' };
|
||||||
}
|
}
|
||||||
// Aggregate history items by artist + title combination
|
// Aggregate history items by path
|
||||||
const aggregation = {};
|
const aggregation = {};
|
||||||
Object.values(historyData).forEach((song) => {
|
Object.values(historyData).forEach((song) => {
|
||||||
const historySong = song;
|
const historySong = song;
|
||||||
if (historySong && historySong.artist && historySong.title) {
|
if (historySong && historySong.path) {
|
||||||
// Create a unique key based on artist and title (case-insensitive)
|
const path = historySong.path;
|
||||||
// Replace invalid Firebase key characters with underscores
|
if (aggregation[path]) {
|
||||||
const sanitizedArtist = String(historySong.artist || '').toLowerCase().trim().replace(/[.#$/[\]]/g, '_');
|
aggregation[path].count += historySong.count || 1;
|
||||||
const sanitizedTitle = String(historySong.title || '').toLowerCase().trim().replace(/[.#$/[\]]/g, '_');
|
|
||||||
const key = `${sanitizedArtist}_${sanitizedTitle}`;
|
|
||||||
if (aggregation[key]) {
|
|
||||||
// Increment count for existing song
|
|
||||||
aggregation[key].count += historySong.count || 1;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Create new entry
|
aggregation[path] = {
|
||||||
aggregation[key] = {
|
|
||||||
artist: historySong.artist,
|
artist: historySong.artist,
|
||||||
title: historySong.title,
|
title: historySong.title,
|
||||||
|
path: historySong.path,
|
||||||
count: historySong.count || 1
|
count: historySong.count || 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -126,30 +107,21 @@ exports.recalculateTopPlayed = functions.https.onCall(async (data, context) => {
|
|||||||
});
|
});
|
||||||
// Convert aggregation to array, sort by count (descending), and take top 100
|
// Convert aggregation to array, sort by count (descending), and take top 100
|
||||||
const sortedSongs = Object.entries(aggregation)
|
const sortedSongs = Object.entries(aggregation)
|
||||||
.map(([key, songData]) => ({
|
.map(([, songData]) => ({
|
||||||
key,
|
|
||||||
artist: songData.artist,
|
artist: songData.artist,
|
||||||
title: songData.title,
|
title: songData.title,
|
||||||
|
path: songData.path,
|
||||||
count: songData.count
|
count: songData.count
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => b.count - a.count) // Sort by count descending
|
.sort((a, b) => b.count - a.count)
|
||||||
.slice(0, 100); // Take only top 100
|
.slice(0, 100);
|
||||||
// Convert back to object format for Firebase
|
// Write as an array so Firebase uses numeric keys
|
||||||
const topPlayedData = {};
|
await controllerRef.child('topPlayed').set(sortedSongs);
|
||||||
sortedSongs.forEach((song) => {
|
console.log(`Successfully recalculated TopPlayed for controller ${controllerName} with ${sortedSongs.length} unique songs (by path)`);
|
||||||
topPlayedData[song.key] = {
|
|
||||||
artist: song.artist,
|
|
||||||
title: song.title,
|
|
||||||
count: song.count
|
|
||||||
};
|
|
||||||
});
|
|
||||||
// Update the topPlayed collection
|
|
||||||
await controllerRef.child('topPlayed').set(topPlayedData);
|
|
||||||
console.log(`Successfully recalculated TopPlayed for controller ${controllerName} with ${Object.keys(topPlayedData).length} unique songs`);
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: `TopPlayed recalculated successfully`,
|
message: `TopPlayed recalculated successfully`,
|
||||||
songCount: Object.keys(topPlayedData).length
|
songCount: sortedSongs.length
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -19,17 +19,11 @@ interface HistorySong {
|
|||||||
key?: string;
|
key?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TopPlayed {
|
interface HistoryAggregationByPath {
|
||||||
artist: string;
|
[path: string]: {
|
||||||
title: string;
|
|
||||||
count: number;
|
|
||||||
key?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface HistoryAggregation {
|
|
||||||
[key: string]: {
|
|
||||||
artist: string;
|
artist: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
path: string;
|
||||||
count: number;
|
count: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -59,26 +53,20 @@ export const updateTopPlayedOnHistoryChange = functions.database
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate history items by artist + title combination
|
// Aggregate history items by path
|
||||||
const aggregation: HistoryAggregation = {};
|
const aggregation: HistoryAggregationByPath = {};
|
||||||
|
|
||||||
Object.values(historyData).forEach((song: unknown) => {
|
Object.values(historyData).forEach((song: unknown) => {
|
||||||
const historySong = song as HistorySong;
|
const historySong = song as HistorySong;
|
||||||
if (historySong && historySong.artist && historySong.title) {
|
if (historySong && historySong.path) {
|
||||||
// Create a unique key based on artist and title (case-insensitive)
|
const path = historySong.path;
|
||||||
// Replace invalid Firebase key characters with underscores
|
if (aggregation[path]) {
|
||||||
const sanitizedArtist = String(historySong.artist || '').toLowerCase().trim().replace(/[.#$/[\]]/g, '_');
|
aggregation[path].count += historySong.count || 1;
|
||||||
const sanitizedTitle = String(historySong.title || '').toLowerCase().trim().replace(/[.#$/[\]]/g, '_');
|
|
||||||
const key = `${sanitizedArtist}_${sanitizedTitle}`;
|
|
||||||
|
|
||||||
if (aggregation[key]) {
|
|
||||||
// Increment count for existing song
|
|
||||||
aggregation[key].count += historySong.count || 1;
|
|
||||||
} else {
|
} else {
|
||||||
// Create new entry
|
aggregation[path] = {
|
||||||
aggregation[key] = {
|
|
||||||
artist: historySong.artist,
|
artist: historySong.artist,
|
||||||
title: historySong.title,
|
title: historySong.title,
|
||||||
|
path: historySong.path,
|
||||||
count: historySong.count || 1
|
count: historySong.count || 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -87,30 +75,19 @@ export const updateTopPlayedOnHistoryChange = functions.database
|
|||||||
|
|
||||||
// Convert aggregation to array, sort by count (descending), and take top 100
|
// Convert aggregation to array, sort by count (descending), and take top 100
|
||||||
const sortedSongs = Object.entries(aggregation)
|
const sortedSongs = Object.entries(aggregation)
|
||||||
.map(([key, songData]) => ({
|
.map(([, songData]) => ({
|
||||||
key,
|
|
||||||
artist: songData.artist,
|
artist: songData.artist,
|
||||||
title: songData.title,
|
title: songData.title,
|
||||||
|
path: songData.path,
|
||||||
count: songData.count
|
count: songData.count
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => b.count - a.count) // Sort by count descending
|
.sort((a, b) => b.count - a.count)
|
||||||
.slice(0, 100); // Take only top 100
|
.slice(0, 100);
|
||||||
|
|
||||||
// Convert back to object format for Firebase
|
// Write as an array so Firebase uses numeric keys
|
||||||
const topPlayedData: { [key: string]: TopPlayed } = {};
|
await controllerRef.child('topPlayed').set(sortedSongs);
|
||||||
|
|
||||||
sortedSongs.forEach((song) => {
|
console.log(`Successfully updated TopPlayed for controller ${controllerName} with ${sortedSongs.length} unique songs (by path)`);
|
||||||
topPlayedData[song.key] = {
|
|
||||||
artist: song.artist,
|
|
||||||
title: song.title,
|
|
||||||
count: song.count
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update the topPlayed collection
|
|
||||||
await controllerRef.child('topPlayed').set(topPlayedData);
|
|
||||||
|
|
||||||
console.log(`Successfully updated TopPlayed for controller ${controllerName} with ${Object.keys(topPlayedData).length} unique songs`);
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating TopPlayed:', error);
|
console.error('Error updating TopPlayed:', error);
|
||||||
@ -122,7 +99,7 @@ export const updateTopPlayedOnHistoryChange = functions.database
|
|||||||
* Alternative function that can be called manually to recalculate TopPlayed
|
* Alternative function that can be called manually to recalculate TopPlayed
|
||||||
* This is useful for initial setup or data migration
|
* This is useful for initial setup or data migration
|
||||||
*/
|
*/
|
||||||
export const recalculateTopPlayed = functions.https.onCall(async (data, context) => {
|
export const recalculateTopPlayed = functions.https.onCall(async (data) => {
|
||||||
const { controllerName } = data;
|
const { controllerName } = data;
|
||||||
|
|
||||||
if (!controllerName) {
|
if (!controllerName) {
|
||||||
@ -145,26 +122,20 @@ export const recalculateTopPlayed = functions.https.onCall(async (data, context)
|
|||||||
return { success: true, message: 'No history data found, TopPlayed cleared' };
|
return { success: true, message: 'No history data found, TopPlayed cleared' };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate history items by artist + title combination
|
// Aggregate history items by path
|
||||||
const aggregation: HistoryAggregation = {};
|
const aggregation: HistoryAggregationByPath = {};
|
||||||
|
|
||||||
Object.values(historyData).forEach((song: unknown) => {
|
Object.values(historyData).forEach((song: unknown) => {
|
||||||
const historySong = song as HistorySong;
|
const historySong = song as HistorySong;
|
||||||
if (historySong && historySong.artist && historySong.title) {
|
if (historySong && historySong.path) {
|
||||||
// Create a unique key based on artist and title (case-insensitive)
|
const path = historySong.path;
|
||||||
// Replace invalid Firebase key characters with underscores
|
if (aggregation[path]) {
|
||||||
const sanitizedArtist = String(historySong.artist || '').toLowerCase().trim().replace(/[.#$/[\]]/g, '_');
|
aggregation[path].count += historySong.count || 1;
|
||||||
const sanitizedTitle = String(historySong.title || '').toLowerCase().trim().replace(/[.#$/[\]]/g, '_');
|
|
||||||
const key = `${sanitizedArtist}_${sanitizedTitle}`;
|
|
||||||
|
|
||||||
if (aggregation[key]) {
|
|
||||||
// Increment count for existing song
|
|
||||||
aggregation[key].count += historySong.count || 1;
|
|
||||||
} else {
|
} else {
|
||||||
// Create new entry
|
aggregation[path] = {
|
||||||
aggregation[key] = {
|
|
||||||
artist: historySong.artist,
|
artist: historySong.artist,
|
||||||
title: historySong.title,
|
title: historySong.title,
|
||||||
|
path: historySong.path,
|
||||||
count: historySong.count || 1
|
count: historySong.count || 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -173,35 +144,24 @@ export const recalculateTopPlayed = functions.https.onCall(async (data, context)
|
|||||||
|
|
||||||
// Convert aggregation to array, sort by count (descending), and take top 100
|
// Convert aggregation to array, sort by count (descending), and take top 100
|
||||||
const sortedSongs = Object.entries(aggregation)
|
const sortedSongs = Object.entries(aggregation)
|
||||||
.map(([key, songData]) => ({
|
.map(([, songData]) => ({
|
||||||
key,
|
|
||||||
artist: songData.artist,
|
artist: songData.artist,
|
||||||
title: songData.title,
|
title: songData.title,
|
||||||
|
path: songData.path,
|
||||||
count: songData.count
|
count: songData.count
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => b.count - a.count) // Sort by count descending
|
.sort((a, b) => b.count - a.count)
|
||||||
.slice(0, 100); // Take only top 100
|
.slice(0, 100);
|
||||||
|
|
||||||
// Convert back to object format for Firebase
|
// Write as an array so Firebase uses numeric keys
|
||||||
const topPlayedData: { [key: string]: TopPlayed } = {};
|
await controllerRef.child('topPlayed').set(sortedSongs);
|
||||||
|
|
||||||
sortedSongs.forEach((song) => {
|
console.log(`Successfully recalculated TopPlayed for controller ${controllerName} with ${sortedSongs.length} unique songs (by path)`);
|
||||||
topPlayedData[song.key] = {
|
|
||||||
artist: song.artist,
|
|
||||||
title: song.title,
|
|
||||||
count: song.count
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update the topPlayed collection
|
|
||||||
await controllerRef.child('topPlayed').set(topPlayedData);
|
|
||||||
|
|
||||||
console.log(`Successfully recalculated TopPlayed for controller ${controllerName} with ${Object.keys(topPlayedData).length} unique songs`);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: `TopPlayed recalculated successfully`,
|
message: `TopPlayed recalculated successfully`,
|
||||||
songCount: Object.keys(topPlayedData).length
|
songCount: sortedSongs.length
|
||||||
};
|
};
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user