From bd4703ca1e5e4620f8c700e70477d2e0e6b04d67 Mon Sep 17 00:00:00 2001 From: Thomas Dickerson Date: Mon, 3 Jun 2024 20:29:45 -0400 Subject: [PATCH] Support for Flickr album and group pool embeds (#3936) * Support for Flickr album and group pool embeds * Oops, forgot to add flickr to the persisted externalEmbeds schema * Need a bigint since our id can have more than 52 bits... * Remove unexpected trailing / from test data to match the expected behavior * nits --------- Co-authored-by: Hailey --- __tests__/lib/string.test.ts | 80 +++++++++++++++++++++++++++++++++ src/lib/strings/embed-player.ts | 76 +++++++++++++++++++++++++++++++ src/state/persisted/schema.ts | 1 + 3 files changed, 157 insertions(+) diff --git a/__tests__/lib/string.test.ts b/__tests__/lib/string.test.ts index cf21d8dd..78478a26 100644 --- a/__tests__/lib/string.test.ts +++ b/__tests__/lib/string.test.ts @@ -480,6 +480,26 @@ describe('parseEmbedPlayerFromUrl', () => { 'https://media.tenor.com/someID/someName.gif', 'https://media.tenor.com/someID', 'https://media.tenor.com', + + 'https://www.flickr.com/photos/username/albums/72177720308493661', + 'https://flickr.com/photos/username/albums/72177720308493661', + 'https://flickr.com/photos/username/albums/72177720308493661/', + 'https://flickr.com/photos/username/albums/72177720308493661//', + 'https://flic.kr/s/aHBqjAES3i', + + 'https://flickr.com/foetoes/username/albums/3903', + 'https://flickr.com/albums/3903', + 'https://flic.kr/s/OolI', + 'https://flic.kr/t/aHBqjAES3i', + + 'https://www.flickr.com/groups/898944@N23/pool', + 'https://flickr.com/groups/898944@N23/pool', + 'https://flickr.com/groups/898944@N23/pool/', + 'https://flickr.com/groups/898944@N23/pool//', + 'https://flic.kr/go/8WJtR', + + 'https://www.flickr.com/groups/898944@N23/', + 'https://www.flickr.com/groups', ] const outputs = [ @@ -777,6 +797,66 @@ describe('parseEmbedPlayerFromUrl', () => { undefined, undefined, undefined, + + { + type: 'flickr_album', + source: 'flickr', + playerUri: 'https://embedr.flickr.com/photosets/72177720308493661', + }, + { + type: 'flickr_album', + source: 'flickr', + playerUri: 'https://embedr.flickr.com/photosets/72177720308493661', + }, + { + type: 'flickr_album', + source: 'flickr', + playerUri: 'https://embedr.flickr.com/photosets/72177720308493661', + }, + { + type: 'flickr_album', + source: 'flickr', + playerUri: 'https://embedr.flickr.com/photosets/72177720308493661', + }, + { + type: 'flickr_album', + source: 'flickr', + playerUri: 'https://embedr.flickr.com/photosets/72177720308493661', + }, + + undefined, + undefined, + undefined, + undefined, + + { + type: 'flickr_album', + source: 'flickr', + playerUri: 'https://embedr.flickr.com/groups/898944@N23', + }, + { + type: 'flickr_album', + source: 'flickr', + playerUri: 'https://embedr.flickr.com/groups/898944@N23', + }, + { + type: 'flickr_album', + source: 'flickr', + playerUri: 'https://embedr.flickr.com/groups/898944@N23', + }, + { + type: 'flickr_album', + source: 'flickr', + playerUri: 'https://embedr.flickr.com/groups/898944@N23', + }, + { + type: 'flickr_album', + source: 'flickr', + playerUri: 'https://embedr.flickr.com/groups/898944@N23', + }, + + undefined, + undefined, ] it('correctly grabs the correct id from uri', () => { diff --git a/src/lib/strings/embed-player.ts b/src/lib/strings/embed-player.ts index 54649f14..30ced149 100644 --- a/src/lib/strings/embed-player.ts +++ b/src/lib/strings/embed-player.ts @@ -23,6 +23,7 @@ export const embedPlayerSources = [ 'vimeo', 'giphy', 'tenor', + 'flickr', ] as const export type EmbedPlayerSource = (typeof embedPlayerSources)[number] @@ -42,6 +43,7 @@ export type EmbedPlayerType = | 'vimeo_video' | 'giphy_gif' | 'tenor_gif' + | 'flickr_album' export const externalEmbedLabels: Record = { youtube: 'YouTube', @@ -53,6 +55,7 @@ export const externalEmbedLabels: Record = { spotify: 'Spotify', appleMusic: 'Apple Music', soundcloud: 'SoundCloud', + flickr: 'Flickr', } export interface EmbedPlayerParams { @@ -375,6 +378,79 @@ export function parseEmbedPlayerFromUrl( } } } + + // this is a standard flickr path! we can use the embedder for albums and groups, so validate the path + if (urlp.hostname === 'www.flickr.com' || urlp.hostname === 'flickr.com') { + let i = urlp.pathname.length - 1 + while (i > 0 && urlp.pathname.charAt(i) === '/') { + --i + } + + const path_components = urlp.pathname.slice(1, i + 1).split('/') + if (path_components.length === 4) { + // discard username - it's not relevant + const [photos, _, albums, id] = path_components + if (photos === 'photos' && albums === 'albums') { + // this at least has the shape of a valid photo-album URL! + return { + type: 'flickr_album', + source: 'flickr', + playerUri: `https://embedr.flickr.com/photosets/${id}`, + } + } + } + + if (path_components.length === 3) { + const [groups, id, pool] = path_components + if (groups === 'groups' && pool === 'pool') { + return { + type: 'flickr_album', + source: 'flickr', + playerUri: `https://embedr.flickr.com/groups/${id}`, + } + } + } + // not an album or a group pool, don't know what to do with this! + return undefined + } + + // link shortened flickr path + if (urlp.hostname === 'flic.kr') { + const b58alph = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ' + let [_, type, idBase58Enc] = urlp.pathname.split('/') + let id = 0n + for (const char of idBase58Enc) { + const nextIdx = b58alph.indexOf(char) + if (nextIdx >= 0) { + id = id * 58n + BigInt(nextIdx) + } else { + // not b58 encoded, ergo not a valid link to embed + return undefined + } + } + + switch (type) { + case 'go': + const formattedGroupId = `${id}` + return { + type: 'flickr_album', + source: 'flickr', + playerUri: `https://embedr.flickr.com/groups/${formattedGroupId.slice( + 0, + -2, + )}@N${formattedGroupId.slice(-2)}`, + } + case 's': + return { + type: 'flickr_album', + source: 'flickr', + playerUri: `https://embedr.flickr.com/photosets/${id}`, + } + default: + // we don't know what this is so we can't embed it + return undefined + } + } } export function getPlayerAspect({ diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts index 77a79b78..1860d34d 100644 --- a/src/state/persisted/schema.ts +++ b/src/state/persisted/schema.ts @@ -65,6 +65,7 @@ export const schema = z.object({ spotify: z.enum(externalEmbedOptions).optional(), appleMusic: z.enum(externalEmbedOptions).optional(), soundcloud: z.enum(externalEmbedOptions).optional(), + flickr: z.enum(externalEmbedOptions).optional(), }) .optional(), mutedThreads: z.array(z.string()), // should move to server