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
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) }