Files
fastwatcher/docs/implementation-plan.md
2026-04-29 21:34:39 +03:00

8.3 KiB
Raw Permalink Blame History

1. Temel Teknoloji Yığını ve Kütüphaneler

Kategori Kütüphane / Teknoloji Neden Bu Tercih Edilmeli?
State Management flutter_riverpod SOLID'in Dependency Inversion (D) prensibini uygulamak ve servisleri izole etmek için en modern ve güvenli yöntem.
Cihaz Keşfi (mDNS) nsd veya bonsoir Zero-config ağ keşfi için endüstri standardı. TV kendini yayınlar, telefon bulur.
Ağ İletişimi shelf (Local HTTP Server) TV tarafında raw TCP socket yerine küçük bir REST API (HTTP Server) kurmak hata yönetimini ve loglamayı inanılmaz kolaylaştırır.
Video Oynatıcı media_kit Chewie/Video_player yerine kesinlikle bunu kullanmalısın. libmpv tabanlıdır. HLS (.m3u8), MKV ve özel codec'leri Android TV'de kusursuz oynatır.
Link Yakalama receive_sharing_intent Mobil cihazda tarayıcıdan "Paylaş" aksiyonunu dinlemek için.
Video Extraction flutter_inappwebview & html Sayfa içindeki gizli .m3u8 veya .mp4 linklerini headless (gizli) bir tarayıcıda yakalamak için.
Lokal Depolama shared_preferences Cihazın "TV" mi yoksa "Mobil" mi olduğunu ilk seçimden sonra hatırlamak için.

2. Proje Klasör Yapısı (Clean Architecture)

Kodun test edilebilir ve modüler olması için Feature-First (Özellik Odaklı) bir Clean Architecture yapısı kurmalıyız:

lib/
├── core/                   # Tüm projede ortak kullanılan yapılar
│   ├── constants/          # Port numaraları, API endpoint'leri
│   ├── error/              # Custom exception sınıfları
│   └── network/            # Temel ağ arayüzleri
├── features/
│   ├── setup/              # Cihaz rolü (TV/Telefon) seçim ekranı
│   ├── discovery/          # mDNS ile cihaz arama ve eşleşme (Mobil)
│   ├── receiver/           # TV tarafı: Local server ve oynatıcı
│   └── sender/             # Mobil taraf: Link yakalama ve gönderme
└── main.dart               # Riverpod ProviderScope ve Init işlemleri

Her feature (özellik) kendi içinde şu üç katmana ayrılmalıdır (SOLID uygulamasının kalbi):

  • domain: Sadece saf Dart kodları. Arayüzler (abstract class), entity'ler.
  • data: Dış dünyayla iletişim. API çağrıları, paket implementasyonları.
  • presentation: UI (Widget'lar) ve State (Riverpod Notifier'lar).

3. Kritik İş Akışları ve "Best Practice" Yöntemler

A. İlk Açılış ve Rol Seçimi (Setup)

Kullanıcı uygulamayı ilk açtığında karşısına iki dev buton çıkar: "Ben bir Telefonum (Gönderici)" ve "Ben bir TV'yim (Alıcı)".

  • Best Practice: Bu seçim yapıldığı an SharedPreferences'a kaydedilir (role = 'sender' | 'receiver'). Uygulamanın bir sonraki açılışında main.dart bu değeri okur ve kullanıcıyı doğrudan ilgili ana ekrana yönlendirir.

B. Cihaz Eşleştirme (Discovery - mDNS)

Bluetooth yerine aynı ağda mDNS (Zero-conf) kullanmak en stabil "Best Practice" yöntemdir.

  1. TV (Receiver): Uygulama açılır açılmaz arka planda nsd ile bir servis kaydeder. Örnek servis adı: FastWatcher._http._tcp. Ayrıca shelf ile 8080 portunda bir HTTP server dinlemeye başlar (POST /play).
  2. Mobil (Sender): "Eşleş" butonuna basıldığında ağı tarar. Bulunan cihazların IP'sini bir listeye koyar. Kullanıcı TV'sine dokunduğunda IP adresi telefona kaydedilir.

C. İletişim Protokolü (HTTP üzerinden)

Raw Socket'ler veriyi bölebilir veya bağlantı kopmalarında sorun yaratabilir. TV'de mini bir HTTP sunucusu kurmak çok daha "Solid" bir çözümdür.

  • Mobil'in Gönderdiği Payload (JSON):
    {
      "url": "https://site.com/master.m3u8",
      "title": "The Instigators (Opsiyonel)",
      "timestamp": 1714415045
    }
    
  • TV'nin Yanıtı: 200 OK (Başarıyla aldım, oynatmaya başlıyorum).

D. Video Linki Ayrıştırma (Video Extraction)

