mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-19 04:21:35 +00:00
feat(parser): Text#toHTML (#300)
Added support to render Text nodes as HTML for use in web applications.
This commit is contained in:
@@ -94,6 +94,17 @@ class NavigationEndpoint extends YTNode {
|
||||
throw new Error('Expected an api_url, but none was found, this is a bug.');
|
||||
return actions.execute(this.metadata.api_url, { ...this.payload, ...args });
|
||||
}
|
||||
|
||||
toURL(): string | undefined {
|
||||
if (!this.metadata.url)
|
||||
return undefined;
|
||||
if (!this.metadata.page_type)
|
||||
return undefined;
|
||||
return (
|
||||
this.metadata.page_type === 'WEB_PAGE_TYPE_UNKNOWN' ?
|
||||
this.metadata.url : `https://www.youtube.com${this.metadata.url}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NavigationEndpoint;
|
||||
@@ -1,6 +1,7 @@
|
||||
import { escape, Run } from './Text';
|
||||
import Thumbnail from './Thumbnail';
|
||||
|
||||
class EmojiRun {
|
||||
class EmojiRun implements Run {
|
||||
text: string;
|
||||
emoji: {
|
||||
emoji_id: string;
|
||||
@@ -24,6 +25,15 @@ class EmojiRun {
|
||||
is_custom: !!data.emoji?.isCustomEmoji
|
||||
};
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
toHTML(): string {
|
||||
const escaped_text = escape(this.text);
|
||||
return `<img src="${this.emoji.image[0].url}" alt="${escaped_text}" title="${escaped_text}" style="display: inline-block; vertical-align: text-top; height: var(--yt-emoji-size, 1rem); width: var(--yt-emoji-size, 1rem);" loading="lazy" crossorigin="anonymous" />`;
|
||||
}
|
||||
}
|
||||
|
||||
export default EmojiRun;
|
||||
@@ -1,6 +1,21 @@
|
||||
import TextRun from './TextRun';
|
||||
import EmojiRun from './EmojiRun';
|
||||
|
||||
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, ''');
|
||||
}
|
||||
|
||||
class Text {
|
||||
text: string;
|
||||
runs;
|
||||
@@ -17,6 +32,10 @@ class Text {
|
||||
}
|
||||
}
|
||||
|
||||
toHTML() {
|
||||
return this.runs ? this.runs.map((run) => run.toHTML()).join('') : this.text;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import NavigationEndpoint from '../NavigationEndpoint';
|
||||
import { escape, Run } from './Text';
|
||||
|
||||
class TextRun {
|
||||
class TextRun implements Run {
|
||||
text: string;
|
||||
endpoint: NavigationEndpoint | undefined;
|
||||
bold: boolean;
|
||||
@@ -14,6 +15,25 @@ class TextRun {
|
||||
this.strikethrough = Boolean(data.strikethrough);
|
||||
this.endpoint = data.navigationEndpoint ? new NavigationEndpoint(data.navigationEndpoint) : undefined;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
toHTML(): string {
|
||||
const tags: string[] = [];
|
||||
if (this.bold) tags.push('b');
|
||||
if (this.italics) tags.push('i');
|
||||
if (this.strikethrough) tags.push('s');
|
||||
const escaped_text = escape(this.text);
|
||||
const styled_text = tags.map((tag) => `<${tag}>`).join('') + escaped_text + tags.map((tag) => `</${tag}>`).join('');
|
||||
const wrapped_text = `<span style="white-space: pre-wrap;">${styled_text}</span>`;
|
||||
if (this.endpoint) {
|
||||
const url = this.endpoint.toURL();
|
||||
if (url) return `<a href="${url}">${wrapped_text}</a>`;
|
||||
}
|
||||
return wrapped_text;
|
||||
}
|
||||
}
|
||||
|
||||
export default TextRun;
|
||||
Reference in New Issue
Block a user