Files
dupe/client/src/stores/musicPlayerStore.js
wisecolt d5d9184872 feat(music): mini player ekle
Müzik çalar durumunu yönetmek için global store oluştur.
Özel bir mini player bileşeni ile çalma listesi ve kontrolleri ekle.
Müzik çaların uygulama genelinde kalıcı olmasını sağla.
2026-01-18 01:51:15 +03:00

204 lines
4.6 KiB
JavaScript

import { writable, get } from "svelte/store";
import { API, withToken } from "../utils/api.js";
const INITIAL_STATE = {
currentTrack: null,
currentIndex: -1,
queue: [],
isPlaying: false,
currentTime: 0,
duration: 0,
volume: 0.8,
isMuted: false
};
const { subscribe, set, update } = writable({ ...INITIAL_STATE });
let audio = null;
let previousVolume = INITIAL_STATE.volume;
function ensureAudio() {
if (audio || typeof Audio === "undefined") return;
audio = new Audio();
audio.preload = "metadata";
audio.volume = INITIAL_STATE.volume;
audio.addEventListener("timeupdate", () => {
update((state) => ({
...state,
currentTime: audio.currentTime || 0,
duration: Number.isFinite(audio.duration) ? audio.duration : state.duration
}));
});
audio.addEventListener("loadedmetadata", () => {
update((state) => ({
...state,
duration: Number.isFinite(audio.duration) ? audio.duration : 0
}));
});
audio.addEventListener("play", () => {
update((state) => ({ ...state, isPlaying: true }));
});
audio.addEventListener("pause", () => {
update((state) => ({ ...state, isPlaying: false }));
});
audio.addEventListener("ended", () => {
playNext();
});
}
function buildStreamURL(item) {
const base = `${API}/stream/${item.infoHash}?index=${item.fileIndex || 0}`;
return withToken(base);
}
function setQueue(items = []) {
update((state) => ({ ...state, queue: Array.isArray(items) ? items : [] }));
}
function playTrack(item, index, items = null) {
if (!item) return;
ensureAudio();
if (items) setQueue(items);
const state = get({ subscribe });
const nextIndex =
Number.isFinite(index) && index >= 0
? index
: state.queue.findIndex((entry) => entry.id === item.id);
update((prev) => ({
...prev,
currentTrack: item,
currentIndex: nextIndex,
currentTime: 0,
duration: item.mediaInfo?.format?.duration || 0
}));
if (!audio) return;
audio.src = buildStreamURL(item);
audio
.play()
.catch(() => update((prev) => ({ ...prev, isPlaying: false })));
}
function playByIndex(index) {
ensureAudio();
const state = get({ subscribe });
if (!state.queue.length || index < 0 || index >= state.queue.length) return;
const item = state.queue[index];
update((prev) => ({
...prev,
currentTrack: item,
currentIndex: index,
currentTime: 0,
duration: item.mediaInfo?.format?.duration || 0
}));
if (!audio) return;
audio.src = buildStreamURL(item);
audio
.play()
.catch(() => update((prev) => ({ ...prev, isPlaying: false })));
}
function togglePlay() {
ensureAudio();
const state = get({ subscribe });
if (!audio || !state.currentTrack) return;
if (state.isPlaying) {
audio.pause();
} else {
audio
.play()
.catch(() => update((prev) => ({ ...prev, isPlaying: false })));
}
}
function playNext() {
const state = get({ subscribe });
if (!state.queue.length) return;
const nextIndex =
state.currentIndex >= 0
? (state.currentIndex + 1) % state.queue.length
: 0;
playByIndex(nextIndex);
}
function playPrevious() {
const state = get({ subscribe });
if (!state.queue.length) return;
const prevIndex =
state.currentIndex > 0
? state.currentIndex - 1
: state.queue.length - 1;
playByIndex(prevIndex);
}
function seekToPercent(percent) {
ensureAudio();
if (!audio) return;
const state = get({ subscribe });
if (!state.duration) return;
const nextTime = (Number(percent) / 100) * state.duration;
audio.currentTime = nextTime;
update((prev) => ({ ...prev, currentTime: nextTime }));
}
function setVolume(value) {
ensureAudio();
const volume = Math.min(Math.max(Number(value) || 0, 0), 1);
if (audio) audio.volume = volume;
update((prev) => ({
...prev,
volume,
isMuted: volume === 0
}));
}
function toggleMute() {
ensureAudio();
const state = get({ subscribe });
if (!audio) return;
if (state.isMuted || state.volume === 0) {
const nextVolume = previousVolume || 0.8;
audio.volume = nextVolume;
update((prev) => ({
...prev,
volume: nextVolume,
isMuted: false
}));
} else {
previousVolume = state.volume;
audio.volume = 0;
update((prev) => ({
...prev,
volume: 0,
isMuted: true
}));
}
}
function stopPlayback() {
if (audio) {
audio.pause();
audio.src = "";
}
set({ ...INITIAL_STATE });
}
export const musicPlayer = { subscribe };
export {
setQueue,
playTrack,
togglePlay,
playNext,
playPrevious,
seekToPercent,
setVolume,
toggleMute,
stopPlayback
};