enh: html token (allow yt embed)

This commit is contained in:
Timothy Jaeryang Baek 2025-04-19 23:38:08 -07:00
parent f4de3b4c45
commit 6fd082d55f
3 changed files with 53 additions and 20 deletions

View File

@ -0,0 +1,49 @@
<script lang="ts">
import DOMPurify from 'dompurify';
import type { Token } from 'marked';
import { WEBUI_BASE_URL } from '$lib/constants';
import Source from './Source.svelte';
export let id: string;
export let token: Token;
export let onSourceClick: Function = () => {};
let html: string | null = null;
$: if (token.type === 'html' && token?.text) {
html = DOMPurify.sanitize(token.text);
} else {
html = null;
}
</script>
{#if token.type === 'html'}
{#if html && html.includes('<video')}
{@html html}
{:else if token.text && token.text.match(/<iframe\s+[^>]*src="https:\/\/www\.youtube\.com\/embed\/([a-zA-Z0-9_-]{11})"[^>]*><\/iframe>/)}
{@const match = token.text.match(
/<iframe\s+[^>]*src="https:\/\/www\.youtube\.com\/embed\/([a-zA-Z0-9_-]{11})"[^>]*><\/iframe>/
)}
{@const ytId = match && match[1]}
{#if ytId}
<iframe
class="w-full aspect-video my-2"
src={`https://www.youtube.com/embed/${ytId}`}
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen
>
</iframe>
{/if}
{:else if token.text.includes(`<iframe src="${WEBUI_BASE_URL}/api/v1/files/`)}
{@html `${token.text}`}
{:else if token.text.includes(`<source_id`)}
<Source {id} {token} onClick={onSourceClick} />
{:else}
{token.text}
{/if}
{/if}

View File

@ -13,6 +13,7 @@
import Image from '$lib/components/common/Image.svelte';
import KatexRenderer from './KatexRenderer.svelte';
import Source from './Source.svelte';
import HtmlToken from './HTMLToken.svelte';
export let id: string;
export let tokens: Token[];
@ -23,16 +24,7 @@
{#if token.type === 'escape'}
{unescapeHtml(token.text)}
{:else if token.type === 'html'}
{@const html = DOMPurify.sanitize(token.text)}
{#if html && html.includes('<video')}
{@html html}
{:else if token.text.includes(`<iframe src="${WEBUI_BASE_URL}/api/v1/files/`)}
{@html `${token.text}`}
{:else if token.text.includes(`<source_id`)}
<Source {id} {token} onClick={onSourceClick} />
{:else}
{@html html}
{/if}
<HtmlToken {id} {token} {onSourceClick} />
{:else if token.type === 'link'}
{#if token.tokens}
<a href={token.href} target="_blank" rel="nofollow" title={token.title}>

View File

@ -21,6 +21,7 @@
import Source from './Source.svelte';
import { settings } from '$lib/stores';
import HtmlToken from './HTMLToken.svelte';
export let id: string;
export let tokens: Token[];
@ -266,16 +267,7 @@
</div>
</Collapsible>
{:else if token.type === 'html'}
{@const html = DOMPurify.sanitize(token.text)}
{#if html && html.includes('<video')}
{@html html}
{:else if token.text.includes(`<iframe src="${WEBUI_BASE_URL}/api/v1/files/`)}
{@html `${token.text}`}
{:else if token.text.includes(`<source_id`)}
<Source {id} {token} onClick={onSourceClick} />
{:else}
{token.text}
{/if}
<HtmlToken {id} {token} {onSourceClick} />
{:else if token.type === 'iframe'}
<iframe
src="{WEBUI_BASE_URL}/api/v1/files/{token.fileId}/content"