feat: interaktif panel kontrolleri (Faz 3)
Yayın durdurma, kanal duraklat/devam (tekli+toplu), şimdi kontrol et, manuel URL ile zorla kayıt başlatma, canlı player+log önizleme, oturum süre sayacı, başarısız/takılı render için tekrar dene ve iptal, poll aralığı + ham segment TTL'yi panelden canlı değiştirme, cookie bayatlık uyarısı, Telegram bildirim aç/kapa, ve kullanım/maliyet özeti (/stats). api-daemon'ın yeni state-değiştiren endpoint'leri (stop/force-start/ render/cancel) INTERNAL_API_TOKEN ile korunuyor — bu daemon'ın portu Coolify'de public'e açık olduğu için korumasız bırakmak güvenlik açığı olurdu. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import { unlink } from "node:fs/promises";
|
||||
import { prisma } from "@streamclipper/db";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { redirect } from "next/navigation";
|
||||
import { postToApiDaemon } from "../lib/apiDaemon";
|
||||
|
||||
export async function addChannel(formData: FormData) {
|
||||
const name = String(formData.get("name") ?? "").trim();
|
||||
@@ -59,6 +60,85 @@ export async function deleteChannel(channelId: string) {
|
||||
redirect("/");
|
||||
}
|
||||
|
||||
export async function toggleChannelActive(channelId: string, nextActive: boolean) {
|
||||
await prisma.channel.update({ where: { id: channelId }, data: { isActive: nextActive } });
|
||||
revalidatePath("/", "layout");
|
||||
}
|
||||
|
||||
export async function toggleAllChannels(nextActive: boolean) {
|
||||
await prisma.channel.updateMany({ data: { isActive: nextActive } });
|
||||
revalidatePath("/", "layout");
|
||||
}
|
||||
|
||||
export async function stopSession(sessionId: string) {
|
||||
await postToApiDaemon(`/sessions/${sessionId}/stop`);
|
||||
revalidatePath("/", "layout");
|
||||
}
|
||||
|
||||
export async function checkChannelNow(channelId: string) {
|
||||
await postToApiDaemon(`/channels/${channelId}/check-now`);
|
||||
revalidatePath("/", "layout");
|
||||
}
|
||||
|
||||
export async function forceStartCapture(channelId: string, formData: FormData) {
|
||||
const url = String(formData.get("url") ?? "").trim();
|
||||
if (!url) throw new Error("YouTube URL zorunlu.");
|
||||
await postToApiDaemon(`/channels/${channelId}/force-start`, { url });
|
||||
revalidatePath("/", "layout");
|
||||
}
|
||||
|
||||
export async function retryRender(candidateId: string) {
|
||||
await postToApiDaemon(`/shorts/${candidateId}/render`);
|
||||
revalidatePath("/segments");
|
||||
revalidatePath("/", "layout");
|
||||
}
|
||||
|
||||
export async function cancelRender(candidateId: string) {
|
||||
await postToApiDaemon(`/shorts/${candidateId}/cancel`);
|
||||
revalidatePath("/segments");
|
||||
revalidatePath("/", "layout");
|
||||
}
|
||||
|
||||
export async function updateSystemSettings(formData: FormData) {
|
||||
const pollSeconds = Number(formData.get("pollIntervalSec"));
|
||||
const ttlHours = Number(formData.get("ttlHours"));
|
||||
|
||||
if (Number.isFinite(pollSeconds) && pollSeconds >= 5) {
|
||||
await prisma.appSetting.upsert({
|
||||
where: { key: "poll_interval_ms" },
|
||||
create: { key: "poll_interval_ms", value: String(pollSeconds * 1000) },
|
||||
update: { value: String(pollSeconds * 1000) },
|
||||
});
|
||||
}
|
||||
if (Number.isFinite(ttlHours) && ttlHours > 0) {
|
||||
await prisma.appSetting.upsert({
|
||||
where: { key: "raw_segment_ttl_hours" },
|
||||
create: { key: "raw_segment_ttl_hours", value: String(ttlHours) },
|
||||
update: { value: String(ttlHours) },
|
||||
});
|
||||
}
|
||||
|
||||
revalidatePath("/settings");
|
||||
}
|
||||
|
||||
export async function updateNotificationPrefs(formData: FormData) {
|
||||
const streamStart = formData.get("notifyStreamStart") === "on";
|
||||
const renderDone = formData.get("notifyRenderDone") === "on";
|
||||
|
||||
await prisma.appSetting.upsert({
|
||||
where: { key: "notify_stream_start" },
|
||||
create: { key: "notify_stream_start", value: String(streamStart) },
|
||||
update: { value: String(streamStart) },
|
||||
});
|
||||
await prisma.appSetting.upsert({
|
||||
where: { key: "notify_render_done" },
|
||||
create: { key: "notify_render_done", value: String(renderDone) },
|
||||
update: { value: String(renderDone) },
|
||||
});
|
||||
|
||||
revalidatePath("/settings");
|
||||
}
|
||||
|
||||
export async function updateYtdlpCookies(formData: FormData) {
|
||||
const value = String(formData.get("cookies") ?? "").trim();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user