[object Object]

← back to Allnewsdaily

/directory UX pass: fix dead logos, tool-first layout, live-checker consent bypass

60e002d514397bba4eec7cd649a0e9b5caf5ed17 · 2026-09-09 14:46:42 -0700 · Steve

- Logos: Clearbit's logo API is dead (NAME_NOT_RESOLVED → ~40 outlets showed text
  placeholders + 81 console errors). Switched to Google's favicon service derived
  from each outlet's domain; verified 98/98 logos now load, 0 placeholders, errors gone.
- Layout: moved the outlet grid ABOVE the intro/guides/regions editorial blocks
  (tool-first) — grid now ~365px instead of below 3 text sections; content kept below.
- Live: 0/98-live was YouTube serving a consent interstitial to prod's datacenter IP
  (Mac2 residential IP finds ~24 live). Added CONSENT/SOCS cookie + gl=US&hl=en to the
  checker's YouTube fetch to bypass it on prod. Local re-check: 24 live, no regression.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PV1DXsyryWT3rLttpPXd4u

Files touched

Diff

commit 60e002d514397bba4eec7cd649a0e9b5caf5ed17
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Sep 9 14:46:42 2026 -0700

    /directory UX pass: fix dead logos, tool-first layout, live-checker consent bypass
    
    - Logos: Clearbit's logo API is dead (NAME_NOT_RESOLVED → ~40 outlets showed text
      placeholders + 81 console errors). Switched to Google's favicon service derived
      from each outlet's domain; verified 98/98 logos now load, 0 placeholders, errors gone.
    - Layout: moved the outlet grid ABOVE the intro/guides/regions editorial blocks
      (tool-first) — grid now ~365px instead of below 3 text sections; content kept below.
    - Live: 0/98-live was YouTube serving a consent interstitial to prod's datacenter IP
      (Mac2 residential IP finds ~24 live). Added CONSENT/SOCS cookie + gl=US&hl=en to the
      checker's YouTube fetch to bypass it on prod. Local re-check: 24 live, no regression.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01PV1DXsyryWT3rLttpPXd4u
---
 public/index.html     | 20 +++++++++++++++-----
 scripts/check-live.js |  5 ++++-
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/public/index.html b/public/index.html
index f895094..6b6c5a2 100644
--- a/public/index.html
+++ b/public/index.html
@@ -148,7 +148,9 @@
       <p style="color:var(--fg-dim);font-size:15px;line-height:1.65;margin:0">
         <strong style="color:var(--fg)">All News Daily</strong> is an independent, continuously-updated directory of the world's newsrooms — searchable by region, language, and topic, with live-status indicators. We don't republish anyone's reporting; we point you to the primary sources and teach you how to weigh them. New here? Start with our <a href="/guides" style="color:var(--accent)">news-literacy guides</a> on evaluating a source, reading past media bias, and verifying a story before you share it.</p>
     </section>
-    <section class="featured" style="max-width:900px;margin:0 auto 26px">
+    <section id="grid" class="grid"></section>
+    <div id="empty" class="empty" hidden>No outlets match those filters.</div>
+    <section class="featured" style="max-width:900px;margin:0 auto 26px;margin-top:36px">
       <h2 style="font-size:17px;margin:0 0 10px;color:var(--fg)">Start here: news-literacy guides</h2>
       <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px">
         <a href="/guides/how-to-evaluate-a-news-source" style="display:block;padding:14px 16px;border:1px solid var(--line,#21262d);border-radius:10px;text-decoration:none;color:inherit;background:var(--card,#161b22)">
@@ -167,8 +169,6 @@
       <p style="margin:0 0 8px">Our index spans public broadcasters, national dailies, wire services, and independent digital outlets across the Americas, Europe, Africa, the Middle East, Asia-Pacific, and beyond — in dozens of languages. The point isn't to hand you one "correct" source; it's to make it effortless to read the same story through several independent newsrooms with different owners and vantage points, which is how the durable facts of any event actually surface.</p>
       <p style="margin:0">Use the search and filters below to browse by region, language, or topic. Outlets are listed on editorial merit and reach — inclusion is free and can't be bought — and live-status indicators show which are broadcasting right now. Then apply the <a href="/guides" style="color:var(--accent)">news-literacy guides above</a> to whatever you read.</p>
     </section>
-    <section id="grid" class="grid"></section>
-    <div id="empty" class="empty" hidden>No outlets match those filters.</div>
   </main>
 
   <footer>
@@ -212,9 +212,19 @@
         .toUpperCase();
     }
 
+    function domainOf(o) {
+      try { return new URL(o.href).hostname.replace(/^www\./, ''); }
+      catch (e) {
+        // fallback: pull the domain out of a legacy clearbit logo URL
+        return (o.logo || '').replace(/^https?:\/\/logo\.clearbit\.com\//, '').replace(/^www\./, '');
+      }
+    }
     function logoHtml(o) {
-      if (!o.logo) return `<div class="logo-wrap placeholder">${initials(o.name)}</div>`;
-      return `<div class="logo-wrap"><img loading="lazy" decoding="async" alt="${o.name} logo" src="${o.logo}" onerror="this.parentElement.classList.add('placeholder');this.parentElement.innerHTML='${initials(o.name)}';"></div>`;
+      const d = domainOf(o);
+      if (!d) return `<div class="logo-wrap placeholder">${initials(o.name)}</div>`;
+      // Clearbit's free logo API is dead (NAME_NOT_RESOLVED); Google's favicon service is reliable.
+      const src = `https://www.google.com/s2/favicons?sz=128&domain=${encodeURIComponent(d)}`;
+      return `<div class="logo-wrap"><img loading="lazy" decoding="async" alt="${o.name} logo" src="${src}" onerror="this.parentElement.classList.add('placeholder');this.parentElement.innerHTML='${initials(o.name)}';"></div>`;
     }
 
     function cardHtml(o) {
diff --git a/scripts/check-live.js b/scripts/check-live.js
index 9bff5ab..8e72b1e 100644
--- a/scripts/check-live.js
+++ b/scripts/check-live.js
@@ -27,6 +27,9 @@ function fetchHtml(url, timeoutMs = 8000) {
           'User-Agent': UA,
           'Accept-Language': 'en-US,en;q=0.9',
           Accept: 'text/html,application/xhtml+xml',
+          // Bypass YouTube's consent/cookie interstitial (served to datacenter IPs like prod,
+          // which otherwise returns a consent page with no live markers → false "not live").
+          Cookie: 'CONSENT=YES+1; SOCS=CAI',
         },
       },
       res => {
@@ -79,7 +82,7 @@ async function checkOne(outlet) {
   if (outlet.liveCheck !== 'youtube' || !outlet.youtube) {
     return { id: outlet.id, isLive: false, videoId: null, skipped: true };
   }
-  const url = `https://www.youtube.com/channel/${outlet.youtube}/live`;
+  const url = `https://www.youtube.com/channel/${outlet.youtube}/live?gl=US&hl=en`;
   try {
     const html = await fetchHtml(url);
     const { isLive, videoId } = detectLive(html);

← e2504ec Banner zones: auto-fallback house banner while AdSense unit  ·  back to Allnewsdaily  ·  Live feature: LIVE_STATIC mode + Mac2 push (consent-cookie f 7620db7 →