mirror of
https://github.com/yattee/yattee.git
synced 2025-08-06 10:44:06 +00:00
CC support with Invidious and MPV
This commit is contained in:
@@ -428,7 +428,8 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
||||
keywords: json["keywords"].arrayValue.compactMap { $0.string },
|
||||
streams: extractStreams(from: json),
|
||||
related: extractRelated(from: json),
|
||||
chapters: extractChapters(from: description)
|
||||
chapters: extractChapters(from: description),
|
||||
captions: extractCaptions(from: json)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -566,4 +567,17 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
||||
channel: Channel(id: channelId, name: author)
|
||||
)
|
||||
}
|
||||
|
||||
private func extractCaptions(from content: JSON) -> [Captions] {
|
||||
content["captions"].arrayValue.compactMap { details in
|
||||
guard let baseURL = account.url,
|
||||
let url = URL(string: baseURL + details["url"].stringValue) else { return nil }
|
||||
|
||||
return Captions(
|
||||
label: details["label"].stringValue,
|
||||
code: details["language_code"].stringValue,
|
||||
url: url
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
Model/Captions.swift
Normal file
12
Model/Captions.swift
Normal file
@@ -0,0 +1,12 @@
|
||||
import Foundation
|
||||
|
||||
struct Captions: Hashable, Identifiable {
|
||||
var id = UUID().uuidString
|
||||
let label: String
|
||||
let code: String
|
||||
let url: URL
|
||||
|
||||
var description: String {
|
||||
"\(label) (\(code))"
|
||||
}
|
||||
}
|
@@ -19,6 +19,13 @@ final class MPVBackend: PlayerBackend {
|
||||
|
||||
var stream: Stream?
|
||||
var video: Video?
|
||||
var captions: Captions? { didSet {
|
||||
guard let captions = captions else {
|
||||
client.removeSubs()
|
||||
return
|
||||
}
|
||||
addSubTrack(captions.url)
|
||||
}}
|
||||
var currentTime: CMTime?
|
||||
|
||||
var loadedVideo = false
|
||||
@@ -155,11 +162,18 @@ final class MPVBackend: PlayerBackend {
|
||||
}
|
||||
#endif
|
||||
|
||||
var captions: Captions?
|
||||
if let captionsLanguageCode = Defaults[.captionsLanguageCode] {
|
||||
captions = video.captions.first { $0.code == captionsLanguageCode } ??
|
||||
video.captions.first { $0.code.contains(captionsLanguageCode) }
|
||||
}
|
||||
|
||||
let updateCurrentStream = {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.stream = stream
|
||||
self?.video = video
|
||||
self?.model.stream = stream
|
||||
self?.captions = captions
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +225,7 @@ final class MPVBackend: PlayerBackend {
|
||||
startPlaying()
|
||||
}
|
||||
|
||||
self.client.loadFile(url, time: time) { [weak self] _ in
|
||||
self.client.loadFile(url, sub: captions?.url, time: time) { [weak self] _ in
|
||||
self?.isLoadingVideo = true
|
||||
}
|
||||
} else {
|
||||
@@ -223,7 +237,7 @@ final class MPVBackend: PlayerBackend {
|
||||
let fileToLoad = self.model.musicMode ? stream.audioAsset.url : stream.videoAsset.url
|
||||
let audioTrack = self.model.musicMode ? nil : stream.audioAsset.url
|
||||
|
||||
self.client?.loadFile(fileToLoad, audio: audioTrack, time: time) { [weak self] _ in
|
||||
self.client?.loadFile(fileToLoad, audio: audioTrack, sub: captions?.url, time: time) { [weak self] _ in
|
||||
self?.isLoadingVideo = true
|
||||
self?.pause()
|
||||
}
|
||||
@@ -454,6 +468,11 @@ final class MPVBackend: PlayerBackend {
|
||||
client?.addVideoTrack(url)
|
||||
}
|
||||
|
||||
func addSubTrack(_ url: URL) {
|
||||
client?.removeSubs()
|
||||
client?.addSubTrack(url)
|
||||
}
|
||||
|
||||
func setVideoToAuto() {
|
||||
client?.setVideoToAuto()
|
||||
}
|
||||
|
@@ -110,7 +110,7 @@ final class MPVClient: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func loadFile(_ url: URL, audio: URL? = nil, time: CMTime? = nil, completionHandler: ((Int32) -> Void)? = nil) {
|
||||
func loadFile(_ url: URL, audio: URL? = nil, sub: URL? = nil, time: CMTime? = nil, completionHandler: ((Int32) -> Void)? = nil) {
|
||||
var args = [url.absoluteString]
|
||||
var options = [String]()
|
||||
|
||||
@@ -123,6 +123,10 @@ final class MPVClient: ObservableObject {
|
||||
options.append("audio-files-append=\"\(audioURL)\"")
|
||||
}
|
||||
|
||||
if let subURL = sub?.absoluteString {
|
||||
options.append("sub-files-append=\"\(subURL)\"")
|
||||
}
|
||||
|
||||
args.append(options.joined(separator: ","))
|
||||
|
||||
command("loadfile", args: args, returnValueCallback: completionHandler)
|
||||
@@ -263,6 +267,14 @@ final class MPVClient: ObservableObject {
|
||||
command("video-add", args: [url.absoluteString])
|
||||
}
|
||||
|
||||
func addSubTrack(_ url: URL) {
|
||||
command("sub-add", args: [url.absoluteString])
|
||||
}
|
||||
|
||||
func removeSubs() {
|
||||
command("sub-remove")
|
||||
}
|
||||
|
||||
func setVideoToAuto() {
|
||||
setString("video", "1")
|
||||
}
|
||||
|
@@ -47,6 +47,11 @@ final class PlayerControlsModel: ObservableObject {
|
||||
|
||||
func handleOverlayPresentationChange() {
|
||||
player?.backend.setNeedsNetworkStateUpdates(presentingControlsOverlay)
|
||||
if presentingControlsOverlay {
|
||||
removeTimer()
|
||||
} else {
|
||||
resetTimer()
|
||||
}
|
||||
}
|
||||
|
||||
func show() {
|
||||
|
@@ -34,6 +34,8 @@ struct Video: Identifiable, Equatable, Hashable {
|
||||
var related = [Video]()
|
||||
var chapters = [Chapter]()
|
||||
|
||||
var captions = [Captions]()
|
||||
|
||||
init(
|
||||
id: String? = nil,
|
||||
videoID: String,
|
||||
@@ -55,7 +57,8 @@ struct Video: Identifiable, Equatable, Hashable {
|
||||
keywords: [String] = [],
|
||||
streams: [Stream] = [],
|
||||
related: [Video] = [],
|
||||
chapters: [Chapter] = []
|
||||
chapters: [Chapter] = [],
|
||||
captions: [Captions] = []
|
||||
) {
|
||||
self.id = id ?? UUID().uuidString
|
||||
self.videoID = videoID
|
||||
@@ -78,6 +81,7 @@ struct Video: Identifiable, Equatable, Hashable {
|
||||
self.streams = streams
|
||||
self.related = related
|
||||
self.chapters = chapters
|
||||
self.captions = captions
|
||||
}
|
||||
|
||||
var publishedDate: String? {
|
||||
|
Reference in New Issue
Block a user