Add podcast index: JSON mapping of article URLs to cached MP3 files
All checks were successful
CI / build-and-deploy (push) Successful in 25s

PodcastIndex.swift stores {articleUrl, filename, title, createdAt} in
App Support/podcasts/index.json. Updated on every successful download.
Enables building a podcast library view later.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Krishna Kumar
2026-05-22 15:45:38 -05:00
parent 476ed9b2a1
commit 544fcd442c
3 changed files with 59 additions and 2 deletions

View File

@@ -0,0 +1,56 @@
import Foundation
struct PodcastEntry: Codable, Identifiable {
var id: String { articleUrl }
let articleUrl: String
let filename: String
var title: String?
let createdAt: Date
}
enum PodcastIndex {
private static let indexURL: URL = {
let dir = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
.appendingPathComponent("podcasts")
return dir.appendingPathComponent("index.json")
}()
private static let encoder: JSONEncoder = {
let e = JSONEncoder()
e.dateEncodingStrategy = .iso8601
e.outputFormatting = .prettyPrinted
return e
}()
private static let decoder: JSONDecoder = {
let d = JSONDecoder()
d.dateDecodingStrategy = .iso8601
return d
}()
static func all() -> [PodcastEntry] {
guard let data = try? Data(contentsOf: indexURL),
let entries = try? decoder.decode([PodcastEntry].self, from: data)
else { return [] }
return entries.sorted { $0.createdAt > $1.createdAt }
}
static func upsert(articleUrl: String, filename: String, title: String?) {
var entries = all()
entries.removeAll { $0.articleUrl == articleUrl }
entries.insert(PodcastEntry(articleUrl: articleUrl, filename: filename,
title: title, createdAt: Date()), at: 0)
save(entries)
}
static func remove(articleUrl: String) {
var entries = all()
entries.removeAll { $0.articleUrl == articleUrl }
save(entries)
}
private static func save(_ entries: [PodcastEntry]) {
guard let data = try? encoder.encode(entries) else { return }
try? data.write(to: indexURL, options: .atomic)
}
}