Written by: Marlon Colca
Posted on 07 Sep 2025 - a month ago
nextjs typescript clones
Define a simple, typed catalog and helpers to query it efficiently from the UI.
Goal: Define a simple, typed catalog and helpers to query it efficiently from the UI.
src/data/movies.json
: sample data (id, title, categories, sources, subtitles).src/lib/catalog.ts
: TypeScript types and helper functions.// src/lib/catalog.ts (excerpt)
export type VideoSource = { src: string; type: string; label?: string };
export type SubtitleTrack = {
src: string;
lang: string;
label: string;
default?: boolean;
};
export type Movie = {
id: string;
title: string;
description?: string;
poster?: string; // local path or external URL
categories: string[]; // e.g. ["Destacados", "Demo"]
sources: VideoSource[]; // multiple quality/format options
subtitles?: SubtitleTrack[];
year?: number;
runtime?: number; // seconds
};
movies.json
entry 📄{
"id": "tears-of-steel",
"title": "Tears of Steel",
"poster": "/posters/tears-of-steel.jpg",
"categories": ["Destacados", "Demo"],
"sources": [
{
"src": "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4",
"type": "video/mp4",
"label": "720p"
}
],
"subtitles": [
{
"src": "/subs/TOS-en.srt",
"lang": "en",
"label": "English",
"default": true
},
{ "src": "/subs/TOS-es.srt", "lang": "es", "label": "Español" }
]
}
// src/lib/catalog.ts (excerpt)
import movies from "@/data/movies.json";
export function getAllMovies(): Movie[] {
return movies as Movie[];
}
export function getMovieById(id: string): Movie | undefined {
return getAllMovies().find((m) => m.id === id);
}
export function getByCategory(): Record<string, Movie[]> {
const map: Record<string, Movie[]> = {};
for (const m of getAllMovies()) {
for (const c of m.categories || []) {
(map[c] ||= []).push(m);
}
}
return map;
}
sources
: multiple qualities/formats; browsers pick the first compatible <source>
. We’ll sort to prefer MP4 for reach.subtitles
: Tracks can include .srt
which we convert to .vtt
at runtime.categories: string[]
: Simple, flexible grouping; rows are derived directly from it.poster/description/year/runtime
: Enrich UI without complicating the core model.movies.json
is easy to edit/diff; with resolveJsonModule
, TS understands imports and you still get types at usage sites.catalog.ts
centralizes types and helper queries so UI doesn’t couple to file shape.rating
, cast
, or background
as optional, then extend Movie
accordingly.next/image
need images.remotePatterns
in next.config.ts
.type
matches encoding (video/mp4
, video/webm
) so source selection works..srt
require CORS headers to be fetchable for conversion.public/videos/
; use CDN for heavy media.public/videos/
. Create a new category and verify it renders on the home page under its own row..srt
subtitle to movies.json
./watch/<id>
: subtitles toggle and render correctly.Build reusable components for the catalog grid and horizontal rows.
08 Sep 2025 - a month ago