// ── Blocklist modal ──
// A proper artist/album/track blacklist. Search the active metadata source,
// block by ID (cross-source matched in the background so a ban survives a
// source switch), and manage existing bans. Opened from the Watchlist page.
// Distinct from the download-source blacklist.
let _blEntityType = 'artist'; // active tab: artist | album | track
let _blSearchSeq = 0; // guards against out-of-order search results
function openBlocklistModal(initialType) {
_blEntityType = ['artist', 'album', 'track'].includes(initialType) ? initialType : 'artist';
let overlay = document.getElementById('blocklist-modal-overlay');
if (!overlay) {
overlay = document.createElement('div');
overlay.id = 'blocklist-modal-overlay';
overlay.className = 'modal-overlay blocklist-modal-overlay';
overlay.innerHTML = `
Blocklist
Block an artist, album, or track from ever being downloaded. Matched across all your metadata sources.
Currently blocked
`;
overlay.addEventListener('click', (e) => { if (e.target === overlay) closeBlocklistModal(); });
document.body.appendChild(overlay);
}
overlay.classList.remove('hidden');
_blRefreshTabs();
_blLoadCurrent();
const input = document.getElementById('blocklist-search-input');
if (input) { input.value = ''; input.focus(); }
document.getElementById('blocklist-search-results').innerHTML = '';
}
function closeBlocklistModal() {
const o = document.getElementById('blocklist-modal-overlay');
if (o) o.classList.add('hidden');
}
function switchBlocklistTab(type) {
if (type === _blEntityType) return;
_blEntityType = type;
_blRefreshTabs();
const input = document.getElementById('blocklist-search-input');
if (input) input.value = '';
document.getElementById('blocklist-search-results').innerHTML = '';
_blLoadCurrent();
}
function _blRefreshTabs() {
document.querySelectorAll('.blocklist-tab').forEach(b =>
b.classList.toggle('active', b.dataset.bl === _blEntityType));
const input = document.getElementById('blocklist-search-input');
if (input) input.placeholder = `Search ${_blEntityType}s to block…`;
}
let _blSearchTimer = null;
function onBlocklistSearchInput() {
clearTimeout(_blSearchTimer);
_blSearchTimer = setTimeout(_blRunSearch, 300); // debounce
}
async function _blRunSearch() {
const input = document.getElementById('blocklist-search-input');
const box = document.getElementById('blocklist-search-results');
const spinner = document.getElementById('blocklist-search-spinner');
const q = (input.value || '').trim();
if (!q) { box.innerHTML = ''; return; }
const seq = ++_blSearchSeq;
spinner.classList.add('spinning');
try {
const res = await fetch(`/api/blocklist/search?type=${_blEntityType}&q=${encodeURIComponent(q)}`);
const data = await res.json();
if (seq !== _blSearchSeq) return; // a newer search superseded this
if (!data.success) throw new Error(data.error || 'Search failed');
const results = data.results || [];
if (!results.length) {
box.innerHTML = '