Audio HLS Streaming, Fiyatlandırma, API, Güvenlik ve Entegrasyon Analizi
Bunny Stream nedir? Bunny.net'in sunduğu bir video barındırma ve yayınlama servisidir. Video yüklersiniz, otomatik olarak farklı kalitelere dönüştürülür (düşük internet hızı olan kişiler düşük kalite, yüksek hızlı olanlar yüksek kalite izler). YouTube'un altyapısının minyatür hali gibi düşünebilirsiniz.
Bizi neden ilgilendiriyor? Şu anda şarkılarımızı kendi sunucumuzda HLS formatına çeviriyoruz (FFmpeg ile), kendi sunucumuzda saklıyoruz ve Bunny CDN üzerinden dağıtıyoruz. Bu iş sunucu gücü ve disk alanı harcıyor. Alternatif olarak:
Seçenek A - Bunny Stream: Şarkı dosyasını (MP3) Bunny'ye yüklüyoruz, onlar otomatik HLS'e çeviriyor, barındırıyor ve dağıtıyor. Biz hiçbir şey yapmıyoruz.
Seçenek B - Bunny Storage + CDN: Biz FFmpeg ile HLS'e çeviriyoruz (şu anki gibi), ama dosyaları kendi sunucumuz yerine Bunny Storage'a yüklüyoruz. Bunny CDN üzerinden dağıtıyoruz.
Seçenek C - Mevcut Sistem: Biz çeviriyoruz, kendi sunucumuzda saklıyoruz, Bunny CDN cache'liyor ve dağıtıyor.
Sonuç olarak ne öneriliyor? Aşağıdaki detaylı araştırmaya göre, bir müzik platformu için Seçenek B (Bunny Storage + CDN) veya Seçenek C'nin geliştirilmiş hali en mantıklı seçenek. Bunny Stream video için tasarlanmış, audio-only konusunda belirsizlikler var ve fiyat avantajı sınırlı.
Bunny Stream'in resmi belgesine göre şu audio container formatları kabul ediliyor:
Bunny Stream, girdi olarak MP3, WAV, OGG gibi audio dosyalarını kabul ediyor. Ancak aşağıdaki sorunlar var:
Bunny Stream, müzik/audio streaming için ideal değil. Birincil olarak video platformu. Audio-only HLS'i doğal olarak desteklediğine dair resmi bir belge yok. Eğer kullanılacaksa, önce bir test MP3 yükleyip çıktının ne olduğunu görmek gerekir.
| Kalem | Birim Fiyat | Not |
|---|---|---|
| Depolama (HDD - Frankfurt) | $0.01/GB | Aylık |
| Geo-replikasyon (2. bölge) | $0.01/GB | Aylık, ek bölge |
| Geo-replikasyon (3.+ bölge) | $0.005/GB | Aylık, ek bölge başı |
| CDN - Avrupa & K.Amerika | $0.010/GB | Standart ağ |
| CDN - Asya & Okyanusya | $0.030/GB | Standart ağ |
| CDN - Güney Amerika | $0.045/GB | Standart ağ |
| CDN - Orta Doğu & Afrika | $0.060/GB | Standart ağ |
| CDN - Volume Ağ (0-500TB) | $0.005/GB | 10 PoP, global tek fiyat |
| Standart Encoding (H.264) | ÜCRETSİZ | 4K'ya kadar |
| Premium Encoding (720p+) | $0.050/dk | H.265, VP9, AV1 |
| Premium Encoding (480p-) | $0.025/dk | SD içerik |
| AI Transkripsiyon | $0.10/dk/dil | Opsiyonel |
| MediaCage Enterprise DRM | $99/ay + lisans | FairPlay + Widevine |
| Minimum Aylık | $1/ay | Tüm hizmetler dahil |
66 şarkı, ortalama 4 dakika, toplam ~2GB HLS dosya (multi-bitrate), aylık ~10GB trafik varsayımıyla:
Gerçek maliyet: $1/ay (minimum fatura). Büyüdükçe trafiğe göre artar.
https://video.bunnycdn.comAccessKey header'ı ile API key# POST - Video nesnesi oluştur
curl --request POST \
--url https://video.bunnycdn.com/library/{libraryId}/videos \
--header 'AccessKey: YOUR_STREAM_API_KEY' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{"title":"sarki-adi"}'
# Yanıt: { "videoLibraryId": 123, "guid": "abc-def-123", "title": "sarki-adi", ... }
# PUT - Binary dosya yükle
curl --request PUT \
--url https://video.bunnycdn.com/library/{libraryId}/videos/{videoId} \
--header 'AccessKey: YOUR_STREAM_API_KEY' \
--header 'Content-Type: application/octet-stream' \
--data-binary '@/path/to/song.mp3'
# Yanıt: { "success": true, "message": "OK" }
# İsteğe bağlı parametreler (query string):
# ?enabledResolutions=240p,360p,480p,720p,1080p
# ?jitEnabled=true (Just-in-Time encoding)
# ?enabledOutputCodecs=x264,vp9
# POST - Uzak URL'den indir
curl --request POST \
--url https://video.bunnycdn.com/library/{libraryId}/videos/fetch \
--header 'AccessKey: YOUR_STREAM_API_KEY' \
--header 'content-type: application/json' \
--data '{"url":"https://example.com/song.mp3"}'
https://{pullzone}.b-cdn.net/{videoId}/playlist.m3u8https://{pullzone}.b-cdn.net/{videoId}/play_720p.mp4https://video.bunnycdn.com/play/{libraryId}/{videoId}https://{pullzone}.b-cdn.net/{videoId}/thumbnail.jpgResmi ve topluluk paketleri mevcut:
BunnyWay/bunnystream-api-php - Resmi PHP SDKToshY/BunnyNet-PHP - Kapsamlı topluluk kütüphanesibangnokia/laravel-bunny-storage - Laravel Storage driveritsemon245/laravel-bunny - Laravel Filesystem adapterBunny Stream yüklenen her videoyu seçilen çözünürlüklere otomatik olarak dönüştürür. Player, kullanıcının internet hızına göre en uygun kaliteyi seçer (Adaptive Bitrate Streaming).
| Çözünürlük | Video Bitrate | Audio Bitrate |
|---|---|---|
| 2160p (4K) | 13,000 kbps | 256 kbps |
| 1080p | 5,000 kbps | 192 kbps |
| 720p | 2,800 kbps | 128 kbps |
| 480p | 1,400 kbps | 128 kbps |
| 360p | 800 kbps | 96 kbps |
| 240p | 600 kbps | 96 kbps |
Ek codec'ler ve JIT encoding:
Tüm bu çözünürlükler video çözünürlükleridir. Audio-only dosya yüklendiğinde sistemin 240p, 360p gibi video çözünürlükleri oluşturup oluşturmayacağı belirsiz. Audio bitrate'ler (96-256 kbps) video çözünürlüklerine bağlı olarak değişiyor - yani audio kalitesini bağımsız olarak kontrol edemeyebilirsiniz.
Bunny Stream, HLS (HTTP Live Streaming) formatında çıktı üretir. Standart yapı:
# URL Yapısı:
https://{pullzone}.b-cdn.net/{videoId}/playlist.m3u8 ← Master playlist
https://{pullzone}.b-cdn.net/{videoId}/play_720p.mp4 ← MP4 fallback
# Dahili yapı (Bunny Stream tarafından yönetilir):
/{videoId}/
├── playlist.m3u8 ← Master manifest (tüm kaliteler)
├── 240p/chunks.m3u8 ← 240p variant playlist
│ ├── segment-0.ts
│ └── segment-1.ts
├── 360p/chunks.m3u8 ← 360p variant playlist
├── 480p/chunks.m3u8
├── 720p/chunks.m3u8
├── 1080p/chunks.m3u8
├── play_720p.mp4 ← MP4 fallback (max 720p)
└── thumbnail.jpg
Şu anda kendi oluşturduğumuz HLS yapısı:
# Bizim mevcut yapımız:
/storage/hls/{songId}/
├── master.m3u8 ← Master manifest
├── high/
│ ├── stream.m3u8 ← 128kbps variant
│ └── segment-*.ts
└── low/
├── stream.m3u8 ← 64kbps variant
└── segment-*.ts
Bunny Stream'in HLS çıktısı standart olduğu için herhangi bir HLS uyumlu player ile çalışır. Ancak audio bitrate kontrolü sınırlı olabilir.
| Özellik | MediaCage Basic | MediaCage Enterprise |
|---|---|---|
| Fiyat | Ücretsiz | $99/ay + lisans |
| Şifreleme Türü | Dynamic Clear Key | FairPlay + Widevine |
| Tarayıcı Desteği | Evet | Evet |
| Mobil App Desteği | Hayır | Evet |
| Hardware Key Exchange | Hayır | Evet |
| Ekran Görüntüsü Engelleme | Hayır | Kısmen* |
| İndirme Engelleme | Evet | Evet |
* Widevine L3 güvenlik seviyesindeki istemcilerde ekran görüntüsü engellenemiyor
1 lisans = 1 benzersiz video oynatma (cihaz başına). SD (<720p) içerik lisans ücreti gerektirmez.
Bunny Stream, klasik AES-128 HLS şifreleme (#EXT-X-KEY tag'i ile) sunmuyor. Bunun yerine kendi MediaCage sistemi var. Eğer kendi AES-128 anahtarlarınızla şifreleme yapmak istiyorsanız, bunu kendi FFmpeg pipeline'ınızda yapıp Bunny Storage'a yüklemeniz gerekir. Bunny Stream bu konuda esneklik sunmuyor.
// Token oluşturma formülü:
token = Base64Encode(
SHA256_RAW(
security_key +
signed_url_path +
expiration_timestamp +
(optional) remote_ip +
(optional) encoded_query_parameters
)
)
// Base64 temizleme:
token = str_replace(['\n', '+', '/', '='], ['', '-', '_', ''], token)
// URL formatı (query string):
https://cdn.example.com/path/file.m3u8?token=ABC123&expires=1702005952
// URL formatı (path-based - HLS için ideal):
https://cdn.example.com/bcdn_token=ABC123&expires=1702005952/path/file.m3u8
token_path parametresi ile bir klasörün tamamı için tek token oluşturulabilir. Bu, HLS streaming için çok önemli çünkü:
// ToshY/BunnyNet-PHP kütüphanesi ile:
use ToshY\BunnyNet\BunnyTokenAuthentication;
$auth = new BunnyTokenAuthentication(
token: 'your-security-key',
hostname: 'https://cdn.muzibu.com',
);
// Tek dosya imzalama:
$signedUrl = $auth->sign(
file: '/songs/123/playlist.m3u8',
expirationTime: 3600, // 1 saat
userIp: '1.2.3.4', // opsiyonel
);
// Directory token (HLS tüm segmentler dahil):
$signedUrl = $auth->sign(
file: '/songs/123/playlist.m3u8',
expirationTime: 3600,
isDirectoryToken: true,
pathAllowed: '/songs/123/', // Bu klasördeki her şey dahil
);
// Ülke kısıtlama:
$signedUrl = $auth->sign(
file: '/songs/123/playlist.m3u8',
expirationTime: 7200,
countriesAllowed: 'TR,DE,NL', // Sadece bu ülkeler
);
// JavaScript tarafında HLS.js ile:
var hls = new Hls();
hls.loadSource('https://cdn.muzibu.com/bcdn_token=TOKEN&expires=EXP/songs/123/playlist.m3u8');
// Veya Video.js HLS eklentisi ile:
videojs.Hls.xhr.beforeRequest = function(options) {
if (options.uri.includes('.ts')) {
options.uri += '?token=TOKEN&expires=EXP&token_path=/songs/123/';
}
return options;
};
Şarkı yükleme akışını Bunny Stream API'sine yönlendirmek:
// app/Services/BunnyStreamService.php
class BunnyStreamService
{
private string $apiKey;
private int $libraryId;
public function uploadSong(Song $song, string $filePath): string
{
// Adım 1: Video nesnesi oluştur
$response = Http::withHeaders([
'AccessKey' => $this->apiKey,
])->post("https://video.bunnycdn.com/library/{$this->libraryId}/videos", [
'title' => $song->title,
]);
$videoId = $response->json('guid');
// Adım 2: Dosyayı yükle
Http::withHeaders([
'AccessKey' => $this->apiKey,
'Content-Type' => 'application/octet-stream',
])->withBody(
file_get_contents($filePath), 'application/octet-stream'
)->put("https://video.bunnycdn.com/library/{$this->libraryId}/videos/{$videoId}");
// Adım 3: Bunny video ID'yi kaydet
$song->update(['bunny_video_id' => $videoId]);
// HLS URL: https://{pullzone}.b-cdn.net/{videoId}/playlist.m3u8
return $videoId;
}
}
Mevcut HLS pipeline'ını koruyup dosyaları Bunny Storage'a yüklemek:
// config/filesystems.php
'bunny' => [
'driver' => 'bunny',
'storage_zone' => env('BUNNY_STORAGE_ZONE'),
'api_key' => env('BUNNY_STORAGE_API_KEY'),
'region' => env('BUNNY_STORAGE_REGION', 'de'), // Frankfurt
'hostname' => env('BUNNY_CDN_HOSTNAME'), // Pull Zone URL
],
// app/Services/HLSService.php - Mevcut sisteme ek
public function uploadToBunnyStorage(Song $song): void
{
$hlsPath = "hls/{$song->id}";
$localPath = storage_path("app/public/{$hlsPath}");
// Tüm HLS dosyalarını Bunny Storage'a yükle
foreach (File::allFiles($localPath) as $file) {
$relativePath = str_replace($localPath, '', $file->getPathname());
Storage::disk('bunny')->put(
"songs/{$song->id}{$relativePath}",
file_get_contents($file->getPathname())
);
}
// Signed URL oluştur
$signedUrl = $this->generateBunnySignedUrl(
"/songs/{$song->id}/master.m3u8"
);
}
// Bunny Storage Upload (ham HTTP ile)
private function uploadFile(string $remotePath, string $localFile): void
{
Http::withHeaders([
'AccessKey' => config('filesystems.disks.bunny.api_key'),
'Content-Type' => 'application/octet-stream',
'Checksum' => strtoupper(hash_file('sha256', $localFile)),
])->withBody(
file_get_contents($localFile), 'application/octet-stream'
)->put(
"https://storage.bunnycdn.com/" .
config('filesystems.disks.bunny.storage_zone') .
"/{$remotePath}"
);
}
SignedUrlService güncellenmeli (Bunny token auth'a geçiş)bunny_video_id veya bunny_storage_path eklenmeli (migration gerekir!)Bu yaklaşımda, kendi sunucumuzda FFmpeg ile HLS dosyalarını oluşturup Bunny Storage'a yüklüyoruz. Bunny CDN Pull Zone bu dosyaları dağıtıyor.
# Dosya yükleme
PUT https://storage.bunnycdn.com/{storageZoneName}/{path}/{fileName}
Headers:
AccessKey: STORAGE_ZONE_PASSWORD (Account API key değil!)
Content-Type: application/octet-stream
Checksum: SHA256_HEX (opsiyonel, doğrulama için)
Body: Raw binary file content
# Bölge endpointleri:
storage.bunnycdn.com # Frankfurt (DE)
ny.storage.bunnycdn.com # New York (US)
la.storage.bunnycdn.com # Los Angeles (US)
sg.storage.bunnycdn.com # Singapur (SG)
syd.storage.bunnycdn.com # Sydney (AU)
# Yanıt: 201 Created (başarılı) / 400 Bad Request (hata)
# Klasörler otomatik oluşturulur!
| Kalem | Fiyat | Not |
|---|---|---|
| Depolama (1-2 bölge) | $0.01/GB/bölge | Aylık |
| Depolama (3+ bölge) | $0.005/GB/bölge | Aylık |
| CDN Trafik (EU & NA) | $0.01/GB | Standart ağ, 119 PoP |
| CDN Trafik (Volume) | $0.005/GB | 10 PoP, global tek fiyat |
| Minimum | $1/ay | Tüm hizmetler |
| Kriter | Bunny Stream | Bunny Storage + CDN | Mevcut Sistem |
|---|---|---|---|
| Transkoding | Bunny yapar Ücretsiz | Biz yaparız (FFmpeg) | Biz yaparız (FFmpeg) |
| Audio-Only HLS | Belirsiz | Tam Kontrol | Tam Kontrol |
| Audio Bitrate Kontrolü | Sınırlı | 128k/64k/32k | 128k/64k |
| Depolama | Bunny'de ($0.01/GB) | Bunny'de ($0.01/GB) | Kendi sunucu + CDN cache |
| CDN Dağıtım | Bunny CDN ($0.01/GB) | Bunny CDN ($0.01/GB) | Bunny CDN (Pull Zone) |
| AES-128 Şifreleme | Yok | Kendi anahtarın | Kendi anahtarın |
| DRM | MediaCage | Yok | Yok |
| Token Auth | Embed token | V2 SHA256 | Kendi signed URL |
| Sunucu CPU Yükü | Sıfır | FFmpeg yükü | FFmpeg + Serve |
| Disk Kullanımı | Sıfır | Geçici | Kalıcı ~2GB+ |
| Upload Akışı | MP3 → API → Otomatik | MP3 → FFmpeg → Upload | MP3 → FFmpeg → Yerel |
| Kod Değişikliği | Büyük | Orta | Yok |
| Aylık Tahmini Maliyet | ~$1 (min) | ~$1 (min) | $0 (CDN hariç) |
* Bunny Stream ve Bunny Storage fiyatlandırması aynı (depolama + CDN). Fark sadece encoding maliyetinde. Standart encoding ücretsiz olduğundan maliyet eşit.
Zaten yapıyoruz. FFmpeg ile HLS oluşturuyoruz, Bunny CDN cache'liyor. En az değişiklik, en az risk. Master.m3u8 + multi-bitrate yapısı tamamlandığında sistem zaten iyi çalışacak.
Şarkı sayısı artıp disk alanı sorun olduğunda, HLS dosyalarını Bunny Storage'a taşı. FFmpeg pipeline korunur (audio kontrolü), sadece dosya depolama ve serve edilme yeri değişir. Token Auth V2 ile güvenlik sağlanır.
Eğer video klip, konser videosu gibi video içerikler eklenecekse, o zaman Bunny Stream mantıklı olur. Audio-only için değil, video transkoding ihtiyacı olduğunda kullan.