diff --git a/kplayer.xcodeproj/project.pbxproj b/kplayer.xcodeproj/project.pbxproj index 9251153..f1d7467 100644 --- a/kplayer.xcodeproj/project.pbxproj +++ b/kplayer.xcodeproj/project.pbxproj @@ -7,7 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - 1C7361D2B6E0AE689FAAF4F4 /* AVPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C7FFBDAC665AE04CB65 /* AVPlayerController.swift */; }; + 1C7360C0F2A4F0214FE353BD /* FileHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7367ECBD369A2A0C94C499 /* FileHelper.swift */; }; + 1C7361D2B6E0AE689FAAF4F4 /* VideoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C7FFBDAC665AE04CB65 /* VideoController.swift */; }; 1C7362A6FA1C5DA0B0677F1E /* readme.md in Sources */ = {isa = PBXBuildFile; fileRef = 1C736871C9B012CB704AB803 /* readme.md */; }; 1C73631EACF56BABD3B2BCFB /* LayoutTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736BC4450890C45F8FBC63 /* LayoutTools.swift */; }; 1C73635138BBD2BB480A308F /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C736777456388CA571DA17B /* MediaPlayer.framework */; }; @@ -15,7 +16,8 @@ 1C73646F87B495A47D7943C7 /* NetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7369EC16B19B32B515169E /* NetData.swift */; }; 1C736503B656C999E5E12081 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */; }; 1C73654C9EA6D255CFC039C5 /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */; }; - 1C7365885FAF292F2221ED44 /* MediaPhotoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73673DC671535E3A049F54 /* MediaPhotoController.swift */; }; + 1C7365885FAF292F2221ED44 /* PhotoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73673DC671535E3A049F54 /* PhotoController.swift */; }; + 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 */; }; 1C73673F39A34C3275D0230A /* BMPlayerClearityChooseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DFBD072763248412F74 /* BMPlayerClearityChooseButton.swift */; }; @@ -29,6 +31,7 @@ 1C736953BDBBAFC40884132A /* BrowserController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73602350ACE2436736F981 /* BrowserController.swift */; }; 1C7369ABC44CFB530EA71FB6 /* HeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */; }; 1C736A5FA5BA53B2597F2ED7 /* Kirschkeks-256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = 1C736059262A57AADE6AB761 /* Kirschkeks-256x256.png */; }; + 1C736A7B6221A1D50FB3904C /* ItemType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73631C96E6C860833052CA /* ItemType.swift */; }; 1C736CB96577F6A9A7BA03E8 /* BMPlayerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7364F924BD979294C3EE4A /* BMPlayerItem.swift */; }; 1C736CD0E54786D3A2405E51 /* BMPlayerLayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7366D766CDE0C9872E86F5 /* BMPlayerLayerView.swift */; }; 1C736D16E81BA1FB325200E0 /* HanekeFetchOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360744ABACC3557D05760 /* HanekeFetchOperation.swift */; }; @@ -36,7 +39,9 @@ 1C736D24B49451141CD4B64D /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7369F53095B7A4D65679C2 /* DetailViewController.swift */; }; 1C736D895B75BDCDB35937C1 /* BMTimeSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360AE55EB115762C42EB9 /* BMTimeSlider.swift */; }; 1C736DB41BD06D359E6A0DEE /* BMSubtitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7366AAB82A46086690E164 /* BMSubtitles.swift */; }; + 1C736E21B246C0BE7E123FD3 /* MediaModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736B41C6AC33F3FA592C63 /* MediaModel.swift */; }; 1C736F278DDC77F40C8CB1D4 /* BMPlayerControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736E51F1A03E3A1200BDB6 /* BMPlayerControlView.swift */; }; + 1C736F307C53C7C07F302630 /* save.json in Resources */ = {isa = PBXBuildFile; fileRef = 1C736B57996546198F6C50CB /* save.json */; }; 1C736F3570EADA086682E6BC /* BMPlayerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360D6580FB5D09C2BBCCB /* BMPlayerManager.swift */; }; 1C736F6A223D4ADB2E1BA733 /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736069C214E9522BB1BD97 /* ItemCell.swift */; }; 1C736FB92B19FE17E4357C85 /* MediaItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C73688DAB88F9360FB62A49 /* MediaItem.swift */; }; @@ -71,22 +76,27 @@ 1C73620D01687FB4F1811C5C /* NetworkHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkHelper.swift; sourceTree = ""; }; 1C736253AB7A95EA41B605B7 /* ItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemModel.swift; sourceTree = ""; }; 1C736260E748CF136FF37EA7 /* UploadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadOperation.swift; sourceTree = ""; }; + 1C73631C96E6C860833052CA /* ItemType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemType.swift; sourceTree = ""; }; 1C73648CEC974A2500172064 /* ViewControllerExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewControllerExtensions.swift; sourceTree = ""; }; + 1C7364F10BED5DA0F1C0423C /* NetworkDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkDelegate.swift; sourceTree = ""; }; 1C7364F924BD979294C3EE4A /* BMPlayerItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerItem.swift; sourceTree = ""; }; 1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; 1C7365F45D765A218FFC100F /* BMPlayerProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerProtocols.swift; sourceTree = ""; }; 1C7366AAB82A46086690E164 /* BMSubtitles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMSubtitles.swift; sourceTree = ""; }; 1C7366D766CDE0C9872E86F5 /* BMPlayerLayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerLayerView.swift; sourceTree = ""; }; - 1C73673DC671535E3A049F54 /* MediaPhotoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaPhotoController.swift; sourceTree = ""; }; + 1C73673DC671535E3A049F54 /* PhotoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoController.swift; sourceTree = ""; }; 1C736777456388CA571DA17B /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; + 1C7367ECBD369A2A0C94C499 /* FileHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileHelper.swift; sourceTree = ""; }; 1C736871C9B012CB704AB803 /* readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = readme.md; sourceTree = ""; }; 1C73688DAB88F9360FB62A49 /* MediaItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaItem.swift; sourceTree = ""; }; 1C736927EA28AFBEB25D7487 /* BMPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayer.swift; sourceTree = ""; }; 1C7369EC16B19B32B515169E /* NetData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetData.swift; sourceTree = ""; }; 1C7369F53095B7A4D65679C2 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; + 1C736B41C6AC33F3FA592C63 /* MediaModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaModel.swift; sourceTree = ""; }; + 1C736B57996546198F6C50CB /* save.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = save.json; 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 = ""; }; - 1C736C7FFBDAC665AE04CB65 /* AVPlayerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AVPlayerController.swift; 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 = ""; }; 1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = ""; }; 1C736DFBD072763248412F74 /* BMPlayerClearityChooseButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerClearityChooseButton.swift; sourceTree = ""; }; @@ -134,7 +144,7 @@ 1C736069C214E9522BB1BD97 /* ItemCell.swift */, 1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */, 1C7369F53095B7A4D65679C2 /* DetailViewController.swift */, - 1C736C7FFBDAC665AE04CB65 /* AVPlayerController.swift */, + 1C736C7FFBDAC665AE04CB65 /* VideoController.swift */, 1C73602350ACE2436736F981 /* BrowserController.swift */, ); path = detail; @@ -143,7 +153,7 @@ 1C7363B608460DED4F522D1C /* photo */ = { isa = PBXGroup; children = ( - 1C73673DC671535E3A049F54 /* MediaPhotoController.swift */, + 1C73673DC671535E3A049F54 /* PhotoController.swift */, ); path = photo; sourceTree = ""; @@ -152,6 +162,7 @@ isa = PBXGroup; children = ( 1C73611D226B48C24DB37535 /* MasterViewController.swift */, + 1C7364F10BED5DA0F1C0423C /* NetworkDelegate.swift */, ); path = master; sourceTree = ""; @@ -169,6 +180,7 @@ 1C736F9338CE36708244D42A /* DataLoadOperation.swift */, 1C736B794396F2E50387B8F2 /* stringutil.swift */, 1C73648CEC974A2500172064 /* ViewControllerExtensions.swift */, + 1C7367ECBD369A2A0C94C499 /* FileHelper.swift */, ); path = util; sourceTree = ""; @@ -180,6 +192,8 @@ 1C73688DAB88F9360FB62A49 /* MediaItem.swift */, 1C736253AB7A95EA41B605B7 /* ItemModel.swift */, 1C736EA15A11AF7D57F85824 /* ThumbnailCache.swift */, + 1C736B41C6AC33F3FA592C63 /* MediaModel.swift */, + 1C73631C96E6C860833052CA /* ItemType.swift */, ); path = core; sourceTree = ""; @@ -227,6 +241,7 @@ 8CB608B13A2BDFA9D708982B /* Frameworks */, 1C736059262A57AADE6AB761 /* Kirschkeks-256x256.png */, 8052F5B3AAC2535E5C08A529 /* Pods */, + 1C736B57996546198F6C50CB /* save.json */, ); sourceTree = ""; }; @@ -343,7 +358,7 @@ }; C98AF5E81B124D6A00D196CC = { CreatedOnToolsVersion = 6.3.1; - LastSwiftMigration = 1000; + LastSwiftMigration = 1240; TestTargetID = C98AF5CE1B124D6A00D196CC; }; }; @@ -377,6 +392,7 @@ C98AF5E41B124D6A00D196CC /* LaunchScreen.xib in Resources */, C98AF5E11B124D6A00D196CC /* Images.xcassets in Resources */, 1C736A5FA5BA53B2597F2ED7 /* Kirschkeks-256x256.png in Resources */, + 1C736F307C53C7C07F302630 /* save.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -456,14 +472,14 @@ 1C73640D928DE56D35175D39 /* UploadOperation.swift in Sources */, 1C73646F87B495A47D7943C7 /* NetData.swift in Sources */, 1C73693A1334A7792856FC58 /* MasterViewController.swift in Sources */, - 1C7365885FAF292F2221ED44 /* MediaPhotoController.swift in Sources */, + 1C7365885FAF292F2221ED44 /* PhotoController.swift in Sources */, 1C736D16E81BA1FB325200E0 /* HanekeFetchOperation.swift in Sources */, 1C736D24891597F2728230EE /* ImageLoadOperation.swift in Sources */, 1C7367AF39961D2BA72480ED /* DataLoadOperation.swift in Sources */, 1C73675C34BE0990D44570BE /* ItemModel.swift in Sources */, 1C73691A9C7174E0C6B57267 /* stringutil.swift in Sources */, 1C736821D6DF2237A3EABCC1 /* ViewControllerExtensions.swift in Sources */, - 1C7361D2B6E0AE689FAAF4F4 /* AVPlayerController.swift in Sources */, + 1C7361D2B6E0AE689FAAF4F4 /* VideoController.swift in Sources */, 1C736953BDBBAFC40884132A /* BrowserController.swift in Sources */, 1C7362A6FA1C5DA0B0677F1E /* readme.md in Sources */, 1C73671FC2CCCACAA2FFC153 /* ThumbnailCache.swift in Sources */, @@ -476,6 +492,10 @@ 1C736DB41BD06D359E6A0DEE /* BMSubtitles.swift in Sources */, 1C736D895B75BDCDB35937C1 /* BMTimeSlider.swift in Sources */, 1C736F3570EADA086682E6BC /* BMPlayerManager.swift in Sources */, + 1C736E21B246C0BE7E123FD3 /* MediaModel.swift in Sources */, + 1C736A7B6221A1D50FB3904C /* ItemType.swift in Sources */, + 1C7360C0F2A4F0214FE353BD /* FileHelper.swift in Sources */, + 1C7366A0CFD2B55BF8C3BAF0 /* NetworkDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -564,7 +584,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -613,7 +633,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -679,7 +699,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "schmickler.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/kplayer.app/kplayer"; }; name = Debug; @@ -697,7 +717,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "schmickler.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/kplayer.app/kplayer"; }; name = Release; diff --git a/kplayer/AppDelegate.swift b/kplayer/AppDelegate.swift index a4c9c9e..1cf56a2 100644 --- a/kplayer/AppDelegate.swift +++ b/kplayer/AppDelegate.swift @@ -24,6 +24,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController let controller = masterNavigationController.topViewController as! MasterViewController + controller.delegate = NetworkDelegate() let web = MediaItem(name: "web", path:"", root: "/srv/samba/ren/web", type: ItemType.WEBROOT) let google = MediaItem(name: "google", path:"", root: "www.google.de", type: ItemType.FOLDER) diff --git a/kplayer/core/ItemType.swift b/kplayer/core/ItemType.swift new file mode 100644 index 0000000..b2fccbb --- /dev/null +++ b/kplayer/core/ItemType.swift @@ -0,0 +1,60 @@ +// +// Created by Marco Schmickler on 29.04.21. +// Copyright (c) 2021 Marco Schmickler. All rights reserved. +// + +import Foundation + +enum ItemType: String, Codable, CustomStringConvertible { + /** + Repräsentiert eine Wurzel, in der nur Bilder angezeigt werden. + */ + case PICROOT = "root" + + /** + Repräsentiert eine Wurzel, in der nur Videos angezeigt werden. + */ + case VIDEOROOT = "videoroot" + + case FAVROOT = "favroot" + + /** + Repräsentiert eine Wurzel, in der nur Webseiten angezeigt werden. + */ + case WEBROOT = "webroot" + + /** + Repräsentiert einen Ordner. Darin sind weitere Ordner enthalten. + */ + case FOLDER = "folder" + + /** + Repräsentiert ein Video. Hat keine Unterordner. Die Children sind Snapshots. + */ + case VIDEO = "video" + + /** + Web-Browser + */ + case WEB = "web" + + /** + Snapshots eines Videos. + */ + case SNAPSHOT = "snapshot" + + /** + Repräsentiert einen Bilder-Ordner. + */ + case PICS = "pics" + + /** + Repräsentiert einen Ordner, der Videos oder Bilder-Ordner enthält. Wird im DetailViewController angezeigt. + */ + case DETAILS = "details" + + var description: String { + return self.rawValue + } +} + diff --git a/kplayer/core/MediaItem.swift b/kplayer/core/MediaItem.swift index 56b67ed..5005adb 100644 --- a/kplayer/core/MediaItem.swift +++ b/kplayer/core/MediaItem.swift @@ -6,65 +6,11 @@ import Foundation import UIKit -enum ItemType: String, CustomStringConvertible { - /** - Repräsentiert eine Wurzel, in der nur Bilder angezeigt werden. - */ - case PICROOT = "root" - - /** - Repräsentiert eine Wurzel, in der nur Videos angezeigt werden. - */ - case VIDEOROOT = "videoroot" - - case FAVROOT = "favroot" - - /** - Repräsentiert eine Wurzel, in der nur Webseiten angezeigt werden. - */ - case WEBROOT = "webroot" - - /** - Repräsentiert einen Ordner. Darin sind weitere Ordner enthalten. - */ - case FOLDER = "folder" - - /** - Repräsentiert ein Video. Hat keine Unterordner. Die Children sind Snapshots. - */ - case VIDEO = "video" - - /** - Web-Browser - */ - case WEB = "web" - - /** - Snapshots eines Videos. - */ - case SNAPSHOT = "snapshot" - - /** - Repräsentiert einen Bilder-Ordner. - */ - case PICS = "pics" - - /** - Repräsentiert einen Ordner, der Videos oder Bilder-Ordner enthält. Wird im DetailViewController angezeigt. - */ - case DETAILS = "details" - - var description: String { - return self.rawValue - } -} - /** Repräsentiert ein Item eines der festgelegten Typen. */ class MediaItem: CustomDebugStringConvertible { - /** Wird durch name, path und root identifiziert. */ @@ -96,6 +42,44 @@ class MediaItem: CustomDebugStringConvertible { var loop = true var thumbUrl: String? + 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 + + for m in model.children { + let item = MediaItem(model: m) + item.index = children.count + item.parent = self + children.append(item) + } + } + + func toMediaModel() -> MediaModel { + var c = [MediaModel]() + + for m in children { + let mm = m.toMediaModel() + c.append(mm) + } + var model: MediaModel = MediaModel(name: name, path: path, root: root, children: c, type: type) + + + model.time = time ?? 0 + model.loop = loop + model.length = length ?? 0 + return model + } + + func toJSON() -> String { + let jsonEncoder = JSONEncoder() + let jsonData = try! jsonEncoder.encode(toMediaModel()) + let json = String(data: jsonData, encoding: String.Encoding.utf8) + return json! + } + init(name: String, path: String, root: String, type: ItemType) { self.name = name let trim = CharacterSet(charactersIn: "/ ") @@ -112,7 +96,7 @@ class MediaItem: CustomDebugStringConvertible { fileprivate func computeSortName(_ sname: String) -> String { var lsortName = sname.replacingOccurrences(of: "full", with: "") - var fullNameArr = lsortName.split { + let fullNameArr = lsortName.split { $0 == "_" }.map { String($0) @@ -220,8 +204,9 @@ class MediaItem: CustomDebugStringConvertible { } func isDetails() -> Bool { - return type == ItemType.FAVROOT || type == ItemType.DETAILS + return type == ItemType.DETAILS || type == ItemType.FAVROOT } + func isFolder() -> Bool { return type == ItemType.PICROOT || type == ItemType.VIDEOROOT || type == ItemType.FOLDER || type == ItemType.WEBROOT } diff --git a/kplayer/core/MediaModel.swift b/kplayer/core/MediaModel.swift new file mode 100644 index 0000000..5be2c21 --- /dev/null +++ b/kplayer/core/MediaModel.swift @@ -0,0 +1,19 @@ +// +// Created by Marco Schmickler on 29.04.21. +// Copyright (c) 2021 Marco Schmickler. All rights reserved. +// + +import Foundation + +public struct MediaModel : Codable { + let name: String + let path: String + let root: String + + var time = 0.0 + var length = 0.0 + var loop = false + + var children: [MediaModel] + let type: ItemType +} diff --git a/kplayer/core/NetworkManager.swift b/kplayer/core/NetworkManager.swift index f1b6d64..67f3440 100644 --- a/kplayer/core/NetworkManager.swift +++ b/kplayer/core/NetworkManager.swift @@ -16,7 +16,7 @@ class NetworkManager { var authenticated = false var favorites = MediaItem(name: "fav", path:"", root: "", type: ItemType.FAVROOT) - var currentFav = MediaItem(name: "current", path:"", root: "", type: ItemType.VIDEO) + var currentFav = MediaItem(name: "current", path:"", root: "", type: ItemType.FOLDER) lazy var operationQueue: OperationQueue = { var queue = OperationQueue() @@ -28,9 +28,34 @@ class NetworkManager { internal typealias Weiter = ([MediaItem]) -> Void + 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]() - res.append(currentFav) + + 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) + } + + // res.append(currentFav) completionHandler(res) } @@ -286,7 +311,9 @@ class NetworkManager { } func deleteThumb(_ path: String) { - AF.request(NetworkManager.sharedInstance.baseurl + "/service/deletethumb\(path)") + AF.request(NetworkManager.sharedInstance.baseurl + "/service/deletethumb\(path)").responseString { response in + print(response) + } } func favItem(_ item: MediaItem) { diff --git a/kplayer/detail/DetailViewController.swift b/kplayer/detail/DetailViewController.swift index 93825ba..a9b0e66 100644 --- a/kplayer/detail/DetailViewController.swift +++ b/kplayer/detail/DetailViewController.swift @@ -9,8 +9,15 @@ import UIKit import Alamofire +protocol DetailDelegate { + func loadDetails(selectedItem: MediaItem, completionHandler: @escaping () -> Void) + func deleteThumb(selectedItem: MediaItem) + func saveItem(selectedItem: MediaItem) +} + class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { + var delegate : DetailDelegate? @IBOutlet weak var detailDescriptionLabel: UILabel! var showFavoritesOnly = false @@ -186,14 +193,8 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout if indexPath!.item >= items.children.count { } else { let c = items.children.remove(at: indexPath!.item) - if let t = c.time { - let ms = Int(t * 1000) - let p = c.snapshotDirPathForVideo + "\(ms).jpg" - let pt = c.snapshotDirPathForVideo + "\(ms)_thumb.jpg" - - NetworkManager.sharedInstance.deleteThumb(p) - NetworkManager.sharedInstance.deleteThumb(pt) - } + + self.delegate!.deleteThumb(selectedItem: c) self.collectionView.reloadData() } } @@ -274,27 +275,35 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if let detail: MediaItem = self.detailItem { - var items = detail.children[indexPath.section] - if (items.type == ItemType.VIDEO || items.loaded) { - if indexPath.item >= items.children.count { - print(items.name) - } else { - items = items.children[indexPath.item] - print(items.name) + print(detail.toJSON()) + NetworkManager.sharedInstance.saveFavDir(name: "fav.json", item: detail) + + var sectionItem = detail.children[indexPath.section] + currentItem = sectionItem + var selectedItem = currentItem! + + let weiter: () -> Void = { + + if (sectionItem.type == ItemType.VIDEO || sectionItem.loaded) { + if indexPath.item >= sectionItem.children.count { + print(sectionItem.name) + } else { + selectedItem = sectionItem.children[indexPath.item] + print(selectedItem.name) + } } - self.currentItem = items + if sectionItem.isVideo() { + self.showVideo(selectedItem: selectedItem) + } else if sectionItem.isPic() { + self.showPhotos(sectionItem.children) + } else { + self.showWeb(sectionItem.children) + } } - if items.isVideo() { - showVideo() - } else if items.isPic() { - NetworkManager.sharedInstance.loadPicDetails(items: items, result: { (im: [MediaItem]) in - self.showPhotos(im) - }) - } else { - showWeb(items.children) - } + delegate!.loadDetails(selectedItem: currentItem!, completionHandler: weiter) + } } @@ -323,31 +332,18 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout self.present(navController, animated: false, completion: nil) } - func showVideo() { + func showVideo(selectedItem: MediaItem) { var pc: ItemController? - // if videoplayer { - pc = AVPlayerController() -// } -// else { - // pc = BrowserController() -// pc = VideoPlayerController() -// } + pc = AVPlayerController() - pc!.setCurrentItem(item: self.currentItem!) + pc!.setCurrentItem(item: selectedItem) pc!.setItems(items: detailItem!.children) pc!.setCompletionHandler(handler: { self.collectionView.reloadData() self.collectionView.collectionViewLayout.invalidateLayout() - if let ci = self.currentItem { - if ci.type == ItemType.SNAPSHOT { - self.currentItem = ci.parent - } - } - if let ci = self.currentItem { - NetworkManager.sharedInstance.saveItem(ci) - } + self.delegate!.saveItem(selectedItem: self.currentItem!) self.dismiss(animated: true, completion: nil); }) let navController = UINavigationController(rootViewController: (pc! as! UIViewController)) diff --git a/kplayer/detail/AVPlayerController.swift b/kplayer/detail/VideoController.swift similarity index 99% rename from kplayer/detail/AVPlayerController.swift rename to kplayer/detail/VideoController.swift index 87622cc..ff338fe 100644 --- a/kplayer/detail/AVPlayerController.swift +++ b/kplayer/detail/VideoController.swift @@ -508,7 +508,7 @@ print("finish") } func bmPlayer(player: BMPlayer, loadedTimeDidChange loadedDuration: TimeInterval, totalDuration: TimeInterval) { - print("load") + // print("load") } func bmPlayer(player: BMPlayer, playTimeDidChange currentTime: TimeInterval, totalTime: TimeInterval) { @@ -519,7 +519,7 @@ print("finish") player.seek(loopStart) } } - print("Time") + // print("Time") } func bmPlayer(player: BMPlayer, playerIsPlaying playing: Bool) { diff --git a/kplayer/master/MasterViewController.swift b/kplayer/master/MasterViewController.swift index dfc4275..519aa9b 100644 --- a/kplayer/master/MasterViewController.swift +++ b/kplayer/master/MasterViewController.swift @@ -10,9 +10,19 @@ import UIKit import CoreData import LocalAuthentication +typealias Weiter = ([MediaItem]) -> Void + +protocol MasterDelegate : DetailDelegate { + func loadFolder(selectedItem: MediaItem, completionHandler: @escaping (MediaItem) -> Void) + + func loadItem(selectedItem: MediaItem, completionHandler: @escaping Weiter) +} + class MasterViewController: UITableViewController, UISearchResultsUpdating { let searchController = UISearchController(searchResultsController: nil) let model = ItemModel() + var delegate : MasterDelegate? + var detailDelegate : DetailDelegate? var authenticated = false @@ -119,51 +129,15 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating { if (selectedItem.isFolder()) { print(selectedItem.path) - NetworkManager.sharedInstance.listDirs(selectedItem.encodedDir!) { - (i, leaf) in - - let details = MediaItem(name: selectedItem.name, path: selectedItem.path, root: selectedItem.root, type: ItemType.DETAILS) - let neu = MediaItem(name: selectedItem.name, path: "", root: "", type: ItemType.FOLDER) - let newFolder = MediaItem(name: ".", path: "", root: selectedItem.root, type: ItemType.DETAILS) - newFolder.loaded = true - - var hasDetails = false - - for item in i { - if item.type != ItemType.FOLDER && item.isVideo() { - item.parent = newFolder - newFolder.children.append(item) - } else { - if item.path == "" { - item.path = item.name - item.name = "" - } - - if item.type == ItemType.PICS { - if !hasDetails { - neu.children.append(details) - hasDetails = true - } - } else { -// item.type = ItemType.FOLDER - item.parent = selectedItem - neu.children.append(item) - } - } - } - - if newFolder.children.count > 0 { - newFolder.parent = selectedItem - neu.children.append(newFolder) - } - - let isVideo = selectedItem.parent != nil && selectedItem.parent!.type == ItemType.VIDEOROOT - if leaf || isVideo { - self.gotoDetails(selectedItem) + delegate!.loadFolder(selectedItem: selectedItem) { + (neu) in + if neu.isDetails() { + self.gotoDetails(neu) } else { self.gotoNextFolder(neu) } } + } } @@ -172,6 +146,7 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating { let vc = mainStoryboard.instantiateViewController(withIdentifier: "mastertable") as! MasterViewController vc.navigationItem.title = selectedItem.name; vc.model.items = selectedItem.children + vc.delegate = delegate navigationController!.pushViewController(vc, animated: true) } @@ -216,25 +191,8 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating { return } - if selectedItem.type != ItemType.FAVROOT { - selectedItem.type = ItemType.DETAILS - } - - let p = selectedItem.superRoot() - let dir = selectedItem.encodedDir! + delegate!.loadItem(selectedItem: selectedItem, completionHandler: weiter) - if p.type == ItemType.FAVROOT { - NetworkManager.sharedInstance.loadFavDirs(dir, completionHandler: weiter) - } - else if p.type == ItemType.VIDEOROOT { - NetworkManager.sharedInstance.loadVideoDirs(dir, completionHandler: weiter) - } - else if p.type == ItemType.WEBROOT { - weiter(p.children) - } - else { - NetworkManager.sharedInstance.loadPicDirs(dir, completionHandler: weiter) - } } override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { @@ -248,6 +206,7 @@ class MasterViewController: UITableViewController, UISearchResultsUpdating { let item = model.items[indexPath.row] let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController controller.detailItem = item + controller.delegate = delegate if item.isPic() { // größere Vorschau für Fotos diff --git a/kplayer/master/NetworkDelegate.swift b/kplayer/master/NetworkDelegate.swift new file mode 100644 index 0000000..5f0e42d --- /dev/null +++ b/kplayer/master/NetworkDelegate.swift @@ -0,0 +1,105 @@ +// +// Created by Marco Schmickler on 29.04.21. +// Copyright (c) 2021 Marco Schmickler. All rights reserved. +// + +import Foundation + +class NetworkDelegate: MasterDelegate, DetailDelegate { + func loadItem(selectedItem: MediaItem, completionHandler: @escaping Weiter) { + let p = selectedItem.superRoot() + let dir = selectedItem.encodedDir! + + if p.type == ItemType.FAVROOT { + NetworkManager.sharedInstance.loadFavDirs(dir, completionHandler: completionHandler) + } + else if p.type == ItemType.VIDEOROOT { + NetworkManager.sharedInstance.loadVideoDirs(dir, completionHandler: completionHandler) + } + else if p.type == ItemType.WEBROOT { + completionHandler(p.children) + } + else { + NetworkManager.sharedInstance.loadPicDirs(dir, completionHandler: completionHandler) + } + } + + func loadFolder(selectedItem: MediaItem, completionHandler: @escaping (MediaItem) -> Void) -> Void { + + NetworkManager.sharedInstance.listDirs(selectedItem.encodedDir!) { + (i, leaf) in + + let details = MediaItem(name: selectedItem.name, path: selectedItem.path, root: selectedItem.root, type: ItemType.DETAILS) + let neu = MediaItem(name: selectedItem.name, path: "", root: "", type: ItemType.FOLDER) + let newFolder = MediaItem(name: ".", path: "", root: selectedItem.root, type: ItemType.DETAILS) + newFolder.loaded = true + + var hasDetails = false + + for item in i { + if item.type != ItemType.FOLDER && item.isVideo() { + item.parent = newFolder + newFolder.children.append(item) + } else { + if item.path == "" { + item.path = item.name + item.name = "" + } + + if item.type == ItemType.PICS { + if !hasDetails { + neu.children.append(details) + hasDetails = true + } + } else { +// item.type = ItemType.FOLDER + item.parent = selectedItem + neu.children.append(item) + } + } + } + + if newFolder.children.count > 0 { + newFolder.parent = selectedItem + neu.children.append(newFolder) + } + + let isVideo = selectedItem.parent != nil && selectedItem.parent!.type == ItemType.VIDEOROOT + if leaf || isVideo { + selectedItem.type = ItemType.DETAILS + completionHandler(selectedItem) + } + else { + completionHandler(neu) + } + } + } + + func loadDetails(selectedItem: MediaItem, completionHandler: @escaping () -> ()) { + + if selectedItem.isPic() { + NetworkManager.sharedInstance.loadPicDetails(items: selectedItem, result: { (im: [MediaItem]) in + selectedItem.children = im + completionHandler() + }) + } + else { + completionHandler() + } + } + + func deleteThumb(selectedItem c: MediaItem) { + if let t = c.time { + let ms = Int(t * 1000) + let p = c.snapshotDirPathForVideo + "\(ms).jpg" + let pt = c.snapshotDirPathForVideo + "\(ms)_thumb.jpg" + + // NetworkManager.sharedInstance.deleteThumb(p) + NetworkManager.sharedInstance.deleteThumb(pt) + } + } + + func saveItem(selectedItem: MediaItem) { + NetworkManager.sharedInstance.saveItem(selectedItem) + } +} diff --git a/kplayer/photo/MediaPhotoController.swift b/kplayer/photo/PhotoController.swift similarity index 95% rename from kplayer/photo/MediaPhotoController.swift rename to kplayer/photo/PhotoController.swift index b26a912..e47dc71 100644 --- a/kplayer/photo/MediaPhotoController.swift +++ b/kplayer/photo/PhotoController.swift @@ -193,21 +193,6 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView } return } - -// let controller = VideoPlayerController() -// controller.edit = false -// controller.allowEdit = false -// -// controller.currentItem = 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() { diff --git a/kplayer/readme.md b/kplayer/readme.md index e69de29..9a5a0d6 100644 --- a/kplayer/readme.md +++ b/kplayer/readme.md @@ -0,0 +1,34 @@ +KPlayer verwaltet MediaItems + +Ein MediaItem ist + +ein Root +ein Folder +ein Detail + +Ein Root kann Children vom Server oder lokal laden. + +Ein Folder ist eine Zwischenebene unter Root (optional) + +Ein Detail ist +- ein Video +- eine Bilderserie +- eine Webseitensammlung + + +Ein Detail hat Children, davon ein ausgewähltes. +Ein Video-Detail enthält Snapshots. +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. +Gibt es Folder, wird die nächste Ebene eingeblendet. +Die Details-Liste wird im Details-Controller dargestellt. + +Der DetailsViewController zeigt die selektierte Details-Liste. +Jede Section zeigt ein Detail, die einzelnen Children werden mit Bild dargestellt. +Beim Klick auf das Bild wird ein Controller angezeigt für die verschiedenen Typen. + + + diff --git a/kplayer/util/FileHelper.swift b/kplayer/util/FileHelper.swift new file mode 100644 index 0000000..895ff2d --- /dev/null +++ b/kplayer/util/FileHelper.swift @@ -0,0 +1,22 @@ +// +// Created by Marco Schmickler on 29.04.21. +// Copyright (c) 2021 Marco Schmickler. All rights reserved. +// + +import Foundation + +struct FileHelper { + static func getDocumentsDirectory() -> URL { + // find all possible documents directories for this user + let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) + + // just send back the first one, which ought to be the only one + return paths[0] + } + + static func getData(name: String) throws -> Data { + let url = getDocumentsDirectory().appendingPathComponent(name) +print(url) + return try Data(contentsOf: url) + } +} diff --git a/kplayer/video/BMPlayer.swift b/kplayer/video/BMPlayer.swift index e6ac9c6..01e698c 100644 --- a/kplayer/video/BMPlayer.swift +++ b/kplayer/video/BMPlayer.swift @@ -444,12 +444,12 @@ print(value) initGesture() } - @available(*, deprecated:3.0, message:"Use newer init(customControlView:_)") - public convenience init(customControllView: BMPlayerControlView?) { - self.init(customControlView: customControllView) - } - - public init(customControlView: BMPlayerControlView?) { +// @available(*, deprecated:3.0, message:"Use newer init(customControlView:_)") +// public convenience init(customControllView: BMPlayerControlView?) { +// self.init(customControlView: customControllView) +// } + + @objc public init(customControlView: BMPlayerControlView?) { super.init(frame:CGRect.zero) self.customControlView = customControlView initUI() diff --git a/kplayerTests/kplayerTests.swift b/kplayerTests/kplayerTests.swift index 7ca6283..71f0779 100644 --- a/kplayerTests/kplayerTests.swift +++ b/kplayerTests/kplayerTests.swift @@ -44,6 +44,20 @@ class kplayerTests: XCTestCase { XCTAssert(i == 1, "Pass") } + func testJson() { + do { + if let bundlePath = Bundle.main.path(forResource: "save", + ofType: "json"), + let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) { + let decodedData = try JSONDecoder().decode(MediaModel.self, + from: jsonData) + print(jsonData) + } + } catch { + print(error) + } + } + func testPerformanceExample() { // This is an example of a performance test case. self.measure() {