尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Piattaforma SaaS proprietaria per la generazione automatica di YouTube Shorts da video lunghi: upload → trascrizione → analisi AI → clip 9:16 con editing automatico e sottotitoli sincronizzati → download. Fase 1 (MVP): upload → transcript → AI clip detection → selezione clip → verticalizzazione 9:16 → captions → editing automatico di base → render → preview → download → pubblicazione su YouTube. Non implementati in questa fase: pagamenti, mobile app, team, scheduling social, multi-lingua avanzato, AI B-roll, avatar AI.檢視完整 README ↗
Piattaforma SaaS proprietaria per la generazione automatica di YouTube Shorts da video lunghi: upload → trascrizione → analisi AI → clip 9:16 con editing automatico e sottotitoli sincronizzati → download.
Fase 1 (MVP): upload → transcript → AI clip detection → selezione clip → verticalizzazione 9:16 → captions → editing automatico di base → render → preview → download → pubblicazione su YouTube. Non implementati in questa fase: pagamenti, mobile app, team, scheduling social, multi-lingua avanzato, AI B-roll, avatar AI.
apps/
web/ Next.js 14 (App Router) — dashboard, auth, upload, API route "leggere". Deploy: Vercel.
worker/ Node.js — pipeline di elaborazione video (ffmpeg, Whisper, Claude). Deploy: container separato
(Railway/Fly.io/VPS/qualsiasi host che esegua Docker o Node) — MAI su Vercel.
packages/
shared/ Tipi e zod schema condivisi (Transcript, Clip, EDL, Template, Job status).
db/ Schema SQL Supabase/Postgres + client tipizzato.
Il frontend e le API route leggere (creazione progetto, signed URL, creazione render job) girano su Vercel. Il worker interroga la coda (tabella Postgres, claim atomico via SELECT ... FOR UPDATE SKIP LOCKED esposto come funzione RPC) e fa tutto il lavoro pesante: estrazione audio, trascrizione, analisi AI, rendering ffmpeg. Frontend e worker comunicano solo attraverso il database e lo storage — nessuna chiamata diretta tra i due, quindi il worker scala e si sostituisce in autonomia.
Interfacce pensate per essere sostituite (Fase 1 usa l'implementazione più semplice/economica, dietro un contratto chiaro):
TranscriptionProvider → OpenAIWhisperProvider (Whisper API, default) oppure LocalFasterWhisperProvider (faster-whisper self-hosted sulla GPU locale, gratis, stessi timestamp a livello di parola — vedi apps/worker/whisper-server/README.md), selezionabile via TRANSCRIPTION_PROVIDER=openai|local.StorageProvider → R2StorageProvider (Cloudflare R2, compatibile S3). Un'implementazione SupabaseStorageProvider alternativa esiste ancora nel codice ma non è usata di default: il piano Free di Supabase Storage limita ogni file a 50MB, troppo poco per video sorgente.FaceTracker → ReactionCamFaceTracker: rilevamento volto reale (ONNX, Ultra-Light-Fast-Generic-Face-Detector, ~1.2MB, onnxruntime-node — binari precompilati, nessuna compilazione nativa richiesta) su alcuni frame campionati della clip. Se trova un volto piccolo e stabile vicino a un bordo (webcam in sovraimpressione su gameplay/reaction) produce un layout split-screen (webcam sopra, contenuto sotto); se trova un volto "normale" centra il crop su di esso; altrimenti ricade su CenterCropFaceTracker (crop centrato statico). Modello in apps/worker/models/.RenderEngine.youtube scope, serve anche a videos.update per l'annullamento programmazione) + coda dedicata (youtube_publish_jobs, stesso pattern di render_jobs). Il worker carica il file su YouTube via googleapis — mai da Vercel. Titolo/descrizione/hashtag sono precompilati dall'AI (generati nello stesso passaggio di ranking, nessuna chiamata extra) e modificabili prima di pubblicare.clips.format = 'longform'): a differenza degli Shorts, niente crop 9:16/zoom/sottotitoli — un secondo passaggio AI (longform-candidates.ts/longform-ranking.ts) individua segmenti coerenti per ARGOMENTO (5-20 min) invece di finestre hook-payoff, e il render (render-longform-clip.ts) è solo trim + card testuale dei crediti allo streamer originale in apertura/chiusura, output orizzontale nella risoluzione nativa. L'ingestion riusa download-youtube.ts as-is (yt-dlp supporta i VOD Twitch nativamente). I VOD arrivano dalla tab Feed seguendo canali Twitch (followed_twitch_channels, nessun OAuth richiesto — vedi sezione 3b).corepack enable && corepack prepare pnpm@latest --activate)ffmpeg -version deve funzionare)yt-dlp --version deve funzionare) — usato per l'import da link YouTubepackages/db/migrations/0001_init.sqlpackages/db/migrations/0002_queue_functions.sqlpackages/db/migrations/0003_add_downloading_status.sqlpackages/db/migrations/0004_youtube_publishing.sqlpackages/db/migrations/0005_clip_caption.sqlpackages/db/migrations/0006_youtube_scheduled_publish.sqlpackages/db/migrations/0007_followed_channels.sqlpackages/db/migrations/0008_clip_badges.sqlpackages/db/migrations/0009_youtube_stats.sqlpackages/db/migrations/0010_project_auto_generate.sqlpackages/db/migrations/0011_cancel_jobs.sqlpackages/db/migrations/0012_voiceover_jobs.sqlpackages/db/migrations/0013_youtube_publish_cancel.sqlpackages/db/migrations/0014_longform_twitch.sqlpackages/db/migrations/0015_video_claim_stale_timeout.sqlpackages/db/migrations/0016_video_streamer_login.sqlpackages/db/migrations/0017_thumbnail_jobs.sqlpackages/db/migrations/0018_thumbnail_reacted_video_url.sqlpackages/db/migrations/0019_worker_control.sqlURL e anon public key (servono al frontend). Vai su Project Settings → API → Service role e copia anche quella (serve solo al worker).clipforge-media) → Location: Automatic.dash.cloudflare.com/<ACCOUNT_ID>/r2).[
{
"AllowedOrigins": ["http://localhost:3000", "https://il-tuo-dominio.vercel.app"],
"AllowedMethods": ["PUT", "GET"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3600
}
]
(senza questo, l'upload diretto dal browser viene bloccato dal CORS — l'import da YouTube non ne ha bisogno, passa tutto dal worker)http://localhost:3000/api/youtube/callback
https://il-tuo-dominio.vercel.app/api/youtube/callback
Nota sulla quota: da giugno 2026 videos.insert ha un bucket dedicato separato dal resto della quota, 100 upload/giorno gratis (1 unità a chiamata in quel bucket) — molto più permissivo del vecchio limite (~6/giorno, quando l'upload costava 1.600 delle 10.000 unità condivise).
A differenza di YouTube, Twitch non richiede un flusso OAuth per-utente per leggere canali/VOD pubblici: basta un'app registrata una volta.
http://localhost (non viene mai usato, Twitch lo richiede comunque per registrare l'app), Category: Application Integration.Nessun URI di redirect reale, nessuna schermata di consenso, nessun "utente di test": le chiamate (risoluzione canale, lista VOD) usano un app access token server-to-server richiesto al volo dal backend web (apps/web/src/lib/twitch-scan.ts).
pnpm --filter esegue ogni app nella propria cartella, quindi servono due file separati (non uno alla radice) — .env.example alla radice resta solo come riferimento con la lista completa delle variabili:
cp .env.example apps/worker/.env
cp .env.example apps/web/.env.local
Compila entrambi con i valori di Supabase/R2/Anthropic/OpenAI (apps/web/.env.local non ha bisogno delle variabili solo-worker come ANTHROPIC_API_KEY/OPENAI_API_KEY/SUPABASE_SERVICE_ROLE_KEY, ma lasciarle non fa danno). Non committare mai questi file (sono già in .gitignore).
pnpm install
Servono due processi separati (frontend e worker), in due terminali:
pnpm dev:web # http://localhost:3000
pnpm dev:worker # poll continuo della coda su Supabase
http://localhost:3000, registrati (/signup), conferma l'email se richiesto da Supabase.pnpm -r typecheck # type-check di tutti i package
pnpm --filter @clipforge/web build # build di produzione del frontend
pnpm --filter @clipforge/worker build # bundle di produzione del worker (esbuild → dist/index.js)
pnpm --filter @clipforge/worker exec tsx src/dev/smoke-test-render.ts <path-video>
# smoke test della sola pipeline di render (crop/zoom/captions/loudness), senza bisogno
# di credenziali Supabase/Anthropic/OpenAI — utile per verificare rapidamente ffmpeg.
apps/web): Vercel, root directory apps/web. Variabili d'ambiente da impostare nel progetto Vercel: NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET (solo se vuoi la pubblicazione YouTube), TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET (solo se vuoi i video long-form dai VOD Twitch). Ricorda di aggiungere il dominio Vercel definitivo sia alla CORS policy del bucket R2 sia agli URI di reindirizzamento autorizzati del client OAuth Google (vedi sopra).apps/worker): qualsiasi host capace di eseguire un processo Node long-running (Railway, Fly.io, un VPS con Docker/systemd, ecc.) — non Vercel, che non è pensato per processi persistenti né per rendering video pesante. Build: pnpm --filter @clipforge/worker build, avvio: pnpm --filter @clipforge/worker start (richiede ffmpeg e yt-dlp installati nell'immagine/host; apps/worker/models/ e node_modules devono essere presenti accanto a dist/ — onnxruntime-node ha un addon nativo per piattaforma che esbuild lascia esterno, vedi commento in scripts/build.mjs)..ttf nell'immagine del worker e puntarli esplicitamente.loudnorm a singolo passaggio (non i due passaggi raccomandati per la massima precisione) — scelta per semplicità/velocità.videos.insert ha un bucket dedicato da 100 upload/giorno (aggiornato da giugno 2026, prima erano ~6/giorno).yt-dlp, quindi eredita i suoi limiti — video privati, con restrizione età o soggetti a protezioni anti-bot possono fallire il download; nessun supporto per playlist (viene scaricato solo il video singolo).