HLS 4 Saniye Production v5

HLS 4-Saniye Standardizasyon

Production Deployment Rehberi + Claude Prompt

Basit Anlatim Teknik Detay Production Adimlari Dogrulama Hata Yonetimi Player Fix MP3 64k Claude Prompt Test Sonuclari

📝 Basit Anlatim (Herkes Icin)

Muzibu'daki sarkilar dinlenirken kucuk parcalar halinde (segment) yukleniyor. Onceden bu parcalar 6 saniyeydi, simdi tum kalite seviyelerinde 4 saniye olarak standardize edildi.

Onceki Durum

  • High kalite: 6 saniye segment
  • Diger kaliteler: 4 saniye segment
  • Tutarsiz FFmpeg parametreleri
  • Eski olu kodlar mevcut

Simdiki Durum

  • Tum kaliteler: 4 saniye segment
  • Standart FFmpeg parametreleri
  • Olu kodlar temizlendi
  • Production'a hazir

Neden Onemli? 4 saniye segment, Apple HLS standardina uygun ve tum varyantlar arasinda tutarlilik sagliyor. Bu sayede adaptive bitrate (otomatik kalite gecisi) daha yumusak calisiyor.

🚨 mztest'te Tespit Edilen Sorun: OPcache

Kod degisiklikleri yapilip cache temizlendikten sonra, yeni eklenen 83 sarki hala eski formatla uretildi:

Eski Format (Horizon eski kodu kullanmis)

  • ❌ 10sn segment (4sn olmasi lazim)
  • ❌ VOD tipi yok
  • ❌ Varyant yok (ultralow/low/mid)
  • ❌ MP3 128k yok
  • ❌ master.m3u8 yok
  • ❌ enc.keyinfo storage URL (403 hatasi)

Dogru Format (opcache temizlendikten sonra)

  • ✅ 4sn segment
  • ✅ VOD tipi
  • ✅ 4 varyant (ultralow + low + mid + high)
  • ✅ MP3 128k
  • ✅ master.m3u8 (4 varyant)
  • ✅ enc.keyinfo /hls-key/ URI

Cozum: curl -s -k https://domain.com/opcache-reset.php calistir. Horizon worker'lari yeni kodu gorecek. Production'da ADIM 1'deki opcache-reset adimini ATLAMA!

🔧 Teknik Detaylar (Gelistiriciler Icin)

Yapilan Kod Degisiklikleri

# Dosya Degisiklik
1 ConvertToHLSJob.php FFmpeg'e -profile:a aac_low -ar 48000 -ac 2 eklendi
2a HLSService.php:125 $targetBitrate undefined bug fix
2b HLSService.php:158 buildFFmpegCommand() internal helper olarak isaretlendi
3 AddHlsVariantsCommand.php --re-encode-high flag'i eklendi (high'i 4sn ile yeniden olusturur)
4 ConvertSongToHLS.php Silindi (olu kod)
5 routes/web.php /stream/key/ eski route kaldirildi
6 hls-streaming.blade.php Dokumantasyon guncellendi

Her Sarki Dosya Yapisi

storage/tenant{id}/app/public/muzibu/hls/{song_id}/
├── enc.bin              ← 16 byte AES-128 key (binary)
├── enc.keyinfo          ← 3 satir: URI + path + IV
├── master.m3u8          ← 4 varyant referansi
├── playlist.m3u8        ← high kalite (4sn, VOD, encrypted)
├── segment-*.ts         ← high segment'ler
├── ultralow/            ← 32kbps, mono, 22050Hz
├── low/                 ← 64kbps, mono, 22050Hz
└── mid/                 ← 128kbps, stereo, 44100Hz

storage/tenant{id}/app/public/muzibu/songs/mp3_128/
└── {song_id}.mp3        ← 128kbps MP3 fallback

storage/tenant{id}/app/public/muzibu/songs/mp3_64/
└── {song_id}.mp3        ← 64kbps MP3 son care fallback

🚀 Production Deployment (~30K Sarki)

Ana sunucuda adim adim yapilacaklar. Sirasini BOZMA!

1

Kodu Cek + Cache Temizle

cd /var/www/vhosts/muzibu.com/httpdocs

# Kodu cek
git pull origin main