Tarayıcıdan paylaşılan link bir web sayfası olduğunda, içindeki asıl videoyu bulmak için şu hiyerarşi uygulanır:

  1. Headless WebView (En Garanti Yöntem): Kullanıcı linki paylaştığında, arka planda gizli bir InAppWebView açılır. onLoadResource veya shouldInterceptRequest metodları ile ağ trafiği dinlenir. .m3u8 veya .mp4 uzantılı bir istek yakalandığı an sayfa kapatılır ve link TV'ye gönderilir.
  2. Open Graph & Meta Tags: Sayfa HTML'i html paketi ile indirilir. <meta property="og:video" content="..."> veya <video src="..."> etiketleri taranır.
  3. Site Özelinde Çözücüler (Scrapers): YouTube için youtube_explode_dart, Twitter/X için özel Regex paternleri gibi "Provider" tabanlı sınıflar kullanılır.
  • SOLID Notu: Bu işlemi bir LinkParser interface'inden türetilen HeadlessParser, RegexParser ve MetaParser gibi sınıflara bölmeliyiz.

4. SOLID Prensiplerinin Projeye Uygulanması

Bu projeyi "Solid" yapacak mimari kararlar şunlardır:

  • S (Tek Sorumluluk): DiscoveryService sadece ağı tarar. UI'a karışmaz. Ekrana yazdırma işini DiscoveryNotifier (State) ve DiscoveryScreen yapar.
  • O (Açık/Kapalı): İletişim katmanını bir abstract class NetworkClient olarak tanımla. Şu an Wi-Fi (HTTP) kullanıyoruz. Yarın Bluetooth eklemek istersen, mevcut kodu bozmadan yeni bir BluetoothClient implementasyonu ekleyebilirsin.
  • L (Liskov Yerine Geçme): Eğer TV tarafında birden fazla oynatıcı motoru kullanma ihtimalin varsa (örn: MediaKitPlayer ve yedek olarak ExoPlayer), ikisi de bir abstract class AppVideoPlayer arayüzünden türemelidir.
  • I (Arayüz Ayrımı): Sender ve Receiver çok farklı işler yapar. Her iki rol için devasa tek bir arayüz yazmak yerine, ILinkSender ve ILinkReceiver olarak küçük arayüzlere böl.
  • D (Bağımlılıkların Tersine Çevrilmesi): UI sınıfların (Widget'lar) asla doğrudan nsd veya shelf paketini bilmemelidir. Araya yazdığın soyut Repository sınıflarını (Riverpod üzerinden) UI'a enjekte etmelisin.

5. Tasarım ve Arayüz (UI Mockups)

Uygulamanın premium ve modern hissettirmesi için tasarlanan ekranlar şunlardır:

Ekran İsmi Açıklama Görsel
Setup (Rol Seçimi) Kullanıcının Telefon veya TV modunu seçtiği ilk açılış ekranı. Setup Screen
Mobil Gönderici Cihaz arama, link yapıştırma ve geçmişin yönetildiği ana mobil ekran. Mobile Sender
TV Alıcı (Home) TV'nin bağlantı beklediği, minimalist ve estetik bekleme ekranı. TV Home
Video Oynatıcı Kumanda kontrollerine duyarlı, yüksek kaliteli video oynatıcı arayüzü. TV Player

6. Geliştirme Adımları (Faz Planı)

Faz 1: Çekirdek ve İletişim (UI Olmadan)

  1. Proje yapısını ve Riverpod kurulumunu tamamla.
  2. TV tarafı için shelf ile basit bir HTTP server yaz ve Postman ile test et.
  3. TV tarafında nsd servisini başlat.
  4. Mobil tarafta ağı tarayıp TV'nin IP'sini bulan kodu yaz.

Faz 2: Gönderim ve Oynatma

  1. Mobil cihazdan HTTP POST ile TV'ye manuel bir test linki (.m3u8) gönder.
  2. TV tarafında media_kit paketini kur ve gelen linki tam ekranda (kumanda odaklamalarına dikkat ederek) oynatan sayfayı tasarla.

Faz 3: Entegrasyon ve Link Extraction

  1. Mobil tarafa receive_sharing_intent paketini kur ve Android Manifest ayarlarını yap.
  2. LinkExtractionService oluştur:
    • Gelen URL eğer doğrudan video ise (.mp4, .m3u8, .mkv) direkt TV'ye gönder.
    • Eğer bir web sayfası ise, InAppWebView (headless) ile sayfayı yükleyip ağ trafiğini dinleyerek gerçek video linkini "crawle" et.
  3. Yakalanan linki ve sayfa başlığını (Title) eşleşmiş olan TV'ye fırlat.
  4. Hatalı/Desteklenmeyen linkler için kullanıcıya "Video bulunamadı" uyarısı göster.

Bu mimariyle yazdığın bir kod hem çok hızlı çalışacak hem de aylar sonra dönüp baktığında nerede ne olduğunu saniyeler içinde bulabileceksin.

İlk olarak projeyi ayağa kaldırdıktan sonra, shelf ile TV tarafındaki o mini HTTP sunucusunun arayüzünü (Interface) tasarlayarak başlamak ister misin? Sana o kısmın Dependency Inversion'a uygun örnek kodunu yazabilirim.