Basit Anlatım (Herkes İçin)
v2'ye ek olarak ne sorun var?
- Ana şube anonsun ismini değiştiriyor → Şubeler eski ismi görüyor
- Anons sıralaması değişiyor → Şubeler eski sırayla çalıyor
- Anons aktif/pasif yapılıyor → Şubeler eski durumu kullanıyor
- Anons arşivleniyor → Şubeler hala çalmaya çalışıyor
- Başlangıç/bitiş tarihi değişiyor → Şubeler eski tarihe göre çalıyor
- Yeni anons ekleniyor → Şubeler görmüyor
v3'te ne yapacağız?
- Anons içeriği değişince → Tüm şubeler otomatik günceller
- Sıralama değişince → Rotation sırası yeniden hesaplanır
- Aktif/Pasif/Arşiv → Player anında uyarlanır
- Preload'lı spot değişirse → İptal edilir, yenisi yüklenir
- Yeni anons → 30 saniye içinde tüm şubeler görür
Örnek Senaryo 3:
Ana şube "Yılbaşı Kampanyası" anonsunu arşivler. 30 saniye içinde tüm şubelerin player'ları bu anosu atlayıp bir sonrakine geçer. Preload'da bu anons varsa iptal edilir!
Version Artırıcı Olaylar (10 Tetikleyici)
Ayar Değişiklikleri (3)
-
1
spot_enableddeğişir -
2
spot_songs_betweendeğişir -
3
spot_current_indexsıfırlanır
Anons İçerik (4)
-
4
titledeğişir -
5
starts_at / ends_atdeğişir -
6
is_enableddeğişir -
7
is_archiveddeğişir
CRUD İşlemleri (2)
- 8 Yeni anons eklenir
- 9 Anons silinir
Sıralama (1)
-
10
positiondeğişir (reorder)
⚡ Otomatik Tetikleme:
Bu 10 olaydan herhangi biri gerçekleşince spot_settings_version otomatik artırılır.
Laravel Observer kullanarak tüm değişiklikler yakalanır.
Teknik Detaylar (Geliştiriciler İçin)
Observer Pattern (Otomatik)
1. CorporateSpotObserver Oluştur
Dosya: Modules/Muzibu/app/Observers/CorporateSpotObserver.php
<?php
namespace Modules\Muzibu\App\Observers;
use Modules\Muzibu\App\Models\CorporateSpot;
use Illuminate\Support\Facades\DB;
class CorporateSpotObserver
{
/**
* Anons oluşturulduğunda
*/
public function created(CorporateSpot $spot)
{
$this->incrementVersion($spot);
}
/**
* Anons güncellendiğinde
* İzlenen field'ler: title, starts_at, ends_at, is_enabled, is_archived, position
*/
public function updated(CorporateSpot $spot)
{
// Sadece önemli field'ler değiştiyse version artır
$trackedFields = ['title', 'starts_at', 'ends_at', 'is_enabled', 'is_archived', 'position'];
foreach ($trackedFields as $field) {
if ($spot->isDirty($field)) {
$this->incrementVersion($spot);
break;
}
}
}
/**
* Anons silindiğinde
*/
public function deleted(CorporateSpot $spot)
{
$this->incrementVersion($spot);
}
/**
* Version'ı artır
*/
protected function incrementVersion(CorporateSpot $spot)
{
DB::table('muzibu_corporate_accounts')
->where('id', $spot->corporate_account_id)
->update([
'spot_settings_version' => DB::raw('spot_settings_version + 1'),
'updated_at' => now()
]);
}
}
2. Observer'ı Kaydet
Dosya: Modules/Muzibu/Providers/MuzibuServiceProvider.php
use Modules\Muzibu\App\Models\CorporateSpot;
use Modules\Muzibu\App\Observers\CorporateSpotObserver;
public function boot()
{
// ...
// ✅ Observer kaydet
CorporateSpot::observe(CorporateSpotObserver::class);
}
3. Reorder İşleminde Version Artır
Dosya: CorporateFrontController::reorderSpots()
public function reorderSpots(Request $request)
{
// ... (mevcut sıralama kodu)
// ✅ YENİ: Sıralama değişti, version artır
$account->update([
'spot_settings_version' => DB::raw('spot_settings_version + 1')
]);
return response()->json([
'success' => true,
'message' => 'Sıralama güncellendi.',
'spot_settings_version' => $account->fresh()->spot_settings_version
]);
}
API Response (Spot Listesi Ekle)
API: Spot Listesini Dön
Dosya: Modules/Muzibu/app/Http/Controllers/Api/SpotController.php
public function settings(Request $request)
{
// ... (mevcut kod)
// ✅ YENİ: Spot listesini de dön (aktif, sıralı)
$spots = CorporateSpot::where('corporate_account_id', $parentAccount->id)
->currentlyActive() // is_enabled=true, is_archived=false, tarih kontrolü
->ordered() // position ASC
->get(['id', 'title', 'slug', 'audio_url', 'duration', 'position', 'starts_at', 'ends_at'])
->map(function($spot) {
return [
'id' => $spot->id,
'title' => $spot->title,
'slug' => $spot->slug,
'audio_url' => $spot->getAudioUrl(),
'duration' => $spot->duration,
'position' => $spot->position,
'starts_at' => $spot->starts_at?->toISOString(),
'ends_at' => $spot->ends_at?->toISOString(),
];
});
return response()->json([
'enabled' => $effectiveEnabled,
'spot_enabled' => $parentAccount->spot_enabled,
'spot_is_paused' => $account->spot_is_paused,
'songs_between' => $parentAccount->spot_songs_between ?? 10,
'corporate_id' => $parentAccount->id,
'branch_id' => $account->id,
'spot_settings_version' => $parentAccount->spot_settings_version ?? 1,
'spots' => $spots, // ✅ YENİ: Spot listesi
]);
}
JavaScript: Spot Listesi + Preload İptali
JavaScript: checkSettingsUpdate() Genişlet
Dosya: public/themes/muzibu/js/player/features/spot-player.js
const state = {
enabled: false,
spotEnabled: true,
isPaused: false,
songsBetween: 10,
songsPlayed: 0,
currentVersion: 1,
checkInterval: null,
spotsList: [], // ✅ YENİ: Spot listesi
preloadedSpot: null,
preloadedAudio: null,
};
async function checkSettingsUpdate() {
try {
const response = await fetch('/api/spot/settings');
const data = await response.json();
// Version farklıysa güncelle!
if (data.spot_settings_version !== state.currentVersion) {
console.log('🎙️ SpotPlayer: Settings/Spots updated! Version:', data.spot_settings_version);
// ✅ Ayarları güncelle
state.songsBetween = data.songs_between || 10;
state.spotEnabled = data.spot_enabled;
state.isPaused = data.spot_is_paused;
state.enabled = data.enabled;
state.currentVersion = data.spot_settings_version;
// ✅ YENİ: Spot listesini güncelle
state.spotsList = data.spots || [];
// ✅ Preloaded spot geçersiz mi kontrol et
if (state.preloadedSpot) {
const stillValid = state.spotsList.find(s => s.id === state.preloadedSpot.id);
if (!stillValid) {
console.log('🎙️ SpotPlayer: Preloaded spot is no longer valid, clearing...');
clearPreload(true); // src'yi de sil
}
}
// Sayacı sıfırla
resetCounter();
// UI güncelle
window.dispatchEvent(new CustomEvent('spot-settings-updated', {
detail: {
songsBetween: state.songsBetween,
spotEnabled: state.spotEnabled,
isPaused: state.isPaused,
enabled: state.enabled,
spots: state.spotsList // ✅ YENİ
}
}));
}
} catch (e) {
console.error('🎙️ SpotPlayer: Failed to check settings', e);
}
}
// ✅ YENİ: playNextSpot() - Liste kullan
async function playNextSpot() {
if (!state.enabled || state.spotsList.length === 0) {
console.log('🎙️ SpotPlayer: No spots available');
resetCounter();
return null;
}
// Rotation: Sıradaki spot
const currentIndex = state.currentSpot ?
state.spotsList.findIndex(s => s.id === state.currentSpot.id) : -1;
const nextIndex = (currentIndex + 1) % state.spotsList.length;
const spot = state.spotsList[nextIndex];
state.currentSpot = spot;
state.wasSkipped = false;
state.spotStartTime = Date.now();
await logPlayStart(spot.id);
resetCounter();
console.log('🎙️ SpotPlayer: Playing spot:', spot.title);
return spot;
}
Uygulama Adımları
CorporateSpotObserver Oluştur
Anons değişikliklerini otomatik yakala
Observer'ı ServiceProvider'a Kaydet
MuzibuServiceProvider::boot()
Reorder İşleminde Version Artır
CorporateFrontController::reorderSpots()
API'ye Spot Listesi Ekle
SpotController::settings() - Aktif spot listesini dön
JavaScript'i Güncelle
spot-player.js - Spot listesi sync + preload invalidation
Test Et (10 Senaryo)
- • Anons ekle → 30s içinde tüm şubeler görür
- • Anons sil → 30s içinde kaldırılır
- • İsim değiştir → 30s içinde yeni isim görünür
- • Sıralama değiştir → 30s içinde yeni sıra uygulanır
- • Aktif/Pasif → 30s içinde anons atlanır/eklenir
- • Arşivle → 30s içinde anons kaldırılır
- • Tarih değiştir → 30s içinde tarih kontrolü güncellenir
- • Preloaded spot'u sil → Preload iptal edilir
- • Global kapat → Tüm şubeler durur
- • Çalma aralığı değiştir → Sayaç sıfırlanır
Önemli Notlar
-
Observer Pattern:
Tüm değişiklikler otomatik yakalanır, manuel version++ yapmaya gerek kalmaz.
-
Spot Listesi:
API her istekte aktif spot listesini döner, player client-side filter yapmaz.
-
Preload Invalidation:
Preload'lı spot silinir/arşivlenir/pasif olursa otomatik iptal edilir.
-
Rotation Senkronizasyonu:
Spot listesi güncellenince rotation sırası yeniden hesaplanır.
-
Cache Stratejisi:
API response 30 saniye cache'lenebilir (version değişince cache clear).
-
10 Tetikleyici:
Ayar (3) + İçerik (4) + CRUD (2) + Sıralama (1) = Toplam 10 olay version artırır.
Versiyon Karşılaştırması
| Özellik | v1 | v2 | v3 |
|---|---|---|---|
| Çalma Aralığı Sync | |||
| Aktif/Pasif Sync | |||
| Ana Şube Global Kapatma | |||
| Anons İçerik Sync | |||
| Sıralama Sync | |||
| Anons Ekle/Sil Sync | |||
| Preload Invalidation | |||
| Observer Pattern |
v3 = Tam Dinamik Senkronizasyon
Ayarlar, anons içeriği, sıralama, CRUD - Her şey otomatik, 30 saniyede senkronize!