TVDB özelliği eklendi.
This commit is contained in:
@@ -8,12 +8,29 @@
|
|||||||
import Sharing from "./routes/Sharing.svelte";
|
import Sharing from "./routes/Sharing.svelte";
|
||||||
import Trash from "./routes/Trash.svelte";
|
import Trash from "./routes/Trash.svelte";
|
||||||
import Movies from "./routes/Movies.svelte";
|
import Movies from "./routes/Movies.svelte";
|
||||||
|
import TvShows from "./routes/TvShows.svelte";
|
||||||
import Login from "./routes/Login.svelte";
|
import Login from "./routes/Login.svelte";
|
||||||
|
import { API } from "./utils/api.js";
|
||||||
import { refreshMovieCount } from "./stores/movieStore.js";
|
import { refreshMovieCount } from "./stores/movieStore.js";
|
||||||
|
import { refreshTvShowCount } from "./stores/tvStore.js";
|
||||||
|
|
||||||
const token = localStorage.getItem("token");
|
const token = localStorage.getItem("token");
|
||||||
|
|
||||||
let menuOpen = false;
|
let menuOpen = false;
|
||||||
|
let wsCounts;
|
||||||
|
let refreshTimer = null;
|
||||||
|
|
||||||
|
const scheduleMediaRefresh = () => {
|
||||||
|
if (refreshTimer) return;
|
||||||
|
refreshTimer = setTimeout(async () => {
|
||||||
|
refreshTimer = null;
|
||||||
|
try {
|
||||||
|
await Promise.all([refreshMovieCount(), refreshTvShowCount()]);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("Medya sayacı yenileme başarısız:", err);
|
||||||
|
}
|
||||||
|
}, 400);
|
||||||
|
};
|
||||||
|
|
||||||
// Menü aç/kapat (hamburger butonuyla)
|
// Menü aç/kapat (hamburger butonuyla)
|
||||||
const toggleMenu = () => {
|
const toggleMenu = () => {
|
||||||
@@ -28,7 +45,48 @@
|
|||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (token) {
|
if (token) {
|
||||||
refreshMovieCount();
|
refreshMovieCount();
|
||||||
|
refreshTvShowCount();
|
||||||
|
const authToken = localStorage.getItem("token");
|
||||||
|
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)
|
||||||
|
) {
|
||||||
|
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>
|
</script>
|
||||||
|
|
||||||
@@ -45,6 +103,7 @@
|
|||||||
<Route path="/" component={Files} />
|
<Route path="/" component={Files} />
|
||||||
<Route path="/files" component={Files} />
|
<Route path="/files" component={Files} />
|
||||||
<Route path="/movies" component={Movies} />
|
<Route path="/movies" component={Movies} />
|
||||||
|
<Route path="/tv" component={TvShows} />
|
||||||
<Route path="/transfers" component={Transfers} />
|
<Route path="/transfers" component={Transfers} />
|
||||||
<Route path="/sharing" component={Sharing} />
|
<Route path="/sharing" component={Sharing} />
|
||||||
<Route path="/trash" component={Trash} />
|
<Route path="/trash" component={Trash} />
|
||||||
|
|||||||
@@ -2,17 +2,24 @@
|
|||||||
import { Link } from "svelte-routing";
|
import { Link } from "svelte-routing";
|
||||||
import { createEventDispatcher, onDestroy } from "svelte";
|
import { createEventDispatcher, onDestroy } from "svelte";
|
||||||
import { movieCount } from "../stores/movieStore.js";
|
import { movieCount } from "../stores/movieStore.js";
|
||||||
|
import { tvShowCount } from "../stores/tvStore.js";
|
||||||
|
|
||||||
export let menuOpen = false;
|
export let menuOpen = false;
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
let hasMovies = false;
|
let hasMovies = false;
|
||||||
|
let hasShows = false;
|
||||||
|
|
||||||
const unsubscribe = movieCount.subscribe((count) => {
|
const unsubscribeMovie = movieCount.subscribe((count) => {
|
||||||
hasMovies = (count ?? 0) > 0;
|
hasMovies = (count ?? 0) > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const unsubscribeTv = tvShowCount.subscribe((count) => {
|
||||||
|
hasShows = (count ?? 0) > 0;
|
||||||
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
unsubscribe();
|
unsubscribeMovie();
|
||||||
|
unsubscribeTv();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Menü öğesine tıklanınca sidebar'ı kapat
|
// Menü öğesine tıklanınca sidebar'ı kapat
|
||||||
@@ -51,6 +58,20 @@
|
|||||||
</Link>
|
</Link>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if hasShows}
|
||||||
|
<Link
|
||||||
|
to="/tv"
|
||||||
|
class="item"
|
||||||
|
getProps={({ isCurrent }) => ({
|
||||||
|
class: isCurrent ? "item active" : "item",
|
||||||
|
})}
|
||||||
|
on:click={handleLinkClick}
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-tv icon"></i>
|
||||||
|
Tv Shows
|
||||||
|
</Link>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
to="/transfers"
|
to="/transfers"
|
||||||
class="item"
|
class="item"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { API, apiFetch } from "../utils/api.js";
|
import { API, apiFetch } from "../utils/api.js";
|
||||||
import { cleanFileName } from "../utils/filename.js";
|
import { cleanFileName } from "../utils/filename.js";
|
||||||
import { refreshMovieCount } from "../stores/movieStore.js";
|
import { refreshMovieCount } from "../stores/movieStore.js";
|
||||||
|
import { refreshTvShowCount } from "../stores/tvStore.js";
|
||||||
let files = [];
|
let files = [];
|
||||||
let showModal = false;
|
let showModal = false;
|
||||||
let selectedVideo = null;
|
let selectedVideo = null;
|
||||||
@@ -65,6 +66,7 @@ let isPlaying = false;
|
|||||||
allSelected = files.length > 0 && selectedItems.size === files.length;
|
allSelected = files.length > 0 && selectedItems.size === files.length;
|
||||||
tryAutoPlay();
|
tryAutoPlay();
|
||||||
refreshMovieCount();
|
refreshMovieCount();
|
||||||
|
refreshTvShowCount();
|
||||||
}
|
}
|
||||||
function formatSize(bytes) {
|
function formatSize(bytes) {
|
||||||
if (!bytes) return "0 MB";
|
if (!bytes) return "0 MB";
|
||||||
@@ -336,7 +338,7 @@ let isPlaying = false;
|
|||||||
|
|
||||||
selectedItems = new Set(failed);
|
selectedItems = new Set(failed);
|
||||||
allSelected = failed.length > 0 && failed.length === files.length;
|
allSelected = failed.length > 0 && failed.length === files.length;
|
||||||
await refreshMovieCount();
|
await Promise.all([refreshMovieCount(), refreshTvShowCount()]);
|
||||||
}
|
}
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await loadFiles(); // önce dosyaları getir
|
await loadFiles(); // önce dosyaları getir
|
||||||
|
|||||||
1523
client/src/routes/TvShows.svelte
Normal file
1523
client/src/routes/TvShows.svelte
Normal file
File diff suppressed because it is too large
Load Diff
16
client/src/stores/tvStore.js
Normal file
16
client/src/stores/tvStore.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { writable } from "svelte/store";
|
||||||
|
import { apiFetch } from "../utils/api.js";
|
||||||
|
|
||||||
|
export const tvShowCount = writable(0);
|
||||||
|
|
||||||
|
export async function refreshTvShowCount() {
|
||||||
|
try {
|
||||||
|
const resp = await apiFetch("/api/tvshows");
|
||||||
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
||||||
|
const list = await resp.json();
|
||||||
|
tvShowCount.set(Array.isArray(list) ? list.length : 0);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("⚠️ TV show count güncellenemedi:", err?.message || err);
|
||||||
|
tvShowCount.set(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,5 +15,5 @@ services:
|
|||||||
USERNAME: ${USERNAME}
|
USERNAME: ${USERNAME}
|
||||||
PASSWORD: ${PASSWORD}
|
PASSWORD: ${PASSWORD}
|
||||||
TMDB_API_KEY: ${TMDB_API_KEY}
|
TMDB_API_KEY: ${TMDB_API_KEY}
|
||||||
TTVDB_API_KEY: ${TTVDB_API_KEY}
|
TVDB_API_KEY: ${TVDB_API_KEY}
|
||||||
VIDEO_THUMBNAIL_TIME: ${VIDEO_THUMBNAIL_TIME}
|
VIDEO_THUMBNAIL_TIME: ${VIDEO_THUMBNAIL_TIME}
|
||||||
|
|||||||
1531
server/server.js
1531
server/server.js
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user