# Cache temizle (route degisti, eski /stream/key/ kaldirildi)
php artisan cache:clear
php artisan route:clear
php artisan config:clear
php artisan view:clear
composer dump-autoload

# KRITIK: OPcache temizle (yoksa Horizon eski kodu calistirir!)
curl -s -k https://muzibu.com/opcache-reset.php

# Route ve config yeniden cache'le
php artisan config:cache
php artisan route:cache

KRITIK UYARI: opcache-reset.php MUTLAKA calistirilmali! mztest'te bu adim atlaninca Horizon eski ConvertToHLSJob kodunu kullanmaya devam etti ve yeni eklenen 83 sarki 10sn segment + VOD'suz + varyant'siz olarak uretildi. Opcache temizlenmezse ayni hata production'da da olur.

Neden? PHP OPcache, dosya degisse bile eski bytecode'u RAM'de tutar. Horizon worker'lari surekli calisan process'ler oldugu icin yeni kodu ancak opcache temizlenince gorur.

2

Dry-Run (Sadece Say, Dokunma)

php artisan tenants:run hls:add-variants --tenants=1001 \
    --option="quality=all" \
    --option="mp3-128=1" \
    --option="mp3-64=1" \
    --option="refresh-master=1" \
    --option="re-encode-high=1" \
    --option="dry-run=1"

Beklenen cikti: "Toplam HLS: ~30000, Islenecek: ~30000". Hicbir dosyaya dokunmaz, sadece sayar.

3

Kucuk Batch Test (10 Sarki)

php artisan tenants:run hls:add-variants --tenants=1001 \
    --option="quality=all" \
    --option="mp3-128=1" \
    --option="mp3-64=1" \
    --option="refresh-master=1" \
    --option="re-encode-high=1" \
    --option="limit=10"

Beklenen: "10 basarili, 0 basarisiz". ~3-5 dakika surer.

4

Test Sonucunu Dogrula

HLS_BASE="storage/tenant1001/app/public/muzibu/hls"

