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