cms.c2sgmbh/src/lib/youtube/analytics-helpers.ts
Martin Porwoll 9e7b433cd0 feat(youtube): add comparison, trends, ROI analytics
Add analytics helper functions (calculateComparison, calculateTrends,
calculateROI) and extend the analytics API route with three new tabs
for video metric comparison, trend analysis, and ROI calculation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:37:51 +00:00

123 lines
2.7 KiB
TypeScript

/**
* YouTube Analytics Helper Functions
*
* Provides calculation utilities for video comparison, trend analysis,
* and ROI metrics used by the analytics API route.
*/
interface VideoWithPerformance {
id: number
title: string
performance: {
views?: number
likes?: number
comments?: number
ctr?: number
watchTimeMinutes?: number
impressions?: number
subscribersGained?: number
avgViewPercentage?: number
}
costs?: {
estimatedProductionCost?: number
estimatedProductionHours?: number
estimatedRevenue?: number
}
}
type Metric =
| 'views'
| 'likes'
| 'comments'
| 'ctr'
| 'watchTimeMinutes'
| 'impressions'
| 'subscribersGained'
function getMetricValue(video: VideoWithPerformance, metric: Metric): number {
return video.performance?.[metric] ?? 0
}
function calculateComparison(
videos: VideoWithPerformance[],
metric: Metric,
): Array<{ videoId: number; title: string; value: number }> {
return videos.map((v) => ({
videoId: v.id,
title: v.title,
value: getMetricValue(v, metric),
}))
}
function calculateTrends(
videos: VideoWithPerformance[],
metric: Metric,
): {
trend: string
growth: number
average?: number
latest?: number
min?: number
max?: number
} {
if (videos.length < 2) {
return { trend: 'insufficient_data', growth: 0 }
}
const values = videos
.map((v) => getMetricValue(v, metric))
.sort((a, b) => a - b)
const avg = values.reduce((sum, v) => sum + v, 0) / values.length
const latest = values[values.length - 1]
const min = values[0]
const max = values[values.length - 1]
let trend: string
if (latest > avg) {
trend = 'up'
} else if (latest < avg) {
trend = 'down'
} else {
trend = 'stable'
}
const growth = avg > 0 ? ((latest - avg) / avg) * 100 : 0
return { trend, average: avg, latest, growth, min, max }
}
function calculateROI(
videos: VideoWithPerformance[],
): Array<{
videoId: number
title: string
cost: number
revenue: number
roi: number
cpv: number
revenuePerView: number
views: number
}> {
return videos
.filter((v) => v.costs?.estimatedProductionCost && v.costs.estimatedProductionCost > 0)
.map((v) => {
const cost = v.costs!.estimatedProductionCost!
const revenue = v.costs?.estimatedRevenue ?? 0
const views = v.performance?.views ?? 0
return {
videoId: v.id,
title: v.title,
cost,
revenue,
roi: cost > 0 ? ((revenue - cost) / cost) * 100 : 0,
cpv: views > 0 ? cost / views : 0,
revenuePerView: views > 0 ? revenue / views : 0,
views,
}
})
}
export { calculateComparison, calculateTrends, calculateROI }
export type { VideoWithPerformance, Metric }