diff --git a/src/components/live/GoLiveDialog.tsx b/src/components/live/GoLiveDialog.tsx index ac51e87527..70954e3431 100644 --- a/src/components/live/GoLiveDialog.tsx +++ b/src/components/live/GoLiveDialog.tsx @@ -6,7 +6,6 @@ import {useLingui} from '@lingui/react' import {cleanError} from '#/lib/strings/errors' import {definitelyUrl} from '#/lib/strings/url-helpers' import {useModerationOpts} from '#/state/preferences/moderation-opts' -import {useLiveNowConfig} from '#/state/service-config' import {useTickEveryMinute} from '#/state/shell' import {atoms as a, ios, native, platform, useTheme, web} from '#/alf' import {Admonition} from '#/components/Admonition' @@ -22,6 +21,7 @@ import {Loader} from '#/components/Loader' import * as ProfileCard from '#/components/ProfileCard' import * as Select from '#/components/Select' import {Text} from '#/components/Typography' +import {useLiveNowConfig} from '#/features/liveNow' import type * as bsky from '#/types/bsky' import {LinkPreview} from './LinkPreview' import {useLiveLinkMetaQuery, useUpsertLiveStatusMutation} from './queries' diff --git a/src/components/live/queries.ts b/src/components/live/queries.ts index 3c2534872c..c03bdb6dc8 100644 --- a/src/components/live/queries.ts +++ b/src/components/live/queries.ts @@ -13,12 +13,12 @@ import {uploadBlob} from '#/lib/api' import {imageToThumb} from '#/lib/api/resolve' import {getLinkMeta, type LinkMeta} from '#/lib/link-meta/link-meta' import {updateProfileShadow} from '#/state/cache/profile-shadow' -import {useLiveNowConfig} from '#/state/service-config' import {useAgent, useSession} from '#/state/session' import * as Toast from '#/view/com/util/Toast' import {useDialogContext} from '#/components/Dialog' import {getLiveServiceNames} from '#/components/live/utils' import {useAnalytics} from '#/analytics' +import {useLiveNowConfig} from '#/features/liveNow' export function useLiveLinkMetaQuery(url: string | null) { const liveNowConfig = useLiveNowConfig() diff --git a/src/features/liveNow/index.tsx b/src/features/liveNow/index.tsx new file mode 100644 index 0000000000..09c5ddbc8c --- /dev/null +++ b/src/features/liveNow/index.tsx @@ -0,0 +1,61 @@ +import {useMemo} from 'react' + +import {useAppConfig} from '#/state/appConfig' +import {useSession} from '#/state/session' +import {useAnalytics} from '#/analytics' + +export const DEFAULT_ALLOWED_DOMAINS = [ + 'twitch.tv', + 'stream.place', + 'bluecast.app', + + // TODO remove need for subdomains + 'www.twitch.tv', + 'www.bluecast.app', +] + +export type LiveNowConfig = { + canGoLive: boolean + currentAccountAllowedHosts: Set + defaultAllowedHosts: Set + allowedHostsExceptionsByDid: Map> +} + +export function useLiveNowConfig(): LiveNowConfig { + const ax = useAnalytics() + const {liveNow} = useAppConfig() + const {currentAccount} = useSession() + + return useMemo(() => { + const disabled = ax.features.enabled(ax.features.LiveNowBetaDisable) + + if (!currentAccount?.did || disabled) { + return { + canGoLive: false, + currentAccountAllowedHosts: new Set(), + defaultAllowedHosts: new Set(), + allowedHostsExceptionsByDid: new Map(), + } + } + + const defaultAllowedHosts = new Set( + DEFAULT_ALLOWED_DOMAINS.concat(liveNow.allow), + ) + const allowedHostsExceptionsByDid = new Map>() + for (const ex of liveNow.exceptions) { + allowedHostsExceptionsByDid.set( + ex.did, + new Set(DEFAULT_ALLOWED_DOMAINS.concat(ex.allow)), + ) + } + + return { + canGoLive: true, + currentAccountAllowedHosts: + allowedHostsExceptionsByDid.get(currentAccount.did) ?? + defaultAllowedHosts, + defaultAllowedHosts, + allowedHostsExceptionsByDid, + } + }, [ax, liveNow, currentAccount]) +} diff --git a/src/lib/actor-status.ts b/src/lib/actor-status.ts index 89a3a163de..b66fe68a92 100644 --- a/src/lib/actor-status.ts +++ b/src/lib/actor-status.ts @@ -8,8 +8,8 @@ import { import {isAfter, parseISO} from 'date-fns' import {useMaybeProfileShadow} from '#/state/cache/profile-shadow' -import {type LiveNowConfig, useLiveNowConfig} from '#/state/service-config' import {useTickEveryMinute} from '#/state/shell' +import {type LiveNowConfig, useLiveNowConfig} from '#/features/liveNow' import type * as bsky from '#/types/bsky' export function useActorStatus(actor?: bsky.profile.AnyProfileView) { diff --git a/src/state/service-config.tsx b/src/state/service-config.tsx index 29fa6bec90..5470f56e4e 100644 --- a/src/state/service-config.tsx +++ b/src/state/service-config.tsx @@ -2,9 +2,6 @@ import {createContext, useContext, useMemo} from 'react' import {useLanguagePrefs} from '#/state/preferences/languages' import {useServiceConfigQuery} from '#/state/queries/service-config' -import {useSession} from '#/state/session' -import {useAnalytics} from '#/analytics' -import {IS_DEV} from '#/env' import {device} from '#/storage' type TrendingContext = { @@ -81,55 +78,6 @@ export function useTrendingConfig() { return useContext(TrendingContext) } -const DEFAULT_LIVE_ALLOWED_DOMAINS = [ - 'twitch.tv', - 'www.twitch.tv', - 'stream.place', - 'bluecast.app', - 'www.bluecast.app', -] -export type LiveNowConfig = { - currentAccountAllowedHosts: Set - defaultAllowedHosts: Set - allowedHostsExceptionsByDid: Map> -} -export function useLiveNowConfig(): LiveNowConfig { - const ctx = useContext(LiveNowContext) - const canGoLive = useCanGoLive() - const {currentAccount} = useSession() - return useMemo(() => { - const defaultAllowedHosts = new Set(DEFAULT_LIVE_ALLOWED_DOMAINS) - const allowedHostsExceptionsByDid = new Map>() - for (const live of ctx) { - allowedHostsExceptionsByDid.set( - live.did, - new Set(DEFAULT_LIVE_ALLOWED_DOMAINS.concat(live.domains)), - ) - } - if (!currentAccount?.did || !canGoLive) - return { - currentAccountAllowedHosts: new Set(), - defaultAllowedHosts, - allowedHostsExceptionsByDid, - } - const vip = ctx.find(live => live.did === currentAccount.did) - return { - currentAccountAllowedHosts: new Set( - DEFAULT_LIVE_ALLOWED_DOMAINS.concat(vip ? vip.domains : []), - ), - defaultAllowedHosts, - allowedHostsExceptionsByDid, - } - }, [ctx, currentAccount, canGoLive]) -} - -export function useCanGoLive() { - const ax = useAnalytics() - const {hasSession} = useSession() - if (!hasSession) return false - return IS_DEV ? true : !ax.features.enabled(ax.features.LiveNowBetaDisable) -} - export function useCheckEmailConfirmed() { const ctx = useContext(CheckEmailConfirmedContext) if (ctx === null) { diff --git a/src/view/com/posts/PostFeed.tsx b/src/view/com/posts/PostFeed.tsx index 3c8d25faf8..cb1e367b4f 100644 --- a/src/view/com/posts/PostFeed.tsx +++ b/src/view/com/posts/PostFeed.tsx @@ -48,7 +48,6 @@ import { RQKEY, usePostFeedQuery, } from '#/state/queries/post-feed' -import {useLiveNowConfig} from '#/state/service-config' import {useSession} from '#/state/session' import {useProgressGuide} from '#/state/shell/progress-guide' import {useSelectedFeed} from '#/state/shell/selected-feed' @@ -71,6 +70,7 @@ import {TrendingVideos as TrendingVideosInterstitial} from '#/components/interst import {useAnalytics} from '#/analytics' import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env' import {DiscoverFeedLiveEventFeedsAndTrendingBanner} from '#/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner' +import {useLiveNowConfig} from '#/features/liveNow' import {ComposerPrompt} from '../feeds/ComposerPrompt' import {DiscoverFallbackHeader} from './DiscoverFallbackHeader' import {FeedShutdownMsg} from './FeedShutdownMsg' diff --git a/src/view/com/profile/ProfileMenu.tsx b/src/view/com/profile/ProfileMenu.tsx index 684dcbf0fe..25601b0228 100644 --- a/src/view/com/profile/ProfileMenu.tsx +++ b/src/view/com/profile/ProfileMenu.tsx @@ -20,7 +20,6 @@ import { useProfileFollowMutationQueue, useProfileMuteMutationQueue, } from '#/state/queries/profile' -import {useCanGoLive} from '#/state/service-config' import {useSession} from '#/state/session' import {EventStopper} from '#/view/com/util/EventStopper' import * as Toast from '#/view/com/util/Toast' @@ -61,6 +60,7 @@ import {VerificationCreatePrompt} from '#/components/verification/VerificationCr import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt' import {useAnalytics} from '#/analytics' import {IS_WEB} from '#/env' +import {useLiveNowConfig} from '#/features/liveNow' import {Dot} from '#/features/nuxs/components/Dot' import {Gradient} from '#/features/nuxs/components/Gradient' import {useDevMode} from '#/storage/hooks/dev-mode' @@ -85,7 +85,7 @@ let ProfileMenu = ({ const isLabelerAndNotBlocked = !!profile.associated?.labeler && !isBlocked const [devModeEnabled] = useDevMode() const verification = useFullVerificationState({profile}) - const canGoLive = useCanGoLive() + const {canGoLive} = useLiveNowConfig() const status = useActorStatus(profile) const statusNudge = useNux(Nux.LiveNowBetaNudge) const statusNudgeActive =