fix: extractUserTag now correctly finds the tag matching the current user
All checks were successful
Build and Push Docker Image / build (push) Successful in 27s
All checks were successful
Build and Push Docker Image / build (push) Successful in 27s
Previously extractUserTag returned the first tag in the list regardless of whether it matched the logged-in user, so matchedUserTag was wrong and unmatched tags weren't separated correctly. - extractUserTag(tags, tagMap, username): finds tag label that matches username via tagMatchesUser(); returns null if no match - extractAllTags(): moved before extractUserTag for readability - All 10 call sites in user-downloads pass username arg - user-summary uses extractAllTags() directly (wants all tags, not just the current user's) — as a bonus this now correctly counts items tagged for multiple users
This commit is contained in:
@@ -20,27 +20,9 @@ function getCoverArt(item) {
|
|||||||
return fanart ? (fanart.remoteUrl || fanart.url || null) : null;
|
return fanart ? (fanart.remoteUrl || fanart.url || null) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to extract user tag from series/movie
|
// Return all resolved tag labels for a series/movie.
|
||||||
// For Radarr: tags is array of IDs, tagMap is id -> label mapping
|
// For Radarr: tags is array of IDs, tagMap is id -> label mapping.
|
||||||
// For Sonarr: tags is array of objects with label property
|
// For Sonarr: tags are objects with a label property.
|
||||||
function extractUserTag(tags, tagMap) {
|
|
||||||
if (!tags || tags.length === 0) return null;
|
|
||||||
|
|
||||||
// If tagMap provided (Radarr), look up label by ID
|
|
||||||
if (tagMap) {
|
|
||||||
for (const tagId of tags) {
|
|
||||||
const label = tagMap.get(tagId);
|
|
||||||
if (label) return label;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sonarr style - tags are objects with label
|
|
||||||
const userTag = tags.find(tag => tag && tag.label);
|
|
||||||
return userTag ? userTag.label : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return all resolved tag labels for a series/movie
|
|
||||||
function extractAllTags(tags, tagMap) {
|
function extractAllTags(tags, tagMap) {
|
||||||
if (!tags || tags.length === 0) return [];
|
if (!tags || tags.length === 0) return [];
|
||||||
if (tagMap) {
|
if (tagMap) {
|
||||||
@@ -49,6 +31,17 @@ function extractAllTags(tags, tagMap) {
|
|||||||
return tags.map(t => t && t.label).filter(Boolean);
|
return tags.map(t => t && t.label).filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the tag label that matches the current username, or null.
|
||||||
|
function extractUserTag(tags, tagMap, username) {
|
||||||
|
const allLabels = extractAllTags(tags, tagMap);
|
||||||
|
if (!allLabels.length) return null;
|
||||||
|
if (username) {
|
||||||
|
const match = allLabels.find(label => tagMatchesUser(label, username));
|
||||||
|
if (match) return match;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Replicate Ombi's StringHelper.SanitizeTagLabel: lowercase, replace non-alphanumeric with hyphen, collapse, trim
|
// Replicate Ombi's StringHelper.SanitizeTagLabel: lowercase, replace non-alphanumeric with hyphen, collapse, trim
|
||||||
function sanitizeTagLabel(input) {
|
function sanitizeTagLabel(input) {
|
||||||
if (!input) return '';
|
if (!input) return '';
|
||||||
@@ -233,10 +226,10 @@ router.get('/user-downloads', async (req, res) => {
|
|||||||
if (sonarrMatch && sonarrMatch.seriesId) {
|
if (sonarrMatch && sonarrMatch.seriesId) {
|
||||||
const series = seriesMap.get(sonarrMatch.seriesId) || sonarrMatch.series;
|
const series = seriesMap.get(sonarrMatch.seriesId) || sonarrMatch.series;
|
||||||
if (series) {
|
if (series) {
|
||||||
const matchedUserTag = extractUserTag(series.tags, sonarrTagMap);
|
|
||||||
const allTags = extractAllTags(series.tags, sonarrTagMap);
|
const allTags = extractAllTags(series.tags, sonarrTagMap);
|
||||||
|
const matchedUserTag = extractUserTag(series.tags, sonarrTagMap, username);
|
||||||
const hasAnyTag = allTags.length > 0;
|
const hasAnyTag = allTags.length > 0;
|
||||||
if (showAll ? hasAnyTag : (matchedUserTag && tagMatchesUser(matchedUserTag, username))) {
|
if (showAll ? hasAnyTag : !!matchedUserTag) {
|
||||||
const dlObj = {
|
const dlObj = {
|
||||||
type: 'series',
|
type: 'series',
|
||||||
title: nzbName,
|
title: nzbName,
|
||||||
@@ -274,10 +267,10 @@ router.get('/user-downloads', async (req, res) => {
|
|||||||
if (radarrMatch && radarrMatch.movieId) {
|
if (radarrMatch && radarrMatch.movieId) {
|
||||||
const movie = moviesMap.get(radarrMatch.movieId) || radarrMatch.movie;
|
const movie = moviesMap.get(radarrMatch.movieId) || radarrMatch.movie;
|
||||||
if (movie) {
|
if (movie) {
|
||||||
const matchedUserTag = extractUserTag(movie.tags, radarrTagMap);
|
|
||||||
const allTags = extractAllTags(movie.tags, radarrTagMap);
|
const allTags = extractAllTags(movie.tags, radarrTagMap);
|
||||||
|
const matchedUserTag = extractUserTag(movie.tags, radarrTagMap, username);
|
||||||
const hasAnyTag = allTags.length > 0;
|
const hasAnyTag = allTags.length > 0;
|
||||||
if (showAll ? hasAnyTag : (matchedUserTag && tagMatchesUser(matchedUserTag, username))) {
|
if (showAll ? hasAnyTag : !!matchedUserTag) {
|
||||||
const dlObj = {
|
const dlObj = {
|
||||||
type: 'movie',
|
type: 'movie',
|
||||||
title: nzbName,
|
title: nzbName,
|
||||||
@@ -332,10 +325,10 @@ router.get('/user-downloads', async (req, res) => {
|
|||||||
if (sonarrMatch && sonarrMatch.seriesId) {
|
if (sonarrMatch && sonarrMatch.seriesId) {
|
||||||
const series = seriesMap.get(sonarrMatch.seriesId) || sonarrMatch.series;
|
const series = seriesMap.get(sonarrMatch.seriesId) || sonarrMatch.series;
|
||||||
if (series) {
|
if (series) {
|
||||||
const matchedUserTag = extractUserTag(series.tags, sonarrTagMap);
|
|
||||||
const allTags = extractAllTags(series.tags, sonarrTagMap);
|
const allTags = extractAllTags(series.tags, sonarrTagMap);
|
||||||
|
const matchedUserTag = extractUserTag(series.tags, sonarrTagMap, username);
|
||||||
const hasAnyTag = allTags.length > 0;
|
const hasAnyTag = allTags.length > 0;
|
||||||
if (showAll ? hasAnyTag : (matchedUserTag && tagMatchesUser(matchedUserTag, username))) {
|
if (showAll ? hasAnyTag : !!matchedUserTag) {
|
||||||
const dlObj = {
|
const dlObj = {
|
||||||
type: 'series',
|
type: 'series',
|
||||||
title: nzbName,
|
title: nzbName,
|
||||||
@@ -367,10 +360,10 @@ router.get('/user-downloads', async (req, res) => {
|
|||||||
if (radarrMatch && radarrMatch.movieId) {
|
if (radarrMatch && radarrMatch.movieId) {
|
||||||
const movie = moviesMap.get(radarrMatch.movieId) || radarrMatch.movie;
|
const movie = moviesMap.get(radarrMatch.movieId) || radarrMatch.movie;
|
||||||
if (movie) {
|
if (movie) {
|
||||||
const matchedUserTag = extractUserTag(movie.tags, radarrTagMap);
|
|
||||||
const allTags = extractAllTags(movie.tags, radarrTagMap);
|
const allTags = extractAllTags(movie.tags, radarrTagMap);
|
||||||
|
const matchedUserTag = extractUserTag(movie.tags, radarrTagMap, username);
|
||||||
const hasAnyTag = allTags.length > 0;
|
const hasAnyTag = allTags.length > 0;
|
||||||
if (showAll ? hasAnyTag : (matchedUserTag && tagMatchesUser(matchedUserTag, username))) {
|
if (showAll ? hasAnyTag : !!matchedUserTag) {
|
||||||
const dlObj = {
|
const dlObj = {
|
||||||
type: 'movie',
|
type: 'movie',
|
||||||
title: nzbName,
|
title: nzbName,
|
||||||
@@ -409,12 +402,10 @@ router.get('/user-downloads', async (req, res) => {
|
|||||||
|
|
||||||
// Show movies/series tagged for this user (from embedded objects in queue/history)
|
// Show movies/series tagged for this user (from embedded objects in queue/history)
|
||||||
const userMovies = Array.from(moviesMap.values()).filter(m => {
|
const userMovies = Array.from(moviesMap.values()).filter(m => {
|
||||||
const tag = extractUserTag(m.tags, radarrTagMap);
|
return !!extractUserTag(m.tags, radarrTagMap, username);
|
||||||
return tag && tagMatchesUser(tag, username);
|
|
||||||
});
|
});
|
||||||
const userSeries = Array.from(seriesMap.values()).filter(s => {
|
const userSeries = Array.from(seriesMap.values()).filter(s => {
|
||||||
const tag = extractUserTag(s.tags, sonarrTagMap);
|
return !!extractUserTag(s.tags, sonarrTagMap, username);
|
||||||
return tag && tagMatchesUser(tag, username);
|
|
||||||
});
|
});
|
||||||
console.log(`[Dashboard] Movies tagged for ${username}:`, userMovies.map(m => m.title));
|
console.log(`[Dashboard] Movies tagged for ${username}:`, userMovies.map(m => m.title));
|
||||||
console.log(`[Dashboard] Series tagged for ${username}:`, userSeries.map(s => s.title));
|
console.log(`[Dashboard] Series tagged for ${username}:`, userSeries.map(s => s.title));
|
||||||
@@ -438,10 +429,10 @@ router.get('/user-downloads', async (req, res) => {
|
|||||||
if (sonarrMatch && sonarrMatch.seriesId) {
|
if (sonarrMatch && sonarrMatch.seriesId) {
|
||||||
const series = seriesMap.get(sonarrMatch.seriesId) || sonarrMatch.series;
|
const series = seriesMap.get(sonarrMatch.seriesId) || sonarrMatch.series;
|
||||||
if (series) {
|
if (series) {
|
||||||
const matchedUserTag = extractUserTag(series.tags, sonarrTagMap);
|
|
||||||
const allTags = extractAllTags(series.tags, sonarrTagMap);
|
const allTags = extractAllTags(series.tags, sonarrTagMap);
|
||||||
|
const matchedUserTag = extractUserTag(series.tags, sonarrTagMap, username);
|
||||||
const hasAnyTag = allTags.length > 0;
|
const hasAnyTag = allTags.length > 0;
|
||||||
if (showAll ? hasAnyTag : (matchedUserTag && tagMatchesUser(matchedUserTag, username))) {
|
if (showAll ? hasAnyTag : !!matchedUserTag) {
|
||||||
console.log(`[Dashboard] Matched torrent "${torrentName}" to Sonarr series "${series.title}"`);
|
console.log(`[Dashboard] Matched torrent "${torrentName}" to Sonarr series "${series.title}"`);
|
||||||
const download = mapTorrentToDownload(torrent);
|
const download = mapTorrentToDownload(torrent);
|
||||||
download.type = 'series';
|
download.type = 'series';
|
||||||
@@ -472,10 +463,10 @@ router.get('/user-downloads', async (req, res) => {
|
|||||||
if (radarrMatch && radarrMatch.movieId) {
|
if (radarrMatch && radarrMatch.movieId) {
|
||||||
const movie = moviesMap.get(radarrMatch.movieId) || radarrMatch.movie;
|
const movie = moviesMap.get(radarrMatch.movieId) || radarrMatch.movie;
|
||||||
if (movie) {
|
if (movie) {
|
||||||
const matchedUserTag = extractUserTag(movie.tags, radarrTagMap);
|
|
||||||
const allTags = extractAllTags(movie.tags, radarrTagMap);
|
const allTags = extractAllTags(movie.tags, radarrTagMap);
|
||||||
|
const matchedUserTag = extractUserTag(movie.tags, radarrTagMap, username);
|
||||||
const hasAnyTag = allTags.length > 0;
|
const hasAnyTag = allTags.length > 0;
|
||||||
if (showAll ? hasAnyTag : (matchedUserTag && tagMatchesUser(matchedUserTag, username))) {
|
if (showAll ? hasAnyTag : !!matchedUserTag) {
|
||||||
console.log(`[Dashboard] Matched torrent "${torrentName}" to Radarr movie "${movie.title}"`);
|
console.log(`[Dashboard] Matched torrent "${torrentName}" to Radarr movie "${movie.title}"`);
|
||||||
const download = mapTorrentToDownload(torrent);
|
const download = mapTorrentToDownload(torrent);
|
||||||
download.type = 'movie';
|
download.type = 'movie';
|
||||||
@@ -506,10 +497,10 @@ router.get('/user-downloads', async (req, res) => {
|
|||||||
if (sonarrHistoryMatch && sonarrHistoryMatch.seriesId) {
|
if (sonarrHistoryMatch && sonarrHistoryMatch.seriesId) {
|
||||||
const series = seriesMap.get(sonarrHistoryMatch.seriesId) || sonarrHistoryMatch.series;
|
const series = seriesMap.get(sonarrHistoryMatch.seriesId) || sonarrHistoryMatch.series;
|
||||||
if (series) {
|
if (series) {
|
||||||
const matchedUserTag = extractUserTag(series.tags, sonarrTagMap);
|
|
||||||
const allTags = extractAllTags(series.tags, sonarrTagMap);
|
const allTags = extractAllTags(series.tags, sonarrTagMap);
|
||||||
|
const matchedUserTag = extractUserTag(series.tags, sonarrTagMap, username);
|
||||||
const hasAnyTag = allTags.length > 0;
|
const hasAnyTag = allTags.length > 0;
|
||||||
if (showAll ? hasAnyTag : (matchedUserTag && tagMatchesUser(matchedUserTag, username))) {
|
if (showAll ? hasAnyTag : !!matchedUserTag) {
|
||||||
console.log(`[Dashboard] Matched torrent "${torrentName}" to Sonarr history "${series.title}"`);
|
console.log(`[Dashboard] Matched torrent "${torrentName}" to Sonarr history "${series.title}"`);
|
||||||
const download = mapTorrentToDownload(torrent);
|
const download = mapTorrentToDownload(torrent);
|
||||||
download.type = 'series';
|
download.type = 'series';
|
||||||
@@ -538,10 +529,10 @@ router.get('/user-downloads', async (req, res) => {
|
|||||||
if (radarrHistoryMatch && radarrHistoryMatch.movieId) {
|
if (radarrHistoryMatch && radarrHistoryMatch.movieId) {
|
||||||
const movie = moviesMap.get(radarrHistoryMatch.movieId) || radarrHistoryMatch.movie;
|
const movie = moviesMap.get(radarrHistoryMatch.movieId) || radarrHistoryMatch.movie;
|
||||||
if (movie) {
|
if (movie) {
|
||||||
const matchedUserTag = extractUserTag(movie.tags, radarrTagMap);
|
|
||||||
const allTags = extractAllTags(movie.tags, radarrTagMap);
|
const allTags = extractAllTags(movie.tags, radarrTagMap);
|
||||||
|
const matchedUserTag = extractUserTag(movie.tags, radarrTagMap, username);
|
||||||
const hasAnyTag = allTags.length > 0;
|
const hasAnyTag = allTags.length > 0;
|
||||||
if (showAll ? hasAnyTag : (matchedUserTag && tagMatchesUser(matchedUserTag, username))) {
|
if (showAll ? hasAnyTag : !!matchedUserTag) {
|
||||||
console.log(`[Dashboard] Matched torrent "${torrentName}" to Radarr history "${movie.title}"`);
|
console.log(`[Dashboard] Matched torrent "${torrentName}" to Radarr history "${movie.title}"`);
|
||||||
const download = mapTorrentToDownload(torrent);
|
const download = mapTorrentToDownload(torrent);
|
||||||
download.type = 'movie';
|
download.type = 'movie';
|
||||||
@@ -636,24 +627,20 @@ router.get('/user-summary', async (req, res) => {
|
|||||||
|
|
||||||
// Process series tags
|
// Process series tags
|
||||||
allSeries.forEach(series => {
|
allSeries.forEach(series => {
|
||||||
const userTag = extractUserTag(series.tags, sonarrTagMap);
|
const tags = extractAllTags(series.tags, sonarrTagMap);
|
||||||
if (userTag) {
|
tags.forEach(userTag => {
|
||||||
const username = userTag.toLowerCase();
|
const uname = userTag.toLowerCase();
|
||||||
if (userDownloads[username]) {
|
if (userDownloads[uname]) userDownloads[uname].seriesCount++;
|
||||||
userDownloads[username].seriesCount++;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Process movie tags
|
// Process movie tags
|
||||||
allMovies.forEach(movie => {
|
allMovies.forEach(movie => {
|
||||||
const userTag = extractUserTag(movie.tags, radarrTagMap);
|
const tags = extractAllTags(movie.tags, radarrTagMap);
|
||||||
if (userTag) {
|
tags.forEach(userTag => {
|
||||||
const username = userTag.toLowerCase();
|
const uname = userTag.toLowerCase();
|
||||||
if (userDownloads[username]) {
|
if (userDownloads[uname]) userDownloads[uname].movieCount++;
|
||||||
userDownloads[username].movieCount++;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
res.json(Object.values(userDownloads));
|
res.json(Object.values(userDownloads));
|
||||||
|
|||||||
Reference in New Issue
Block a user