mirror of
https://github.com/cranci1/Sora.git
synced 2026-03-11 17:45:37 +00:00
Merge branch 'pr/124' into dev
This commit is contained in:
commit
298bd88fd9
7 changed files with 192 additions and 166 deletions
|
|
@ -18,4 +18,5 @@ struct ContinueWatchingItem: Codable, Identifiable {
|
|||
let subtitles: String?
|
||||
let aniListID: Int?
|
||||
let module: ScrapingModule
|
||||
let headers: [String:String]?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ extension JSContext {
|
|||
if(method != "GET")
|
||||
{
|
||||
// Ensure body is properly serialized
|
||||
processedBody = body ? JSON.stringify(body) : null
|
||||
processedBody = (body && (typeof body === 'object')) ? JSON.stringify(body) : (body || null)
|
||||
}
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import JavaScriptCore
|
|||
|
||||
extension JSController {
|
||||
|
||||
func fetchStreamUrl(episodeUrl: String, softsub: Bool = false, module: ScrapingModule, completion: @escaping ((streams: [String]?, subtitles: [String]?)) -> Void) {
|
||||
func fetchStreamUrl(episodeUrl: String, softsub: Bool = false, module: ScrapingModule, completion: @escaping ((streams: [String]?, subtitles: [String]?, sources: [[String:Any]]? )) -> Void) {
|
||||
guard let url = URL(string: episodeUrl) else {
|
||||
completion((nil, nil))
|
||||
completion((nil, nil,nil))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -20,13 +20,13 @@ extension JSController {
|
|||
|
||||
if let error = error {
|
||||
Logger.shared.log("Network error: \(error)", type: "Error")
|
||||
DispatchQueue.main.async { completion((nil, nil)) }
|
||||
DispatchQueue.main.async { completion((nil, nil,nil)) }
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data, let html = String(data: data, encoding: .utf8) else {
|
||||
Logger.shared.log("Failed to decode HTML", type: "Error")
|
||||
DispatchQueue.main.async { completion((nil, nil)) }
|
||||
DispatchQueue.main.async { completion((nil, nil, nil)) }
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -36,10 +36,21 @@ extension JSController {
|
|||
if let data = resultString.data(using: .utf8) {
|
||||
do {
|
||||
if let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
||||
print("JSON DATA IS \(json) 2")
|
||||
var streamUrls: [String]? = nil
|
||||
var subtitleUrls: [String]? = nil
|
||||
|
||||
if let streamsArray = json["streams"] as? [String] {
|
||||
var streamUrlsAndHeaders : [[String:Any]]? = nil
|
||||
if let streamSources = json["streams"] as? [[String:Any]]
|
||||
{
|
||||
streamUrlsAndHeaders = streamSources
|
||||
Logger.shared.log("Found \(streamSources.count) streams and headers", type: "Stream")
|
||||
}
|
||||
else if let streamSource = json["stream"] as? [String:Any]
|
||||
{
|
||||
streamUrlsAndHeaders = [streamSource]
|
||||
Logger.shared.log("Found single stream with headers", type: "Stream")
|
||||
}
|
||||
else if let streamsArray = json["streams"] as? [String] {
|
||||
streamUrls = streamsArray
|
||||
Logger.shared.log("Found \(streamsArray.count) streams", type: "Stream")
|
||||
} else if let streamUrl = json["stream"] as? String {
|
||||
|
|
@ -57,45 +68,45 @@ extension JSController {
|
|||
|
||||
Logger.shared.log("Starting stream with \(streamUrls?.count ?? 0) sources and \(subtitleUrls?.count ?? 0) subtitles", type: "Stream")
|
||||
DispatchQueue.main.async {
|
||||
completion((streamUrls, subtitleUrls))
|
||||
completion((streamUrls, subtitleUrls,streamUrlsAndHeaders))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if let streamsArray = try? JSONSerialization.jsonObject(with: data, options: []) as? [String] {
|
||||
Logger.shared.log("Starting multi-stream with \(streamsArray.count) sources", type: "Stream")
|
||||
DispatchQueue.main.async { completion((streamsArray, nil)) }
|
||||
DispatchQueue.main.async { completion((streamsArray, nil,nil)) }
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.shared.log("Starting stream from: \(resultString)", type: "Stream")
|
||||
DispatchQueue.main.async { completion(([resultString], nil)) }
|
||||
DispatchQueue.main.async { completion(([resultString], nil,nil)) }
|
||||
} else {
|
||||
Logger.shared.log("Failed to extract stream URL", type: "Error")
|
||||
DispatchQueue.main.async { completion((nil, nil)) }
|
||||
DispatchQueue.main.async { completion((nil, nil,nil)) }
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
|
||||
func fetchStreamUrlJS(episodeUrl: String, softsub: Bool = false, module: ScrapingModule, completion: @escaping ((streams: [String]?, subtitles: [String]?)) -> Void) {
|
||||
func fetchStreamUrlJS(episodeUrl: String, softsub: Bool = false, module: ScrapingModule, completion: @escaping ((streams: [String]?, subtitles: [String]?,sources: [[String:Any]]? )) -> Void) {
|
||||
if let exception = context.exception {
|
||||
Logger.shared.log("JavaScript exception: \(exception)", type: "Error")
|
||||
completion((nil, nil))
|
||||
completion((nil, nil,nil))
|
||||
return
|
||||
}
|
||||
|
||||
guard let extractStreamUrlFunction = context.objectForKeyedSubscript("extractStreamUrl") else {
|
||||
Logger.shared.log("No JavaScript function extractStreamUrl found", type: "Error")
|
||||
completion((nil, nil))
|
||||
completion((nil, nil,nil))
|
||||
return
|
||||
}
|
||||
|
||||
let promiseValue = extractStreamUrlFunction.call(withArguments: [episodeUrl])
|
||||
guard let promise = promiseValue else {
|
||||
Logger.shared.log("extractStreamUrl did not return a Promise", type: "Error")
|
||||
completion((nil, nil))
|
||||
completion((nil, nil,nil))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -106,10 +117,21 @@ extension JSController {
|
|||
let data = jsonString.data(using: .utf8) {
|
||||
do {
|
||||
if let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
||||
print("JSON object is \(json) 1")
|
||||
var streamUrls: [String]? = nil
|
||||
var subtitleUrls: [String]? = nil
|
||||
|
||||
if let streamsArray = json["streams"] as? [String] {
|
||||
var streamUrlsAndHeaders : [[String:Any]]? = nil
|
||||
if let streamSources = json["streams"] as? [[String:Any]]
|
||||
{
|
||||
streamUrlsAndHeaders = streamSources
|
||||
Logger.shared.log("Found \(streamSources.count) streams and headers", type: "Stream")
|
||||
}
|
||||
else if let streamSource = json["stream"] as? [String:Any]
|
||||
{
|
||||
streamUrlsAndHeaders = [streamSource]
|
||||
Logger.shared.log("Found single stream with headers", type: "Stream")
|
||||
}
|
||||
else if let streamsArray = json["streams"] as? [String] {
|
||||
streamUrls = streamsArray
|
||||
Logger.shared.log("Found \(streamsArray.count) streams", type: "Stream")
|
||||
} else if let streamUrl = json["stream"] as? String {
|
||||
|
|
@ -127,14 +149,14 @@ extension JSController {
|
|||
|
||||
Logger.shared.log("Starting stream with \(streamUrls?.count ?? 0) sources and \(subtitleUrls?.count ?? 0) subtitles", type: "Stream")
|
||||
DispatchQueue.main.async {
|
||||
completion((streamUrls, subtitleUrls))
|
||||
completion((streamUrls, subtitleUrls,streamUrlsAndHeaders))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if let streamsArray = try? JSONSerialization.jsonObject(with: data, options: []) as? [String] {
|
||||
Logger.shared.log("Starting multi-stream with \(streamsArray.count) sources", type: "Stream")
|
||||
DispatchQueue.main.async { completion((streamsArray, nil)) }
|
||||
DispatchQueue.main.async { completion((streamsArray, nil,nil)) }
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -143,14 +165,14 @@ extension JSController {
|
|||
let streamUrl = result.toString()
|
||||
Logger.shared.log("Starting stream from: \(streamUrl ?? "nil")", type: "Stream")
|
||||
DispatchQueue.main.async {
|
||||
completion((streamUrl != nil ? [streamUrl!] : nil, nil))
|
||||
completion((streamUrl != nil ? [streamUrl!] : nil, nil,nil))
|
||||
}
|
||||
}
|
||||
|
||||
let catchBlock: @convention(block) (JSValue) -> Void = { error in
|
||||
Logger.shared.log("Promise rejected: \(String(describing: error.toString()))", type: "Error")
|
||||
DispatchQueue.main.async {
|
||||
completion((nil, nil))
|
||||
completion((nil, nil,nil))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,40 +183,40 @@ extension JSController {
|
|||
promise.invokeMethod("catch", withArguments: [catchFunction as Any])
|
||||
}
|
||||
|
||||
func fetchStreamUrlJSSecond(episodeUrl: String, softsub: Bool = false, module: ScrapingModule, completion: @escaping ((streams: [String]?, subtitles: [String]?)) -> Void) {
|
||||
func fetchStreamUrlJSSecond(episodeUrl: String, softsub: Bool = false, module: ScrapingModule, completion: @escaping ((streams: [String]?, subtitles: [String]?,sources: [[String:Any]]? )) -> Void) {
|
||||
let url = URL(string: episodeUrl)!
|
||||
let task = URLSession.custom.dataTask(with: url) { [weak self] data, response, error in
|
||||
guard let self = self else { return }
|
||||
|
||||
if let error = error {
|
||||
Logger.shared.log("URLSession error: \(error.localizedDescription)", type: "Error")
|
||||
DispatchQueue.main.async { completion((nil, nil)) }
|
||||
DispatchQueue.main.async { completion((nil, nil,nil)) }
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data, let htmlString = String(data: data, encoding: .utf8) else {
|
||||
Logger.shared.log("Failed to fetch HTML data", type: "Error")
|
||||
DispatchQueue.main.async { completion((nil, nil)) }
|
||||
DispatchQueue.main.async { completion((nil, nil, nil)) }
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if let exception = self.context.exception {
|
||||
Logger.shared.log("JavaScript exception: \(exception)", type: "Error")
|
||||
completion((nil, nil))
|
||||
completion((nil, nil, nil))
|
||||
return
|
||||
}
|
||||
|
||||
guard let extractStreamUrlFunction = self.context.objectForKeyedSubscript("extractStreamUrl") else {
|
||||
Logger.shared.log("No JavaScript function extractStreamUrl found", type: "Error")
|
||||
completion((nil, nil))
|
||||
completion((nil, nil, nil))
|
||||
return
|
||||
}
|
||||
|
||||
let promiseValue = extractStreamUrlFunction.call(withArguments: [htmlString])
|
||||
guard let promise = promiseValue else {
|
||||
Logger.shared.log("extractStreamUrl did not return a Promise", type: "Error")
|
||||
completion((nil, nil))
|
||||
completion((nil, nil, nil))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -205,10 +227,21 @@ extension JSController {
|
|||
let data = jsonString.data(using: .utf8) {
|
||||
do {
|
||||
if let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
||||
print("JSON object is \(json) 3 ")
|
||||
var streamUrls: [String]? = nil
|
||||
var subtitleUrls: [String]? = nil
|
||||
|
||||
if let streamsArray = json["streams"] as? [String] {
|
||||
var streamUrlsAndHeaders : [[String:Any]]? = nil
|
||||
if let streamSources = json["streams"] as? [[String:Any]]
|
||||
{
|
||||
streamUrlsAndHeaders = streamSources
|
||||
Logger.shared.log("Found \(streamSources.count) streams and headers", type: "Stream")
|
||||
}
|
||||
else if let streamSource = json["stream"] as? [String:Any]
|
||||
{
|
||||
streamUrlsAndHeaders = [streamSource]
|
||||
Logger.shared.log("Found single stream with headers", type: "Stream")
|
||||
}
|
||||
else if let streamsArray = json["streams"] as? [String] {
|
||||
streamUrls = streamsArray
|
||||
Logger.shared.log("Found \(streamsArray.count) streams", type: "Stream")
|
||||
} else if let streamUrl = json["stream"] as? String {
|
||||
|
|
@ -226,14 +259,14 @@ extension JSController {
|
|||
|
||||
Logger.shared.log("Starting stream with \(streamUrls?.count ?? 0) sources and \(subtitleUrls?.count ?? 0) subtitles", type: "Stream")
|
||||
DispatchQueue.main.async {
|
||||
completion((streamUrls, subtitleUrls))
|
||||
completion((streamUrls, subtitleUrls, streamUrlsAndHeaders))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if let streamsArray = try? JSONSerialization.jsonObject(with: data, options: []) as? [String] {
|
||||
Logger.shared.log("Starting multi-stream with \(streamsArray.count) sources", type: "Stream")
|
||||
DispatchQueue.main.async { completion((streamsArray, nil)) }
|
||||
DispatchQueue.main.async { completion((streamsArray, nil, nil)) }
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -242,14 +275,14 @@ extension JSController {
|
|||
let streamUrl = result.toString()
|
||||
Logger.shared.log("Starting stream from: \(streamUrl ?? "nil")", type: "Stream")
|
||||
DispatchQueue.main.async {
|
||||
completion((streamUrl != nil ? [streamUrl!] : nil, nil))
|
||||
completion((streamUrl != nil ? [streamUrl!] : nil, nil, nil))
|
||||
}
|
||||
}
|
||||
|
||||
let catchBlock: @convention(block) (JSValue) -> Void = { error in
|
||||
Logger.shared.log("Promise rejected: \(String(describing: error.toString()))", type: "Error")
|
||||
DispatchQueue.main.async {
|
||||
completion((nil, nil))
|
||||
completion((nil, nil, nil))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
let subtitlesURL: String?
|
||||
let onWatchNext: () -> Void
|
||||
let aniListID: Int
|
||||
var headers: [String:String]? = nil
|
||||
|
||||
private var aniListUpdatedSuccessfully = false
|
||||
private var aniListUpdateImpossible: Bool = false
|
||||
|
|
@ -177,7 +178,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
onWatchNext: @escaping () -> Void,
|
||||
subtitlesURL: String?,
|
||||
aniListID: Int,
|
||||
episodeImageUrl: String) {
|
||||
episodeImageUrl: String,headers:[String:String]?) {
|
||||
|
||||
self.module = module
|
||||
self.streamURL = urlString
|
||||
|
|
@ -188,6 +189,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
self.onWatchNext = onWatchNext
|
||||
self.subtitlesURL = subtitlesURL
|
||||
self.aniListID = aniListID
|
||||
self.headers = headers
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
|
|
@ -196,8 +198,18 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
}
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Referer")
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Origin")
|
||||
if let mydict = headers, !mydict.isEmpty
|
||||
{
|
||||
for (key,value) in mydict
|
||||
{
|
||||
request.addValue(value, forHTTPHeaderField: key)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Referer")
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Origin")
|
||||
}
|
||||
request.addValue("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
|
||||
forHTTPHeaderField: "User-Agent")
|
||||
|
||||
|
|
@ -1380,7 +1392,8 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
fullUrl: self.fullUrl,
|
||||
subtitles: self.subtitlesURL,
|
||||
aniListID: self.aniListID,
|
||||
module: self.module
|
||||
module: self.module,
|
||||
headers: self.headers
|
||||
)
|
||||
ContinueWatchingManager.shared.save(item: item)
|
||||
}
|
||||
|
|
@ -1712,8 +1725,18 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
|
||||
private func parseM3U8(url: URL, completion: @escaping () -> Void) {
|
||||
var request = URLRequest(url: url)
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Referer")
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Origin")
|
||||
if let mydict = headers, !mydict.isEmpty
|
||||
{
|
||||
for (key,value) in mydict
|
||||
{
|
||||
request.addValue(value, forHTTPHeaderField: key)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Referer")
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Origin")
|
||||
}
|
||||
request.addValue("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
|
||||
forHTTPHeaderField: "User-Agent")
|
||||
|
||||
|
|
@ -1799,8 +1822,18 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
let wasPlaying = player.rate > 0
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Referer")
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Origin")
|
||||
if let mydict = headers, !mydict.isEmpty
|
||||
{
|
||||
for (key,value) in mydict
|
||||
{
|
||||
request.addValue(value, forHTTPHeaderField: key)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Referer")
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Origin")
|
||||
}
|
||||
request.addValue("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
|
||||
forHTTPHeaderField: "User-Agent")
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class VideoPlayerViewController: UIViewController {
|
|||
var fullUrl: String = ""
|
||||
var subtitles: String = ""
|
||||
var aniListID: Int = 0
|
||||
var headers: [String:String]? = nil
|
||||
|
||||
var episodeNumber: Int = 0
|
||||
var episodeImageUrl: String = ""
|
||||
|
|
@ -40,8 +41,18 @@ class VideoPlayerViewController: UIViewController {
|
|||
}
|
||||
|
||||
var request = URLRequest(url: url)
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Referer")
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Origin")
|
||||
if let mydict = headers, !mydict.isEmpty
|
||||
{
|
||||
for (key,value) in mydict
|
||||
{
|
||||
request.addValue(value, forHTTPHeaderField: key)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Referer")
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Origin")
|
||||
}
|
||||
request.addValue("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", forHTTPHeaderField: "User-Agent")
|
||||
|
||||
let asset = AVURLAsset(url: url, options: ["AVURLAssetHTTPHeaderFieldsKey": request.allHTTPHeaderFields ?? [:]])
|
||||
|
|
@ -127,7 +138,8 @@ class VideoPlayerViewController: UIViewController {
|
|||
fullUrl: self.fullUrl,
|
||||
subtitles: self.subtitles,
|
||||
aniListID: self.aniListID,
|
||||
module: self.module
|
||||
module: self.module,
|
||||
headers: self.headers
|
||||
)
|
||||
ContinueWatchingManager.shared.save(item: item)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,7 +272,9 @@ struct ContinueWatchingCell: View {
|
|||
onWatchNext: { },
|
||||
subtitlesURL: item.subtitles,
|
||||
aniListID: item.aniListID ?? 0,
|
||||
episodeImageUrl: item.imageUrl
|
||||
episodeImageUrl: item.imageUrl,
|
||||
headers: item.headers ?? nil
|
||||
|
||||
)
|
||||
customMediaPlayer.modalPresentationStyle = .fullScreen
|
||||
|
||||
|
|
|
|||
|
|
@ -643,119 +643,41 @@ struct MediaInfoView: View {
|
|||
currentStreamTitle = "Episode \(selectedEpisodeNumber)"
|
||||
showStreamLoadingView = true
|
||||
isFetchingEpisode = true
|
||||
let completion: ((streams: [String]?, subtitles: [String]?, sources: [[String: Any]]?)) -> Void = { result in
|
||||
guard self.activeFetchID == fetchID else { return }
|
||||
if let streams = result.sources, !streams.isEmpty{
|
||||
if streams.count > 1 {
|
||||
self.showStreamSelectionAlert(streams: streams, fullURL: href, subtitles: result.subtitles?.first)
|
||||
} else {
|
||||
self.playStream(url: streams[0]["streamUrl"] as? String ?? "", fullURL: href, subtitles: streams[0]["subtitle"] as? String ?? "",headers: streams[0]["headers"] as! [String : String])
|
||||
}
|
||||
}
|
||||
else if let streams = result.streams, !streams.isEmpty {
|
||||
if streams.count > 1 {
|
||||
self.showStreamSelectionAlert(streams: streams, fullURL: href, subtitles: result.subtitles?.first)
|
||||
} else {
|
||||
self.playStream(url: streams[0], fullURL: href, subtitles: result.subtitles?.first)
|
||||
}
|
||||
} else {
|
||||
self.handleStreamFailure(error: nil)
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.isFetchingEpisode = false
|
||||
}
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
Task {
|
||||
do {
|
||||
let jsContent = try moduleManager.getModuleContent(module)
|
||||
jsController.loadScript(jsContent)
|
||||
|
||||
if module.metadata.softsub == true {
|
||||
if module.metadata.asyncJS == true {
|
||||
jsController.fetchStreamUrlJS(episodeUrl: href, softsub: true, module: module) { result in
|
||||
guard self.activeFetchID == fetchID else { return }
|
||||
|
||||
if let streams = result.streams, !streams.isEmpty {
|
||||
if streams.count > 1 {
|
||||
self.showStreamSelectionAlert(streams: streams, fullURL: href, subtitles: result.subtitles?.first)
|
||||
} else {
|
||||
self.playStream(url: streams[0], fullURL: href, subtitles: result.subtitles?.first)
|
||||
}
|
||||
} else {
|
||||
self.handleStreamFailure(error: nil)
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.isFetchingEpisode = false
|
||||
}
|
||||
}
|
||||
} else if module.metadata.streamAsyncJS == true {
|
||||
jsController.fetchStreamUrlJSSecond(episodeUrl: href, softsub: true, module: module) { result in
|
||||
guard self.activeFetchID == fetchID else { return }
|
||||
|
||||
if let streams = result.streams, !streams.isEmpty {
|
||||
if streams.count > 1 {
|
||||
self.showStreamSelectionAlert(streams: streams, fullURL: href, subtitles: result.subtitles?.first)
|
||||
} else {
|
||||
self.playStream(url: streams[0], fullURL: href, subtitles: result.subtitles?.first)
|
||||
}
|
||||
} else {
|
||||
self.handleStreamFailure(error: nil)
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.isFetchingEpisode = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
jsController.fetchStreamUrl(episodeUrl: href, softsub: true, module: module) { result in
|
||||
guard self.activeFetchID == fetchID else { return }
|
||||
|
||||
if let streams = result.streams, !streams.isEmpty {
|
||||
if streams.count > 1 {
|
||||
self.showStreamSelectionAlert(streams: streams, fullURL: href, subtitles: result.subtitles?.first)
|
||||
} else {
|
||||
self.playStream(url: streams[0], fullURL: href, subtitles: result.subtitles?.first)
|
||||
}
|
||||
} else {
|
||||
self.handleStreamFailure(error: nil)
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.isFetchingEpisode = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if module.metadata.asyncJS == true {
|
||||
jsController.fetchStreamUrlJS(episodeUrl: href, softsub: module.metadata.softsub == true, module: module, completion: completion)
|
||||
} else if module.metadata.streamAsyncJS == true {
|
||||
jsController.fetchStreamUrlJSSecond(episodeUrl: href, softsub: module.metadata.softsub == true, module: module, completion: completion)
|
||||
} else {
|
||||
if module.metadata.asyncJS == true {
|
||||
jsController.fetchStreamUrlJS(episodeUrl: href, module: module) { result in
|
||||
guard self.activeFetchID == fetchID else { return }
|
||||
|
||||
if let streams = result.streams, !streams.isEmpty {
|
||||
if streams.count > 1 {
|
||||
self.showStreamSelectionAlert(streams: streams, fullURL: href, subtitles: result.subtitles?.first)
|
||||
} else {
|
||||
self.playStream(url: streams[0], fullURL: href, subtitles: result.subtitles?.first)
|
||||
}
|
||||
} else {
|
||||
self.handleStreamFailure(error: nil)
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.isFetchingEpisode = false
|
||||
}
|
||||
}
|
||||
} else if module.metadata.streamAsyncJS == true {
|
||||
jsController.fetchStreamUrlJSSecond(episodeUrl: href, module: module) { result in
|
||||
guard self.activeFetchID == fetchID else { return }
|
||||
|
||||
if let streams = result.streams, !streams.isEmpty {
|
||||
if streams.count > 1 {
|
||||
self.showStreamSelectionAlert(streams: streams, fullURL: href, subtitles: result.subtitles?.first)
|
||||
} else {
|
||||
self.playStream(url: streams[0], fullURL: href, subtitles: result.subtitles?.first)
|
||||
}
|
||||
} else {
|
||||
self.handleStreamFailure(error: nil)
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.isFetchingEpisode = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
jsController.fetchStreamUrl(episodeUrl: href, module: module) { result in
|
||||
guard self.activeFetchID == fetchID else { return }
|
||||
|
||||
if let streams = result.streams, !streams.isEmpty {
|
||||
if streams.count > 1 {
|
||||
self.showStreamSelectionAlert(streams: streams, fullURL: href, subtitles: result.subtitles?.first)
|
||||
} else {
|
||||
self.playStream(url: streams[0], fullURL: href, subtitles: result.subtitles?.first)
|
||||
}
|
||||
} else {
|
||||
self.handleStreamFailure(error: nil)
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.isFetchingEpisode = false
|
||||
}
|
||||
}
|
||||
}
|
||||
jsController.fetchStreamUrl(episodeUrl: href, softsub: module.metadata.softsub == true, module: module, completion: completion)
|
||||
}
|
||||
|
||||
} catch {
|
||||
self.handleStreamFailure(error: error)
|
||||
DispatchQueue.main.async {
|
||||
|
|
@ -779,9 +701,10 @@ struct MediaInfoView: View {
|
|||
self.isLoading = false
|
||||
}
|
||||
|
||||
func showStreamSelectionAlert(streams: [String], fullURL: String, subtitles: String? = nil) {
|
||||
func showStreamSelectionAlert(streams: [Any], fullURL: String, subtitles: String? = nil) {
|
||||
self.isFetchingEpisode = false
|
||||
self.showStreamLoadingView = false
|
||||
print("MULTIPLE STREAMS \(streams)")
|
||||
DispatchQueue.main.async {
|
||||
let alert = UIAlertController(title: "Select Server", message: "Choose a server to play from", preferredStyle: .actionSheet)
|
||||
|
||||
|
|
@ -789,27 +712,46 @@ struct MediaInfoView: View {
|
|||
var streamIndex = 1
|
||||
|
||||
while index < streams.count {
|
||||
let title: String
|
||||
let streamUrl: String
|
||||
|
||||
if index + 1 < streams.count {
|
||||
if !streams[index].lowercased().contains("http") {
|
||||
title = streams[index]
|
||||
streamUrl = streams[index + 1]
|
||||
index += 2
|
||||
var title: String = ""
|
||||
var streamUrl: String = ""
|
||||
var headers: [String:String]? = nil
|
||||
if let streams = streams as? [String]
|
||||
{
|
||||
if index + 1 < streams.count {
|
||||
if !streams[index].lowercased().contains("http") {
|
||||
title = streams[index]
|
||||
streamUrl = streams[index + 1]
|
||||
index += 2
|
||||
} else {
|
||||
title = "Stream \(streamIndex)"
|
||||
streamUrl = streams[index]
|
||||
index += 1
|
||||
}
|
||||
} else {
|
||||
title = "Stream \(streamIndex)"
|
||||
streamUrl = streams[index]
|
||||
index += 1
|
||||
}
|
||||
} else {
|
||||
title = "Stream \(streamIndex)"
|
||||
streamUrl = streams[index]
|
||||
}
|
||||
else if let streams = streams as? [[String: Any]]
|
||||
{
|
||||
if let currTitle = streams[index]["title"] as? String
|
||||
{
|
||||
title = currTitle
|
||||
streamUrl = (streams[index]["streamUrl"] as? String) ?? ""
|
||||
}
|
||||
else
|
||||
{
|
||||
title = "Stream \(streamIndex)"
|
||||
streamUrl = (streams[index]["streamUrl"] as? String)!
|
||||
}
|
||||
headers = streams[index]["headers"] as? [String:String] ?? [:]
|
||||
index += 1
|
||||
}
|
||||
|
||||
|
||||
alert.addAction(UIAlertAction(title: title, style: .default) { _ in
|
||||
self.playStream(url: streamUrl, fullURL: fullURL, subtitles: subtitles)
|
||||
self.playStream(url: streamUrl, fullURL: fullURL, subtitles: subtitles,headers: headers)
|
||||
})
|
||||
|
||||
streamIndex += 1
|
||||
|
|
@ -843,7 +785,7 @@ struct MediaInfoView: View {
|
|||
}
|
||||
}
|
||||
|
||||
func playStream(url: String, fullURL: String, subtitles: String? = nil) {
|
||||
func playStream(url: String, fullURL: String, subtitles: String? = nil,headers: [String:String]? = nil) {
|
||||
self.isFetchingEpisode = false
|
||||
self.showStreamLoadingView = false
|
||||
DispatchQueue.main.async {
|
||||
|
|
@ -863,6 +805,7 @@ struct MediaInfoView: View {
|
|||
scheme = "SenPlayer://x-callback-url/play?url=\(url)"
|
||||
case "Default":
|
||||
let videoPlayerViewController = VideoPlayerViewController(module: module)
|
||||
videoPlayerViewController.headers = headers
|
||||
videoPlayerViewController.streamUrl = url
|
||||
videoPlayerViewController.fullUrl = fullURL
|
||||
videoPlayerViewController.episodeNumber = selectedEpisodeNumber
|
||||
|
|
@ -892,6 +835,7 @@ struct MediaInfoView: View {
|
|||
}
|
||||
|
||||
let customMediaPlayer = CustomMediaPlayerViewController(
|
||||
|
||||
module: module,
|
||||
urlString: url.absoluteString,
|
||||
fullUrl: fullURL,
|
||||
|
|
@ -902,7 +846,8 @@ struct MediaInfoView: View {
|
|||
},
|
||||
subtitlesURL: subtitles,
|
||||
aniListID: itemID ?? 0,
|
||||
episodeImageUrl: selectedEpisodeImage
|
||||
episodeImageUrl: selectedEpisodeImage,
|
||||
headers: headers ?? nil
|
||||
)
|
||||
customMediaPlayer.modalPresentationStyle = .fullScreen
|
||||
Logger.shared.log("Opening custom media player with url: \(url)")
|
||||
|
|
|
|||
Loading…
Reference in a new issue