Basit Anlatım (Herkes İçin)
Player neden donuyor? Müzik çalar yazılımı 9.463 satırlık tek bir dev dosyadan oluşuyor. İçinde yüzlerce fonksiyon, zamanlayıcı (timer) ve olay dinleyici (event listener) var. Bunların bir kısmı birbirleriyle çarpışıp "donma" etkisi yaratıyor.
Şarkı geçişlerinde neden bekleme oluyor? Bir sonraki şarkıya geçerken 6-7 adımlık bir sıra bekleniyor: URL al, bağlantı kur, şifreleme anahtarını indir, ses kalitesini belirle, tamponu doldur, çal. Bu adımların HER BİRİ internete bağımlı. Yavaş internette toplam 5-15 saniye sürebilir. Debug logları bunu doğruluyor: ortalama ilk şarkı başlama süresi 3.3-5.2 saniye.
Neden bazen şarkı ortasında donuyor? Arka planda çalışan "debug paneli" her saniye tüm sayfayı tarayıp rapor oluşturuyor. Bu işlem sırasında müzik çalıcısı bir anlığına duraksıyor. Chrome kullanıcılarında (nurullah, deneme) 7+ saatlik oturumlarda 20+ PROC-HOLD (donma) olayı kaydedildi. Safari kullanıcılarında ise 0 donma — çünkü Safari daha katı throttle uyguluyor.
Gerçek veriler ne diyor? 69 debug log dosyası, 6 kullanıcıdan analiz edildi. Preload (önceden yükleme) başarılı olunca geçiş 222-270ms (mükemmel). Başarısız olunca 3-5 saniye bekleme. Bazı şarkıların HLS dosyaları bozuk (equanimity #34928). Idle (boş duran) oturumlar bile kaynak tüketiyor (773 jank, 0 şarkı).
Safari'de özel bir sorun var: Safari, tab arka plandayken (gizliyken) yeni ses çalmaya başlamayı engelliyor. Bu bir güvenlik politikası. Sonuç olarak: şarkı geçişi sırasında tab gizliyse, HLS hata veriyor, yedek çalar da hata veriyor, şarkı geçişi tamamen başarısız oluyor. Bu sorun Chrome'da yok, sadece Safari'de var.
Redis optimizasyonları nedir? Her şarkı çalındığında veritabanına 3-4 sorgu gidiyordu. Şimdi bu sorgular Redis (hızlı bellek deposu) üzerinden yapılıyor. Şarkı dinlenme sayısı anlık yerine 5 dakikada bir topluca güncelleniyor. Şarkı bağlantı bilgileri 5 dakika önbellekte tutuluyor. Kötüye kullanım kontrolü de Redis counter ile yapılıyor. Sonuç: Veritabanı yükü dramatik şekilde azaldı.
Yeni: Hız optimizasyonları (1 Mart): Üç önemli iyileştirme yapıldı: 1) Fast-start: Playlist/Albüm/Tür başlatılınca artık tüm şarkı listesi yüklenmeden ilk şarkı hemen çalmaya başlıyor, kalan şarkılar arka planda 1 saniye sonra dolduruluyor. 2) Hover preload: Şarkı kartının üzerine fare geldiğinde, tıklamadan önce bağlantı bilgisi arka planda hazırlanıyor. Bu sayede tıklandığında ~730ms daha hızlı başlıyor. 3) Albüm bug düzeltmesi: Albüm çalma butonu uzun süredir sessizce bozuktu (API cevabı yanlış okunuyordu) — düzeltildi.
Bölüm 1: Kod Analizi (19 Dosya, 20.326 Satır)
Her dosya satır satır okundu. Tüm fonksiyonlar, timer'lar ve event listener'lar haritlandı.
Donma (Freeze) Nedenleri
Kullanıcının "player dondu, tepki vermiyor" dediği durumlar
D1: _hlsRetryCount Asla Sıfırlanmıyor
HLS hatası aldıktan sonra _hlsRetryCount sayacı hiç resetlenmiyor. Bir şarkıda 3 deneme yapıldıysa, sonraki TÜM şarkılarda HLS retry devre dışı kalır ve kalıcı MP3 fallback'e düşer.
ÇÖZÜM:
Her yeni şarkı başladığında this._hlsRetryCount = 0 yapmak yeterli. playSong() fonksiyonunun başına eklenmeli.
D2: _nextTrackInProgress 10 Saniye Kilit
Bir şarkı geçişi başladığında 10 saniyelik kilit konuyor. Geçiş sırasında hata olursa veya takılırsa, kullanıcı 10 saniye boyunca next/prev yapamaz.
ÇÖZÜM:
Kilidi 3-4 saniyeye düşürmek + hata durumunda hemen serbest bırakmak.
D3: saveQueueState 4x Tetikleniyor ($watch)
Alpine.js'in 4 farklı $watch handler'ı her şarkı değişiminde saveQueueState() fonksiyonunu çağırıyor. 100+ şarkılık kuyrukta her seferinde ~5-15ms (4x = 20-60ms).
ÇÖZÜM:
500ms debounce eklemek. 4 $watch yerine tek bir requestAnimationFrame bazlı queue save.
D4: Performance-Debug updatePanel() Her Saniye
İRONİ: Donmaları tespit etmek için yazılan debug aracı, kendisi donmaların en büyük kaynaklarından biri! updatePanel() her saniye: captureFullState(), collectMetrics(), ve 400+ satırlık innerHTML ataması yapıyor.
ÇÖZÜM:
Panel görünür değilken interval'ı durdurmak. 3-5 saniyeye çıkarmak. innerHTML yerine hedefli DOM güncellemeleri.
D5: startAutoLog() TÜM Kullanıcılar İçin Çalışıyor
Debug paneli açılmasa bile startAutoLog() TÜM kullanıcılar için çalıştırılıyor. Her 60 dakikada generateReport() senkron olarak ~20-50ms GC spike'a neden oluyor.
ÇÖZÜM:
startAutoLog() çağrısını isDebugAllowed() koşuluna bağlamak.
D6: Crossfade Race Condition (250ms Pencere)
28 Şubat — Crossfade kökten kaldırıldıCrossfade sistemi tamamen kaldırıldı (~480 satır player-core.js, ~60 satır perf-debug.js, config, blade, test dosyalarından silindi). Bu sorun artık mevcut değil.
D7: Timer Birikimi (Tab Switching)
visibilitychange dinleyicisi her tab geçişinde yeni setTimeout oluşturuyor. Hızlı alt-tab yapıldığında timer'lar birikiyor.
ÇÖZÜM:
Önceki timeout'u clearTimeout() ile iptal edip sonra yenisini oluşturmak.
D8: MutationObserver document.body subtree:true
Performance-debug modülü document.body üzerinde childList: true, subtree: true ile MutationObserver kaydediyor. Sayfadaki HER DOM değişikliğinde callback tetikleniyor.
ÇÖZÜM:
Sadece debug aktifken başlat. Kapsamını daralt veya throttle ekle.
D9: _safePlayFromQueue Recursive Retry
Kuyruktan şarkı çalma fonksiyonu recursive olarak kendini çağırıyor. 100 şarkılık kuyrukta potansiyel 300 fetch isteği.
ÇÖZÜM:
Maksimum 5-10 deneme limiti koymak. Ard arda X hata sonrası kuyruğu durdurmak.
D10: Safari Arka Planda audio.play() Engeli
Safari, tab arka plandayken (gizli/hidden) yeni bir audio.play() çağrısı yapılmasını güvenlik politikası gereği engelliyor. Bu, arka planda şarkı geçişi yapıldığında zincirleme hata oluşturuyor:
Gerçek veri doğrulaması: DaVinci (Safari) oturumunda test1 kullanıcısı 726 saniye (~12 dakika) tab'ı arka plana almış. Bu sürede gapless geçişler çalışabilmiş çünkü mevcut audio element devam ediyordu. Ancak DaVinci'de 2. şarkıya geçişte HLS FATAL x2 + Howler error x2 zinciri tam olarak bu senaryoyu yansıtmaktadır.
ÇÖZÜM ÖNERİLERİ:
1. Visibility Check: document.visibilityState === 'hidden' kontrolü eklenip, arka plandayken yeni şarkı başlatmayı ERTELEMEK (kuyruklama). Tab öne gelince başlatmak.
2. Mevcut Audio Element Yeniden Kullanımı: Arka plandayken yeni audio element oluşturmak yerine, mevcut çalışan audio element'in src'sini değiştirip devam ettirmek. Safari mevcut audio element'in çalışmaya devam etmesine izin veriyor — sorun YENİ audio başlatmakta.
3. Web Audio API Bypass: Web Audio API üzerinden AudioContext kullanarak ses çıkışı yapmak. AudioContext bir kez kullanıcı etkileşimiyle oluşturulduktan sonra arka planda da çalışabilir.
4. Preload Tamponlama: Tab arka plandayken preload edilen şarkının audio buffer'ını hazır tutup, tab öne geldiğinde anında başlatmak (buffer zaten yüklü olacağı için geçiş hızlı olur).
Gecikme (Delay) Nedenleri
Kullanıcının "şarkı arası çok uzun bekliyor" dediği durumlar
G1: Waterfall Await Zinciri (6-7 Sıralı Adım)
Bir şarkı başlatılırken 6-7 sıralı await çalıştırılır. Her biri ağ gecikmesine bağımlı.
ÇÖZÜM:
Preload daha agresif + manifest/key indirme paralelleştirilmeli + buffer bekleme kısaltılmalı.
G2: 8 Saniye Loading Guard
Şarkı yüklenirken 8 saniyelik guard timer var. Dolunca otomatik nextTrack(). Zincirleme etki: yüklenemedi → next → yüklenemedi → sonsuz döngü.
ÇÖZÜM:
5 saniyeye düşürmek. 3 başarısız guard sonrası durmak. Kullanıcıya mesaj göstermek.
G3: DEVRALMA (Preload Handoff) 3 Saniye Bloğu
Preload edilen şarkı devralınırken polling mekanizması 3 saniye boyunca bloke olabiliyor.
ÇÖZÜM:
Polling yerine event-driven handoff kullanmak.
G4: Promise Constructor Antipattern (Crossfade)
new Promise(async (resolve, reject)) antipattern'i. Async fonksiyon içindeki hatalar yakalanmaz.
ÇÖZÜM:
new Promise(async ...) yerine düz async function kullanmak.
G5: Dual Progress Interval Birikimi
HLS ve crossfade progress interval'ları birlikte çalışabilir. İki ayrı setInterval her 250ms'de progress bar günceller.
G6: setInterval(attachSegmentStatListener, 5000) Asla Temizlenmiyor
Performance-debug'daki segment stat listener interval'ı ASLA temizlenmiyor.
Backend Sorunları
Stream URL'leri ve HLS dosya sunumundaki performans darboğazları
B1: getFormattedBitrate() Her Stream İsteğinde Dosya Parse Ediyor
stream() metodu her çağrıldığında getID3::analyze() ile 5MB'lık MP3 dosyasını disk'ten okuyor.
ÇÖZÜM:
Bitrate değerini DB'de saklamak. İlk parse'dan sonra cache'lemek.
B2: $song->genre N+1 Lazy Load
MuzibuCacheService::getSong() sadece album.artist eager load yapıyor. genre dahil değil.
ÇÖZÜM:
CacheService eager load'a genre, coverMedia eklemek.
B3: HLS Playlist Regex İşleme Cache'siz
HLS playlist Redis cache'te ama regex işlemleri (key URI yazma, variant filtreleme, query ekleme) her istekte yeniden yapılıyor.
B4: trackStart/trackHit Auth Tutarsızlığı
trackStart() sadece auth('sanctum'), trackEnd() ise hem auth('web') hem auth('sanctum') kontrol ediyor.
Orphan (Kullanılmayan) Kod
10 orphan fonksiyondan 8'i kaldırıldı (kullanıcı onayıyla). 2'si (buffer-monitor.js) henüz dokunulmadı.
| Fonksiyon | Dosya | Eski Durum | Şimdi |
|---|---|---|---|
| detectDevice() | SongStreamController.php | ORPHAN | KALDIRILDI |
| detectBrowserFromUA() | SongStreamController.php | ORPHAN | KALDIRILDI |
| getSessionTerminationMessage() | SongStreamController.php | ORPHAN | KALDIRILDI |
| incrementPlayCount() | SongStreamController.php | DEPRECATED | KALDIRILDI |
| trackProgress() | SongStreamController.php | DEPRECATED | KALDIRILDI |
| login/register handlers | auth.js | STUB | KALDIRILDI |
| runFirstVisitTest() | buffer-monitor.js | DISABLED | KALIYOR |
| setupConnectionChangeTest() | buffer-monitor.js | DISABLED | KALIYOR |
| startPolling() | spot-player.js | DISABLED | KALDIRILDI |
| prefetchVisible/prefetchHover | spa-router.js | DISABLED | KALDIRILDI |
Dosya Haritası
| Dosya | Satır | Risk | Açıklama |
|---|---|---|---|
| player-core.js | 9.463 | KRİTİK | Ana player kodu — "God File" |
| performance-debug.js | 4.145 | YÜKSEK | Debug paneli — prod'da 194KB |
| SongStreamController.php | 1.062 | YÜKSEK | Stream + HLS + tracking |
| play-helpers.js | 979 | DÜŞÜK | playGenres, playPlaylist vb. |
| spa-router.js | 687 | DÜŞÜK | SPA navigasyon |
| SongController.php | 628 | ORTA | Şarkı listeleme/detay |
| spot-player.js | 564 | DÜŞÜK | Kurumsal spot sistemi |
| speed-tester.js | 395 | DÜŞÜK | Hız testi |
| device-profiler.js | 356 | DÜŞÜK | Cihaz tespit |
| player.blade.php | 330 | DÜŞÜK | Player UI template |
| buffer-monitor.js | 294 | DÜŞÜK | Buffer izleme |
| old-device-checker.js | 244 | DÜŞÜK | Eski cihaz kontrolü |
| MuzikStreamController.php | 232 | DÜŞÜK | Müzik stream |
| favorites.js | 230 | DÜŞÜK | Favori sistemi |
| PlayController.php | 213 | DÜŞÜK | AI Assistant play |
| session.js | 190 | DÜŞÜK | Oturum sonlandırma |
| auth.js | 177 | STUB | Boş handler'lar |
| api.js | 99 | DÜŞÜK | API istemci |
| safe-storage.js | 38 | DÜŞÜK | localStorage wrapper |
| TOPLAM | 20.326 | ||
Şarkı Çalma Çağrı Akışı
Normal Şarkı Başlatma
Crossfade Akışı
KALDIRILDI (28 Şubat 2026) — Crossfade sistemi kökten kaldırıldı. ~540 satır kod silindi (startCrossfade, createNextHowlerPlayer, createNextHlsPlayer, completeCrossfade). Player artık doğrudan onTrackEnded() ile şarkı geçişi yapıyor.
Timer ve Interval Envanteri
| Timer | Süre | Dosya | Temizleniyor mu? | Risk |
|---|---|---|---|---|
| updatePanel interval | 1s | perf-debug.js | Evet | KRİTİK |
| metric collection interval | 1s | perf-debug.js | Evet | YÜKSEK |
| segmentStatListener interval | 5s | perf-debug.js | HAYIR! | ORTA |
| autoLog interval | 60dk | perf-debug.js | Evet | ORTA |
| expireCheck interval | 30s | perf-debug.js | Evet | DÜŞÜK |
| _nextTrackInProgress timeout | 10s | player-core.js | Kısmen | KRİTİK |
| loadingGuard timeout | 8s | player-core.js | Evet | YÜKSEK |
| crossfade progress interval | 250ms | player-core.js | Kısmen | ORTA |
| HLS progress interval | 250ms | player-core.js | Evet | DÜŞÜK |
| visibilitychange setTimeout'lar | 1-5s | player-core.js | HAYIR! | YÜKSEK |
| 8x fakeCore timeout zinciri | 0.6-7s | perf-debug.js | DOM'a bağlı | DÜŞÜK |
Bölüm 2: Debug Log Analizi (69 Dosya, 6 Kullanıcı)
storage/tenant1001/logs/debug-mod/2026/02/28/ altındaki tüm loglar analiz edildi
Kullanıcı Oturumları Özeti
Chrome vs Safari Karşılaştırma
| Metrik | Chrome (nurullah, deneme) | Safari (test, test1) | Sonuç |
|---|---|---|---|
| PROC-HOLD (Freeze) | 20+ olay | 0 | Chrome sorunu |
| JANK (Mikro duraklama) | 773-1077 | 0 | Chrome sorunu |
| Memory API | Mevcut | Yok (-1MB) | Safari kör |
| Ad-Block | Var | Var | Tüm kullanıcılar |
| Preload | Çalışıyor | Sorunlu | Safari sorunu |
Safari Şarkı Geçişleri (Detay)
TTP — İlk Ses Çıkma Süresi
BUF-SYNC (Rebuffer) Özeti
| Kullanıcı | Olay Sayısı | Ort. Süre | Patern |
|---|---|---|---|
| nurullah (Chrome) | Tüm geçişlerde | ~1300ms | Her fresh geçişte |
| test1 (Safari) | 2 | 1162ms | İlk şarkıda çift |
| DaVinci (Safari) | 2 | 848ms | İlk şarkıda çift |
HLS FATAL Hata Zinciri (DaVinci)
Tüm Kullanıcılarda Ortak Paternler
Patern 1: İlk Şarkıda Yüksek TTP + Çift BUF-SYNC
Her kullanıcıda ilk şarkı 3-5s sürüyor. Arka arkaya 2 BUF-SYNC olayı (manifest + decode). Gapless geçişlerde sorun yok.
Patern 2: PROC-HOLD Sadece Chrome'da
Chrome: 20+ PROC-HOLD, 773-1077 JANK. Safari: 0 PROC-HOLD, 0 JANK. Fark: Chrome'un performance-debug.js timer'larına daha az throttle uygulaması.
Patern 3: Safari Preload Sorunları
safari_native_error + timeout_15s + fragParsingError. Safari'nin HLS native handling'i preload mekanizmasıyla çatışıyor.
Patern 4: Gapless Geçişler Mükemmel
Preload başarılı olunca 222-270ms geçiş. Mekanizma doğru çalışıyor, sorun preload başarısızlıkları.
Patern 5: Ad-Block Yaygın
3/4 kullanıcıda ad-block aktif. HLS segment yüklemelerini etkileme potansiyeli var.
Patern 6: ABR Bant Genişliği Donuk
Gerçek hız 7-15 Mbps iken ABR estimate 250 kbps'de donabiliyor. BW ölçümü düzeltilmeli.
Patern 7: Idle Oturumlar Kaynak Tüketiyor
deneme: 7 saat, 0 şarkı, 773 jank. autoLog + MutationObserver + timer'lar boş bile çalışıyor.
Patern 8: ALONE Şarkısı Anomalisi
nurullah oturumunda ALONE (34855): 396 PROC-HOLD. Diğer şarkıların hepsinden 10x fazla. Bu şarkının HLS dosyaları araştırılmalı.
Safari Karşılaştırma Tablosu
| Metrik | test1 (Safari) | DaVinci (Safari) | Durum |
|---|---|---|---|
| Oturum Süresi | 15dk | 4dk | - |
| Şarkı Sayısı | 5 | 1 (+1 başarısız) | |
| PROC-HOLD | 0 | 0 | |
| TTP | 4026ms | 3323ms | |
| Gapless | 3 (ort 251ms) | 0 | |
| BUF-SYNC | 2 (1162ms) | 2 (848ms) | |
| HLS FATAL | 0 | 2 | |
| Segment Başarı | 112/112 | 56/56 | |
| ABR Kalite | high | low | |
| Ad-Block | VAR | VAR |
Bölüm 3: Kod Analizi vs Gerçek Veri Çapraz Doğrulama
Kodda tespit edilen sorunlar gerçek debug loglarıyla doğrulandı mı?
| Kod Bulgusu | Gerçek Veride Doğrulandı mı? | Kanıt |
|---|---|---|
| D1 _hlsRetryCount reset yok | Dolaylı | DaVinci'de HLS FATAL sonrası Howler fallback'e düşülmesi bu mekanizmayı işaret ediyor |
| D3 saveQueueState 4x | EVET | Chrome kullanıcılarında 1077 JANK olayı — her şarkı değişiminde burst görüldü |
| D4 updatePanel 1s | EVET | Chrome'da 20 PROC-HOLD, Safari'de 0. Debug paneli Chrome'da daha agresif çalışıyor |
| D5 autoLog tüm kullanıcılar | EVET | 69 log dosyası 6 kullanıcıdan — debug izni olmayan kullanıcılar dahil |
| G1 Waterfall await 6-7 adım | EVET | Fresh TTP: 3.3-5.2s. Gapless: 222-270ms. Fark tam olarak await zinciri süresi |
| G2 8s loading guard | Dolaylı | DaVinci'de 2. şarkıdaki FATAL sonrası zincirleme geçiş oluşabilmiş olabilir |
| B1 getID3 her istekte | Dolaylı | Server RTT 2616ms'e kadar çıkmış — disk I/O etkisi olabilir |
| D7 Tab switch timer birikimi | EVET | test1: 726 saniye arka planda, geri dönüşte SONG_CHANGE_DETECTED tetiklendi |
| D8 MutationObserver subtree | EVET | deneme: 0 şarkı, 7 saat, 773 JANK — MutationObserver idle'da bile çalışmasının kanıtı |
| D10 Safari arka plan audio.play() engeli | EVET | DaVinci: HLS FATAL x2 + Howler error x2 — tab arka plandayken yeni audio başlatma reddedilmiş. test1: 726sn arka plan sonrası SONG_CHANGE_DETECTED |
Sonuç: Kod analizindeki 10 kritik bulgunun 7'si gerçek verilerle DOĞRUDAN doğrulandı, 3'ü DOLAYLI olarak desteklendi. Hiçbiri yanlış çıkmadı.
Bölüm 5: Redis Optimizasyonları (R1-R4)
Veritabanı yükünü azaltmak için yapılan Redis tabanlı cache ve batching iyileştirmeleri
R1: Play Count Batching
Sorun: Her trackHit() çağrısında direkt DB UPDATE ($song->increment('play_count')). Yoğun dinlemede saniyede 10+ DB write.
Çözüm: Redis HINCRBY ile biriktir, 5 dakikada bir topluca flush. Atomik RENAME ile flush sırasında veri kaybı yok.
SongStreamController.php — trackHit() metoduFlushPlayCountsCommand.php — yeni Artisan komutuKernel.php — scheduler (5dk'da bir)muzibu:playcount_pending hash — {tenantId}:{songId} → countRENAME pending → flushing (atomik) → HGETALL flushing → DB batch update → DEL flushingTest: 10/10 geçti (HINCRBY doğru, flush doğru, DB artış doğru)
R2: Stream URL Backend Cache
Sorun: Her stream isteğinde format resolution + URL üretimi tekrar hesaplanıyor.
Çözüm: Response'u 5dk Redis cache (auth/premium kontrolü her seferinde yapılır, sadece hesaplama sonucu cache'lenir).
SongStreamController.php — stream() metodumuzibu:stream_resp:{tenantId}:{userId}:{songId}Test: Cache hit doğrulandı, canlıda 4 key aktif görüldü
R3: Abuse Detection Redis Counter
Sorun: Her trackStart'ta DB query ile abuse kontrolü.
Çözüm: Redis INCR counter (1 saat TTL). quickCheck ile düşük aktivitede DB atla.
AbuseDetectionService.phpmuzibu:abuse:{tenantId}:{userId}:plays_1hTest: Counter doğru, TTL 3600s, quickCheck mantığı çalışıyor
R4: .env CACHE_STORE Temizliği
CACHE_DRIVER=redis zaten aktifti. .env'de gereksiz CACHE_STORE satırı temizlendi. Tutarsızlık giderildi.
CustomMedia Serialize Sorunu — ÇÖZÜLDÜ
CustomMedia::__serialize() ve __unserialize() düzgün implement edildi. parent::__serialize() çağrısı BadMethodCallException fırlatıyordu (Eloquent Model'de yok). Artık model attributes + relations kendi serialize ediliyor.
app/Models/CustomMedia.phpCacheService.getSong() artık album.media eager load ile çalışıyor (cold: 13ms, warm: 1ms)Bölüm 6: TODO / Fix Planı
Her madde yapıldıkça işaretlenecek. Bu liste canlı tutulacak.
P0 Hemen Yapılmalı — Donmayı Azaltır
P0-1: _hlsRetryCount Her Yeni Şarkıda Sıfırla
playSong() başına this._hlsRetryCount = 0; eklendi. loadAndPlaySong() başında da zaten sıfırlanıyordu — çift güvenlik.
P0-2: saveQueueState() Debounce
500ms debounce eklendi. 4 $watch aynı anda çağırıyor → debounce ile 1'e düşürüldü.
P0-3: startAutoLog() Sadece Debug Aktif Kullanıcılarda
Root kullanıcılar için otomatik log üretimi devre dışı. isRootUser() helper eklendi.
P0-4: _nextTrackInProgress Timeout 10s → 3s
Guard timeout 10000ms → 3000ms olarak düşürüldü.
P0-5: Tab Switching clearTimeout Eklendi
visibilitychange handler'ında _visLoadingTimerId ve _visBufferTimerId için clearTimeout eklendi.
P0-6: Auto Modda Her Şarkıda HLS'ten Başla
Mekanizma zaten doğru çalışıyor. Backend her API çağrısında format kararını yeniden hesaplar.
P0-7: Safari Arka Plan Koruması (Pragmatik)
İki katmanlı çözüm: 1) onTrackEnded() kuyruk — tab gizliyse _pendingNextOnVisible = true. 2) Safari + arka plan ise HLS preload atla.
P0-8: _loadingGuard 8sn Timeout — ZATEN MEVCUT
İncelendi — 8sn loading guard timeout zaten mevcut (satır 3748-3762). Ek işlem gereksiz.
P0-9: stopCurrentPlayback() Await — handleSessionTerminated async
handleSessionTerminated() → async handleSessionTerminated(). Await/async uyumsuzluğu Safari'de tüm Alpine store'u çökertti — düzeltildi.
DERS: Await Eklerken Fonksiyonu Async Yap!
P0-9'da await eklendi ama fonksiyon async yapılmadı → SyntaxError → tüm Alpine store çöktü → player görünmedi. Kural: await ekle → fonksiyonu async yap!
P0-10: rAF İzleme Döngüsü — SORUN YOK
Sürekli dönen rAF döngüsü yok. Mevcut rAF kullanımları one-shot. Ek işlem gereksiz.
P0-11: HLS BUFFER_EOS Şarkı Sonu — ZATEN MEVCUT
BUFFER_EOS handler mevcut (satır 5398-5423). Pozisyon + süre kontrolü yapıyor. Ek işlem gereksiz.
P0-12: stream_url Null Kontrolü
Null URL ile HLS yükleme denenmez. Sessizce sonraki şarkıya geçer.
P0-13: Watchdog Timer — ZATEN KORUMALI
_manifestTimeoutId ve _abrUnlockTimerId stopCurrentPlayback() başında temizleniyor. Ek işlem gereksiz.
P0-14: performance-debug.js Production'da Yükleniyor
Sorun yok. Dosya zaten koşullu yükleniyor: @if($isDebugAllowed).
P1 Kısa Vade — Gecikmeyi Azaltır
P1-1: getFormattedBitrate() Sonucunu Cache'le
getBitrate()'e Redis cache eklendi (24 saat TTL). İlk çağrıda getID3, sonrakiler Redis'ten.
muzibu:song_bitrate:{songId}P1-2: CacheService Eager Load'a genre, media Ekle
Eager load güncellendi. N+1 sorgu problemi çözüldü. CustomMedia serialize düzeltildi — album.media eager load geri eklendi.
P1-3: Crossfade _crossfadeInProgress Mutex
Crossfade sistemi 28 Şubat 2026'da kökten kaldırıldı. Bu madde geçersiz.
P1-4 + P1-5: segmentStatListener Polling → Event-Driven
5 saniyede bir çalışan setInterval kaldırıldı. Yerine player:play event'ine listener eklendi.
P1-6: Safari Preload Stratejisi
Safari + arka plan durumunda HLS preload atlanır. Sadece stream URL cache'lenir.
P1-7: updatePanel() Optimizasyonu
3 katmanlı optimizasyon: data toplama her zaman, innerHTML sadece panel açıkken.
P1-8: MutationObserver Kapsamını Daralt
Debug panelinde ne kadar çok veri o kadar iyi. Olduğu gibi kalacak.
Redis Optimizasyonları
R1: Play Count Batching (Redis HINCRBY + 5dk Flush)
Her trackHit() direkt DB UPDATE yerine Redis HINCRBY ile biriktir, 5dk'da bir flush. Atomik RENAME ile veri kaybı yok.
R2: Stream URL Backend Cache (5dk Redis)
Stream response'u 5dk Redis cache. Auth/premium kontrolü her seferinde yapılır, sadece hesaplama sonucu cache'lenir.
muzibu:stream_resp:{tenantId}:{userId}:{songId}R3: Abuse Detection Redis Counter (1 saat TTL)
Redis INCR counter ile quickCheck. Düşük aktivitede DB sorgusu atlanır.
R4: .env CACHE_STORE Temizliği
Gereksiz CACHE_STORE satırı .env'den temizlendi. CACHE_DRIVER=redis zaten aktifti.
P2 Orta Vade — Mimari İyileştirme
P2-1: player-core.js Modüler Ayırma
9.463 satırlık "God File" — tüm mantık tek dosyada. Hedef modüller: AudioEngine, StateManager, Preloader, QueueManager. İlk adım: fonksiyonları gruplara ayırıp ES module import/export ile bağla.
P2-2: performance-debug.js Prod'da Yüklenmemeli
Zaten koşullu: @if($isDebugAllowed).
P2-3: Alpine Proxy Bypass (Kritik Yollar)
Alpine.js proxy bypass genişletildi. HLS instance, queue işlemleri ve preload fonksiyonlarında closure variable kullanımı yaygınlaştırıldı. İlk yapılan: 22 Şubat keyLoadError fix'i (var _rawHls). Genişletilen: playSong, playAlbum, playPlaylist, preloadSongOnHover ve diğer hot path'ler.
var _self = this; + var _rawHls = HlsPool.acquire(); (proxy dışı)P2-4: Waterfall Await → Paralel
playSong() içindeki refillQueue() artık loadAndPlaySong()'u beklemiyor. Fire-and-forget pattern: şarkı hemen çalmaya başlıyor, queue arka planda doluyor.
player-core.js playSong() ~satır 3687P2-5: Orphan Kodları Temizle (~1000 Satır)
8 orphan fonksiyon kaldırıldı. 2 fonksiyon (buffer-monitor) aktif kullanımda — korundu.
P2-6: ABR Bant Genişliği Fix
ABR başlangıç tahmini ve geçiş eşikleri düzeltildi. Audio-only stream için gereksiz muhafazakâr ayarlar kaldırıldı.
player-core.js HLS_SHARED_CONFIG ~satır 545P2-7: Fast-Start Pattern (5 Fonksiyon)
Playlist/Album/Genre/Sector/Radio başlatma fonksiyonları yeniden yazıldı. Eski: Tüm şarkıları API'den al → queue'ya koy → sonra çalmaya başla. Yeni: İlk şarkıyı hemen queue'ya koy ve çalmaya başla → 1 saniye sonra kalan şarkıları arka planda doldur.
playAlbum(), playPlaylist(), playGenre(), playSector(), playRadio()this.queue = [firstSong] → playSongFromQueue(0).then(() => setTimeout(fillRest, 1000))P2-8: Hover Preload (Stream URL Ön Yükleme)
Şarkı kartı üzerine fare geldiğinde stream URL arka planda önceden yükleniyor. preloadSongOnHover() fonksiyonu zaten vardı ama DOM event dinleyicisi bağlanmamıştı. Delegated mouseover listener eklendi.
document.addEventListener('mouseover', ...) — delegated, passive@click="play-song" içeren element aranırstreamUrlCache Map'e yazılır — getCachedStream() ile okunurP2-9: playAlbum() API Response Bug Fix
Uzun süredir fark edilmeyen bug: API { album: { songs: [...] } } dönüyordu ama kod album.songs okuyordu (üst seviye). Sonuç: undefined → albüm hiç çalmıyordu.
player-core.js playAlbum() ~satır 3227const album = await response.json(); if (album.songs...) — songs undefinedconst data = await response.json(); const album = data.album || data;P2-10: master.m3u8 Bypass (~662ms Kazanç)
Şu an HLS akışı 3 adımlı: Stream API → master.m3u8 → playlist.m3u8 → segment.ts. master.m3u8 sadece tek playlist'e yönlendiriyor (gereksiz aracı). Backend direkt playlist.m3u8 URL döndürürse ~662ms tasarruf.
P3 Uzun Vade — Player v2 Yeniden Yazım
P3-1: AudioEngine (Alpine Dışı, Web Audio API)
Alpine.js reaktivitesinden bağımsız ses motoru. Web Audio API tabanlı. GainNode ile donanım hızlandırmalı geçişler.
P3-2: State Machine (FSM)
Durumlar: idle → loading → playing → paused → transitioning → error. Geçersiz durum geçişlerini önler.
P3-3: Worker-Based Preload
Ana thread'i bloke etmeyen preload. Service Worker veya Web Worker ile arka planda segment indirme.
Bekleyen Ek İşler
CustomMedia __serialize Kök Çözüm
TAMAMLANDI — CustomMedia::__serialize() / __unserialize() implement edildi. Eager load geri eklendi.
MuzibuCacheService Redis KEYS → SCAN Migration
TAMAMLANDI — 4 metot (invalidatePopularSongs, invalidateFeaturedPlaylists, flushAll, getCacheStats) PhpRedis SCAN'a geçirildi.
Preload HLS FATAL (internalException) Araştırması
ÇÖZÜLDÜ — Preload sırasında orphan HLS instance'lar internalException fırlatıyordu. Orphan cleanup (HlsPool._active iterate), preload guard ve retryHlsWithNewUrl pool capacity kontrolü eklendi. Puppeteer testi: 0 internalException.
master.m3u8 Bypass (~662ms Kazanç)
HLS akışında master.m3u8 gereksiz aracı. Backend direkt playlist.m3u8 URL döndürürse ~662ms tasarruf. Detay: P2-10.
149 Şarkı v2 Re-encode
4sn segment + v2 filtreler + ses eşitleme. Test ortamı şarkıları.
Production ~30K Şarkı Re-encode
Doğru enc.keyinfo + 4sn segment + v2 audio filtreler. Prodüksiyon ortamı.
Yavaş Bağlantı Badge
Player bar'da WiFi ikonu animasyonlu — yavaş bağlantıda kullanıcıya görsel geri bildirim.
Test Matrisi
Her fix sonrası aşağıdaki senaryolar test edilmeli:
| Senaryo | Chrome | Safari | Beklenen Sonuç |
|---|---|---|---|
| İlk şarkı başlatma (fresh) | ☐ | ☐ | TTP < 3s |
| Gapless geçiş (preload başarılı) | ☐ | ☐ | < 300ms |
| Fresh geçiş (preload başarısız) | ☐ | ☐ | < 4s |
| Tab arka planda şarkı geçişi | ☐ | ☐ | Kuyruklanmalı veya çalışmalı |
| Hızlı next/prev spam (5x) | ☐ | ☐ | Donma yok, son şarkı çalmalı |
| 1 saat idle (0 şarkı) | ☐ | ☐ | JANK/PROC-HOLD artmamalı |
| HLS hata sonrası recovery | ☐ | ☐ | Sonraki şarkı HLS ile çalmalı |
| Crossfade (şarkı sonu) | — | — | KALDIRILDI — Crossfade sistemi silindi |
Kontrol Edilecek Şarkılar
| ID | Şarkı | Sorun | Kaynak | Durum |
|---|---|---|---|---|
| 34855 | ALONE | 396 PROC-HOLD anomalisi | nurullah logu | ☐ |
| 34928 | equanimity | fragParsingError + HLS FATAL x2 | DaVinci logu | ☐ |
Korunacak İyi Mekanizmalar (Dokunma!)
Instance pooling — havuzdan al, her seferinde yeni oluşturma
HLS şifreleme anahtarını cache'le, tekrar indirme
Hata veren şarkıları geçici kara listeye al
Format bilgisini URL'e gömme (s/u/l/m/h)
30dk blok bazlı URL → Cloudflare cache uyumlu
Kuyruk bitince türüne göre otomatik doldurma
trackStart → trackHit (30s) → trackEnd
activeBlobUrls Set ile bellek sızıntısı önleme