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.
183 lines
5.2 KiB
Svelte
183 lines
5.2 KiB
Svelte
<script>
|
||
import { Router, Route } from "svelte-routing";
|
||
import { onMount } from "svelte";
|
||
import Sidebar from "./components/Sidebar.svelte";
|
||
import Topbar from "./components/Topbar.svelte";
|
||
import MiniPlayer from "./components/MiniPlayer.svelte";
|
||
import Files from "./routes/Files.svelte";
|
||
import Transfers from "./routes/Transfers.svelte";
|
||
import Trash from "./routes/Trash.svelte";
|
||
import Movies from "./routes/Movies.svelte";
|
||
import TvShows from "./routes/TvShows.svelte";
|
||
import Music from "./routes/Music.svelte";
|
||
import Profile from "./routes/Profile.svelte";
|
||
import Settings from "./routes/Settings.svelte";
|
||
import Login from "./routes/Login.svelte";
|
||
import { API, getAccessToken } from "./utils/api.js";
|
||
import { refreshMovieCount } from "./stores/movieStore.js";
|
||
import { refreshTvShowCount } from "./stores/tvStore.js";
|
||
import { refreshMusicCount } from "./stores/musicStore.js";
|
||
import { fetchTrashItems } from "./stores/trashStore.js";
|
||
import { setAvatarUrl } from "./stores/avatarStore.js";
|
||
|
||
const token = getAccessToken();
|
||
|
||
let menuOpen = false;
|
||
let wsCounts;
|
||
let refreshTimer = null;
|
||
|
||
const scheduleMediaRefresh = () => {
|
||
if (refreshTimer) return;
|
||
refreshTimer = setTimeout(async () => {
|
||
refreshTimer = null;
|
||
try {
|
||
await Promise.all([
|
||
refreshMovieCount(),
|
||
refreshTvShowCount(),
|
||
refreshMusicCount(),
|
||
fetchTrashItems()
|
||
]);
|
||
} catch (err) {
|
||
console.warn("Medya sayacı yenileme başarısız:", err);
|
||
}
|
||
}, 400);
|
||
};
|
||
|
||
const loadUserProfile = async () => {
|
||
try {
|
||
const response = await fetch(`${API}/api/profile`, {
|
||
method: 'GET',
|
||
headers: {
|
||
'Authorization': `Bearer ${getAccessToken()}`,
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
|
||
if (response.ok) {
|
||
const profileData = await response.json();
|
||
if (profileData?.avatarExists) {
|
||
const token = getAccessToken();
|
||
if (token) {
|
||
const avatarUrl = `${API}/api/profile/avatar?token=${token}&v=${Date.now()}`;
|
||
setAvatarUrl(avatarUrl);
|
||
}
|
||
} else {
|
||
setAvatarUrl(null);
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.warn('Profil bilgileri yüklenemedi:', error);
|
||
setAvatarUrl(null);
|
||
}
|
||
};
|
||
|
||
// Menü aç/kapat (hamburger butonuyla)
|
||
const toggleMenu = () => {
|
||
menuOpen = !menuOpen;
|
||
};
|
||
|
||
// 🔹 Sidebar'ı kapatma fonksiyonu
|
||
function closeSidebar() {
|
||
menuOpen = false;
|
||
}
|
||
|
||
onMount(() => {
|
||
if (token) {
|
||
refreshMovieCount();
|
||
refreshTvShowCount();
|
||
refreshMusicCount();
|
||
fetchTrashItems();
|
||
loadUserProfile();
|
||
const authToken = getAccessToken();
|
||
if (authToken) {
|
||
const wsUrl = `${API.replace("http", "ws")}?token=${authToken}`;
|
||
try {
|
||
wsCounts = new WebSocket(wsUrl);
|
||
wsCounts.onmessage = (event) => {
|
||
try {
|
||
const msg = JSON.parse(event.data);
|
||
if (msg.type === "fileUpdate") {
|
||
scheduleMediaRefresh();
|
||
} else if (
|
||
msg.type === "progress" &&
|
||
Array.isArray(msg.torrents) &&
|
||
msg.torrents.some(
|
||
(t) =>
|
||
Number(t.progress) >= 1 ||
|
||
(t.type && String(t.type).toLowerCase() === "youtube")
|
||
)
|
||
) {
|
||
scheduleMediaRefresh();
|
||
}
|
||
} catch (err) {
|
||
console.warn("WS mesajı çözümlenemedi:", err);
|
||
}
|
||
};
|
||
wsCounts.onerror = () => scheduleMediaRefresh();
|
||
} catch (err) {
|
||
console.warn("WS bağlantısı kurulamadı:", err);
|
||
}
|
||
}
|
||
}
|
||
return () => {
|
||
if (wsCounts) {
|
||
try {
|
||
wsCounts.close();
|
||
} catch (err) {
|
||
/* no-op */
|
||
}
|
||
wsCounts = null;
|
||
}
|
||
if (refreshTimer) {
|
||
clearTimeout(refreshTimer);
|
||
refreshTimer = null;
|
||
}
|
||
};
|
||
});
|
||
</script>
|
||
|
||
{#if token}
|
||
<Router>
|
||
<div class="app">
|
||
<!-- Sidebar -->
|
||
<Sidebar {menuOpen} on:closeMenu={closeSidebar} />
|
||
|
||
<!-- İçerik -->
|
||
<div class="content">
|
||
<Topbar on:toggleMenu={toggleMenu} />
|
||
|
||
<Route path="/" component={Files} />
|
||
<Route path="/files" component={Files} />
|
||
<Route path="/movies" component={Movies} />
|
||
<Route path="/tv" component={TvShows} />
|
||
<Route path="/music" component={Music} />
|
||
<Route path="/profile" component={Profile} />
|
||
<Route path="/settings" component={Settings} />
|
||
<Route path="/transfers" component={Transfers} />
|
||
<Route path="/trash" component={Trash} />
|
||
</div>
|
||
|
||
<MiniPlayer />
|
||
|
||
<!-- Sidebar dışına tıklayınca kapanma -->
|
||
{#if menuOpen}
|
||
<div
|
||
class="backdrop show"
|
||
role="button"
|
||
tabindex="0"
|
||
aria-label="Menüyü kapat"
|
||
on:click={closeSidebar}
|
||
on:keydown={(event) => {
|
||
if (event.key === "Enter" || event.key === " ") {
|
||
event.preventDefault();
|
||
closeSidebar();
|
||
}
|
||
}}
|
||
></div>
|
||
{/if}
|
||
</div>
|
||
</Router>
|
||
{:else}
|
||
<Login />
|
||
{/if}
|