diff --git a/materialious/src/lib/api/model.ts b/materialious/src/lib/api/model.ts index 906215f6..30e0fe3a 100644 --- a/materialious/src/lib/api/model.ts +++ b/materialious/src/lib/api/model.ts @@ -176,6 +176,7 @@ export interface Comments { videoId: string; continuation?: string; comments: Comment[]; + getContinuation?: () => Promise; } export interface Channel { diff --git a/materialious/src/lib/api/youtubejs/comments.ts b/materialious/src/lib/api/youtubejs/comments.ts index 895cac97..2b5d0ba4 100644 --- a/materialious/src/lib/api/youtubejs/comments.ts +++ b/materialious/src/lib/api/youtubejs/comments.ts @@ -1,9 +1,9 @@ import { extractNumber } from '$lib/numbers'; -import { YTNodes } from 'youtubei.js'; +import { YT, YTNodes } from 'youtubei.js'; import { getInnertube } from '.'; import type { Comment, Comments, CommentsOptions, Thumbnail } from '../model'; -function invidiousSchema(result: YTNodes.CommentView): Comment | undefined { +function invidiousCommentContentSchema(result: YTNodes.CommentView): Comment | undefined { if (!result.author) return; return { @@ -15,7 +15,7 @@ function invidiousSchema(result: YTNodes.CommentView): Comment | undefined { isPinned: result.is_pinned === true, content: result.content?.text ?? '', contentHtml: result.content?.toHTML() ?? '', - published: 0, // Placeholder, adjust accordingly + published: 0, publishedText: result.published_time ?? '', likeCount: extractNumber(result.like_count ?? '0'), authorIsChannelOwner: result.author_is_channel_owner === true, @@ -30,6 +30,37 @@ function invidiousSchema(result: YTNodes.CommentView): Comment | undefined { }; } +function invidiousCommentSchema(innerResults: YT.Comments, videoId: string) { + const comment: Comment[] = []; + + innerResults.contents.forEach(async (result) => { + if (result.comment) { + const invidiousResult = invidiousCommentContentSchema(result.comment); + if (invidiousResult) { + if (result.has_replies) + invidiousResult.getReplies = async (): Promise => { + const replies = await result.getReplies(); + if (!replies.replies) return { videoId: '', comments: [], commentCount: 0 }; + + const comments: Comment[] = replies.replies + .map((reply) => invidiousCommentContentSchema(reply)) + .filter((comment): comment is Comment => !!comment); + + return { + videoId: videoId, + comments: comments, + commentCount: 0 + }; + }; + + comment.push(invidiousResult); + } + } + }); + + return comment; +} + export async function getCommentsYTjs( videoId: string, options: CommentsOptions @@ -41,36 +72,23 @@ export async function getCommentsYTjs( options.sort_by === 'top' ? 'TOP_COMMENTS' : 'NEWEST_FIRST' ); - const comments: Comment[] = []; - - innerResults.contents.forEach(async (result) => { - if (result.comment) { - const invidiousResult = invidiousSchema(result.comment); - if (invidiousResult) { - if (result.has_replies) - invidiousResult.getReplies = async (): Promise => { - const replies = await result.getReplies(); - if (!replies.replies) return { videoId: '', comments: [], commentCount: 0 }; - - const comments: Comment[] = replies.replies - .map((reply) => invidiousSchema(reply)) - .filter((comment): comment is Comment => !!comment); - - return { - videoId: '', - comments: comments, - commentCount: 0 - }; - }; - - comments.push(invidiousResult); - } - } - }); - - return { + const comments: Comments = { videoId: videoId, - comments: comments, - commentCount: extractNumber(innerResults.header?.comments_count.text ?? '0') + comments: invidiousCommentSchema(innerResults, videoId), + commentCount: extractNumber(innerResults.header?.comments_count.text ?? '0'), + continuation: innerResults.has_continuation ? 'logicalPlaceholder' : undefined }; + + if (comments.continuation) { + comments.getContinuation = async () => { + return { + videoId: videoId, + comments: invidiousCommentSchema(await innerResults.getContinuation(), videoId), + commentCount: extractNumber(innerResults.header?.comments_count.text ?? '0'), + continuation: innerResults.has_continuation ? 'logicalPlaceholder' : undefined + }; + }; + } + + return comments; } diff --git a/materialious/src/routes/(app)/watch/[slug]/+page.svelte b/materialious/src/routes/(app)/watch/[slug]/+page.svelte index 8a417f55..0935f112 100644 --- a/materialious/src/routes/(app)/watch/[slug]/+page.svelte +++ b/materialious/src/routes/(app)/watch/[slug]/+page.svelte @@ -348,12 +348,16 @@ return; } - const loadedComments = await getComments(data.video.videoId, { - continuation: comments?.continuation - }); + let loadedComments: Comments; + if (comments.getContinuation) { + loadedComments = await comments.getContinuation(); + } else { + loadedComments = await getComments(data.video.videoId, { + continuation: comments?.continuation + }); + } comments.continuation = loadedComments.continuation; - comments.comments = [...comments.comments, ...loadedComments.comments]; }