Skip to content

Movies: rework schema for new upstream + add Category/Type filters#1425

Merged
andygrunwald merged 9 commits intomainfrom
andygrunwald/movies-schema-rework-and-filters
May 5, 2026
Merged

Movies: rework schema for new upstream + add Category/Type filters#1425
andygrunwald merged 9 commits intomainfrom
andygrunwald/movies-schema-rework-and-filters

Conversation

@andygrunwald
Copy link
Copy Markdown
Contributor

Summary

Upstream awesome-software-engineering-movies reshaped its generated/ JSON: a single link is now a links map, new category/type fields drive the taxonomy, IMDb ratings and per-language overrides arrived, and several previously-required fields (duration, publishedAt, channel, language) can now be empty for non-YouTube entries (Netflix/bpb/...).

The Astro build was failing under the old Zod schema. This PR realigns the website with the new upstream shape, replaces the per-tag listing pages with per-category and per-type pages, and adds two client-side filters on the movies index in the same style as /deutsche-tech-podcasts/.

Three commits

  1. Migrate movies collection to new upstream schema — schema rewrite, German display-label helpers (src/scripts/movie-labels.js), reworked card (linked Category + Type badges, multi-platform link buttons, IMDb row, hide-empty rows, localized title/description via localized.de), per-category and per-type static pages with German URL slugs (/kategorie-programmiersprachen/, /typ-dokumentation/), per-tag page deleted. JSON-LD adapted to drop fields that may be empty and to emit aggregateRating from ratings.imdb.
  2. Add Category and Type filters to movie listing — two inline <select> dropdowns; client-side public/js/movie-listing-filter.js that AND-combines the two filters by toggling .hidden on each .movie section via data-category / data-type. Dropdown labels are German; option values are the raw English data values.
  3. Refresh movies tag description stubs — new upstream snapshot expanded unique tag count from 27 to 51; re-ran tags find --write-file.

Schema changes (src/content.config.ts)

  • link / videoID / viewCount removed
  • links: z.record(z.string(), z.string().url())
  • category, type: open strings (display labels live in JS)
  • language, subtitles: nullable arrays
  • ratings.youtube / ratings.imdb / views.youtube / imdbID / youtubeTrailerForThumbnail / localized: optional
  • duration, publishedAt, channel.id, channel.title allowed empty

URL structure

  • /filme-fuer-softwareentwickler/<tag>-filme/ — gone
  • /filme-fuer-softwareentwickler/kategorie-programmiersprachen/
  • /filme-fuer-softwareentwickler/kategorie-kultur-gesellschaft/
  • /filme-fuer-softwareentwickler/kategorie-kultur-personen/
  • /filme-fuer-softwareentwickler/kategorie-anwendungen-frameworks-systeme/
  • /filme-fuer-softwareentwickler/typ-dokumentation/ (and future typ-film/, typ-tv-serie/ once those entries appear upstream)

Test plan

  • make build — 472 pages built (was failing on main)
  • Index renders all 32 movies; filter dropdowns appear (only when JS runs); selecting Category + Type narrows correctly; "no match" fallback shows when combination has 0 hits
  • Linked badges navigate to the correct per-category / per-type page
  • the-great-hack: German localized.de.title ("Cambridge Analyticas großer Hack") rendered, Netflix link present, IMDb row "7,0 / 10 (25.799 Bewertungen)"
  • the-cleaners: German localized.de.description rendered, bpb link present, IMDb row "7,1"
  • angular-the-documentary: Category badge → kategorie-anwendungen-frameworks-systeme, Type badge → typ-dokumentation, YouTube link, data-category="Applications / Frameworks / Systems" data-type="Documentary"
  • Visual review on staging
  • Validate JSON-LD on the index against schema.org once deployed

🤖 Generated with Claude Code

andygrunwald and others added 3 commits May 5, 2026 11:45
The awesome-software-engineering-movies repository reshaped its generated
JSON: a single `link` is now a `links` map (youtube/netflix/bpb/...), new
`category` and `type` fields drive the taxonomy, IMDb ratings live under
`ratings.imdb`, and per-language overrides come through a `localized` map.
Several previously-required fields (duration, publishedAt, channel,
language) can now be empty for non-YouTube entries. The build was failing
under the old Zod schema, so this commit aligns the Astro side with the
new shape and reworks the consuming UI in one step.

Schema change in src/content.config.ts:
  - link/videoID/viewCount removed
  - links: open record of platform -> URL
  - category, type: open strings (display labels live in JS)
  - language, subtitles: nullable arrays
  - ratings.youtube, ratings.imdb, views.youtube, imdbID,
    youtubeTrailerForThumbnail, localized: optional
  - duration / publishedAt / channel.* allowed empty

src/scripts/movie-labels.js owns the German translation maps so the JSON
stays in English (no upstream churn) while the UI reads German. It also
exports the label-driven slug helpers used by the per-category and
per-type listing pages, plus localizedTitle/Description that prefer
movie.data.localized.de fields when present and fall through name/title
otherwise.

The card now:
  - links category and type badges to the new listing pages
  - renders tags as plain (unlinked) chips
  - shows every entry in `links` as its own platform button (YouTube has
    a brand SVG today; the rest fall back to a generic external-link icon)
  - hides Dauer/Veröffentlicht/Sprache/Untertitel rows when the data is
    empty
  - shows an IMDb rating row formatted with German number formatting when
    ratings.imdb is present
  - exposes data-category / data-type for client-side filtering

