fix: populate queue titles independently of playback extraction
The sidebar scheduler waited for playback and used full stream extraction for titles. Use independent utility-priority title requests, native YouTube oEmbed, and metadata-only extraction for generic sites. Preserve foreground title precedence and stale row protection. Verified: make check-youtube check-queue check-resolved check-adaptive check-stream all.
This commit is contained in:
+10
-12
@@ -187,6 +187,7 @@ final class PlayerModel: ObservableObject {
|
||||
private var reportingErrorShown = false
|
||||
private var reportingErrorBuffer = [CChar]()
|
||||
private let youtubeResolver: @MainActor (URL, Int?) async throws -> YouTubeVideo
|
||||
private let youtubeTitleResolver: @MainActor (URL) async throws -> String?
|
||||
private let miruroResolver: @MainActor (String, Int) async throws -> ResolvedSource
|
||||
private let miruroMetadataResolver: @MainActor (String, Int) async throws -> MiruroMetadata
|
||||
private var reportingErrorMessage: String {
|
||||
@@ -196,6 +197,7 @@ final class PlayerModel: ObservableObject {
|
||||
init(defaults: UserDefaults = .standard, configuration: PlayerConfiguration = PlayerConfiguration(),
|
||||
progressFile: String? = nil, streamQueue: StreamQueue? = nil,
|
||||
youtubeResolver: @escaping @MainActor (URL, Int?) async throws -> YouTubeVideo = { try await YouTubeResolver.resolve($0, height: $1) },
|
||||
youtubeTitleResolver: @escaping @MainActor (URL) async throws -> String? = { try await YouTubeResolver.resolveTitle($0) },
|
||||
miruroResolver: @escaping @MainActor (String, Int) async throws -> ResolvedSource = { try await MiruroResolver.resolve(mediaID: $0, episode: $1) },
|
||||
miruroMetadataResolver: @escaping @MainActor (String, Int) async throws -> MiruroMetadata = { try await MiruroMetadataResolver.resolve(mediaID: $0, episode: $1) },
|
||||
qualityClock: @escaping () -> Double = { ProcessInfo.processInfo.systemUptime },
|
||||
@@ -203,6 +205,7 @@ final class PlayerModel: ObservableObject {
|
||||
self.qualityClock = qualityClock
|
||||
self.skipClock = skipClock
|
||||
self.youtubeResolver = youtubeResolver
|
||||
self.youtubeTitleResolver = youtubeTitleResolver
|
||||
self.miruroResolver = miruroResolver
|
||||
self.miruroMetadataResolver = miruroMetadataResolver
|
||||
keyBindings = configuration.keys
|
||||
@@ -656,7 +659,6 @@ final class PlayerModel: ObservableObject {
|
||||
}
|
||||
|
||||
private func cancelStreamResolution() {
|
||||
cancelQueueMetadata()
|
||||
guard transition.isResolving else { return }
|
||||
objectWillChange.send()
|
||||
transition.cancelResolution()
|
||||
@@ -681,18 +683,14 @@ final class PlayerModel: ObservableObject {
|
||||
}
|
||||
|
||||
private func resolveQueueMetadataIfNeeded() {
|
||||
// Playback and quality changes own the network before sidebar enrichment.
|
||||
guard !isBusy, !resolvingStream, !state.buffering else {
|
||||
cancelQueueMetadata()
|
||||
return
|
||||
}
|
||||
// One utility-priority title lookup runs alongside (never behind) stream extraction.
|
||||
if let request = queueMetadataTask,
|
||||
!queue.items.contains(where: { $0.id == request.id }) {
|
||||
cancelQueueMetadata()
|
||||
}
|
||||
guard queueMetadataPending, queueMetadataTask == nil else { return }
|
||||
guard let item = queue.items.first(where: {
|
||||
!$0.url.isFileURL && $0.id != queue.currentID && !$0.metadataAttempted
|
||||
!$0.url.isFileURL && !$0.metadataAttempted
|
||||
}) else {
|
||||
queueMetadataPending = false
|
||||
return
|
||||
@@ -701,16 +699,14 @@ final class PlayerModel: ObservableObject {
|
||||
queue.updateLabel(nil, for: item.id)
|
||||
return
|
||||
}
|
||||
let youtube = youtubeResolver
|
||||
let youtube = youtubeTitleResolver
|
||||
let miruro = miruroMetadataResolver
|
||||
let task = Task(priority: .utility) { [weak self] in
|
||||
let title: String?
|
||||
do {
|
||||
switch stream {
|
||||
case .youtube(let url):
|
||||
let video = try await youtube(url, nil)
|
||||
guard video.webpageURL == url else { throw CocoaError(.fileReadCorruptFile) }
|
||||
title = video.title
|
||||
title = try await youtube(url)
|
||||
case .miruro(let id, let episode):
|
||||
title = try await miruro(id, episode).title
|
||||
}
|
||||
@@ -719,7 +715,8 @@ final class PlayerModel: ObservableObject {
|
||||
title = nil
|
||||
}
|
||||
guard !Task.isCancelled, let self else { return }
|
||||
if self.queue.currentID != item.id {
|
||||
// Full playback/episode metadata may have populated this row while we waited.
|
||||
if self.queue.items.first(where: { $0.id == item.id })?.metadataAttempted == false {
|
||||
self.queue.updateLabel(title, for: item.id)
|
||||
}
|
||||
self.queueMetadataTask = nil
|
||||
@@ -1559,6 +1556,7 @@ final class PlayerModel: ObservableObject {
|
||||
if castDevice != nil { stopCasting(resume: false) }
|
||||
castDiscovery.stop()
|
||||
cancelStreamResolution()
|
||||
cancelQueueMetadata()
|
||||
replaceMetadata(for: nil)
|
||||
selectSubtitle(nil)
|
||||
systemPlayback?.shutdown()
|
||||
|
||||
Reference in New Issue
Block a user