Basit Anlatım — Herkes İçin
Muzibu'nun müzik çaları şu an tek bir dev JavaScript dosyası (8.310 satır) üzerinden çalışıyor. Bu dosya hem şarkı çalma, hem sıra yönetimi, hem HLS şifreleme, hem kalite ayarı, hem de hata kurtarma işlemlerinin hepsini yapıyor.
Sorun Ne?
- Eski telefonlar: 1.5 MB JavaScript'i yükleyip çalıştırmak eski cihazların belleğini ve işlemcisini zorluyor → donma
- Kötü internet: Şarkı çalmak için 5-8 HTTP isteği gerekiyor, biri bile gecikse → takılma
- Bellek (RAM): Normal çalma ~50MB, preload ile ~120-150MB → eski cihazlarda taşma
Çözüm Önerileri
- API-Driven: Ağır işlemleri sunucu tarafında yapıp, tarayıcıya sadece "şunu çal" demek
- Soft Mode: Eski/zayıf cihazlar için hafif bir versiyon (debug paneli yok, otomatik test yok, düşük kalite)
- HLS/MP3 Geçişi: Admin panelinden kişi bazlı "bu kullanıcıya MP3 ver" seçeneği
Mevcut Mimari — Büyük Resim
┌─────────────────────────────────────────────────────────────────────────┐
│ TARAYICI (Client-Side) │
│ │
│ ┌──────────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ player-core.js │ │ play-helpers.js │ │ performance- │ │
│ │ 8.310 satır │ │ 1.017 satır │ │ debug.js │ │
│ │ 384 KB │ │ 37 KB │ │ 3.505 satır │ │
│ │ │ │ │ │ 180 KB │ │
│ │ • HLS.js yönetimi │ │ • playAlbum() │ │ • Freeze analizi │ │
│ │ • Howler.js fallback │ │ • playPlaylist() │ │ • Memory izleme │ │
│ │ • Queue yönetimi │ │ • playGenre() │ │ • Jank detection │ │
│ │ • Preload sistemi │ │ • playRadio() │ │ • Root cause │ │
│ │ • Buffer health │ │ • playSector() │ │ │ │
│ │ • ABR startup lock │ │ │ │ │ │
│ │ • Crossfade (OFF) │ │ │ │ │ │
│ └──────────┬───────────┘ └────────┬──────────┘ └─────────┬────────┘ │
│ │ │ │ │
│ ┌──────────┴───────────────────────┴────────────────────────┴────────┐ │
│ │ Alpine.js Store ('muzibu') │ │
│ │ currentSong, queue, isPlaying, volume, progress, ... │ │
│ └──────────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────────┐ │
│ │ spot-player │ │ spa-router │ │ speed-tester │ │ buffer-monitor │ │
│ │ 564 satır │ │ 687 satır │ │ 395 satır │ │ 295 satır │ │
│ │ Reklam │ │ SPA nav │ │ Hız testi │ │ Buffer izleme │ │
│ └──────┬──────┘ └──────┬───────┘ └──────┬───────┘ └──────┬─────────┘ │
│ │ │ │ │ │
│ ┌──────┴───────────────┴────────────────┴─────────────────┴─────────┐ │
│ │ HLS.js (100KB) + Howler.js (50KB) + libs │ │
│ └───────────────────────────────┬───────────────────────────────────┘ │
└──────────────────────────────────┼──────────────────────────────────────┘
│ HTTP/HTTPS
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ SUNUCU (Server-Side) │
│ │
│ ┌─────────────────────┐ ┌──────────────────────┐ ┌────────────────┐ │
│ │ SongStreamController │ │ SongController │ │ SignedUrl │ │
│ │ /stream, /track-* │ │ /recent, /popular │ │ Service │ │
│ │ /hls-key, /hls/* │ │ /show, /audio/cdn │ │ HMAC-SHA256 │ │
│ └─────────┬───────────┘ └──────────┬───────────┘ └──────┬─────────┘ │
│ │ │ │ │
│ ┌─────────┴──────────────────────────┴──────────────────────┴─────────┐ │
│ │ Redis Cache + MySQL DB + Storage (HLS files) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
JavaScript Yükleme Waterfall
Sayfa açıldığında JS dosyalarının yüklenme sırası ve boyutları
HEAD'deki toplam: 791 KB render-blocking JavaScript. Sayfa bu dosyalar yüklenene kadar boş kalıyor.
Play Butonuna Basılınca Ne Olur?
Kullanıcının "Çal" butonuna basmasından ses çıkana kadar olan tam akış
T0: Yetki Kontrolü
~0msGiriş yapılmış mı? Premium mu? Kontrol et. Değilse engelle.
playSong() → satır 3707-3721
T1: Mevcut Çalmayı Durdur
~10-50msEski HLS instance'ını pool'a geri ver, Howler'ı unload et, blob URL'leri serbest bırak, audio element'i temizle.
stopCurrentPlayback() → satır 3754, HlsPool.release()
T2: API — Stream URL İste
100-400msPOST /api/muzibu/songs/{id}/stream — Şifreli stream URL'si, fallback MP3 URL'si, şarkı metadata'sı döner.
XOR + Base64 ile şifrelenmiş → decryptStreamData() ile çözülür
T3: Queue Oluştur + UI Güncelle
~20-50msSıra oluştur, tema renklerini güncelle, MediaSession API'yi set et (kilit ekranı kontrolleri), analitik gönder.
T4: HLS Yükleme Başlat
150-400ms1. Key Pre-fetch: Şifreleme anahtarını önceden indir (paralel)
2. Blob URL: Gerçek stream URL'sini DevTools'tan gizle
3. ABR Lock: İlk 3 saniye sadece düşük kalite (hızlı başla)
4. HLS.js: loadSource → attachMedia → startLoad
5. Manifest: master.m3u8 indir ve parse et
T5: SES ÇIKTI!
TOPLAM: 300ms - 1.2sMANIFEST_PARSED → audio.play() → İlk segment decode → Ses başladı!
Bir Şarkı İçin Network Waterfall
Şarkı Çalarken Arkada Dönen İşlemler
| İşlem | Aralık | Amaç | CPU Etkisi | Devre Dışı? |
|---|---|---|---|---|
| Progress Güncelleme | 250ms | İlerleme çubuğu + süre gösterimi | ~2ms | Hayır (zorunlu) |
| Buffer Sağlık Kontrolü | 500ms | Buffer < 0.5s ise durdur, ≥ 2s ise devam | ~1ms | Kısmen |
| Queue İzleme | 10s | Sırada < 3 şarkı varsa API'den yenilerini getir | ~5ms/10s | Hayır |
| Preload (Sonraki Şarkı) | Tetik | Şarkı bitiminden 15s önce sonrakini yükle | ~20MB RAM | Evet |
| Performance Debug | Sürekli | Memory, jank, freeze izleme + PerformanceObserver | ~1% CPU, 3-4MB RAM | Evet! |
| Buffer Monitor | Event | Takılma algıla → Otomatik hız testi tetikle | 100MB test! | Evet! |
| Spot (Reklam) Preload | Tetik | Şarkının %80'inde sonraki reklamı önceden yükle | 5MB audio blob | Evet |
| Play Count (30s) | Bir kez | 30 saniye dinlenirse play_count +1 | Minimal | Hayır |
Bellek Kullanım Haritası
Normal Çalma (~50MB)
Peak Kullanım (~120-150MB)
API-Driven Mimari Ne Kazandırır?
Mevcut yapıda tarayıcı hem karar veriyor hem uyguluyor. API-driven'da sunucu karar verir, tarayıcı sadece uygular.
Mevcut Yapı (Client-Heavy)
"HLS mi MP3 mi?", "Kalite kaç?", "Preload yap mı?", "Hız testi gerekli mi?" — Hepsi tarayıcıda
8.310 satır tek dosya, tüm iş mantığı tarayıcıda
device-profiler.js + old-device-checker.js tarayıcıda çalışıyor, sonucu backend'e gönderiyor, ama karar yine tarayıcıda
API-Driven (Server-Decides)
"Bu kullanıcıya HLS ver", "Kalite: 64kbps", "Preload: kapalı", "Debug: kapalı" — Tek API'den gelir
Sadece çalma + UI. Karar mantığı sunucuda
Kişi bazlı "bu kullanıcıya MP3 ver", "bu cihaza low mode" seçeneği
Önerilen API Akışı
// ÖNERİLEN: Tek API çağrısı ile tüm kararları al POST /api/v2/player/init Request: { device_fingerprint, connection_type, screen_size } Response: { "player_mode": "full" | "soft", // Sunucu karar veriyor "stream_type": "hls" | "mp3", // Admin panelinden set edilmiş "max_quality": "mid", // Cihaza/plana göre "features": { "preload": false, // Eski cihaz → kapalı "debug_panel": false, // Production → kapalı "speed_test": false, // Kötü internet → kapalı "buffer_monitor": false, // Soft mode → kapalı "spot_ads": true, // Reklam aktif "crossfade": false, // Zaten kapalı "gapless": false // Soft mode → kapalı }, "hls_config": { "maxBufferLength": 8, // Eski cihaz → düşük "maxBufferSize": 5242880, // 5MB (normal: 10MB) "startLevel": 0 // Her zaman düşükten başla }, "scripts": [ // Sadece gerekli JS dosyaları "player-core-lite.js", // 80KB (384 yerine) "spot-player.js" // Gerekli modüller ] } // Sonraki şarkı API'si: POST /api/v2/player/next Request: { current_song_id, queue_context, device_profile_id } Response: { "song": { id, title, cover, duration, color_hash }, "stream_url": "https://...", // Direkt URL (şifreleme sunucuda) "stream_type": "mp3", // Sunucu kararı "quality": "low", // Sunucu kararı "preload_next": false // Preload yapma }
API-Driven'ın Somut Faydaları
%60-75 Daha Az JavaScript
1.5 MB → ~400 KB. Karar mantığı sunucuda olunca tarayıcı sadece çalma yapıyor.
Admin Panel Kontrolü
Her kullanıcıya özel ayar: "Bu kişiye HLS ver, şuna MP3 ver, eski cihazına soft mode aç"
Eski Cihaz Desteği
RAM < 2GB → Sunucu otomatik soft mode + MP3 + düşük kalite + preload kapalı gönderir.
Merkezi Hata Yönetimi
HLS hata → Sunucu bilir → Otomatik MP3'e geçirir. Tarayıcı fallback mantığı basitleşir.
Mevcut API Endpoint'leri & Query Yükleri
| Endpoint | Method | DB Query | Cache | Auth | Süre |
|---|---|---|---|---|---|
| /api/songs/{id}/stream | GET | 0-2 | Redis 24h | Web+Sanctum | 40ms |
| /api/songs/recent | GET | 3-4 | Yok! | Sanctum | 70ms |
| /api/songs/popular | GET | 1 | Redis 30dk | Public | 10ms |
| /api/songs/{id}/track-start | POST | 3 | Yok | Sanctum | 10ms |
| /api/songs/{id}/track-hit | POST | 2 | Yok | Sanctum | 7ms |
| /hls-key/songs/{id} | GET | 0 | Redis 24h | Signed URL | 5ms |
| /hls/songs/{id}/{file} | GET | 0 | HTTP immutable | Signed URL | 2ms |
Günlük query tahmini (1000 aktif kullanıcı): ~1 milyon query/gün. /recent endpoint'ine cache eklenmeli, play_count Redis counter'a taşınmalı.
Neden Donuyor? — Kök Neden Analizi
Ters mühendislik ile tespit edilen donma sebepleri, önem sırasına göre
1. JavaScript Boyutu — 1.5 MB
KRİTİKBasit Anlatım
Bir eski telefon 1.5 MB JavaScript'i indirmek, okumak ve çalıştırmak zorunda. Bu süre boyunca sayfa donuk kalıyor. 4G bile olsa parser süresi eski CPU'da 3-5 saniye.
Teknik Detay
HEAD'de 791 KB render-blocking JS var. player-core.js (384 KB) + performance-debug.js (180 KB) ana suçlular. DOMContentLoaded 1.4-2s gecikiyor.
app.blade.php: satır 126-128 (HEAD script'ler)
2. Speed Test — 100 MB İndirme
KRİTİKBasit Anlatım
Şarkı 1 kez takılınca sistem otomatik 100 MB dosya indirip hız testi yapıyor. Kötü internette hem şarkı hem test birlikte indirmeye çalışınca her şey donuyor.
Teknik Detay
BufferMonitor CONFIG.BUFFER_THRESHOLD = 1. Tek bir buffer event → SpeedTester.runTest(). Auto test: 10 MB, manual: 100 MB. 30 dakika cooldown var ama kötü internette sık tetikleniyor.
buffer-monitor.js: satır 120-140, speed-tester.js: satır 80-120
3. RAM Baskısı — 120-150 MB Peak
YÜKSEKBasit Anlatım
Player aynı anda 2 şarkı hazırlıyor (mevcut + sonraki), reklam ses dosyası, hız testi blob'u ve debug logları tutuyor. 2 GB RAM'li telefonda bu çok ağır.
Teknik Detay
HlsPool max 3 instance × ~20 MB = 60 MB. Preload + spot preload + speed test blob. GC (çöp toplayıcı) baskısı → UI jank (50ms+ longtask).
4. Network Waterfall — 5-8 İstek
YÜKSEKBasit Anlatım
Her şarkı için sırayla: stream URL iste, manifest indir, şifre anahtarı al, ilk parçayı indir, analitik gönder. Kötü internette her biri 500ms+ gecikebilir.
Teknik Detay
API call (100-400ms) → master.m3u8 (60ms) → enc.bin key (50ms) → segment-0.ts (150-300ms). Toplam: 300ms-1.2s. Kötü internette: 3-8s.
5. Buffer Health Auto-Pause
ORTABasit Anlatım
Buffer 0.5 saniyenin altına düşerse player kendini durduruyor, 2 saniye dolunca devam ediyor. Kötü internette bu "durdur-devam" döngüsü titreme etkisi yaratıyor.
Teknik Detay
500ms interval ile buffer kontrolü. buffered < 0.5s → audio.pause(). buffered >= 2s → audio.play(). Sık tetiklenince kullanıcı "donuyor" algısı yaşıyor.
player-core.js: satır 7618-7630
6. HLS Key Load Gecikme
ORTABasit Anlatım
Her şarkı şifrelenmiş. Şifre anahtarı ayrı bir istekle geliyor. Bu anahtar gecikmeli gelirse ses geç başlıyor.
Teknik Detay
prefetchHlsKey() key'i browser HTTP cache'ine yerleştiriyor. Ama HLS.js'in kendi key-load pipeline'ı cache miss olursa 50-150ms ek gecikme. Non-fatal keyLoadError → exponential backoff retry (5x).
player-core.js: satır 5033-5036, 5262-5270
Soft Mode — Hafif Player Versiyonu
Eski cihazlar ve kötü internet için minimal kaynak tüketen alternatif çalma modu
| Özellik | Full Mode | Soft Mode | Tasarruf |
|---|---|---|---|
| JavaScript Boyutu | ~1.5 MB | ~400 KB | -73% |
| RAM Kullanımı | 50-150 MB | 20-35 MB | -75% |
| Stream Tipi | HLS (adaptive) | MP3 (direkt) | Daha az istek |
| Kalite | 32-320 kbps (adaptif) | 64 kbps (sabit) | %50 az bant |
| Preload (Sonraki) | Açık | Kapalı | -20 MB RAM |
| Debug Panel | Açık | Kapalı | -180 KB JS, -4 MB RAM |
| Hız Testi | Otomatik | Kapalı | -100 MB indirme yok |
| Buffer Monitor | Aktif | Kapalı | Daha az CPU |
| Gapless Geçiş | Açık | Kapalı | Kısa kesinti olur |
| Context Menu | Tam | Basit | -40 KB JS |
| Reklam (Spot) | Preload | Talep üzerine | -5 MB preload yok |
Soft Mode Ne Zaman Devreye Girer?
Otomatik (Cihaz)
- RAM < 2 GB
- CPU cores < 2
- Tarayıcı 5+ yıl eski
- iOS Safari < 15
Otomatik (İnternet)
- effectiveType: slow-2g / 2g
- downlink < 1 Mbps
- rtt > 500ms
- saveData: true
Manuel (Admin)
- Kullanıcı bazlı set etme
- Cihaz profili bazlı
- Plan bazlı (free = soft)
- Genel varsayılan ayar
Uygulama Stratejisi
// YOL 1: Mevcut player-core.js içinde feature flag'ler (Hızlı) // API'den gelen config ile modülleri aç/kapat window.MUZIBU_CONFIG = await fetch('/api/v2/player/init').then(r => r.json()); if (MUZIBU_CONFIG.player_mode === 'soft') { // Debug panel → YÜKLEME // Speed tester → YÜKLEME // Buffer monitor → YÜKLEME // Device profiler → YÜKLEME // Preload → DEVRE DIŞI // HLS → MP3 fallback olarak yükle } // YOL 2: Ayrı player-core-lite.js dosyası (İdeal ama daha fazla iş) // Sadece çalma + UI kodu, 80-100 KB // HLS.js yerine sadece Howler.js // Tüm monitoring/debug kodu yok // ÖNERİ: Yol 1 ile başla, sonra Yol 2'ye geçiş yap
HLS / MP3 Geçiş Sistemi — Kişi Bazlı
Admin panelinden her kullanıcıya özel stream tipi atama
Mevcut Durum
Mevcut Karar: SongStreamController şarkının hls_path olup olmadığına bakıyor.
hls_path var → HLS stream URL döndür
hls_path yok → MP3 URL döndür + ConvertToHLSJob dispatch et
HLS hata → Player tarafında MP3 fallback (Howler.js)
Şu an kullanıcı bazlı seçim yok — herkese aynı mantık uygulanıyor.
Önerilen: Kişi Bazlı Stream Tipi
// Admin Panel → Kullanıcı Ayarları users tablosu: + stream_preference ENUM('auto', 'hls', 'mp3') DEFAULT 'auto' + max_quality ENUM('ultralow','low','mid','high') DEFAULT NULL + player_mode ENUM('full', 'soft') DEFAULT 'full' // SongStreamController'da karar mantığı: public function stream(Request $request, $songId) { $user = auth()->user(); // 1. Admin override kontrolü if ($user->stream_preference === 'mp3') { return $this->serveMp3($song, $user); } if ($user->stream_preference === 'hls') { return $this->serveHls($song, $user); } // 2. 'auto' mod: cihaz profiline göre karar $deviceProfile = $user->activeDeviceProfile; if ($deviceProfile?->is_old_device) { return $this->serveMp3($song, $user); // Eski cihaz → MP3 } if ($song->has_hls_path) { return $this->serveHls($song, $user); // Normal → HLS } return $this->serveMp3($song, $user); // Fallback → MP3 }
HLS (Varsayılan)
- Adaptif kalite
- Şifreleme (DRM)
- Segment caching
- 5-8 HTTP isteği
- HLS.js gerekli (100 KB)
- ~20 MB RAM/instance
MP3 (Hafif)
- Tek HTTP isteği
- Düşük RAM (~5 MB)
- Anında başlama
- Sabit kalite
- Şifreleme zor
- CDN cache yönetimi
Auto (Akıllı)
- Cihaz profiline göre
- İnternet hızına göre
- Hata sonrası geçiş
- Admin override
- A/B testi desteği
- Analitik toplama
Admin Panel — Kullanıcı Stream Ayarı
Kullanıcı #1234 — Ahmet Yılmaz
Premium | Son giriş: 2 saat önce | Cihaz: Samsung Galaxy A10 (2GB RAM)
2 GB RAM algılandı — Soft Mode öneriliyor
Uygulama Yol Haritası
Faz 1 — Acil Optimizasyonlar (Mevcut kod üzerinde)
Yeni mimari gerektirmeyen, hemen yapılabilecek iyileştirmeler
performance-debug.js → Conditional Load
Kolay180 KB sadece debug_level > 0 ise yükle. Production'da hiç yüklenmemeli.
Kazanç: -180 KB, ~600ms hızlanma
player-core.js → defer attribute
KolayHEAD'den render-blocking kaldır. <script defer> ile yükle.
Kazanç: ~1000ms ilk render hızlanma
Buffer Monitor threshold artır
KolayBUFFER_THRESHOLD: 1 → 3. Tek takılmada test tetiklenmesin.
Kazanç: Gereksiz 100 MB indirme engellenir
Modülleri lazy-load yap
Ortaspeed-tester, device-profiler, old-device-checker, context-menu → İhtiyaç olunca yükle.
Kazanç: -70 KB başlangıç, ~300ms hızlanma
Faz 2 — API-Driven Player Init + Soft Mode
Sunucu kararı ile player konfigürasyonu
/api/v2/player/init endpoint
OrtaCihaz bilgisi gönder → Sunucu player_mode, stream_type, features, hls_config döndürsün.
Feature flag sistemi (player-core.js)
OrtaAPI'den gelen config ile modülleri aç/kapat. preload, debug, speedTest, bufferMonitor flag'leri.
Admin panel: Kullanıcı stream ayarı
Ortausers tablosuna stream_preference, max_quality, player_mode alanları. Admin'den set edilebilir.
Stream controller güncelleme
OrtaSongStreamController'da kullanıcı tercihine göre HLS/MP3 kararı. Device profile entegrasyonu.
Faz 3 — Player Lite (Ayrı Build)
Tamamen hafif alternatif player
player-core-lite.js oluştur
Büyük~80-100 KB. Sadece: çalma, duraklatma, ileri/geri, sıra, ses. HLS.js opsiyonel. Howler.js yeterli.
Dinamik script yükleme
BüyükAPI'den gelen scripts[] listesine göre sadece gerekli JS dosyalarını yükle. Soft mode = lite dosyalar.