Store: Smashwords as a family-filtered book source; free audiobooks stream through the hub; extensions and Sites on Home
build-container / build (push) Failing after 1m30s
build-container / build (push) Failing after 1m30s
- Smashwords: free EPUBs from its shelf feed, filtered (adult/erotica flags, LGBTQ+, keywords, unlabelled romance); admin saves a Smashwords sign-in (encrypted) used to download - LibriVox chapter audio is fetched and streamed by the hub (with seeking) instead of redirecting the browser to archive.org - Home: a My apps section with installed extensions and Sites, also in the command palette Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3c42d1ecd5
commit
dc8265a850
11 files changed
+223
-15
No files matched your search
@@ -12,6 +12,8 @@ const fake = http.createServer((req, res) => {
|
||||
if (u.searchParams.get('title') === 'prejudice' || u.searchParams.get('author') === 'austen') return J({ books: [book] });
|
||||
return J({ error: 'Audiobooks could not be found' }, 404);
|
||||
}
|
||||
if (p === '/dl/1.mp3') { const rg = /^bytes=(\d+)-(\d+)$/.exec(req.headers.range || ''), data = Buffer.from('0123456789'); if (rg) { res.writeHead(206, { 'content-type': 'audio/mpeg', 'content-range': `bytes ${rg[1]}-${rg[2]}/10`, 'content-length': +rg[2] - +rg[1] + 1 }); return res.end(data.subarray(+rg[1], +rg[2] + 1)); } res.writeHead(200, { 'content-type': 'audio/mpeg', 'content-length': 10 }); return res.end(data); }
|
||||
if (p === '/dl/moved.mp3') { res.writeHead(302, { location: '/dl/1.mp3' }); return res.end(); }
|
||||
if (p === '/cover.gif') { res.writeHead(200, { 'content-type': 'image/gif' }); return res.end(gif); }
|
||||
res.writeHead(404); res.end();
|
||||
}).listen(0, () => {
|
||||
@@ -25,7 +27,8 @@ const fake = http.createServer((req, res) => {
|
||||
assert.deepEqual((await j(await call('/search?q=zzz'))).items, [], 'nothing found is an empty list, not an error');
|
||||
assert.ok((await j(await call('/search'))).items.length >= 0, 'no search words lists the catalogue');
|
||||
r = await call('/book/55'); const b = await j(r); assert.equal(b.chapters.length, 2, 'chapters on other sites are dropped'); assert.ok(!JSON.stringify(b).includes('127.0.0.1:' + port + '/dl'), 'audio addresses are not sent to the browser'); assert.equal(b.chapters[1].title, 'Chapter 3'); assert.equal(b.description, 'A novel');
|
||||
r = await call('/audio/55/0'); assert.equal(r.status, 302); assert.equal(r.headers.get('location'), `http://127.0.0.1:${port}/dl/1.mp3`);
|
||||
r = await call('/audio/55/0'); assert.equal(r.status, 200); assert.equal(r.headers.get('content-type'), 'audio/mpeg'); assert.equal(await r.text(), '0123456789', 'the hub passes the recording on itself');
|
||||
r = await call('/audio/55/0', { headers: { range: 'bytes=2-4' } }); assert.equal(r.status, 206); assert.equal(await r.text(), '234'); assert.equal(r.headers.get('content-range'), 'bytes 2-4/10', 'seeking works');
|
||||
assert.equal((await call('/audio/55/9')).status, 404); assert.equal((await call('/book/abc')).status, 404);
|
||||
r = await call('/cover/55'); assert.equal(r.headers.get('content-type'), 'image/gif');
|
||||
assert.equal((await call('/cover/55?u=' + encodeURIComponent('http://169.254.169.254/x'))).status, 200, 'an address off the allowed sites is ignored (the book\'s own cover is used)');
|
||||
|
||||
Reference in new issue
Block a user