Add new slug property for videos.

These will in the future hold pre-generated slugs since some runs can have the
same title and slugs are generated based on those titles.

This also implements a default for when no slugs are set (as is the case for all
videos right now) where the slug is still generated based on the title but a
counter suffix is added for dupe titles.
master
Icedream 2021-07-09 10:59:46 +02:00
parent 5781966b91
commit 40cbd2ed6e
Signed by: icedream
GPG Key ID: 1573F6D8EFE4D0CF
5 changed files with 31 additions and 7 deletions

View File

@ -89,6 +89,7 @@ class VideoList extends React.Component<VideoListProps, VideoListState> {
duration, duration,
fileName, fileName,
title, title,
slug,
sourceVideoStart, sourceVideoStart,
sourceVideoEnd, sourceVideoEnd,
}, },
@ -100,6 +101,7 @@ class VideoList extends React.Component<VideoListProps, VideoListState> {
id={id} id={id}
thumbnailServerURL={thumbnailServerURL} thumbnailServerURL={thumbnailServerURL}
fileName={fileName} fileName={fileName}
slug={slug}
title={title} title={title}
sourceVideoStart={sourceVideoStart} sourceVideoStart={sourceVideoStart}
sourceVideoEnd={sourceVideoEnd} sourceVideoEnd={sourceVideoEnd}

View File

@ -39,6 +39,7 @@ export default function VideoListItem({
duration, duration,
id, id,
fileName, fileName,
slug,
title, title,
sourceVideoStart, sourceVideoStart,
sourceVideoEnd, sourceVideoEnd,
@ -47,6 +48,7 @@ export default function VideoListItem({
duration: number | string, duration: number | string,
id: string, id: string,
fileName: string, fileName: string,
slug: string,
title: string, title: string,
sourceVideoStart: number | string, sourceVideoStart: number | string,
sourceVideoEnd: number | string, sourceVideoEnd: number | string,
@ -77,7 +79,6 @@ export default function VideoListItem({
} }
displayDuration = videoEnd - videoStart; displayDuration = videoEnd - videoStart;
} }
const titleUrlSlug = sanitizeTitle(title);
const listGroupItem = ( const listGroupItem = (
<ListGroup.Item action> <ListGroup.Item action>
<Media> <Media>
@ -131,7 +132,7 @@ export default function VideoListItem({
); );
if (fileName) { if (fileName) {
return ( return (
<Link passHref href="/[id]/[vslug]" as={`/${id}/${titleUrlSlug}`}> <Link passHref href="/[id]/[vslug]" as={`/${id}/${slug}`}>
{listGroupItem} {listGroupItem}
</Link> </Link>
); );

View File

@ -115,7 +115,7 @@ const getProps = withSession(async (req, _res, { id, vslug }: VideoPlayerPagePar
redirect: true, redirect: true,
id, id,
video, video,
vslug: sanitizeTitle(video.title), vslug: video.slug,
}, },
}; };
} }
@ -132,13 +132,13 @@ const getProps = withSession(async (req, _res, { id, vslug }: VideoPlayerPagePar
redirect: true, redirect: true,
id, id,
video: realVIndex, video: realVIndex,
vslug: sanitizeTitle(video.title), vslug: video.slug,
}, },
}; };
} }
// Check if we can find any video with matching vslug // Check if we can find any video with matching vslug
const video = videos.find(({ title }: { title: string }) => sanitizeTitle(title) === vslug); const video = videos.find(({ slug }: VideoEntry) => slug === vslug);
if (!video) { if (!video) {
return { props: {} }; return { props: {} };
} }

View File

@ -15,8 +15,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { VideoList } from './datatypes/VideoList'; import { VideoEntry, VideoList } from './datatypes/VideoList';
import { VideoOnDemandIndex } from './datatypes/VideoOnDemandIdentifier'; import { VideoOnDemandIndex } from './datatypes/VideoOnDemandIdentifier';
import sanitizeTitle from './sanitizeTitle';
const upstreamURL = process.env.UPSTREAM_URL; const upstreamURL = process.env.UPSTREAM_URL;
const upstreamDirectURL = process.env.UPSTREAM_DIRECT_URL || upstreamURL; const upstreamDirectURL = process.env.UPSTREAM_DIRECT_URL || upstreamURL;
@ -73,7 +74,26 @@ export async function getIndex(): Promise<VideoOnDemandIndex> {
} }
export async function getVideos(id: string): Promise<VideoList> { export async function getVideos(id: string): Promise<VideoList> {
return getDirect(`videos/${id}.json`); const result: VideoList = await getDirect(`videos/${id}.json`);
result.videos = result.videos.reduce((all: Array<VideoEntry>, {
slug,
title,
...video
}: VideoEntry) => [
...all,
{
...video,
title,
slug: typeof slug === 'string'
? slug
: sanitizeTitle(title + (
all.find(v => v.title === title)
? ` ${all.filter(v => v.title === title).length + 1}`
: ''
)),
},
], [])
return result;
} }
export function getDownloadURL(id: string, fileName: string): string { export function getDownloadURL(id: string, fileName: string): string {

View File

@ -19,6 +19,7 @@ export interface VideoEntry {
fileName:string fileName:string
title: string title: string
duration?: number | string, duration?: number | string,
slug: string,
sourceVideoURL: string sourceVideoURL: string
sourceVideoStart: number | string sourceVideoStart: number | string
sourceVideoEnd: number | string sourceVideoEnd: number | string