ux: return clear BitMidi outage message and handoff notes

This commit is contained in:
b1rdmania
2026-02-02 23:39:29 +00:00
parent 5e81227907
commit 686c961fb3
6 changed files with 90 additions and 13 deletions
+2 -2
View File
@@ -22,7 +22,7 @@ export class BitMidiAdapter implements SearchAdapter {
return this.parseSearchResults(html, query);
} catch (error) {
console.error('BitMidi search error:', error);
return [];
throw error instanceof Error ? error : new Error('BitMidi search failed');
}
}
@@ -179,4 +179,4 @@ export class BitMidiAdapter implements SearchAdapter {
// but keeping for backward compatibility
return pageUrl;
}
}
}
+10 -3
View File
@@ -147,6 +147,9 @@ app.get('/api/midi/search', async (req, res) => {
res.json({ results, count: results.length });
} catch (error) {
console.error('Search error:', error);
if (error instanceof Error && error.message === 'MIDI_SOURCE_UNAVAILABLE') {
return res.status(503).json({ error: 'BitMidi is temporarily unavailable. Please try again in a minute.' });
}
res.status(500).json({ error: 'Search failed' });
}
});
@@ -284,7 +287,9 @@ app.get('/api/midi/fetch', async (req, res) => {
res.setHeader('Content-Length', result.data!.byteLength);
res.send(Buffer.from(result.data!));
} else {
res.status(404).json({ error: result.error });
const error = String(result.error || 'Fetch failed');
const blocked = /blocked|not allowed/i.test(error);
res.status(blocked ? 403 : 404).json({ error });
}
} catch (error) {
console.error('Fetch error:', error);
@@ -307,7 +312,9 @@ app.get('/api/midi/parse', async (req, res) => {
const metadata = parseService.parseMIDI(result.data);
res.json(metadata);
} else {
res.status(404).json({ error: result.error || 'Failed to fetch MIDI' });
const error = String(result.error || 'Failed to fetch MIDI');
const blocked = /blocked|not allowed/i.test(error);
res.status(blocked ? 403 : 404).json({ error });
}
} catch (error) {
console.error('Parse error:', error);
@@ -328,4 +335,4 @@ if (!process.env.VERCEL) {
app.listen(port, () => {
console.log(`🎵 Motif backend running on port ${port}`);
});
}
}
+10 -4
View File
@@ -19,22 +19,28 @@ export class MIDISearchService {
try {
const results = await adapter.search(query);
console.log(`${adapter.name}: Found ${results.length} results`);
return results;
return { ok: true, results } as const;
} catch (error) {
console.error(`${adapter.name} search failed:`, error);
return [];
return { ok: false, results: [] as MIDICandidate[] } as const;
}
});
const results = await Promise.all(searchPromises);
const allFailed = results.length > 0 && results.every(r => !r.ok);
// Combine and deduplicate results
for (const adapterResults of results) {
allResults.push(...adapterResults);
allResults.push(...adapterResults.results);
}
// Remove duplicates (same MIDI URL)
const uniqueResults = this.deduplicateResults(allResults);
// Distinguish provider outage from "no matches found"
if (uniqueResults.length === 0 && allFailed) {
throw new Error('MIDI_SOURCE_UNAVAILABLE');
}
// Sort by confidence score
uniqueResults.sort((a, b) => b.confidence - a.confidence);
@@ -59,4 +65,4 @@ export class MIDISearchService {
return unique;
}
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
export interface MIDICandidate {
id: string;
title: string;
source: 'bitmidi' | 'dongrays' | 'mock';
source: 'bitmidi' | 'dongrays' | 'freemidi' | 'mock';
pageUrl: string;
midiUrl: string;
confidence: number;
@@ -38,4 +38,4 @@ export interface CacheEntry {
filename: string;
size: number;
timestamp: number;
}
}