const admin = require('firebase-admin') const { FieldValue } = require('firebase-admin/firestore') const { onDocumentWritten } = require('firebase-functions/firestore') const _ = require('lodash') const { refList, db } = require('../index') const { SUNO_API_KEY } = require('../config/secrets') const { getSunoTimestamps } = require('./lyrics') const { deleteFolder } = require('../helpers/firebase') const { buildMonthKey } = require('../helpers/stats') const PROJECT_FUNCTION_OPTIONS = { document: 'projects/{projectId}', secrets: [SUNO_API_KEY], } exports.onProjectWritten = onDocumentWritten(PROJECT_FUNCTION_OPTIONS, 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 { const selectedSongChanged = !!afterData?.songUrl && (beforeData?.songUrl !== afterData.songUrl || beforeData?.sunoAudioId !== afterData?.sunoAudioId) if (selectedSongChanged) { 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 projectsRef = refList.projects.doc(projectId) 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: FieldValue.increment(delta), } const hasFirstStream = statsSnapshot.exists && statsSnapshot.data()?.firstStreamAt if (!hasFirstStream) { updatePayload.firstStreamAt = now } transaction.set(statsDocRef, updatePayload, { merge: true }) transaction.set(projectsRef, { monthViews: FieldValue.increment(delta) }, { merge: true }) const totalsUpdatePayload = { monthKey, updatedAt: now, lastStreamAt: now, lastDelta: delta, totalStreams: 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 } })