import Foundation import Darwin struct StreamQueue: Sendable { struct Entry: Sendable { let url: URL let identity: String let progressFile: URL let label: String } let entries: [Entry] private struct Document: Decodable { struct Item: Decodable { let url: String; let progress_file: String } let version: Int let items: [Item] } private struct InvalidQueue: LocalizedError { var errorDescription: String? { "Invalid stream queue: expected version 1, 1–4096 unique supported videos and new absolute report files in private owned directories." } } static func load(from file: URL) throws -> StreamQueue { do { guard file.isFileURL, file.path.hasPrefix("/") else { throw InvalidQueue() } let descriptor = Darwin.open(file.path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW | O_CLOEXEC) guard descriptor >= 0 else { throw InvalidQueue() } let handle = FileHandle(fileDescriptor: descriptor, closeOnDealloc: true) defer { try? handle.close() } var info = stat() guard fstat(descriptor, &info) == 0, (info.st_mode & S_IFMT) == S_IFREG else { throw InvalidQueue() } let data = try handle.read(upToCount: 8 * 1024 * 1024 + 1) ?? Data() guard data.count <= 8 * 1024 * 1024 else { throw InvalidQueue() } let document = try JSONDecoder().decode(Document.self, from: data) guard document.version == 1, (1...4096).contains(document.items.count) else { throw InvalidQueue() } var identities = Set() var reports = Set() let entries = try document.items.map { item -> Entry in let stream = try StreamURL.parse(item.url) let url: URL let identity: String let label: String switch stream { case .youtube(let canonical): url = canonical identity = canonical.absoluteString label = "YouTube · " + (URLComponents(url: canonical, resolvingAgainstBaseURL: false)?.queryItems?.first?.value ?? "Video") case .miruro(let mediaID, let episode): url = URL(string: item.url)! identity = "miruro:\(mediaID):\(episode)" label = "\(url.lastPathComponent.replacingOccurrences(of: "-", with: " ")) · Episode \(episode)" } guard identities.insert(identity).inserted, item.progress_file.hasPrefix("/"), !item.progress_file.contains("\0") else { throw InvalidQueue() } let report = URL(fileURLWithPath: item.progress_file).standardizedFileURL let parent = report.deletingLastPathComponent() var directoryInfo = stat() guard lstat(parent.path, &directoryInfo) == 0, (directoryInfo.st_mode & S_IFMT) == S_IFDIR, directoryInfo.st_uid == geteuid(), (directoryInfo.st_mode & 0o777) == 0o700, parent.resolvingSymlinksInPath().path == parent.path, reports.insert(report.path).inserted else { throw InvalidQueue() } var existing = stat() guard lstat(report.path, &existing) != 0, errno == ENOENT else { throw InvalidQueue() } return Entry(url: url, identity: identity, progressFile: report, label: label) } return StreamQueue(entries: entries) } catch { throw InvalidQueue() } } }