diff --git a/public/app.js b/public/app.js
index c01cc9f..88193cc 100644
--- a/public/app.js
+++ b/public/app.js
@@ -458,6 +458,24 @@ function createDownloadCard(download) {
const completed = createDetailItem('Completed', formatDate(download.completedAt));
details.appendChild(completed);
}
+
+ if (isAdmin && (download.downloadPath || download.targetPath)) {
+ const pathsDiv = document.createElement('div');
+ pathsDiv.className = 'download-paths';
+ if (download.downloadPath) {
+ const dlPath = document.createElement('div');
+ dlPath.className = 'path-item';
+ dlPath.innerHTML = 'Download: ' + escapeHtml(download.downloadPath) + '';
+ pathsDiv.appendChild(dlPath);
+ }
+ if (download.targetPath) {
+ const tgtPath = document.createElement('div');
+ tgtPath.className = 'path-item';
+ tgtPath.innerHTML = 'Target: ' + escapeHtml(download.targetPath) + '';
+ pathsDiv.appendChild(tgtPath);
+ }
+ details.appendChild(pathsDiv);
+ }
infoDiv.appendChild(details);
card.appendChild(infoDiv);
@@ -484,6 +502,12 @@ function createDetailItem(label, value) {
return item;
}
+function escapeHtml(str) {
+ const div = document.createElement('div');
+ div.textContent = str;
+ return div.innerHTML;
+}
+
function formatSize(size) {
if (!size) return 'N/A';
// If already a formatted string (e.g., "21.5 GB"), return as-is
diff --git a/public/style.css b/public/style.css
index cd72a7b..be0284b 100644
--- a/public/style.css
+++ b/public/style.css
@@ -602,6 +602,36 @@ body {
accent-color: var(--accent);
}
+/* ===== Download Paths (Admin) ===== */
+.download-paths {
+ flex-basis: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ margin-top: 2px;
+}
+
+.path-item {
+ font-size: 0.7rem;
+ font-family: 'SF Mono', 'Fira Code', 'Fira Mono', Menlo, Consolas, monospace;
+ color: var(--text-muted);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.path-label {
+ font-weight: 600;
+ color: var(--text-secondary);
+ font-size: 0.65rem;
+ text-transform: uppercase;
+ letter-spacing: 0.3px;
+}
+
+.path-value {
+ color: var(--text-muted);
+}
+
.download-user-badge {
padding: 2px 8px;
border-radius: 10px;
diff --git a/server/routes/dashboard.js b/server/routes/dashboard.js
index db1671d..3a37e74 100644
--- a/server/routes/dashboard.js
+++ b/server/routes/dashboard.js
@@ -304,7 +304,7 @@ router.get('/user-downloads', async (req, res) => {
if (series) {
const userTag = extractUserTag(series.tags, sonarrTagMap);
if (userTag && (showAll || userTag.toLowerCase() === username)) {
- userDownloads.push({
+ const dlObj = {
type: 'series',
title: nzbName,
coverArt: getCoverArt(series),
@@ -318,7 +318,12 @@ router.get('/user-downloads', async (req, res) => {
seriesName: series.title,
episodeInfo: sonarrMatch,
userTag: userTag
- });
+ };
+ if (isAdmin) {
+ dlObj.downloadPath = slot.storage || null;
+ dlObj.targetPath = series.path || null;
+ }
+ userDownloads.push(dlObj);
}
}
}
@@ -334,7 +339,7 @@ router.get('/user-downloads', async (req, res) => {
if (movie) {
const userTag = extractUserTag(movie.tags, radarrTagMap);
if (userTag && (showAll || userTag.toLowerCase() === username)) {
- userDownloads.push({
+ const dlObj = {
type: 'movie',
title: nzbName,
coverArt: getCoverArt(movie),
@@ -348,7 +353,12 @@ router.get('/user-downloads', async (req, res) => {
movieName: movie.title,
movieInfo: radarrMatch,
userTag: userTag
- });
+ };
+ if (isAdmin) {
+ dlObj.downloadPath = slot.storage || null;
+ dlObj.targetPath = movie.path || null;
+ }
+ userDownloads.push(dlObj);
}
}
}
@@ -381,7 +391,7 @@ router.get('/user-downloads', async (req, res) => {
if (series) {
const userTag = extractUserTag(series.tags, sonarrTagMap);
if (userTag && (showAll || userTag.toLowerCase() === username)) {
- userDownloads.push({
+ const dlObj = {
type: 'series',
title: nzbName,
coverArt: getCoverArt(series),
@@ -391,7 +401,12 @@ router.get('/user-downloads', async (req, res) => {
seriesName: series.title,
episodeInfo: sonarrMatch,
userTag: userTag
- });
+ };
+ if (isAdmin) {
+ dlObj.downloadPath = slot.storage || null;
+ dlObj.targetPath = series.path || null;
+ }
+ userDownloads.push(dlObj);
}
}
}
@@ -407,7 +422,7 @@ router.get('/user-downloads', async (req, res) => {
if (movie) {
const userTag = extractUserTag(movie.tags, radarrTagMap);
if (userTag && (showAll || userTag.toLowerCase() === username)) {
- userDownloads.push({
+ const dlObj = {
type: 'movie',
title: nzbName,
coverArt: getCoverArt(movie),
@@ -417,7 +432,12 @@ router.get('/user-downloads', async (req, res) => {
movieName: movie.title,
movieInfo: radarrMatch,
userTag: userTag
- });
+ };
+ if (isAdmin) {
+ dlObj.downloadPath = slot.storage || null;
+ dlObj.targetPath = movie.path || null;
+ }
+ userDownloads.push(dlObj);
}
}
}
@@ -476,6 +496,10 @@ router.get('/user-downloads', async (req, res) => {
download.seriesName = series.title;
download.episodeInfo = sonarrMatch;
download.userTag = userTag;
+ if (isAdmin) {
+ download.downloadPath = download.savePath || null;
+ download.targetPath = series.path || null;
+ }
userDownloads.push(download);
continue; // Skip to next torrent
}
@@ -500,6 +524,10 @@ router.get('/user-downloads', async (req, res) => {
download.movieName = movie.title;
download.movieInfo = radarrMatch;
download.userTag = userTag;
+ if (isAdmin) {
+ download.downloadPath = download.savePath || null;
+ download.targetPath = movie.path || null;
+ }
userDownloads.push(download);
continue; // Skip to next torrent
}
@@ -524,6 +552,10 @@ router.get('/user-downloads', async (req, res) => {
download.seriesName = series.title;
download.episodeInfo = sonarrHistoryMatch;
download.userTag = userTag;
+ if (isAdmin) {
+ download.downloadPath = download.savePath || null;
+ download.targetPath = series.path || null;
+ }
userDownloads.push(download);
continue;
}
@@ -548,6 +580,10 @@ router.get('/user-downloads', async (req, res) => {
download.movieName = movie.title;
download.movieInfo = radarrHistoryMatch;
download.userTag = userTag;
+ if (isAdmin) {
+ download.downloadPath = download.savePath || null;
+ download.targetPath = movie.path || null;
+ }
userDownloads.push(download);
continue;
}
diff --git a/server/utils/qbittorrent.js b/server/utils/qbittorrent.js
index 5cb4846..91d06b2 100644
--- a/server/utils/qbittorrent.js
+++ b/server/utils/qbittorrent.js
@@ -198,6 +198,7 @@ function mapTorrentToDownload(torrent) {
hash: torrent.hash,
category: torrent.category,
tags: torrent.tags,
+ savePath: torrent.save_path || torrent.content_path || null,
qbittorrent: true
};
}