fix(matching): Match SAB to Sonarr by downloadId first
All checks were successful
All checks were successful
Sonarr tracks the exact SAB download ID (nzo_id). Now tries to match by downloadId first, then falls back to title matching. Also adds debug to show if matches are via downloadId vs title, and logs downloadIds in history to verify the link exists.
This commit is contained in:
@@ -1016,21 +1016,38 @@ router.get('/stream', requireAuth, async (req, res) => {
|
||||
// Normalize SAB name (dots to spaces) for better matching
|
||||
const nzbNameNormalized = nzbNameLower.replace(/\./g, ' ');
|
||||
|
||||
// Check Sonarr/Radarr QUEUE (active downloads)
|
||||
let sonarrMatch = sonarrQueue.data.records.find(r => {
|
||||
const rTitle = (r.title || r.sourceTitle || '').toLowerCase();
|
||||
return rTitle && (
|
||||
rTitle.includes(nzbNameLower) || nzbNameLower.includes(rTitle) ||
|
||||
rTitle.includes(nzbNameNormalized) || nzbNameNormalized.includes(rTitle)
|
||||
);
|
||||
});
|
||||
let radarrMatch = radarrQueue.data.records.find(r => {
|
||||
const rTitle = (r.title || r.sourceTitle || '').toLowerCase();
|
||||
return rTitle && (
|
||||
rTitle.includes(nzbNameLower) || nzbNameLower.includes(rTitle) ||
|
||||
rTitle.includes(nzbNameNormalized) || nzbNameNormalized.includes(rTitle)
|
||||
);
|
||||
});
|
||||
// Try to match by downloadId first (most reliable)
|
||||
const sabDownloadId = slot.nzo_id || slot.id;
|
||||
let sonarrMatch = sabDownloadId ? sonarrQueue.data.records.find(r => r.downloadId === sabDownloadId) : null;
|
||||
let radarrMatch = sabDownloadId ? radarrQueue.data.records.find(r => r.downloadId === sabDownloadId) : null;
|
||||
|
||||
// Also check HISTORY by downloadId
|
||||
if (!sonarrMatch && sabDownloadId) {
|
||||
sonarrMatch = sonarrHistory.data.records.find(r => r.downloadId === sabDownloadId);
|
||||
}
|
||||
if (!radarrMatch && sabDownloadId) {
|
||||
radarrMatch = radarrHistory.data.records.find(r => r.downloadId === sabDownloadId);
|
||||
}
|
||||
|
||||
// Fallback: Check by title matching
|
||||
if (!sonarrMatch) {
|
||||
sonarrMatch = sonarrQueue.data.records.find(r => {
|
||||
const rTitle = (r.title || r.sourceTitle || '').toLowerCase();
|
||||
return rTitle && (
|
||||
rTitle.includes(nzbNameLower) || nzbNameLower.includes(rTitle) ||
|
||||
rTitle.includes(nzbNameNormalized) || nzbNameNormalized.includes(rTitle)
|
||||
);
|
||||
});
|
||||
}
|
||||
if (!radarrMatch) {
|
||||
radarrMatch = radarrQueue.data.records.find(r => {
|
||||
const rTitle = (r.title || r.sourceTitle || '').toLowerCase();
|
||||
return rTitle && (
|
||||
rTitle.includes(nzbNameLower) || nzbNameLower.includes(rTitle) ||
|
||||
rTitle.includes(nzbNameNormalized) || nzbNameNormalized.includes(rTitle)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Also check HISTORY (completed downloads) if no queue match
|
||||
if (!sonarrMatch) {
|
||||
@@ -1055,19 +1072,29 @@ router.get('/stream', requireAuth, async (req, res) => {
|
||||
if (sabSlotsChecked <= 5) {
|
||||
if (sonarrMatch) {
|
||||
const source = sonarrQueue.data.records.includes(sonarrMatch) ? 'queue' : 'history';
|
||||
console.log(`[SSE] ✓ Sonarr ${source} match: SAB:"${nzbNameLower.substring(0, 50)}" → Sonarr:"${(sonarrMatch.title || sonarrMatch.sourceTitle || '').substring(0, 50)}"`);
|
||||
const matchType = (sonarrMatch.downloadId === sabDownloadId) ? 'downloadId' : 'title';
|
||||
console.log(`[SSE] ✓ Sonarr ${source} ${matchType} match: SAB:"${nzbNameLower.substring(0, 40)}" → Sonarr:"${(sonarrMatch.title || sonarrMatch.sourceTitle || '').substring(0, 40)}"`);
|
||||
} else if (radarrMatch) {
|
||||
const source = radarrQueue.data.records.includes(radarrMatch) ? 'queue' : 'history';
|
||||
console.log(`[SSE] ✓ Radarr ${source} match: SAB:"${nzbNameLower.substring(0, 50)}" → Radarr:"${(radarrMatch.title || radarrMatch.sourceTitle || '').substring(0, 50)}"`);
|
||||
const matchType = (radarrMatch.downloadId === sabDownloadId) ? 'downloadId' : 'title';
|
||||
console.log(`[SSE] ✓ Radarr ${source} ${matchType} match: SAB:"${nzbNameLower.substring(0, 40)}" → Radarr:"${(radarrMatch.title || radarrMatch.sourceTitle || '').substring(0, 40)}"`);
|
||||
} else {
|
||||
console.log(`[SSE] ✗ No match for SAB: "${nzbNameLower.substring(0, 60)}"`);
|
||||
// Show counts
|
||||
console.log(`[SSE] Queue: ${sonarrQueue.data.records.length}, History: ${sonarrHistory.data.records.length}`);
|
||||
// Show history titles if there are any
|
||||
if (sonarrHistory.data.records.length > 0) {
|
||||
const histTitles = sonarrHistory.data.records.slice(0, 3).map(r => (r.title || r.sourceTitle || 'NO_TITLE').substring(0, 40));
|
||||
const histTitles = sonarrHistory.data.records.slice(0, 3).map(r => {
|
||||
const title = (r.title || r.sourceTitle || 'NO_TITLE').substring(0, 35);
|
||||
const dlId = r.downloadId ? r.downloadId.substring(0, 15) : 'no-dl-id';
|
||||
return `${title}[${dlId}]`;
|
||||
});
|
||||
console.log(`[SSE] History titles: ${histTitles.join(' | ')}`);
|
||||
}
|
||||
// Also check if SAB slots have nzo_id we could use
|
||||
if (slot.nzo_id) {
|
||||
console.log(`[SSE] SAB nzo_id: ${slot.nzo_id.substring(0, 20)}...`);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sonarrMatch && sonarrMatch.seriesId) {
|
||||
|
||||
Reference in New Issue
Block a user