From 4c1b11c3cc71b6376859c3179b826519d2aa95e5 Mon Sep 17 00:00:00 2001 From: Gronod Date: Fri, 15 May 2026 21:46:43 +0100 Subject: [PATCH] fix: handle Ombi-mangled tags for email-style usernames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replicate Ombi's SanitizeTagLabel logic (lowercase, replace non-alnum with hyphen, collapse, trim) - Try exact tag match first (handles users with normal usernames) - Fall back to sanitized comparison (handles email usernames like robcunn@live.co.uk → robcunn-live-co-uk) - Applied to all tag matching locations --- server/routes/dashboard.js | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) 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';