Muzibu Player & Anons Sistemi Analizi

Kapsamlı teknik inceleme • Sorun tespiti • Çözüm önerileri

KRİTİK SORUN TESPİT EDİLDİ

Anons sistemi belirtilen şarkı aralığında çalışmıyor. Asıl sebep: listenedDuration hesaplaması yanlış!

Basit Anlatım (Herkes İçin)

Sorun nedir?
Kurumsal müşteriler "10 şarkıda bir anons çalsın" diye ayarlıyor ama anons hiç çalmıyor.

Neden oluyor?
Sistem şarkının kaç saniye dinlendiğini yanlış hesaplıyor. Şarkı 3 dakika bile çalsa, sistem "0 saniye dinlendi" diye kaydediyor. 30 saniyenin altı sayılmadığı için sayaç hiç artmıyor.

Ne yapılmalı?
Dinleme süresini doğru hesaplayan kod kullanılmalı. Sistem zaten doğru hesaplama yapıyor (abuse tespiti için) ama anons için yanlış kod kullanılmış.

Teknik Detaylar (Geliştiriciler İçin)

Dosya: player-core.js:2860

Hatalı kod:

const listenedDuration = this.currentTime || this.duration || 0;

Doğru hesaplama: trackSongEnd() fonksiyonundaki gibi totalListenedMs + playbackStartTime kullanılmalı.

1. Player Mimarisi

Dosya Yapısı

