Geo blocklist - reimplement with backend support (#1089)
Ticket: 1079 Support geoblocking channels/videos ## Changes - Replaced the .env version with iapi version. - Includes 'videos' blocking and custom messages.
This commit is contained in:
parent
de29e323a8
commit
99f87e95e3
14 changed files with 118 additions and 74 deletions
|
@ -130,13 +130,6 @@ FIREBASE_APP_ID=1:638894153788:web:35b295b15297201bd2e339
|
||||||
FIREBASE_MEASUREMENT_ID=G-2MPJGFEEXC
|
FIREBASE_MEASUREMENT_ID=G-2MPJGFEEXC
|
||||||
FIREBASE_VAPID_KEY=BFayEBpwMTU9GQQpXgitIJkfx-SD8-ltrFb3wLTZWgA27MfBhG4948pe0eERl432NzPrMKsbkXnA7ap_vLPgLYk
|
FIREBASE_VAPID_KEY=BFayEBpwMTU9GQQpXgitIJkfx-SD8-ltrFb3wLTZWgA27MfBhG4948pe0eERl432NzPrMKsbkXnA7ap_vLPgLYk
|
||||||
|
|
||||||
# --- Geoblock ---
|
|
||||||
# Note: our current version of dotenv doesn't support multiline definition.
|
|
||||||
#
|
|
||||||
# FORMAT: "<channel_id>; type=[livestream|video|*]; country=[xx|*]; continent=[xx|*]; | ..."
|
|
||||||
#
|
|
||||||
GEOBLOCKED_CHANNELS="148bfcb49da2c2e781ae27387e45043a4bcbd51e; types=livestream; countries=FR,MS; continents=AF,EU; | 636098f86be74be8b609c38e643e48786d58f413; types=livestream,video; countries=EU,SA; continents=EU;"
|
|
||||||
|
|
||||||
# --- Development ---
|
# --- Development ---
|
||||||
REPORT_NEW_STRINGS=false
|
REPORT_NEW_STRINGS=false
|
||||||
USE_LOCAL_HOMEPAGE_DATA=false
|
USE_LOCAL_HOMEPAGE_DATA=false
|
||||||
|
|
24
config.js
24
config.js
|
@ -90,30 +90,6 @@ const config = {
|
||||||
AD_KEYWORD_BLOCKLIST_CHECK_DESCRIPTION: process.env.AD_KEYWORD_BLOCKLIST_CHECK_DESCRIPTION,
|
AD_KEYWORD_BLOCKLIST_CHECK_DESCRIPTION: process.env.AD_KEYWORD_BLOCKLIST_CHECK_DESCRIPTION,
|
||||||
};
|
};
|
||||||
|
|
||||||
config.GEOBLOCKED_CHANNELS = {};
|
|
||||||
if (process.env.GEOBLOCKED_CHANNELS) {
|
|
||||||
const entries = process.env.GEOBLOCKED_CHANNELS.split('|');
|
|
||||||
|
|
||||||
entries.forEach((entry) => {
|
|
||||||
const fields = entry.split(';');
|
|
||||||
|
|
||||||
if (fields.length > 0) {
|
|
||||||
const channelId = fields[0].trim();
|
|
||||||
config.GEOBLOCKED_CHANNELS[channelId] = {};
|
|
||||||
|
|
||||||
for (let i = 1; i < fields.length; ++i) {
|
|
||||||
const kv = fields[i].split('=');
|
|
||||||
|
|
||||||
if (kv.length === 2) {
|
|
||||||
const key = kv[0].trim();
|
|
||||||
const values = kv[1].trim();
|
|
||||||
config.GEOBLOCKED_CHANNELS[channelId][key] = values.split(',');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
config.SDK_API_PATH = `${config.LBRY_WEB_API}/api/v1`;
|
config.SDK_API_PATH = `${config.LBRY_WEB_API}/api/v1`;
|
||||||
config.PROXY_URL = `${config.SDK_API_PATH}/proxy`;
|
config.PROXY_URL = `${config.SDK_API_PATH}/proxy`;
|
||||||
|
|
||||||
|
|
30
flow-typed/Blocklist.js
vendored
30
flow-typed/Blocklist.js
vendored
|
@ -1,5 +1,6 @@
|
||||||
declare type BlocklistState = {
|
declare type BlocklistState = {
|
||||||
blockedChannels: Array<string>
|
blockedChannels: Array<string>,
|
||||||
|
geoBlockedList: ?GBL,
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type BlocklistAction = {
|
declare type BlocklistAction = {
|
||||||
|
@ -8,3 +9,30 @@ declare type BlocklistAction = {
|
||||||
uri: string,
|
uri: string,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ****************************************************************************
|
||||||
|
// Geo-blocked list (GBL)
|
||||||
|
// ****************************************************************************
|
||||||
|
|
||||||
|
declare type GeoChannelId = string;
|
||||||
|
|
||||||
|
declare type GeoRestriction = {
|
||||||
|
id: string,
|
||||||
|
trigger?: string,
|
||||||
|
reason?: string,
|
||||||
|
message?: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
declare type GeoConfig = {
|
||||||
|
countries?: Array<GeoRestriction>,
|
||||||
|
continents?: Array<GeoRestriction>,
|
||||||
|
specials?: Array<GeoRestriction>,
|
||||||
|
};
|
||||||
|
|
||||||
|
declare type GBL = {
|
||||||
|
livestreams?: { [GeoChannelId]: GeoConfig },
|
||||||
|
videos?: { [GeoChannelId]: GeoConfig }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ****************************************************************************
|
||||||
|
// ****************************************************************************
|
||||||
|
|
6
flow-typed/user.js
vendored
6
flow-typed/user.js
vendored
|
@ -41,9 +41,3 @@ declare type LocaleInfo = {
|
||||||
gdpr_required: boolean,
|
gdpr_required: boolean,
|
||||||
is_eu_member: boolean,
|
is_eu_member: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type GeoBlock = {
|
|
||||||
types: Array<string>,
|
|
||||||
countries: Array<string>,
|
|
||||||
continents: Array<string>,
|
|
||||||
};
|
|
||||||
|
|
|
@ -2186,7 +2186,7 @@
|
||||||
"The minimum duration must not exceed Feb 8th, 2022.": "The minimum duration must not exceed Feb 8th, 2022.",
|
"The minimum duration must not exceed Feb 8th, 2022.": "The minimum duration must not exceed Feb 8th, 2022.",
|
||||||
"No limit": "No limit",
|
"No limit": "No limit",
|
||||||
"Search results are being filtered by language. Click here to change the setting.": "Search results are being filtered by language. Click here to change the setting.",
|
"Search results are being filtered by language. Click here to change the setting.": "Search results are being filtered by language. Click here to change the setting.",
|
||||||
"This creator has requested that their livestream be blocked in your region.": "This creator has requested that their livestream be blocked in your region.",
|
"Content unavailable": "Content unavailable",
|
||||||
"There are language translations available for your location! Do you want to switch from English?": "There are language translations available for your location! Do you want to switch from English?",
|
"There are language translations available for your location! Do you want to switch from English?": "There are language translations available for your location! Do you want to switch from English?",
|
||||||
"A homepage and language translations are available for your location! Do you want to switch?": "A homepage and language translations are available for your location! Do you want to switch?",
|
"A homepage and language translations are available for your location! Do you want to switch?": "A homepage and language translations are available for your location! Do you want to switch?",
|
||||||
"A homepage is available for your location! Do you want to switch?": "A homepage is available for your location! Do you want to switch?",
|
"A homepage is available for your location! Do you want to switch?": "A homepage is available for your location! Do you want to switch?",
|
||||||
|
|
|
@ -430,6 +430,11 @@ export const COMMENT_SUPER_CHAT_LIST_FAILED = 'COMMENT_SUPER_CHAT_LIST_FAILED';
|
||||||
// Blocked channels
|
// Blocked channels
|
||||||
export const TOGGLE_BLOCK_CHANNEL = 'TOGGLE_BLOCK_CHANNEL';
|
export const TOGGLE_BLOCK_CHANNEL = 'TOGGLE_BLOCK_CHANNEL';
|
||||||
|
|
||||||
|
// Geo-block
|
||||||
|
export const FETCH_GBL_STARTED = 'FETCH_GBL_STARTED';
|
||||||
|
export const FETCH_GBL_FAILED = 'FETCH_GBL_FAILED';
|
||||||
|
export const FETCH_GBL_DONE = 'FETCH_GBL_DONE';
|
||||||
|
|
||||||
// Coin swap
|
// Coin swap
|
||||||
export const ADD_COIN_SWAP = 'ADD_COIN_SWAP';
|
export const ADD_COIN_SWAP = 'ADD_COIN_SWAP';
|
||||||
export const REMOVE_COIN_SWAP = 'REMOVE_COIN_SWAP';
|
export const REMOVE_COIN_SWAP = 'REMOVE_COIN_SWAP';
|
||||||
|
|
|
@ -14,6 +14,7 @@ import React, { Fragment, useState, useEffect } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { doDaemonReady, doAutoUpdate, doOpenModal, doHideModal, doToggle3PAnalytics } from 'redux/actions/app';
|
import { doDaemonReady, doAutoUpdate, doOpenModal, doHideModal, doToggle3PAnalytics } from 'redux/actions/app';
|
||||||
|
import { doFetchGeoBlockedList } from 'redux/actions/blocked';
|
||||||
import Lbry, { apiCall } from 'lbry';
|
import Lbry, { apiCall } from 'lbry';
|
||||||
import { isURIValid } from 'util/lbryURI';
|
import { isURIValid } from 'util/lbryURI';
|
||||||
import { setSearchApi } from 'redux/actions/search';
|
import { setSearchApi } from 'redux/actions/search';
|
||||||
|
@ -246,6 +247,7 @@ function AppWrapper() {
|
||||||
app.store.dispatch(doUpdateIsNightAsync());
|
app.store.dispatch(doUpdateIsNightAsync());
|
||||||
app.store.dispatch(doBlackListedOutpointsSubscribe());
|
app.store.dispatch(doBlackListedOutpointsSubscribe());
|
||||||
app.store.dispatch(doFilteredOutpointsSubscribe());
|
app.store.dispatch(doFilteredOutpointsSubscribe());
|
||||||
|
app.store.dispatch(doFetchGeoBlockedList());
|
||||||
}, 25);
|
}, 25);
|
||||||
|
|
||||||
analytics.startupEvent(Date.now());
|
analytics.startupEvent(Date.now());
|
||||||
|
|
|
@ -6,32 +6,11 @@ import analytics from 'analytics';
|
||||||
import LivestreamLayout from 'component/livestreamLayout';
|
import LivestreamLayout from 'component/livestreamLayout';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import Yrbl from 'component/yrbl';
|
|
||||||
import { GEOBLOCKED_CHANNELS } from 'config';
|
|
||||||
import * as SETTINGS from 'constants/settings';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useIsMobile } from 'effects/use-screensize';
|
import { useIsMobile } from 'effects/use-screensize';
|
||||||
|
|
||||||
const LivestreamChatLayout = lazyImport(() => import('component/livestreamChatLayout' /* webpackChunkName: "chat" */));
|
const LivestreamChatLayout = lazyImport(() => import('component/livestreamChatLayout' /* webpackChunkName: "chat" */));
|
||||||
|
|
||||||
function isLivestreamGeoAllowed(channelId: ?string, isLive: boolean) {
|
|
||||||
const locale: LocaleInfo = window[SETTINGS.LOCALE];
|
|
||||||
const geoBlock: GeoBlock = GEOBLOCKED_CHANNELS[channelId];
|
|
||||||
|
|
||||||
if (locale && geoBlock) {
|
|
||||||
const typeBlocked = geoBlock.types && geoBlock.types.includes('livestream');
|
|
||||||
const countryBlocked = geoBlock.countries && geoBlock.countries.includes(locale.country);
|
|
||||||
const europeanUnionOnly = geoBlock.continents && geoBlock.continents.includes('EU-UNION') && locale.is_eu_member;
|
|
||||||
const continentBlocked =
|
|
||||||
europeanUnionOnly || (geoBlock.continents && geoBlock.continents.includes(locale.continent));
|
|
||||||
|
|
||||||
return typeBlocked && !countryBlocked && !continentBlocked;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If 'locale/get' fails, we don't know whether to block or not. Flaw?
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
activeLivestreamForChannel: any,
|
activeLivestreamForChannel: any,
|
||||||
activeLivestreamInitialized: boolean,
|
activeLivestreamInitialized: boolean,
|
||||||
|
@ -75,7 +54,6 @@ export default function LivestreamPage(props: Props) {
|
||||||
const claimId = claim && claim.claim_id;
|
const claimId = claim && claim.claim_id;
|
||||||
const isCurrentClaimLive = isChannelBroadcasting && activeLivestreamForChannel.claimId === claimId;
|
const isCurrentClaimLive = isChannelBroadcasting && activeLivestreamForChannel.claimId === claimId;
|
||||||
const livestreamChannelId = channelClaimId || '';
|
const livestreamChannelId = channelClaimId || '';
|
||||||
const isGeoBlocked = !isLivestreamGeoAllowed(channelClaimId, isCurrentClaimLive);
|
|
||||||
|
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
const release = moment.unix(claim.value.release_time);
|
const release = moment.unix(claim.value.release_time);
|
||||||
|
@ -182,7 +160,6 @@ export default function LivestreamPage(props: Props) {
|
||||||
livestream
|
livestream
|
||||||
chatDisabled={hideComments}
|
chatDisabled={hideComments}
|
||||||
rightSide={
|
rightSide={
|
||||||
!isGeoBlocked &&
|
|
||||||
!hideComments &&
|
!hideComments &&
|
||||||
isInitialized && (
|
isInitialized && (
|
||||||
<React.Suspense fallback={null}>
|
<React.Suspense fallback={null}>
|
||||||
|
@ -191,17 +168,7 @@ export default function LivestreamPage(props: Props) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{isGeoBlocked && (
|
{isInitialized && (
|
||||||
<div className="main--empty">
|
|
||||||
<Yrbl
|
|
||||||
title={__('This creator has requested that their livestream be blocked in your region.')}
|
|
||||||
type="sad"
|
|
||||||
alwaysShow
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isInitialized && !isGeoBlocked && (
|
|
||||||
<LivestreamLayout
|
<LivestreamLayout
|
||||||
uri={uri}
|
uri={uri}
|
||||||
hideComments={hideComments}
|
hideComments={hideComments}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
selectClaimIsMine,
|
selectClaimIsMine,
|
||||||
makeSelectClaimIsPending,
|
makeSelectClaimIsPending,
|
||||||
selectIsStreamPlaceholderForUri,
|
selectIsStreamPlaceholderForUri,
|
||||||
|
selectGeoRestrictionForUri,
|
||||||
} from 'redux/selectors/claims';
|
} from 'redux/selectors/claims';
|
||||||
import {
|
import {
|
||||||
makeSelectCollectionForId,
|
makeSelectCollectionForId,
|
||||||
|
@ -86,6 +87,7 @@ const select = (state, props) => {
|
||||||
collectionId,
|
collectionId,
|
||||||
collectionUrls: makeSelectUrlsForCollectionId(collectionId)(state),
|
collectionUrls: makeSelectUrlsForCollectionId(collectionId)(state),
|
||||||
isResolvingCollection: makeSelectIsResolvingCollectionForId(collectionId)(state),
|
isResolvingCollection: makeSelectIsResolvingCollectionForId(collectionId)(state),
|
||||||
|
geoRestriction: selectGeoRestrictionForUri(state, uri),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ type Props = {
|
||||||
collection: Collection,
|
collection: Collection,
|
||||||
collectionUrls: Array<string>,
|
collectionUrls: Array<string>,
|
||||||
isResolvingCollection: boolean,
|
isResolvingCollection: boolean,
|
||||||
|
geoRestriction: ?GeoRestriction,
|
||||||
doResolveUri: (uri: string, returnCached: boolean, resolveReposts: boolean, options: any) => void,
|
doResolveUri: (uri: string, returnCached: boolean, resolveReposts: boolean, options: any) => void,
|
||||||
doBeginPublish: (name: ?string) => void,
|
doBeginPublish: (name: ?string) => void,
|
||||||
doFetchItemsInCollection: ({ collectionId: string }) => void,
|
doFetchItemsInCollection: ({ collectionId: string }) => void,
|
||||||
|
@ -57,6 +58,7 @@ export default function ShowPage(props: Props) {
|
||||||
collection,
|
collection,
|
||||||
collectionUrls,
|
collectionUrls,
|
||||||
isResolvingCollection,
|
isResolvingCollection,
|
||||||
|
geoRestriction,
|
||||||
doResolveUri,
|
doResolveUri,
|
||||||
doBeginPublish,
|
doBeginPublish,
|
||||||
doFetchItemsInCollection,
|
doFetchItemsInCollection,
|
||||||
|
@ -87,7 +89,7 @@ export default function ShowPage(props: Props) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// changed this from 'isCollection' to resolve strangers' collections.
|
// changed this from 'isCollection' to resolve strangers' collections.
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (collectionId && !resolvedCollection) {
|
if (collectionId && !resolvedCollection) {
|
||||||
doFetchItemsInCollection({ collectionId });
|
doFetchItemsInCollection({ collectionId });
|
||||||
}
|
}
|
||||||
|
@ -229,6 +231,14 @@ export default function ShowPage(props: Props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (geoRestriction) {
|
||||||
|
return (
|
||||||
|
<div className="main--empty">
|
||||||
|
<Yrbl title={__('Content unavailable')} subtitle={__(geoRestriction.message || '')} type="sad" alwaysShow />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (showLiveStream) {
|
if (showLiveStream) {
|
||||||
return (
|
return (
|
||||||
<React.Suspense fallback={null}>
|
<React.Suspense fallback={null}>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
import { Lbryio } from 'lbryinc';
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import { selectPrefsReady } from 'redux/selectors/sync';
|
import { selectPrefsReady } from 'redux/selectors/sync';
|
||||||
import { doAlertWaitingForSync } from 'redux/actions/app';
|
import { doAlertWaitingForSync } from 'redux/actions/app';
|
||||||
|
@ -39,3 +40,22 @@ export function doChannelUnmute(uri: string, showLink: boolean = true) {
|
||||||
return dispatch(doToggleMuteChannel(uri, showLink, true));
|
return dispatch(doToggleMuteChannel(uri, showLink, true));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doFetchGeoBlockedList() {
|
||||||
|
return (dispatch: Dispatch) => {
|
||||||
|
dispatch({ type: ACTIONS.FETCH_GBL_STARTED });
|
||||||
|
|
||||||
|
const success = (response: GBL) => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.FETCH_GBL_DONE,
|
||||||
|
data: response,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const failure = (error) => {
|
||||||
|
dispatch({ type: ACTIONS.FETCH_GBL_FAILED, data: error });
|
||||||
|
};
|
||||||
|
|
||||||
|
Lbryio.call('geo', 'blocked_list').then(success, failure);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { handleActions } from 'util/redux-utils';
|
||||||
|
|
||||||
const defaultState: BlocklistState = {
|
const defaultState: BlocklistState = {
|
||||||
blockedChannels: [],
|
blockedChannels: [],
|
||||||
|
geoBlockedList: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default handleActions(
|
export default handleActions(
|
||||||
|
@ -20,9 +21,16 @@ export default handleActions(
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
...state,
|
||||||
blockedChannels: newBlockedChannels,
|
blockedChannels: newBlockedChannels,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
[ACTIONS.FETCH_GBL_DONE]: (state: BlocklistState, action: any): BlocklistState => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
geoBlockedList: action.data,
|
||||||
|
};
|
||||||
|
},
|
||||||
[ACTIONS.USER_STATE_POPULATE]: (state: BlocklistState, action: { data: { blocked: ?Array<string> } }) => {
|
[ACTIONS.USER_STATE_POPULATE]: (state: BlocklistState, action: { data: { blocked: ?Array<string> } }) => {
|
||||||
const { blocked } = action.data;
|
const { blocked } = action.data;
|
||||||
const sanitizedBlocked = blocked && blocked.filter((e) => typeof e === 'string');
|
const sanitizedBlocked = blocked && blocked.filter((e) => typeof e === 'string');
|
||||||
|
|
|
@ -7,6 +7,7 @@ type State = { blocked: BlocklistState };
|
||||||
const selectState = (state: State) => state.blocked || {};
|
const selectState = (state: State) => state.blocked || {};
|
||||||
|
|
||||||
export const selectMutedChannels = (state: State) => selectState(state).blockedChannels;
|
export const selectMutedChannels = (state: State) => selectState(state).blockedChannels;
|
||||||
|
export const selectGeoBlockLists = (state: State) => selectState(state).geoBlockedList;
|
||||||
|
|
||||||
export const makeSelectChannelIsMuted = (uri: string) =>
|
export const makeSelectChannelIsMuted = (uri: string) =>
|
||||||
createSelector(selectMutedChannels, (state: Array<string>) => {
|
createSelector(selectMutedChannels, (state: Array<string>) => {
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { CHANNEL_CREATION_LIMIT } from 'config';
|
import { CHANNEL_CREATION_LIMIT } from 'config';
|
||||||
import { normalizeURI, parseURI, isURIValid } from 'util/lbryURI';
|
import { normalizeURI, parseURI, isURIValid } from 'util/lbryURI';
|
||||||
|
import { selectGeoBlockLists } from 'redux/selectors/blocked';
|
||||||
import { selectYoutubeChannels } from 'redux/selectors/user';
|
import { selectYoutubeChannels } from 'redux/selectors/user';
|
||||||
import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
|
import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { createCachedSelector } from 're-reselect';
|
import { createCachedSelector } from 're-reselect';
|
||||||
import { isClaimNsfw, filterClaims, getChannelIdFromClaim, isStreamPlaceholderClaim } from 'util/claim';
|
import { isClaimNsfw, filterClaims, getChannelIdFromClaim, isStreamPlaceholderClaim } from 'util/claim';
|
||||||
import * as CLAIM from 'constants/claim';
|
import * as CLAIM from 'constants/claim';
|
||||||
|
import * as SETTINGS from 'constants/settings';
|
||||||
import { INTERNAL_TAGS } from 'constants/tags';
|
import { INTERNAL_TAGS } from 'constants/tags';
|
||||||
|
|
||||||
type State = { claims: any, user: User };
|
type State = { claims: any, user: User };
|
||||||
|
@ -829,3 +831,39 @@ export const selectOdyseeMembershipForChannelId = function (state: State, channe
|
||||||
|
|
||||||
return matchingMembershipOfUser;
|
return matchingMembershipOfUser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const selectGeoRestrictionForUri = createCachedSelector(
|
||||||
|
selectClaimForUri,
|
||||||
|
selectGeoBlockLists,
|
||||||
|
(claim, geoBlockLists) => {
|
||||||
|
const locale: LocaleInfo = window[SETTINGS.LOCALE]; // <-- NOTE: not handled by redux updates
|
||||||
|
const channelId: ?string = getChannelIdFromClaim(claim);
|
||||||
|
|
||||||
|
if (locale && geoBlockLists && channelId && claim) {
|
||||||
|
let geoConfig: ?GeoConfig;
|
||||||
|
|
||||||
|
// --- livestreams
|
||||||
|
if (isStreamPlaceholderClaim(claim)) {
|
||||||
|
geoConfig = geoBlockLists.livestreams && geoBlockLists.livestreams[channelId];
|
||||||
|
}
|
||||||
|
// --- videos (a.k.a everything else)
|
||||||
|
else {
|
||||||
|
geoConfig = geoBlockLists.videos && geoBlockLists.videos[channelId];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geoConfig) {
|
||||||
|
const specials = geoConfig.specials || [];
|
||||||
|
const countries = geoConfig.countries || [];
|
||||||
|
const continents = geoConfig.continents || [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
specials.find((x: GeoRestriction) => x.id === 'EU-ONLY' && locale.is_eu_member) ||
|
||||||
|
countries.find((x: GeoRestriction) => x.id === locale.country) ||
|
||||||
|
continents.find((x: GeoRestriction) => x.id === locale.continent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
)((state, uri) => String(uri));
|
||||||
|
|
Loading…
Add table
Reference in a new issue