diff --git a/__tests__/lib/string.test.ts b/__tests__/lib/string.test.ts index 6dba812cb4..8bb82cc194 100644 --- a/__tests__/lib/string.test.ts +++ b/__tests__/lib/string.test.ts @@ -421,6 +421,39 @@ describe('parseEmbedPlayerFromUrl', () => { 'https://vimeo.com/videoId', 'https://vimeo.com/videoId?autoplay=0', + + 'https://giphy.com/gifs/some-random-gif-name-gifId', + 'https://giphy.com/gif/some-random-gif-name-gifId', + 'https://giphy.com/gifs/', + + 'https://media.giphy.com/media/gifId/giphy.gif', + 'https://media0.giphy.com/media/gifId/giphy.gif', + 'https://media1.giphy.com/media/gifId/giphy.gif', + 'https://media2.giphy.com/media/gifId/giphy.gif', + 'https://media3.giphy.com/media/gifId/giphy.gif', + 'https://media4.giphy.com/media/gifId/giphy.gif', + 'https://media5.giphy.com/media/gifId/giphy.gif', + 'https://media1.google.com/media/gifId/giphy.gif', + + 'https://media.giphy.com/media/trackingId/gifId/giphy.gif', + + 'https://i.giphy.com/media/gifId/giphy.gif', + 'https://i.giphy.com/media/gifId/giphy.gif', + 'https://i.giphy.com/gifId.gif', + 'https://i.giphy.com/gifId.gif', + + 'https://media1.tenor.com/m/gifId/someName.gif', + 'https://media.tenor.com/m/gifId/someName.mp4', + 'https://media1.tenor.com/m/gifId', + + 'https://tenor.com/view/gifId', + 'https://tenor.com/notView/gifId', + 'https://tenor.com/view', + 'https://tenor.com/view/gifId.gif', + + 'https://c.tenor.com/gifId/tenor.gif', + 'https://c.tenor.com/gifId/tenor.webp', + 'https://c.tenor.com/gifId/tenor.mp4', ] const outputs = [ @@ -544,6 +577,90 @@ describe('parseEmbedPlayerFromUrl', () => { videoId: 'videoId', playerUri: 'https://player.vimeo.com/video/videoId?autoplay=1', }, + + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + undefined, + undefined, + + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + undefined, + undefined, + + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + { + type: 'giphy_gif', + imageUri: 'https://i.giphy.com/media/gifId/giphy.gif', + }, + + { + type: 'tenor_gif', + imageUri: 'https://media1.tenor.com/m/gifId/someName.gif', + }, + undefined, + undefined, + + { + type: 'tenor_gif', + imageUri: 'https://tenor.com/view/gifId.gif', + }, + undefined, + undefined, + { + type: 'tenor_gif', + imageUri: 'https://tenor.com/view/gifId.gif', + }, + + { + type: 'tenor_gif', + imageUri: 'https://c.tenor.com/gifId/tenor.gif', + }, + { + type: 'tenor_gif', + imageUri: 'https://c.tenor.com/gifId/tenor.webp', + }, + 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 32a7807354..dcc7585d92 100644 --- a/src/lib/strings/embed-player.ts +++ b/src/lib/strings/embed-player.ts @@ -16,6 +16,8 @@ export type EmbedPlayerParams = | {type: 'apple_music_album'; albumId: string; playerUri: string} | {type: 'apple_music_song'; songId: string; playerUri: string} | {type: 'vimeo_video'; videoId: string; playerUri: string} + | {type: 'giphy_gif'; imageUri: string} + | {type: 'tenor_gif'; imageUri: string} export function parseEmbedPlayerFromUrl( url: string, @@ -170,6 +172,111 @@ export function parseEmbedPlayerFromUrl( } } } + + if (urlp.hostname === 'giphy.com' || urlp.hostname === 'www.giphy.com') { + const [_, gifs, nameAndId] = urlp.pathname.split('/') + + /* + * nameAndId is a string that consists of the name (dash separated) and the id of the gif (the last part of the name) + * We want to get the id of the gif, then direct to media.giphy.com/media/{id}/giphy.gif so we can + * use it in an component + */ + + if (gifs === 'gifs' && nameAndId) { + const id = nameAndId.split('-').pop() + + if (id) { + return { + type: 'giphy_gif', + imageUri: `https://i.giphy.com/media/${id}/giphy.gif`, + } + } + } + } + + // There are five possible hostnames that also can be giphy urls: media.giphy.com and media0-4.giphy.com + // These can include (presumably) a tracking id in the path name, so we have to check for that as well + if (/media(?:[0-4]\.giphy\.com|\.giphy\.com)/gm.test(urlp.hostname)) { + // We can link directly to the gif, if its a proper link + const [_, media, trackingOrId, idOrFilename, filename] = + urlp.pathname.split('/') + + if (media === 'media') { + if (idOrFilename === 'giphy.gif' || idOrFilename === 'giphy.gif') { + return { + type: 'giphy_gif', + imageUri: `https://i.giphy.com/media/${trackingOrId}/giphy.gif`, + } + } else if (filename === 'giphy.gif' || filename === 'giphy.gif') { + return { + type: 'giphy_gif', + imageUri: `https://i.giphy.com/media/${idOrFilename}/giphy.gif`, + } + } + } + } + + // Finally, we should see if it is a link to i.giphy.com. These links don't necessarily end in .gif but can also + // be .webp + if (urlp.hostname === 'i.giphy.com' || urlp.hostname === 'www.i.giphy.com') { + const [_, mediaOrFilename, filename] = urlp.pathname.split('/') + + if (mediaOrFilename === 'media' && filename) { + return { + type: 'giphy_gif', + imageUri: `https://i.giphy.com/media/${ + filename.split('.')[0] + }/giphy.gif`, + } + } else if (mediaOrFilename) { + return { + type: 'giphy_gif', + imageUri: `https://i.giphy.com/media/${ + mediaOrFilename.split('.')[0] + }/giphy.gif`, + } + } + } + + if (urlp.hostname === 'media1.tenor.com') { + const parts = urlp.pathname.split('/') + const filename = parts[3] + + if (parts.length === 4 && filename?.split('.').pop() === 'gif') { + return { + type: 'tenor_gif', + imageUri: url, + } + } + } + + if (urlp.hostname === 'tenor.com' || urlp.hostname === 'www.tenor.com') { + const [_, path, filename] = urlp.pathname.split('/') + + if (path === 'view' && filename) { + const includesExt = filename.split('.').pop() === 'gif' + + return { + type: 'tenor_gif', + imageUri: `${url}${!includesExt ? '.gif' : ''}`, + } + } + } + + if (urlp.host === 'c.tenor.com') { + const [_, id, filename] = urlp.pathname.split('/') + + if (id && filename) { + const ext = filename.split('.').pop() + + if (ext === 'gif' || ext === 'webp') { + return { + type: 'tenor_gif', + imageUri: url, + } + } + } + } } export function getPlayerHeight({ diff --git a/src/view/com/util/post-embeds/ExternalPlayerEmbed.tsx b/src/view/com/util/post-embeds/ExternalPlayerEmbed.tsx index 580cf363ac..d0fc629681 100644 --- a/src/view/com/util/post-embeds/ExternalPlayerEmbed.tsx +++ b/src/view/com/util/post-embeds/ExternalPlayerEmbed.tsx @@ -201,7 +201,9 @@ export function ExternalPlayer({ }, styles.topRadius, ]} - source={{uri: link.thumb}} + source={{ + uri: 'https://media1.tenor.com/m/UNTqMDwqh1gAAAAC/hello-hi.gif', + }} accessibilityIgnoresInvertColors /> )}