From 7ad4552c68e30bb701927827a316ad7d9d8a9c5e Mon Sep 17 00:00:00 2001 From: WardPearce Date: Tue, 22 Oct 2024 21:10:27 +1300 Subject: [PATCH] Added support for chapters on youtubejs fallback --- materialious/src/lib/misc.ts | 21 +++++++++++-------- .../src/routes/(app)/watch/[slug]/+page.ts | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/materialious/src/lib/misc.ts b/materialious/src/lib/misc.ts index c1aecfe0..b890e6f9 100644 --- a/materialious/src/lib/misc.ts +++ b/materialious/src/lib/misc.ts @@ -103,18 +103,20 @@ export function decodeHtmlCharCodes(str: string): string { return decode(str); } -export function phaseDescription(content: string): PhasedDescription { +export function phaseDescription(content: string, usingYoutubeJs: boolean = false): PhasedDescription { const timestamps: { title: string; time: number; timePretty: string; }[] = []; const lines = content.split('\n'); + // Regular expressions for different timestamp formats const urlRegex = /(\d+:\d+(?::\d+)?)<\/a>\s*(.+)/; + const timestampRegexInvidious = /(\d+:\d+(?::\d+)?)<\/a>\s*(.+)/; + const timestampRegexYtJs = /&t=(\d+)\s*s.*?]*>([^<]*)<\/span>.*?>(.*?)<\/span>/; let filteredLines: string[] = []; lines.forEach((line) => { const urlMatch = urlRegex.exec(line); - const timestampMatch = timestampRegex.exec(line); + // Use appropriate regex based on the `usingYoutubeJs` flag + const timestampMatch = (usingYoutubeJs ? timestampRegexYtJs : timestampRegexInvidious).exec(usingYoutubeJs ? line + '' : line); if (urlMatch !== null && timestampMatch === null) { // If line contains a URL but not a timestamp, modify the URL @@ -125,13 +127,13 @@ export function phaseDescription(content: string): PhasedDescription { filteredLines.push(modifiedLine); } else if (timestampMatch !== null) { // If line contains a timestamp, extract details and push into timestamps array - const time = timestampMatch[2]; - const timestamp = timestampMatch[3]; - const title = timestampMatch[4] || ''; + const time = usingYoutubeJs ? timestampMatch[1] : timestampMatch[2]; + const timestamp = usingYoutubeJs ? timestampMatch[2] : timestampMatch[3]; + const title = usingYoutubeJs ? timestampMatch[3] || '' : timestampMatch[4] || ''; timestamps.push({ time: convertToSeconds(time), - // Remove any URL in the timestamp title. - title: decodeHtmlCharCodes(title.replace(/]*>(.*?)<\/a>/gi, '')), + // Remove any HTML in the timestamp title. + title: decodeHtmlCharCodes(title.replace(/<[^>]+>/g, '').replace(/\n/g, '').trim()), timePretty: timestamp }); } else { @@ -144,6 +146,7 @@ export function phaseDescription(content: string): PhasedDescription { return { description: filteredContent, timestamps: timestamps }; } + function convertToSeconds(time: string): number { const parts = time.split(':').map((part) => parseInt(part)); let seconds = 0; diff --git a/materialious/src/routes/(app)/watch/[slug]/+page.ts b/materialious/src/routes/(app)/watch/[slug]/+page.ts index 900e22e7..4d7c58c9 100644 --- a/materialious/src/routes/(app)/watch/[slug]/+page.ts +++ b/materialious/src/routes/(app)/watch/[slug]/+page.ts @@ -62,7 +62,7 @@ export async function load({ params, url }) { return { video: video, - content: phaseDescription(video.descriptionHtml), + content: phaseDescription(video.descriptionHtml, video.fallbackPatch === 'youtubejs'), playlistId: url.searchParams.get('playlist'), streamed: { personalPlaylists: personalPlaylists,