# Ilk 10 sarkinin hepsini kontrol et
GOOD=0; BAD=0; COUNT=0
for DIR in $(ls -d $HLS_BASE/*/ | head -10); do
    [ ! -f "$DIR/master.m3u8" ] && continue
    COUNT=$((COUNT + 1))

    # Segment suresi (4.xxx olmali, 6.xxx olmamali)
    MAX=$(grep '#EXTINF:' "$DIR/playlist.m3u8" | sed 's/#EXTINF://' | sed 's/,.*//' | sort -rn | head -1)
    INT=$(echo "$MAX" | cut -d. -f1)

    # 4 varyant olmali
    HAS_ALL=1
    for V in ultralow low mid; do
        [ ! -f "$DIR/$V/playlist.m3u8" ] && HAS_ALL=0
    done

    # VOD olmali
    HAS_VOD=0
    grep -q '#EXT-X-PLAYLIST-TYPE:VOD' "$DIR/playlist.m3u8" && HAS_VOD=1

    if [ "$INT" -le 4 ] && [ "$HAS_ALL" -eq 1 ] && [ "$HAS_VOD" -eq 1 ]; then
        GOOD=$((GOOD + 1))
    else
        BAD=$((BAD + 1))
        echo "SORUN: $(basename $DIR) max=$MAX varyant=$HAS_ALL vod=$HAS_VOD"
    fi
done
echo "Kontrol: $COUNT sarki, $GOOD OK, $BAD SORUNLU"

Beklenen: "10 OK, 0 SORUNLU". Sorun varsa DURMA, once analiz et.

5

Tam Re-encode (3 Paralel Terminal)

~7 SAAT

3 ayri terminal ac. Her birinde farkli offset ile calistir. screen veya tmux kullan ki terminal kapansa da devam etsin!

TERMINAL 1 — Sarki 1 - 10.000

screen -S hls-batch1
php artisan tenants:run hls:add-variants --tenants=1001 \
    --option="quality=all" \
    --option="mp3-128=1" \
    --option="mp3-64=1" \
    --option="refresh-master=1" \
    --option="re-encode-high=1" \
    --option="limit=10000" \
    --option="offset=0"

TERMINAL 2 — Sarki 10.001 - 20.000

screen -S hls-batch2
php artisan tenants:run hls:add-variants --tenants=1001 \
    --option="quality=all" \
    --option="mp3-128=1" \
    --option="mp3-64=1" \
    --option="refresh-master=1" \
    --option="re-encode-high=1" \
    --option="limit=10000" \
    --option="offset=10000"

TERMINAL 3 — Sarki 20.001 - 30.000

screen -S hls-batch3
php artisan tenants:run hls:add-variants --tenants=1001 \
    --option="quality=all" \
    --option="mp3-128=1" \
    --option="mp3-64=1" \
    --option="refresh-master=1" \
    --option="re-encode-high=1" \
    --option="limit=10000" \
    --option="offset=20000"

Tahmini Sure: ~30K sarki x ~20sn/sarki = ~7 saat (3 paralel). mztest'te 66 sarki 22 dakikada bitti.

screen kullanimi: Ctrl+A D = ayir (arka planda calisir), screen -r hls-batch1 = geri baglan

6

Son Dogrulama (3 Batch Bittikten Sonra)

HLS_BASE="storage/tenant1001/app/public/muzibu/hls"

echo "=== GENEL DURUM ==="
echo "Toplam HLS klasoru: $(ls -d $HLS_BASE/*/ 2>/dev/null | wc -l)"
echo "master.m3u8 olan: $(ls $HLS_BASE/*/master.m3u8 2>/dev/null | wc -l)"
echo "MP3 128k: $(ls storage/tenant1001/app/public/muzibu/songs/mp3_128/*.mp3 2>/dev/null | wc -l)"
echo "MP3 64k: $(ls storage/tenant1001/app/public/muzibu/songs/mp3_64/*.mp3 2>/dev/null | wc -l)"

echo ""
echo "=== RASTGELE 20 SARKI KONTROL ==="
GOOD=0; BAD=0
for DIR in $(ls -d $HLS_BASE/*/ | shuf | head -20); do
    [ ! -f "$DIR/master.m3u8" ] && continue
    MAX=$(grep '#EXTINF:' "$DIR/playlist.m3u8" | sed 's/#EXTINF://' | sed 's/,.*//' | sort -rn | head -1)
    INT=$(echo "$MAX" | cut -d. -f1)
    HAS_ALL=1
    for V in ultralow low mid; do
        [ ! -f "$DIR/$V/playlist.m3u8" ] && HAS_ALL=0
    done
    if [ "$INT" -le 4 ] && [ "$HAS_ALL" -eq 1 ]; then
        GOOD=$((GOOD + 1))
    else
        BAD=$((BAD + 1))
        echo "SORUN: $(basename $DIR)"
    fi
done
echo "Sonuc: $GOOD OK, $BAD SORUNLU"
7

Final Cache Temizligi

php artisan cache:clear
php artisan view:clear
php artisan responsecache:clear

Dogrulama Kontrol Listesi

Kontrol Beklenen Nasil Kontrol?
High segment suresi ~4.0xx sn grep '#EXTINF:' playlist.m3u8 | head -3
master.m3u8 varyant sayisi 4 (ultralow + low + mid + original) cat master.m3u8
Varyant klasorleri ultralow/ + low/ + mid/ mevcut ls -d */
enc.keyinfo URI /hls-key/muzibu/songs/{id} head -1 enc.keyinfo
Playlist tipi #EXT-X-PLAYLIST-TYPE:VOD grep PLAYLIST-TYPE playlist.m3u8
MP3 128k dosyasi mp3_128/{song_id}.mp3 mevcut ls songs/mp3_128/ | wc -l
MP3 64k dosyasi mp3_64/{song_id}.mp3 mevcut ls songs/mp3_64/ | wc -l

⚠️ Hata Yonetimi + Guvenlik Garantileri

Durum Ne Olur? Risk
MP3 dosyasi yok Atlar, failed sayar, devam eder Yok
HLS klasoru yok Atlar Yok
FFmpeg hata Log'lar, failed sayar, devam eder Yok
enc.keyinfo yok re-encode atlar, variant eklemeye devam Yok
Zaten variant var Atlar (uzerine yazmaz) Yok
Disk dolu FFmpeg hata verir, log'lanir, devam eder Orta
Terminal kapanirsa screen kullan! Orta
Islem ortasinda durur Ayni komutu tekrar calistir, mevcut olanlari atlar Yok

Onemli Guvenlik Notu

  • • Orijinal MP3'ler HICBIR ZAMAN silinmez veya degistirilmez
  • • enc.bin (encryption key) korunur, sadece segment'ler yeniden uretilir
  • • Islem sirasinda sarkilar calismaya devam eder (mevcut segment'ler silinip yerine yenileri yazilir)
  • • Komut hatada durmaz, devam eder ve sonunda rapor verir

Rollback Plani

En kotu senaryoda geri almak icin:

  1. Kod degisikliklerini geri al: git checkout -- .
  2. Orijinal MP3'ler her zaman mevcut
  3. Yeniden HLS donusumu icin: ConvertToHLSJob zaten 4sn + varyant uretiyor
  4. Tek sarki test: --option="song=12345" ile belirli sarki test et

🎵 Player Fix: MEDIA_ERR_DECODE Auto-Skip

Re-encode sirasinda player'da PIPELINE_ERROR_DECODE (code: 3) hatasi olustu. Sebep: Re-encode arka planda calisirken segment dosyalari silinip yeniden yazildi, player tam o anki segment'i okuyunca decode hatasi aldi.

Hata Mesaji

PIPELINE_ERROR_DECODE: Failed to send audio packet for decoding:
{timestamp=20000000 duration=10666 size=688 is_key_frame=1 encrypted=0}

encrypted=0 → Segment decrypt edilmis ama yarim yazilmis dosya oldugu icin decode basarisiz.

Uygulanan Fix

player-core.js dosyasina auto-skip mekanizmasi eklendi:

  • MEDIA_ERR_DECODE (code 3) veya MEDIA_ERR_NETWORK (code 2) oldugunda
  • • 500ms bekle → otomatik nextTrack() cagir
  • • Player durmak yerine sonraki sarkiya gecer
  • • Hem ana oynatma hem preloaded audio error handler'larina eklendi

Production Icin Not

Re-encode sirasinda kullanicilar dinliyorsa ayni hata olusabilir. Auto-skip sayesinde player durmayacak, sonraki sarkiya gececek. Re-encode bitince bu hata tamamen kaybolur.

📡 MP3 64k Fallback Sistemi

Basit Aciklama (Herkes Icin)

64kbps MP3 en dusuk kaliteli son care yedek. HLS calismadiginda ve 128k MP3 de basarisiz oldugunda devreye girer. Cok yavas baglantilarda veya cok eski cihazlarda bile sarkilarin calmasini garanti eder.

Teknik Detaylar

Dosya Konumu mp3_64/{song_id}.mp3 — mono, 22050Hz, 64kbps
Serve SongController'da serveAudioCdn() zaten mp3_64 destekliyor
Fallback Zinciri HLSmp3_128mp3_64orijinal MP3 (64k yoksa 128k'ya duser)
Test Parametresi Player'da ?_mz=s1 parametresi ile test edilebilir (root kullanicilar)
Kullanim Senaryosu Cok yavas baglanti, cok eski cihaz, HLS + 128k her ikisi de basarisiz
FFmpeg Parametreleri -b:a 64k -ar 22050 -ac 1 -map_metadata -1 -vn -y
Dosya Boyutu Orijinal ~5MB → MP3 64k ~480KB (~10x kucuk)

Orijinal MP3

~5 MB

320kbps, stereo

MP3 128k

~1.5 MB

128kbps, stereo

MP3 64k

~480 KB

64kbps, mono, 22050Hz

🔑 enc.keyinfo URI Toplu Fix (Production Icin Kritik!)

Re-encode komutu varyant enc.keyinfo dosyalarini dogru URI ile olusturur ama Horizon tarafindan uretilen ana enc.keyinfo'ya dokunmaz. Eski kodla uretilen sarkilarda URI hala storage URL'e isaret eder → 403 hatasi.

Fix Script (Production'da Re-encode Sonrasi Calistir!)

cd /var/www/vhosts/muzibu.com/httpdocs
HLS_BASE="storage/tenant1001/app/public/muzibu/hls"
DOMAIN="https://muzibu.com"

fixed=0
for dir in $HLS_BASE/*/; do
    id=$(basename "$dir")
    for keyinfo in "$dir/enc.keyinfo" "$dir/ultralow/enc.keyinfo" "$dir/low/enc.keyinfo" "$dir/mid/enc.keyinfo"; do
        [ ! -f "$keyinfo" ] && continue
        uri=$(head -1 "$keyinfo")
        if echo "$uri" | grep -q "storage"; then
            variant=""
            case "$keyinfo" in
                */ultralow/*) variant="?v=ultralow" ;;
                */low/*) variant="?v=low" ;;
                */mid/*) variant="?v=mid" ;;
            esac
            new_uri="${DOMAIN}/hls-key/muzibu/songs/${id}${variant}"
            sed -i "1s|.*|${new_uri}|" "$keyinfo"
            fixed=$((fixed + 1))
        fi
    done
done
echo "Duzeltildi: $fixed enc.keyinfo dosyasi"

Bu fix'i ATLAMA! mztest'te 332 dosya (83 ana + 249 varyant) yanlis URI ile uretilmisti. Production'da cok daha fazla olacak.

🤖 Claude Prompt (Production Sunucuya Kopyala-Yapistir)

Asagidaki prompt'u production sunucudaki Claude'a ver. Tum islemleri otomatik yapacak.

KOPYALA
## GOREV: Muzibu HLS Standardizasyon — Production (~30K Sarki)

Kullanicilar su an orijinal MP3 dinliyor. Orijinal MP3 dosyalarina DOKUNULMAYACAK.
Amac: Her sarki icin HLS varyantlari + MP3 fallback dosyalari URETMEK.

Detayli bilgi icin bu dosyayi oku:
public/readme/2026/02/22/hls-4sn-standardizasyon/index.html

## Her sarki icin uretilecekler:
- HLS high: 4sn segment, VOD, AES-128 encrypted (orijinal bitrate)
- HLS ultralow: 32kbps, mono, 22050Hz, 4sn segment
- HLS low: 64kbps, mono, 22050Hz, 4sn segment
- HLS mid: 128kbps, stereo, 44100Hz, 4sn segment
- master.m3u8: 4 varyant referansi
- MP3 128k: 128kbps stereo fallback
- MP3 64k: 64kbps mono son care fallback
- enc.keyinfo URI: /hls-key/muzibu/songs/{id} formatinda

## ADIMLAR (SIRAYLA!)

### 1. Kod cek + cache temizle
```bash
cd /var/www/vhosts/muzibu.com/httpdocs
git pull origin main
php artisan cache:clear && php artisan route:clear && php artisan config:clear && php artisan view:clear
composer dump-autoload
curl -s -k https://muzibu.com/opcache-reset.php
php artisan config:cache && php artisan route:cache
```
opcache-reset KRITIK! Yoksa Horizon eski kodu kullanir.

### 2. Dry-run
```bash
php artisan tenants:run hls:add-variants --tenants=1001 \
    --option="quality=all" --option="mp3-128=1" --option="mp3-64=1" \
    --option="refresh-master=1" --option="re-encode-high=1" \
    --option="dry-run=1"
```
Beklenen: "Toplam HLS: ~30000, Islenecek: ~30000". Bana sonucu raporla.

### 3. 10 sarki test
```bash
php artisan tenants:run hls:add-variants --tenants=1001 \
    --option="quality=all" --option="mp3-128=1" --option="mp3-64=1" \
    --option="refresh-master=1" --option="re-encode-high=1" \
    --option="limit=10"
```
Beklenen: "10 basarili, 0 basarisiz". Ilk 10 sarkiyi dogrula:
- playlist.m3u8: #EXTINF ~4.0xx (6.xxx OLMAMALI)
- master.m3u8: 4 varyant (ultralow + low + mid + original)
- enc.keyinfo 1. satir: /hls-key/ ile baslamali (storage OLMAMALI)
- #EXT-X-PLAYLIST-TYPE:VOD olmali
- mp3_128/{id}.mp3 ve mp3_64/{id}.mp3 mevcut olmali
Bana sonucu raporla. Sorun varsa DURMA.

### 4. Tam re-encode (3 paralel terminal)
```bash
# Terminal 1 (screen -S hls-batch1)
php artisan tenants:run hls:add-variants --tenants=1001 \
    --option="quality=all" --option="mp3-128=1" --option="mp3-64=1" \
    --option="refresh-master=1" --option="re-encode-high=1" \
    --option="limit=10000" --option="offset=0"

# Terminal 2 (screen -S hls-batch2)
php artisan tenants:run hls:add-variants --tenants=1001 \
    --option="quality=all" --option="mp3-128=1" --option="mp3-64=1" \
    --option="refresh-master=1" --option="re-encode-high=1" \
    --option="limit=10000" --option="offset=10000"

# Terminal 3 (screen -S hls-batch3)
php artisan tenants:run hls:add-variants --tenants=1001 \
    --option="quality=all" --option="mp3-128=1" --option="mp3-64=1" \
    --option="refresh-master=1" --option="re-encode-high=1" \
    --option="limit=10000" --option="offset=20000"
```
screen kullan — terminal kapansa da devam etsin.

### 5. enc.keyinfo URI fix
Re-encode sonrasi eski kodla uretilmis enc.keyinfo'lardaki storage URL'leri duzelt:
```bash
cd /var/www/vhosts/muzibu.com/httpdocs
HLS_BASE="storage/tenant1001/app/public/muzibu/hls"
DOMAIN="https://muzibu.com"
fixed=0
for dir in $HLS_BASE/*/; do
    id=$(basename "$dir")
    for keyinfo in "$dir/enc.keyinfo" "$dir/ultralow/enc.keyinfo" "$dir/low/enc.keyinfo" "$dir/mid/enc.keyinfo"; do
        [ ! -f "$keyinfo" ] && continue
        uri=$(head -1 "$keyinfo")
        if echo "$uri" | grep -q "storage"; then
            variant=""
            case "$keyinfo" in */ultralow/*) variant="?v=ultralow";; */low/*) variant="?v=low";; */mid/*) variant="?v=mid";; esac
            sed -i "1s|.*|${DOMAIN}/hls-key/muzibu/songs/${id}${variant}|" "$keyinfo"
            fixed=$((fixed + 1))
        fi
    done
done
echo "Duzeltildi: $fixed dosya"
```

### 6. Final dogrulama + cache temizligi
```bash
php artisan cache:clear && php artisan view:clear && php artisan responsecache:clear
```
Rastgele 20 sarki kontrol et ve bana su bilgileri raporla:
- Toplam HLS klasor sayisi
- master.m3u8 olan sarki sayisi
- MP3 128k dosya sayisi
- MP3 64k dosya sayisi
- 20 rastgele sarkida: segment suresi (4sn mi?), varyant sayisi, VOD tipi, enc.keyinfo URI

## KURALLAR
- Orijinal MP3'lere DOKUNMA (sadece okunur, kaynak dosya)
- Servis restart YAPMA (apache, nginx, redis)
- Migration YOK, sadece dosya uretimi
- Hata olursa komut durmaz, sayar ve devam eder
- Kesilirse ayni komutu tekrar calistir (mevcut dosyalari atlar)
- Her adim sonrasi bana durum raporla

Test Sunucusu Sonuclari (mztest.muzibu.com)

149/149 basarili, 0 hata, 1 saat 18 dakika

Kontrol Sonuc
High segment suresi 149/149 = 4sn
6sn eski segment 0 (tamamen temizlendi)
master.m3u8 (4 varyant) 149/149
enc.keyinfo URI (/hls-key/) 149/149
VOD tipi 149/149
MP3 128k 149/149
MP3 64k 149/149
Re-encode suresi 1 saat 18 dakika (149 sarki)
enc.keyinfo URI fix 332 dosya (83 ana + 249 varyant)
Basarisiz 0

⚙️ Artisan Command Referansi

php artisan tenants:run hls:add-variants --tenants=1001

Secenekler:
  --option="quality=all"        Tum varyantlar (ultralow + low + mid)
  --option="quality=low"        Sadece low varyant
  --option="mp3-128=1"          128kbps MP3 de uret
  --option="mp3-64=1"           64kbps MP3 de uret (son care fallback)
  --option="refresh-master=1"   master.m3u8'i yeniden olustur
  --option="re-encode-high=1"   High playlist'i 4sn segment ile yeniden olustur
  --option="song=123"           Belirli bir sarki ID
  --option="limit=100"          Maksimum islenecek sarki
  --option="offset=0"           Atlanacak sarki (paralel batch icin)
  --option="dry-run=1"          Sadece sayilari goster, islem yapma
22-23 Subat 2026 • Muzibu.com.tr