diff --git a/tests/page-unit.ts b/tests/page-unit.ts index b557d41..8418098 100644 --- a/tests/page-unit.ts +++ b/tests/page-unit.ts @@ -331,3 +331,15 @@ test('a shared link starts where you are, from five seconds in (#447)', () => { assert.equal(run(`shareAt(${JSON.stringify(url)}, 754.6)`), `${url}?t=754`); assert.equal(run(`shareAt(${JSON.stringify(url)}, 3)`), url); }); + +test('Share says why an episode gets no page anyone can play, and warns of a key in its address (#454)', () => { + const note = (why: string | null, url: string) => run(`noLinkNote(${JSON.stringify(why)}, ${JSON.stringify(url)})`) as string; + const paid = 'https://c10.patreonusercdn.com/ep.mp3?token-hash=abc'; + assert.match(note('private', paid), /private to you.*includes your own access/s); + assert.match(note('failed', 'https://example.com/ep.mp3'), /could not be made just now/); + assert.doesNotMatch(note('failed', 'https://example.com/ep.mp3'), /own access/); + // A server with no ipx-play shares as it always has, with no reason to give. + assert.equal(note('not_set_up', 'https://example.com/ep.mp3'), ''); + // The request failed outright: no reason known, but the key is still warned of. + assert.match(note(null, paid), /own access/); +}); diff --git a/tests/ui/app.spec.ts b/tests/ui/app.spec.ts index 70fe001..a09e68f 100644 --- a/tests/ui/app.spec.ts +++ b/tests/ui/app.spec.ts @@ -2266,6 +2266,7 @@ test('Share hands the feed, and an episode as a link to its page on ipx-play (#4 const e = (await api('/api/feeds/paid-show/entries') as ListPage).entries[0]; await shareEpisode({ ...e, link: 'https://www.patreon.com/posts/1?auth=secret123' }, null); }); + await expect(page.locator('#modalCard')).toContainText('private to you'); await expect(page.locator('#modalCard')).toContainText('includes your own access'); await expect(page.locator('#shat')).toHaveCount(0); await page.locator('#shlink').click(); diff --git a/web/CHANGELOG.md b/web/CHANGELOG.md index 16b6311..6a68ec2 100644 --- a/web/CHANGELOG.md +++ b/web/CHANGELOG.md @@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Share on an episode offers Share link, Share from where you are, and Copy link, with a link to the episode's page on ipx-play that anyone can play; an episode of a private feed offers its own address in the same menu, saying so when the address carries your own access to the feed. An admin sets ipx-play up in Admin, Directory (#447, #452). +- Share on an episode offers Share link, Share from where you are, and Copy link, with a link to the episode's page on ipx-play that anyone can play; an episode of a private feed offers its own address in the same menu, which says why there is no page for it and warns when the address carries your own access to the feed. An admin sets ipx-play up in Admin, Directory (#447, #452, #454). - In the iOS app, Settings has a This device section for the app's server and player token, with a button that makes a token and hands it to the app (#445). - In the iOS app, the page registers the phone with ipx for its icon's count, and signing out removes it (#433). - In the iOS app, the player bar shows what CarPlay plays, so it can be paused on the phone after leaving the car, including when the app was opened by the car (#420, #442). diff --git a/web/src/items.ts b/web/src/items.ts index 3ea7abd..3a24c06 100644 --- a/web/src/items.ts +++ b/web/src/items.ts @@ -522,6 +522,17 @@ function encBox(x: Enclosure){ /// seconds in is the start. const shareAt=(url: string, secs: number)=>secs>=5 ? `${url}?t=${Math.floor(secs)}` : url; +/// Why Share offers the item's own address rather than a page anyone can play (#454), and the +/// warning when that address carries your own access to the feed. No reason for a server with no +/// ipx-play, where the item's own address is all Share has ever given. +function noLinkNote(why: string|null, url: string): string{ + const notes: string[]=[]; + if(why==='private') notes.push('This podcast\'s feed is private to you, so it gets no page anyone can play: Share gives the episode\'s own address instead.'); + else if(why==='failed') notes.push('The page anyone can play could not be made just now, so this is the episode\'s own address. Try again later for a link to it.'); + if(carriesAccess(url)) notes.push(ACCESS_WARNING); + return notes.map(n=>`
${esc(n)}
`).join(''); +} + /// An episode shared as Overcast shares one (#447): a link to its page on ipx-play, where anyone /// can play it, from where you are in it if you like. A private feed, a post, or a server with no /// ipx-play shares the item's own address, through the same menu. @@ -543,7 +554,7 @@ async function shareEpisode(e: Entry, encId: number|null){ // warning is written here, not asked with confirm(), which the iOS app answers Cancel (#453). openModal(`${esc(name)}
- ${!link.url && carriesAccess(url) ? `${esc(ACCESS_WARNING)}
` : ''} + ${link.url ? '' : noLinkNote(link.why, url)}