Video oynatıcıya özel kontroller, WebSocket desteği, arama fonksiyonu ve altyazı yükleme özelliği eklendi. Metadata yönetimi güçlendirildi, dosya silme ve geri yükleme işlemlerinde Rabbit listesi otomatik güncelleniyor.
185 lines
5.3 KiB
Svelte
185 lines
5.3 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 Files from "./routes/Files.svelte";
|
||
import Transfers from "./routes/Transfers.svelte";
|
||
import Trash from "./routes/Trash.svelte";
|
||
import Rabbit from "./routes/Rabbit.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 { refreshRabbitCount } from "./stores/rabbitStore.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(),
|
||
refreshRabbitCount(),
|
||
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();
|
||
refreshRabbitCount();
|
||
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="/rabbit" component={Rabbit} />
|
||
<Route path="/profile" component={Profile} />
|
||
<Route path="/settings" component={Settings} />
|
||
<Route path="/transfers" component={Transfers} />
|
||
<Route path="/trash" component={Trash} />
|
||
</div>
|
||
|
||
<!-- 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}
|