Improved comment parsing
This commit is contained in:
@@ -252,7 +252,7 @@ export async function getFeed(
|
||||
fetchOptions: RequestInit = {}
|
||||
): Promise<Feed> {
|
||||
if (isYTBackend()) {
|
||||
return getFeedYTjs(maxResults, page);
|
||||
return getFeedYTjs();
|
||||
}
|
||||
|
||||
const path = buildPath('auth/feed');
|
||||
|
||||
@@ -128,9 +128,7 @@ export async function parseChannelRSS(channelId: string): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
// 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<Feed> {
|
||||
export async function getFeedYTjs(): Promise<Feed> {
|
||||
const channelSubscriptions = await localDb.channelSubscriptions.toArray();
|
||||
|
||||
const toUpdatePromises: Promise<void>[] = [];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 href="([^"]+)" data-onclick="jump_to_time" data-jump-time="(\d+)">([^<]+)<\/a>\s*(.+)/g;
|
||||
const replacement = `<a href=${resolve(`/watch/[videoId]?time=$2`, { videoId: videoId })} data-sveltekit-preload-data="off" class="link">$3 $4</a>`;
|
||||
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 @@
|
||||
</a>
|
||||
<p class="no-margin">
|
||||
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
||||
{@html commentTimestamps(comment.contentHtml)}
|
||||
{@html parseComment(comment.contentHtml)}
|
||||
<!-- Comment comes directly from YT so is already sanitized -->
|
||||
</p>
|
||||
<div class="comment-actions">
|
||||
|
||||
@@ -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[] = [];
|
||||
|
||||
@@ -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<string[]> = writable([]);
|
||||
|
||||
export interface PlayerState {
|
||||
data: { video: VideoPlay; content: PhasedDescription; playlistId: string | null };
|
||||
data: { video: VideoPlay; content: parsedDescription; playlistId: string | null };
|
||||
playerElement?: HTMLMediaElement | undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user