diff --git a/server/routes/dashboard.js b/server/routes/dashboard.js index d3dbe0c..4deb9bf 100644 --- a/server/routes/dashboard.js +++ b/server/routes/dashboard.js @@ -42,6 +42,23 @@ function extractUserTag(tags, tagMap) { return userTag ? userTag.label : null; } +// Replicate Ombi's StringHelper.SanitizeTagLabel: lowercase, replace non-alphanumeric with hyphen, collapse, trim +function sanitizeTagLabel(input) { + if (!input) return ''; + return input.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, ''); +} + +// Check if a tag matches the username: exact match first, then sanitized match +function tagMatchesUser(tag, username) { + if (!tag || !username) return false; + const tagLower = tag.toLowerCase(); + // Exact match (handles users whose tags weren't mangled) + if (tagLower === username) return true; + // Sanitized match (handles Ombi-mangled tags for email-style usernames) + if (tagLower === sanitizeTagLabel(username)) return true; + return false; +} + // Helper to build Sonarr web UI link for a series function getSonarrLink(series) { if (!series || !series._instanceUrl || !series.titleSlug) return null; @@ -65,6 +82,7 @@ router.get('/user-downloads', async (req, res) => { const user = JSON.parse(userCookie); const username = user.name.toLowerCase(); + const usernameSanitized = sanitizeTagLabel(user.name); const isAdmin = !!user.isAdmin; const showAll = isAdmin && req.query.showAll === 'true'; console.log(`[Dashboard] Fetching downloads for authenticated user: ${user.name} (${username}), isAdmin: ${isAdmin}, showAll: ${showAll}`); @@ -321,7 +339,7 @@ router.get('/user-downloads', async (req, res) => { const series = seriesMap.get(sonarrMatch.seriesId) || sonarrMatch.series; if (series) { const userTag = extractUserTag(series.tags, sonarrTagMap); - if (userTag && (showAll || userTag.toLowerCase() === username)) { + if (userTag && (showAll || tagMatchesUser(userTag, username))) { const dlObj = { type: 'series', title: nzbName, @@ -357,7 +375,7 @@ router.get('/user-downloads', async (req, res) => { const movie = moviesMap.get(radarrMatch.movieId) || radarrMatch.movie; if (movie) { const userTag = extractUserTag(movie.tags, radarrTagMap); - if (userTag && (showAll || userTag.toLowerCase() === username)) { + if (userTag && (showAll || tagMatchesUser(userTag, username))) { const dlObj = { type: 'movie', title: nzbName, @@ -410,7 +428,7 @@ router.get('/user-downloads', async (req, res) => { const series = seriesMap.get(sonarrMatch.seriesId) || sonarrMatch.series; if (series) { const userTag = extractUserTag(series.tags, sonarrTagMap); - if (userTag && (showAll || userTag.toLowerCase() === username)) { + if (userTag && (showAll || tagMatchesUser(userTag, username))) { const dlObj = { type: 'series', title: nzbName, @@ -442,7 +460,7 @@ router.get('/user-downloads', async (req, res) => { const movie = moviesMap.get(radarrMatch.movieId) || radarrMatch.movie; if (movie) { const userTag = extractUserTag(movie.tags, radarrTagMap); - if (userTag && (showAll || userTag.toLowerCase() === username)) { + if (userTag && (showAll || tagMatchesUser(userTag, username))) { const dlObj = { type: 'movie', title: nzbName, @@ -481,11 +499,11 @@ router.get('/user-downloads', async (req, res) => { // Show movies/series tagged for this user const userMovies = radarrMovies.data.filter(m => { const tag = extractUserTag(m.tags, radarrTagMap); - return tag && tag.toLowerCase() === username; + return tag && tagMatchesUser(tag, username); }); const userSeries = sonarrSeries.data.filter(s => { const tag = extractUserTag(s.tags, sonarrTagMap); - return tag && tag.toLowerCase() === username; + return tag && tagMatchesUser(tag, username); }); console.log(`[Dashboard] Movies tagged for ${username}:`, userMovies.map(m => m.title)); console.log(`[Dashboard] Series tagged for ${username}:`, userSeries.map(s => s.title)); @@ -510,7 +528,7 @@ router.get('/user-downloads', async (req, res) => { const series = seriesMap.get(sonarrMatch.seriesId) || sonarrMatch.series; if (series) { const userTag = extractUserTag(series.tags, sonarrTagMap); - if (userTag && (showAll || userTag.toLowerCase() === username)) { + if (userTag && (showAll || tagMatchesUser(userTag, username))) { console.log(`[Dashboard] Matched torrent "${torrentName}" to Sonarr series "${series.title}"`); const download = mapTorrentToDownload(torrent); download.type = 'series'; @@ -539,7 +557,7 @@ router.get('/user-downloads', async (req, res) => { const movie = moviesMap.get(radarrMatch.movieId) || radarrMatch.movie; if (movie) { const userTag = extractUserTag(movie.tags, radarrTagMap); - if (userTag && (showAll || userTag.toLowerCase() === username)) { + if (userTag && (showAll || tagMatchesUser(userTag, username))) { console.log(`[Dashboard] Matched torrent "${torrentName}" to Radarr movie "${movie.title}"`); const download = mapTorrentToDownload(torrent); download.type = 'movie'; @@ -568,7 +586,7 @@ router.get('/user-downloads', async (req, res) => { const series = seriesMap.get(sonarrHistoryMatch.seriesId) || sonarrHistoryMatch.series; if (series) { const userTag = extractUserTag(series.tags, sonarrTagMap); - if (userTag && (showAll || userTag.toLowerCase() === username)) { + if (userTag && (showAll || tagMatchesUser(userTag, username))) { console.log(`[Dashboard] Matched torrent "${torrentName}" to Sonarr history "${series.title}"`); const download = mapTorrentToDownload(torrent); download.type = 'series'; @@ -597,7 +615,7 @@ router.get('/user-downloads', async (req, res) => { const movie = moviesMap.get(radarrHistoryMatch.movieId) || radarrHistoryMatch.movie; if (movie) { const userTag = extractUserTag(movie.tags, radarrTagMap); - if (userTag && (showAll || userTag.toLowerCase() === username)) { + if (userTag && (showAll || tagMatchesUser(userTag, username))) { console.log(`[Dashboard] Matched torrent "${torrentName}" to Radarr history "${movie.title}"`); const download = mapTorrentToDownload(torrent); download.type = 'movie';