your personal website on atproto - mirror
blento.app
1import type { CardDefinition } from '../types';
2import CreateYoutubeCardModal from './CreateYoutubeCardModal.svelte';
3import YoutubeCard from './YoutubeCard.svelte';
4import YoutubeCardSettings from './YoutubeCardSettings.svelte';
5
6export const YoutubeCardDefinition = {
7 type: 'youtubeVideo',
8 contentComponent: YoutubeCard,
9 settingsComponent: YoutubeCardSettings,
10 creationModalComponent: CreateYoutubeCardModal,
11 createNew: (card) => {
12 card.cardType = 'youtubeVideo';
13 card.cardData = {};
14 card.w = 4;
15 card.mobileW = 8;
16 },
17
18 onUrlHandler: (url, item) => {
19 const id = matcher(url);
20 if (!id) return;
21
22 const posterFile = 'hqdefault';
23 const posterURL = `https://i.ytimg.com/vi/${id}/${posterFile}.jpg`;
24
25 item.cardData.poster = posterURL;
26 item.cardData.youtubeId = id;
27 item.cardData.href = url;
28 item.cardData.showInline = true;
29
30 item.w = 4;
31 item.mobileW = 8;
32 item.h = 3;
33 item.mobileH = 5;
34
35 return item;
36 },
37 urlHandlerPriority: 2,
38
39 canChange: (item) => Boolean(matcher(item.cardData.href)),
40
41 change: (item) => {
42 const href = item.cardData?.href;
43
44 const id = matcher(href);
45 if (!id) return;
46
47 const posterFile = 'hqdefault';
48 const posterURL = `https://i.ytimg.com/vi/${id}/${posterFile}.jpg`;
49
50 item.cardData.poster = posterURL;
51 item.cardData.youtubeId = id;
52 item.cardData.showInline ??= true;
53
54 return item;
55 },
56 name: 'Youtube Video',
57
58 keywords: ['video', 'yt', 'stream', 'watch'],
59 groups: ['Media'],
60
61 icon: `<svg xmlns="http://www.w3.org/2000/svg" class="h-3" viewBox="0 0 256 180"
62 ><path
63 fill="currentColor"
64 d="M250.346 28.075A32.18 32.18 0 0 0 227.69 5.418C207.824 0 127.87 0 127.87 0S47.912.164 28.046 5.582A32.18 32.18 0 0 0 5.39 28.24c-6.009 35.298-8.34 89.084.165 122.97a32.18 32.18 0 0 0 22.656 22.657c19.866 5.418 99.822 5.418 99.822 5.418s79.955 0 99.82-5.418a32.18 32.18 0 0 0 22.657-22.657c6.338-35.348 8.291-89.1-.164-123.134"
65 /><path fill="currentColor" class="invert" d="m102.421 128.06l66.328-38.418l-66.328-38.418z" /></svg
66 >`
67} as CardDefinition & { type: 'youtubeVideo' };
68
69// Thanks to eleventy-plugin-youtube-embed
70// https://github.com/gfscott/eleventy-plugin-youtube-embed/blob/main/lib/extractMatches.js
71const urlPattern =
72 /(?=(\s*))\1(?:<a [^>]*?>)??(?=(\s*))\2(?:https?:\/\/)??(?:w{3}\.)??(?:youtube\.com|youtu\.be)\/(?:watch\?v=|embed\/|shorts\/)??([A-Za-z0-9-_]{11})(?:[^\s<>]*)(?=(\s*))\4(?:<\/a>)??(?=(\s*))\5/;
73
74/**
75 * Extract a YouTube ID from a URL if it matches the pattern.
76 * @param url URL to test
77 * @returns A YouTube video ID or undefined if none matched
78 */
79export function matcher(url: string | undefined): string | undefined {
80 if (!url) return;
81
82 const match = url.match(urlPattern);
83 return match?.[3];
84}