Skip to content

Commit e6650f7

Browse files
authored
Merge pull request #1650 from fturmel/PR/youtube-redirects
YouTube redirects feature
2 parents 51a66e8 + 6ff260f commit e6650f7

File tree

4 files changed

+87
-1
lines changed

4 files changed

+87
-1
lines changed

netlify/edge-functions/yt/index.mjs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// The JSON lookup gets generated at build time, do not manually edit. See `node-scripts/generate-youtube-redirects.js`
2+
import redirects from './redirects.json' assert { type: 'json' };
3+
4+
export default async (request) => {
5+
const url = new URL(request.url);
6+
const youtubeId = url.pathname.split('/')[2];
7+
8+
const headers = {
9+
'Cache-Control': 'public, max-age=86400' // 24h
10+
};
11+
12+
if (redirects[youtubeId]) {
13+
return new Response(null, {
14+
status: 302,
15+
headers: {
16+
...headers,
17+
Location: redirects[youtubeId]
18+
}
19+
});
20+
}
21+
22+
return new Response('Not Found', {
23+
status: 404,
24+
headers
25+
});
26+
};
27+
28+
export const config = { path: '/yt/:youtubeId' };
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
const fs = require('node:fs');
2+
const { paths, toSlug } = require('../content-testing/content');
3+
4+
// Generates a JSON file that maps YouTube IDs to their challenge or track URL
5+
// Priority: challenge > canonical track > track
6+
7+
const redirects = {};
8+
9+
for (const path of paths.challenges) {
10+
const slug = toSlug.videosAndChallenges(path);
11+
const video = JSON.parse(fs.readFileSync(path));
12+
const parts = video.parts ?? [video];
13+
14+
parts.forEach((part, i) => {
15+
const partAnchor = i > 0 ? `#part-${i + 1}` : '';
16+
redirects[part.videoId] = `/${slug}${partAnchor}`;
17+
});
18+
}
19+
20+
const slugToVideo = new Map();
21+
for (const path of paths.videos) {
22+
const slug = toSlug.videosAndChallenges(path);
23+
const video = JSON.parse(fs.readFileSync(path));
24+
slugToVideo.set(slug, video);
25+
}
26+
27+
for (const path of paths.tracks) {
28+
const trackSlug = toSlug.tracks(path);
29+
const track = JSON.parse(fs.readFileSync(path));
30+
31+
const chaptersOrVideos =
32+
track.videos ?? track.chapters.flatMap((c) => c.videos);
33+
34+
for (const slug of chaptersOrVideos) {
35+
if (!slugToVideo.has(slug)) continue;
36+
37+
const video = slugToVideo.get(slug);
38+
const parts = video.parts ?? [video];
39+
const isCanonicalTrack = video.canonicalTrack === trackSlug;
40+
41+
parts.forEach((part, i) => {
42+
if (!redirects[part.videoId] || isCanonicalTrack) {
43+
const partAnchor = i > 0 ? `#part-${i + 1}` : '';
44+
redirects[part.videoId] = `/tracks/${trackSlug}/${slug}${partAnchor}`;
45+
}
46+
});
47+
}
48+
}
49+
50+
fs.writeFileSync(
51+
'netlify/edge-functions/yt/redirects.json',
52+
JSON.stringify(redirects)
53+
);
54+
55+
console.log(
56+
`${Object.keys(redirects).length} YouTube redirects were generated.`
57+
);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"scripts": {
1212
"dev": "gatsby develop -H 0.0.0.0",
1313
"build": "gatsby build --verbose",
14-
"build-ci": "node node-scripts/generate-challenges-redirects && npm run tags-transforms && npm run build",
14+
"build-ci": "node node-scripts/generate-challenges-redirects && node node-scripts/generate-youtube-redirects && npm run tags-transforms && npm run build",
1515
"serve": "gatsby serve",
1616
"clean": "gatsby clean",
1717
"test": "jest",

0 commit comments

Comments
 (0)