diff --git a/client/src/routes/Files.svelte b/client/src/routes/Files.svelte index 14acd05..6a64d32 100644 --- a/client/src/routes/Files.svelte +++ b/client/src/routes/Files.svelte @@ -188,6 +188,41 @@ reader.readAsArrayBuffer(file); } + async function deleteFile(file) { + const token = localStorage.getItem("token"); + if (!confirm("Bu dosyayı silmek istediğine emin misin?")) return; + + // 1️⃣ Önce dosyayı backend'den sil + const resp = await fetch( + `${API}/api/file?path=${encodeURIComponent(file.name)}`, + { + method: "DELETE", + headers: { Authorization: `Bearer ${token}` } + } + ); + + if (resp.ok) { + console.log("🗑️ Dosya silindi:", file.name); + files = files.filter((f) => f.name !== file.name); + + // 2️⃣ Ek olarak Transfers listesindeki torrent'i de sil + // hash = dosya yolundaki ilk klasör (örnek: downloads//video.mp4) + const hash = file.name.split("/")[0]; + console.log("🔄 Transfers listesinden de siliyorum:", hash); + try { + await fetch(`${API}/api/torrents/${hash}`, { + method: "DELETE", + headers: { Authorization: `Bearer ${token}` } + }); + } catch (err) { + console.warn("⚠️ Transfers tarafı silinemedi:", err); + } + } else { + const data = await resp.json(); + alert("Silme hatası: " + (data.error || resp.statusText)); + } + } + onMount(() => { loadFiles(); // ✅ Tek event handler içinde hem Esc hem ok tuşlarını kontrol et @@ -244,6 +279,12 @@ {/if} +
deleteFile(f)} + > + +
{/each} @@ -515,6 +556,45 @@ filter: drop-shadow(0 1px 1px rgba(255, 255, 255, 0.3)); } + /* === DELETE OVERLAY (alt kısımda) === */ + .delete-overlay { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 60px; /* 🔹 alt kısmın yüksekliği */ + background: rgba(0, 0, 0, 0.45); + backdrop-filter: blur(4px); + display: flex; + align-items: center; + justify-content: center; + color: white; + font-size: 24px; + opacity: 0; + transition: opacity 0.25s ease; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; + } + + /* Hover olunca görünür */ + .media-card:hover .delete-overlay { + opacity: 1; + } + + /* 🗑️ ikonu hover efekti */ + .delete-overlay i { + background: rgba(255, 255, 255, 0.2); + border-radius: 50%; + padding: 8px 10px; + transition: + transform 0.15s ease, + background 0.15s ease; + } + + .delete-overlay i:hover { + transform: scale(1.2); + background: rgba(255, 255, 255, 0.35); + } /* === RESPONSIVE === */ @media (max-width: 768px) { .gallery { diff --git a/client/src/routes/Transfers.svelte b/client/src/routes/Transfers.svelte index 8e56268..bba3173 100644 --- a/client/src/routes/Transfers.svelte +++ b/client/src/routes/Transfers.svelte @@ -60,11 +60,12 @@ ws?.send(JSON.stringify({ type: "select", infoHash: hash, index })); } - async function removeTorrent(hash) { - if (!confirm("Bu transferi silmek istediğine emin misin?")) return; - await apiFetch(`/api/torrents/${hash}`, { method: "DELETE" }); // ✅ - await list(); - } +async function removeTorrent(hash) { + if (!confirm("Bu transferi silmek istediğine emin misin?")) return; + await apiFetch(`/api/torrents/${hash}`, { method: "DELETE" }); + torrents = torrents.filter(t => t.infoHash !== hash); + await list(); +} function streamURL(hash, index = 0) { const token = localStorage.getItem("token"); diff --git a/server/server.js b/server/server.js index f7fd735..f537ad1 100644 --- a/server/server.js +++ b/server/server.js @@ -288,6 +288,67 @@ app.get("/media/:path(*)", requireAuth, (req, res) => { } }); +// --- 🗑️ Tekil dosya veya torrent klasörü silme --- +app.delete("/api/file", requireAuth, (req, res) => { + const filePath = req.query.path; + if (!filePath) return res.status(400).json({ error: "path gerekli" }); + + const fullPath = path.join(DOWNLOAD_DIR, filePath); + if (!fs.existsSync(fullPath)) + return res.status(404).json({ error: "Dosya bulunamadı" }); + + try { + // 1) Dosya/klasörü sil + fs.rmSync(fullPath, { recursive: true, force: true }); + console.log(`🗑️ Dosya/klasör silindi: ${fullPath}`); + + // 2) İlk segment (klasör adı) => folderId (örn: "1730048432921") + const folderId = (filePath.split(/[\\/]/)[0] || "").trim(); + + // 3) torrents Map’inde, savePath'in son klasörü folderId olan entry’yi bul + let matchedInfoHash = null; + for (const [infoHash, entry] of torrents.entries()) { + const lastDir = path.basename(entry.savePath); + if (lastDir === folderId) { + matchedInfoHash = infoHash; + break; + } + } + + // 4) Eşleşen torrent varsa destroy + Map’ten sil + snapshot yayınla + if (matchedInfoHash) { + const entry = torrents.get(matchedInfoHash); + entry?.torrent?.destroy(() => { + torrents.delete(matchedInfoHash); + console.log(`🧹 Torrent kaydı da temizlendi: ${matchedInfoHash}`); + // anında WebSocket güncellemesi (broadcastSnapshot global fonksiyonunu kullanıyorsan onu çağır) + if (typeof broadcastSnapshot === "function") { + broadcastSnapshot(); + } else if (wss) { + const data = JSON.stringify({ + type: "progress", + torrents: snapshot() + }); + wss.clients.forEach((c) => c.readyState === 1 && c.send(data)); + } + }); + } else { + // Torrent eşleşmediyse de listeyi tazele (ör. sade dosya silinmiştir) + if (typeof broadcastSnapshot === "function") { + broadcastSnapshot(); + } else if (wss) { + const data = JSON.stringify({ type: "progress", torrents: snapshot() }); + wss.clients.forEach((c) => c.readyState === 1 && c.send(data)); + } + } + + res.json({ ok: true }); + } catch (err) { + console.error("❌ Dosya silinemedi:", err.message); + res.status(500).json({ error: err.message }); + } +}); + // --- 📁 Dosya gezgini (🆕 type ve url alanları eklendi; resim thumb'ı) --- app.get("/api/files", requireAuth, (req, res) => { // --- 🧩 .ignoreFiles içeriğini oku ---