Browse Source

Delegates

master
marcoschmickler 5 years ago
parent
commit
4b1ffa6193
  1. 4
      kplayer.xcodeproj/project.pbxproj
  2. 8
      kplayer/AppDelegate.swift
  3. 39
      kplayer/core/ItemModel.swift
  4. 31
      kplayer/core/MediaItem.swift
  5. 1
      kplayer/core/MediaModel.swift
  6. 78
      kplayer/core/NetworkManager.swift
  7. 2
      kplayer/core/ThumbnailCache.swift
  8. 9
      kplayer/detail/DetailViewController.swift
  9. 37
      kplayer/detail/VideoController.swift
  10. 49
      kplayer/master/MasterViewController.swift
  11. 57
      kplayer/master/NetworkDelegate.swift
  12. 16
      kplayer/photo/PhotoController.swift
  13. 2
      kplayer/readme.md
  14. 27
      kplayer/util/FileHelper.swift
  15. 4
      kplayer/util/UploadOperation.swift
  16. 64
      kplayer/util/VideoHelper.swift
  17. 16
      kplayer/util/stringutil.swift

4
kplayer.xcodeproj/project.pbxproj

@ -25,6 +25,7 @@
1C7367AF39961D2BA72480ED /* DataLoadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736F9338CE36708244D42A /* DataLoadOperation.swift */; };
1C7367FA10AE13598FDDE865 /* BMPlayerProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365F45D765A218FFC100F /* BMPlayerProtocols.swift */; };
1C736821D6DF2237A3EABCC1 /* ViewControllerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73648CEC974A2500172064 /* ViewControllerExtensions.swift */; };
1C7368242038C0FF6C9631E7 /* VideoHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7364709899FF62774B0199 /* VideoHelper.swift */; };
1C73688D13E5A804880C8768 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */; };
1C73691A9C7174E0C6B57267 /* stringutil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736B794396F2E50387B8F2 /* stringutil.swift */; };
1C73693A1334A7792856FC58 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73611D226B48C24DB37535 /* MasterViewController.swift */; };
@ -77,6 +78,7 @@
1C736253AB7A95EA41B605B7 /* ItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemModel.swift; sourceTree = "<group>"; };
1C736260E748CF136FF37EA7 /* UploadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadOperation.swift; sourceTree = "<group>"; };
1C73631C96E6C860833052CA /* ItemType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemType.swift; sourceTree = "<group>"; };
1C7364709899FF62774B0199 /* VideoHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoHelper.swift; sourceTree = "<group>"; };
1C73648CEC974A2500172064 /* ViewControllerExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewControllerExtensions.swift; sourceTree = "<group>"; };
1C7364F10BED5DA0F1C0423C /* NetworkDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkDelegate.swift; sourceTree = "<group>"; };
1C7364F924BD979294C3EE4A /* BMPlayerItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerItem.swift; sourceTree = "<group>"; };
@ -181,6 +183,7 @@
1C736B794396F2E50387B8F2 /* stringutil.swift */,
1C73648CEC974A2500172064 /* ViewControllerExtensions.swift */,
1C7367ECBD369A2A0C94C499 /* FileHelper.swift */,
1C7364709899FF62774B0199 /* VideoHelper.swift */,
);
path = util;
sourceTree = "<group>";
@ -496,6 +499,7 @@
1C736A7B6221A1D50FB3904C /* ItemType.swift in Sources */,
1C7360C0F2A4F0214FE353BD /* FileHelper.swift in Sources */,
1C7366A0CFD2B55BF8C3BAF0 /* NetworkDelegate.swift in Sources */,
1C7368242038C0FF6C9631E7 /* VideoHelper.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

8
kplayer/AppDelegate.swift

@ -42,10 +42,10 @@ google
MediaItem(name: "knk_archiv2", path:"", root: "/srv/samba/ren/knk_archiv2", type: ItemType.VIDEOROOT),
MediaItem(name: "knk_archiv3", path:"", root: "/srv/samba/ren/knk_archiv3", type: ItemType.VIDEOROOT),
MediaItem(name: "knk_archiv4", path:"", root: "/srv/samba/ren/knk_archiv4", type: ItemType.VIDEOROOT),
MediaItem(name: "real", path:"", root: "/srv/samba/ren/real", type: ItemType.VIDEOROOT),
MediaItem(name: "fetish", path:"", root: "/srv/samba/ren/fetish", type: ItemType.VIDEOROOT),
MediaItem(name: "fjoy", path:"", root: "/srv/samba/ren/fjoy", type: ItemType.PICROOT),
MediaItem(name: "heg", path:"", root: "/srv/samba/ren/heg", type: ItemType.PICROOT),
MediaItem(name: "hegvid", path:"", root: "/srv/samba/ren/heg/videos", type: ItemType.VIDEOROOT),
MediaItem(name: "ten", path:"", root: "/srv/samba/ren/ten", type: ItemType.PICROOT),
MediaItem(name: "leg", path:"", root: "/srv/samba/ren/leg", type: ItemType.PICROOT),
MediaItem(name: "ang", path:"", root: "/srv/samba/ren/ang", type: ItemType.PICROOT),
@ -56,6 +56,12 @@ google
web,
]
NetworkManager.sharedInstance.alive()
Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { (t) in
NetworkManager.sharedInstance.alive()
}
return true
}

39
kplayer/core/ItemModel.swift

@ -10,12 +10,19 @@ class ItemModel {
var itemsMap = Dictionary<String, MediaItem>()
func addItem(_ item: MediaItem) {
if item.path == "" {
item.index = items.count
items.append(item)
return
}
let path = item.encodedDir!
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!)
}
@ -30,4 +37,36 @@ class ItemModel {
itemsMap.removeAll()
}
func sortItems(selectedItem: MediaItem, children: [MediaItem]) {
for f in children {
addItem(f)
}
selectedItem.children = items
selectedItem.loaded = false
if selectedItem.path.contains("*") {
selectedItem.loaded = true
} else
{
var all: [MediaItem]?
for f in selectedItem.children {
print(f.path)
if f.type == ItemType.FOLDER && f.path == "" {
all = f.children
break
}
}
if all != nil {
selectedItem.children = all!
selectedItem.loaded = false
for f in all! {
f.loaded = false
f.parent = selectedItem
}
}
}
}
}

31
kplayer/core/MediaItem.swift

@ -42,12 +42,15 @@ class MediaItem: CustomDebugStringConvertible {
var loop = true
var thumbUrl: String?
var local = false
convenience init(model: MediaModel) {
self.init(name: model.name, path: model.path, root: model.root, type: model.type)
self.time = model.time
self.length = model.length
self.loop = model.loop
self.thumbUrl = model.thumbURL
for m in model.children {
let item = MediaItem(model: m)
@ -70,6 +73,8 @@ class MediaItem: CustomDebugStringConvertible {
model.time = time ?? 0
model.loop = loop
model.length = length ?? 0
model.thumbURL = thumbUrl
return model
}
@ -146,6 +151,15 @@ class MediaItem: CustomDebugStringConvertible {
}
var playerURL: URL? {
if local {
var file = FileHelper.getDocumentsDirectory()
if (path != "") {
file = file.appendingPathComponent(path)
}
file = file.appendingPathComponent(name)
return file
}
let enc = name.replacingOccurrences(of: " ", with: "%20")
let index = encodedDir!.index(encodedDir!.startIndex, offsetBy: 10)
let s = NetworkManager.sharedInstance.vidurl + encodedDir!.substring(from:index)
@ -189,6 +203,12 @@ class MediaItem: CustomDebugStringConvertible {
children.sort(by: {
$0.sortName < $1.sortName
})
var j = 0
for i in children {
i.index = j
j += 1
}
}
func isWeb() -> Bool {
@ -200,14 +220,19 @@ class MediaItem: CustomDebugStringConvertible {
}
func isVideo() -> Bool {
return (superRoot().type == ItemType.VIDEOROOT || superRoot().type == ItemType.FAVROOT) && (type == ItemType.VIDEO || type == ItemType.SNAPSHOT)
return (superRoot().type == ItemType.VIDEOROOT || (superRoot().type == ItemType.VIDEO) || local) && (type == ItemType.VIDEO || type == ItemType.SNAPSHOT)
}
func isDetails() -> Bool {
return type == ItemType.DETAILS || type == ItemType.FAVROOT
if !children.isEmpty {
if (children[0].type == ItemType.VIDEO) {
return true;
}
}
return type == ItemType.DETAILS
}
func isFolder() -> Bool {
return type == ItemType.PICROOT || type == ItemType.VIDEOROOT || type == ItemType.FOLDER || type == ItemType.WEBROOT
return type == ItemType.PICROOT || type == ItemType.VIDEOROOT || type == ItemType.FOLDER || type == ItemType.WEBROOT || type == ItemType.FAVROOT
}
}

1
kplayer/core/MediaModel.swift

@ -13,6 +13,7 @@ public struct MediaModel : Codable {
var time = 0.0
var length = 0.0
var loop = false
var thumbURL : String?
var children: [MediaModel]
let type: ItemType

78
kplayer/core/NetworkManager.swift

@ -10,13 +10,13 @@ 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 authenticated = true
var favorites = MediaItem(name: "fav", path:"", root: "", type: ItemType.FAVROOT)
var currentFav = MediaItem(name: "current", path:"", root: "", type: ItemType.FOLDER)
lazy var operationQueue: OperationQueue = {
var queue = OperationQueue()
@ -41,16 +41,63 @@ class NetworkManager {
}
}
func loadFavFolders(_ rootParam: String, completionHandler: @escaping Weiter) -> Void {
}
func loadFavDirs(_ rootParam: String, completionHandler: @escaping Weiter) -> Void {
var res = [MediaItem]()
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 == "mp4") {
print(fileURL.absoluteString)
let p = fileURL.absoluteString.substringAfter("/Documents")
var path = p.substringBefore("/")
let m = MediaItem(name: fileURL.lastPathComponent, path: path, root: "1", type: ItemType.VIDEO)
m.local = true
res.append(m)
}
}
} catch { print(error, fileURL) }
}
}
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)
currentFav.loaded = true
res = loaded.children
// currentFav.children.append(loaded)
} catch {
print(error.localizedDescription)
}
@ -229,6 +276,10 @@ class NetworkManager {
}
func loadItems(_ item: MediaItem) {
if item.local {
return
}
if (item.type != ItemType.FOLDER && item.type != ItemType.DETAILS) {
return
}
@ -311,7 +362,17 @@ class NetworkManager {
}
func deleteThumb(_ path: String) {
AF.request(NetworkManager.sharedInstance.baseurl + "/service/deletethumb\(path)").responseString { response in
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
print(response)
}
}
@ -325,6 +386,9 @@ class NetworkManager {
func saveItem(_ item: MediaItem) {
print(item.children)
if (item.local) {
return
}
if (item.type != ItemType.VIDEO) {
return
@ -356,13 +420,13 @@ class NetworkManager {
print("contained")
} else {
if let id = c.image, let imageData = id.jpegData(compressionQuality: 1.0) {
let op = UploadOperation(baseUrl: self.baseurl + "/service/upload", data: imageData, path: p)
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.baseurl + "/service/upload", data: imageDataT, path: pt)
let opT = UploadOperation(baseUrl: self.nodeurl + "upload", data: imageDataT, path: pt)
self.operationQueue.addOperation(opT)
}

2
kplayer/core/ThumbnailCache.swift

@ -75,7 +75,7 @@ class ThumbnailCache {
let size = (Int(bytes[index+2]) << 8) + Int(bytes[index+3]) + sizeHi
index += 4
if size > 0 {
if size > 0 && (d.count >= index + size){
// var buf = //UnsafeMutablePointer<UInt8>(&bytes[index])
let part = d.subdata(in: index ..< (index + size))
if let img = UIImage(data: part) {

9
kplayer/detail/DetailViewController.swift

@ -117,6 +117,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
self.dismiss(animated: true, completion: nil);
}
let navController = UINavigationController(rootViewController: pc) // Creating a navigation controller with pc at the root of the navigation stack.
navController.modalPresentationStyle = .fullScreen
present(navController, animated: false, completion: nil)
}
@ -138,9 +139,9 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
if let detail: MediaItem = self.detailItem {
if i.type == ItemType.VIDEO {
if i.parent!.type != ItemType.DETAILS {
let path = IndexPath(item: index, section: i.parent!.index)
self.collectionView.reloadItems(at: [path])
let set = IndexSet(integer: index)
if index < detail.children.count {
collectionView.reloadSections(set)
}
} else {
if i.parent! !== detail {
@ -335,7 +336,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout
func showVideo(selectedItem: MediaItem) {
var pc: ItemController?
pc = AVPlayerController()
pc = VideoController()
pc!.setCurrentItem(item: selectedItem)
pc!.setItems(items: detailItem!.children)

37
kplayer/detail/VideoController.swift

@ -14,7 +14,7 @@ protocol ItemController {
func setCompletionHandler(handler: @escaping (() -> Void))
}
class AVPlayerController: UIViewController, ItemController, BMPlayerDelegate {
class VideoController: UIViewController, ItemController, BMPlayerDelegate {
var player = BMPlayer()
var currentItem: MediaItem?
var currentSnapshot: MediaItem?
@ -52,16 +52,16 @@ class AVPlayerController: UIViewController, ItemController, BMPlayerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
barbutton = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(AVPlayerController.captureThumbnail));
barbutton = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(VideoController.captureThumbnail));
navigationItem.rightBarButtonItems = [barbutton!]
backButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(AVPlayerController.back(_:)))
speedButton = UIBarButtonItem(title:"1.0", style:UIBarButtonItem.Style.plain, target: self, action: #selector(AVPlayerController.speed(_:)))
loopButton = UIBarButtonItem(title:"1.0", style:UIBarButtonItem.Style.plain, target: self, action: #selector(AVPlayerController.loop(_:)))
aspectButton = UIBarButtonItem(title:"1", style:UIBarButtonItem.Style.plain, target: self, action: #selector(AVPlayerController.aspect(_:)))
playButton = UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(AVPlayerController.startstop(_:)))
favButton = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(AVPlayerController.favorite(_:)))
reviewButton = UIBarButtonItem(title:"Edit ", style:UIBarButtonItem.Style.plain, target: self, action: #selector(AVPlayerController.doEdit(_:)))
backButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(VideoController.back(_:)))
speedButton = UIBarButtonItem(title:"1.0", style:UIBarButtonItem.Style.plain, target: self, action: #selector(VideoController.speed(_:)))
loopButton = UIBarButtonItem(title:"1.0", style:UIBarButtonItem.Style.plain, target: self, action: #selector(VideoController.loop(_:)))
aspectButton = UIBarButtonItem(title:"1", style:UIBarButtonItem.Style.plain, target: self, action: #selector(VideoController.aspect(_:)))
playButton = UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(VideoController.startstop(_:)))
favButton = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(VideoController.favorite(_:)))
reviewButton = UIBarButtonItem(title:"Edit ", style:UIBarButtonItem.Style.plain, target: self, action: #selector(VideoController.doEdit(_:)))
navigationItem.leftBarButtonItems = [backButton!, speedButton!, playButton!, loopButton!, aspectButton!, favButton!, reviewButton!]
@ -119,7 +119,16 @@ class AVPlayerController: UIViewController, ItemController, BMPlayerDelegate {
print("favorite")
if let c = currentSnapshot {
NetworkManager.sharedInstance.currentFav.children.append(currentItem!)
do {
let file = FileHelper.getDocumentsDirectory().appendingPathComponent(c.name)
VideoHelper.export(item: player.avPlayer!.currentItem!, clipStart: c.time!, clipDuration: c.length!, file: file) { url in
print(url)
}
} catch {
print(error)
}
// NetworkManager.sharedInstance.currentFav.children.append(currentItem!)
}
}
@ -214,6 +223,12 @@ print("play")
var def = [BMPlayerResourceDefinition]()
var index = 0;
var count = 0;
if allItems.isEmpty {
print("no items found")
return
}
for i in allItems {
let r = BMPlayerResourceDefinition(url: i.playerURL!, definition: i.name);
def.append(r)
@ -514,8 +529,6 @@ print("finish")
func bmPlayer(player: BMPlayer, playTimeDidChange currentTime: TimeInterval, totalTime: TimeInterval) {
if loopOption == 1 {
if currentTime > loopEnd {
print("loop")
player.seek(loopStart)
}
}

49
kplayer/master/MasterViewController.swift

@ -15,7 +15,7 @@ typealias Weiter = ([MediaItem]) -> Void
protocol MasterDelegate : DetailDelegate {
func loadFolder(selectedItem: MediaItem, completionHandler: @escaping (MediaItem) -> Void)
func loadItem(selectedItem: MediaItem, completionHandler: @escaping Weiter)
func loadItem(selectedItem: MediaItem, completionHandler: @escaping (MediaItem) -> Void)
}
class MasterViewController: UITableViewController, UISearchResultsUpdating {
@ -131,7 +131,7 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating {
delegate!.loadFolder(selectedItem: selectedItem) {
(neu) in
if neu.isDetails() {
if neu.isDetails() || neu.isVideo() {
self.gotoDetails(neu)
} else {
self.gotoNextFolder(neu)
@ -151,48 +151,13 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating {
}
fileprivate func gotoDetails(_ selectedItem: MediaItem) {
let weiter: NetworkManager.Weiter = {
(g) in
let weiter: (MediaItem) -> Void = {
(m) in
let model = ItemModel()
for f in g {
model.addItem(f)
}
selectedItem.children = model.items
selectedItem.loaded = false
if selectedItem.path.contains("*") {
selectedItem.loaded = true
} else
{
var all: [MediaItem]?
for f in selectedItem.children {
print(f.path)
if f.type == ItemType.FOLDER && f.path == "" {
all = f.children
break
}
}
if all != nil {
selectedItem.children = all!
selectedItem.loaded = false
for f in all! {
f.loaded = false
f.parent = selectedItem
}
}
}
self.performSegue(withIdentifier: "showDetail", sender: self)
return
}
delegate!.loadItem(selectedItem: selectedItem, completionHandler: weiter)
}
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
@ -215,12 +180,6 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating {
item.sort()
var j = 0
for i in item.children {
i.index = j
j += 1
}
NetworkManager.sharedInstance.loadItems(item)
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true

57
kplayer/master/NetworkDelegate.swift

@ -6,27 +6,53 @@
import Foundation
class NetworkDelegate: MasterDelegate, DetailDelegate {
func loadItem(selectedItem: MediaItem, completionHandler: @escaping Weiter) {
func loadItem(selectedItem: MediaItem, completionHandler: @escaping (MediaItem) -> Void) {
if selectedItem.loaded {
completionHandler(selectedItem)
return
}
let p = selectedItem.superRoot()
let dir = selectedItem.encodedDir!
let weiter:Weiter = {
(g) in
ItemModel().sortItems(selectedItem: selectedItem, children: g)
completionHandler(selectedItem)
}
if p.type == ItemType.FAVROOT {
NetworkManager.sharedInstance.loadFavDirs(dir, completionHandler: completionHandler)
NetworkManager.sharedInstance.loadFavDirs(dir, completionHandler: weiter)
}
else if p.type == ItemType.VIDEOROOT {
NetworkManager.sharedInstance.loadVideoDirs(dir, completionHandler: completionHandler)
NetworkManager.sharedInstance.loadVideoDirs(dir, completionHandler: weiter)
}
else if p.type == ItemType.WEBROOT {
completionHandler(p.children)
weiter(p.children)
}
else {
NetworkManager.sharedInstance.loadPicDirs(dir, completionHandler: completionHandler)
NetworkManager.sharedInstance.loadPicDirs(dir, completionHandler: weiter)
}
}
func loadFolder(selectedItem: MediaItem, completionHandler: @escaping (MediaItem) -> Void) -> Void {
let weiter:Weiter = {
(g) in
ItemModel().sortItems(selectedItem: selectedItem, children: g)
completionHandler(selectedItem)
}
if selectedItem.type == ItemType.FOLDER && selectedItem.loaded {
completionHandler(selectedItem)
return
}
if selectedItem.type == ItemType.FAVROOT {
NetworkManager.sharedInstance.loadFavDirs("dir", completionHandler: weiter)
return
}
NetworkManager.sharedInstance.listDirs(selectedItem.encodedDir!) {
NetworkManager.sharedInstance.listDirs(selectedItem.encodedDir!, completionHandler: {
(i, leaf) in
let details = MediaItem(name: selectedItem.name, path: selectedItem.path, root: selectedItem.root, type: ItemType.DETAILS)
@ -66,13 +92,24 @@ class NetworkDelegate: MasterDelegate, DetailDelegate {
let isVideo = selectedItem.parent != nil && selectedItem.parent!.type == ItemType.VIDEOROOT
if leaf || isVideo {
// if selectedItem.type == ItemType.VIDEOROOT {
// NetworkManager.sharedInstance.loadVideoDirs(selectedItem.encodedDir!, completionHandler: {
// (i) in
// selectedItem.children = i
// completionHandler(selectedItem)
// return
// })
// }
if selectedItem.type == ItemType.FOLDER {
selectedItem.type = ItemType.DETAILS
completionHandler(selectedItem)
}
else {
completionHandler(selectedItem)
} else {
completionHandler(neu)
}
}
})
}
func loadDetails(selectedItem: MediaItem, completionHandler: @escaping () -> ()) {
@ -94,7 +131,7 @@ class NetworkDelegate: MasterDelegate, DetailDelegate {
let p = c.snapshotDirPathForVideo + "\(ms).jpg"
let pt = c.snapshotDirPathForVideo + "\(ms)_thumb.jpg"
// NetworkManager.sharedInstance.deleteThumb(p)
NetworkManager.sharedInstance.deleteThumb(p)
NetworkManager.sharedInstance.deleteThumb(pt)
}
}

16
kplayer/photo/PhotoController.swift

@ -193,6 +193,22 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView
}
return
}
let controller = VideoController()
controller.edit = false
controller.allowEdit = false
controller.currentItem = currentItem
controller.setItems(items: [currentItem])
controller.navigationItem.leftItemsSupplementBackButton = true
navigationController!.navigationBar.barTintColor = UIColor.black
navigationController!.pushViewController(controller, animated: true)
controller.completionHandler = {
() in
// NetworkManager.sharedInstance.saveItem(self.currentItem!)
self.dismiss(animated: true, completion: nil);
}
}
override func loadView() {

2
kplayer/readme.md

@ -22,7 +22,7 @@ Ein Picture-Detail enthält Bilder.
Ein Web-Detail enthält Bookmarks.
Der MasterViewController enthält eine Liste von Roots.
Wird ein Root ausgewählt, werden die Children geladen.
Wird ein Root ausgewählt, werden die Folder geladen.
Gibt es Folder, wird die nächste Ebene eingeblendet.
Die Details-Liste wird im Details-Controller dargestellt.

27
kplayer/util/FileHelper.swift

@ -19,4 +19,31 @@ struct FileHelper {
print(url)
return try Data(contentsOf: url)
}
static func createDir(name: String) throws -> URL {
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent(name)
do {
try fileManager.createDirectory(at: documentsURL, withIntermediateDirectories: true)
} catch {
print(error)
}
print(documentsURL)
return documentsURL
}
static func listFiles(name: String)-> [URL] {
let fileManager = FileManager.default
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0] //.appendingPathComponent(name)
print (documentsURL)
do {
let fileURLs = try fileManager.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil)
// process files
return fileURLs
} catch {
print("Error while enumerating files \(documentsURL.path): \(error.localizedDescription)")
}
return []
}
}

4
kplayer/util/UploadOperation.swift

@ -31,7 +31,9 @@ class UploadOperation: Operation {
multipartFormData.append(self.path.data(using: String.Encoding.utf8)!, withName: "name")
}, with: URLRequest(url: URL(string: baseUrl)!, method: HTTPMethod.post))
.response(completionHandler: { data in
print(data.data!)
if let d = data.data {
print(String(decoding: d, as: UTF8.self))
}
})
} catch {
print("Upload Error")

64
kplayer/util/VideoHelper.swift

@ -0,0 +1,64 @@
//
// Created by Marco Schmickler on 30.04.21.
// Copyright (c) 2021 Marco Schmickler. All rights reserved.
//
import Foundation
import AVFoundation
class VideoHelper {
public static func export(item: AVPlayerItem, clipStart: Double, clipDuration: Double, file: URL, completion: @escaping (URL?) -> ()) {
guard item.asset.isExportable else {
completion(nil)
return
}
let composition = AVMutableComposition()
let compositionVideoTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))
let compositionAudioTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))
let sourceVideoTrack = item.asset.tracks(withMediaType: AVMediaType.video).first!
let sourceAudioTrack = item.asset.tracks(withMediaType: AVMediaType.audio).first!
let start = CMTime(seconds: clipStart, preferredTimescale: 1);
let dur = CMTime(seconds: clipDuration, preferredTimescale: 100);
do {
try compositionVideoTrack!.insertTimeRange(CMTimeRangeMake(start: start, duration: dur), of: sourceVideoTrack, at: start)
try compositionAudioTrack!.insertTimeRange(CMTimeRangeMake(start: start, duration: dur), of: sourceAudioTrack, at: start)
} catch(_) {
completion(nil)
return
}
let compatiblePresets = AVAssetExportSession.exportPresets(compatibleWith: composition)
var preset: String = AVAssetExportPresetPassthrough
// if compatiblePresets.contains(AVAssetExportPreset3840x2160) { preset = AVAssetExportPreset3840x2160 }
guard
let exportSession = AVAssetExportSession(asset: composition, presetName: preset),
exportSession.supportedFileTypes.contains(AVFileType.mp4) else {
completion(nil)
return
}
exportSession.outputURL = file
exportSession.outputFileType = AVFileType.mp4
let startTime = CMTime(seconds: 0.0, preferredTimescale: 100);
let timeRange = CMTimeRangeMake(start: start, duration: dur)
exportSession.timeRange = timeRange
print("Write file \(file)")
do {
try FileManager.default.removeItem(at: file)
} catch {
}
exportSession.exportAsynchronously {
print("ready \(exportSession.error)")
// let data = try? Data(contentsOf: tempFileUrl)
// _ = try? FileManager.default.removeItem(at: tempFileUrl)
let r = FileManager.default.fileExists(atPath: file.absoluteString)
print (r)
completion(file)
}
}
}

16
kplayer/util/stringutil.swift

@ -38,6 +38,22 @@ public extension String {
return substring(from: ix)
}
func substringAfter(_ str: String) -> String {
if let range = range(of: str) {
let substring = self[range.upperBound..<endIndex] // ab
return String(substring)
}
return self
}
func substringBefore(_ str: String) -> String {
if let range = range(of: str, options: .backwards) {
let substring = self[..<range.lowerBound] // ab
return String(substring)
}
return self
}
func length() -> Int {
return count
}

Loading…
Cancel
Save