From c5137a8af8dae7384434ca05220ba5edaf91f201 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Sun, 23 Nov 2025 14:20:28 +0100 Subject: [PATCH] Prefer fast-loading formats when switching to AVPlayer When switching from MPV to AVPlayer, prioritize HLS and stream formats over non-streamable MP4/AVC1 formats to avoid long loading times. Changes: - Added isFastLoadingFormat() helper to AVPlayerBackend - Modified streamByQualityProfile to prefer fast-loading formats for AVPlayer - Falls back to non-streamable formats only if no fast-loading option exists - Ensures quick backend switching without waiting for metadata download --- Model/Player/Backends/AVPlayerBackend.swift | 6 ++++++ Model/Player/PlayerQueue.swift | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Model/Player/Backends/AVPlayerBackend.swift b/Model/Player/Backends/AVPlayerBackend.swift index 2548ad1c..02199afd 100644 --- a/Model/Player/Backends/AVPlayerBackend.swift +++ b/Model/Player/Backends/AVPlayerBackend.swift @@ -178,6 +178,12 @@ final class AVPlayerBackend: PlayerBackend { return stream.kind == .hls || stream.kind == .stream } + func isFastLoadingFormat(_ stream: Stream) -> Bool { + // HLS and stream formats load quickly + // Non-streamable MP4/AVC1 formats may take a long time + return stream.kind == .hls || stream.kind == .stream + } + func playStream( _ stream: Stream, of video: Video, diff --git a/Model/Player/PlayerQueue.swift b/Model/Player/PlayerQueue.swift index b24dec4f..ef06b4b3 100644 --- a/Model/Player/PlayerQueue.swift +++ b/Model/Player/PlayerQueue.swift @@ -133,6 +133,26 @@ extension PlayerModel { let profile = qualityProfile ?? .defaultProfile + // For AVPlayer, prefer fast-loading formats (HLS/stream) over non-streamable formats + // to avoid long loading times when switching backends + if activeBackend == .appleAVPlayer, let avBackend = backend as? AVPlayerBackend { + // Try to find a fast-loading stream first + let fastLoadingStreams = availableStreams.filter { backend.canPlay($0) && avBackend.isFastLoadingFormat($0) } + if let fastStream = backend.bestPlayable( + fastLoadingStreams.filter { profile.isPreferred($0) }, + maxResolution: profile.resolution, formatOrder: profile.formats + ) { + return fastStream + } + // Fallback to any fast-loading stream + if let fastStream = backend.bestPlayable( + fastLoadingStreams, + maxResolution: profile.resolution, formatOrder: profile.formats + ) { + return fastStream + } + } + // First attempt: Filter by both `canPlay` and `isPreferred` if let streamPreferredForProfile = backend.bestPlayable( availableStreams.filter { backend.canPlay($0) && profile.isPreferred($0) },