← back to AsSeenInMovies
asseeninmovies: SEO surface — inline SVG favicon (data: URI, kills /favicon.ico 404s), JSON-LD Movie schema on /movie/:id, JSON-LD Person schema on /person/:id, Open Graph + Twitter Card meta tags on both, meta description on home page. htmlShell now accepts optional headExtras fragment.
b59fa66d769feaf94f0a79d0055fdfcebd2bc129 · 2026-05-12 18:20:36 -0700 · SteveStudio2
Files touched
Diff
commit b59fa66d769feaf94f0a79d0055fdfcebd2bc129
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Tue May 12 18:20:36 2026 -0700
asseeninmovies: SEO surface — inline SVG favicon (data: URI, kills /favicon.ico 404s), JSON-LD Movie schema on /movie/:id, JSON-LD Person schema on /person/:id, Open Graph + Twitter Card meta tags on both, meta description on home page. htmlShell now accepts optional headExtras fragment.
---
server.js | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 67 insertions(+), 3 deletions(-)
diff --git a/server.js b/server.js
index 151f175..9f47069 100644
--- a/server.js
+++ b/server.js
@@ -841,11 +841,13 @@ function imageCreditHtml(credit, license, sourceUrl, sourceKind) {
return `<span class="img-credit">Photo: ${artistPart}${licPart}<a href="${esc(sourceUrl)}" rel="nofollow noopener" target="_blank">source</a></span>`;
}
-function htmlShell(title, body) {
+function htmlShell(title, body, headExtras = '') {
return `<!doctype html>
<html lang="en"><head>
<meta charset="utf-8"><title>${esc(title)} · AsSeenInMovies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
+<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='6' fill='%230d0c0a'/%3E%3Ctext x='16' y='22' font-family='Georgia,serif' font-style='italic' font-size='20' fill='%23c9a14b' text-anchor='middle'%3EA%3C/text%3E%3C/svg%3E">
+${headExtras}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;1,400&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
@@ -1005,7 +1007,38 @@ app.get('/movie/:id', async (req, res) => {
</div>`).join('')}
`).join('');
- res.type('html').send(htmlShell(mv.title || ('Movie #' + id), heroHtml + spottedHtml + (creditsHtml ? `<section><h2>Cast & crew</h2>${creditsHtml}</section>` : '')));
+ // JSON-LD Movie schema + Open Graph + Twitter Card for share previews
+ // and rich snippets. The poster_url goes into og:image (preferring real
+ // posters over the made-with-ai placeholder).
+ const ogImage = mv.poster_url && (mv.poster_source || '').toLowerCase() !== 'made-with-ai'
+ ? mv.poster_url
+ : 'https://asseeninmovies.com/img/made-with-ai.svg';
+ const ogDesc = mv.overview ? mv.overview.slice(0, 280) : `${mv.title}${mv.release_year ? ' (' + mv.release_year + ')' : ''} — credits, scene details, and SPOTTED placements on AsSeenInMovies.`;
+ const jsonLd = JSON.stringify({
+ '@context': 'https://schema.org',
+ '@type': 'Movie',
+ name: mv.title,
+ ...(mv.release_year ? { datePublished: String(mv.release_year) } : {}),
+ ...(mv.overview ? { description: mv.overview } : {}),
+ ...(mv.poster_url ? { image: ogImage } : {}),
+ ...(mv.imdb_id ? { sameAs: `https://www.imdb.com/title/${mv.imdb_id}/` } : {}),
+ ...(mv.genres && mv.genres.length ? { genre: mv.genres } : {}),
+ ...(mv.runtime_min ? { duration: `PT${mv.runtime_min}M` } : {}),
+ url: `https://asseeninmovies.com/movie/${id}`,
+ });
+ const headExtras = `
+<meta name="description" content="${esc(ogDesc)}">
+<meta property="og:type" content="video.movie">
+<meta property="og:title" content="${esc(mv.title || 'Untitled')}">
+<meta property="og:description" content="${esc(ogDesc)}">
+<meta property="og:image" content="${esc(ogImage)}">
+<meta property="og:url" content="https://asseeninmovies.com/movie/${id}">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:title" content="${esc(mv.title || 'Untitled')}">
+<meta name="twitter:description" content="${esc(ogDesc)}">
+<meta name="twitter:image" content="${esc(ogImage)}">
+<script type="application/ld+json">${jsonLd}</script>`;
+ res.type('html').send(htmlShell(mv.title || ('Movie #' + id), heroHtml + spottedHtml + (creditsHtml ? `<section><h2>Cast & crew</h2>${creditsHtml}</section>` : ''), headExtras));
} catch (e) {
res.status(500).type('html').send(htmlShell('Error', `<div class="empty">${esc(e.message)}</div>`));
}
@@ -1085,7 +1118,36 @@ app.get('/person/:id', async (req, res) => {
</div>`).join('')}
</section>` : '';
- res.type('html').send(htmlShell(person.full_name, heroHtml + filmHtml + personSpottedHtml));
+ const ogImage = person.headshot_url && (person.headshot_source || '').toLowerCase() !== 'made-with-ai'
+ ? person.headshot_url
+ : 'https://asseeninmovies.com/img/made-with-ai.svg';
+ const profProf = (person.primary_profession || []).slice(0, 2).join(', ') || 'film professional';
+ const ogDesc = `${person.full_name} — ${profProf}${person.birth_year ? ', born ' + person.birth_year : ''}. Filmography and verified SPOTTED placements on AsSeenInMovies.`;
+ const jsonLd = JSON.stringify({
+ '@context': 'https://schema.org',
+ '@type': 'Person',
+ name: person.full_name,
+ ...(person.bio ? { description: person.bio.slice(0, 800) } : {}),
+ ...(person.headshot_url ? { image: ogImage } : {}),
+ ...(person.imdb_id ? { sameAs: `https://www.imdb.com/name/${person.imdb_id}/` } : {}),
+ ...(person.birth_year ? { birthDate: String(person.birth_year) } : {}),
+ ...(person.death_year ? { deathDate: String(person.death_year) } : {}),
+ ...(person.primary_profession && person.primary_profession.length ? { jobTitle: person.primary_profession[0] } : {}),
+ url: `https://asseeninmovies.com/person/${id}`,
+ });
+ const headExtras = `
+<meta name="description" content="${esc(ogDesc)}">
+<meta property="og:type" content="profile">
+<meta property="og:title" content="${esc(person.full_name)}">
+<meta property="og:description" content="${esc(ogDesc)}">
+<meta property="og:image" content="${esc(ogImage)}">
+<meta property="og:url" content="https://asseeninmovies.com/person/${id}">
+<meta name="twitter:card" content="summary_large_image">
+<meta name="twitter:title" content="${esc(person.full_name)}">
+<meta name="twitter:description" content="${esc(ogDesc)}">
+<meta name="twitter:image" content="${esc(ogImage)}">
+<script type="application/ld+json">${jsonLd}</script>`;
+ res.type('html').send(htmlShell(person.full_name, heroHtml + filmHtml + personSpottedHtml, headExtras));
} catch (e) {
res.status(500).type('html').send(htmlShell('Error', `<div class="empty">${esc(e.message)}</div>`));
}
@@ -1382,6 +1444,8 @@ app.get('/', async (_req, res) => {
<html lang="en"><head>
<meta charset="utf-8"><title>AsSeenInMovies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
+<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='6' fill='%230d0c0a'/%3E%3Ctext x='16' y='22' font-family='Georgia,serif' font-style='italic' font-size='20' fill='%23c9a14b' text-anchor='middle'%3EA%3C/text%3E%3C/svg%3E">
+<meta name="description" content="AsSeenInMovies — a film + TV reference built on public data. Browse 290k+ movies, 61k+ people, and verified SPOTTED set decor, wallcoverings, lighting, and props from the films you love.">
<style>
:root { --bg:#0d0c0a; --ink:#f0ebe3; --gold:#c9a14b; --muted:#7a706a; --line:#2a2620; }
*,*::before,*::after { box-sizing: border-box; }
← bbaae4b asseeninmovies: GET /sitemap.xml + /robots.txt — XML sitemap
·
back to AsSeenInMovies
·
asseeninmovies: GET /favicon.ico fallback — same inline SVG 2261023 →