Pular para o conteúdo

YouTube Videos Page (youtube-sync)

YouTube Videos Page

scripts/youtube-sync.sh (systemd unit redecasas-youtube-sync.timer, 04:30 daily) keeps the /videos/ page — the listing of the RedeCasas TV channel videos — in sync with the channel. It runs four steps:

  1. go run . youtube-sync — fetches the channel Atom feed (youtube.com/feeds/videos.xml, one plain HTTP GET, no API key, no LLM) into site/cache/youtube/videos.json.
  2. go run . generate-videos-page — renders /videos/ from the disk cache only; a missing cache renders an empty state with the channel CTA, never a network fetch.
  3. go run . generate-sitemap — rebuild from disk with stable lastmods.
  4. go run . smart-deploy --yes --scope videos/ --scope sitemap --scope robots.txt — a handful of mutations, far under the 500 gate. When the channel published nothing new, the page renders byte-identical and the deploy uploads nothing.

Doctrine

  • A zero-entry or failed feed is never cached (the #225 anti-poisoning rule): the run fails, the page keeps the previous snapshot, and the next timer tick retries. Emptiness must not freeze as truth.
  • The page is deterministic — dates come from the feed, not the wall clock, so unchanged content keeps its sitemap lastmod (the October 2026 post-mortem rule).
  • Freeze-gated: the script sources scripts/lib/freeze.sh and skips the whole run while the estate freeze is active (it deploys, unlike the read-only gsc-watch). Both Go commands are also guarded by sitefreeze.RequireNotFrozen.

The channel-page fallback

YouTube does not generate the Atom feed for brand-new channels (it 404s), and it can lag after that. When the feed errors, the sync falls back to the channel’s public /videos page and writes the same cache slot with "source":"channel-page" — the same primary-plus-fallback shape as serper + deepsearch:

  • Video renderers are discovered by recursively walking the page’s ytInitialData JSON (both the classic videoRenderer and the modern lockupViewModel shapes), so YouTube’s shifting markup does not break it.
  • Absolute publish dates and descriptions come from each new video’s watch page (ytInitialPlayerResponse); already-cached IDs are reused without a refetch, so steady state is one or two requests.
  • Relative “há 2 h” timestamps are never cached — only absolute dates keep page bytes stable.
  • YOUTUBE_FALLBACK=off disables the fallback (a feed error then fails the sync; the page keeps the previous snapshot either way).

The channel ID

The Atom feed is addressed by channel ID (UC...), not by handle. The sync resolves @RedeCasasTv → ID by scraping the channel page; hosts that only reach YouTube’s consent wall must set YOUTUBE_CHANNEL_ID (from YouTube Studio → Settings → Channel → Advanced) in .env. The env override always wins and skips the scrape.

Manual runs

Terminal window
scripts/youtube-sync.sh # sync + page + sitemap + deploy
scripts/youtube-sync.sh --skip-deploy
cd site && go run . youtube-sync # feed fetch only
cd site && go run . generate-videos-page
cd site && go test ./youtube/...

Installation

Same as the other timers (see the scripts index):

Terminal window
cp scripts/systemd-units/redecasas-youtube-sync.{service,timer} ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now redecasas-youtube-sync.timer