Production Deployment Rehberi + Claude Prompt
Muzibu'daki sarkilar dinlenirken kucuk parcalar halinde (segment) yukleniyor. Onceden bu parcalar 6 saniyeydi, simdi tum kalite seviyelerinde 4 saniye olarak standardize edildi.
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.
Kod degisiklikleri yapilip cache temizlendikten sonra, yeni eklenen 83 sarki hala eski formatla uretildi:
Eski Format (Horizon eski kodu kullanmis)
Dogru Format (opcache temizlendikten sonra)
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!
| # | 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 |
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
Ana sunucuda adim adim yapilacaklar. Sirasini BOZMA!
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.
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.
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.
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.
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
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"
php artisan cache:clear
php artisan view:clear
php artisan responsecache:clear
| 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 |
| 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 |
En kotu senaryoda geri almak icin:
git checkout -- .--option="song=12345" ile belirli sarki test etRe-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.
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.
player-core.js dosyasina auto-skip mekanizmasi eklendi:
MEDIA_ERR_DECODE (code 3) veya MEDIA_ERR_NETWORK (code 2) oldugundanextTrack() cagirRe-encode sirasinda kullanicilar dinliyorsa ayni hata olusabilir. Auto-skip sayesinde player durmayacak, sonraki sarkiya gececek. Re-encode bitince bu hata tamamen kaybolur.
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.
| Dosya Konumu | mp3_64/{song_id}.mp3 — mono, 22050Hz, 64kbps |
| Serve | SongController'da serveAudioCdn() zaten mp3_64 destekliyor |
| Fallback Zinciri | HLS → mp3_128 → mp3_64 → orijinal 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
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.
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.
Asagidaki prompt'u production sunucudaki Claude'a ver. Tum islemleri otomatik yapacak.
## 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
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 |
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
Aşağıdaki 3 konu ayrı bir raporda detaylı anlatılmıştır:
&v=Date.now() cache-busting signed URL'yi bozuyordu → tüm HLS 404 → MP3 fallback'e düşüyorduMUZIBU_AUDIO_FORCE=mp3_original ile tüm sistemi anında değiştir (.env kill switch)hls-4sn-standardization branch'i GitHub'a yüklendi