Tüm player mantığı tek bir büyük Alpine component içinde. Function-based component pattern kullanılıyor.
| Kategori | Variables | Amaç |
|---|---|---|
| Playback State | isPlaying, currentSong, queue, queueIndex |
Şu an çalan şarkı ve queue durumu |
| Audio Control | volume, isMuted, currentTime, duration, progressPercent |
Ses seviyesi, progress bar kontrolü |
| Player Modes | shuffle, repeatMode (off/all/one) |
Karışık çalma ve tekrar modu |
| Audio Engines | howl, howlNext, hls, hlsNext, isHlsStream |
Howler ve HLS instance'ları |
| Crossfade | isCrossfading, crossfadeEnabled, crossfadeDuration |
Şarkı geçişlerinde crossfade efekti |
| Auth System | showAuthModal, loginForm, registerForm, isLoggedIn |
Login/Register modal state |
| Queue UI | showQueue, draggedIndex, dropTargetIndex |
Queue paneli ve drag-drop |
| Validation | registerValidation, loginValidation |
Form validation state |
currentStreamType: HLS mi MP3 mü tespit ederSistemde iki farklı audio engine paralel çalışıyor:
.mp3, .ogg, .wav, .webm dosyalarıthis.howl (aktif), this.howlNext (crossfade için)howl.volume(), howl.fade() ile smooth fadehowl.seek(newTime).m3u8 adaptive streamingthis.hls (aktif), this.hlsNext (crossfade için)<audio id="hlsAudio"> (blade template'de gizli)audio.canPlayType('application/vnd.apple.mpegurl'))
// API'den stream_type gelir
const streamType = data.stream_type || 'mp3';
const useHls = streamType === 'hls';
// Fallback: URL'den tespit
const isHlsUrl = url.includes('.m3u8') || url.includes('m3u8') || url.includes('/hls/');
hlsAudio: Ana HLS audio element (Blade template'de tanımlı)hlsAudioNext: Crossfade için ikinci element (JavaScript ile dinamik oluşturuluyor)activeHlsAudioId: Hangi element'in aktif olduğunu takip edergetActiveHlsAudio(): Aktif audio element'i döndürürplaySong(id) veya playSongFromQueue(index)/api/muzibu/songs/{id}/stream endpoint'ine istek{ stream_url, stream_type, duration }stopCurrentPlayback() - fade out ve cleanuploadAndPlaySong(url, streamType)playHlsStream(), MP3 ise playWithHowler()startProgressTracking() - 100ms intervalplayer:play, player:timeupdate, player:stopsetInterval her zaman clearInterval ile temizleniyor mu?howl.unload() çağrılıyor ama howlNext.unload() nerede?Şarkı bitiminde bir sonraki şarkı overlapping olarak başlar (Spotify tarzı).
crossfadeEnabled: true (default aktif)crossfadeDuration: 6000ms (6 saniye)fadeOutDuration: 1000ms (pause/play/manual change için)startCrossfade() tetiklenircreateNextHlsPlayer(), MP3 ise createNextHowlerPlayer()completeCrossfade() - next player main player olurisCrossfading: true ise crossfade devam ediyor (duplicate trigger engellemek için)onTrackEnded() içinde: if (!this.isCrossfading) kontrolü varProgress tracking interval'ında her 100ms kontrol edilir:
const timeRemaining = this.duration - currentTime;
if (crossfadeEnabled && timeRemaining <= 6 && timeRemaining > 0 && !isCrossfading) {
startCrossfade();
}
hlsAudioNext element'i her crossfade'de yeniden mi oluşuyor?queue: []: Array of song objectsqueueIndex: Şu an çalan şarkının index'i (0-based){ song_id, song_title, artist_title, album_cover, duration, ... }| Method | Açıklama |
|---|---|
playSongFromQueue(index) |
Queue'dan belirli index'teki şarkıyı çal |
removeFromQueue(index) |
Queue'dan şarkı sil (queueIndex güncellemesi var) |
addToQueue(type, id) |
Queue'ya şarkı ekle (ŞU AN PLACEHOLDER!) |
nextTrack() |
queueIndex++, repeat mode kontrolü |
previousTrack() |
queueIndex--, 0'ın altına düşmez |
shuffle: true/false state var AMA...playRandomSongs() içinde manuel shuffle yapılıyoroff: Queue bitince durall: Queue bitince başa dön (loop)one: Aynı şarkıyı tekrarlacycleRepeat(): off → all → one → offQueue panelinde şarkılar sürükle-bırak ile yeniden sıralanabilir.
draggedIndex: Sürüklenen şarkının index'idropTargetIndex: Bırakılacağı indexdragStart(index, event): Sürükleme başladıdragOver(index): Üzerinden geçiliyordrop(dropIndex): Bırakıldı - queue yeniden sıralanır, queueIndex güncellenirdragEnd(): Sürükleme bitti - state temizleLogin/Register/Forgot Password tek modal içinde (x-show ile switch)
showAuthModal: 'login', 'register', 'forgot', veya nullloginForm: { email, password, remember }registerForm: { firstName, lastName, name, email, password, phone }forgotForm: { email }/api/auth/check-email)| Endpoint | Method | Açıklama |
|---|---|---|
/api/auth/login |
POST | Login (email + password) |
/api/auth/register |
POST | Register (7 günlük trial başlatır) |
/api/auth/forgot-password |
POST | Şifre sıfırlama linki gönderir |
/api/auth/check-email |
POST | Email kullanımda mı kontrol eder |
/logout |
POST | Logout (CSRF token gerekli) |
remembered_email)location.reload() kullanılıyor - SPA mantığına ters!showPassword, showLoginPassword ayrı state'ler - tutarsızlık| Endpoint | Method | Açıklama | Response |
|---|---|---|---|
/api/muzibu/songs/popular |
GET | Popüler şarkılar (play_count DESC) | Song array (limit: 20 default) |
/api/muzibu/songs/recent |
GET | Kullanıcının son dinledikleri | Song array (auth gerekli) |
/api/muzibu/songs/{id}/stream |
GET | Şarkı stream URL'i (HLS veya MP3) | { stream_url, stream_type, duration } |
/api/muzibu/songs/{id}/serve |
GET | MP3 dosyasını direkt serve eder | audio/mpeg (StreamedResponse) |
/api/muzibu/albums/{id} |
GET | Albüm detayı + şarkıları | Album object with songs array |
/api/muzibu/playlists/{id} |
GET | Playlist detayı + şarkıları | Playlist object with songs array |
/api/muzibu/playlists/featured |
GET | Öne çıkan playlistler | Playlist array |
/api/favorites/toggle |
POST | Favori ekle/çıkar | { success: true/false } |
/api/favorites/check |
GET | Favori mi kontrol et | { is_favorited: true/false } |
song_title, album_title, artist_title{ tr: "Şarkı Adı", en: "Song Title" }showToast('Bulunamadı', 'error')showAuthModal = 'login'prefetchHlsForQueue(currentIndex): Sıradaki 3 şarkı için stream API'sine istek atılırisLoading var ama kullanılmıyor)Fixed bottom bar, blur background, Spotify tarzı layout.
#181818 + album blur image overlayleft: 256px (sidebar genişliği kadar içerde)@media (max-width: 768px) → left: 0fas fa-play, fas fa-pause, vb.fas fa-signal (mavi), MP3 → fas fa-file-audio (yeşil)Sağ taraftan slide-in panel (x-transition ile animasyon).
player-queue.css: 525 satır!right: 0, bottom: 88px, top: 0Centered modal, blur overlay, tab-based switching (login/register/forgot).
auth-modal.css: 192 satır#181818 background#1DB954 accentlocalStorage erişim hatalarına karşı wrapper (iframe, incognito mode için).
const safeStorage = {
getItem(key) { try { return localStorage.getItem(key); } catch (e) { return null; } },
setItem(key, value) { try { localStorage.setItem(key, value); } catch (e) {} },
removeItem(key) { try { localStorage.removeItem(key); } catch (e) {} }
};
remembered_email: Login remember me emailtheme: Dark/Light mode (şu an sadece dark kullanılıyor)dragOver event'i throttle'suz - her pixel harekette trigger olurInternal linkler AJAX ile yükleniyor (full page reload yok).
<a> click'leri intercept edilirnavigateTo(url): history.pushState ile URL güncellenirloadPage(url): Fetch ile sayfa içeriği alınır (AJAX)<main> içeriği değiştirilirpopstate event'i ile handle edilir
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'text/html'
}
window.location.href = url (full reload)useAudioEngine(): Howler + HLS logicuseQueue(): Queue managementuseAuth(): AuthenticationuseCrossfade(): Crossfade logicMuzibu player profesyonel bir ürün seviyesinde. Ancak monolithic yapı ve eksik özellikler (shuffle, persistence) nedeniyle refactoring gerekiyor. Uzun vadede component abstraction ve TypeScript migration öncelikli.