fix(rclone): ilerleme takibini ve mount kontrolünü iyileştir

İlerleme güncellemelerinde artık hedef dosya/dizin GDrive'da mevcutsa
durum "done" olarak işaretleniyor. Transfer eşleştirmesi birden fazla
prefix desteği ile daha doğru çalışıyor. Cache temizleme işleminde
vfs/refresh kullanılıyor ve mount işlemlerinden önce aktiflik kontrolü
eklendi.
This commit is contained in:
2026-02-02 19:04:04 +03:00
parent a95c844af9
commit e34b8fc024

View File

@@ -835,9 +835,14 @@ function updateMoveProgressFromStats(stats) {
if (!stats) return false; if (!stats) return false;
const transfers = Array.isArray(stats.transferring) ? stats.transferring : []; const transfers = Array.isArray(stats.transferring) ? stats.transferring : [];
let updated = false; let updated = false;
const applyProgress = (entry, prefix) => { const applyProgress = (entry, prefixes, relRoot) => {
if (!entry) return; if (!entry) return;
const matched = transfers.filter((t) => String(t.name || "").includes(prefix)); const safePrefixes = Array.isArray(prefixes)
? prefixes.filter(Boolean)
: [prefixes].filter(Boolean);
const matched = transfers.filter((t) =>
safePrefixes.some((p) => String(t.name || "").includes(p))
);
if (matched.length) { if (matched.length) {
const bytes = matched.reduce((sum, t) => sum + (Number(t.bytes) || 0), 0); const bytes = matched.reduce((sum, t) => sum + (Number(t.bytes) || 0), 0);
const pct = matched.reduce((sum, t) => sum + (Number(t.percentage) || 0), 0) / matched.length; const pct = matched.reduce((sum, t) => sum + (Number(t.percentage) || 0), 0) / matched.length;
@@ -859,8 +864,14 @@ function updateMoveProgressFromStats(stats) {
updated = true; updated = true;
} }
} else { } else {
// Transfer görünmüyorsa queued kalır; done kararı aşağıda verilecek. const gdriveTarget = relRoot ? path.join(GDRIVE_ROOT, relRoot) : null;
if (entry.moveStatus === "uploading") { const targetExists = gdriveTarget ? fs.existsSync(gdriveTarget) : false;
if (targetExists) {
entry.moveStatus = "done";
entry.moveProgress = 1;
updated = true;
} else if (entry.moveStatus === "uploading") {
// Transfer görünmüyorsa queued kalır; done kararı yukarıda olabilir.
entry.moveStatus = "queued"; entry.moveStatus = "queued";
updated = true; updated = true;
} }
@@ -868,15 +879,29 @@ function updateMoveProgressFromStats(stats) {
}; };
for (const entry of torrents.values()) { for (const entry of torrents.values()) {
applyProgress(entry, `${RCLONE_REMOTE_PATH}/${entry.rootFolder || ""}`); const relRoot = entry.rootFolder || "";
const prefixes = [
relRoot,
RCLONE_REMOTE_PATH ? `${RCLONE_REMOTE_PATH}/${relRoot}` : null
];
applyProgress(entry, prefixes, relRoot);
} }
for (const job of youtubeJobs.values()) { for (const job of youtubeJobs.values()) {
applyProgress(job, `${RCLONE_REMOTE_PATH}/${job.folderId || ""}`); const relRoot = job.folderId || "";
const prefixes = [
relRoot,
RCLONE_REMOTE_PATH ? `${RCLONE_REMOTE_PATH}/${relRoot}` : null
];
applyProgress(job, prefixes, relRoot);
} }
for (const job of mailruJobs.values()) { for (const job of mailruJobs.values()) {
const folderPrefix = job.folderId ? `${RCLONE_REMOTE_PATH}/${job.folderId}` : null; const relRoot = job.folderId || "";
if (folderPrefix) { const prefixes = [
applyProgress(job, folderPrefix); relRoot,
RCLONE_REMOTE_PATH ? `${RCLONE_REMOTE_PATH}/${relRoot}` : null
];
if (relRoot) {
applyProgress(job, prefixes, relRoot);
} }
} }
@@ -1004,17 +1029,17 @@ function startRcloneCacheCleanSchedule(minutes) {
if (!interval || interval <= 0) return; if (!interval || interval <= 0) return;
rcloneCacheCleanTimer = setInterval(() => { rcloneCacheCleanTimer = setInterval(() => {
if (!RCLONE_RC_ENABLED) return; if (!RCLONE_RC_ENABLED) return;
fetch(`http://${RCLONE_RC_ADDR}/vfs/forget`, { fetch(`http://${RCLONE_RC_ADDR}/vfs/refresh`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path: "", recursive: true }) body: JSON.stringify({ recursive: true })
}) })
.then((resp) => { .then((resp) => {
if (resp.status === 404) { if (resp.status === 404) {
return fetch(`http://${RCLONE_RC_ADDR}/rc/vfs/forget`, { return fetch(`http://${RCLONE_RC_ADDR}/rc/vfs/refresh`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path: "", recursive: true }) body: JSON.stringify({ recursive: true })
}); });
} }
return resp; return resp;
@@ -1032,16 +1057,16 @@ async function runRcloneCacheClean() {
const wasRunning = Boolean(rcloneProcess && !rcloneProcess.killed); const wasRunning = Boolean(rcloneProcess && !rcloneProcess.killed);
try { try {
if (wasRunning && RCLONE_RC_ENABLED) { if (wasRunning && RCLONE_RC_ENABLED) {
const resp = await fetch(`http://${RCLONE_RC_ADDR}/vfs/forget`, { const resp = await fetch(`http://${RCLONE_RC_ADDR}/vfs/refresh`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path: "", recursive: true }) body: JSON.stringify({ recursive: true })
}); });
if (resp.status === 404) { if (resp.status === 404) {
const fallback = await fetch(`http://${RCLONE_RC_ADDR}/rc/vfs/forget`, { const fallback = await fetch(`http://${RCLONE_RC_ADDR}/rc/vfs/refresh`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path: "", recursive: true }) body: JSON.stringify({ recursive: true })
}); });
if (!fallback.ok) { if (!fallback.ok) {
const body = await fallback.text(); const body = await fallback.text();
@@ -1194,8 +1219,16 @@ async function moveRootFolderToGdrive(rootFolder) {
if (!fs.existsSync(sourceDir)) { if (!fs.existsSync(sourceDir)) {
return { ok: false, error: "Kaynak root bulunamadı" }; return { ok: false, error: "Kaynak root bulunamadı" };
} }
try {
ensureRcloneDirs({ mountDir: GDRIVE_ROOT });
} catch (err) {
return { ok: false, error: err?.message || String(err) };
}
if (!fs.existsSync(GDRIVE_ROOT)) { if (!fs.existsSync(GDRIVE_ROOT)) {
return { ok: false, error: "GDrive mount dizini bulunamadı" }; return { ok: false, error: `GDrive mount dizini bulunamadı: ${GDRIVE_ROOT}` };
}
if (!isRcloneMounted(GDRIVE_ROOT)) {
return { ok: false, error: "GDrive mount aktif değil" };
} }
const targetDir = path.join(GDRIVE_ROOT, safeRoot); const targetDir = path.join(GDRIVE_ROOT, safeRoot);
if (fs.existsSync(targetDir)) { if (fs.existsSync(targetDir)) {
@@ -1228,6 +1261,17 @@ async function movePathToGdrive(relPath) {
if (!safeRel) return { ok: false, error: "Geçersiz yol" }; if (!safeRel) return { ok: false, error: "Geçersiz yol" };
const sourceFile = path.join(DOWNLOAD_DIR, safeRel); const sourceFile = path.join(DOWNLOAD_DIR, safeRel);
if (fs.existsSync(sourceFile) && fs.statSync(sourceFile).isFile()) { if (fs.existsSync(sourceFile) && fs.statSync(sourceFile).isFile()) {
try {
ensureRcloneDirs({ mountDir: GDRIVE_ROOT });
} catch (err) {
return { ok: false, error: err?.message || String(err) };
}
if (!fs.existsSync(GDRIVE_ROOT)) {
return { ok: false, error: `GDrive mount dizini bulunamadı: ${GDRIVE_ROOT}` };
}
if (!isRcloneMounted(GDRIVE_ROOT)) {
return { ok: false, error: "GDrive mount aktif değil" };
}
const targetFile = path.join(GDRIVE_ROOT, safeRel); const targetFile = path.join(GDRIVE_ROOT, safeRel);
ensureDirForFile(targetFile); ensureDirForFile(targetFile);
try { try {