FINAL v9 31 Aralik 2025

Muzibu Corporate Spots Sistemi

Kurumsal hesaplar icin sarki arasi sesli spot yayin sistemi

Sistem Ozeti

2

Yeni Tablo

+4

Kolon

Media

Library

song_plays

Kopyasi

Tum Kararlar

Spot atlanabilir
Corporate yukler
Silme yok, arsiv
localStorage sayac
Max 30 MB
30 sn = 1 sarki
MediaLibrary
Tum formatlar

Veritabani (2 Tablo + 4 Kolon)

1 muzibu_corporate_spots

Kolon Tip Aciklama
id BIGINT PK
corporate_account_id BIGINT FK Hangi corporate'a ait
title VARCHAR(255) Spot basligi
slug VARCHAR(255) URL-friendly isim
duration INT Sure (saniye)
starts_at TIMESTAMP NULL Baslangic (NULL = her zaman)
ends_at TIMESTAMP NULL Bitis (NULL = suresiz)
position INT DEFAULT 0 Siralama
is_enabled BOOLEAN DEFAULT TRUE Aktif mi?
is_archived BOOLEAN DEFAULT FALSE Arsivlendi mi?
timestamps TIMESTAMP created_at, updated_at

Dosya: MediaLibrary ile iliskilendirilir. spots->getFirstMedia('audio')

2 muzibu_corporate_spot_plays (song_plays kopyasi)

Kolon Tip Aciklama
id BIGINT PK
spot_id BIGINT FK Hangi spot
corporate_account_id BIGINT FK Hangi sube
user_id BIGINT FK NULL Kim dinledi
ip_address VARCHAR(45) NULL IP adresi
user_agent VARCHAR(255) NULL Tarayici bilgisi
device_type VARCHAR(255) NULL mobile / desktop
browser VARCHAR(50) NULL Chrome, Safari, etc.
platform VARCHAR(50) NULL Windows, iOS, Android
listened_duration INT UNSIGNED NULL Kac saniye dinledi
was_skipped BOOLEAN DEFAULT FALSE Atlandi mi?
created_at TIMESTAMP Basladi
updated_at TIMESTAMP
ended_at TIMESTAMP NULL Bitti
INDEX (spot_id, created_at)
INDEX (corporate_account_id, created_at)
INDEX (user_id)
INDEX (ip_address)
INDEX (device_type)

GUNCELLEME: muzibu_corporate_accounts (+4 kolon)

spot_enabled BOOLEAN DEFAULT TRUE       -- Ana sube: Sistem acik mi?
spot_songs_between INT DEFAULT 10       -- Ana sube: Kac sarkida bir?
spot_current_index INT DEFAULT 0        -- Rotation index
spot_is_paused BOOLEAN DEFAULT FALSE    -- Her sube: Durduruldu mu?

Dosya Yukleme

Spatie MediaLibrary Kullanimi

Model Ayarlari

class CorporateSpot extends Model
    implements HasMedia
{
    use InteractsWithMedia;

    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('audio')
            ->singleFile()
            ->acceptsMimeTypes([
                'audio/mpeg',      // MP3
                'audio/wav',       // WAV
                'audio/ogg',       // OGG
                'audio/aac',       // AAC
                'audio/mp4',       // M4A
            ]);
    }
}

Yukleme Islemi

// Yukleme
$spot->addMediaFromRequest('audio')
    ->usingFileName(Str::slug($title) . '.mp3')
    ->toMediaCollection('audio');

// Okuma
$url = $spot->getFirstMediaUrl('audio');
$path = $spot->getFirstMediaPath('audio');

// Duration almak
$media = $spot->getFirstMedia('audio');
$duration = $media->getCustomProperty('duration');

Dosya Ozellikleri

Max Boyut

30 MB

Formatlar

MP3, WAV, OGG, AAC, M4A

(Tum ses formatlari)

Isimlendirme

Orijinal ismin slug'i

yilbasi-kampanyasi.mp3

