feat: segment süresi varsayılanını 15 dk -> 5 dk düşür + dashboard'u kart-grid'e çevir
Global SEGMENT_TIME_SEC varsayılanı 900->300 (docker-compose, .env.example, env.ts, signal_detection.py fallback'i) — kanal bazlı override zaten panelden ayarlanabiliyordu, bu sadece varsayılanı değiştiriyor. Dashboard'daki kanal listesi tablo yerine kart-grid: her kanal kendi kartında, durum rozetleri üstte belirgin, aksiyonlar altta — önceki tablo düzeni (özellikle aksiyon sütunundaki sıkışık butonlar) okunması zor bulunuyordu. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ export const env = {
|
||||
redisUrl: process.env.REDIS_URL ?? "redis://localhost:6379",
|
||||
sharedMediaRoot: process.env.SHARED_MEDIA_ROOT ?? "./shared-media",
|
||||
pollIntervalMs: Number(process.env.POLL_INTERVAL_MS ?? 60_000),
|
||||
segmentTimeSec: Number(process.env.SEGMENT_TIME_SEC ?? 900),
|
||||
segmentTimeSec: Number(process.env.SEGMENT_TIME_SEC ?? 300),
|
||||
port: Number(process.env.API_DAEMON_PORT ?? 4001),
|
||||
forceLiveUrl: process.env.FORCE_LIVE_URL ?? "",
|
||||
ytdlpPotProviderUrl: process.env.YTDLP_POT_PROVIDER_URL ?? "",
|
||||
|
||||
+64
-69
@@ -6,8 +6,8 @@ import { formatTr } from "../lib/formatDate";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from "@/components/ui/card";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -47,9 +47,9 @@ export default async function DashboardPage() {
|
||||
{channels.length === 0 ? (
|
||||
<p className="text-sm text-muted-foreground">Henüz kanal eklenmedi.</p>
|
||||
) : (
|
||||
<Card>
|
||||
<CardHeader className="flex-row items-center justify-between">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">{channels.length} kanal</CardTitle>
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm font-medium text-muted-foreground">{channels.length} kanal</span>
|
||||
<div className="flex gap-2">
|
||||
<form action={toggleAllChannels.bind(null, true)}>
|
||||
<Button type="submit" variant="outline" size="sm">
|
||||
@@ -62,70 +62,65 @@ export default async function DashboardPage() {
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Kanal</TableHead>
|
||||
<TableHead>Durum</TableHead>
|
||||
<TableHead>Kayıt</TableHead>
|
||||
<TableHead>Son Kontrol</TableHead>
|
||||
<TableHead className="text-right">Aksiyon</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{channels.map((c) => {
|
||||
const recording = c.sessions.length > 0;
|
||||
const status = statuses.get(c.id);
|
||||
return (
|
||||
<TableRow key={c.id}>
|
||||
<TableCell>
|
||||
<Link href={`/channels/${c.id}`} className="font-medium hover:text-primary hover:underline">
|
||||
{c.name}
|
||||
</Link>{" "}
|
||||
<span className="font-mono-num text-xs text-muted-foreground">{c.youtubeHandle}</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant={c.isActive ? "ok" : "muted"}>{c.isActive ? "Aktif" : "Pasif"}</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Badge variant={recording ? "live" : "muted"}>{recording ? "🔴 Kayıtta" : "—"}</Badge>
|
||||
{status?.lastPollError && (
|
||||
<Badge
|
||||
variant="err"
|
||||
title={`${formatTr(status.lastPollError.at)} — ${status.lastPollError.message}`}
|
||||
>
|
||||
hata
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="font-mono-num text-xs text-muted-foreground">
|
||||
{c.lastCheckedAt ? formatTr(c.lastCheckedAt) : "—"}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex justify-end gap-1.5">
|
||||
<form action={toggleChannelActive.bind(null, c.id, !c.isActive)}>
|
||||
<Button type="submit" variant="outline" size="sm">
|
||||
{c.isActive ? "Duraklat" : "Devam Ettir"}
|
||||
</Button>
|
||||
</form>
|
||||
<form action={checkChannelNow.bind(null, c.id)}>
|
||||
<Button type="submit" variant="ghost" size="sm">
|
||||
Şimdi Kontrol Et
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{channels.map((c) => {
|
||||
const recording = c.sessions.length > 0;
|
||||
const status = statuses.get(c.id);
|
||||
return (
|
||||
<Card
|
||||
key={c.id}
|
||||
className={cn("gap-4 py-5", recording && "border-live/40")}
|
||||
>
|
||||
<CardHeader className="gap-1 px-5">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<Link href={`/channels/${c.id}`} className="font-semibold leading-tight hover:text-primary hover:underline">
|
||||
{c.name}
|
||||
</Link>
|
||||
<Badge variant={c.isActive ? "ok" : "muted"} className="shrink-0">
|
||||
{c.isActive ? "Aktif" : "Pasif"}
|
||||
</Badge>
|
||||
</div>
|
||||
<span className="font-mono-num text-xs text-muted-foreground">{c.youtubeHandle}</span>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="flex flex-col gap-2 px-5">
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
<Badge variant={recording ? "live" : "muted"}>
|
||||
{recording ? "🔴 Kayıtta" : "Kayıtta değil"}
|
||||
</Badge>
|
||||
{status?.lastPollError && (
|
||||
<Badge
|
||||
variant="err"
|
||||
title={`${formatTr(status.lastPollError.at)} — ${status.lastPollError.message}`}
|
||||
>
|
||||
hata
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<span className="font-mono-num text-xs text-muted-foreground">
|
||||
Son kontrol: {c.lastCheckedAt ? formatTr(c.lastCheckedAt) : "—"}
|
||||
</span>
|
||||
</CardContent>
|
||||
|
||||
<CardFooter className="gap-2 px-5">
|
||||
<form action={toggleChannelActive.bind(null, c.id, !c.isActive)}>
|
||||
<Button type="submit" variant="outline" size="sm">
|
||||
{c.isActive ? "Duraklat" : "Devam Ettir"}
|
||||
</Button>
|
||||
</form>
|
||||
<form action={checkChannelNow.bind(null, c.id)}>
|
||||
<Button type="submit" variant="ghost" size="sm">
|
||||
Şimdi Kontrol Et
|
||||
</Button>
|
||||
</form>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -17,7 +17,7 @@ WINDOW_SEC = 1.0
|
||||
PEAK_STD_MULTIPLIER = 1.5
|
||||
CANDIDATE_PAD_SEC = 45
|
||||
CHAT_SPIKE_MULTIPLIER = 3
|
||||
SEGMENT_TIME_SEC = int(os.environ.get("SEGMENT_TIME_SEC", "900"))
|
||||
SEGMENT_TIME_SEC = int(os.environ.get("SEGMENT_TIME_SEC", "300"))
|
||||
|
||||
stt_scoring_queue = Queue(QUEUE_NAMES["STT_SCORING"], {"connection": REDIS_URL})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user