Added deletion and simultaneous deletion of files/transfers on the Files screen.

This commit is contained in:
2025-10-24 20:51:44 +03:00
parent fb3b61e297
commit b79b60ea0f
3 changed files with 147 additions and 5 deletions

View File

@@ -188,6 +188,41 @@
reader.readAsArrayBuffer(file); 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/<hash>/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(() => { onMount(() => {
loadFiles(); loadFiles();
// ✅ Tek event handler içinde hem Esc hem ok tuşlarını kontrol et // ✅ Tek event handler içinde hem Esc hem ok tuşlarını kontrol et
@@ -244,6 +279,12 @@
<i class="fa-solid fa-image"></i> <i class="fa-solid fa-image"></i>
{/if} {/if}
</div> </div>
<div
class="delete-overlay"
on:click|stopPropagation={() => deleteFile(f)}
>
<i class="fa-solid fa-trash"></i>
</div>
</div> </div>
{/each} {/each}
</div> </div>
@@ -515,6 +556,45 @@
filter: drop-shadow(0 1px 1px rgba(255, 255, 255, 0.3)); 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 === */ /* === RESPONSIVE === */
@media (max-width: 768px) { @media (max-width: 768px) {
.gallery { .gallery {

View File

@@ -60,11 +60,12 @@
ws?.send(JSON.stringify({ type: "select", infoHash: hash, index })); ws?.send(JSON.stringify({ type: "select", infoHash: hash, index }));
} }
async function removeTorrent(hash) { async function removeTorrent(hash) {
if (!confirm("Bu transferi silmek istediğine emin misin?")) return; if (!confirm("Bu transferi silmek istediğine emin misin?")) return;
await apiFetch(`/api/torrents/${hash}`, { method: "DELETE" }); // ✅ await apiFetch(`/api/torrents/${hash}`, { method: "DELETE" });
await list(); torrents = torrents.filter(t => t.infoHash !== hash);
} await list();
}
function streamURL(hash, index = 0) { function streamURL(hash, index = 0) {
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");

View File

@@ -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 Mapinde, savePath'in son klasörü folderId olan entryyi 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 + Mapten 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'ı) --- // --- 📁 Dosya gezgini (🆕 type ve url alanları eklendi; resim thumb'ı) ---
app.get("/api/files", requireAuth, (req, res) => { app.get("/api/files", requireAuth, (req, res) => {
// --- 🧩 .ignoreFiles içeriğini oku --- // --- 🧩 .ignoreFiles içeriğini oku ---