mirror of
https://github.com/yattee/yattee.git
synced 2026-10-28 15:37:17 +00:00
Play direct media links without Yattee Server by probing the URL first
Debrid and CDN download links (TorBox, Real-Debrid, presigned S3) hide the file behind an opaque path, so the extension-based direct media check missed them and every one was sent to Yattee Server for yt-dlp extraction, failing outright when no server is configured. Add DirectMediaProbe: a HEAD request classifies the response by Content-Type and Content-Disposition, and when the type is generic or HEAD is refused, a ranged GET sniffs the first bytes for container signatures (Matroska/WebM, ISO BMFF, Ogg, FLAC, MP3, RIFF, FLV, ASF, MPEG-PS/TS, HLS and DASH manifests). Anything playable goes straight to mpv with the server-reported filename as the title; everything else falls back to extraction as before. The probe runs ahead of the Yattee Server path in ExternalVideoView, both OpenLinkSheet flows and the deep-link download path, and PlayerService rebuilds direct_media streams itself so replays from history no longer depend on a server either.
This commit is contained in:
@@ -754,6 +754,12 @@ struct OpenLinkFormView: View {
|
||||
return (video, [stream])
|
||||
|
||||
case .externalVideo, nil:
|
||||
// A file mpv plays as-is needs no extraction
|
||||
if let probe = await DirectMediaProbe.probe(url) {
|
||||
let video = DirectMediaHelper.createVideo(from: url, probe: probe)
|
||||
let stream = DirectMediaHelper.createStream(from: url, probe: probe)
|
||||
return (video, [stream])
|
||||
}
|
||||
// External URL - use Yattee Server
|
||||
guard let instance = appEnvironment.instancesManager.yatteeServerInstance else {
|
||||
throw OpenLinkError.noYatteeServer
|
||||
@@ -896,6 +902,12 @@ struct OpenLinkFormView: View {
|
||||
return (video, [stream], [], [])
|
||||
|
||||
case .externalVideo, nil:
|
||||
// A file mpv plays as-is needs no extraction, no captions/storyboards
|
||||
if let probe = await DirectMediaProbe.probe(url) {
|
||||
let video = DirectMediaHelper.createVideo(from: url, probe: probe)
|
||||
let stream = DirectMediaHelper.createStream(from: url, probe: probe)
|
||||
return (video, [stream], [], [])
|
||||
}
|
||||
// External URL - use Yattee Server (doesn't support storyboards)
|
||||
guard let instance = appEnvironment.instancesManager.yatteeServerInstance else {
|
||||
throw OpenLinkError.noYatteeServer
|
||||
|
||||
@@ -59,6 +59,18 @@ struct ExternalVideoView: View {
|
||||
isLoading = true
|
||||
errorMessage = nil
|
||||
|
||||
// A file mpv can play as-is (debrid/CDN download links with an opaque
|
||||
// path) needs no extraction and no Yattee Server.
|
||||
if let probe = await DirectMediaProbe.probe(url) {
|
||||
let video = DirectMediaHelper.createVideo(from: url, probe: probe)
|
||||
let stream = DirectMediaHelper.createStream(from: url, probe: probe)
|
||||
await MainActor.run {
|
||||
shouldDismissWhenPlayerExpands = true
|
||||
appEnvironment.playerService.openVideo(video, stream: stream)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Find a Yattee Server instance
|
||||
guard let instance = appEnvironment.instancesManager.yatteeServerInstance else {
|
||||
errorMessage = String(localized: "externalVideo.noYatteeServer")
|
||||
|
||||
Reference in New Issue
Block a user