Radio: artist and song in the player, lyrics for the song that is on (LRCLIB), synced for The Journey FM
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UaC9HmtHMdRP8dAbN4wAKj
This commit is contained in:
11 files changed
+129
-43
No files matched your search
@@ -0,0 +1,34 @@
|
||||
// Lyrics without any extra service: LRCLIB (free, no key) is asked for the exact song, then for the closest title; synced lines when it has them, plain words otherwise.
|
||||
const http = require('http'), assert = require('assert'), fs = require('fs'), os = require('os'), path = require('path');
|
||||
const seen = [];
|
||||
const fake = http.createServer((req, res) => {
|
||||
const u = new URL(req.url, 'http://x'), J = (o, c = 200) => { res.writeHead(c, { 'content-type': 'application/json' }); res.end(JSON.stringify(o)); }; seen.push(u.pathname + '?' + u.searchParams.get('track_name'));
|
||||
const t = u.searchParams.get('track_name'), a = u.searchParams.get('artist_name');
|
||||
if (u.pathname === '/api/get') {
|
||||
if (t === 'Synced') return J({ trackName: 'Synced', artistName: a, albumName: 'Alb', duration: 200, syncedLyrics: '[00:10.00]First line\n[00:20.50]Second line', plainLyrics: 'First line\nSecond line' });
|
||||
if (t === 'Plain') return J({ trackName: 'Plain', artistName: a, plainLyrics: 'Just words\n\nMore words' });
|
||||
if (t === 'Quiet') return J({ trackName: 'Quiet', artistName: a, instrumental: true });
|
||||
if (t === 'Long') return J({ trackName: 'Long', artistName: a, duration: 500, plainLyrics: 'words' });
|
||||
return J({ statusCode: 404, message: 'not found' }, 404);
|
||||
}
|
||||
if (u.pathname === '/api/search') return J(t === 'Fuzzy' ? [{ trackName: 'Other', artistName: 'Someone' }, { trackName: 'Fuzzy', artistName: 'The Band', plainLyrics: 'found by search' }] : []);
|
||||
res.writeHead(404); res.end();
|
||||
}).listen(0, async () => {
|
||||
process.env.LRCLIB_URL = 'http://127.0.0.1:' + fake.address().port; delete process.env.LYRICS_LRCLIB;
|
||||
const lyrics = require('../lyrics'); lyrics.init({ dataDir: fs.mkdtempSync(path.join(os.tmpdir(), 'nehub-lrclib-')), apiUrl: '' });
|
||||
const srv = http.createServer((q, r) => lyrics.handle(q, r)).listen(0, async () => {
|
||||
const ask = async (a, t, d = '') => (await fetch(`http://127.0.0.1:${srv.address().port}/api/lyrics?artist=${encodeURIComponent(a)}&title=${encodeURIComponent(t)}${d ? '&duration=' + d : ''}`)).json();
|
||||
try {
|
||||
assert.ok(lyrics.enabled(), 'lyrics work with no Lyrica service');
|
||||
let r = await ask('Band', 'Synced'); assert.equal(r.found, true); assert.equal(r.source, 'LRCLIB'); assert.equal(r.sync, 'line'); assert.deepEqual(r.lines.map(l => [l.t, l.text]), [[10000, 'First line'], [20500, 'Second line']]);
|
||||
r = await ask('Band', 'Plain'); assert.equal(r.sync, 'none'); assert.equal(r.lines.filter(l => l.text).length, 2, 'plain words are kept, blank lines too');
|
||||
assert.equal((await ask('Band', 'Quiet')).instrumental, true);
|
||||
r = await ask('The Band', 'Fuzzy'); assert.equal(r.found, true, 'when the exact song is not there, the search finds the closest title'); assert.equal(r.lines[0].text, 'found by search');
|
||||
assert.equal((await ask('Band', 'Nothing here')).found, false);
|
||||
assert.equal((await ask('Band', 'Long', '200')).found, false, 'a much longer or shorter version is not the same recording'); assert.equal((await ask('Band', 'Long')).found, true, 'a live radio song has no length to compare');
|
||||
const n = seen.length; await ask('Band', 'Synced'); assert.equal(seen.length, n, 'a song is looked up once, then remembered');
|
||||
console.log('lrclib test ok');
|
||||
} catch (e) { console.error(e); process.exitCode = 1; }
|
||||
srv.close(); fake.close();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user