Sources/App/Coordinator.swift:178 starts a security scope for a local video file routed to the AVPlayer/AirPlay path:
_ = url.startAccessingSecurityScopedResource() // released on next load/stop
The comment is wrong. Nothing releases it:
Player.stop() (Sources/Core/Player.swift:96) only releases Player.current when item.scoped — but on this path the item was never loaded into Player at all.
AirPlayVideoPlayer.stop() (Sources/Core/AirPlayVideo.swift:62) only calls replaceCurrentItem(with: nil).
Impact — every AirPlay-routed local video play leaks one scope. iOS caps outstanding scoped resources per process; once exhausted, file access starts failing until relaunch.
Fix sketch — give AirPlayVideoPlayer the same scoped handling Player.Item has, so load/stop balance start/stop. The VLC path already models this correctly and is the pattern to copy.
Sources/App/Coordinator.swift:178starts a security scope for a local video file routed to the AVPlayer/AirPlay path:The comment is wrong. Nothing releases it:
Player.stop()(Sources/Core/Player.swift:96) only releasesPlayer.currentwhenitem.scoped— but on this path the item was never loaded intoPlayerat all.AirPlayVideoPlayer.stop()(Sources/Core/AirPlayVideo.swift:62) only callsreplaceCurrentItem(with: nil).Impact — every AirPlay-routed local video play leaks one scope. iOS caps outstanding scoped resources per process; once exhausted, file access starts failing until relaunch.
Fix sketch — give
AirPlayVideoPlayerthe samescopedhandlingPlayer.Itemhas, soload/stopbalance start/stop. The VLC path already models this correctly and is the pattern to copy.