public/themes/muzibu/js/player/
├── core/
│   ├── player-core.js    (445KB - Ana logic)
│   └── safe-storage.js     (localStorage güvenli erişim)
├── features/
│   ├── spot-player.js    (⭐ ANONS SİSTEMİ)
│   ├── play-helpers.js     (Genre/Playlist/Album çalma)
│   ├── session.js          (Session yönetimi)
│   ├── api.js              (API endpoint'leri)
│   ├── favorites.js        (Favori işlemleri)
│   ├── device-profiler.js  (Cihaz tespiti)
│   └── buffer-monitor.js   (Buffer izleme)
└── lib/
    └── hls.min.js          (HLS.js v1.4.12)

Alpine.js Store (player)

Alpine.store('player') = {
  currentSong: null,
  queue: [],
  queueIndex: 0,
  isPlaying: false,
  currentTime: 0,
  duration: 0,
  volume: 70,

  // HLS
  hls: null,
  hlsCurrentLevel: 3,

  // Kritik: Dinleme takibi
  playbackStartTime: null,
  totalListenedMs: 0,
  currentPlayId: null,

  // Spot guard
  _isPlayingSpot: false
}

2. Anons Sistemi Akışı

Normal Akış (Çalışması Gereken)

1 Şarkı çalmaya başlar playSongFromQueue()
2 30 saniye sonra track-hit API (play_count++)
3 Şarkı biter onTrackEnded()
4 ⚠️ listenedDuration hesapla this.currentTime || this.duration || 0
5 Spot sayacını kontrol et MuzibuSpotPlayer.onSongListened(listenedDuration)
6 30 saniyeden uzunsa sayaç++ songsPlayed++
7 Sayaç = songsBetween ise playNextSpot()

Tespit Edilen Sorun

Hatalı Kod (Satır 2860)

const listenedDuration = this.currentTime || this.duration || 0;

// SORUN:
// - this.currentTime şarkı bittiğinde 0 olabilir
// - Safari'de gapless geçişte sıfırlanıyor
// - undefined || undefined || 0 = 0
// - Sonuç: Her zaman 0 veya çok düşük değer

Doğru Hesaplama (trackSongEnd)

let listenedDuration = 0;
if (this.playbackStartTime) {
  const currentSession = this.isPlaying
    ? (Date.now() - this.playbackStartTime) : 0;
  listenedDuration = Math.floor(
    (this.totalListenedMs + currentSession) / 1000
  );
}

3. Veritabanı Durumu

Aktif Spot Kayıtları

ID Şirket Başlık Audio
2 Macro Center Homemade Kampanya
3 Shell Deli2go Anons

Toplam 2 aktif spot kaydı mevcut

spot_enabled=1 Olan Şirketler

ID Şirket Aralık Spot?
28 Blain Coffee 10
37 LOTTA COFFEE 1
38 Macro Center 1
39 Shell 1
45 Kırka Tatlıcısı 5
71 WolfBull Gym 1
74 RED EKSPRES 2

⚠️ 6 şirketin spot sistemi açık ama spot kaydı yok!

Veritabanı Tabloları

muzibu_corporate_accounts

  • • spot_enabled (boolean)
  • • spot_songs_between (int)
  • • spot_current_index (int)
  • • spot_is_paused (boolean)
  • • spot_settings_version (int)

muzibu_corporate_spots

  • • corporate_account_id (FK)
  • • title, slug
  • • duration (saniye)
  • • starts_at, ends_at
  • • position, is_enabled, is_archived

media (Spatie)

  • • model_type: CorporateSpot
  • • collection_name: 'audio'
  • • file_name: *.mp3
  • • disk: 'public'

4. API Endpoint'leri

Endpoint Method Amaç Controller
/api/spot/settings GET Spot ayarları + aktif spot listesi apiSpotSettings()
/api/spot/next GET Sıradaki spot (rotation) apiNextSpot()
/api/spot/play-start POST Spot çalmaya başladı (log) apiSpotPlayStart()
/api/spot/play-end POST Spot bitti (duration, skip) apiSpotPlayEnd()
/api/spot/toggle-pause POST Şube için durdur/devam apiSpotTogglePause()

/api/spot/settings Response Örneği

{
  "enabled": true,
  "songs_between": 10,
  "corporate_id": 38,
  "branch_id": 38,
  "spot_is_paused": false,
  "spot_settings_version": 12,
  "spots": [
    {
      "id": 2,
      "title": "Homemade Kampanya",
      "url": "/storage/tenant1001/...",  // ⚠️ JS'de audio_url bekleniyor!
      "position": 1,
      "duration": 12
    }
  ]
}

5. ENV & Config Değişkenleri

Player Ayarları (.env)

# Audio Format (4 seviyeli öncelik)
MUZIBU_DEFAULT_AUDIO_FORMAT=mp3_auto
MUZIBU_AUDIO_FORCE=           # Boş = kill switch kapalı
MUZIBU_HLS_TIMEOUT=2          # 2 saniye sonra MP3'e düş

# Soft Player (ABR kısıtlama)
MUZIBU_SOFT_PLAYER_VARIANTS=ultralow,low,mid

# Debug
PLAYER_DEBUG=0                # 0=Kapalı, 1=Root, 2=Herkes

# Session
MUZIBU_SESSION_POLLING=30000  # 30 saniye
MUZIBU_SESSION_TTL=7200       # 2 saat

Anons Ayarları (Veritabanı)

# muzibu_corporate_accounts tablosu
spot_enabled = true/false     # Sistem açık mı?
spot_songs_between = 10       # Kaç şarkıda bir
spot_current_index = 0        # Rotation sırası
spot_is_paused = false        # Şube durduruldu mu?
spot_settings_version = 1     # Sync için versiyon

# JavaScript (localStorage)
muzibu_spot_counter = 0-10    # Şarkı sayacı
muzibu_spot_counter_settings  # Settings hash

⚠️ .env'de anons ile ilgili değişken YOK. Tüm ayarlar veritabanında.

6. Çözüm Önerileri

1

listenedDuration Hesaplamasını Düzelt (KRİTİK)

player-core.js satır 2860'daki kodu değiştir:

// ESKİ (YANLIŞ):
const listenedDuration = this.currentTime || this.duration || 0;

// YENİ (DOĞRU):
let listenedDuration = 0;
if (this.playbackStartTime) {
    const currentSession = this.isPlaying
        ? (Date.now() - this.playbackStartTime) : 0;
    listenedDuration = Math.floor(
        (this.totalListenedMs + currentSession) / 1000
    );
}
2

API Response'da audio_url Kullan

CorporateFrontController.php'de url yerine audio_url döndür:

// apiSpotSettings() içinde:
return [
    'id' => $spot->id,
    'title' => $spot->title,
    'audio_url' => $spot->getAudioUrl(),  // 'url' değil!
    'position' => $spot->position,
    'duration' => $spot->duration,
];
3

Debug Log Ekle (Test İçin)

Geçici olarak console.log ekleyerek değerleri kontrol et:

// onTrackEnded() içinde:
console.log('🎙️ DEBUG:', {
    currentTime: this.currentTime,
    duration: this.duration,
    playbackStartTime: this.playbackStartTime,
    totalListenedMs: this.totalListenedMs,
    calculatedDuration: listenedDuration
});
4

Spot Kaydı Olmayan Şirketleri Uyar

Admin panelde spot_enabled=1 ama spot kaydı olmayan şirketleri listele ve uyar.

7. Test Senaryosu

Anons Sistemi Test Adımları

  1. 1 Macro Center (user_id: 2378) veya Shell (user_id: 2384) kullanıcısı ile giriş yap
  2. 2 Console'da MuzibuSpotPlayer.isEnabled() çalıştır → true dönmeli
  3. 3 Console'da MuzibuSpotPlayer.getSongsBetween() çalıştır → 1 dönmeli
  4. 4 Bir şarkı çal, 30+ saniye dinle, şarkı bitsin
  5. 5 Console'da şu log'u gör: 🎙️ SpotPlayer: Song counted. Progress: 1/1
  6. 6 Ardından: 🎙️ SpotPlayer: Time for a spot! ve anons çalmalı

Beklenen Sorun

Şu an adım 5'te Song listened for Xs (< 30s, not counted) mesajı görülecek çünkü listenedDuration yanlış hesaplanıyor.

8. Özet

Bileşen Durum Sorun Aksiyon
listenedDuration Hesaplama HATALI currentTime || duration yanlış Düzelt
API Response (audio_url) UYUMSUZ 'url' döndürülüyor, JS 'audio_url' bekliyor Düzelt
spot-player.js OK - -
Backend API OK - -
Veritabanı Yapısı OK - -
Aktif Spot Kaydı KISITLI Sadece 2 şirketin spotu var Bilgilendirme