Video Altyazıları (Bunny Stream)
Uçtan uca altyazı sistemi — veritabanı, Bunny Stream API, eğitmen yükleme/silme, öğrenci oynatıcıda gösterim.
Achidemy’de ders videolarına altyazı (.vtt) ekleme, Bunny.net Stream API ile senkron çalışır. Eğitmen altyazı yükler; sistem hem Bunny’e hem veritabanına kaydeder. Öğrenci tarafında video oynatıcıda altyazılar otomatik listelenir ve varsayılan dil iframe parametresi ile açılabilir.
Genel Akış
Section titled “Genel Akış”- Eğitmen: Müfredat veya “Altyazılar” sayfasından ders seçer → dil seçer → .vtt dosyası yükler →
POST /api/lesson/caption-upload. - Backend: Dersin
bunnyVideoId’si ile Bunny Stream “Add Caption” API’ye istek atar; başarılıysalesson_captionstablosuna kayıt ekler. - Öğrenci:
learn/:slugsayfasında video yüklenirken loader ders altyazılarını çeker; iframe URL’ine?captions=tr(veya seçilen dil) eklenir. Bunny oynatıcı CC menüsünde altyazıları gösterir. - Silme: Eğitmen altyazı silerse
POST /api/lesson/caption-delete→ önce Bunny’den silinir, sonra veritabanından.
Veritabanı: lesson_captions
Section titled “Veritabanı: lesson_captions”Dosya: app/db/schema.ts
| Sütun | Tip | Açıklama |
|---|---|---|
id | uuid | PK, default random. |
lesson_id | uuid | FK → lessons.id, on delete cascade. |
language_code | text | Dil kodu (örn. tr, en, de). |
label | text | Görünen etiket (örn. Türkçe, English). |
bunny_url | text | Opsiyonel; Bunny tarafındaki dosya yolu. |
created_at | timestamp | Kayıt zamanı. |
Altyazı listesi öğrenci sayfasında loader’da lesson_captions tablosundan ders bazlı çekilir; iframe’e varsayılan dil parametresi verilir.
Kurs Seviyesi: Desteklenen Altyazı Dilleri (subtitle_languages)
Section titled “Kurs Seviyesi: Desteklenen Altyazı Dilleri (subtitle_languages)”Kurs başlığı altında “Bu kursta hangi dillerde altyazı var?” bilgisi kurs bazlı saklanır ve gösterilir.
Veritabanı: courses.subtitle_languages (text[]). Eğitmen landing veya kurs yönetiminde desteklenen altyazı dillerini seçer (örn. tr, en, de); bu kodlar dizi olarak kaydedilir.
Kurs sayfası (course.$id): Hero bölümünde ilk birkaç dil adı (Türkçe, English, Deutsch vb.) ve ”+ N daha” metni gösterilir. ”+ N daha” veya “(Tümünü gör)” tıklanınca bir modal açılır; tüm desteklenen diller “[Otomatik]” etiketiyle listelenir. Dil adları app/routes/course.$id.tsx içindeki langNames eşlemesiyle (tr → Türkçe, en → English, de → Deutsch, vb.) gösterilir.
Eğitmen tarafı: Landing sayfasında veya kurs yönetiminde altyazı dilleri çoklu seçim ile güncellenir; GraphQL updateCourse(subtitleLanguages) veya ilgili form ile courses.subtitle_languages yazılır.
Bu özellik, ders bazlı .vtt altyazılarından (lesson_captions) bağımsızdır: ders altyazıları hangi dillerde yüklü, kurs meta verisi ise “bu kurs şu dillerde altyazı sunuyor” listesidir.
Bunny Stream API Katmanı
Section titled “Bunny Stream API Katmanı”Dosya: app/lib/bunny.ts
- Ortam değişkenleri:
BUNNY_LIBRARY_ID,BUNNY_STREAM_API_KEY(veyaBUNNY_API_KEY— kodda fallback). Cloudflare Workers’ta API key güvenli şekilde env üzerinden okunur. - uploadCaptionToBunny(videoId, langCode, label, fileBuffer, env):
POST https://video.bunnycdn.com/library/{libraryId}/videos/{videoId}/captions/{srclang}
Body:{ srclang, label, captionsFile }—captionsFilebase64 ile gönderilir. Workers’taBufferyok; base64 Web API (btoa+Uint8Array) ile üretilir. - getBunnyCaptions(videoId, env): Video detayından
captionsdizisini döndürür. - deleteBunnyCaption(videoId, langCode, env):
DELETE .../videos/{videoId}/captions/{langCode}.
Bunny dokümantasyonu: Add Caption — path captions (çoğul), body alanı captionsFile.
Bunny CDN geliştirmeleri ve daha fazla bilgi için: Bunny.net Dokümantasyonu
API Endpoint’leri
Section titled “API Endpoint’leri”| Endpoint | Method | Dosya | Açıklama |
|---|---|---|---|
| POST /api/lesson/caption-upload | POST | api.lesson.caption-upload.ts | Altyazı .vtt yükleme. FormData: lessonId, captionFile, langCode, label. Bunny’e gönderir; başarılıysa lesson_captions’a insert. |
| POST /api/lesson/caption-delete | POST | api.lesson.caption-delete.ts | Altyazı silme. FormData: captionId. Önce Bunny’den siler, sonra DB’den. |
Her iki endpoint de 500 hatalarında JSON döner ({ "error": "..." }); React fetcher’ın HTML hata sayfası alması engellenir.
Eğitmen Arayüzü
Section titled “Eğitmen Arayüzü”- Müfredat sayfası:
app/routes/instructor.course.$slug.manage.curriculum.tsx
Videolu her ders için “Altyazılar” butonu (CaptionManager). Tıklanınca modal açılır; dil seçimi + .vtt dosyası + “Bunny.net’e Gönder” ilecaption-uploadçağrılır. - Altyazılar sayfası:
app/routes/instructor.course.$slug.manage.captions.tsx
URL:/:lang/instructor/course/:slug/manage/captions. Bölüm/ders listesi; videolu derslerde mevcut altyazılar listelenir, “Altyazı Ekle” ve satır bazlı “Sil” (caption-delete) kullanılır. - Route:
routes.tsiçindecourse/:slug/managealtındacaptions→instructor.course.$slug.manage.captions.tsx.
Öğrenci Tarafı: learn.$slug.tsx
Section titled “Öğrenci Tarafı: learn.$slug.tsx”- Loader: Müfredat çekilirken her ders için
lesson_captionstablosundanid,languageCode,labelalınır; dersecaptionsdizisi eklenir. - Video URL: Varsayılan altyazı dili (önce
tr, yoksa ilk dil) seçilir; iframe URL’ine?captions=tr(veya ilgili kod) eklenir. Bunny embed bu parametre ile varsayılan altyazıyı açar. - Erişilebilirlik: Altyazı varsa ekranda görünmeyen (sr-only) metin ile “Altyazılar: Türkçe, English” benzeri bilgi verilir.
Ortam Değişkenleri
Section titled “Ortam Değişkenleri”| Değişken | Açıklama |
|---|---|
BUNNY_LIBRARY_ID | Bunny Stream kütüphane ID’si (altyazı endpoint path’inde kullanılır). |
BUNNY_API_KEY veya BUNNY_STREAM_API_KEY | Bunny Stream API anahtarı. .dev.vars / .env içinde BUNNY_API_KEY kullanılıyorsa kod bunu otomatik okur. |
Yerelde .dev.vars (Wrangler) veya .env (process.env) ile birleştirilerek okunur; Cloudflare Workers’ta context.cloudflare.env önceliklidir.
İlgili Dosyalar
Section titled “İlgili Dosyalar”| Dosya | Görev |
|---|---|
app/db/schema.ts | lessonCaptions tablosu. |
app/lib/bunny.ts | uploadCaptionToBunny, getBunnyCaptions, deleteBunnyCaption; Workers uyumlu base64. |
app/routes/api.lesson.caption-upload.ts | Altyazı yükleme action; env birleştirme, try/catch, JSON 500. |
app/routes/api.lesson.caption-delete.ts | Altyazı silme action. |
app/routes/learn.$slug.tsx | Loader’da captions, videoUrl’de captions param, sr-only altyazı listesi. |
app/routes/instructor.course.$slug.manage.curriculum.tsx | CaptionManager bileşeni, “Altyazılar” butonu. |
app/routes/instructor.course.$slug.manage.captions.tsx | Altyazılar yönetim sayfası (liste, ekle, sil). |
app/routes.ts | api/lesson/caption-upload, api/lesson/caption-delete, manage/captions route’ları. |
- Veritabanı:
lesson_captions— ders bazlı dil kodu ve etiket; Bunny’e dosya yolu opsiyonel. - Bunny: Stream “Add Caption” / “Delete Caption” API’leri; path
captions(çoğul), bodycaptionsFile(base64). - API: caption-upload (yükleme + DB insert), caption-delete (Bunny + DB delete); her zaman JSON yanıt.
- Eğitmen: Müfredat’ta “Altyazılar” butonu + modal; ayrı “Altyazılar” sayfası (captions) ile liste/ekle/sil.
- Öğrenci: Learn sayfasında loader ile altyazılar yüklenir; iframe’e
?captions=ile varsayılan dil verilir; Bunny oynatıcı CC menüsünde altyazıları gösterir.