diff --git a/config.js b/config.js index c30a1c96b..f2efb3a81 100644 --- a/config.js +++ b/config.js @@ -1515,6 +1515,8 @@ var config = { // tileTime: 5000, // // Limit results by rating: g, pg, pg-13, r. Default value: g. // rating: 'pg', + // // The proxy server url for giphy requests in the web app. + // proxyUrl: 'https://giphy-proxy.example.com', // }, // Logging diff --git a/package-lock.json b/package-lock.json index f92977c4f..8920af9e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "@atlaskit/tooltip": "17.1.2", "@emotion/react": "11.10.0", "@emotion/styled": "11.10.0", - "@giphy/js-fetch-api": "4.1.2", + "@giphy/js-fetch-api": "4.7.1", "@giphy/react-components": "5.6.0", "@giphy/react-native-sdk": "1.7.0", "@hapi/bourne": "2.0.0", @@ -3497,26 +3497,26 @@ } }, "node_modules/@giphy/js-fetch-api": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@giphy/js-fetch-api/-/js-fetch-api-4.1.2.tgz", - "integrity": "sha512-wDfDQu8HiVkLb+YXcZf8QFbznmMHWbg86ZBydYmnp2mfuHyaHKsz9n9PnxdH3RorMS9YM/Ca/zqAM5y89Qj+Hw==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/@giphy/js-fetch-api/-/js-fetch-api-4.7.1.tgz", + "integrity": "sha512-LFpi8ZbV/N51nhIDc7ig6HnBUZ0Y/Av0GVCVDOs9zmUK1/zgTA33fkWMCNVxc4wgrugwRXCJA7Mj8Zb8BTea2w==", "dependencies": { - "@giphy/js-types": "^4.1.0", - "@giphy/js-util": "^4.0.1", + "@giphy/js-types": "^4.4.0", + "@giphy/js-util": "^4.3.0", "qs": "^6.9.4" } }, "node_modules/@giphy/js-types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@giphy/js-types/-/js-types-4.1.0.tgz", - "integrity": "sha512-+qSN4Mx4TmrjLQm4SC0I/ZBkb5eWM94sljXwfjIlqn0GMSR3geqEqwmE9Uf/ldgzFh+XMMCasQjIdUl2nWc++Q==" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@giphy/js-types/-/js-types-4.4.0.tgz", + "integrity": "sha512-W9G6crS2oqTn7g0RpvYu1l/sna4LnivRTk25jmxdzujOFb9kvQ+VFM/v9RPYV2GIBnzT/maW/EwjFIba9jkflA==" }, "node_modules/@giphy/js-util": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@giphy/js-util/-/js-util-4.0.1.tgz", - "integrity": "sha512-46wXgt5Y+MxZjuzjE6JlvMLE+6Vlag+PYxbyTxpsunhmOKNoYK99d51E09iynmXTFuZWYgWJR9LcfnzqsWHy+Q==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@giphy/js-util/-/js-util-4.3.0.tgz", + "integrity": "sha512-ZxYw4DiNVchMxtCjVdLzXJ6+40To1C1B37PJ2a7zUP8Dxa62uGctbyb2PXAB1NmsCZOhy1d0QGEnjxK5LQocHQ==", "dependencies": { - "@giphy/js-types": "^4.1.0", + "@giphy/js-types": "^4.4.0", "dompurify": "^2.2.2", "uuid": "^8.3.0" } @@ -23036,26 +23036,26 @@ } }, "@giphy/js-fetch-api": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@giphy/js-fetch-api/-/js-fetch-api-4.1.2.tgz", - "integrity": "sha512-wDfDQu8HiVkLb+YXcZf8QFbznmMHWbg86ZBydYmnp2mfuHyaHKsz9n9PnxdH3RorMS9YM/Ca/zqAM5y89Qj+Hw==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/@giphy/js-fetch-api/-/js-fetch-api-4.7.1.tgz", + "integrity": "sha512-LFpi8ZbV/N51nhIDc7ig6HnBUZ0Y/Av0GVCVDOs9zmUK1/zgTA33fkWMCNVxc4wgrugwRXCJA7Mj8Zb8BTea2w==", "requires": { - "@giphy/js-types": "^4.1.0", - "@giphy/js-util": "^4.0.1", + "@giphy/js-types": "^4.4.0", + "@giphy/js-util": "^4.3.0", "qs": "^6.9.4" } }, "@giphy/js-types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@giphy/js-types/-/js-types-4.1.0.tgz", - "integrity": "sha512-+qSN4Mx4TmrjLQm4SC0I/ZBkb5eWM94sljXwfjIlqn0GMSR3geqEqwmE9Uf/ldgzFh+XMMCasQjIdUl2nWc++Q==" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@giphy/js-types/-/js-types-4.4.0.tgz", + "integrity": "sha512-W9G6crS2oqTn7g0RpvYu1l/sna4LnivRTk25jmxdzujOFb9kvQ+VFM/v9RPYV2GIBnzT/maW/EwjFIba9jkflA==" }, "@giphy/js-util": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@giphy/js-util/-/js-util-4.0.1.tgz", - "integrity": "sha512-46wXgt5Y+MxZjuzjE6JlvMLE+6Vlag+PYxbyTxpsunhmOKNoYK99d51E09iynmXTFuZWYgWJR9LcfnzqsWHy+Q==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@giphy/js-util/-/js-util-4.3.0.tgz", + "integrity": "sha512-ZxYw4DiNVchMxtCjVdLzXJ6+40To1C1B37PJ2a7zUP8Dxa62uGctbyb2PXAB1NmsCZOhy1d0QGEnjxK5LQocHQ==", "requires": { - "@giphy/js-types": "^4.1.0", + "@giphy/js-types": "^4.4.0", "dompurify": "^2.2.2", "uuid": "^8.3.0" } diff --git a/package.json b/package.json index b940e1fee..41bdf75dd 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@atlaskit/tooltip": "17.1.2", "@emotion/react": "11.10.0", "@emotion/styled": "11.10.0", - "@giphy/js-fetch-api": "4.1.2", + "@giphy/js-fetch-api": "4.7.1", "@giphy/react-components": "5.6.0", "@giphy/react-native-sdk": "1.7.0", "@hapi/bourne": "2.0.0", diff --git a/react/features/base/config/configType.ts b/react/features/base/config/configType.ts index b8d19dc4c..b64a85450 100644 --- a/react/features/base/config/configType.ts +++ b/react/features/base/config/configType.ts @@ -343,6 +343,7 @@ export interface IConfig { giphy?: { displayMode?: 'all' | 'tile' | 'chat'; enabled?: boolean; + proxyUrl?: string; rating?: 'g' | 'pg' | 'pg-13' | 'r'; sdkKey?: string; tileTime?: number; diff --git a/react/features/gifs/components/native/GifsMenu.js b/react/features/gifs/components/native/GifsMenu.js index 255bd722c..ea3a93db2 100644 --- a/react/features/gifs/components/native/GifsMenu.js +++ b/react/features/gifs/components/native/GifsMenu.js @@ -8,7 +8,7 @@ import JitsiScreen from '../../../base/modal/components/JitsiScreen'; import Input from '../../../base/ui/components/native/Input'; import { sendMessage } from '../../../chat/actions.any'; import { goBack } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef'; -import { formatGifUrlMessage, getGifRating, getGifUrl } from '../../functions'; +import { formatGifUrlMessage, getGifRating, getGifUrl, getGiphyProxyUrl } from '../../functions'; import GifsMenuFooter from './GifsMenuFooter'; import styles from './styles'; @@ -18,6 +18,7 @@ const GifsMenu = () => { const dispatch = useDispatch(); const { t } = useTranslation(); const rating = useSelector(getGifRating); + const proxyUrl = useSelector(getGiphyProxyUrl); const options = { mediaType: GiphyMediaType.Gif, @@ -33,7 +34,7 @@ const GifsMenu = () => { }); const sendGif = useCallback(e => { - const url = getGifUrl(e.nativeEvent.media); + const url = getGifUrl(e.nativeEvent.media, proxyUrl); sendAnalytics(createGifSentEvent()); diff --git a/react/features/gifs/components/web/GifsMenu.tsx b/react/features/gifs/components/web/GifsMenu.tsx index 0a869f1dc..707447d5d 100644 --- a/react/features/gifs/components/web/GifsMenu.tsx +++ b/react/features/gifs/components/web/GifsMenu.tsx @@ -1,4 +1,4 @@ -import { GiphyFetch, TrendingOptions } from '@giphy/js-fetch-api'; +import { GiphyFetch, TrendingOptions, setServerUrl } from '@giphy/js-fetch-api'; import { Grid } from '@giphy/react-components'; import React, { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -22,7 +22,8 @@ import { formatGifUrlMessage, getGifAPIKey, getGifRating, - getGifUrl + getGifUrl, + getGiphyProxyUrl } from '../../function.any'; const OVERFLOW_DRAWER_PADDING = 16; @@ -92,6 +93,7 @@ function GifsMenu() { const overflowDrawer: boolean = useSelector(showOverflowDrawer); const { clientWidth } = useSelector((state: IReduxState) => state['features/base/responsive-ui']); const rating = useSelector(getGifRating); + const proxyUrl = useSelector(getGiphyProxyUrl); const fetchGifs = useCallback(async (offset = 0) => { const options: TrendingOptions = { @@ -114,7 +116,7 @@ function GifsMenu() { const handleGifClick = useCallback((gif, e) => { e?.stopPropagation(); - const url = getGifUrl(gif); + const url = getGifUrl(gif, proxyUrl); sendAnalytics(createGifSentEvent()); batch(() => { @@ -177,6 +179,12 @@ function GifsMenu() { // This fixes that. useEffect(() => setSearchKey(''), []); + useEffect(() => { + if (proxyUrl) { + setServerUrl(proxyUrl); + } + }, []); + const onInputKeyPress = useCallback((e: React.KeyboardEvent) => { e.stopPropagation(); }, []); diff --git a/react/features/gifs/function.any.ts b/react/features/gifs/function.any.ts index 41754e880..61a507924 100644 --- a/react/features/gifs/function.any.ts +++ b/react/features/gifs/function.any.ts @@ -3,6 +3,46 @@ import { IReduxState } from '../app/types'; import { GIF_DEFAULT_RATING, GIF_PREFIX } from './constants'; import { IGif } from './reducer'; +/** + * Returns the gif config. + * + * @param {IReduxState} state - Redux state. + * @returns {Object} + */ +export function getGifConfig(state: IReduxState) { + return state['features/base/config'].giphy || {}; +} + +/** + * Get the GIF display mode. + * + * @param {IReduxState} state - Redux state. + * @returns {string} + */ +export function getGifDisplayMode(state: IReduxState) { + return getGifConfig(state).displayMode || 'all'; +} + +/** + * Get the GIF audience rating. + * + * @param {IReduxState} state - Redux state. + * @returns {string} + */ +export function getGifRating(state: IReduxState) { + return getGifConfig(state).rating || GIF_DEFAULT_RATING; +} + +/** + * Get the Giphy proxy url. + * + * @param {IReduxState} state - Redux state. + * @returns {string} + */ +export function getGiphyProxyUrl(state: IReduxState) { + return getGifConfig(state).proxyUrl; +} + /** * Gets the URL of the GIF for the given participant or null if there's none. * @@ -29,13 +69,18 @@ export function isGifMessage(message: string) { * Returns the url of the gif selected in the gifs menu. * * @param {Object} gif - The gif data. + * @param {string} proxyUrl - The proxy server url. * @returns {boolean} */ -export function getGifUrl(gif?: { data?: { embed_url: string; }; embed_url?: string; }) { +export function getGifUrl(gif?: { data?: { embed_url: string; }; embed_url?: string; }, proxyUrl?: string) { const embedUrl = gif?.embed_url || gif?.data?.embed_url || ''; const idx = embedUrl.lastIndexOf('/'); const id = embedUrl.substr(idx + 1); + if (proxyUrl) { + return `${proxyUrl}gifs/id/${id}`; + } + return `https://i.giphy.com/media/${id}/giphy.gif`; } @@ -56,7 +101,7 @@ export function formatGifUrlMessage(url: string) { * @returns {string} */ export function getGifAPIKey(state: IReduxState) { - return state['features/base/config']?.giphy?.sdkKey ?? ''; + return getGifConfig(state).sdkKey ?? ''; } /** @@ -77,26 +122,3 @@ export function isGifEnabled(state: IReduxState) { return showGiphyIntegration && Boolean(!disableThirdPartyRequests && giphy?.enabled && Boolean(giphy?.sdkKey)); } -/** - * Get the GIF display mode. - * - * @param {IReduxState} state - Redux state. - * @returns {string} - */ -export function getGifDisplayMode(state: IReduxState) { - const { giphy } = state['features/base/config']; - - return giphy?.displayMode || 'all'; -} - -/** - * Get the GIF audience rating. - * - * @param {IReduxState} state - Redux state. - * @returns {string} - */ -export function getGifRating(state: IReduxState) { - const { giphy } = state['features/base/config']; - - return giphy?.rating || GIF_DEFAULT_RATING; -} diff --git a/react/features/gifs/subscriber.native.ts b/react/features/gifs/subscriber.native.ts index aba2ce6e3..f8e9e0d83 100644 --- a/react/features/gifs/subscriber.native.ts +++ b/react/features/gifs/subscriber.native.ts @@ -2,13 +2,13 @@ import { GiphySDK } from '@giphy/react-native-sdk'; import StateListenerRegistry from '../base/redux/StateListenerRegistry'; -import { isGifEnabled } from './function.any'; +import { getGifConfig, isGifEnabled } from './function.any'; /** * Listens for changes in the number of participants to calculate the dimensions of the tile view grid and the tiles. */ StateListenerRegistry.register( - /* selector */ state => state['features/base/config']?.giphy, + /* selector */ state => getGifConfig(state), /* listener */ (_, store) => { const state = store.getState();