Skip to content

Commit 074798b

Browse files
committed
Fixed YouTube Player
1 parent 29f3b74 commit 074798b

File tree

6 files changed

+118
-26
lines changed

6 files changed

+118
-26
lines changed

astro.config.mjs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ if (!gitVersion) {
2626
}
2727
}
2828

29+
const fastBuild= true;
30+
2931
function dontDie() {
3032
return {
3133
name: "dont-die",
@@ -113,20 +115,23 @@ export default defineConfig({
113115
},
114116
integrations: [
115117
mdx(),
116-
sitemap(),
117-
metaTags(),
118-
deleteUnusedImages(),
119118
svelte(),
120-
compress({
121-
HTML: false,
122-
CSS: false,
123-
SVG: false,
124-
}),
125-
dontDie(),
119+
...(fastBuild? [] : [
120+
sitemap(),
121+
metaTags(),
122+
deleteUnusedImages(),
123+
compress({
124+
HTML: false,
125+
JavaScript: false,
126+
CSS: false,
127+
SVG: false,
128+
}),
129+
dontDie(),
130+
]),
126131
],
127132
output: "static",
128133
build: {
129-
minify: true,
134+
...(fastBuild? {} : { minify: true,}),
130135
},
131136
image: {
132137
remotePatterns: [{ protocol: "https" }],

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"date-fns-tz": "^3.2.0",
3333
"hastscript": "^9.0.1",
3434
"js-yaml": "^4.1.0",
35+
"lite-youtube-embed": "^0.3.3",
3536
"marked": "^15.0.12",
3637
"nanostores": "^1.0.1",
3738
"pagefind": "^1.3.0",

pnpm-lock.yaml

Lines changed: 3 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/ui/Markdown.astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
---
22
import { marked } from 'marked';
3+
import { replaceYouTubeLinks } from "@utils/markdown";
34
45
interface Props {
56
content: string;
67
}
78
89
const { content } = Astro.props;
9-
const html = marked.parse(content);
10+
const html = marked.parse(await replaceYouTubeLinks(content) );
1011
---
1112

1213
<div class="prose prose-xl max-w-none" >

src/components/ui/YouTube.astro

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,78 @@
11
---
2-
import { YouTube as Player } from "@astro-community/astro-embed-youtube";
32
4-
type Props = {
5-
id?: string;
6-
class?: string;
7-
[key: string]: any;
3+
import 'lite-youtube-embed/src/lite-yt-embed.css';
4+
import liteJS from 'lite-youtube-embed/src/lite-yt-embed.js?url';
5+
6+
const urlPattern =
7+
/(?=(\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/;
8+
9+
function urlMatcher(url: string): string | undefined {
10+
const match = url.match(urlPattern);
11+
return match?.[3];
12+
}
13+
14+
export interface Props extends astroHTML.JSX.HTMLAttributes {
15+
id: string;
16+
poster?: string;
17+
posterQuality?: 'max' | 'high' | 'default' | 'low';
18+
params?: string;
19+
playlabel?: string;
820
}
921
1022
const {
23+
id,
24+
poster,
25+
posterQuality = 'default',
26+
title,
1127
class: userClass = '',
12-
...attrs
13-
} = Astro.props;
14-
15-
const attrId = attrs.id || '';
28+
...attrs
29+
} = Astro.props as Props;
1630
1731
const defaultClass = 'border-4 border-white rounded-lg shadow-lg';
1832
const className = `${defaultClass} ${userClass}`.trim();
33+
34+
const idRegExp = /^[A-Za-z0-9-_]+$/;
35+
36+
function extractID(idOrUrl: string) {
37+
if (idRegExp.test(idOrUrl)) return idOrUrl;
38+
return urlMatcher(idOrUrl);
39+
}
40+
41+
const videoid = extractID(id);
42+
const posterFile =
43+
{
44+
max: 'maxresdefault',
45+
high: 'sddefault',
46+
default: 'hqdefault',
47+
low: 'default',
48+
}[posterQuality] || 'hqdefault';
49+
const posterURL =
50+
poster || `https://i.ytimg.com/vi/${videoid}/${posterFile}.jpg`;
51+
const href = `https://youtube.com/watch?v=${videoid}`;
1952
---
2053

21-
<Player id={attrId} class={className} {...attrs} />
54+
<lite-youtube
55+
{videoid}
56+
{title}
57+
data-title={title}
58+
{...attrs}
59+
class={className}
60+
style=`background-image: url('${posterURL}');`
61+
>
62+
<a {href} class="lty-playbtn ">
63+
<span class="lyt-visually-hidden">{attrs.playlabel || 'Play'}</span>
64+
</a>
65+
</lite-youtube>
66+
67+
<script is:inline type="module" src={liteJS}></script>
68+
69+
<style is:global>
70+
lite-youtube > iframe {
71+
all: unset !important;
72+
width: 100% !important;
73+
height: 100% !important;
74+
position: absolute !important;
75+
inset: 0 !important;
76+
border: 0 !important;
77+
}
78+
</style>

src/utils/markdown.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { experimental_AstroContainer } from "astro/container";
2+
import YouTube from "@ui/YouTube.astro";
3+
4+
export async function replaceYouTubeLinks(
5+
markdownContent: string
6+
): Promise<string> {
7+
const youtubeRegex =
8+
/(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^\s'"()[\]<>]+)/gi;
9+
10+
const matches = [...markdownContent.matchAll(youtubeRegex)];
11+
if (matches.length === 0) return markdownContent;
12+
13+
const container = await experimental_AstroContainer.create();
14+
let updatedContent = markdownContent;
15+
16+
for (const match of matches) {
17+
const fullUrl = match[0];
18+
const id = match[1];
19+
20+
if (!id) continue;
21+
22+
const html = await container.renderToString(YouTube, {
23+
props: { id, alt: "Embedded YouTube video" },
24+
});
25+
26+
updatedContent = updatedContent.replace(fullUrl, html);
27+
}
28+
29+
return updatedContent;
30+
}

0 commit comments

Comments
 (0)