diff --git a/src/components/VideoHeader.astro b/src/components/VideoHeader.astro
index 321908983..2cfae98f5 100644
--- a/src/components/VideoHeader.astro
+++ b/src/components/VideoHeader.astro
@@ -6,7 +6,7 @@ export interface Props {
}
const { video } = Astro.props;
-const { frontmatter, author } = video;
+const { data: frontmatter, author } = video;
---
diff --git a/src/components/VideoListItem.astro b/src/components/VideoListItem.astro
index a95bf4905..6c7aafa8a 100644
--- a/src/components/VideoListItem.astro
+++ b/src/components/VideoListItem.astro
@@ -6,21 +6,21 @@ export interface Props {
}
const { video } = Astro.props;
-const { frontmatter, id } = video;
+const { data: frontmatter, slug: id } = video;
---
-
+
{frontmatter.title}
{
frontmatter.isNew && (
-
+
New
·
@@ -32,9 +32,9 @@ const { frontmatter, id } = video;
)
}
-
+
{frontmatter.duration}
- »
+ »
diff --git a/src/content/config.ts b/src/content/config.ts
index 3f4e01b12..cc4d4b9db 100644
--- a/src/content/config.ts
+++ b/src/content/config.ts
@@ -2,10 +2,12 @@ import { authorCollection } from './author';
import { guideCollection } from './guide';
import { projectCollection } from './project';
import { questionGroupCollection } from './question-group';
+import { videoCollection } from './video';
export const collections = {
authors: authorCollection,
guides: guideCollection,
'question-groups': questionGroupCollection,
projects: projectCollection,
+ videos: videoCollection,
};
diff --git a/src/content/video.ts b/src/content/video.ts
new file mode 100644
index 000000000..1768f0d2c
--- /dev/null
+++ b/src/content/video.ts
@@ -0,0 +1,24 @@
+import { defineCollection, z } from 'astro:content';
+
+export const videoCollection = defineCollection({
+ type: 'content',
+ schema: z.object({
+ title: z.string(),
+ description: z.string(),
+ authorId: z.string(),
+ seo: z
+ .object({
+ title: z.string().optional(),
+ description: z.string().optional(),
+ })
+ .optional(),
+ isNew: z.boolean(),
+ duration: z.string(),
+ date: z.date(),
+ sitemap: z.object({
+ priority: z.number(),
+ changefreq: z.enum(['daily', 'weekly', 'monthly', 'yearly']),
+ }),
+ tags: z.array(z.string()),
+ }),
+});
diff --git a/src/data/videos/acid-explained.md b/src/content/videos/acid-explained.md
similarity index 100%
rename from src/data/videos/acid-explained.md
rename to src/content/videos/acid-explained.md
diff --git a/src/data/videos/all-about-http-caching.md b/src/content/videos/all-about-http-caching.md
similarity index 100%
rename from src/data/videos/all-about-http-caching.md
rename to src/content/videos/all-about-http-caching.md
diff --git a/src/data/videos/array-structure.md b/src/content/videos/array-structure.md
similarity index 100%
rename from src/data/videos/array-structure.md
rename to src/content/videos/array-structure.md
diff --git a/src/data/videos/arrays-and-objects-in-javascript.md b/src/content/videos/arrays-and-objects-in-javascript.md
similarity index 100%
rename from src/data/videos/arrays-and-objects-in-javascript.md
rename to src/content/videos/arrays-and-objects-in-javascript.md
diff --git a/src/data/videos/async-javascript.md b/src/content/videos/async-javascript.md
similarity index 100%
rename from src/data/videos/async-javascript.md
rename to src/content/videos/async-javascript.md
diff --git a/src/data/videos/basic-authentication.md b/src/content/videos/basic-authentication.md
similarity index 100%
rename from src/data/videos/basic-authentication.md
rename to src/content/videos/basic-authentication.md
diff --git a/src/data/videos/basics-of-authentication.md b/src/content/videos/basics-of-authentication.md
similarity index 100%
rename from src/data/videos/basics-of-authentication.md
rename to src/content/videos/basics-of-authentication.md
diff --git a/src/data/videos/big-o-notation.md b/src/content/videos/big-o-notation.md
similarity index 100%
rename from src/data/videos/big-o-notation.md
rename to src/content/videos/big-o-notation.md
diff --git a/src/data/videos/content-delivery-networks.md b/src/content/videos/content-delivery-networks.md
similarity index 100%
rename from src/data/videos/content-delivery-networks.md
rename to src/content/videos/content-delivery-networks.md
diff --git a/src/data/videos/dns-explained.md b/src/content/videos/dns-explained.md
similarity index 100%
rename from src/data/videos/dns-explained.md
rename to src/content/videos/dns-explained.md
diff --git a/src/data/videos/dns-records.md b/src/content/videos/dns-records.md
similarity index 100%
rename from src/data/videos/dns-records.md
rename to src/content/videos/dns-records.md
diff --git a/src/data/videos/floating-point-arithmetic.md b/src/content/videos/floating-point-arithmetic.md
similarity index 100%
rename from src/data/videos/floating-point-arithmetic.md
rename to src/content/videos/floating-point-arithmetic.md
diff --git a/src/data/videos/freeze-and-seal-objects-in-javascript.md b/src/content/videos/freeze-and-seal-objects-in-javascript.md
similarity index 100%
rename from src/data/videos/freeze-and-seal-objects-in-javascript.md
rename to src/content/videos/freeze-and-seal-objects-in-javascript.md
diff --git a/src/data/videos/graph-data-structure.md b/src/content/videos/graph-data-structure.md
similarity index 100%
rename from src/data/videos/graph-data-structure.md
rename to src/content/videos/graph-data-structure.md
diff --git a/src/data/videos/hash-table-data-structure.md b/src/content/videos/hash-table-data-structure.md
similarity index 100%
rename from src/data/videos/hash-table-data-structure.md
rename to src/content/videos/hash-table-data-structure.md
diff --git a/src/data/videos/heap-data-structure.md b/src/content/videos/heap-data-structure.md
similarity index 100%
rename from src/data/videos/heap-data-structure.md
rename to src/content/videos/heap-data-structure.md
diff --git a/src/data/videos/how-to-use-css-variables.md b/src/content/videos/how-to-use-css-variables.md
similarity index 100%
rename from src/data/videos/how-to-use-css-variables.md
rename to src/content/videos/how-to-use-css-variables.md
diff --git a/src/data/videos/how-to-use-github-actions.md b/src/content/videos/how-to-use-github-actions.md
similarity index 100%
rename from src/data/videos/how-to-use-github-actions.md
rename to src/content/videos/how-to-use-github-actions.md
diff --git a/src/data/videos/javascript-fetch-api.md b/src/content/videos/javascript-fetch-api.md
similarity index 100%
rename from src/data/videos/javascript-fetch-api.md
rename to src/content/videos/javascript-fetch-api.md
diff --git a/src/data/videos/linked-list-data-structure.md b/src/content/videos/linked-list-data-structure.md
similarity index 100%
rename from src/data/videos/linked-list-data-structure.md
rename to src/content/videos/linked-list-data-structure.md
diff --git a/src/data/videos/load-balancers-101.md b/src/content/videos/load-balancers-101.md
similarity index 100%
rename from src/data/videos/load-balancers-101.md
rename to src/content/videos/load-balancers-101.md
diff --git a/src/data/videos/osi-model.md b/src/content/videos/osi-model.md
similarity index 100%
rename from src/data/videos/osi-model.md
rename to src/content/videos/osi-model.md
diff --git a/src/data/videos/practical-intro-to-react.md b/src/content/videos/practical-intro-to-react.md
similarity index 100%
rename from src/data/videos/practical-intro-to-react.md
rename to src/content/videos/practical-intro-to-react.md
diff --git a/src/data/videos/promises-in-javascript.md b/src/content/videos/promises-in-javascript.md
similarity index 100%
rename from src/data/videos/promises-in-javascript.md
rename to src/content/videos/promises-in-javascript.md
diff --git a/src/data/videos/queue-data-structure.md b/src/content/videos/queue-data-structure.md
similarity index 100%
rename from src/data/videos/queue-data-structure.md
rename to src/content/videos/queue-data-structure.md
diff --git a/src/data/videos/random-number-generators.md b/src/content/videos/random-number-generators.md
similarity index 100%
rename from src/data/videos/random-number-generators.md
rename to src/content/videos/random-number-generators.md
diff --git a/src/data/videos/scaling-the-unscalable.md b/src/content/videos/scaling-the-unscalable.md
similarity index 100%
rename from src/data/videos/scaling-the-unscalable.md
rename to src/content/videos/scaling-the-unscalable.md
diff --git a/src/data/videos/session-based-authentication.md b/src/content/videos/session-based-authentication.md
similarity index 100%
rename from src/data/videos/session-based-authentication.md
rename to src/content/videos/session-based-authentication.md
diff --git a/src/data/videos/ssh-ssl-tls.md b/src/content/videos/ssh-ssl-tls.md
similarity index 100%
rename from src/data/videos/ssh-ssl-tls.md
rename to src/content/videos/ssh-ssl-tls.md
diff --git a/src/data/videos/stack-data-structure.md b/src/content/videos/stack-data-structure.md
similarity index 100%
rename from src/data/videos/stack-data-structure.md
rename to src/content/videos/stack-data-structure.md
diff --git a/src/data/videos/system-design-101.md b/src/content/videos/system-design-101.md
similarity index 100%
rename from src/data/videos/system-design-101.md
rename to src/content/videos/system-design-101.md
diff --git a/src/data/videos/tcp-ip-model.md b/src/content/videos/tcp-ip-model.md
similarity index 100%
rename from src/data/videos/tcp-ip-model.md
rename to src/content/videos/tcp-ip-model.md
diff --git a/src/data/videos/transport-protocols-tcp-vs-udp.md b/src/content/videos/transport-protocols-tcp-vs-udp.md
similarity index 100%
rename from src/data/videos/transport-protocols-tcp-vs-udp.md
rename to src/content/videos/transport-protocols-tcp-vs-udp.md
diff --git a/src/data/videos/tree-data-structure.md b/src/content/videos/tree-data-structure.md
similarity index 100%
rename from src/data/videos/tree-data-structure.md
rename to src/content/videos/tree-data-structure.md
diff --git a/src/data/videos/what-are-data-structures.md b/src/content/videos/what-are-data-structures.md
similarity index 100%
rename from src/data/videos/what-are-data-structures.md
rename to src/content/videos/what-are-data-structures.md
diff --git a/src/data/videos/what-is-cap-theorem.md b/src/content/videos/what-is-cap-theorem.md
similarity index 100%
rename from src/data/videos/what-is-cap-theorem.md
rename to src/content/videos/what-is-cap-theorem.md
diff --git a/src/data/videos/what-is-dependency-injection.md b/src/content/videos/what-is-dependency-injection.md
similarity index 100%
rename from src/data/videos/what-is-dependency-injection.md
rename to src/content/videos/what-is-dependency-injection.md
diff --git a/src/data/videos/what-is-dom-shadow-dom-virtual-dom.md b/src/content/videos/what-is-dom-shadow-dom-virtual-dom.md
similarity index 100%
rename from src/data/videos/what-is-dom-shadow-dom-virtual-dom.md
rename to src/content/videos/what-is-dom-shadow-dom-virtual-dom.md
diff --git a/src/data/videos/what-is-eventual-consistency.md b/src/content/videos/what-is-eventual-consistency.md
similarity index 100%
rename from src/data/videos/what-is-eventual-consistency.md
rename to src/content/videos/what-is-eventual-consistency.md
diff --git a/src/data/videos/yaml-in-depth.md b/src/content/videos/yaml-in-depth.md
similarity index 100%
rename from src/data/videos/yaml-in-depth.md
rename to src/content/videos/yaml-in-depth.md
diff --git a/src/lib/video.ts b/src/lib/video.ts
index e0bba39e1..0d4907c7e 100644
--- a/src/lib/video.ts
+++ b/src/lib/video.ts
@@ -1,44 +1,12 @@
import type { MarkdownFileType } from './file';
import type { AuthorFileType } from './author.ts';
import { getAllAuthors } from './author.ts';
-import type { GuideFileType } from './guide.ts';
-import { getAllGuides } from './guide.ts';
+import { getCollection, type CollectionEntry } from 'astro:content';
-export interface VideoFrontmatter {
- title: string;
- description: string;
- authorId: string;
- seo: {
- title: string;
- description: string;
- };
- isNew: boolean;
- duration: string;
- date: string;
- sitemap: {
- priority: number;
- changefreq: 'daily' | 'weekly' | 'monthly' | 'yearly';
- };
- tags: string[];
-}
-
-export type VideoFileType = MarkdownFileType
& {
- id: string;
+export type VideoFileType = CollectionEntry<'videos'> & {
author: AuthorFileType;
};
-/**
- * Generates id from the given video file
- * @param filePath Markdown file path
- *
- * @returns unique video identifier
- */
-function videoPathToId(filePath: string): string {
- const fileName = filePath.split('/').pop() || '';
-
- return fileName.replace('.md', '');
-}
-
export async function getVideosByAuthor(
authorId: string,
): Promise {
@@ -52,43 +20,38 @@ export async function getVideosByAuthor(
* @returns Promisifed video files
*/
export async function getAllVideos(): Promise {
- const videos = import.meta.glob('/src/data/videos/*.md', {
- eager: true,
- });
-
+ const videoEntries = await getCollection('videos');
const allAuthors = await getAllAuthors();
- const videoFiles = Object.values(videos);
- const enrichedVideos = videoFiles.map((videoFile) => ({
- ...videoFile,
- id: videoPathToId(videoFile.file),
- author: allAuthors.find(
- (author) => author.slug === videoFile.frontmatter.authorId,
- )!,
- }));
+ const enrichedVideos = videoEntries.map((videoFile) => {
+ const author = allAuthors.find(
+ (author) => author.slug === videoFile.data.authorId,
+ );
+
+ if (!author) {
+ throw new Error(
+ `Author with ID ${videoFile.data.authorId} not found for video ${videoFile.data.title}`,
+ );
+ }
+
+ return {
+ ...videoFile,
+ author,
+ };
+ });
return enrichedVideos.sort(
- (a, b) =>
- new Date(b.frontmatter.date).valueOf() -
- new Date(a.frontmatter.date).valueOf(),
+ (a, b) => new Date(b.data.date).valueOf() - new Date(a.data.date).valueOf(),
);
}
export async function getVideoById(id: string): Promise {
- const videoFilesMap: Record =
- import.meta.glob('../data/videos/*.md', {
- eager: true,
- });
+ const allVideos = await getAllVideos();
+ const videoFile = allVideos.find((video) => video.slug === id);
- const videoFile = Object.values(videoFilesMap).find((videoFile) => {
- return videoPathToId(videoFile.file) === id;
- });
if (!videoFile) {
throw new Error(`Video with ID ${id} not found`);
}
- return {
- ...videoFile,
- id: videoPathToId(videoFile.file),
- };
+ return videoFile;
}
diff --git a/src/pages/pages.json.ts b/src/pages/pages.json.ts
index 2996e7ea3..456258f0d 100644
--- a/src/pages/pages.json.ts
+++ b/src/pages/pages.json.ts
@@ -50,9 +50,9 @@ export async function GET() {
group: 'Guides',
})),
...videos.map((video) => ({
- id: video.id,
- url: `/videos/${video.id}`,
- title: video.frontmatter.title,
+ id: video.slug,
+ url: `/videos/${video.slug}`,
+ title: video.data.title,
group: 'Videos',
})),
...projects.map((project) => ({
diff --git a/src/pages/videos/[videoId].astro b/src/pages/videos/[videoId].astro
index 096e230a0..bd7058872 100644
--- a/src/pages/videos/[videoId].astro
+++ b/src/pages/videos/[videoId].astro
@@ -1,7 +1,7 @@
---
import VideoHeader from '../../components/VideoHeader.astro';
import BaseLayout from '../../layouts/BaseLayout.astro';
-import { getAllVideos, VideoFileType } from '../../lib/video';
+import { getAllVideos, type VideoFileType } from '../../lib/video';
export interface Props {
video: VideoFileType;
@@ -11,18 +11,19 @@ export async function getStaticPaths() {
const videos = await getAllVideos();
return videos.map((video) => ({
- params: { videoId: video.id },
+ params: { videoId: video.slug },
props: { video },
}));
}
const { videoId } = Astro.params;
const { video } = Astro.props;
+const { Content } = await video.render();
---
@@ -31,7 +32,7 @@ const { video } = Astro.props;
-
+