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.
657 lines
22 KiB
657 lines
22 KiB
//
|
|
// Created by Marco Schmickler on 24.05.15.
|
|
// Copyright (c) 2015 Marco Schmickler. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import Alamofire
|
|
|
|
class NetworkManager {
|
|
static let sharedInstance = NetworkManager()
|
|
|
|
let nodeurl = "http://linkstation:8081/"
|
|
let baseurl = "http://linkstation:8080/tomcat/media"
|
|
let vidurl = "http://linkstation:8089"
|
|
|
|
var authenticated = false
|
|
var offline = false
|
|
|
|
var favorites = MediaItem(name: "fav", path:"", root: "", type: ItemType.FAVROOT)
|
|
|
|
var currentDownloads = [String : MediaItem]()
|
|
|
|
lazy var operationQueue: OperationQueue = {
|
|
var queue = OperationQueue()
|
|
queue.name = "Backup queue"
|
|
queue.maxConcurrentOperationCount = 1
|
|
return queue
|
|
}()
|
|
|
|
|
|
internal typealias Weiter = ([MediaItem]) -> Void
|
|
|
|
func getDownloadJs() -> URL {
|
|
if offline {
|
|
let url = Bundle.main.url(forResource: "download.js", withExtension: nil)!
|
|
return url
|
|
}
|
|
return URL(string: "http://l inkstation:8089/ren/web/download.js")!
|
|
}
|
|
|
|
func saveFavDir(name: String, item: MediaItem) -> Void {
|
|
let json = item.toJSON()
|
|
let url = FileHelper.getDocumentsDirectory().appendingPathComponent(name)
|
|
do {
|
|
print (url)
|
|
try json.write(to: url, atomically: true, encoding: .utf8)
|
|
let input = try String(contentsOf: url)
|
|
print(input)
|
|
} catch {
|
|
print(json)
|
|
}
|
|
}
|
|
|
|
func loadFavDirs(_ rootParam: String, completionHandler: @escaping Weiter) -> Void {
|
|
var res = [MediaItem]()
|
|
|
|
var itemsMap = Dictionary<String, MediaItem>()
|
|
|
|
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)
|
|
|
|
let p = fileURL.absoluteString.substringAfter("/Documents")
|
|
|
|
var path = p.substringBefore("/")
|
|
|
|
let m = MediaItem(name: fileURL.lastPathComponent, path: path, root: "fav", type: ItemType.VIDEO)
|
|
m.local = true
|
|
m.thumbUrl = fileURL.appendingPathExtension("jpg").absoluteString
|
|
|
|
res.append(m)
|
|
|
|
}
|
|
}
|
|
} catch { print(error, fileURL) }
|
|
}
|
|
}
|
|
|
|
let m = MediaItem(name: "new", path: "new", root: "fav", type: ItemType.FOLDER)
|
|
m.local = true
|
|
res.append(m)
|
|
|
|
completionHandler(res)
|
|
}
|
|
|
|
func loadFav2Dirs(_ rootParam: String, completionHandler: @escaping Weiter) -> Void {
|
|
let files = FileHelper.listFiles(name: "1")
|
|
var res = [MediaItem]()
|
|
for f in files {
|
|
if f.pathExtension == "mp4" {
|
|
let m = MediaItem(name: f.lastPathComponent, path: "", root: "1", type: ItemType.VIDEO)
|
|
|
|
m.local = true
|
|
res.append(m)
|
|
}
|
|
}
|
|
|
|
completionHandler(res)
|
|
}
|
|
|
|
func loadFav1Dirs(_ rootParam: String, completionHandler: @escaping Weiter) -> Void {
|
|
var res = [MediaItem]()
|
|
|
|
do {
|
|
let jsonData = try FileHelper.getData(name: "fav.json")
|
|
let items = try JSONDecoder().decode(MediaModel.self, from: jsonData)
|
|
let loaded = MediaItem(model: items)
|
|
res = loaded.children
|
|
} catch {
|
|
print(error.localizedDescription)
|
|
}
|
|
|
|
// res.append(currentFav)
|
|
completionHandler(res)
|
|
}
|
|
|
|
func loadVideoDirs(_ rootParam: String, completionHandler: @escaping Weiter) -> Void {
|
|
var root = rootParam
|
|
|
|
if root.contains("*") {
|
|
root = String(rootParam[rootParam.startIndex..<rootParam.range(of: "*")!.lowerBound])
|
|
}
|
|
|
|
if root.endsWith("/") {
|
|
root = String(root[root.startIndex..<root.index(before: root.endIndex)])
|
|
}
|
|
let url1 = baseurl + "/service/listvideos" + rootParam
|
|
let len = root.count
|
|
var res = [MediaItem]()
|
|
let url = (url1 as NSString).replacingOccurrences(of: " ", with: "+")
|
|
print(url)
|
|
AF.request(url).responseJSON {
|
|
(response) in
|
|
|
|
if let json = response.value as? [String] {
|
|
print("Empfange \(json.count) Ergebnisse")
|
|
|
|
for s in json {
|
|
if s.hasSuffix(".mp4") || s.hasSuffix(".m4v") {
|
|
let l = s.count
|
|
let name = NSURL(fileURLWithPath: s).lastPathComponent!
|
|
var pathlen = l - len - name.count
|
|
|
|
if (pathlen < 2) {
|
|
pathlen = 2
|
|
}
|
|
|
|
let path = (s as NSString).substring(with: NSMakeRange(len + 1, pathlen - 2))
|
|
let i = MediaItem(name: name, path: path, root: root, type: ItemType.VIDEO)
|
|
if !name.hasPrefix(".") {
|
|
res.append(i)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
completionHandler(res)
|
|
}
|
|
}
|
|
|
|
func loadPicDirs(_ rootParam: String, completionHandler: @escaping Weiter) -> Void {
|
|
var root = rootParam
|
|
|
|
if root.contains("*") {
|
|
root = String(rootParam[rootParam.startIndex..<rootParam.range(of: "*")!.lowerBound])
|
|
}
|
|
|
|
if root.endsWith("/") {
|
|
root = String(root[root.startIndex..<root.index(before: root.endIndex)])
|
|
}
|
|
|
|
let url1 = baseurl + "/service/listpicdirs" + rootParam
|
|
let len = root.count
|
|
var res = [MediaItem]()
|
|
let url = (url1 as NSString).replacingOccurrences(of: " ", with: "+")
|
|
print(url)
|
|
|
|
AF.request(url).responseJSON {
|
|
(response) in
|
|
|
|
if let json = response.value {
|
|
var items = Dictionary<String, MediaItem>()
|
|
|
|
let result = json as! [String]
|
|
print("Empfange \(result.count) Ergebnisse")
|
|
|
|
for s in result {
|
|
if s.lowercased().hasSuffix(".jpg") {
|
|
let l = s.count
|
|
let name = (s as NSString).lastPathComponent
|
|
var pathlen = l - len - name.count
|
|
|
|
if (pathlen < 2) {
|
|
pathlen = 2
|
|
}
|
|
|
|
let path = (s as NSString).substring(with: NSMakeRange(len + 1, pathlen - 2))
|
|
|
|
let folderName = NSURL(fileURLWithPath: path).lastPathComponent!
|
|
let fl = path.count
|
|
let pfl = fl - folderName.count
|
|
|
|
let fpath = (path as NSString).substring(with: NSMakeRange(0, pfl))
|
|
|
|
let i = MediaItem(name: folderName, path: fpath, root: root, type: ItemType.PICS)
|
|
i.thumbUrl = "\(s)?preview=true"
|
|
i.loaded = true
|
|
if !name.hasPrefix(".") {
|
|
if let picfolder = items[path] {
|
|
picfolder.children.append(i)
|
|
} else {
|
|
let iff = MediaItem(name: folderName, path: fpath, root: root, type: ItemType.PICS)
|
|
iff.thumbUrl = i.thumbUrl
|
|
|
|
items[path] = iff
|
|
res.append(iff)
|
|
iff.children.append(i)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
completionHandler(res)
|
|
}
|
|
}
|
|
|
|
func deleteLocal(selectedItem: MediaItem) {
|
|
if (selectedItem.local) {
|
|
print(selectedItem.playerURL?.absoluteString)
|
|
do {
|
|
try FileManager.default.removeItem(at: selectedItem.playerURL!)
|
|
} catch {
|
|
print(error)
|
|
}
|
|
}
|
|
}
|
|
|
|
func listDirs(_ root: String, completionHandler: @escaping ([MediaItem], Bool) -> Void) -> Void {
|
|
let len = root.count
|
|
let url = (root as NSString).replacingOccurrences(of: " ", with: "+")
|
|
|
|
let ux = nodeurl + "listdirs" + url
|
|
print(ux)
|
|
AF.request(ux).responseJSON {
|
|
(response) in
|
|
|
|
if let json = response.value {
|
|
var res = [MediaItem]()
|
|
var leaf = false
|
|
var hasPics = false
|
|
|
|
let result = json as! [[String]]
|
|
|
|
print("Empfange \(result.count) Ergebnisse")
|
|
|
|
for s in result {
|
|
var name = s[0]
|
|
var type = s[1]
|
|
|
|
var t = ItemType.FOLDER
|
|
|
|
if (type == "video") {
|
|
t = ItemType.VIDEO
|
|
}
|
|
if (type == "pictures") {
|
|
t = ItemType.DETAILS
|
|
}
|
|
if (type == "web") {
|
|
t = ItemType.WEB
|
|
}
|
|
|
|
let i = MediaItem(name: name, path: name, root: root, type: t)
|
|
res.append(i)
|
|
}
|
|
completionHandler(res, leaf)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func loadItems(_ item: MediaItem) {
|
|
if (offline) {
|
|
return
|
|
}
|
|
|
|
if item.local {
|
|
if item.name == "download" {
|
|
var nodes = [MediaItem]()
|
|
for c in item.children {
|
|
if c.type != ItemType.DOWNLOAD {
|
|
nodes.append(c)
|
|
}
|
|
|
|
}
|
|
for d in NetworkManager.sharedInstance.currentDownloads {
|
|
nodes.append(d.value)
|
|
}
|
|
item.children = nodes
|
|
}
|
|
return
|
|
}
|
|
|
|
if (item.type == ItemType.WEB) {
|
|
let url = URL(string: vidurl)!.appendingPathComponent(item.root.substringStartingFrom(10)).appendingPathComponent(item.path).appendingPathComponent("links.html")
|
|
|
|
let parser = HtmlParser(url: url)
|
|
parser.parse()
|
|
|
|
item.children = parser.items
|
|
|
|
NotificationCenter.default.post(name: Notification.Name(rawValue: "loadedItems"), object: nil)
|
|
|
|
return
|
|
}
|
|
|
|
if (item.type != ItemType.VIDEO && item.type != ItemType.DETAILS) {
|
|
return
|
|
}
|
|
|
|
var j = 0
|
|
for i in item.children {
|
|
loadItem(i, index: j)
|
|
j+=1
|
|
}
|
|
NotificationCenter.default.post(name: Notification.Name(rawValue: "loadedItems"), object: nil)
|
|
}
|
|
|
|
func loadItem(_ item: MediaItem, index: Int) {
|
|
if (item.type != ItemType.VIDEO) {
|
|
var j = 0
|
|
for i in item.children {
|
|
loadItem(i, index: j)
|
|
j+=1
|
|
}
|
|
return
|
|
}
|
|
|
|
if item.loaded {
|
|
return
|
|
}
|
|
|
|
if !item.children.isEmpty {
|
|
return
|
|
}
|
|
|
|
let url = baseurl + "/service/listfiles" + item.snapshotDirPathForVideo
|
|
|
|
print(url)
|
|
|
|
AF.request(url).responseJSON {
|
|
(response) in
|
|
|
|
if let json = response.value {
|
|
var hashes = Dictionary<String, String>()
|
|
|
|
for b in json as! [String] {
|
|
|
|
let p = NSURL(fileURLWithPath: b).lastPathComponent!
|
|
|
|
if p.contains("_thumb.jpg") {
|
|
let ts = p.substringWithoutLast(10)
|
|
|
|
hashes[ts] = b
|
|
} else {
|
|
let ts = p.substringWithoutLast(4)
|
|
|
|
if hashes[ts] == nil {
|
|
hashes[ts] = b
|
|
}
|
|
}
|
|
}
|
|
|
|
item.children.removeAll(keepingCapacity: true)
|
|
|
|
for (ts, p) in hashes {
|
|
let t = (ts as NSString).doubleValue / 1000
|
|
|
|
let snap = MediaItem(name: item.name, path: item.path, root: item.root, type: .SNAPSHOT)
|
|
snap.time = t
|
|
snap.thumbUrl = p
|
|
|
|
snap.parent = item
|
|
snap.loaded = true
|
|
item.children.append(snap)
|
|
}
|
|
|
|
item.loaded = true
|
|
NotificationCenter.default.post(name: Notification.Name(rawValue: "loadedItems"), object: item)
|
|
}
|
|
}
|
|
}
|
|
|
|
func deleteThumb(_ path: String) {
|
|
let p = self.nodeurl + "deleteThumb\(path)"
|
|
print("Delete \(path)")
|
|
AF.request(p).responseString { response in
|
|
print(response)
|
|
}
|
|
}
|
|
|
|
func alive() {
|
|
let p = self.nodeurl + "alive"
|
|
print("alive")
|
|
AF.request(p).responseString { response in
|
|
self.offline = response.value == nil
|
|
print(response.result)
|
|
}
|
|
}
|
|
|
|
func favItem(_ item: MediaItem) {
|
|
let url = baseurl + "/service/linkfav" + item.fullPath
|
|
|
|
AF.request(url)
|
|
}
|
|
|
|
func saveItem(_ item: MediaItem) {
|
|
print(item.children)
|
|
|
|
if (item.local) {
|
|
return
|
|
}
|
|
|
|
if (item.type != ItemType.VIDEO) {
|
|
return
|
|
}
|
|
|
|
let url = baseurl + "/service/listfiles" + item.snapshotDirPathForVideo
|
|
|
|
print(url)
|
|
|
|
AF.request(url).responseJSON {
|
|
(response) in
|
|
|
|
var hashes = Set<String>()
|
|
|
|
if let json = response.value {
|
|
for b in json as! [String] {
|
|
hashes.insert(b)
|
|
print(b)
|
|
}
|
|
}
|
|
|
|
for c in item.children {
|
|
if let t = c.time {
|
|
let ms = Int(t * 1000)
|
|
let p = c.snapshotDirPathForVideo + "\(ms).jpg"
|
|
let pt = c.snapshotDirPathForVideo + "\(ms)_thumb.jpg"
|
|
print(p)
|
|
if hashes.contains(pt) {
|
|
print("contained")
|
|
} else {
|
|
if let id = c.image, let imageData = id.jpegData(compressionQuality: 1.0) {
|
|
let op = UploadOperation(baseUrl: self.nodeurl + "upload", data: imageData, path: p)
|
|
self.operationQueue.addOperation(op)
|
|
|
|
let thumb = id.scaleToSize(15 * 16, height: 15 * 9)
|
|
if let imageDataT = thumb.jpegData(compressionQuality: 1.0) {
|
|
c.image = thumb
|
|
let opT = UploadOperation(baseUrl: self.nodeurl + "upload", data: imageDataT, path: pt)
|
|
self.operationQueue.addOperation(opT)
|
|
}
|
|
|
|
c.loaded = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func loadPicDetails(items: MediaItem, result: @escaping ([MediaItem]) -> () ) {
|
|
let len = items.root.count
|
|
let url = NetworkManager.sharedInstance.baseurl + "/service/listfiles" + items.fullPath
|
|
|
|
print(items)
|
|
print(url)
|
|
|
|
AF.request(url).responseJSON {
|
|
(response) in
|
|
|
|
if let json = response.value {
|
|
var im = [MediaItem]()
|
|
|
|
for s in json as! [String] {
|
|
|
|
if s.lowercased().hasSuffix(".jpg") {
|
|
let l = s.count
|
|
let name = NSURL(fileURLWithPath: s).lastPathComponent!
|
|
var pathlen = l - len - name.count
|
|
|
|
print(pathlen)
|
|
print(name)
|
|
print(s)
|
|
|
|
if (pathlen < 2) {
|
|
pathlen = 2
|
|
}
|
|
|
|
let path = (s as NSString).substring(with: NSMakeRange(len + 1, pathlen - 2))
|
|
|
|
let folderName = NSURL(fileURLWithPath: path).lastPathComponent!
|
|
let fl = path.count
|
|
let pfl = fl - folderName.count
|
|
|
|
print("\(folderName) \(pfl)")
|
|
let fpath = s.substringLeft(pfl)
|
|
|
|
let i = MediaItem(name: folderName, path: fpath, root: items.root, type: ItemType.PICS)
|
|
i.thumbUrl = "\(s)?preview=true"
|
|
if !name.hasPrefix(".") {
|
|
im.append(i)
|
|
}
|
|
}
|
|
}
|
|
result(im)
|
|
}
|
|
}
|
|
}
|
|
|
|
func downloadToServer(path: String, url: URL) {
|
|
let name = path + "/" + url.lastPathComponent
|
|
let queryItems = [URLQueryItem(name: "url", value: url.absoluteString), URLQueryItem(name: "name", value: name)]
|
|
|
|
let cmd: String
|
|
if url.pathExtension == "m3u8" {
|
|
cmd = "ffmpeg"
|
|
}
|
|
else {
|
|
cmd = "webdl"
|
|
}
|
|
|
|
var urlComps = URLComponents(string: nodeurl + cmd)!
|
|
urlComps.queryItems = queryItems
|
|
let p = urlComps.url!
|
|
print("ffmpeg \(url.lastPathComponent)")
|
|
AF.request(p).responseString { response in
|
|
print(response)
|
|
}
|
|
}
|
|
|
|
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: path)
|
|
let downloadedFilePath = directory.appendingPathComponent(suggestedFileName)
|
|
// if downloadedFilePath.exists { try self.downloadedFilePath?.deleteFile() }
|
|
return (downloadedFilePath, [.removePreviousFile, .createIntermediateDirectories])
|
|
|
|
} catch let e {
|
|
print("Failed to get temporary directory - \(e)")
|
|
}
|
|
}
|
|
|
|
let (downloadedFileURL, _) = DownloadRequest.suggestedDownloadDestination()(temporaryURL, response)
|
|
return (downloadedFileURL, [.removePreviousFile, .createIntermediateDirectories])
|
|
}
|
|
|
|
let request = AF.download(url, to: destination)
|
|
|
|
request.downloadProgress(queue: .main, closure: { (progress) in
|
|
|
|
let name = url.lastPathComponent
|
|
var dl = NetworkManager.sharedInstance.currentDownloads[name]
|
|
if dl == nil && !request.isCancelled {
|
|
dl = MediaItem(name: name, path: name, root: "", type: ItemType.DOWNLOAD)
|
|
NetworkManager.sharedInstance.currentDownloads[name] = dl
|
|
}
|
|
|
|
if (dl!.cancelled) {
|
|
request.cancel()
|
|
NetworkManager.sharedInstance.currentDownloads.removeValue(forKey: name)
|
|
}
|
|
|
|
dl!.length = progress.fractionCompleted
|
|
//progress closure
|
|
print(progress.fractionCompleted)
|
|
}).responseData { response in
|
|
if let destinationUrl = response.fileURL {
|
|
print(destinationUrl)
|
|
|
|
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
|
|
NetworkManager.sharedInstance.currentDownloads.removeValue(forKey: url.lastPathComponent)
|
|
print("Success: \(statusCode)")
|
|
}
|
|
result(destinationUrl)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|