diff --git a/Podfile b/Podfile index d564137..dba01d7 100644 --- a/Podfile +++ b/Podfile @@ -13,5 +13,6 @@ target 'kplayer' do pod 'SnapKit' pod 'WebBrowser' pod 'FileBrowser' + pod 'ZIPFoundation' end diff --git a/Pods/Nimbus/src/photos/src/NIPhotoScrollView.m b/Pods/Nimbus/src/photos/src/NIPhotoScrollView.m index 196afb3..6512684 100644 --- a/Pods/Nimbus/src/photos/src/NIPhotoScrollView.m +++ b/Pods/Nimbus/src/photos/src/NIPhotoScrollView.m @@ -189,6 +189,8 @@ BOOL didZoomIn; + _scrollView.scrollEnabled = true; + if (isCompletelyZoomedIn) { // Zoom the photo back out. [_scrollView setZoomScale:_scrollView.minimumZoomScale animated:YES]; diff --git a/Pods/WebBrowser/WebBrowser/WebBrowserViewController.swift b/Pods/WebBrowser/WebBrowser/WebBrowserViewController.swift index fb6b268..baaaec7 100644 --- a/Pods/WebBrowser/WebBrowser/WebBrowserViewController.swift +++ b/Pods/WebBrowser/WebBrowser/WebBrowserViewController.swift @@ -282,7 +282,7 @@ extension WebBrowserViewController { extension WebBrowserViewController { // MARK: - Tool bar - fileprivate func updateToolBarState() { + public func updateToolBarState() { backButton.isEnabled = webView.canGoBack forwardButton.isEnabled = webView.canGoForward diff --git a/kplayer.xcodeproj/project.pbxproj b/kplayer.xcodeproj/project.pbxproj index 9f8e547..de7362b 100644 --- a/kplayer.xcodeproj/project.pbxproj +++ b/kplayer.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 1C736503B656C999E5E12081 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */; }; 1C73654C9EA6D255CFC039C5 /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */; }; 1C7365885FAF292F2221ED44 /* PhotoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73673DC671535E3A049F54 /* PhotoController.swift */; }; + 1C736662E43C6E8FFED11AC4 /* download.js in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C1368E0DE89BAA2DF60 /* download.js */; }; 1C7366A0CFD2B55BF8C3BAF0 /* NetworkDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7364F10BED5DA0F1C0423C /* NetworkDelegate.swift */; }; 1C7366DAC06047DE335EFC37 /* BMPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736927EA28AFBEB25D7487 /* BMPlayer.swift */; }; 1C73671FC2CCCACAA2FFC153 /* ThumbnailCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736EA15A11AF7D57F85824 /* ThumbnailCache.swift */; }; @@ -32,6 +33,7 @@ 1C73691A9C7174E0C6B57267 /* stringutil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736B794396F2E50387B8F2 /* stringutil.swift */; }; 1C73693A1334A7792856FC58 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73611D226B48C24DB37535 /* MasterViewController.swift */; }; 1C736953BDBBAFC40884132A /* BrowserController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73602350ACE2436736F981 /* BrowserController.swift */; }; + 1C73696E4C0353053BF98031 /* links.html in Resources */ = {isa = PBXBuildFile; fileRef = 1C73615FFA2AA98BD1C56CD4 /* links.html */; }; 1C7369ABC44CFB530EA71FB6 /* HeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */; }; 1C736A06A2AD75B8C14EEBBE /* HtmlParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DBB6986A8B62963FBB3 /* HtmlParser.swift */; }; 1C736A5FA5BA53B2597F2ED7 /* Kirschkeks-256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = 1C736059262A57AADE6AB761 /* Kirschkeks-256x256.png */; }; @@ -77,6 +79,7 @@ 1C7360D6580FB5D09C2BBCCB /* BMPlayerManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerManager.swift; sourceTree = ""; }; 1C73610B997EBA367C806C1B /* BMPlayerCompositionResourceDefinition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerCompositionResourceDefinition.swift; sourceTree = ""; }; 1C73611D226B48C24DB37535 /* MasterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; + 1C73615FFA2AA98BD1C56CD4 /* links.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = links.html; sourceTree = ""; }; 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkHelper.swift; sourceTree = ""; }; 1C73625012D50E457D18A785 /* kplayer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = kplayer.js; sourceTree = ""; }; 1C736253AB7A95EA41B605B7 /* ItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemModel.swift; sourceTree = ""; }; @@ -101,6 +104,7 @@ 1C736B41C6AC33F3FA592C63 /* MediaModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaModel.swift; sourceTree = ""; }; 1C736B794396F2E50387B8F2 /* stringutil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = stringutil.swift; sourceTree = ""; }; 1C736BC4450890C45F8FBC63 /* LayoutTools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutTools.swift; sourceTree = ""; }; + 1C736C1368E0DE89BAA2DF60 /* download.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = download.js; sourceTree = ""; }; 1C736C7FFBDAC665AE04CB65 /* VideoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoController.swift; sourceTree = ""; }; 1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderCell.swift; sourceTree = ""; }; 1C736DBB6986A8B62963FBB3 /* HtmlParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HtmlParser.swift; sourceTree = ""; }; @@ -160,6 +164,8 @@ isa = PBXGroup; children = ( 1C73625012D50E457D18A785 /* kplayer.js */, + 1C736C1368E0DE89BAA2DF60 /* download.js */, + 1C73615FFA2AA98BD1C56CD4 /* links.html */, ); path = server; sourceTree = ""; @@ -409,6 +415,7 @@ C98AF5E41B124D6A00D196CC /* LaunchScreen.xib in Resources */, C98AF5E11B124D6A00D196CC /* Images.xcassets in Resources */, 1C736A5FA5BA53B2597F2ED7 /* Kirschkeks-256x256.png in Resources */, + 1C73696E4C0353053BF98031 /* links.html in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -436,6 +443,7 @@ "${BUILT_PRODUCTS_DIR}/Nimbus/Nimbus.framework", "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework", "${BUILT_PRODUCTS_DIR}/WebBrowser/WebBrowser.framework", + "${BUILT_PRODUCTS_DIR}/ZIPFoundation/ZIPFoundation.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( @@ -446,6 +454,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimbus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WebBrowser.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZIPFoundation.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -518,6 +527,7 @@ 1C736A06A2AD75B8C14EEBBE /* HtmlParser.swift in Sources */, 1C736048BFA120F5C7D36874 /* readme.md in Sources */, 1C736771C503FB0D52AEB8F7 /* kplayer.js in Sources */, + 1C736662E43C6E8FFED11AC4 /* download.js in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/kplayer/Info.plist b/kplayer/Info.plist index b85200b..9943101 100644 --- a/kplayer/Info.plist +++ b/kplayer/Info.plist @@ -55,6 +55,8 @@ UIFileSharingEnabled + NSFaceIDUsageDescription + cool NSAppTransportSecurity NSAllowsArbitraryLoads diff --git a/kplayer/core/MediaItem.swift b/kplayer/core/MediaItem.swift index af81641..e8e8db0 100644 --- a/kplayer/core/MediaItem.swift +++ b/kplayer/core/MediaItem.swift @@ -47,6 +47,10 @@ class MediaItem: CustomDebugStringConvertible { var leaf = false var cancelled = false + var scale = 0.0 + var offset = CGPoint() + var size = CGSize() + convenience init(model: MediaModel) { self.init(name: model.name, path: model.path, root: model.root, type: model.type) @@ -54,6 +58,9 @@ class MediaItem: CustomDebugStringConvertible { self.length = model.length self.loop = model.loop self.thumbUrl = model.thumbURL + self.scale = model.scale + self.offset = model.offset + self.size = model.size for m in model.children { let item = MediaItem(model: m) @@ -77,6 +84,9 @@ class MediaItem: CustomDebugStringConvertible { model.loop = loop model.length = length ?? 0 model.thumbURL = thumbUrl + model.size = size + model.offset = offset + model.scale = scale return model } @@ -153,6 +163,10 @@ class MediaItem: CustomDebugStringConvertible { Absolute URL, unter der das Image des Items abgerufen werden kann. */ var imageUrlAbsolute: String { + if thumbUrl!.starts(with: "file:") { + return thumbUrl! + } + var imageUrl = thumbUrl!.replacingOccurrences(of: "_thumb.", with: ".") imageUrl = imageUrl.replacingOccurrences(of: "?preview=true", with: "") imageUrl = imageUrl.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)! diff --git a/kplayer/core/MediaModel.swift b/kplayer/core/MediaModel.swift index 1007750..412f69b 100644 --- a/kplayer/core/MediaModel.swift +++ b/kplayer/core/MediaModel.swift @@ -4,6 +4,7 @@ // import Foundation +import UIKit public struct MediaModel : Codable { let name: String @@ -15,6 +16,10 @@ public struct MediaModel : Codable { var loop = false var thumbURL : String? + var scale = 0.0 + var offset = CGPoint() + var size = CGSize() + var children: [MediaModel] let type: ItemType } diff --git a/kplayer/core/NetworkManager.swift b/kplayer/core/NetworkManager.swift index c923a07..549a1a3 100644 --- a/kplayer/core/NetworkManager.swift +++ b/kplayer/core/NetworkManager.swift @@ -46,12 +46,73 @@ class NetworkManager { func loadFavDirs(_ rootParam: String, completionHandler: @escaping Weiter) -> Void { var res = [MediaItem]() + var itemsMap = Dictionary() + + let fi = MediaItem(name: "images", path: "", root: "fav", type: ItemType.DETAILS) + fi.local = true + fi.loaded = true + + res.append(fi) + let url = FileHelper.getDocumentsDirectory() if let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) { for case let fileURL as URL in enumerator { do { let fileAttributes = try fileURL.resourceValues(forKeys:[.isRegularFileKey]) if fileAttributes.isRegularFile! { + if (fileURL.pathExtension == "jpg" && fileURL.absoluteString.contains("/images/")) { + let p = fileURL.absoluteString.substringAfter("/Documents") + + var path = p.substringBefore("/") + + let fp = fileURL.absoluteString.substringAfter("/Documents/images/") + + var fpath = fp.substringBefore("/") + + var folder = itemsMap[fpath] + + if folder == nil { + let f = MediaItem(name: fpath, path: "images", root: "fav", type: ItemType.PICS) + f.local = true + f.loaded = true + folder = f + itemsMap[fpath] = folder! + fi.children.append(f) + } + + let m = MediaItem(name: fileURL.lastPathComponent, path: path, root: "fav", type: ItemType.PICS) + m.local = true + m.loaded = true + m.thumbUrl = fileURL.absoluteString + + let jsonURL = fileURL.absoluteString.replacingOccurrences(of: ".jpg", with: ".json") + + do { + let jsonData = try Data(contentsOf: URL(string: jsonURL)!) + let item = try JSONDecoder().decode(MediaModel.self, from: jsonData) + m.scale = item.scale + m.offset = item.offset + m.size = item.size + } + catch { + + } + +// var folder = itemsMap[path] +// +// if folder == nil { +// folder = MediaItem(name: item.path, path: item.path, root: item.root, type: ItemType.FOLDER) +// folder!.loaded = true +// folder!.local = item.local +// itemsMap[path] = folder! +// items.append(folder!) +// } + + folder!.children.append(m) + + print(fileURL.absoluteString) + } + if (fileURL.pathExtension == "mp4") { print(fileURL.absoluteString) @@ -533,13 +594,13 @@ class NetworkManager { } } - func download(url: URL) { + func download(url: URL, path: String, result: @escaping (URL) -> () ) { UIApplication.shared.isIdleTimerDisabled = true let destination: DownloadRequest.Destination = {temporaryURL, response in if let suggestedFileName = response.suggestedFilename { do { - let directory = try FileHelper.createDir(name: "download") + let directory = try FileHelper.createDir(name: path) let downloadedFilePath = directory.appendingPathComponent(suggestedFileName) // if downloadedFilePath.exists { try self.downloadedFilePath?.deleteFile() } return (downloadedFilePath, [.removePreviousFile, .createIntermediateDirectories]) @@ -580,6 +641,7 @@ class NetworkManager { NetworkManager.sharedInstance.currentDownloads.removeValue(forKey: url.lastPathComponent) print("Success: \(statusCode)") } + result(destinationUrl) } } } diff --git a/kplayer/core/ThumbnailCache.swift b/kplayer/core/ThumbnailCache.swift index a643691..a15a9a1 100644 --- a/kplayer/core/ThumbnailCache.swift +++ b/kplayer/core/ThumbnailCache.swift @@ -107,9 +107,20 @@ class ThumbnailCache { return } + var file = false for k in start ..< end { - let tu = items[k].thumbUrl!.replacingOccurrences(of: "?preview=true", with: "") - preview += "\(tu);" + if items[k].thumbUrl!.starts(with:"file::") { + file = true + let thumbnail: (UIImage, Int) -> () = { (i: UIImage, thumbnailIndex: Int) in } + loadThumbnail(thumbnailIndex: k, thumbnail: thumbnail) + } + else { + let tu = items[k].thumbUrl!.replacingOccurrences(of: "?preview=true", with: "") + preview += "\(tu);" + } + } + if (file) { + return } preview = preview.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)! @@ -153,6 +164,32 @@ class ThumbnailCache { return nil } + func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage? { + let size = image.size + + let widthRatio = targetSize.width / size.width + let heightRatio = targetSize.height / size.height + + // Figure out what our orientation is, and use that to form the rectangle + var newSize: CGSize + if(widthRatio > heightRatio) { + newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio) + } else { + newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio) + } + + // This is the rect that we've calculated out and this is what is actually used below + let rect = CGRect(origin: .zero, size: newSize) + + // Actually do the resizing to the rect using the ImageContext stuff + UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0) + image.draw(in: rect) + let newImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + return newImage + } + func loadThumbnail(thumbnailIndex: Int, thumbnail: @escaping (UIImage, Int) -> ()) -> UIImage? { var image: UIImage? let newItem = items[thumbnailIndex] @@ -163,12 +200,16 @@ class ThumbnailCache { image = imageCache.object(forKey: URL.absoluteString as AnyObject) as? UIImage if (image == nil && (!loading||thumbnailIndex == 0)) { - let task: URLSessionDataTask = urlSession!.dataTask(with: URL) { + let task: URLSessionDataTask = urlSession!.dataTask(with: URL) { [self] (da, response, error) in if let d = da { - if let i = UIImage(data: d) { -// println("thumb image loaded \(newItem.thumbUrlAbsolute)") + if var i = UIImage(data: d) { + + if d.count > 500000 { + i = resizeImage(image: i, targetSize: CGSize(width: 1200, height: 1200))! + } + print("thumb image loaded \(newItem.thumbUrlAbsolute)") let imageRef = i.cgImage; self.imageCache.setObject(i, forKey: newItem.thumbUrlAbsolute as AnyObject, cost: d.count) diff --git a/kplayer/detail/BrowserController.swift b/kplayer/detail/BrowserController.swift index 1271030..41a2536 100644 --- a/kplayer/detail/BrowserController.swift +++ b/kplayer/detail/BrowserController.swift @@ -85,6 +85,8 @@ class BrowserController : UIViewController, ItemController, WebBrowserDelegate, self.completionHandler!() //self.navigationController?.popViewController(animated: true) } + let backButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(BrowserController.back(_:))) + webBrowserViewController.navigationItem.leftBarButtonItems = [backButton] let reviewButton = UIBarButtonItem(title:"download", style:UIBarButtonItem.Style.plain, target: self, action: #selector(BrowserController.doDownload(_:))) @@ -99,6 +101,16 @@ class BrowserController : UIViewController, ItemController, WebBrowserDelegate, executeDocumentDownloadScript(webView: web!.getWKWebView(), forAbsoluteUrl: "hello") } + @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)") @@ -154,8 +166,21 @@ class BrowserController : UIViewController, ItemController, WebBrowserDelegate, } 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 vc = VideoController() - let name = URL(string: url)!.lastPathComponent let hostcomp = currentItem!.name.split(separator: ".") let site = String(hostcomp[hostcomp.count-2]) @@ -179,6 +204,12 @@ class BrowserController : UIViewController, ItemController, WebBrowserDelegate, self.present(navController, animated: false, completion: nil) } + 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) } @@ -231,4 +262,16 @@ print(url?.absoluteString) } } + + func showAlert(title:String, message:String ) { + + let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) + + let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil) + alertVC.addAction(okAction) + + DispatchQueue.main.async() { () -> Void in + self.present(alertVC, animated: true, completion: nil) + } + } } diff --git a/kplayer/detail/DetailViewController.swift b/kplayer/detail/DetailViewController.swift index b918756..6187bf6 100644 --- a/kplayer/detail/DetailViewController.swift +++ b/kplayer/detail/DetailViewController.swift @@ -10,6 +10,7 @@ import UIKit import Alamofire import FileBrowser import AVFoundation +import ZIPFoundation protocol DetailDelegate { func loadDetails(selectedItem: MediaItem, completionHandler: @escaping () -> Void) @@ -105,13 +106,38 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout let files = FileHelper.listFiles(name: "") for f in files { if f.pathExtension == "mp4" { - try FileManager.default.moveItem(at: f, to: i.appendingPathComponent(f.lastPathComponent)) + var dest = i.appendingPathComponent(f.lastPathComponent) + try FileManager.default.moveItem(at: f, to: dest) + try FileHelper.setExcludeFromiCloudBackup(&dest, isExcluded: true) + } + } + } catch { + } + + do { + let i = try FileHelper.createDir(name: "images") + + let files = FileHelper.listFiles(name: "download") + for f in files { + print(f) + if f.pathExtension == "zip" { + var dest = i.appendingPathComponent(f.lastPathComponent) + + do { + try FileManager.default.createDirectory(at: dest, withIntermediateDirectories: true, attributes: nil) + try FileManager.default.unzipItem(at: f, to: dest) + } catch { + print("Extraction of ZIP archive failed with error:\(error)") + } + try FileManager.default.removeItem(at: f) + try FileHelper.setExcludeFromiCloudBackup(&dest, isExcluded: true) } } } catch { } let fileBrowser = FileBrowser(initialPath: d, allowEditing: true) + fileBrowser.modalPresentationStyle = .fullScreen present(fileBrowser, animated: true, completion: nil) } diff --git a/kplayer/detail/VideoController.swift b/kplayer/detail/VideoController.swift index 38b5b21..f62ff80 100644 --- a/kplayer/detail/VideoController.swift +++ b/kplayer/detail/VideoController.swift @@ -161,7 +161,9 @@ class VideoController: UIViewController, ItemController, BMPlayerDelegate { let downloadAction = UIAlertAction(title: "Download to fav", style: .default) { (action) in let url = self.currentItem!.playerURL - NetworkManager.sharedInstance.download(url: url!) + NetworkManager.sharedInstance.download(url: url!, path: "download") { url in + self.showAlert(title: url.lastPathComponent, message: "ready") + } } let url = self.currentItem!.playerURL diff --git a/kplayer/master/MasterViewController.swift b/kplayer/master/MasterViewController.swift index 831165f..d365294 100644 --- a/kplayer/master/MasterViewController.swift +++ b/kplayer/master/MasterViewController.swift @@ -296,11 +296,13 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating, UITa m.local = true let at = m.playerURL! m.path = destinationItem.path - let to = m.playerURL! + var to = m.playerURL! print(destinationItem.name) do { try FileManager.default.moveItem(at: at, to: to) + + try FileHelper.setExcludeFromiCloudBackup(&to, isExcluded: true) try FileManager.default.moveItem(at: at.appendingPathExtension("json"), to: to.appendingPathExtension("json")) do { try FileManager.default.moveItem(at: at.appendingPathExtension("jpg"), to: to.appendingPathExtension("jpg")) diff --git a/kplayer/master/NetworkDelegate.swift b/kplayer/master/NetworkDelegate.swift index 1a6a47e..a694f2d 100644 --- a/kplayer/master/NetworkDelegate.swift +++ b/kplayer/master/NetworkDelegate.swift @@ -66,7 +66,7 @@ class NetworkDelegate: MasterDelegate, DetailDelegate { func loadDetails(selectedItem: MediaItem, completionHandler: @escaping () -> ()) { - if selectedItem.isPic() { + if selectedItem.isPic() && !selectedItem.local { NetworkManager.sharedInstance.loadPicDetails(items: selectedItem, result: { (im: [MediaItem]) in selectedItem.children = im completionHandler() diff --git a/kplayer/photo/PhotoController.swift b/kplayer/photo/PhotoController.swift index 84aa700..6e95a7d 100644 --- a/kplayer/photo/PhotoController.swift +++ b/kplayer/photo/PhotoController.swift @@ -87,12 +87,41 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView let currentItem = items[photoAlbumView.centerPageIndex] var imageUrl = currentItem.thumbUrl!.replacingOccurrences(of: "_thumb.jpg", with: ".jpg") imageUrl = imageUrl.replacingOccurrences(of: "?preview=true", with: "") - let url = NetworkManager.sharedInstance.baseurl + "/service/linkfavpic" + imageUrl - print(url) - AF.request(url).responseString { - (result) in - print("ok") + if imageUrl.starts(with: "file://") { + + let pages = photoAlbumView.visiblePages()! + for case let page as NIPhotoScrollView in pages { + if (page.pageIndex == photoAlbumView.centerPageIndex) { + let scroll = page.value(forKey: "scrollView") as! UIScrollView + + if scroll.isScrollEnabled { + currentItem.scale = Double(scroll.zoomScale) + currentItem.offset = scroll.contentOffset + currentItem.size = scroll.contentSize + + let jsonFile = currentItem.path + "/" + currentItem.name.replacingOccurrences(of: ".jpg", with: ".json") + NetworkManager.sharedInstance.saveFavDir(name: jsonFile, item: currentItem) + // print(currentItem.toJSON()) + + scroll.isScrollEnabled = false + } + else { + scroll.isScrollEnabled = true + } + } + } + + + } + else { + let url = NetworkManager.sharedInstance.baseurl + "/service/linkfavpic" + imageUrl + + print(url) + AF.request(url).responseString { + (result) in + print("ok") + } } } @@ -288,6 +317,7 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView } let view2 = photoAlbumView.centerPageView() as! NIPhotoScrollView + restoreScrollState(currentIndex: currentIndex, view: view2) if view2.photoSize() != NIPhotoScrollViewPhotoSizeOriginal { if nextImage != nil && currentIndex == nextImageIndex { @@ -299,6 +329,7 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView i in // self.photoAlbumView.isZoomingAboveOriginalSizeEnabled = max(i.size.height, i.size.width) <= 6000; self.photoAlbumView.didLoadPhoto(i, at: currentIndex, photoSize: NIPhotoScrollViewPhotoSizeOriginal) + self.restoreScrollState(currentIndex: currentIndex, view: view2) }, index: currentIndex) loadOriginal = op2 op2.qualityOfService = QualityOfService.userInitiated @@ -346,6 +377,19 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView } + private func restoreScrollState(currentIndex: Int, view: NIPhotoScrollView) { + let item = items[currentIndex] + + if item.scale > 0.0 { + // view.setValue(false, forKey: "zoomingIsEnabled") + let scroll = view.value(forKey: "scrollView") as! UIScrollView + scroll.zoomScale = CGFloat(item.scale) + scroll.contentSize = item.size + scroll.contentOffset = item.offset + scroll.isScrollEnabled = false + } + } + func numberOfPages(in pagingScrollView: NIPagingScrollView) -> Int { let c = items.count return c diff --git a/kplayer/server/download.js b/kplayer/server/download.js new file mode 100644 index 0000000..cb0280c --- /dev/null +++ b/kplayer/server/download.js @@ -0,0 +1,97 @@ +(async function download() { + try { + window.webkit.messageHandlers.jsError.postMessage(document.cookie) + window.webkit.messageHandlers.jsError.postMessage(window.location.hostname) + + var links = [] + var linkname = "href" + window.kplayerUrls = [] + + if (window.location.hostname.endsWith("hegre.com")) { + links = document.querySelectorAll('a[class="members-only"], a[class="image-download"]') + linkname = "href" + } + else if (window.location.hostname == "www.kink.com") { + links = document.querySelectorAll('span[data-resolution="720"], span[data-resolution="1080"]') + linkname = "data-url" + } + else if (window.location.hostname.endsWith("xhamster.com")) { + var lnks = document.querySelectorAll('link[rel="preload"]') + + for (var i=0; i0) { + var base = u.split('/').slice(0,3).join('/') + window.webkit.messageHandlers.jsError.postMessage('base: ' + base) + window.webkit.messageHandlers.jsError.postMessage('url: ' + u) + var r = await fetch(u) + var data = await r.text() + + // Do something with your data + var lines = data.split('\n') + + for (let l of lines) { + if (!l.startsWith("#")) { + window.webkit.messageHandlers.jsError.postMessage('l: ' + base + l) + + window.kplayerUrls.push(base + l) + } + } + } + } + + } + else if (window.location.hostname.endsWith("xvideos.com")) { + if (html5player) { + if (html5player.url_hls) { + var u = html5player.url_hls + window.webkit.messageHandlers.jsError.postMessage(u) + + if (u.indexOf("hls.m3u8")>0) { + var base = u.split('/').slice(0,-1).join('/') + var r = await fetch(u) + var data = await r.text() + + // Do something with your data + var lines = data.split('\n') + + for (let l of lines) { + if (!l.startsWith("#")) { + window.kplayerUrls.push(base + "/" + l) + } + } + } + window.webkit.messageHandlers.jsError.postMessage(JSON.stringify(window.kplayerUrls)) + + window.kplayerUrls.push(u) + } + } + } + + links.forEach( + function(currentValue, currentIndex, listObj) { + window.webkit.messageHandlers.jsError.postMessage(JSON.stringify(currentValue)) + + window.kplayerUrls.push(currentValue.getAttribute(linkname)) + }, + 'myThisArg' + ); + window.webkit.messageHandlers.openDocument.postMessage(JSON.stringify(window.kplayerUrls)); + + // window.webkit.messageHandlers.jsError.postMessage("k"+links); + // we use a second try block here to have more detailed error information + // because of the nature of JS the outer try-catch doesn't know anything where the error happended + let res; + try { + + } catch (err) { + window.webkit.messageHandlers.jsError.postMessage('fetch threw, error: '+ err ); + return; + } + } catch (err) { + window.webkit.messageHandlers.jsError.postMessage('fetch threw, error: '+ err); + return; + } +})(); +// null is needed here as this eval returns the last statement and we can't return a promise +null; diff --git a/kplayer/server/links.html b/kplayer/server/links.html new file mode 100644 index 0000000..64aee23 --- /dev/null +++ b/kplayer/server/links.html @@ -0,0 +1,12 @@ + + +Google +XVID +XVID +XVID +XVID +XVID +XVID + + + diff --git a/kplayer/util/FileHelper.swift b/kplayer/util/FileHelper.swift index 215618a..d709e61 100644 --- a/kplayer/util/FileHelper.swift +++ b/kplayer/util/FileHelper.swift @@ -35,7 +35,7 @@ print(url) static func listFiles(name: String)-> [URL] { let fileManager = FileManager.default - let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0] //.appendingPathComponent(name) + let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent(name) print (documentsURL) do { let fileURLs = try fileManager.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil) @@ -46,4 +46,10 @@ print(url) } return [] } + + static func setExcludeFromiCloudBackup(_ fileOrDirectoryURL: inout URL, isExcluded: Bool) throws { + var values = URLResourceValues() + values.isExcludedFromBackup = isExcluded + try fileOrDirectoryURL.setResourceValues(values) + } } diff --git a/kplayer/util/ImageLoadOperation.swift b/kplayer/util/ImageLoadOperation.swift index 65e5b20..af61750 100644 --- a/kplayer/util/ImageLoadOperation.swift +++ b/kplayer/util/ImageLoadOperation.swift @@ -24,6 +24,10 @@ public class ImageLoadOperation: Operation { } override public func main() { + if imageURL.isFileURL { + usleep(100000) + } + if self.isCancelled { return } @@ -32,10 +36,15 @@ public class ImageLoadOperation: Operation { if let data = try? Data(contentsOf: imageURL) { // print("lazy fetch image ready \(imageURL)") if self.isCancelled { - // print("Decoding 1 cancelled") return } if let img = UIImage(data: data, scale: 1) { + if imageURL.isFileURL { + DispatchQueue.main.async { + self.succeeder(img) + } + return + } if let decodedImg = img.decodeImage() { if self.isCancelled { // print("Decoding 2 cancelled")