Skip to content

Commit 5c23233

Browse files
authored
Merge pull request #1294 from dipamsen/rewrite-yt-desc
yt-desc refactor
2 parents 1e9185c + 203152d commit 5c23233

File tree

1 file changed

+110
-51
lines changed

1 file changed

+110
-51
lines changed

node-scripts/yt-description.mjs

Lines changed: 110 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,50 @@ import clipboard from 'clipboardy';
1616

1717
const videos = [];
1818

19+
/**
20+
* @typedef {object} VideoInfo
21+
* @property {string} title
22+
* @property {string} description
23+
* @property {string} videoNumber
24+
* @property {string} videoId
25+
* @property {string} date
26+
* @property {string[]} languages
27+
* @property {string} nebulaSlug
28+
* @property {string[]} topics
29+
* @property {boolean} canContribute
30+
* @property {string[]} relatedChallenges
31+
* @property {{time: number, title: string}[]} timestamps
32+
* @property {{time: number, title: string}[]} corrections
33+
* @property {{title: string, description: string, image: string, urls: object}[]} codeExamples
34+
* @property {{title: string, links: {title: string, url: string, description: string}[]}[]} groupLinks
35+
*/
36+
37+
/**
38+
* A Coding Train Video
39+
*/
40+
class Video {
41+
constructor(
42+
data,
43+
parentTracks,
44+
urls,
45+
filePath,
46+
canonicalTrack,
47+
slug,
48+
canonicalURL,
49+
isMultipartChallenge = false
50+
) {
51+
/** @type {VideoInfo} */
52+
this.data = data;
53+
this.parentTracks = parentTracks;
54+
this.urls = urls;
55+
this.filePath = filePath;
56+
this.canonicalTrack = canonicalTrack;
57+
this.slug = slug;
58+
this.canonicalURL = canonicalURL;
59+
this.isMultipartChallenge = isMultipartChallenge;
60+
}
61+
}
62+
1963
/**
2064
* Searches for `index.json` files in a given directory and returns an array of parsed files.
2165
* @param {string} dir Name of directory to search for files
@@ -82,31 +126,48 @@ function parseTrack(track) {
82126
function getVideoData(file) {
83127
const videoList = [];
84128
const content = fs.readFileSync(`./${file}`, 'utf-8');
85-
const video = JSON.parse(content);
129+
const videoData = JSON.parse(content);
86130

87131
const filePath = file.split(path.sep).slice(2);
88132
const videoPath = filePath.slice(0, -1).join('/');
89133
// console.log('[Parsing File]:', filePath.join('/'));
90-
let url, canonicalTrack;
134+
let urls = [],
135+
canonicalTrack,
136+
canonicalURL;
137+
const parentTracks = [];
91138

92139
if (filePath[0] === 'challenges') {
93-
url = filePath.slice(0, 2).join('/');
140+
urls.push(filePath.slice(0, 2).join('/'));
141+
canonicalURL = urls[0];
142+
for (let track of allTracks) {
143+
if (track.videoList.includes(videoPath)) {
144+
urls.push(['tracks', track.trackName, videoPath].join('/'));
145+
parentTracks.push(track.trackName);
146+
}
147+
}
94148
} else {
95-
if (video.canonicalTrack) {
96-
canonicalTrack = video.canonicalTrack;
97-
url = ['tracks', video.canonicalTrack, videoPath].join('/');
149+
if (videoData.canonicalTrack) {
150+
canonicalTrack = videoData.canonicalTrack;
151+
canonicalURL = ['tracks', canonicalTrack, videoPath].join('/');
152+
for (let track of allTracks) {
153+
if (track.videoList.includes(videoPath)) {
154+
urls.push(['tracks', track.trackName, videoPath].join('/'));
155+
parentTracks.push(track.trackName);
156+
}
157+
}
98158
} else {
99159
for (let track of allTracks) {
100160
if (track.videoList.includes(videoPath)) {
101161
canonicalTrack = track.trackName;
102-
url = ['tracks', track.trackName, videoPath].join('/');
103-
break;
162+
urls.push(['tracks', track.trackName, videoPath].join('/'));
163+
parentTracks.push(track.trackName);
104164
}
105165
}
166+
canonicalURL = urls[0];
106167
}
107168
}
108169

109-
if (!url) {
170+
if (urls.length == 0) {
110171
console.log(
111172
'⚠️ Warning: Could not find this video: ' +
112173
videoPath +
@@ -115,50 +176,50 @@ function getVideoData(file) {
115176
return [];
116177
}
117178

118-
const slug = url.split('/').at(-1);
119-
120-
if (!url || url.length == 0) {
121-
throw new Error(
122-
'Something went wrong in parsing this file: ' + filePath.join('/')
123-
);
124-
}
179+
const slug = urls[0].split('/').at(-1);
125180

126-
if (video.parts && video.parts.length > 0) {
181+
if (videoData.parts && videoData.parts.length > 0) {
127182
// Multipart Coding Challenge
128183
// https://github.com/CodingTrain/thecodingtrain.com/issues/420#issuecomment-1218529904
129184

130-
for (const part of video.parts) {
185+
for (const part of videoData.parts) {
131186
// copy all info from base object
132-
const partInfo = JSON.parse(JSON.stringify(video));
187+
const partInfo = JSON.parse(JSON.stringify(videoData));
133188
delete partInfo.parts;
134189

135190
// copy videoId, title, timestamps from parts
136191
partInfo.videoId = part.videoId;
137192
partInfo.timestamps = part.timestamps;
138-
partInfo.challengeTitle = video.title;
193+
partInfo.challengeTitle = videoData.title;
139194
partInfo.partTitle = part.title;
140-
partInfo.title = video.title + ' - ' + part.title;
195+
partInfo.title = videoData.title + ' - ' + part.title;
141196

142-
const videoData = {
143-
pageURL: url,
144-
data: partInfo,
145-
filePath: file,
146-
isMultipartChallenge: true,
197+
const video = new Video(
198+
partInfo,
199+
parentTracks,
200+
urls,
201+
file,
147202
canonicalTrack,
148-
slug: slug
149-
};
150-
videoList.push(videoData);
203+
slug,
204+
canonicalURL,
205+
true
206+
);
207+
208+
videoList.push(video);
151209
}
152210
} else {
153-
video.challengeTitle = video.title;
154-
const videoData = {
155-
pageURL: url,
156-
data: video,
157-
filePath: file,
211+
videoData.challengeTitle = videoData.title;
212+
const video = new Video(
213+
videoData,
214+
parentTracks,
215+
urls,
216+
file,
158217
canonicalTrack,
159-
slug: slug
160-
};
161-
videoList.push(videoData);
218+
slug,
219+
canonicalURL
220+
);
221+
222+
videoList.push(video);
162223
}
163224
return videoList;
164225
}
@@ -219,7 +280,7 @@ function resolveCTLink(url) {
219280

220281
let page;
221282
try {
222-
page = videos.find((vid) => vid.pageURL === location).data;
283+
page = videos.find((vid) => vid.urls.includes(location)).data;
223284
} catch (err) {
224285
console.warn('⚠️ Warning: Could not resolve to YT video:', url);
225286
return `https://thecodingtrain.com${url}`;
@@ -273,7 +334,7 @@ function findMaxOccurences(arr) {
273334
*/
274335
function writeDescription(video) {
275336
const data = video.data;
276-
const pageURL = video.pageURL;
337+
const pageURL = video.canonicalURL;
277338
let description = '';
278339

279340
// Description
@@ -340,7 +401,7 @@ function writeDescription(video) {
340401

341402
// Previous Video / Next Video / All Videos
342403

343-
if (video.pageURL.startsWith('challenges/')) {
404+
if (video.canonicalURL.startsWith('challenges/')) {
344405
const i = +video.data.videoNumber;
345406
const previousVideo = videos.find((vid) => vid.data.videoNumber == i - 1);
346407
const nextVideo = videos.find((vid) => vid.data.videoNumber == i + 1);
@@ -355,7 +416,7 @@ function writeDescription(video) {
355416
description += `🎥 Next: https://youtu.be/${nextVideo.data.videoId}?list=${challengePL}\n`;
356417
description += `🎥 All: https://www.youtube.com/playlist?list=${challengePL}\n`;
357418
} else {
358-
const path = video.pageURL.split('/');
419+
const path = video.canonicalURL.split('/');
359420
const videoDir = path.slice(2).join('/');
360421

361422
const track = allTracks.find((t) => t.trackName === video.canonicalTrack);
@@ -365,13 +426,13 @@ function writeDescription(video) {
365426
let id = track.videoList.indexOf(videoDir);
366427

367428
const previousPath = track.videoList[id - 1];
368-
const previousVideo = videos.find(
369-
(vid) => vid.pageURL == 'tracks/' + track.trackName + '/' + previousPath
429+
const previousVideo = videos.find((vid) =>
430+
vid.urls.includes('tracks/' + track.trackName + '/' + previousPath)
370431
);
371432

372433
const nextPath = track.videoList[id + 1];
373-
const nextVideo = videos.find(
374-
(vid) => vid.pageURL == 'tracks/' + track.trackName + '/' + nextPath
434+
const nextVideo = videos.find((vid) =>
435+
vid.urls.includes('tracks/' + track.trackName + '/' + nextPath)
375436
);
376437
const plId = track.data.playlistId
377438
? `?list=${track.data.playlistId}`
@@ -413,12 +474,12 @@ function writeDescription(video) {
413474
if (data.relatedChallenges && data.relatedChallenges.length > 0) {
414475
description += `\nRelated Coding Challenges:\n`;
415476
for (const challenge of data.relatedChallenges) {
416-
const challengeData = videos.find(
417-
(vid) => vid.pageURL === `challenges/${challenge}`
477+
const challengeData = videos.find((vid) =>
478+
vid.urls.includes(`challenges/${challenge}`)
418479
);
419480
if (challengeData) {
420481
const { videoNumber, challengeTitle } = challengeData.data;
421-
const url = challengeData.pageURL;
482+
const url = challengeData.canonicalURL;
422483
description +=
423484
`🚂 ${videoNumber} ${challengeTitle}: ${resolveCTLink(url)}` + '\n';
424485
} else {
@@ -526,9 +587,7 @@ const allTracks = [...mainTracks, ...sideTracks];
526587
const url = new URL(video);
527588
if (url.hostname == 'thecodingtrain.com') {
528589
const pathName = url.pathname;
529-
specifiedVideos = videos.filter(
530-
(data) => '/' + data.pageURL === pathName
531-
);
590+
specifiedVideos = videos.filter((data) => data.urls.includes(pathName));
532591
} else {
533592
const video = resolveYTLink(url);
534593
if (video) {

0 commit comments

Comments
 (0)