Files
musicland/functions/src/project.js
T
Thomas Demirdjian 7b3a47090d functions
2025-11-03 13:47:07 +01:00

115 lines
3.7 KiB
JavaScript

const admin = require("firebase-admin");
const { onDocumentWritten } = require("firebase-functions/firestore");
const _ = require("lodash");
const { refList, db } = require("../index");
const { getSunoTimestamps } = require("./lyrics");
const { deleteFolder } = require("../helpers/firebase");
const { buildMonthKey } = require("../helpers/stats");
exports.onProjectWritten = onDocumentWritten(
"projects/{projectId}",
async (projectSnap) => {
try {
const { projectId } = projectSnap.params;
const beforeData = projectSnap?.data?.before?.data() || null;
const afterData = projectSnap?.data?.after?.data() || null;
if (!afterData) {
const { userId } = beforeData || {};
if (userId) {
await deleteFolder(`users/${userId}/projects/${projectId}/`);
}
const snapshot = await refList.tasks
.where("projectId", "==", projectId)
.get();
if (!snapshot.empty) {
const batch = db.batch();
snapshot.forEach((doc) => {
batch.delete(doc.ref);
});
await batch.commit();
}
return null;
} else if (!beforeData) {
//song create
} else {
if (!beforeData?.songUrl && afterData?.songUrl) {
await getSunoTimestamps(projectId);
await refList.projects.doc(projectId).update({ hasSong: true });
}
if (!beforeData?.playbackUrl && afterData?.playbackUrl) {
await refList.projects.doc(projectId).update({ hasPlayback: true });
}
}
const beforeViews = _.toFinite(_.get(beforeData, "views", 0));
const afterViews = _.toFinite(_.get(afterData, "views", 0));
const delta = afterViews - beforeViews;
if (delta > 0) {
const userIdRaw = _.get(afterData, "userId", null);
const userId =
_.isString(userIdRaw) && _.trim(userIdRaw).length
? _.trim(userIdRaw)
: null;
const now = admin.firestore.Timestamp.now();
const monthKey = buildMonthKey(now);
const statsDocRef = refList.projectStreamStats
.doc(projectId)
.collection("monthlyListens")
.doc(monthKey);
const totalsDocRef =
refList.projectStreamStatsMonthlyTotals.doc(monthKey);
await db.runTransaction(async (transaction) => {
const statsSnapshot = await transaction.get(statsDocRef);
const totalsSnapshot = await transaction.get(totalsDocRef);
const updatePayload = {
projectId,
userId,
monthKey,
updatedAt: now,
lastStreamAt: now,
lastDelta: delta,
streams: admin.firestore.FieldValue.increment(delta),
};
const hasFirstStream =
statsSnapshot.exists && statsSnapshot.data()?.firstStreamAt;
if (!hasFirstStream) {
updatePayload.firstStreamAt = now;
}
transaction.set(statsDocRef, updatePayload, { merge: true });
const totalsUpdatePayload = {
monthKey,
updatedAt: now,
lastStreamAt: now,
lastDelta: delta,
totalStreams: admin.firestore.FieldValue.increment(delta),
};
const totalsHasFirstStream =
totalsSnapshot.exists && totalsSnapshot.data()?.firstStreamAt;
if (!totalsHasFirstStream) {
totalsUpdatePayload.firstStreamAt = now;
}
transaction.set(totalsDocRef, totalsUpdatePayload, { merge: true });
});
}
return null;
} catch (error) {
console.log("onProjectViewsIncrement error", {
message: error?.message || String(error || ""),
});
return null;
}
},
);