feat(parser): Support CommentView nodes (#614)

This commit is contained in:
absidue
2024-03-25 11:20:29 +01:00
committed by GitHub
parent 7ca2a0c3e4
commit 900f557202
5 changed files with 147 additions and 10 deletions

View File

@@ -2,6 +2,7 @@ import { Parser } from '../../index.js';
import Button from '../Button.js';
import ContinuationItem from '../ContinuationItem.js';
import Comment from './Comment.js';
import CommentView from './CommentView.js';
import CommentReplies from './CommentReplies.js';
import { InnertubeError } from '../../../utils/Utils.js';
@@ -17,15 +18,20 @@ export default class CommentThread extends YTNode {
#actions?: Actions;
#continuation?: ContinuationItem;
comment: Comment | null;
replies?: ObservedArray<Comment>;
comment: Comment | CommentView | null;
replies?: ObservedArray<Comment | CommentView>;
comment_replies_data: CommentReplies | null;
is_moderated_elq_comment: boolean;
has_replies: boolean;
constructor(data: RawNode) {
super();
this.comment = Parser.parseItem(data.comment, Comment);
if (Reflect.has(data, 'commentViewModel')) {
this.comment = Parser.parseItem(data.commentViewModel, CommentView);
} else {
this.comment = Parser.parseItem(data.comment, Comment);
}
this.comment_replies_data = Parser.parseItem(data.replies, CommentReplies);
this.is_moderated_elq_comment = data.isModeratedElqComment;
this.has_replies = !!this.comment_replies_data;
@@ -51,7 +57,7 @@ export default class CommentThread extends YTNode {
if (!response.on_response_received_endpoints_memo)
throw new InnertubeError('Unexpected response.', response);
this.replies = observe(response.on_response_received_endpoints_memo.getType(Comment).map((comment) => {
this.replies = observe(response.on_response_received_endpoints_memo.getType(Comment, CommentView).map((comment) => {
comment.setActions(this.#actions);
return comment;
}));

View File

@@ -0,0 +1,88 @@
import { YTNode } from '../../helpers.js';
import type { RawNode } from '../../index.js';
import type Actions from '../../../core/Actions.js';
import Author from '../misc/Author.js';
import Text from '../misc/Text.js';
export default class CommentView extends YTNode {
static type = 'CommentView';
#actions?: Actions;
comment_id: string;
is_pinned: boolean;
keys: {
comment: string;
comment_surface: string;
toolbar_state: string;
toolbar_surface: string;
shared: string;
};
content?: Text;
published_time?: string;
author_is_channel_owner?: boolean;
like_count?: string;
reply_count?: string;
is_member?: boolean;
member_badge?: {
url: string,
a11y: string;
};
author?: Author;
is_liked?: boolean;
is_disliked?: boolean;
is_hearted?: boolean;
constructor(data: RawNode) {
super();
this.comment_id = data.commentId;
this.is_pinned = !!data.pinnedText;
this.keys = {
comment: data.commentKey,
comment_surface: data.commentSurfaceKey,
toolbar_state: data.toolbarStateKey,
toolbar_surface: data.toolbarSurfaceKey,
shared: data.sharedKey
};
}
applyMutations(comment?: RawNode, toolbar_state?: RawNode) {
if (comment) {
this.content = Text.fromAttributed(comment.properties.content);
this.published_time = comment.properties.publishedTime;
this.author_is_channel_owner = !!comment.author.isCreator;
this.like_count = comment.toolbar.likeCountNotliked ? comment.toolbar.likeCountNotliked : '0';
this.reply_count = comment.toolbar.replyCount ? comment.toolbar.replyCount : '0';
this.is_member = !!comment.author.sponsorBadgeUrl;
if (Reflect.has(comment.author, 'sponsorBadgeUrl')) {
this.member_badge = {
url: comment.author.sponsorBadgeUrl,
a11y: comment.author.A11y
};
}
this.author = new Author({
simpleText: comment.author.displayName,
navigationEndpoint: comment.avatar.endpoint
}, comment.author, comment.avatar.image, comment.author.channelId);
}
if (toolbar_state) {
this.is_hearted = toolbar_state.heartState === 'TOOLBAR_HEART_STATE_HEARTED';
this.is_liked = toolbar_state.likeState === 'TOOLBAR_LIKE_STATE_LIKED';
this.is_disliked = toolbar_state.likeState === 'TOOLBAR_HEART_STATE_DISLIKED';
}
}
setActions(actions: Actions | undefined) {
this.#actions = actions;
}
}

View File

@@ -25,10 +25,21 @@ export default class Author {
this.name = nav_text?.text || 'N/A';
this.thumbnails = thumbs ? Thumbnail.fromResponse(thumbs) : [];
this.endpoint = ((nav_text?.runs?.[0] as TextRun) as TextRun)?.endpoint || nav_text?.endpoint;
this.badges = Array.isArray(badges) ? Parser.parseArray(badges) : observe([] as YTNode[]);
this.is_moderator = this.badges?.some((badge: any) => badge.icon_type == 'MODERATOR');
this.is_verified = this.badges?.some((badge: any) => badge.style == 'BADGE_STYLE_TYPE_VERIFIED');
this.is_verified_artist = this.badges?.some((badge: any) => badge.style == 'BADGE_STYLE_TYPE_VERIFIED_ARTIST');
if (badges) {
if (Array.isArray(badges)) {
this.badges = Parser.parseArray(badges);
this.is_moderator = this.badges?.some((badge: any) => badge.icon_type == 'MODERATOR');
this.is_verified = this.badges?.some((badge: any) => badge.style == 'BADGE_STYLE_TYPE_VERIFIED');
this.is_verified_artist = this.badges?.some((badge: any) => badge.style == 'BADGE_STYLE_TYPE_VERIFIED_ARTIST');
} else {
this.badges = observe([] as YTNode[]);
this.is_verified = !!badges.isVerified;
this.is_verified_artist = !!badges.isArtist;
}
} else {
this.badges = observe([] as YTNode[]);
}
// @TODO: Refactor this mess.
this.url =