diff --git a/server/routes/history.js b/server/routes/history.js index 28f4d3e..89fb331 100644 --- a/server/routes/history.js +++ b/server/routes/history.js @@ -1,5 +1,6 @@ const express = require('express'); const router = express.Router(); +const axios = require('axios'); const requireAuth = require('../middleware/requireAuth'); const cache = require('../utils/cache'); const { fetchSonarrHistory, fetchRadarrHistory, classifySonarrEvent, classifyRadarrEvent } = require('../utils/historyFetcher'); @@ -48,6 +49,39 @@ function extractUserTag(tags, tagMap, username) { return null; } +async function getEmbyUsers() { + const cached = cache.get('emby:users'); + if (cached) return cached; + try { + const embyUrl = process.env.EMBY_URL; + const embyKey = process.env.EMBY_API_KEY; + if (!embyUrl || !embyKey) return new Map(); + const res = await axios.get(`${embyUrl}/Users`, { params: { api_key: embyKey } }); + const users = res.data || []; + const map = new Map(); + for (const u of users) { + if (!u.Name) continue; + const lower = u.Name.toLowerCase(); + map.set(lower, u.Name); + map.set(sanitizeTagLabel(lower), u.Name); + } + cache.set('emby:users', map, 60000); + return map; + } catch (err) { + console.error('[History] Failed to fetch Emby users:', err.message); + return new Map(); + } +} + +function buildTagBadges(allTags, embyUserMap) { + return allTags.map(label => { + const lower = label.toLowerCase(); + const sanitized = sanitizeTagLabel(label); + const matchedUser = embyUserMap.get(lower) || embyUserMap.get(sanitized) || null; + return { label, matchedUser }; + }); +} + function getSonarrLink(series) { if (!series || !series._instanceUrl || !series.titleSlug) return null; return `${series._instanceUrl}/series/${series.titleSlug}`; @@ -109,9 +143,10 @@ router.get('/recent', requireAuth, async (req, res) => { const sonarrInstances = getSonarrInstances(); const radarrInstances = getRadarrInstances(); - const [sonarrHistory, radarrHistory] = await Promise.all([ + const [sonarrHistory, radarrHistory, embyUserMap] = await Promise.all([ fetchSonarrHistory(since), - fetchRadarrHistory(since) + fetchRadarrHistory(since), + showAll ? getEmbyUsers() : Promise.resolve(new Map()) ]); // Build tag maps from the cached poll data where available, @@ -153,7 +188,8 @@ router.get('/recent', requireAuth, async (req, res) => { instanceName: record._instanceName || null, arrLink: getSonarrLink(series), allTags, - matchedUserTag: matchedUserTag || null + matchedUserTag: matchedUserTag || null, + tagBadges: showAll ? buildTagBadges(allTags, embyUserMap) : undefined }; if (isAdmin) { @@ -199,7 +235,8 @@ router.get('/recent', requireAuth, async (req, res) => { instanceName: record._instanceName || null, arrLink: getRadarrLink(movie), allTags, - matchedUserTag: matchedUserTag || null + matchedUserTag: matchedUserTag || null, + tagBadges: showAll ? buildTagBadges(allTags, embyUserMap) : undefined }; if (isAdmin) {