(folder, name, inline = false, sourceId = "")
| 3355 | SECURITY: build file URLs only via the API (no /uploads) |
| 3356 | =========================================================== */ |
| 3357 | function apiFileUrl(folder, name, inline = false, sourceId = "") { |
| 3358 | const fParam = folder && folder !== "root" ? folder : "root"; |
| 3359 | const q = new URLSearchParams({ |
| 3360 | folder: fParam, |
| 3361 | file: name, |
| 3362 | inline: inline ? "1" : "0" |
| 3363 | }); |
| 3364 | let meta = null; |
| 3365 | let sid = String(sourceId || "").trim(); |
| 3366 | |
| 3367 | try { |
| 3368 | if (Array.isArray(fileData)) { |
| 3369 | meta = fileData.find( |
| 3370 | f => f.name === name && (f.folder || "root") === fParam |
| 3371 | ); |
| 3372 | if (!sid && meta && meta.sourceId) { |
| 3373 | sid = String(meta.sourceId || "").trim(); |
| 3374 | } |
| 3375 | } |
| 3376 | } catch (e) { /* best-effort only */ } |
| 3377 | |
| 3378 | if (!sid) { |
| 3379 | try { |
| 3380 | sid = String(getActivePaneSourceId() || "").trim(); |
| 3381 | } catch (e) { /* ignore */ } |
| 3382 | } |
| 3383 | if (sid) q.set("sourceId", sid); |
| 3384 | |
| 3385 | // Try to find this file in fileData to get a stable cache key |
| 3386 | if (meta) { |
| 3387 | const v = meta.cacheKey || meta.modified || meta.uploaded || meta.sizeBytes; |
| 3388 | if (v != null && v !== "") { |
| 3389 | q.set("t", String(v)); // stable per-file token |
| 3390 | } |
| 3391 | } |
| 3392 | |
| 3393 | return withBase(`/api/file/download.php?${q.toString()}`); |
| 3394 | } |
| 3395 | |
| 3396 | function apiMediaThumbUrl(folder, name, sourceId = "") { |
| 3397 | const fParam = folder && folder !== "root" ? folder : "root"; |
no test coverage detected