Depolama Yolu

// MediaLibrary varsayilan yolu:

storage/app/public/media/{media_id}/{slug}.mp3

// Ornek:

storage/app/public/media/1234/yilbasi-kampanyasi.mp3

// Public URL:

https://muzibu.com/storage/media/1234/yilbasi-kampanyasi.mp3

Sistem Akisi

1
Corporate Spot Yukler

Ses dosyasi (MediaLibrary) + baslik + tarih + sira

2
Sube Kontrol Eder

Durdur/devam (spot_is_paused)

3
Player 30 sn Sayar

localStorage ile sayac tutar (performans)

4
10 Sarkida Spot Calar

Siradaki spot calar, kullanici atlayabilir

5
Dinlenme Loglanir

spot_plays tablosuna (song_plays gibi) detayli kayit

Spot Calmasi Icin Kosullar

SELECT s.*, m.file_name, m.disk
FROM muzibu_corporate_spots s
LEFT JOIN media m ON m.model_id = s.id
    AND m.model_type = 'CorporateSpot'
    AND m.collection_name = 'audio'
WHERE s.corporate_account_id = :main_corporate_id
  AND s.is_enabled = TRUE
  AND s.is_archived = FALSE
  AND (s.starts_at IS NULL OR s.starts_at <= NOW())
  AND (s.ends_at IS NULL OR s.ends_at >= NOW())
ORDER BY s.position ASC

Kurumsal Panel

Spot Yukleme

Dosya adi: yilbasi-kampanyasi.mp3

Dosyayi surukle veya tikla

Max 30 MB • MP3, WAV, OGG, AAC, M4A

Yilbasi Kampanyasi

yilbasi-kampanyasi.mp3

0:00 0:45

Spotlariniz

1

Yilbasi Kampanyasi

0:45 • 1.2 MB • yilbasi-kampanyasi.mp3

25 Ara - 05 Oca

152 dinlenme • 12 atlama

Player & 30 Saniye Kurali

Spot Calarken

SPOT

Yilbasi Kampanyasi

0:27

30 Saniye Kurali & Loglama

// Sarki 30 sn dinlenince sayac artar
function onSongTimeUpdate(currentTime) {
    if (currentTime >= 30 && !this.songCounted) {
        this.songCounted = true;
        let count = parseInt(localStorage.getItem('spot_count') || '0');
        count++;

        if (count >= this.spotSongsBetween) {
            this.playNextSpot();
            localStorage.setItem('spot_count', '0');
        } else {
            localStorage.setItem('spot_count', count.toString());
        }
    }
}

// Spot bitince veya atlaninca - DETAYLI LOG
async function logSpotPlay(spot, wasSkipped, listenedDuration) {
    await fetch('/api/spot/played', {
        method: 'POST',
        body: JSON.stringify({
            spot_id: spot.id,
            was_skipped: wasSkipped,
            listened_duration: listenedDuration,
            // Backend otomatik ekler:
            // user_id, ip_address, user_agent,
            // device_type, browser, platform
        })
    });
}

API Endpoints

Corporate

GET /api/corporate/spot-settings
PUT /api/corporate/spot-settings
GET /api/corporate/spots
POST /api/corporate/spots ← MediaLibrary upload
PUT /api/corporate/spots/{id}
POST /api/corporate/spots/reorder
POST /api/corporate/spots/{id}/archive
POST /api/corporate/spots/{id}/unarchive
GET /api/corporate/spots/{id}/stats

Sube

POST /api/branch/spots/pause
POST /api/branch/spots/resume

Player

GET /api/spot/init
GET /api/spot/next
POST /api/spot/played ← Detayli log (song_plays gibi)

Gelistirme Sirasi

1 Veritabani

2 migration + 2 model + MediaLibrary

2 Kurumsal Panel

CRUD + upload + istatistik

3 Sube Widget

Durdur/devam

4 Player JS

30 sn kurali + spot calar + loglama

5 Test

Migration + build + test