diff --git a/materialious/src/lib/api/index.ts b/materialious/src/lib/api/index.ts index b60b9481..bc920a6c 100644 --- a/materialious/src/lib/api/index.ts +++ b/materialious/src/lib/api/index.ts @@ -252,7 +252,7 @@ export async function getFeed( fetchOptions: RequestInit = {} ): Promise { if (isYTBackend()) { - return getFeedYTjs(maxResults, page); + return getFeedYTjs(); } const path = buildPath('auth/feed'); diff --git a/materialious/src/lib/api/youtubejs/subscriptions.ts b/materialious/src/lib/api/youtubejs/subscriptions.ts index 66d513ed..ffb1f783 100644 --- a/materialious/src/lib/api/youtubejs/subscriptions.ts +++ b/materialious/src/lib/api/youtubejs/subscriptions.ts @@ -128,9 +128,7 @@ export async function parseChannelRSS(channelId: string): Promise { } } -// Ignored to match non ytjs version of getfeed. -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export async function getFeedYTjs(maxResults: number, page: number): Promise { +export async function getFeedYTjs(): Promise { const channelSubscriptions = await localDb.channelSubscriptions.toArray(); const toUpdatePromises: Promise[] = []; diff --git a/materialious/src/lib/components/Player.svelte b/materialious/src/lib/components/Player.svelte index 5293bf73..c4e0b638 100644 --- a/materialious/src/lib/components/Player.svelte +++ b/materialious/src/lib/components/Player.svelte @@ -2,7 +2,7 @@ import { page } from '$app/stores'; import { getBestThumbnail, ImageCache } from '$lib/images'; import { videoLength } from '$lib/numbers'; - import { generateChapterWebVTT, type PhasedDescription, type Timestamp } from '$lib/description'; + import { generateChapterWebVTT, type parsedDescription, type Timestamp } from '$lib/description'; import { SystemBars, SystemBarsStyle, SystemBarType } from '@capacitor/core'; import { Capacitor } from '@capacitor/core'; import { ScreenOrientation, type ScreenOrientationResult } from '@capacitor/screen-orientation'; @@ -67,7 +67,7 @@ } from '$lib/timelineThumbnails'; interface Props { - data: { video: VideoPlay; content: PhasedDescription; playlistId: string | null }; + data: { video: VideoPlay; content: parsedDescription; playlistId: string | null }; currentTime?: number; userManualSeeking?: boolean; isEmbed?: boolean; diff --git a/materialious/src/lib/components/watch/Comment.svelte b/materialious/src/lib/components/watch/Comment.svelte index 332f3645..cc3081ac 100644 --- a/materialious/src/lib/components/watch/Comment.svelte +++ b/materialious/src/lib/components/watch/Comment.svelte @@ -9,6 +9,7 @@ import CommentSelf from './Comment.svelte'; import { insecureRequestImageHandler, truncate } from '$lib/misc'; import { _ } from '$lib/i18n'; + import { extractActualLink } from '$lib/description'; interface Props { comment: Comment; @@ -36,15 +37,39 @@ } } } + function parseComment(html: string): string { + console.log(html); + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); - function commentTimestamps(html: string): string { - const regex = - /([^<]+)<\/a>\s*(.+)/g; - const replacement = `$3 $4`; + const links = doc.querySelectorAll('a'); - const processedHtml = html.replace(regex, replacement); + links.forEach((link) => { + const href = link.getAttribute('href'); + if (!href) return; - return processedHtml; + const realHref = extractActualLink(href); + const dataOnClick = link.getAttribute('data-onclick'); + + link.classList.add('link'); + + if (dataOnClick === 'jump_to_time' || (realHref && realHref.includes('t='))) { + const match = realHref?.match(/t=(\d+)/); + const timestamp = match ? match[1] : ''; + + const newHref = resolve(`/watch/[videoId]?time=${timestamp}`, { videoId }); + + link.setAttribute('href', newHref); + link.removeAttribute('data-onclick'); + link.setAttribute('data-sveltekit-preload-data', 'off'); + } else { + link.setAttribute('href', realHref); + link.setAttribute('target', '_blank'); + link.setAttribute('referrerpolicy', 'no-referrer'); + } + }); + + return doc.documentElement.outerHTML; } let userPfp = $state(''); @@ -77,7 +102,7 @@

- {@html commentTimestamps(comment.contentHtml)} + {@html parseComment(comment.contentHtml)}

diff --git a/materialious/src/lib/description.ts b/materialious/src/lib/description.ts index c49beac2..7c3b392d 100644 --- a/materialious/src/lib/description.ts +++ b/materialious/src/lib/description.ts @@ -5,7 +5,7 @@ import { convertToSeconds, padTime } from './time'; export type Timestamp = { title: string; time: number; timePretty: string; endTime: number }; export type Timestamps = Timestamp[]; -export interface PhasedDescription { +export interface parsedDescription { description: string; timestamps: Timestamps; } @@ -41,11 +41,11 @@ function cleanTimestampTitle(title: string): string { return title.replace(/^[\s\-•|:/\\*#>~]+/, '').trim(); } -export function phaseDescription( +export function parseDescription( videoId: string, content: string, fallbackPatch?: 'youtubejs' | 'piped' -): PhasedDescription { +): parsedDescription { const timestamps: Timestamps = []; const lines = content.split('\n'); const filteredLines: string[] = []; diff --git a/materialious/src/lib/store.ts b/materialious/src/lib/store.ts index f63772eb..36fced3d 100644 --- a/materialious/src/lib/store.ts +++ b/materialious/src/lib/store.ts @@ -21,7 +21,7 @@ import type { VideoBase, VideoPlay } from './api/model'; -import type { PhasedDescription } from './description'; +import type { parsedDescription } from './description'; import { ensureNoTrailingSlash } from './misc'; import type { EngineFallback } from './api/misc'; @@ -182,7 +182,7 @@ export const playerAndroidPauseOnNetworkChange = persist( export const playerPlaylistHistory: Writable = writable([]); export interface PlayerState { - data: { video: VideoPlay; content: PhasedDescription; playlistId: string | null }; + data: { video: VideoPlay; content: parsedDescription; playlistId: string | null }; playerElement?: HTMLMediaElement | undefined; } diff --git a/materialious/src/lib/watch.ts b/materialious/src/lib/watch.ts index 95a61285..661614ac 100644 --- a/materialious/src/lib/watch.ts +++ b/materialious/src/lib/watch.ts @@ -13,7 +13,7 @@ import { returnYTDislikesInstanceStore, returnYtDislikesStore } from '$lib/store'; -import { phaseDescription } from '$lib/description'; +import { parseDescription } from '$lib/description'; import { error } from '@sveltejs/kit'; import { get } from 'svelte/store'; import { _ } from './i18n'; @@ -71,7 +71,7 @@ export async function getWatchDetails(videoId: string, url: URL) { return { video: video, - content: phaseDescription(video.videoId, video.descriptionHtml, video.fallbackPatch), + content: parseDescription(video.videoId, video.descriptionHtml, video.fallbackPatch), playlistId: playlistId, streamed: { personalPlaylists: personalPlaylists,