mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-15 10:32:14 +00:00
140 lines
3.6 KiB
TypeScript
140 lines
3.6 KiB
TypeScript
import type { RawNode } from '../../index.js';
|
|
import NavigationEndpoint from '../NavigationEndpoint.js';
|
|
import EmojiRun from './EmojiRun.js';
|
|
import TextRun from './TextRun.js';
|
|
|
|
export interface Run {
|
|
text: string;
|
|
toString(): string;
|
|
toHTML(): string;
|
|
}
|
|
|
|
export function escape(text: string) {
|
|
return text
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
|
|
export default class Text {
|
|
text?: string;
|
|
runs?: (EmojiRun | TextRun)[];
|
|
endpoint?: NavigationEndpoint;
|
|
|
|
constructor(data: RawNode) {
|
|
if (typeof data === 'object' && data !== null && Reflect.has(data, 'runs') && Array.isArray(data.runs)) {
|
|
this.runs = data.runs.map((run: RawNode) => run.emoji ?
|
|
new EmojiRun(run) :
|
|
new TextRun(run)
|
|
);
|
|
this.text = this.runs.map((run) => run.text).join('');
|
|
} else {
|
|
this.text = data?.simpleText;
|
|
}
|
|
if (typeof data === 'object' && data !== null && Reflect.has(data, 'navigationEndpoint')) {
|
|
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
|
}
|
|
if (typeof data === 'object' && data !== null && Reflect.has(data, 'titleNavigationEndpoint')) {
|
|
this.endpoint = new NavigationEndpoint(data.titleNavigationEndpoint);
|
|
}
|
|
if (!this.endpoint) {
|
|
if ((this.runs?.[0] as TextRun)?.endpoint) {
|
|
this.endpoint = (this.runs?.[0] as TextRun)?.endpoint;
|
|
}
|
|
}
|
|
}
|
|
|
|
static fromAttributed(data: RawNode): Text {
|
|
const runs: {
|
|
text: string,
|
|
navigationEndpoint?: RawNode,
|
|
attachment?: RawNode
|
|
}[] = [];
|
|
|
|
const content = data.content;
|
|
const command_runs = data.commandRuns;
|
|
|
|
let last_end_index = 0;
|
|
|
|
if (command_runs) {
|
|
for (const item of command_runs) {
|
|
const length: number = item.length;
|
|
const start_index: number = item.startIndex;
|
|
|
|
if (start_index > last_end_index) {
|
|
runs.push({
|
|
text: content.slice(last_end_index, start_index)
|
|
});
|
|
}
|
|
|
|
if (Reflect.has(item, 'onTap')) {
|
|
let attachment = null;
|
|
|
|
if (Reflect.has(data, 'attachmentRuns')) {
|
|
const attachment_runs = data.attachmentRuns;
|
|
|
|
for (const attatchment_run of attachment_runs) {
|
|
if ((attatchment_run.startIndex - 2) == start_index) {
|
|
attachment = attatchment_run;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (attachment) {
|
|
runs.push({
|
|
text: content.slice(start_index, start_index + length),
|
|
navigationEndpoint: item.onTap,
|
|
attachment
|
|
});
|
|
} else {
|
|
runs.push({
|
|
text: content.slice(start_index, start_index + length),
|
|
navigationEndpoint: item.onTap
|
|
});
|
|
}
|
|
}
|
|
|
|
last_end_index = start_index + length;
|
|
}
|
|
|
|
if (last_end_index < content.length) {
|
|
runs.push({
|
|
text: content.slice(last_end_index)
|
|
});
|
|
}
|
|
} else {
|
|
runs.push({
|
|
text: content
|
|
});
|
|
}
|
|
|
|
return new Text({ runs });
|
|
}
|
|
|
|
/**
|
|
* Converts the text to HTML.
|
|
* @returns The HTML.
|
|
*/
|
|
toHTML(): string | undefined {
|
|
return this.runs ? this.runs.map((run) => run.toHTML()).join('') : this.text;
|
|
}
|
|
|
|
/**
|
|
* Checks if the text is empty.
|
|
* @returns Whether the text is empty.
|
|
*/
|
|
isEmpty(): boolean {
|
|
return this.text === undefined;
|
|
}
|
|
|
|
/**
|
|
* Converts the text to a string.
|
|
* @returns The text.
|
|
*/
|
|
toString(): string {
|
|
return this.text || 'N/A';
|
|
}
|
|
} |