Swift Media Player
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

336 lines
12 KiB

//
// Created by Marco Schmickler on 2018-11-01.
// Copyright (c) 2018 Marco Schmickler. All rights reserved.
//
import Foundation
import UIKit
import WebBrowser
import WebKit
import Alamofire
import SwiftUI
protocol DownloadDelegate {
func killFFMPEG()
func dlserverlen(result: @escaping (String) -> ())
func download(url: URL, path: String, result: @escaping (URL) -> () )
func downloadToServer(path: String, url: URL, result: @escaping (String) -> ())
func inProgress() -> Int
}
protocol ItemController {
func setCurrentItem(item: MediaItem)
func setItems(items: [MediaItem])
func setCompletionHandler(handler: @escaping (() -> Void))
}
class BrowserController : UIViewController, ItemController, WebBrowserDelegate, UINavigationControllerDelegate, WKScriptMessageHandler, WKHTTPCookieStoreObserver {
var completionHandler: (() -> Void)?
var currentItem : MediaItem?
var web : WebBrowserViewController?
var dl = false
func setItems(items: [MediaItem]) {
}
func setCurrentItem(item: MediaItem) {
currentItem = item
}
func setCompletionHandler(handler: @escaping (() -> Void)) {
completionHandler = handler
}
func cookiesDidChange(in cookieStore: WKHTTPCookieStore) {
cookieStore.getAllCookies { cookies in
print(cookies)
}
}
override func viewDidLoad() {
let preferences = WKPreferences()
preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
let config = WKWebViewConfiguration()
config.preferences = preferences
config.allowsInlineMediaPlayback = true
config.allowsAirPlayForMediaPlayback = false
config.userContentController.add(self, name: "openDocument")
config.userContentController.add(self, name: "jsError")
config.setValue(true, forKey: "_allowUniversalAccessFromFileURLs")
if (currentItem!.name.contains(".x")) {
config.websiteDataStore = WKWebsiteDataStore.nonPersistent()
}
config.websiteDataStore.httpCookieStore.add(self)
let cookiesStore = config.websiteDataStore.httpCookieStore
let cookieProps: [HTTPCookiePropertyKey : Any] = [
HTTPCookiePropertyKey.domain: "URL",
HTTPCookiePropertyKey.path: "/",
HTTPCookiePropertyKey.name: "key",
HTTPCookiePropertyKey.value: "value",
HTTPCookiePropertyKey.secure: "TRUE",
HTTPCookiePropertyKey.expires: NSDate(timeIntervalSinceNow: 209000)
]
cookiesStore.setCookie(HTTPCookie(properties: cookieProps)!)
let webBrowserViewController = WebBrowserViewController(configuration: config)
web = webBrowserViewController
web?.getWKWebView().customUserAgent = "Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5";
webBrowserViewController.delegate = self
webBrowserViewController.language = .english
// webBrowserViewController.tintColor = ...
// webBrowserViewController.barTintColor = ...
webBrowserViewController.isToolbarHidden = false
webBrowserViewController.isShowActionBarButton = false
webBrowserViewController.toolbarItemSpace = 50
webBrowserViewController.isShowURLInNavigationBarWhenLoading = true
webBrowserViewController.isShowPageTitleInNavigationBar = true
// webBrowserViewController.customApplicationActivities = ...
webBrowserViewController.loadURLString(currentItem!.name)
webBrowserViewController.onOpenExternalAppHandler = { [weak self] _ in
guard let `self` = self else { return }
self.completionHandler!()
//self.navigationController?.popViewController(animated: true)
}
let backButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(BrowserController.back(_:)))
let closeButton = UIBarButtonItem(barButtonSystemItem: .close, target: self, action: #selector(BrowserController.close(_:)))
webBrowserViewController.navigationItem.leftBarButtonItems = [backButton, closeButton]
let reviewButton = UIBarButtonItem(title:"download", style:UIBarButtonItem.Style.plain, target: self, action: #selector(BrowserController.doDownload(_:)))
let dlButton = UIBarButtonItem(title:"server", style:UIBarButtonItem.Style.plain, target: self, action: #selector(BrowserController.doServerDownload(_:)))
webBrowserViewController.navigationItem.rightBarButtonItems = [dlButton, reviewButton]
navigationController?.delegate = self
navigationController?.pushViewController(webBrowserViewController, animated: true)
// present(webBrowserViewController, animated: false)
}
@objc public func doDownload(_ sender: AnyObject) {
dl=false
executeDocumentDownloadScript(webView: web!.getWKWebView(), forAbsoluteUrl: "hello")
}
@objc public func doServerDownload(_ sender: AnyObject) {
dl=true
executeDocumentDownloadScript(webView: web!.getWKWebView(), forAbsoluteUrl: "hello")
}
@IBAction func close(_ sender: AnyObject) {
completionHandler!()
}
@IBAction func back(_ sender: AnyObject) {
if (web!.getWKWebView().canGoBack) {
web!.getWKWebView().goBack()
web!.updateToolBarState()
}
else {
completionHandler!()
}
}
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
debugPrint("did receive message \(message.name)")
if (message.name == "openDocument") {
do {
let data = (message.body as! String).data(using: .utf8)
let jsonObject = try JSONSerialization.jsonObject(with: data!, options: [])
handleDocument(jsonObject as! [String])
} catch {
}
} else if (message.name == "jsError") {
debugPrint(message.body as! String)
}
}
private func handleDocument(_ strings: [String]) {
print(strings)
let alertController = UIAlertController(title: "Download", message: "Videos found", preferredStyle: .alert)
NetworkManager.sharedInstance.dlserverlen { c in
alertController.title = "On Server: \(c)";
}
for s in strings {
var name = s
if let u = URL(string: s) {
name = u.lastPathComponent
if s.contains("720") {
name = name + "720 "
}
if s.contains("1080") {
name = name + "1080 "
}
if s.contains("480") {
name = name + "480 "
}
}
let oneAction = UIAlertAction(title: name, style: .default) { (action) in
self.preview(url: s)
}
alertController.addAction(oneAction)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
}
alertController.addAction(cancelAction)
web!.present(alertController, animated: true) {
}
}
func preview(url: String) {
let url2 = URL(string: url)!
if (url2.pathExtension == "zip") {
downloadZip(url2, path: "download")
return
}
if (url2.pathExtension == "jpg") {
downloadZip(url2, path: "images/new")
return
}
let name = url2.lastPathComponent
let hostcomp = currentItem!.name.split(separator: ".")
let site = String(hostcomp[hostcomp.count-2])
if ((url2.pathExtension == "mp4" || url2.pathExtension == "m3u8") && dl) {
NetworkManager.sharedInstance.downloadToServer(path: site, url: url2, result: {
(r) in
print(r)
self.showAlert(title: "download ready", message: r)
if (r == "exists") {
}
})
return
}
let item = MediaItem(name: name, path: name, root: site, type: ItemType.VIDEO)
item.externalURL = url
showVideo(selectedItem: item)
}
func showVideo(selectedItem: MediaItem) {
var se = selectedItem
var children = [MediaItem]()
var clonedChildren = [MediaItem]()
var baseItem = selectedItem
if baseItem.type == ItemType.SNAPSHOT {
baseItem = selectedItem.parent!
}
children = baseItem.children
clonedChildren = baseItem.clone().children
let model = SVideoModel(allItems: children, currentSnapshot: se, baseItem: baseItem)
model.edit = LocalManager.sharedInstance.settings.edit
model.loop = LocalManager.sharedInstance.settings.autoloop
model.zoomed = LocalManager.sharedInstance.settings.zoomed
let player = SVideoPlayer(completionHandler: { saved in
baseItem.children = clonedChildren
self.dismiss(animated: true, completion: nil);
}, model: model)
player
let pc = UIHostingController(rootView: player)
pc.view.backgroundColor = .black
getWindow().rootViewController!.definesPresentationContext = true
pc.modalPresentationStyle = .overCurrentContext
getWindow().rootViewController!.present(pc, animated: true)
}
func getWindow() -> UIWindow {
let delegate2 = UIApplication.shared.delegate!
return delegate2.window as! UIWindow
}
private func downloadZip(_ url: URL, path: String) {
NetworkManager.sharedInstance.download(url: url, path: path) { url in
self.showAlert(title: url.lastPathComponent, message: "ready")
}
}
func webBrowser(_ webBrowser: WebBrowserViewController, didStartLoad url: URL?) {
print(url?.absoluteString)
}
func webBrowser(_ webBrowser: WebBrowserViewController, didFinishLoad url: URL?) {
}
func webBrowser(_ webBrowser: WebBrowserViewController, didFailLoad url: URL?, withError error: Error) {
}
func webBrowserWillDismiss(_ webBrowser: WebBrowserViewController) {
completionHandler!()
}
func webBrowserDidDismiss(_ webBrowser: WebBrowserViewController) {
completionHandler!()
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if (animated && viewController == self) {
completionHandler!()
}
}
// func webBrowser(_ webBrowser: WebBrowserViewController, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) -> Bool {
// let url = navigationAction.request.url
// decisionHandler(.cancel)
// let closure = webBrowser.getWKWebView()
// executeDocumentDownloadScript(webView: closure, forAbsoluteUrl: url!.absoluteString)
//
// return true
// }
/*
Intercept the download of documents in webView, trigger the download in JavaScript and pass the binary file to JavaScript handler in Swift code
*/
private func executeDocumentDownloadScript(webView: WKWebView, forAbsoluteUrl absoluteUrl : String) {
// TODO: Add more supported mime-types for missing content-disposition headers
do {
let url = NetworkManager.sharedInstance.getDownloadJs()
let js = try String(contentsOf: url, encoding: .utf8)
let j = js.replacingOccurrences(of: "(absoluteUrl)", with: absoluteUrl)
webView.evaluateJavaScript(j) { (result, err) in
if (err != nil) {
debugPrint("JS ERR: \(String(describing: err))")
}
}
} catch {
print(error)
}
}
}