Files
songs2vid/lib/plans.ts
T
Songs2YTandCursor d951ecb489 Sync layouts, typography, and watermark studio for self-hosted OSS.
Unlock features without credits/Stripe, point docs to docs.songs2vid.com, and drop leftover billing admin surfaces.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-25 03:50:06 +02:00

81 lines
2.9 KiB
TypeScript

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;
customWatermark: boolean;
perItemImages: boolean;
artTrackLayouts: boolean;
allowedAudioExtensions: readonly string[];
id3TagSupport: boolean;
};
/** Unlimited self-hosted limits — used for every plan in this OSS build. */
export const SELFHOSTED_LIMITS: PlanLimits = {
monthlyQuota: 1_000_000,
maxBatchSize: 1_000,
maxResolutionHeight: Math.max(...RESOLUTIONS.map((r) => r.height)),
maxFileSizeBytes: 500 * 1024 * 1024,
watermarkOptional: true,
customWatermark: true,
perItemImages: true,
artTrackLayouts: true,
allowedAudioExtensions: [".mp3", ".wav", ".flac"],
id3TagSupport: true,
};
/** Kept for type compatibility; OSS always returns SELFHOSTED_LIMITS. */
export const PLAN_LIMITS: Record<Plan, PlanLimits> = {
FREE: { ...SELFHOSTED_LIMITS },
PREMIUM: { ...SELFHOSTED_LIMITS },
};
export const SALES_EMAIL = "songs2vid@atakanozban.com";
export const SUPPORT_EMAIL = "songs2vid@atakanozban.com";
export const QUOTA_REQUEST_EMAIL = "songs2vid@atakanozban.com";
export const UPGRADE_URL = "https://songs2vid.com";
export const WEBSITE_URL = "https://songs2vid.com";
export const GITEA_ISSUES_URL =
process.env.NEXT_PUBLIC_GITEA_ISSUES_URL ??
"https://git.atakanozban.com/Songs2VID/songs2vid/issues";
export const GITEA_URL =
process.env.NEXT_PUBLIC_GITEA_URL ?? "https://git.atakanozban.com/Songs2VID/songs2vid";
export const DOCKER_HUB_URL =
process.env.NEXT_PUBLIC_DOCKER_HUB_URL ?? "https://hub.docker.com/r/atakanozban/songs2vid";
/** Public docs (Docusaurus). Override with NEXT_PUBLIC_DOCS_URL if needed. */
export const DOCS_URL = (
process.env.NEXT_PUBLIC_DOCS_URL?.trim() || "https://docs.songs2vid.com"
).replace(/\/$/, "");
export const API_DOCS_URL = `${DOCS_URL}/docs/api/overview`;
export function getPlanLimits(_plan?: Plan): PlanLimits {
void isSelfHostedEdition();
return SELFHOSTED_LIMITS;
}
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);
}