9 changed files with 416 additions and 299 deletions
-
4kplayer.xcodeproj/project.pbxproj
-
60kplayer/core/NetworkManager.swift
-
187kplayer/core/ThumbnailCache.swift
-
57kplayer/detail/DetailViewController.swift
-
310kplayer/photo/MediaPhotoController.swift
-
4kplayer/util/HanekeFetchOperation.swift
-
58kplayer/util/ImageLoadOperation.swift
-
14kplayer/util/UIImageExtension.swift
-
21kplayerTests/kplayerTests.swift
@ -0,0 +1,187 @@ |
|||||
|
// |
||||
|
// Created by Marco Schmickler on 2018-12-23. |
||||
|
// Copyright (c) 2018 Marco Schmickler. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
import Foundation |
||||
|
import UIKit |
||||
|
|
||||
|
class ThumbnailCache { |
||||
|
let items: [MediaItem] |
||||
|
var urlSession: Foundation.URLSession? |
||||
|
|
||||
|
var sessionOwner = false |
||||
|
|
||||
|
let dateFormatter = DateFormatter() |
||||
|
|
||||
|
var imageCache = NSCache<AnyObject, AnyObject>() |
||||
|
var total = 0 |
||||
|
var currentIndex = 80 |
||||
|
|
||||
|
let refresh: () -> Void; |
||||
|
|
||||
|
var loading = true; |
||||
|
|
||||
|
init(items: [MediaItem], refresh: @escaping () -> Void) { |
||||
|
self.items = items |
||||
|
self.refresh = refresh |
||||
|
|
||||
|
imageCache.totalCostLimit = 1024 * 1024 * 1024 |
||||
|
|
||||
|
if urlSession == nil { |
||||
|
sessionOwner = true |
||||
|
let configuration = URLSessionConfiguration.ephemeral; // backgroundSessionConfigurationWithIdentifier("imageLoad"); |
||||
|
configuration.httpMaximumConnectionsPerHost = 10; |
||||
|
configuration.timeoutIntervalForRequest = 100; |
||||
|
configuration.timeoutIntervalForResource = 200; |
||||
|
urlSession = Foundation.URLSession(configuration: configuration, delegate: nil, delegateQueue: nil); |
||||
|
} |
||||
|
|
||||
|
preload(0, count: 20) |
||||
|
preload(20, count: 20) |
||||
|
preload(40, count: 20) |
||||
|
preload(60, count: 20) |
||||
|
|
||||
|
usleep(10000) |
||||
|
} |
||||
|
|
||||
|
func loadData(_ d: Data, start: Int, end: Int) { |
||||
|
let bytes = Array(UnsafeBufferPointer(start: (d as NSData).bytes.bindMemory(to: UInt8.self, capacity: d.count), count: d.count)) |
||||
|
let string1 = NSString(data: d, encoding: String.Encoding.utf8.rawValue) |
||||
|
print(string1) |
||||
|
var index = 0 |
||||
|
let fHi = (Int(bytes[index]) << 24) + (Int(bytes[index+1]) << 16) |
||||
|
let f = fHi + (Int(bytes[index+2]) << 8) + Int(bytes[index+3]) |
||||
|
index += 4 |
||||
|
let time = dateFormatter.string(from: Date()) |
||||
|
print("\(time) start \(start) count \(f) size \(d.count)") |
||||
|
|
||||
|
var rest = self.items.count - self.currentIndex |
||||
|
|
||||
|
if rest > 20 { |
||||
|
rest = 20 |
||||
|
} |
||||
|
|
||||
|
if rest > 0 { |
||||
|
self.preload(self.currentIndex, count: rest) |
||||
|
self.currentIndex += rest |
||||
|
} else { |
||||
|
loading = false |
||||
|
DispatchQueue.main.async(execute: refresh) |
||||
|
} |
||||
|
|
||||
|
for bild in start ..< end { |
||||
|
let sizeHi = (Int(bytes[index]) << 24) + (Int(bytes[index+1]) << 16) |
||||
|
let size = (Int(bytes[index+2]) << 8) + Int(bytes[index+3]) + sizeHi |
||||
|
index += 4 |
||||
|
|
||||
|
if size > 0 { |
||||
|
// var buf = //UnsafeMutablePointer<UInt8>(&bytes[index]) |
||||
|
let part = d.subdata(in: index ..< (index + size)) |
||||
|
if let img = UIImage(data: part) { |
||||
|
let imageRef = img.cgImage; |
||||
|
self.total += d.count |
||||
|
|
||||
|
let i = self.items[bild] |
||||
|
// print("\(time) preload combi image loaded \(i.name) cost \(cost) total\(self.total)") |
||||
|
self.imageCache.setObject(img, forKey: i.thumbUrlAbsolute as AnyObject, cost: size) |
||||
|
} |
||||
|
} |
||||
|
index += size |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func preload(_ start: Int, count: Int) { |
||||
|
|
||||
|
dateFormatter.dateFormat = "HH:mm:ss.SSSZ" |
||||
|
|
||||
|
var preview = "" |
||||
|
var end = start + count |
||||
|
if end > items.count { |
||||
|
end = items.count |
||||
|
} |
||||
|
|
||||
|
if end < start { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
for k in start ..< end { |
||||
|
let tu = items[k].thumbUrl!.replacingOccurrences(of: "?preview=true", with: "") |
||||
|
preview += "\(tu);" |
||||
|
} |
||||
|
|
||||
|
preview = preview.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)! |
||||
|
|
||||
|
let u2 = "\(NetworkManager.sharedInstance.baseurl)/service/preload?preview=\(preview)" |
||||
|
let u3 = URL(string: u2) |
||||
|
|
||||
|
if let URL = u3 { |
||||
|
let time = dateFormatter.string(from: Date()) |
||||
|
print("\(time) preload image \(u2)") |
||||
|
|
||||
|
urlSession!.dataTask(with: URL, completionHandler: { |
||||
|
(da, response, error) in |
||||
|
if let d = da { |
||||
|
DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.high).async { |
||||
|
() -> Void in |
||||
|
self.loadData(d, start: start, end: end) |
||||
|
} |
||||
|
} |
||||
|
}) .resume() |
||||
|
} else { |
||||
|
print("## Invalid URL: \(u2)") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func cancel() { |
||||
|
imageCache.removeAllObjects() |
||||
|
|
||||
|
if sessionOwner { |
||||
|
urlSession!.invalidateAndCancel() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func getThumbnail(_ item: MediaItem) -> UIImage? { |
||||
|
let u1 = URL(string: item.thumbUrlAbsolute) |
||||
|
|
||||
|
if let URL = u1 { |
||||
|
return imageCache.object(forKey: URL.absoluteString as AnyObject) as? UIImage |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func loadThumbnail(thumbnailIndex: Int, thumbnail: @escaping (UIImage, Int) -> ()) -> UIImage? { |
||||
|
var image: UIImage? |
||||
|
let newItem = items[thumbnailIndex] |
||||
|
let u1 = URL(string: newItem.thumbUrlAbsolute) |
||||
|
|
||||
|
if let URL = u1 { |
||||
|
|
||||
|
image = imageCache.object(forKey: URL.absoluteString as AnyObject) as? UIImage |
||||
|
|
||||
|
if (image == nil && (!loading||thumbnailIndex == 0)) { |
||||
|
let task: URLSessionDataTask = urlSession!.dataTask(with: URL) { |
||||
|
(da, response, error) in |
||||
|
|
||||
|
if let d = da { |
||||
|
if let i = UIImage(data: d) { |
||||
|
// println("thumb image loaded \(newItem.thumbUrlAbsolute)") |
||||
|
let imageRef = i.cgImage; |
||||
|
self.imageCache.setObject(i, forKey: newItem.thumbUrlAbsolute as AnyObject, cost: d.count) |
||||
|
|
||||
|
DispatchQueue.main.async { |
||||
|
thumbnail(i, thumbnailIndex); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
task.resume() |
||||
|
} |
||||
|
} |
||||
|
else { |
||||
|
print("## Invalid URL: \(newItem.thumbUrlAbsolute)") |
||||
|
} |
||||
|
return image |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue