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 <me@haileyok.com>
zio/stable
Thomas Dickerson 2024-06-03 20:29:45 -04:00 committed by GitHub
parent 891b432ead
commit bd4703ca1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 157 additions and 0 deletions

View File

@ -480,6 +480,26 @@ describe('parseEmbedPlayerFromUrl', () => {
'https://media.tenor.com/someID/someName.gif', 'https://media.tenor.com/someID/someName.gif',
'https://media.tenor.com/someID', 'https://media.tenor.com/someID',
'https://media.tenor.com', '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 = [ const outputs = [
@ -777,6 +797,66 @@ describe('parseEmbedPlayerFromUrl', () => {
undefined, undefined,
undefined, 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', () => { it('correctly grabs the correct id from uri', () => {

View File

@ -23,6 +23,7 @@ export const embedPlayerSources = [
'vimeo', 'vimeo',
'giphy', 'giphy',
'tenor', 'tenor',
'flickr',
] as const ] as const
export type EmbedPlayerSource = (typeof embedPlayerSources)[number] export type EmbedPlayerSource = (typeof embedPlayerSources)[number]
@ -42,6 +43,7 @@ export type EmbedPlayerType =
| 'vimeo_video' | 'vimeo_video'
| 'giphy_gif' | 'giphy_gif'
| 'tenor_gif' | 'tenor_gif'
| 'flickr_album'
export const externalEmbedLabels: Record<EmbedPlayerSource, string> = { export const externalEmbedLabels: Record<EmbedPlayerSource, string> = {
youtube: 'YouTube', youtube: 'YouTube',
@ -53,6 +55,7 @@ export const externalEmbedLabels: Record<EmbedPlayerSource, string> = {
spotify: 'Spotify', spotify: 'Spotify',
appleMusic: 'Apple Music', appleMusic: 'Apple Music',
soundcloud: 'SoundCloud', soundcloud: 'SoundCloud',
flickr: 'Flickr',
} }
export interface EmbedPlayerParams { 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({ export function getPlayerAspect({

View File

@ -65,6 +65,7 @@ export const schema = z.object({
spotify: z.enum(externalEmbedOptions).optional(), spotify: z.enum(externalEmbedOptions).optional(),
appleMusic: z.enum(externalEmbedOptions).optional(), appleMusic: z.enum(externalEmbedOptions).optional(),
soundcloud: z.enum(externalEmbedOptions).optional(), soundcloud: z.enum(externalEmbedOptions).optional(),
flickr: z.enum(externalEmbedOptions).optional(),
}) })
.optional(), .optional(),
mutedThreads: z.array(z.string()), // should move to server mutedThreads: z.array(z.string()), // should move to server