Files
musicland/functions/src/project.js
T
2026-07-20 15:23:16 +02:00

115 lines
3.7 KiB
JavaScript

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 {
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 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
}
})