File browser özelliği eklendi.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
113
server/server.js
113
server/server.js
@@ -2939,6 +2939,37 @@ app.get("/api/files", requireAuth, (req, res) => {
|
|||||||
if (isIgnored(entry.name) || isIgnored(rel)) continue;
|
if (isIgnored(entry.name) || isIgnored(rel)) continue;
|
||||||
|
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
|
const safeRel = sanitizeRelative(rel);
|
||||||
|
if (!safeRel) continue;
|
||||||
|
|
||||||
|
const dirInfo = getInfo(safeRel) || {};
|
||||||
|
const rootFolder = rootFromRelPath(safeRel);
|
||||||
|
const added = dirInfo.added ?? dirInfo.createdAt ?? null;
|
||||||
|
const completedAt = dirInfo.completedAt ?? null;
|
||||||
|
const tracker = dirInfo.tracker ?? null;
|
||||||
|
const torrentName = dirInfo.name ?? null;
|
||||||
|
const infoHash = dirInfo.infoHash ?? null;
|
||||||
|
|
||||||
|
result.push({
|
||||||
|
name: safeRel,
|
||||||
|
size: 0,
|
||||||
|
type: "inode/directory",
|
||||||
|
isDirectory: true,
|
||||||
|
rootFolder,
|
||||||
|
added,
|
||||||
|
completedAt,
|
||||||
|
tracker,
|
||||||
|
torrentName,
|
||||||
|
infoHash,
|
||||||
|
extension: null,
|
||||||
|
mediaInfo: null,
|
||||||
|
primaryVideoPath: null,
|
||||||
|
primaryMediaInfo: null,
|
||||||
|
movieMatch: null,
|
||||||
|
seriesEpisode: null,
|
||||||
|
thumbnail: null,
|
||||||
|
});
|
||||||
|
|
||||||
result = result.concat(walk(full));
|
result = result.concat(walk(full));
|
||||||
} else {
|
} else {
|
||||||
if (entry.name.toLowerCase() === INFO_FILENAME) continue;
|
if (entry.name.toLowerCase() === INFO_FILENAME) continue;
|
||||||
@@ -4059,6 +4090,88 @@ app.post("/api/match/manual", requireAuth, async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- Klasör oluşturma endpoint'i ---
|
||||||
|
app.post("/api/folder", requireAuth, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { name, path: targetPath } = req.body;
|
||||||
|
|
||||||
|
if (!name || !targetPath) {
|
||||||
|
return res.status(400).json({ error: "Klasör adı ve yol gerekli" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Güvenli yol kontrolü
|
||||||
|
const safePath = sanitizeRelative(targetPath);
|
||||||
|
if (!safePath) {
|
||||||
|
return res.status(400).json({ error: "Geçersiz klasör yolu" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullPath = path.join(DOWNLOAD_DIR, safePath);
|
||||||
|
|
||||||
|
// Klasörü oluştur
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(fullPath, { recursive: true });
|
||||||
|
console.log(`📁 Klasör oluşturuldu: ${fullPath}`);
|
||||||
|
|
||||||
|
// İlişkili info.json dosyasını güncelle
|
||||||
|
const rootFolder = rootFromRelPath(safePath);
|
||||||
|
if (rootFolder) {
|
||||||
|
const rootDir = path.join(DOWNLOAD_DIR, rootFolder);
|
||||||
|
upsertInfoFile(rootDir, {
|
||||||
|
folder: rootFolder,
|
||||||
|
updatedAt: Date.now()
|
||||||
|
});
|
||||||
|
broadcastFileUpdate(rootFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /downloads klasörüne de aynı yapıda oluştur
|
||||||
|
try {
|
||||||
|
// Mevcut yolun yapısını analiz et
|
||||||
|
const pathSegments = safePath.split('/').filter(Boolean);
|
||||||
|
|
||||||
|
// Eğer mevcut dizin Home ise doğrudan downloads içine oluştur
|
||||||
|
if (pathSegments.length === 1) {
|
||||||
|
const downloadsPath = path.join(DOWNLOAD_DIR, name);
|
||||||
|
fs.mkdirSync(downloadsPath, { recursive: true });
|
||||||
|
console.log(`📁 Downloads klasörü oluşturuldu: ${downloadsPath}`);
|
||||||
|
} else {
|
||||||
|
// İç içe klasör yapısını koru
|
||||||
|
// Örn: Home/IT.Welcome.to.Derry.S01E01.1080p.x265-ELiTE ise
|
||||||
|
// downloads/1761836594224/IT.Welcome.to.Derry.S01E01.1080p.x265-ELiTE oluştur
|
||||||
|
const rootSegment = pathSegments[0]; // İlk segment (örn: 1761836594224)
|
||||||
|
const remainingPath = pathSegments.slice(1).join('/'); // Kalan path
|
||||||
|
|
||||||
|
const downloadsRootPath = path.join(DOWNLOAD_DIR, rootSegment);
|
||||||
|
const downloadsFullPath = path.join(downloadsRootPath, remainingPath);
|
||||||
|
|
||||||
|
fs.mkdirSync(downloadsFullPath, { recursive: true });
|
||||||
|
console.log(`📁 Downloads iç klasör oluşturuldu: ${downloadsFullPath}`);
|
||||||
|
}
|
||||||
|
} catch (downloadsErr) {
|
||||||
|
console.warn("⚠️ Downloads klasörü oluşturulamadı:", downloadsErr.message);
|
||||||
|
// Ana klasör oluşturulduysa hata döndürme
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: "Klasör başarıyla oluşturuldu",
|
||||||
|
path: safePath
|
||||||
|
});
|
||||||
|
} catch (mkdirErr) {
|
||||||
|
console.error("❌ Klasör oluşturma hatası:", mkdirErr);
|
||||||
|
const friendlyMessage =
|
||||||
|
mkdirErr?.code === "EACCES"
|
||||||
|
? "Sunucu bu dizine yazma iznine sahip değil. Lütfen downloads klasörünün izinlerini güncelle."
|
||||||
|
: "Klasör oluşturulamadı: " + (mkdirErr?.message || "Bilinmeyen hata");
|
||||||
|
res.status(500).json({
|
||||||
|
error: friendlyMessage
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("❌ Folder API error:", err);
|
||||||
|
res.status(500).json({ error: err.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
client.on("error", (err) => {
|
client.on("error", (err) => {
|
||||||
if (!String(err).includes("uTP"))
|
if (!String(err).includes("uTP"))
|
||||||
console.error("WebTorrent error:", err.message);
|
console.error("WebTorrent error:", err.message);
|
||||||
|
|||||||
Reference in New Issue
Block a user