Per-tag page is gone. Two new static routes take its place:
  /filme-fuer-softwareentwickler/kategorie-<de-slug>/
  /filme-fuer-softwareentwickler/typ-<de-slug>/

Slugs are derived from the German display label (kategorie-programmiersprachen,
typ-dokumentation), keeping URLs in line with the rest of the German UI.
The page filters use the raw English data value carried in props.

JSON-LD was tightened up to drop fields that may no longer be present and
to emit aggregateRating from ratings.imdb when available.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror the /deutsche-tech-podcasts/ filter pattern: two inline <select>
dropdowns above the listing, a small client-side script that toggles
.hidden on each .movie section based on data-category and data-type, and
a "Leider passt kein Film zu deinen Filterkriterien :(" fallback section
when no entry matches. The filter bar starts invisible and is unhidden on
DOMContentLoaded so the static, no-JS page still shows every movie.

Dropdown options are sourced from the actual data so brand-new categories
or types show up the next sync without code changes. Labels in the
dropdowns are German via the CATEGORY_LABELS / TYPE_LABELS maps; the
underlying option value is the raw English string the cards carry in
their data attributes, so the comparison stays trivial.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The new upstream snapshot expanded the unique-tag list from 27 to 51
entries (Privacy, Social Media, Politics, Content Moderation, Ethics,
... appear with the Culture-themed documentaries). Re-run
"./website-admin tags find awesome-software-engineering-movies
--write-file" to add stubs for the new tags and refresh usage_count
across the board. SEO descriptions are left blank for the editorial team
to fill in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@netlify
Copy link
Copy Markdown

netlify Bot commented May 5, 2026

Deploy Preview for nifty-bardeen-5c7e53 ready!

Name Link
🔨 Latest commit d263ae3
🔍 Latest deploy log https://app.netlify.com/projects/nifty-bardeen-5c7e53/deploys/69f9c547a1d8180008ecb81a
😎 Deploy Preview https://deploy-preview-1425--nifty-bardeen-5c7e53.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

andygrunwald and others added 6 commits May 5, 2026 11:55
The card now shows recognisable brand artwork for the streaming
platforms that already appear in the upstream data, instead of falling
back to a generic external-link icon.

  - Netflix wordmark from simple-icons (CC0), tinted with the brand red
    #E50914 since simple-icons ships path-only SVGs.
  - Amazon Prime Video wordmark from Wikimedia Commons.

Both files live next to the existing youtube.svg under
public/images/brands/. movie-labels.js' KNOWN_BRAND_ICONS set was
extended so iconFor() picks them up automatically.

Drive-bys requested in the same review:
  - Removed `disneyplus` from LINK_PLATFORM_LABELS and from the
    PLATFORM_ORDER constants in the card component and the JSON-LD
    builder. There's no entry on disneyplus today and dragging the slug
    around just invites a stale fallback icon if one ever appears.
  - Replaced the abbreviated `bpb` label with the full
    "Bundeszentrale für politische Bildung" so visitors who don't know
    the acronym still get the context.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a movie carries an imdbID, wrap the literal "IMDb" word in the
ratings line in an anchor that points at https://www.imdb.com/title/<id>/.
Visitors who want to read user reviews or check the cast can do so with
one click instead of having to search for the title manually. Falls back
to plain text when imdbID is absent (in practice the upstream couples
imdbID with ratings.imdb, but the guard keeps the markup safe if that
ever drifts).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Above the headline only the Category and Type stay — those are the
high-signal navigation entry points and they were getting visually
crowded out by 4-6 tag chips per card. Tags move into a "Tags:" row in
the same <ul> as Dauer / Veröffentlicht / Sprache, keeping the badge
styling for visual consistency. The row only renders when the entry
actually has tags.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The upstream `title` field often carries a marketing subtitle, e.g.
"Angular: The Documentary | An origin story". The `name` field is the
short canonical version ("Angular: The Documentary") and reads better in
the listing where the headline already competes with badges, tags and
the description. Reorder localizedTitle's fallback chain so `name` wins
over `title`; the German `localized.de.title` override still takes
precedence for entries like The Great Hack ("Cambridge Analyticas großer
Hack").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adding the Tags and IMDb rows to the metadata bullet list pushed the
total card height up enough that the 600-character description was
crowding everything below it off screen on the listing. 400 is a more
balanced teaser length now that more metadata sits inside each card.

Pass the override at the call site rather than retuning
truncateDescription's default — the helper stays generic for any future
non-movie caller.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Upstream descriptions are scraped verbatim from the source platform and
frequently contain http(s):// URLs (e.g., a Patreon link in the IRC
documentary blurb, a Laravel-swag bit.ly in the Laravel origin story, an
IMDb back-link in Revolution OS). Rendering them as plain text was
unhelpful — visitors who want to follow the reference had to copy the
URL by hand.

Add a small `linkify` helper to src/scripts/text.js that splits a string
into a sequence of plain-text and URL segments, stripping trailing
sentence punctuation off the matched URL so "...visit https://x.com."
doesn't link the period. The movie preview component then renders each
segment, wrapping link segments in an <a target="_blank" rel="noopener">.

Truncation still happens before linkification, so the smart-cut keeps
URLs whole (URLs contain no whitespace, so the cut moves past them) and
the helper sees exactly what gets rendered.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@andygrunwald andygrunwald merged commit 206d2af into main May 5, 2026
6 checks passed
@andygrunwald andygrunwald deleted the andygrunwald/movies-schema-rework-and-filters branch May 5, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant