import 'package:isar/isar.dart'; import 'package:path/path.dart' as p; import '../cekirdek/ffmpeg_servisi.dart'; import '../veri/isar_servisi.dart'; import '../veri/modeller/sahne.dart'; /// Film/Dizi bölümünün üretilmiş sahnelerini tek videoya birleştirir. /// Direktör montaj motorunu (FfmpegServisi.klipBirlestirGecisli) köprüler — /// üretilen sahneler artık dağınık mp4 olarak kalmaz, bölüm çıktısına dönüşür. abstract final class FilmMontajServisi { /// Bölümün [SahneDurumu.hazir] sahnelerini [Sahne.sira]'ya göre birleştirir. /// Çıktı dosya yolunu döner; hazır sahne yoksa null. static Future bolumuBirlestir({ required int bolumId, required String ciktiKlasoru, String gecis = 'fade', void Function(double oran)? ilerle, }) async { final videolar = await _hazirVideolar(bolumId); if (videolar.isEmpty) return null; final hedef = p.join(ciktiKlasoru, 'bolum_${bolumId}_montaj.mp4'); if (videolar.length == 1) { return FfmpegServisi.klipBirlestir( videoYollari: videolar, hedefYol: hedef); } final gecisler = List.filled(videolar.length - 1, gecis); return FfmpegServisi.klipBirlestirGecisli( videoYollari: videolar, gecisler: gecisler, hedefYol: hedef, ilerle: ilerle, ); } /// Birleştirmeye dahil olacak (hazır + dosyası var) sahne sayısı. static Future birlestirilebilirSayi(int bolumId) async => (await _hazirVideolar(bolumId)).length; static Future> _hazirVideolar(int bolumId) async { final sahneler = await isar.sahnes .filter() .bolumIdEqualTo(bolumId) .durumEqualTo(SahneDurumu.hazir) .sortBySira() .findAll(); return [ for (final s in sahneler) if (s.uretilenVideoYolu.isNotEmpty) s.uretilenVideoYolu, ]; } }