Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move to Tenor for GIFs #3654

Merged
merged 11 commits into from
Apr 22, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,7 @@ public class ExpoBlueskyGifViewModule: Module {
Name("ExpoBlueskyGifView")

OnCreate {
// See expo-image. SDImageAWebPCoder is preferred (and uses Apple's own WebP coder)
// but only is available on 14.0+. We probably don't have many users on iOS 13 but
// for now let's keep it there until RN targets change.
if #available(iOS 14.0, tvOS 14.0, *) {
SDImageCodersManager.shared.addCoder(SDImageAWebPCoder.shared)
} else {
SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
}
SDImageCodersManager.shared.addCoder(SDImageGIFCoder.shared)
}

AsyncFunction("prefetchAsync") { (sources: [URL]) in
Expand Down
46 changes: 23 additions & 23 deletions src/lib/strings/embed-player.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Dimensions} from 'react-native'
import {Dimensions, Platform} from 'react-native'

import {isWeb} from 'platform/detection'
const {height: SCREEN_HEIGHT} = Dimensions.get('window')
Expand Down Expand Up @@ -255,16 +255,6 @@ export function parseEmbedPlayerFromUrl(
if (urlp.hostname === 'giphy.com' || urlp.hostname === 'www.giphy.com') {
const [_, gifs, nameAndId] = urlp.pathname.split('/')

const h = urlp.searchParams.get('hh')
const w = urlp.searchParams.get('ww')
let dimensions
if (h && w) {
dimensions = {
height: Number(h),
width: Number(w),
}
}

/*
* 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.webp so we can
Expand All @@ -281,10 +271,7 @@ export function parseEmbedPlayerFromUrl(
isGif: true,
hideDetails: true,
metaUri: `https://giphy.com/gifs/${gifId}`,
playerUri: `https://i.giphy.com/media/${gifId}/${
dimensions && isWeb ? 'giphy.mp4' : '200.webp'
}`,
dimensions,
playerUri: `https://i.giphy.com/media/${gifId}/giphy.webp`,
}
}
}
Expand Down Expand Up @@ -350,21 +337,34 @@ export function parseEmbedPlayerFromUrl(
}
}

if (urlp.hostname === 'tenor.com' || urlp.hostname === 'www.tenor.com') {
const [_, pathOrIntl, pathOrFilename, intlFilename] =
urlp.pathname.split('/')
const isIntl = pathOrFilename === 'view'
const filename = isIntl ? intlFilename : pathOrFilename
if (urlp.hostname === 'media.tenor.com') {
let [_, id, filename] = urlp.pathname.split('/')

if ((pathOrIntl === 'view' || pathOrFilename === 'view') && filename) {
const includesExt = filename.split('.').pop() === 'gif'
const h = urlp.searchParams.get('hh')
const w = urlp.searchParams.get('ww')
let dimensions
if (h && w) {
dimensions = {
height: Number(h),
width: Number(w),
}
}

if (id && filename && dimensions && id.includes('AAAAC')) {
if (Platform.OS === 'web') {
id = id.replace('AAAAC', 'AAAP3')
filename = filename.replace('.gif', '.webm')
} else {
id = id.replace('AAAAC', 'AAAAM')
}

return {
type: 'tenor_gif',
source: 'tenor',
isGif: true,
hideDetails: true,
playerUri: `${url}${!includesExt ? '.gif' : ''}`,
playerUri: `https://t.gifs.bsky.app/${id}/${filename}`,
dimensions,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/view/com/composer/Composer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ export const ComposePost = observer(function ComposePost({
const onSelectGif = useCallback(
(gif: Gif) => {
setExtLink({
uri: `${gif.media_formats.gif.url}?hh=${gif.media_formats.gif.dims[0]}&ww=${gif.media_formats.gif.dims[1]}`,
uri: `${gif.media_formats.gif.url}?hh=${gif.media_formats.gif.dims[1]}&ww=${gif.media_formats.gif.dims[0]}`,
isLoading: true,
meta: {
url: gif.media_formats.gif.url,
Expand Down
18 changes: 7 additions & 11 deletions src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ export const ExternalLinkEmbed = ({
return params
}
}, [link.uri, externalEmbedPrefs])
const isCompatibleGiphy =
embedPlayerParams?.source === 'giphy' && embedPlayerParams.dimensions

if (isCompatibleGiphy) {
if (embedPlayerParams?.source === 'tenor') {
return <GifEmbed params={embedPlayerParams} thumb={link.thumb} />
}

Expand Down Expand Up @@ -69,14 +67,12 @@ export const ExternalLinkEmbed = ({
paddingHorizontal: isMobile ? 10 : 14,
},
]}>
{!isCompatibleGiphy && (
<Text
type="sm"
numberOfLines={1}
style={[pal.textLight, {marginVertical: 2}]}>
{toNiceDomain(link.uri)}
</Text>
)}
<Text
type="sm"
numberOfLines={1}
style={[pal.textLight, {marginVertical: 2}]}>
{toNiceDomain(link.uri)}
</Text>

{!embedPlayerParams?.isGif && !embedPlayerParams?.dimensions && (
<Text type="lg-bold" numberOfLines={3} style={[pal.text]}>
Expand Down
65 changes: 18 additions & 47 deletions src/view/com/util/post-embeds/GifEmbed.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import React from 'react'
import {Pressable, View} from 'react-native'
import {Image} from 'expo-image'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'

import {EmbedPlayerParams} from 'lib/strings/embed-player'
import {useAutoplayDisabled, useExternalEmbedsPrefs} from 'state/preferences'
import {useAutoplayDisabled} from 'state/preferences'
import {atoms as a, useTheme} from '#/alf'
import {useDialogControl} from '#/components/Dialog'
import * as Dialog from '#/components/Dialog'
import {GiphyConsentPrompt} from '#/components/dialogs/GifSelect'
import {Loader} from '#/components/Loader'
import {GifView} from '../../../../../modules/expo-bluesky-gif-view'
import {GifViewStateChangeEvent} from '../../../../../modules/expo-bluesky-gif-view/src/GifView.types'
Expand All @@ -17,12 +13,10 @@ function PlaybackControls({
onPress,
isPlaying,
isLoaded,
needsPermissions,
}: {
onPress: () => void
isPlaying: boolean
isLoaded: boolean
needsPermissions: boolean
}) {
const t = useTheme()

Expand All @@ -41,16 +35,15 @@ function PlaybackControls({
top: 0,
bottom: 0,
zIndex: 2,
backgroundColor:
!needsPermissions && !isLoaded
? t.atoms.bg_contrast_25.backgroundColor
: !isPlaying
? 'rgba(0, 0, 0, 0.3)'
: undefined,
backgroundColor: !isLoaded
? t.atoms.bg_contrast_25.backgroundColor
: !isPlaying
? 'rgba(0, 0, 0, 0.3)'
: undefined,
},
]}
onPress={onPress}>
{!needsPermissions && !isLoaded ? (
{!isLoaded ? (
<View>
<View style={[a.align_center, a.justify_center]}>
<Loader size="xl" />
Expand Down Expand Up @@ -87,18 +80,15 @@ export function GifEmbed({
params: EmbedPlayerParams
thumb?: string
}) {
const consentControl = useDialogControl()
const autoplayDisabled = useAutoplayDisabled()
const externalEmbedsPrefs = useExternalEmbedsPrefs()
const needsPermissions = externalEmbedsPrefs?.giphy === undefined

const playerRef = React.useRef<GifView>(null)

const [playerState, setPlayerState] = React.useState<{
isPlaying: boolean
isLoaded: boolean
}>({
isPlaying: !autoplayDisabled && !needsPermissions,
isPlaying: !autoplayDisabled,
isLoaded: false,
})

Expand All @@ -110,12 +100,8 @@ export function GifEmbed({
)

const onPress = React.useCallback(() => {
if (needsPermissions) {
consentControl.open()
} else {
playerRef.current?.toggleAsync()
}
}, [consentControl, needsPermissions])
playerRef.current?.toggleAsync()
}, [])

return (
<View style={[a.rounded_sm, a.overflow_hidden, a.mt_sm]}>
Expand All @@ -131,30 +117,15 @@ export function GifEmbed({
onPress={onPress}
isPlaying={playerState.isPlaying}
isLoaded={playerState.isLoaded}
needsPermissions={needsPermissions}
/>
{needsPermissions ? (
<>
<Image
style={[a.flex_1, a.rounded_sm]}
source={{uri: thumb}}
accessibilityIgnoresInvertColors
/>
<Dialog.Outer control={consentControl}>
<Dialog.Handle />
<GiphyConsentPrompt />
</Dialog.Outer>
</>
) : (
<GifView
source={params.playerUri}
placeholderSource={thumb}
style={[a.flex_1, a.rounded_sm]}
autoplay={!autoplayDisabled}
onPlayerStateChange={onPlayerStateChange}
ref={playerRef}
/>
)}
<GifView
source={params.playerUri}
placeholderSource={thumb}
style={[a.flex_1, a.rounded_sm]}
autoplay={!autoplayDisabled}
onPlayerStateChange={onPlayerStateChange}
ref={playerRef}
/>
</View>
</View>
)
Expand Down
Loading