Do not offer a player for a file that is not audio or video
The media-type filter stopped new image enclosures being fetched, but ones already on disk still got a play button and an <audio> element, because the UI tested for a path rather than for a playable type. Four places did this, including play() itself, which picked the first downloaded enclosure whatever it was. isPlayable() checks audio/* or video/*, falling back to the extension when a feed declares no type. A downloaded non-media file now shows as its kind with Save and Delete, so it stays available without posing as an episode. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdXho5tTkjFLeUXKbEjKBh
This commit is contained in:
@@ -10,7 +10,8 @@ test.beforeEach(async ({ page }) => {
|
||||
test('the page loads and lists the configured feeds', async ({ page }) => {
|
||||
// Regression: a ReferenceError in the script left the shell rendered and the sidebar
|
||||
// empty, with every handler below the error dead. Server-side checks all passed.
|
||||
await expect(page.locator('.feed')).toHaveCount(2, { timeout: 15_000 });
|
||||
// Three top-level feeds in the fixture config; the OPML's child is inside a closed folder.
|
||||
await expect(page.locator('.feed')).toHaveCount(3, { timeout: 15_000 });
|
||||
await expect(page.getByText('Test Show')).toBeVisible();
|
||||
const errors = [];
|
||||
page.on('pageerror', e => errors.push(e.message));
|
||||
@@ -84,6 +85,24 @@ test('the three panes are there and the item text lands in the bottom one', asyn
|
||||
await expect(page.locator('#detail audio')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('a downloaded file that is not audio gets no player', async ({ page }) => {
|
||||
// Regression: anything with a file got an <audio> element and a play button, so a blog's
|
||||
// header image rendered as a broken player.
|
||||
await page.locator('.feed', { hasText: 'Picture Blog' }).click();
|
||||
const row = page.locator('.ep', { hasText: 'An Article' });
|
||||
await expect(row).toBeVisible({ timeout: 20_000 });
|
||||
|
||||
await expect(row.locator('[data-a="play"]')).toHaveCount(0);
|
||||
await row.click();
|
||||
|
||||
await expect(page.locator('#detail .dt')).toHaveText('An Article');
|
||||
await expect(page.locator('#detail audio')).toHaveCount(0);
|
||||
await expect(page.locator('#detail .encbox')).toContainText('image');
|
||||
await expect(page.locator('#detail .encbox')).toContainText('downloaded');
|
||||
// Still offered as a file, just not as an episode.
|
||||
await expect(page.locator('#detail .btn', { hasText: 'Save' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('the filter tabs change what is listed', async ({ page }) => {
|
||||
await page.getByText('Test Show').click();
|
||||
await expect(page.locator('.ep').first()).toBeVisible({ timeout: 20_000 });
|
||||
|
||||
BIN
tests/ui/fixtures/art.jpg
Normal file
BIN
tests/ui/fixtures/art.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
8
tests/ui/fixtures/pics.xml
Normal file
8
tests/ui/fixtures/pics.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<rss version="2.0"><channel><title>Picture Blog</title><link>http://127.0.0.1:8792/</link>
|
||||
<description>A text blog whose entries carry a header image, as Substack does.</description>
|
||||
<item><title>An Article</title><guid>pic-1</guid>
|
||||
<pubDate>Mon, 01 Sep 2026 10:00:00 +0000</pubDate>
|
||||
<description><p>Words, not audio.</p></description>
|
||||
<enclosure url="http://127.0.0.1:8792/art.jpg" length="3020" type="image/jpeg"/></item>
|
||||
</channel></rss>
|
||||
@@ -34,6 +34,12 @@ token = "${TOKEN}"
|
||||
url = "http://127.0.0.1:8792/show.xml"
|
||||
auto_download = true
|
||||
|
||||
# Downloads its image, so the UI has a file that is not playable to deal with.
|
||||
[feeds.picture-blog]
|
||||
url = "http://127.0.0.1:8792/pics.xml"
|
||||
auto_download = true
|
||||
media_types = ["image"]
|
||||
|
||||
[feeds.test-subscriptions]
|
||||
url = "http://127.0.0.1:8792/subs.opml"
|
||||
auto_download = false
|
||||
|
||||
Reference in New Issue
Block a user