Auto-apply local sidecar subtitles on iOS playback start.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
37e7aafdf5
commit
300409da06
2 changed files with 35 additions and 5 deletions
|
|
@ -52,6 +52,17 @@ struct PlayResult: Decodable {
|
||||||
let streamUrl: String
|
let streamUrl: String
|
||||||
let sessionId: String?
|
let sessionId: String?
|
||||||
let mediaFileId: String?
|
let mediaFileId: String?
|
||||||
|
let defaultSubtitle: DefaultSubtitle?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DefaultSubtitle: Decodable {
|
||||||
|
let fileId: Int?
|
||||||
|
let source: String?
|
||||||
|
let language: String?
|
||||||
|
let fileName: String?
|
||||||
|
let format: String?
|
||||||
|
let contentBase64: String
|
||||||
|
let label: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ViewerProfile: Decodable, Identifiable, Hashable {
|
struct ViewerProfile: Decodable, Identifiable, Hashable {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ struct PlayRequest: Identifiable {
|
||||||
let startMs: Int64
|
let startMs: Int64
|
||||||
let isLive: Bool
|
let isLive: Bool
|
||||||
let fallbackUrl: URL?
|
let fallbackUrl: URL?
|
||||||
|
let subtitleFileURL: URL?
|
||||||
|
|
||||||
static func vod(
|
static func vod(
|
||||||
url: URL,
|
url: URL,
|
||||||
|
|
@ -21,12 +22,13 @@ struct PlayRequest: Identifiable {
|
||||||
movieId: String?,
|
movieId: String?,
|
||||||
episodeId: String?,
|
episodeId: String?,
|
||||||
seriesId: String?,
|
seriesId: String?,
|
||||||
startMs: Int64
|
startMs: Int64,
|
||||||
|
subtitleFileURL: URL? = nil
|
||||||
) -> PlayRequest {
|
) -> PlayRequest {
|
||||||
PlayRequest(
|
PlayRequest(
|
||||||
url: url, title: title, mediaType: mediaType, mediaFileId: mediaFileId,
|
url: url, title: title, mediaType: mediaType, mediaFileId: mediaFileId,
|
||||||
movieId: movieId, episodeId: episodeId, seriesId: seriesId,
|
movieId: movieId, episodeId: episodeId, seriesId: seriesId,
|
||||||
startMs: startMs, isLive: false, fallbackUrl: nil
|
startMs: startMs, isLive: false, fallbackUrl: nil, subtitleFileURL: subtitleFileURL
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,7 +36,7 @@ struct PlayRequest: Identifiable {
|
||||||
PlayRequest(
|
PlayRequest(
|
||||||
url: url, title: title, mediaType: "live", mediaFileId: nil,
|
url: url, title: title, mediaType: "live", mediaFileId: nil,
|
||||||
movieId: nil, episodeId: nil, seriesId: nil,
|
movieId: nil, episodeId: nil, seriesId: nil,
|
||||||
startMs: 0, isLive: true, fallbackUrl: fallback
|
startMs: 0, isLive: true, fallbackUrl: fallback, subtitleFileURL: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -361,7 +363,7 @@ struct PlayerScreen: View {
|
||||||
if request.isLive {
|
if request.isLive {
|
||||||
player.playLive(url: request.url, fallback: request.fallbackUrl)
|
player.playLive(url: request.url, fallback: request.fallbackUrl)
|
||||||
} else {
|
} else {
|
||||||
player.play(url: request.url, startMs: request.startMs)
|
player.play(url: request.url, startMs: request.startMs, subtitleFileURL: request.subtitleFileURL)
|
||||||
progressTask = Task { await progressLoop() }
|
progressTask = Task { await progressLoop() }
|
||||||
}
|
}
|
||||||
try? await Task.sleep(nanoseconds: 900_000_000)
|
try? await Task.sleep(nanoseconds: 900_000_000)
|
||||||
|
|
@ -468,9 +470,26 @@ struct PlayLauncher: View {
|
||||||
guard let url = URL(string: play.streamUrl) else {
|
guard let url = URL(string: play.streamUrl) else {
|
||||||
throw ApiError.message("Ongeldige stream-URL")
|
throw ApiError.message("Ongeldige stream-URL")
|
||||||
}
|
}
|
||||||
|
var subtitleURL: URL?
|
||||||
|
if let sub = play.defaultSubtitle,
|
||||||
|
let data = Data(base64Encoded: sub.contentBase64),
|
||||||
|
!data.isEmpty {
|
||||||
|
let ext: String = {
|
||||||
|
let f = (sub.format ?? "").lowercased()
|
||||||
|
if f == "vtt" { return "vtt" }
|
||||||
|
if f == "ass" || f == "ssa" { return "ass" }
|
||||||
|
return "srt"
|
||||||
|
}()
|
||||||
|
let fileId = sub.fileId ?? 0
|
||||||
|
let path = FileManager.default.temporaryDirectory
|
||||||
|
.appendingPathComponent("vmc-auto-sub-\(fileId).\(ext)")
|
||||||
|
try data.write(to: path, options: .atomic)
|
||||||
|
subtitleURL = path
|
||||||
|
}
|
||||||
request = .vod(
|
request = .vod(
|
||||||
url: url, title: title, mediaType: mediaType, mediaFileId: mediaFileId,
|
url: url, title: title, mediaType: mediaType, mediaFileId: mediaFileId,
|
||||||
movieId: movieId, episodeId: episodeId, seriesId: seriesId, startMs: startMs
|
movieId: movieId, episodeId: episodeId, seriesId: seriesId, startMs: startMs,
|
||||||
|
subtitleFileURL: subtitleURL
|
||||||
)
|
)
|
||||||
loading = false
|
loading = false
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue