mirror of
https://github.com/yattee/yattee.git
synced 2025-04-24 15:46:28 +00:00
Add support for invidious companion
This commit is contained in:
parent
3a17cc4dee
commit
5239b36cfe
@ -10,14 +10,16 @@ struct Instance: Defaults.Serializable, Hashable, Identifiable {
|
||||
let apiURLString: String
|
||||
var frontendURL: String?
|
||||
var proxiesVideos: Bool
|
||||
var invidiousCompanion: Bool
|
||||
|
||||
init(app: VideosApp, id: String? = nil, name: String? = nil, apiURLString: String, frontendURL: String? = nil, proxiesVideos: Bool = false) {
|
||||
init(app: VideosApp, id: String? = nil, name: String? = nil, apiURLString: String, frontendURL: String? = nil, proxiesVideos: Bool = false, invidiousCompanion: Bool = false) {
|
||||
self.app = app
|
||||
self.id = id ?? UUID().uuidString
|
||||
self.name = name ?? app.rawValue
|
||||
self.apiURLString = apiURLString
|
||||
self.frontendURL = frontendURL
|
||||
self.proxiesVideos = proxiesVideos
|
||||
self.invidiousCompanion = invidiousCompanion
|
||||
}
|
||||
|
||||
var apiURL: URL! {
|
||||
|
@ -16,7 +16,8 @@ struct InstancesBridge: Defaults.Bridge {
|
||||
"name": value.name,
|
||||
"apiURL": value.apiURLString,
|
||||
"frontendURL": value.frontendURL ?? "",
|
||||
"proxiesVideos": value.proxiesVideos ? "true" : "false"
|
||||
"proxiesVideos": value.proxiesVideos ? "true" : "false",
|
||||
"invidiousCompanion": value.invidiousCompanion ? "true" : "false"
|
||||
]
|
||||
}
|
||||
|
||||
@ -33,7 +34,8 @@ struct InstancesBridge: Defaults.Bridge {
|
||||
let name = object["name"] ?? ""
|
||||
let frontendURL: String? = object["frontendURL"]!.isEmpty ? nil : object["frontendURL"]
|
||||
let proxiesVideos = object["proxiesVideos"] == "true"
|
||||
let invidiousCompanion = object["invidiousCompanion"] == "true"
|
||||
|
||||
return Instance(app: app, id: id, name: name, apiURLString: apiURL, frontendURL: frontendURL, proxiesVideos: proxiesVideos)
|
||||
return Instance(app: app, id: id, name: name, apiURLString: apiURL, frontendURL: frontendURL, proxiesVideos: proxiesVideos, invidiousCompanion: invidiousCompanion)
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,17 @@ final class InstancesModel: ObservableObject {
|
||||
Defaults[.instances][index] = instance
|
||||
}
|
||||
|
||||
func setInvidiousCompanion(_ instance: Instance, _ invidiousCompanion: Bool) {
|
||||
guard let index = Defaults[.instances].firstIndex(where: { $0.id == instance.id }) else {
|
||||
return
|
||||
}
|
||||
|
||||
var instance = Defaults[.instances][index]
|
||||
instance.invidiousCompanion = invidiousCompanion
|
||||
|
||||
Defaults[.instances][index] = instance
|
||||
}
|
||||
|
||||
func remove(_ instance: Instance) {
|
||||
let accounts = accounts(instance.id)
|
||||
if let index = Defaults[.instances].firstIndex(where: { $0.id == instance.id }) {
|
||||
|
@ -655,21 +655,29 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
||||
if json["liveNow"].boolValue {
|
||||
return hls
|
||||
}
|
||||
let videoId = json["videoId"].stringValue
|
||||
|
||||
return extractFormatStreams(from: json["formatStreams"].arrayValue) +
|
||||
extractAdaptiveFormats(from: json["adaptiveFormats"].arrayValue) +
|
||||
return extractFormatStreams(from: json["formatStreams"].arrayValue, videoId: videoId) +
|
||||
extractAdaptiveFormats(from: json["adaptiveFormats"].arrayValue, videoId: videoId) +
|
||||
hls
|
||||
}
|
||||
|
||||
private func extractFormatStreams(from streams: [JSON]) -> [Stream] {
|
||||
private func extractFormatStreams(from streams: [JSON], videoId: String?) -> [Stream] {
|
||||
streams.compactMap { stream in
|
||||
guard let streamURL = stream["url"].url else {
|
||||
return nil
|
||||
}
|
||||
let finalURL: URL
|
||||
if let videoId, let itag = stream["itag"].string, account.instance.invidiousCompanion {
|
||||
let companionURLString = "\(account.instance.apiURLString)/latest_version?id=\(videoId)&itag=\(itag)"
|
||||
finalURL = URL(string: companionURLString) ?? streamURL
|
||||
} else {
|
||||
finalURL = streamURL
|
||||
}
|
||||
|
||||
return SingleAssetStream(
|
||||
instance: account.instance,
|
||||
avAsset: AVURLAsset(url: streamURL),
|
||||
avAsset: AVURLAsset(url: finalURL),
|
||||
resolution: Stream.Resolution.from(resolution: stream["resolution"].string ?? ""),
|
||||
kind: .stream,
|
||||
encoding: stream["encoding"].string ?? ""
|
||||
@ -677,7 +685,7 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
||||
}
|
||||
}
|
||||
|
||||
private func extractAdaptiveFormats(from streams: [JSON]) -> [Stream] {
|
||||
private func extractAdaptiveFormats(from streams: [JSON], videoId: String?) -> [Stream] {
|
||||
let audioStreams = streams
|
||||
.filter { $0["type"].stringValue.starts(with: "audio/mp4") }
|
||||
.sorted {
|
||||
@ -692,15 +700,29 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
||||
|
||||
return videoStreams.compactMap { videoStream in
|
||||
guard let audioAssetURL = audioStream["url"].url,
|
||||
let videoAssetURL = videoStream["url"].url
|
||||
let videoAssetURL = videoStream["url"].url,
|
||||
let audioItag = audioStream["itag"].string,
|
||||
let videoItag = videoStream["itag"].string
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
let finalAudioURL: URL
|
||||
let finalVideoURL: URL
|
||||
|
||||
if let videoId, account.instance.invidiousCompanion {
|
||||
let audioCompanionURLString = "\(account.instance.apiURLString)/latest_version?id=\(videoId)&itag=\(audioItag)"
|
||||
let videoCompanionURLString = "\(account.instance.apiURLString)/latest_version?id=\(videoId)&itag=\(videoItag)"
|
||||
finalAudioURL = URL(string: audioCompanionURLString) ?? audioAssetURL
|
||||
finalVideoURL = URL(string: videoCompanionURLString) ?? videoAssetURL
|
||||
} else {
|
||||
finalAudioURL = audioAssetURL
|
||||
finalVideoURL = videoAssetURL
|
||||
}
|
||||
|
||||
return Stream(
|
||||
instance: account.instance,
|
||||
audioAsset: AVURLAsset(url: audioAssetURL),
|
||||
videoAsset: AVURLAsset(url: videoAssetURL),
|
||||
audioAsset: AVURLAsset(url: finalAudioURL),
|
||||
videoAsset: AVURLAsset(url: finalVideoURL),
|
||||
resolution: Stream.Resolution.from(resolution: videoStream["resolution"].stringValue),
|
||||
kind: .adaptive,
|
||||
encoding: videoStream["encoding"].string,
|
||||
@ -711,6 +733,7 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func extractHLSStreams(from content: JSON) -> [Stream] {
|
||||
if let hlsURL = content.dictionaryValue["hlsUrl"]?.url {
|
||||
return [Stream(instance: account.instance, hlsURL: hlsURL)]
|
||||
|
@ -8,6 +8,7 @@ struct InstanceSettings: View {
|
||||
|
||||
@State private var frontendURL = ""
|
||||
@State private var proxiesVideos = false
|
||||
@State private var invidiousCompanion = false
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
@ -87,6 +88,16 @@ struct InstanceSettings: View {
|
||||
InstancesModel.shared.setProxiesVideos(instance, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
if instance.app == .invidious {
|
||||
invidiousCompanionToggle
|
||||
.onAppear {
|
||||
invidiousCompanion = instance.invidiousCompanion
|
||||
}
|
||||
.onChange(of: invidiousCompanion) { newValue in
|
||||
InstancesModel.shared.setInvidiousCompanion(instance, newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
#if os(tvOS)
|
||||
.frame(maxWidth: 1000)
|
||||
@ -100,6 +111,10 @@ struct InstanceSettings: View {
|
||||
private var proxiesVideosToggle: some View {
|
||||
Toggle("Proxy videos", isOn: $proxiesVideos)
|
||||
}
|
||||
|
||||
private var invidiousCompanionToggle: some View {
|
||||
Toggle("Invidious companion", isOn: $invidiousCompanion)
|
||||
}
|
||||
|
||||
private func removeAccount(_ account: Account) {
|
||||
AccountsModel.remove(account)
|
||||
|
@ -11,6 +11,7 @@ struct InstancesSettings: View {
|
||||
|
||||
@State private var frontendURL = ""
|
||||
@State private var proxiesVideos = false
|
||||
@State private var invidiousCompanion = false
|
||||
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
@ObservedObject private var accounts = AccountsModel.shared
|
||||
@ -105,6 +106,16 @@ struct InstancesSettings: View {
|
||||
}
|
||||
}
|
||||
|
||||
if selectedInstance != nil, selectedInstance.app == .invidious {
|
||||
invidiousCompanionToggle
|
||||
.onAppear {
|
||||
invidiousCompanion = selectedInstance.invidiousCompanion
|
||||
}
|
||||
.onChange(of: invidiousCompanion) { newValue in
|
||||
InstancesModel.shared.setInvidiousCompanion(selectedInstance, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
if selectedInstance != nil, !selectedInstance.app.supportsAccounts {
|
||||
Spacer()
|
||||
Text("Accounts are not supported for the application of this instance")
|
||||
@ -191,6 +202,10 @@ struct InstancesSettings: View {
|
||||
private var proxiesVideosToggle: some View {
|
||||
Toggle("Proxy videos", isOn: $proxiesVideos)
|
||||
}
|
||||
|
||||
private var invidiousCompanionToggle: some View {
|
||||
Toggle("Invidious companion", isOn: $invidiousCompanion)
|
||||
}
|
||||
}
|
||||
|
||||
struct InstancesSettingsView_Previews: PreviewProvider {
|
||||
|
Loading…
x
Reference in New Issue
Block a user