Yeni "Ham Kayıt Modu" ayarı (send_raw_segments_to_telegram, varsayılan
kapalı): açıksa her ham segment tamamlanır tamamlanmaz sinyal analizi/
STT/9:16 render zincirine hiç girmeden doğrudan Telegram'a gönderiliyor
ve sunucudan siliniyor. Kullanıcı transkript/9:16 istemediğinde ("sen
bana direk videoyu gönder") tüm analiz pipeline'ını atlayıp sadece
kayıt+gönder+sil yapan basit bir mod.
- RawSegmentStatus'a SENT_TO_TELEGRAM eklendi, RawSegment.filePath
nullable yapıldı (aynı ShortVideo.filePath deseni — gönderim sonrası
null, dosya diskten silinmiş demek).
- api-daemon/src/telegram.ts'e sendTelegramVideo eklendi (native fetch+
FormData+Blob ile multipart upload, ~50MB bot-limiti önceden kontrol
ediliyor) — worker/telegram.py'deki aynı fonksiyonun Node karşılığı.
- streamIngest.ts: segment tamamlanınca, mod açıksa signal-detection
kuyruğuna hiç eklemeden doğrudan gönderiyor (kuyruğa eklemek, aşağıda
dosyayı silmenin sinyal analizini bozmasına sebep olurdu).
- Panel: segment listelerinde filePath=null durumunda video/indir yerine
"Telegram'a gönderildi" notu (segments, channels/[id]).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Proxy IP'lerini havuza dağıttığımız aynı sorun cookie/hesap seviyesinde de
vardı: tek bir Google hesabı 7-8 kanalı taramaya çalışınca YouTube hesabın
kendisini şüpheli bulup çoğu/tüm kanalda "Sign in to confirm you're not a
bot" veriyordu — proxy IP'den bağımsız bir sinyal, IP dağıtımı bunu
çözemez.
Yeni CookieProfile tablosu: her kanal, DB id'sinden aynı deterministik hash
ile (proxyUrlForChannel'daki gibi) havuzdaki hesaplardan birine sabitlenir.
Her profil kendi ayrı geçici dosyasına yazılıyor (/tmp/yt-cookies-<id>.txt)
— tek paylaşılan dosya, farklı profil kullanan kanallar eşzamanlı
çalışınca birbirinin cookie'sini ezerdi. Hiç profil eklenmemişse eski tekli
ytdlp_cookies ayarına geri düşüyor (geriye dönük uyumlu, hemen kırılmaz).
Ayarlar sayfasında yeni "Cookie Hesapları" kartı: hesap ekle/sil/yenile,
her biri için ayrı bayatlık rozeti. Eski tekli cookie kartı "tekli/eski"
etiketiyle fallback olarak duruyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- auto_render_enabled (varsayılan açık): kapatılınca transkript sonrası
otomatik render tetiklenmez, aday TRANSCRIBED'de bekler — panelin zaten
var olan "9:16 Render Et" butonuyla elle tetiklenebilir.
- delete_after_telegram_send (varsayılan KAPALI — geri alınamaz bir
davranış, bilinçli açılmalı): açıksa render biten video Telegram'a
gerçek dosya olarak gönderilir (yeni send_telegram_video, sendVideo
multipart upload, ~50MB bot-upload limiti önceden kontrol ediliyor);
gönderim başarılıysa dosya diskten silinip ShortVideo.file_path NULL'a
çekiliyor (DB kaydı/transkript kalıcı kalıyor), başarısızsa dosya
sunucuda kalıp düz metin bildirimi gidiyor. Kanal sayısı arttıkça VPS
disk doluluğunu önlemek için.
- Panel: READY + file_path=null durumunda video/indir yerine "Telegram'a
gönderildi, sunucuda saklanmıyor" notu (channels/[id], segments).
Şema değişikliği yok — ShortVideo.filePath zaten nullable.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dockerfile'ın CMD'si next dev kullanıyordu — Coolify'de canlı sistemde
dev-mode overlay/bildirimleri (Next.js sürüm uyarısı, hata detayları) ve
optimize edilmemiş, JIT-compile edilen bir build çalışıyordu. Artık image
build sırasında next build çalışıyor, CMD sadece next start.
DATABASE_URL build adımında gerçek bir DB'ye ihtiyaç duymuyor (tüm
sayfalar force-dynamic, build sırasında sorgu atılmıyor) ama Prisma
client import'ta connection string formatını doğruluyor — yer tutucu bir
değer verildi, Coolify'nin gerçek DATABASE_URL'i runtime'da onun üzerine
yazıyor zaten.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
3 seviyeli border-left girinti (oturum > segment > aday klip) yerine
gerçek kutu (soft-card) blokları — her segment kendi arka planıyla
ayrışıyor, adaylar onun içinde daha da net bir alt kutuda. Segment
başlığı artık ham dosya yolu değil ("15sn segment · 02.09.2026 20:14"
gibi) insan-okur bir etiket — dosya yolu küçük/soluk referans olarak
altta kaldı. "Canlı Durum" kartındaki karışık bölümler de (hata/canlı
önizleme/log/segment ayarı/manuel başlat) Separator ile ayrıştırıldı.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
UI yenilemesinde segments/page.tsx'teki "aday klip bulunamadı" boş-durum
mesajı kanal detay sayfasına taşınmamıştı — sinyal analizi bir segmentte
ilginç an bulamayınca panelde sessizce hiçbir şey görünmüyordu, bozukmuş
gibi duruyordu.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Poll hatası şu ana kadar sadece panele girip bakınca görülüyordu — proaktif
haberdar olma yolu yoktu. Şimdi bir kanal hata vermeye BAŞLADIĞINDA (her
60sn'de tekrar değil, sadece durum değişince) ve düzeldiğinde Telegram
bildirimi gidiyor. Ayarlar'dan kapatılabilir (notify_poll_error).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
.toLocaleString("tr-TR") tarih formatını Türkçe yapıyor ama saat değerini
hâlâ sunucunun sistem saat dilimiyle (Coolify/Hetzner container'ı UTC)
hesaplıyordu. Tüm tarih gösterimleri artık ortak formatTr() helper'ı
üzerinden timeZone: "Europe/Istanbul" ile sabitleniyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Channel.segmentTimeSec (nullable, null = global SEGMENT_TIME_SEC env
var'ı kullan) eklendi. Kanal detay sayfasından dakika cinsinden
girilebiliyor, StreamIngestJob'a taşınıp streamIngest.ts'te ffmpeg'in
-segment_time argümanına yansıyor. Sadece o kanal için bundan sonra
başlayacak yeni kayıt oturumlarını etkiler — halihazırda çalışan bir
ffmpeg process'inin segment süresi zaten sabitlenmiş durumda.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Radix Switch'in kendi gizli-input form entegrasyonu bu ortamda Server
Action'ın FormData'sına güvenilir şekilde ulaşmıyordu — switch'i "off"
yapıp Kaydet'e basınca eski değer kalıcı oluyordu (STT hep otomatik
çalışmaya devam ediyordu). Artık her switch kendi değerini doğrudan
kontrol eden bir hidden input'la (SettingSwitch) submit ediliyor,
Radix'in iç mekanizmasına bağımlı değil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- lastPollErrors artık {message, at} tutuyor — panelde hangi hatanın ne
zaman oluştuğu görünmüyordu, eski/güncel ayrımı yapılamıyordu.
- "This live event will begin in N minutes" gibi zararsız mesajlar da
hata rozetine düşüyordu, "is not currently live" ile aynı gruba alındı.
- Yeni stt_enabled ayarı (Ayarlar sayfası): kapatılınca stt_scoring.py
OpenAI Whisper çağrısı yapmadan adayı PENDING_STT'de bırakıp çıkıyor —
konuşmasız/ambiyans yayınlarda (bkz. NASA testi) boşa API maliyeti
önleniyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Elle yazılmış tek-dosya CSS (sabit koyu tema, ham table/button, window.confirm
ile silme onayı) yerine tutarlı bir bileşen sistemi: Card/Table/Badge/Button/
Input/Switch/AlertDialog primitifleri, Hanken Grotesk + JetBrains Mono
tipografi çifti, "broadcast/monitör" temalı özel bir renk paleti (camgöbeği
accent, ok/warn/err/live durum rengi sözlüğü). Tüm sayfalar (dashboard, kanal
detay, segmentler, ayarlar, istatistik, kullanıcılar, login) aynı oturumda
taşındı — silme onayları artık gerçek AlertDialog, native confirm() değil.
Veri akışı/server action'lar değişmedi, tamamen görsel katman.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Faz 2'de ShortVideo eklenirken deleteRawSegment/deleteCandidateSegment/
deleteChannel güncellenmemiş — candidate_id FK'sı yüzünden bir short'u
olan candidate silinmeye çalışılınca Postgres reddediyordu. Şimdi her
üç yol da candidate'leri silmeden önce ilişkili ShortVideo satırlarını
(+ render edilmiş dosyalarını) temizliyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
Her aday klip transkribe olduktan hemen sonra otomatik olarak
video-render kuyruğuna giriyor. Yeni Python worker (video_render.py):
- Klibi ffmpeg ile keser
- OpenCV + MediaPipe Face Detector (Tasks API — yeni mediapipe
sürümlerinde eski solutions API'si kalktı, .tflite model dosyası
Docker build'de indiriliyor) ile örneklenmiş karelerde yüz merkezi
tespit eder, yumuşatır (moving average); hiç yüz bulunamazsa sabit
merkez crop'a düşer, hata saymaz
- Kırpılmış kareleri OpenCV'den ffmpeg'e pipe'layıp tek geçişte orijinal
sesi map'ler ve transcript_json'dan ürettiği .ass altyazıyı yakar
- Sonucu /shared-media/shorts/<candidate_id>.mp4'e yazar
Yeni ShortVideo modeli (PENDING/RENDERING/READY/FAILED). Panelde
(segments + kanal detay sayfaları) render durumu + READY olunca video
önizleme/indirme. VIDEO_RENDER_CONCURRENCY ayrı ve düşük (varsayılan 2)
— bu iş diğerlerinden çok daha ağır.
Kapsam: sadece tekil konuşmacı şablonu (çoklu konuşmacı/split-screen
sonraki bir iterasyona bırakıldı — aktif-konuşmacı tespiti gerektiriyor).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
/users: kullanıcı listesi, ekleme formu, silme (kendi hesabını veya
son kalan tek kullanıcıyı silmeye izin verilmiyor). Nav'a link eklendi.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
NODE_ENV=production'da cookie hep secure:true oluyordu, ama panel
şu an SSL'siz sslip.io preview domain'inde (http://) çalışıyor —
tarayıcı Secure cookie'yi HTTP origin'de hiç saklamıyor. Giriş
"başarılı" gibi görünüp anında /login'e geri dönülüyordu. Artık
gerçek istek protokolüne (Traefik'in x-forwarded-proto header'ı)
bakılıyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Panel şu ana kadar herkese açıktı — URL'yi bilen herkes kanal
ekleyip/silebilir, cookie güncelleyebilir, kayıt indirebilirdi.
- users tablosu (bcrypt şifre hash'i)
- /login: hiç kullanıcı yoksa "ilk admin hesabı oluştur" formu, varsa
normal giriş formu
- jose ile imzalanmış, httpOnly çerezde tutulan 30 günlük oturum
- middleware.ts: /login hariç tüm rotaları korur (video stream route'u
dahil — aynı origin istekleri çerezi otomatik taşır)
- layout: oturum yoksa nav hiç gösterilmiyor, varsa kullanıcı adı +
çıkış butonu ekleniyor
SESSION_SECRET production'da zorunlu (docker-compose derleme zamanında
kontrol ediyor); Coolify'a rastgele bir değer eklendi.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Kanal detay sayfasına "Kanalı Sil" eklendi — kanal + tüm session/
segment/candidate geçmişini (dosyalar dahil) siler, ana sayfaya
yönlendirir. Yanlışlıkla/test amaçlı eklenen kanalları temizlemek için.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cookie'ler saatler içinde eskiyordu, her seferinde manuel Coolify env
güncellemesi + redeploy gerekiyordu. Artık DB'de (app_settings tablosu)
tutuluyor; /settings sayfasından yeni cookies.txt yapıştırılıp
kaydedilebiliyor, bir sonraki yt-dlp çağrısında redeploy gerekmeden
devreye giriyor. YTDLP_COOKIES_B64 env var mekanizması kaldırıldı.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- streamIngest worker concurrency 3'ten sabit değildi, artık
MAX_CONCURRENT_CAPTURES (varsayılan 10) ile ayarlanabiliyor. Eskiden
3'ten fazla kanal aynı anda canlıya geçerse fazlası, ilk 3'ten biri
bitene kadar (saatlerce) hiç kayda alınmıyordu.
- Python worker'larda (signal-detection, stt-scoring) bullmq varsayılan
concurrency'si 1'di — WORKER_CONCURRENCY (varsayılan 5) ile
paralelleştirildi, birden fazla kanal aynı anda segment/transkript
üretirse sıraya takılmasın diye.
- Frontend artık shared-media volume'üne bağlı: /api/segments/[id]/video
route'u Range destekli video stream/indirme sağlıyor. Segment ve
kanal detay sayfalarına <video> oynatıcı, indirme linki ve onaylı
silme (RawSegment + CandidateSegment, dosya dahil) eklendi.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
/channels/[id] rotası eklendi: dashboard'daki kanal adı artık oraya
link veriyor. Sayfa api-daemon'un /status'undan canlı durum ve son
poll hatasını (lastPollError, DB'de değil sadece bellekte tutuluyordu)
çekiyor, Prisma'dan da o kanala ait tüm StreamSession/RawSegment/
CandidateSegment geçmişini transkript önizlemesiyle listeliyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dashboard'a name/youtubeHandle/channelId alanlarıyla bir server action
formu eklendi. Polling ve /status için channel_id gerçek bir YouTube
UC... kimliği olmalı.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
yt-dlp headless capture (15dk segmentleme), ses peak + chat velocity sinyal
tespiti, OpenAI Whisper STT (kelime zaman damgalı), BullMQ/Redis/Postgres
altyapısı ve kanal durumu + transkript kütüphanesi gösteren Next.js panel.
LLM virality skorlama, render/crop/altyazı ve multi-platform dağıtım bu
fazın kapsamı dışında.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>