Added deletion and simultaneous deletion of files/transfers on the Files screen.
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -62,7 +62,8 @@
|
|||||||
|
|
||||||
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" });
|
||||||
|
torrents = torrents.filter(t => t.infoHash !== hash);
|
||||||
await list();
|
await list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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'ı) ---
|
// --- 📁 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 ---
|
||||||
|
|||||||
Reference in New Issue
Block a user