feat: receive ordered stream playback queues

This commit is contained in:
2026-10-22 14:06:47 +02:00
parent e7a33ff68e
commit 70672321a1
9 changed files with 239 additions and 7 deletions
+69
View File
@@ -0,0 +1,69 @@
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<String>()
var reports = Set<String>()
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() }
}
}