diff --git a/Model/Player/Backends/AVPlayerBackend.swift b/Model/Player/Backends/AVPlayerBackend.swift index 96d38506..d676a486 100644 --- a/Model/Player/Backends/AVPlayerBackend.swift +++ b/Model/Player/Backends/AVPlayerBackend.swift @@ -232,7 +232,10 @@ final class AVPlayerBackend: PlayerBackend { upgrading: Bool = false ) { asset?.cancelLoading() - asset = AVURLAsset(url: url) + asset = AVURLAsset( + url: url, + options: ["AVURLAssetHTTPHeaderFieldsKey": ["User-Agent": "\(UserAgentManager.shared.userAgent)"]] + ) asset?.loadValuesAsynchronously(forKeys: Self.assetKeysToLoad) { [weak self] in var error: NSError? switch self?.asset?.statusOfValue(forKey: "duration", error: &error) { diff --git a/Model/Player/Backends/MPVClient.swift b/Model/Player/Backends/MPVClient.swift index 75f9128c..b5695328 100644 --- a/Model/Player/Backends/MPVClient.swift +++ b/Model/Player/Backends/MPVClient.swift @@ -68,6 +68,7 @@ final class MPVClient: ObservableObject { checkError(mpv_set_option_string(mpv, "vo", "libmpv")) checkError(mpv_set_option_string(mpv, "demuxer-lavf-analyzeduration", "1")) checkError(mpv_set_option_string(mpv, "deinterlace", Defaults[.mpvDeinterlace] ? "yes" : "no")) + checkError(mpv_set_option_string(mpv, "user-agent", UserAgentManager.shared.userAgent)) checkError(mpv_initialize(mpv)) diff --git a/Shared/Constants.swift b/Shared/Constants.swift index fbecc16e..b8fa0b07 100644 --- a/Shared/Constants.swift +++ b/Shared/Constants.swift @@ -103,9 +103,8 @@ enum Constants { #elseif os(iOS) if isIPad { return .sidebar - } else { - return .tab } + return .tab #else return .tab #endif diff --git a/Shared/URLTester.swift b/Shared/URLTester.swift index 29b7e1ac..1dda64ca 100644 --- a/Shared/URLTester.swift +++ b/Shared/URLTester.swift @@ -20,6 +20,7 @@ enum URLTester { var request = URLRequest(url: url) request.httpMethod = "HEAD" request.setValue("bytes=\(range)", forHTTPHeaderField: "Range") + request.setValue(UserAgentManager.shared.userAgent, forHTTPHeaderField: "User-Agent") var dataTask: URLSessionDataTask? dataTask = URLSession.shared.dataTask(with: request) { _, response, _ in diff --git a/Shared/UserAgentManager.swift b/Shared/UserAgentManager.swift new file mode 100644 index 00000000..378dd2fb --- /dev/null +++ b/Shared/UserAgentManager.swift @@ -0,0 +1,28 @@ +import Logging +import WebKit + +final class UserAgentManager { + static let shared = UserAgentManager() + + private(set) var userAgent: String + private var webView: WKWebView? + + private init() { + // In case an error occurs while retrieving the actual User-Agent, + // we set a default User-Agent value that represents a commonly used User-Agent. + userAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)" + + webView = WKWebView() + webView?.evaluateJavaScript("navigator.userAgent") { [weak self] result, _ in + if let userAgent = result as? String { + DispatchQueue.main.async { + self?.userAgent = userAgent + Logger(label: "stream.yattee.userAgentManager").info("User-Agent: \(userAgent)") + print("User-Agent updated: \(userAgent)") + } + } else { + Logger(label: "stream.yattee.userAgentManager").warning("Failed to update User-Agent.") + } + } + } +} diff --git a/Shared/YatteeApp.swift b/Shared/YatteeApp.swift index 4adfbd16..81458521 100644 --- a/Shared/YatteeApp.swift +++ b/Shared/YatteeApp.swift @@ -206,6 +206,9 @@ struct YatteeApp: App { } #endif + // Initialize UserAgentManager + _ = UserAgentManager.shared + DispatchQueue.global(qos: .userInitiated).async { URLBookmarkModel.shared.refreshAll() } diff --git a/Yattee.xcodeproj/project.pbxproj b/Yattee.xcodeproj/project.pbxproj index 5691e4bb..9409e09b 100644 --- a/Yattee.xcodeproj/project.pbxproj +++ b/Yattee.xcodeproj/project.pbxproj @@ -1070,6 +1070,9 @@ 37FFC440272734C3009FFD26 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FFC43F272734C3009FFD26 /* Throttle.swift */; }; 37FFC441272734C3009FFD26 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FFC43F272734C3009FFD26 /* Throttle.swift */; }; 37FFC442272734C3009FFD26 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FFC43F272734C3009FFD26 /* Throttle.swift */; }; + E24DC6582BFA124100BF6187 /* UserAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24DC6572BFA124100BF6187 /* UserAgentManager.swift */; }; + E24DC6592BFA124100BF6187 /* UserAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24DC6572BFA124100BF6187 /* UserAgentManager.swift */; }; + E24DC65A2BFA124100BF6187 /* UserAgentManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24DC6572BFA124100BF6187 /* UserAgentManager.swift */; }; E25028B02BF790F5002CB9FC /* HTTPStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25028AF2BF790F5002CB9FC /* HTTPStatus.swift */; }; E25028B12BF790F5002CB9FC /* HTTPStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25028AF2BF790F5002CB9FC /* HTTPStatus.swift */; }; E25028B22BF790F5002CB9FC /* HTTPStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = E25028AF2BF790F5002CB9FC /* HTTPStatus.swift */; }; @@ -1545,6 +1548,7 @@ 3DA101AD287C30F50027D920 /* DEVELOPMENT_TEAM.template.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DEVELOPMENT_TEAM.template.xcconfig; sourceTree = ""; }; 3DA101AE287C30F50027D920 /* DEVELOPMENT_TEAM.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DEVELOPMENT_TEAM.xcconfig; sourceTree = ""; }; 3DA101AF287C30F50027D920 /* Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; + E24DC6572BFA124100BF6187 /* UserAgentManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentManager.swift; sourceTree = ""; }; E25028AF2BF790F5002CB9FC /* HTTPStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPStatus.swift; sourceTree = ""; }; E258F3892BF61BD2005B8C28 /* URLTester.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLTester.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -2303,6 +2307,7 @@ 37FFC43F272734C3009FFD26 /* Throttle.swift */, 378FFBC328660172009E3FBE /* URLParser.swift */, E258F3892BF61BD2005B8C28 /* URLTester.swift */, + E24DC6572BFA124100BF6187 /* UserAgentManager.swift */, 37D4B0C22671614700C925CA /* YatteeApp.swift */, 37D4B0C42671614800C925CA /* Assets.xcassets */, 37BD07C42698ADEE003EBB87 /* Yattee.entitlements */, @@ -3149,6 +3154,7 @@ 377FC7DC267A081800A6BBAF /* PopularView.swift in Sources */, 3752069D285E910600CA655F /* ChapterView.swift in Sources */, 375EC96A289F232600751258 /* QualityProfilesModel.swift in Sources */, + E24DC6582BFA124100BF6187 /* UserAgentManager.swift in Sources */, E258F38A2BF61BD2005B8C28 /* URLTester.swift in Sources */, 3751B4B227836902000B7DF4 /* SearchPage.swift in Sources */, 37CC3F4C270CFE1700608308 /* PlayerQueueView.swift in Sources */, @@ -3413,6 +3419,7 @@ 3743CA4F270EFE3400E4D32B /* PlayerQueueRow.swift in Sources */, 374C053C2724614F009BDDBE /* PlayerTVMenu.swift in Sources */, 377FC7DD267A081A00A6BBAF /* PopularView.swift in Sources */, + E24DC6592BFA124100BF6187 /* UserAgentManager.swift in Sources */, 374924DB2921050B0017D862 /* LocationsSettings.swift in Sources */, 371AC0A0294D13AA0085989E /* UnwatchedFeedCountModel.swift in Sources */, 379E7C342A20FE3900AF8118 /* FocusableSearchTextField.swift in Sources */, @@ -3878,6 +3885,7 @@ 37BA221329526A19000DAD1F /* ControlsGradientView.swift in Sources */, 374C0541272472C0009BDDBE /* PlayerSponsorBlock.swift in Sources */, 37130A61277657300033018A /* PersistenceController.swift in Sources */, + E24DC65A2BFA124100BF6187 /* UserAgentManager.swift in Sources */, 37E70929271CDDAE00D34DDE /* OpenSettingsButton.swift in Sources */, 3717407F2949D40800FDDBC7 /* ChannelLinkView.swift in Sources */, E25028B22BF790F5002CB9FC /* HTTPStatus.swift in Sources */,