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

Feat / Deterministic public URLs #644

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/common/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type Env = {
APP_PLAYER_ID: string;
APP_FOOTER_TEXT: string;
APP_DEFAULT_LANGUAGE: string;
APP_PUBLIC_URL: string;

APP_DEFAULT_CONFIG_SOURCE?: string;
APP_PLAYER_LICENSE_KEY?: string;
Expand All @@ -20,6 +21,7 @@ const env: Env = {
APP_PLAYER_ID: 'M4qoGvUk',
APP_FOOTER_TEXT: '',
APP_DEFAULT_LANGUAGE: 'en',
APP_PUBLIC_URL: '',
};

export const configureEnv = (options: Partial<Env>) => {
Expand All @@ -29,6 +31,7 @@ export const configureEnv = (options: Partial<Env>) => {
env.APP_PLAYER_ID = options.APP_PLAYER_ID || env.APP_PLAYER_ID;
env.APP_FOOTER_TEXT = options.APP_FOOTER_TEXT || env.APP_FOOTER_TEXT;
env.APP_DEFAULT_LANGUAGE = options.APP_DEFAULT_LANGUAGE || env.APP_DEFAULT_LANGUAGE;
env.APP_PUBLIC_URL = options.APP_PUBLIC_URL || env.APP_PUBLIC_URL;

env.APP_DEFAULT_CONFIG_SOURCE ||= options.APP_DEFAULT_CONFIG_SOURCE;
env.APP_PLAYER_LICENSE_KEY ||= options.APP_PLAYER_LICENSE_KEY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import AccountController from '@jwp/ott-common/src/controllers/AccountController
import { modalURLFromLocation } from '@jwp/ott-ui-react/src/utils/location';
import useForm, { type UseFormOnSubmitHandler } from '@jwp/ott-hooks-react/src/useForm';
import { logDebug, logError } from '@jwp/ott-common/src/logger';
import env from '@jwp/ott-common/src/env';

import ResetPasswordForm from '../../../components/ResetPasswordForm/ResetPasswordForm';
import ForgotPasswordForm from '../../../components/ForgotPasswordForm/ForgotPasswordForm';
Expand Down Expand Up @@ -54,7 +55,7 @@ const ResetPassword: React.FC<Prop> = ({ type }: Prop) => {
};

const resetPasswordClickHandler = async () => {
const resetUrl = `${window.location.origin}/?u=edit-password`;
const resetUrl = `${env.APP_PUBLIC_URL}/?u=edit-password`;
try {
if (!user?.email) {
logDebug('ResetPassword', 'invalid param email');
Expand All @@ -73,7 +74,7 @@ const ResetPassword: React.FC<Prop> = ({ type }: Prop) => {
};

const emailSubmitHandler: UseFormOnSubmitHandler<ForgotPasswordFormData> = async (formData, { setErrors, setSubmitting }) => {
const resetUrl = `${window.location.origin}/?u=edit-password`;
const resetUrl = `${env.APP_PUBLIC_URL}/?u=edit-password`;

try {
await accountController.resetPassword(formData.email, resetUrl);
Expand Down
3 changes: 2 additions & 1 deletion packages/ui-react/src/pages/LegacySeries/LegacySeries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import useBreakpoint, { Breakpoint } from '@jwp/ott-ui-react/src/hooks/useBreakp
import useQueryParam from '@jwp/ott-ui-react/src/hooks/useQueryParam';
import usePlaylist from '@jwp/ott-hooks-react/src/usePlaylist';
import PlayTrailer from '@jwp/ott-theme/assets/icons/play_trailer.svg?react';
import env from '@jwp/ott-common/src/env';

import VideoLayout from '../../components/VideoLayout/VideoLayout';
import InlinePlayer from '../../containers/InlinePlayer/InlinePlayer';
Expand Down Expand Up @@ -114,7 +115,7 @@ const LegacySeries = () => {

const pageTitle = `${selectedItem.title} - ${siteName}`;
const pageDescription = selectedItem?.description || '';
const canonicalUrl = `${window.location.origin}${legacySeriesURL({ episodeId: episode?.mediaid, seriesId })}`;
const canonicalUrl = `${env.APP_PUBLIC_URL}${legacySeriesURL({ episodeId: episode?.mediaid, seriesId })}`;
const backgroundImage = (selectedItem.backgroundImage as string) || undefined;

const primaryMetadata = episode ? (
Expand Down
5 changes: 3 additions & 2 deletions packages/ui-react/src/pages/LegacySeries/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Playlist, PlaylistItem } from '@jwp/ott-common/types/playlist';
import type { EpisodeMetadata } from '@jwp/ott-common/types/series';
import { legacySeriesURL } from '@jwp/ott-common/src/utils/urlFormatting';
import { secondsToISO8601 } from '@jwp/ott-common/src/utils/datetime';
import env from '@jwp/ott-common/src/env';

/**
* Get an array of options for a season filter
Expand Down Expand Up @@ -57,7 +58,7 @@ export const getEpisodesInSeason = (episode: PlaylistItem | undefined, seriesPla

export const generateLegacySeriesMetadata = (seriesPlaylist: Playlist, seriesId: string | undefined) => {
// Use playlist for old flow and media id for a new flow
const seriesCanonical = `${window.location.origin}/s/${seriesId}`;
const seriesCanonical = `${env.APP_PUBLIC_URL}/s/${seriesId}`;

return {
'@type': 'TVSeries',
Expand All @@ -78,7 +79,7 @@ export const generateLegacyEpisodeJSONLD = (
episodeMetadata: EpisodeMetadata | undefined,
seriesId: string,
) => {
const episodeCanonical = `${window.location.origin}${legacySeriesURL({ episodeId: episode?.mediaid, seriesId })}`;
const episodeCanonical = `${env.APP_PUBLIC_URL}${legacySeriesURL({ episodeId: episode?.mediaid, seriesId })}`;
const seriesMetadata = generateLegacySeriesMetadata(seriesPlaylist, seriesId);

if (!episode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import useEntitlement from '@jwp/ott-hooks-react/src/useEntitlement';
import useBreakpoint, { Breakpoint } from '@jwp/ott-ui-react/src/hooks/useBreakpoint';
import PlayTrailer from '@jwp/ott-theme/assets/icons/play_trailer.svg?react';
import useQueryParam from '@jwp/ott-ui-react/src/hooks/useQueryParam';
import env from '@jwp/ott-common/src/env';

import type { ScreenComponent } from '../../../../../types/screens';
import VideoLayout from '../../../../components/VideoLayout/VideoLayout';
Expand Down Expand Up @@ -90,7 +91,7 @@ const MediaEvent: ScreenComponent<PlaylistItem> = ({ data: media, isLoading }) =
// UI
const { title, mediaid } = media;
const pageTitle = `${title} - ${siteName}`;
const canonicalUrl = media ? `${window.location.origin}${mediaURL({ id: mediaid, title })}` : window.location.href;
const canonicalUrl = media ? `${env.APP_PUBLIC_URL}${mediaURL({ id: mediaid, title })}` : window.location.href;

const primaryMetadata = (
<>
Expand Down Expand Up @@ -149,7 +150,7 @@ const MediaEvent: ScreenComponent<PlaylistItem> = ({ data: media, isLoading }) =
{media.tags?.split(',').map((tag) => (
<meta property="og:video:tag" content={tag} key={tag} />
))}
{media ? <script type="application/ld+json">{generateMovieJSONLD(media, window.location.origin)}</script> : null}
{media ? <script type="application/ld+json">{generateMovieJSONLD(media, env.APP_PUBLIC_URL)}</script> : null}
</Helmet>
<VideoLayout
item={media}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import useEntitlement from '@jwp/ott-hooks-react/src/useEntitlement';
import useBreakpoint, { Breakpoint } from '@jwp/ott-ui-react/src/hooks/useBreakpoint';
import PlayTrailer from '@jwp/ott-theme/assets/icons/play_trailer.svg?react';
import useQueryParam from '@jwp/ott-ui-react/src/hooks/useQueryParam';
import env from '@jwp/ott-common/src/env';

import type { ScreenComponent } from '../../../../../types/screens';
import VideoLayout from '../../../../components/VideoLayout/VideoLayout';
Expand Down Expand Up @@ -78,7 +79,7 @@ const MediaMovie: ScreenComponent<PlaylistItem> = ({ data, isLoading }) => {

// UI
const pageTitle = `${data.title} - ${siteName}`;
const canonicalUrl = data ? `${window.location.origin}${mediaURL({ id: data.mediaid, title: data.title })}` : window.location.href;
const canonicalUrl = data ? `${env.APP_PUBLIC_URL}${mediaURL({ id: data.mediaid, title: data.title })}` : window.location.href;

const primaryMetadata = <VideoMetaData attributes={createVideoMetadata(data)} />;
const shareButton = <ShareButton title={data.title} description={data.description} url={canonicalUrl} />;
Expand Down Expand Up @@ -130,7 +131,7 @@ const MediaMovie: ScreenComponent<PlaylistItem> = ({ data, isLoading }) => {
{data.tags?.split(',').map((tag) => (
<meta property="og:video:tag" content={tag} key={tag} />
))}
{data ? <script type="application/ld+json">{generateMovieJSONLD(data, window.location.origin)}</script> : null}
{data ? <script type="application/ld+json">{generateMovieJSONLD(data, env.APP_PUBLIC_URL)}</script> : null}
</Helmet>
<VideoLayout
item={data}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { useNextEpisode } from '@jwp/ott-hooks-react/src/series/useNextEpisode';
import PlayTrailer from '@jwp/ott-theme/assets/icons/play_trailer.svg?react';
import useBreakpoint, { Breakpoint } from '@jwp/ott-ui-react/src/hooks/useBreakpoint';
import { useFirstEpisode } from '@jwp/ott-hooks-react/src/series/useFirstEpisode';
import env from '@jwp/ott-common/src/env';

import type { ScreenComponent } from '../../../../../types/screens';
import ErrorPage from '../../../../components/ErrorPage/ErrorPage';
Expand Down Expand Up @@ -193,7 +194,7 @@ const MediaSeries: ScreenComponent<PlaylistItem> = ({ data: seriesMedia }) => {
if (!seriesMedia || !series || !playEpisode) return <ErrorPage title={t('series_error')} />;

const pageTitle = `${selectedItem.title} - ${siteName}`;
const canonicalUrl = `${window.location.origin}${mediaURL({ id: seriesMedia.mediaid, title: seriesMedia.title, episodeId: episode?.mediaid })}`;
const canonicalUrl = `${env.APP_PUBLIC_URL}${mediaURL({ id: seriesMedia.mediaid, title: seriesMedia.title, episodeId: episode?.mediaid })}`;

const primaryMetadata = <VideoMetaData attributes={createVideoMetadata(selectedItem, t('video:total_episodes', { count: series.episode_count }))} />;
const secondaryMetadata = episodeMetadata && episode && (
Expand Down Expand Up @@ -245,7 +246,7 @@ const MediaSeries: ScreenComponent<PlaylistItem> = ({ data: seriesMedia }) => {
<meta property="og:video:tag" content={tag} key={tag} />
))}
{selectedItem ? (
<script type="application/ld+json">{generateEpisodeJSONLD(series, seriesMedia, window.location.origin, episode, episodeMetadata)}</script>
<script type="application/ld+json">{generateEpisodeJSONLD(series, seriesMedia, env.APP_PUBLIC_URL, episode, episodeMetadata)}</script>
) : null}
</Helmet>
<VideoLayout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { shallow } from '@jwp/ott-common/src/utils/compare';
import type { PlaylistItem } from '@jwp/ott-common/types/playlist';
import { useConfigStore } from '@jwp/ott-common/src/stores/ConfigStore';
import { mediaURL } from '@jwp/ott-common/src/utils/urlFormatting';
import env from '@jwp/ott-common/src/env';

import type { ScreenComponent } from '../../../../../types/screens';
import MarkdownComponent from '../../../../components/MarkdownComponent/MarkdownComponent';
Expand All @@ -14,7 +15,7 @@ const MediaStaticPage: ScreenComponent<PlaylistItem> = ({ data }) => {
const { config } = useConfigStore(({ config }) => ({ config }), shallow);
const { siteName } = config;
const pageTitle = `${data.title} - ${siteName}`;
const canonicalUrl = data ? `${window.location.origin}${mediaURL({ id: data.mediaid, title: data.title })}` : window.location.href;
const canonicalUrl = data ? `${env.APP_PUBLIC_URL}${mediaURL({ id: data.mediaid, title: data.title })}` : window.location.href;

useEffect(() => {
(document.scrollingElement || document.body).scroll({ top: 0 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import useLiveChannels from '@jwp/ott-hooks-react/src/useLiveChannels';
import useEntitlement from '@jwp/ott-hooks-react/src/useEntitlement';
import useLiveProgram from '@jwp/ott-hooks-react/src/useLiveProgram';
import Play from '@jwp/ott-theme/assets/icons/play.svg?react';
import env from '@jwp/ott-common/src/env';

import type { ScreenComponent } from '../../../../../types/screens';
import Epg from '../../../../components/Epg/Epg';
Expand Down Expand Up @@ -127,7 +128,7 @@ const PlaylistLiveChannels: ScreenComponent<Playlist> = ({ data: { feedid, playl

// SEO (for channels)
// const getUrl = (id: string) => liveChannelsURL(feedid, id);
const canonicalUrl = `${window.location.origin}${liveChannelsURL(feedid, channel.id)}`;
const canonicalUrl = `${env.APP_PUBLIC_URL}${liveChannelsURL(feedid, channel.id)}`;
const pageTitle = `${channel.title} - ${siteName}`;

const shareButton = channelMediaItem ? (
Expand Down Expand Up @@ -187,7 +188,7 @@ const PlaylistLiveChannels: ScreenComponent<Playlist> = ({ data: { feedid, playl
{channelMediaItem?.tags?.split(',').map((tag) => (
<meta property="og:video:tag" content={tag} key={tag} />
))}
{channelMediaItem ? <script type="application/ld+json">{generateMovieJSONLD(channelMediaItem, window.location.origin)}</script> : null}
{channelMediaItem ? <script type="application/ld+json">{generateMovieJSONLD(channelMediaItem, env.APP_PUBLIC_URL)}</script> : null}
</Helmet>
<VideoDetails
title={videoDetails.title}
Expand Down
3 changes: 3 additions & 0 deletions platforms/web/.env
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ APP_FOOTER_TEXT="\u00a9 JW Player | [jwplayer.com](https://www.jwplayer.com/) |
#APP_BODY_FONT_FAMILY
#APP_BODY_ALT_FONT_FAMILY

# public URL must be set for standalone applications
#APP_PUBLIC_URL

# the default language that the app should load when the language couldn't be detected
APP_DEFAULT_LANGUAGE=en

Expand Down
1 change: 1 addition & 0 deletions platforms/web/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ configureEnv({
APP_FOOTER_TEXT: import.meta.env.APP_FOOTER_TEXT,
APP_BODY_FONT: import.meta.env.APP_BODY_FONT,
APP_BODY_ALT_FONT: import.meta.env.APP_BODY_ALT_FONT,
APP_PUBLIC_URL: import.meta.env.APP_PUBLIC_URL || window.location.origin,
});

attachAccessibilityListener();
Expand Down
Loading