[object Object]

← 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 &amp; 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 &amp; 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 →