JWT, server modüler hale getirildi, Torrent durumu kalıcı hale getirildi.
This commit is contained in:
@@ -9,12 +9,12 @@
|
||||
import Movies from "./routes/Movies.svelte";
|
||||
import TvShows from "./routes/TvShows.svelte";
|
||||
import Login from "./routes/Login.svelte";
|
||||
import { API } from "./utils/api.js";
|
||||
import { API, getAccessToken } from "./utils/api.js";
|
||||
import { refreshMovieCount } from "./stores/movieStore.js";
|
||||
import { refreshTvShowCount } from "./stores/tvStore.js";
|
||||
import { fetchTrashItems } from "./stores/trashStore.js";
|
||||
|
||||
const token = localStorage.getItem("token");
|
||||
const token = getAccessToken();
|
||||
|
||||
let menuOpen = false;
|
||||
let wsCounts;
|
||||
@@ -47,7 +47,7 @@
|
||||
refreshMovieCount();
|
||||
refreshTvShowCount();
|
||||
fetchTrashItems();
|
||||
const authToken = localStorage.getItem("token");
|
||||
const authToken = getAccessToken();
|
||||
if (authToken) {
|
||||
const wsUrl = `${API.replace("http", "ws")}?token=${authToken}`;
|
||||
try {
|
||||
|
||||
@@ -759,6 +759,12 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceLabel = cleanFileName(source.displayName || source.name || normalizedSource);
|
||||
const targetLabel = cleanFileName(target.displayName || target.name || normalizedTarget);
|
||||
if (!confirm(`"${sourceLabel}" öğesini "${targetLabel}" içine taşımak istiyor musun?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await moveEntry(normalizedSource, normalizedTarget);
|
||||
if (!result?.success) {
|
||||
@@ -1588,6 +1594,13 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceLabel = cleanFileName(clipboardItem.displayName || clipboardItem.name || normalizedSource);
|
||||
const targetLabel = cleanFileName(currentPath || normalizedTarget);
|
||||
const actionLabel = clipboardOperation === 'cut' ? 'taşı' : 'kopyala';
|
||||
if (!confirm(`"${sourceLabel}" öğesini "${targetLabel}" konumuna ${actionLabel}mak istiyor musun?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let result;
|
||||
if (clipboardOperation === 'cut') {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import { API } from "../utils/api.js";
|
||||
import { API, persistTokens, clearTokens } from "../utils/api.js";
|
||||
import logo from "../assets/image/logo.png";
|
||||
|
||||
let username = "";
|
||||
@@ -14,11 +14,14 @@
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const { token } = await res.json();
|
||||
localStorage.setItem("token", token);
|
||||
const { accessToken, refreshToken, user } = await res.json();
|
||||
persistTokens({ accessToken, refreshToken });
|
||||
if (accessToken) localStorage.setItem("token", accessToken); // Geçiş dönemi uyumluluğu
|
||||
if (user) localStorage.setItem("user", JSON.stringify(user));
|
||||
window.location.reload();
|
||||
} else {
|
||||
error = "Kullanıcı adı veya şifre hatalı.";
|
||||
clearTokens();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { API, apiFetch } from "../utils/api.js"; // ✅ apiFetch eklendi
|
||||
import { API, apiFetch, getAccessToken, withToken } from "../utils/api.js"; // ✅ apiFetch eklendi
|
||||
|
||||
let torrents = [];
|
||||
let ws;
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
// --- WebSocket & API ---
|
||||
function wsConnect() {
|
||||
const token = localStorage.getItem("token"); // 🔒 token ekle
|
||||
const url = `${API.replace("http", "ws")}?token=${token}`;
|
||||
const token = getAccessToken();
|
||||
const url = `${API.replace("http", "ws")}?token=${token || ""}`;
|
||||
ws = new WebSocket(url);
|
||||
ws.onmessage = (e) => {
|
||||
const d = JSON.parse(e.data);
|
||||
@@ -157,8 +157,8 @@
|
||||
}
|
||||
|
||||
function streamURL(hash, index = 0) {
|
||||
const token = localStorage.getItem("token");
|
||||
return `${API}/stream/${hash}?index=${index}&token=${token}`;
|
||||
const base = `${API}/stream/${hash}?index=${index}`;
|
||||
return withToken(base);
|
||||
}
|
||||
|
||||
function formatSpeed(bytesPerSec) {
|
||||
@@ -463,7 +463,7 @@
|
||||
<div class="torrent" on:click={() => openModal(t)}>
|
||||
{#if t.thumbnail}
|
||||
<img
|
||||
src={`${API}${t.thumbnail}?token=${localStorage.getItem("token")}`}
|
||||
src={withToken(`${API}${t.thumbnail}`)}
|
||||
alt="thumb"
|
||||
class="thumb"
|
||||
on:load={(e) => e.target.classList.add("loaded")}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { onMount, tick } from "svelte";
|
||||
import { API } from "../utils/api.js";
|
||||
import { API, getAccessToken } from "../utils/api.js";
|
||||
import { cleanFileName } from "../utils/filename.js";
|
||||
import { refreshMovieCount } from "../stores/movieStore.js";
|
||||
import { refreshTvShowCount } from "../stores/tvStore.js";
|
||||
@@ -80,6 +80,14 @@
|
||||
if (Number.isNaN(date.getTime())) return "—";
|
||||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
function buildThumbnailUrl(item) {
|
||||
const token = getAccessToken();
|
||||
const cacheBuster = `t=${Date.now()}`;
|
||||
const authPart = token ? `token=${token}` : null;
|
||||
const query = [authPart, cacheBuster].filter(Boolean).join("&");
|
||||
return `${API}${item.thumbnail}?${query}`;
|
||||
}
|
||||
|
||||
function toggleView() {
|
||||
viewMode = viewMode === "grid" ? "list" : "grid";
|
||||
@@ -410,7 +418,7 @@
|
||||
{:else}
|
||||
{#if item.thumbnail}
|
||||
<img
|
||||
src={`${API}${item.thumbnail}?token=${localStorage.getItem("token")}&t=${Date.now()}`}
|
||||
src={buildThumbnailUrl(item)}
|
||||
alt={item.name}
|
||||
class="thumb"
|
||||
on:load={(e) => e.target.classList.add("loaded")}
|
||||
|
||||
@@ -1,22 +1,72 @@
|
||||
const apiBase = import.meta.env.VITE_API;
|
||||
export const API = apiBase || window.location.origin;
|
||||
|
||||
const ACCESS_TOKEN_KEY = "accessToken";
|
||||
const REFRESH_TOKEN_KEY = "refreshToken";
|
||||
|
||||
export function getAccessToken() {
|
||||
return localStorage.getItem(ACCESS_TOKEN_KEY);
|
||||
}
|
||||
|
||||
export function getRefreshToken() {
|
||||
return localStorage.getItem(REFRESH_TOKEN_KEY);
|
||||
}
|
||||
|
||||
export function persistTokens({ accessToken, refreshToken }) {
|
||||
if (accessToken) localStorage.setItem(ACCESS_TOKEN_KEY, accessToken);
|
||||
if (refreshToken) localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken);
|
||||
}
|
||||
|
||||
export function clearTokens() {
|
||||
localStorage.removeItem(ACCESS_TOKEN_KEY);
|
||||
localStorage.removeItem(REFRESH_TOKEN_KEY);
|
||||
localStorage.removeItem("token");
|
||||
}
|
||||
|
||||
export function withToken(url) {
|
||||
const token = getAccessToken();
|
||||
if (!token) return url;
|
||||
const separator = url.includes("?") ? "&" : "?";
|
||||
return `${url}${separator}token=${token}`;
|
||||
}
|
||||
|
||||
// 🔐 Ortak kimlik doğrulama başlığı (token varsa ekler)
|
||||
export function authHeaders() {
|
||||
const token = localStorage.getItem("token");
|
||||
const token = getAccessToken();
|
||||
return token ? { Authorization: `Bearer ${token}` } : {};
|
||||
}
|
||||
|
||||
// 🔧 Yardımcı fetch (otomatik token ekler, hata durumunda logout)
|
||||
export async function apiFetch(path, options = {}) {
|
||||
async function refreshAccessToken() {
|
||||
const refreshToken = getRefreshToken();
|
||||
if (!refreshToken) return null;
|
||||
const res = await fetch(`${API}/api/token/refresh`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ refreshToken })
|
||||
});
|
||||
if (!res.ok) return null;
|
||||
const { accessToken } = await res.json();
|
||||
if (accessToken) {
|
||||
persistTokens({ accessToken });
|
||||
}
|
||||
return accessToken || null;
|
||||
}
|
||||
|
||||
// 🔧 Yardımcı fetch (otomatik token ekler, 401'de refresh dener)
|
||||
export async function apiFetch(path, options = {}, retry = true) {
|
||||
const headers = { ...(options.headers || {}), ...authHeaders() };
|
||||
const res = await fetch(`${API}${path}`, { ...options, headers });
|
||||
|
||||
// Token süresi dolmuşsa veya yanlışsa kullanıcıyı çıkışa yönlendir
|
||||
if (res.status === 401) {
|
||||
localStorage.removeItem("token");
|
||||
if (res.status === 401 && retry) {
|
||||
const refreshed = await refreshAccessToken();
|
||||
if (refreshed) {
|
||||
const retryHeaders = { ...(options.headers || {}), ...authHeaders() };
|
||||
return fetch(`${API}${path}`, { ...options, headers: retryHeaders });
|
||||
}
|
||||
clearTokens();
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user