Cache the HRN feed locally
The show ended in 2021 so the feed will never change. Rake downloads
it once to cache/ and subsequent runs read from disk.

Assisted-by: Claude Opus 4.6 via pi
change qonrtnnkrusmllssnymqzoxpyzmxxvml
commit 805211536ca008cee00ee318596894ae888b2e09
author Alpha Chen <alpha@kejadlen.dev>
date
parent otxyrsyp
diff --git a/.gitignore b/.gitignore
index 383b8bd..0f0d7fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 /audio/
+/cache/
diff --git a/Rakefile b/Rakefile
index 0d83bfc..5d1cca2 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,11 +1,29 @@
+require "fileutils"
+require "net/http"
+require "uri"
 require_relative "lib/feed"
 require_relative "lib/sync"
 
+CACHE_DIR = "cache"
+HRN_FEED = File.join(CACHE_DIR, "hrn_feed.xml")
+HRN_FEED_URL = "https://rss.art19.com/cooking-issues"
+
+directory CACHE_DIR
+
+file HRN_FEED => CACHE_DIR do
+  puts "Downloading HRN feed..."
+  uri = URI(HRN_FEED_URL)
+  response = Net::HTTP.get_response(uri)
+  raise "Feed returned #{response.code}" unless response.is_a?(Net::HTTPSuccess)
+
+  File.write(HRN_FEED, response.body)
+end
+
 task default: :sync
 
 desc "Fetch the feed, download episodes missing transcripts"
-task :sync do
-  feed = CookingIssues::Feed.new
+task sync: HRN_FEED do
+  feed = CookingIssues::Feed.new(HRN_FEED)
   episodes = feed.episodes
   puts "Found #{episodes.size} episodes in feed."
 
@@ -14,8 +32,8 @@ task :sync do
 end
 
 desc "List all episodes from the feed"
-task :episodes do
-  feed = CookingIssues::Feed.new
+task episodes: HRN_FEED do
+  feed = CookingIssues::Feed.new(HRN_FEED)
   feed.episodes.sort_by(&:number).each do |ep|
     status = Dir.glob(File.join("transcripts", "#{ep.slug}.*")).any? ? "✓" : " "
     puts "[#{status}] #{ep.number}. #{ep.title}"
diff --git a/lib/feed.rb b/lib/feed.rb
index ec9c9e2..c40d862 100644
--- a/lib/feed.rb
+++ b/lib/feed.rb
@@ -1,12 +1,8 @@
-require "net/http"
 require "nokogiri"
-require "uri"
 
 module CookingIssues
   # Parses a podcast RSS feed and returns episode data.
   class Feed
-    FEED_URL = "https://rss.art19.com/cooking-issues"
-
     Episode = Struct.new(:number, :title, :published_at, :audio_url, keyword_init: true) do
       def slug
         formatted_number = format("%03d", number)
@@ -20,24 +16,16 @@ module CookingIssues
       end
     end
 
-    def initialize(url = FEED_URL)
-      @url = url
+    def initialize(path)
+      @path = path
     end
 
     def episodes
-      @episodes ||= parse(fetch)
+      @episodes ||= parse(File.read(@path))
     end
 
     private
 
-    def fetch
-      uri = URI(@url)
-      response = Net::HTTP.get_response(uri)
-      raise "Feed returned #{response.code}" unless response.is_a?(Net::HTTPSuccess)
-
-      response.body
-    end
-
     def parse(xml)
       doc = Nokogiri::XML(xml)
       doc.xpath("//item").filter_map { |item| parse_item(item) }