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:
go run . youtube-sync— fetches the channel Atom feed (youtube.com/feeds/videos.xml, one plain HTTP GET, no API key, no LLM) intosite/cache/youtube/videos.json.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.go run . generate-sitemap— rebuild from disk with stable lastmods.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.shand skips the whole run while the estate freeze is active (it deploys, unlike the read-only gsc-watch). Both Go commands are also guarded bysitefreeze.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
ytInitialDataJSON (both the classicvideoRendererand the modernlockupViewModelshapes), 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=offdisables 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
scripts/youtube-sync.sh # sync + page + sitemap + deployscripts/youtube-sync.sh --skip-deploycd site && go run . youtube-sync # feed fetch onlycd site && go run . generate-videos-pagecd site && go test ./youtube/...Installation
Same as the other timers (see the scripts index):
cp scripts/systemd-units/redecasas-youtube-sync.{service,timer} ~/.config/systemd/user/systemctl --user daemon-reloadsystemctl --user enable --now redecasas-youtube-sync.timer