import { Plan } from "@prisma/client"; import { getResolution, RESOLUTIONS } from "./constants"; import { isSelfHostedEdition } from "./edition"; export type PlanLimits = { monthlyQuota: number; maxBatchSize: number; maxResolutionHeight: number; maxFileSizeBytes: number; watermarkOptional: boolean; allowedAudioExtensions: readonly string[]; id3TagSupport: boolean; }; export const PLAN_LIMITS: Record = { FREE: { monthlyQuota: 14, maxBatchSize: 3, maxResolutionHeight: 720, maxFileSizeBytes: 30 * 1024 * 1024, watermarkOptional: true, allowedAudioExtensions: [".mp3"], id3TagSupport: true, }, PREMIUM: { monthlyQuota: 50, maxBatchSize: 5, maxResolutionHeight: 1080, maxFileSizeBytes: 30 * 1024 * 1024, watermarkOptional: true, allowedAudioExtensions: [".mp3", ".wav", ".flac"], id3TagSupport: true, }, }; export const SELFHOSTED_LIMITS: PlanLimits = { monthlyQuota: 1_000_000, maxBatchSize: 100, maxResolutionHeight: Math.max(...RESOLUTIONS.map((r) => r.height)), maxFileSizeBytes: 500 * 1024 * 1024, watermarkOptional: true, allowedAudioExtensions: [".mp3", ".wav", ".flac"], id3TagSupport: true, }; export const SALES_EMAIL = "songs2yt@atakanozban.com"; export const SUPPORT_EMAIL = "songs2yt@atakanozban.com"; export const UPGRADE_URL = "/#pricing"; export const GITEA_ISSUES_URL = process.env.NEXT_PUBLIC_GITEA_ISSUES_URL ?? "https://git.atakanozban.com/Songs2YT/issues"; export const GITEA_URL = process.env.NEXT_PUBLIC_GITEA_URL ?? "https://git.atakanozban.com/Songs2YT"; export const DOCKER_HUB_URL = process.env.NEXT_PUBLIC_DOCKER_HUB_URL ?? "https://hub.docker.com/r/atakanozban/songs2yt"; export function getPlanLimits(plan: Plan): PlanLimits { if (isSelfHostedEdition()) return SELFHOSTED_LIMITS; return PLAN_LIMITS[plan]; } export function getResolutionsForPlan(plan: Plan) { const maxHeight = getPlanLimits(plan).maxResolutionHeight; return RESOLUTIONS.filter((r) => r.height <= maxHeight); } export function isResolutionAllowedForPlan(resolution: string, plan: Plan): boolean { const res = getResolution(resolution); if (!res) return false; return res.height <= getPlanLimits(plan).maxResolutionHeight; } export function isAudioExtensionAllowed(filename: string, plan: Plan): boolean { const ext = filename.slice(filename.lastIndexOf(".")).toLowerCase(); return getPlanLimits(plan).allowedAudioExtensions.includes(ext); } export function getNextMonthlyQuotaReset(from: Date = new Date()): Date { return new Date(from.getFullYear(), from.getMonth() + 1, 1, 0, 0, 0, 0); }