Browse Source

Delegates

master
marcoschmickler 5 years ago
parent
commit
641ceca15f
  1. 46
      kplayer.xcodeproj/project.pbxproj
  2. 1
      kplayer/AppDelegate.swift
  3. 60
      kplayer/core/ItemType.swift
  4. 97
      kplayer/core/MediaItem.swift
  5. 19
      kplayer/core/MediaModel.swift
  6. 33
      kplayer/core/NetworkManager.swift
  7. 80
      kplayer/detail/DetailViewController.swift
  8. 4
      kplayer/detail/VideoController.swift
  9. 77
      kplayer/master/MasterViewController.swift
  10. 105
      kplayer/master/NetworkDelegate.swift
  11. 15
      kplayer/photo/PhotoController.swift
  12. 34
      kplayer/readme.md
  13. 22
      kplayer/util/FileHelper.swift
  14. 12
      kplayer/video/BMPlayer.swift
  15. 14
      kplayerTests/kplayerTests.swift

46
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 = "<group>"; };
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>"; };
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>"; };
1C7365B06FA66294E99AC2D3 /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = "<group>"; };
1C7365F45D765A218FFC100F /* BMPlayerProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerProtocols.swift; sourceTree = "<group>"; };
1C7366AAB82A46086690E164 /* BMSubtitles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMSubtitles.swift; sourceTree = "<group>"; };
1C7366D766CDE0C9872E86F5 /* BMPlayerLayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerLayerView.swift; sourceTree = "<group>"; };
1C73673DC671535E3A049F54 /* MediaPhotoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaPhotoController.swift; sourceTree = "<group>"; };
1C73673DC671535E3A049F54 /* PhotoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoController.swift; sourceTree = "<group>"; };
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 = "<group>"; };
1C736871C9B012CB704AB803 /* readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = readme.md; sourceTree = "<group>"; };
1C73688DAB88F9360FB62A49 /* MediaItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaItem.swift; sourceTree = "<group>"; };
1C736927EA28AFBEB25D7487 /* BMPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayer.swift; sourceTree = "<group>"; };
1C7369EC16B19B32B515169E /* NetData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetData.swift; sourceTree = "<group>"; };
1C7369F53095B7A4D65679C2 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = "<group>"; };
1C736B41C6AC33F3FA592C63 /* MediaModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaModel.swift; sourceTree = "<group>"; };
1C736B57996546198F6C50CB /* save.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = save.json; sourceTree = "<group>"; };
1C736B794396F2E50387B8F2 /* stringutil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = stringutil.swift; sourceTree = "<group>"; };
1C736BC4450890C45F8FBC63 /* LayoutTools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutTools.swift; sourceTree = "<group>"; };
1C736C7FFBDAC665AE04CB65 /* AVPlayerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AVPlayerController.swift; sourceTree = "<group>"; };
1C736C7FFBDAC665AE04CB65 /* VideoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoController.swift; sourceTree = "<group>"; };
1C736D9BB5498E7E8F11C754 /* HeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderCell.swift; sourceTree = "<group>"; };
1C736DCCE3AA9993E15F7652 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = "<group>"; };
1C736DFBD072763248412F74 /* BMPlayerClearityChooseButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerClearityChooseButton.swift; sourceTree = "<group>"; };
@ -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 = "<group>";
@ -152,6 +162,7 @@
isa = PBXGroup;
children = (
1C73611D226B48C24DB37535 /* MasterViewController.swift */,
1C7364F10BED5DA0F1C0423C /* NetworkDelegate.swift */,
);
path = master;
sourceTree = "<group>";
@ -169,6 +180,7 @@
1C736F9338CE36708244D42A /* DataLoadOperation.swift */,
1C736B794396F2E50387B8F2 /* stringutil.swift */,
1C73648CEC974A2500172064 /* ViewControllerExtensions.swift */,
1C7367ECBD369A2A0C94C499 /* FileHelper.swift */,
);
path = util;
sourceTree = "<group>";
@ -180,6 +192,8 @@
1C73688DAB88F9360FB62A49 /* MediaItem.swift */,
1C736253AB7A95EA41B605B7 /* ItemModel.swift */,
1C736EA15A11AF7D57F85824 /* ThumbnailCache.swift */,
1C736B41C6AC33F3FA592C63 /* MediaModel.swift */,
1C73631C96E6C860833052CA /* ItemType.swift */,
);
path = core;
sourceTree = "<group>";
@ -227,6 +241,7 @@
8CB608B13A2BDFA9D708982B /* Frameworks */,
1C736059262A57AADE6AB761 /* Kirschkeks-256x256.png */,
8052F5B3AAC2535E5C08A529 /* Pods */,
1C736B57996546198F6C50CB /* save.json */,
);
sourceTree = "<group>";
};
@ -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;

1
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)

60
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
}
}

97
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
}

19
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
}

33
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) {

80
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))

4
kplayer/detail/AVPlayerController.swift → 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) {

77
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

105
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)
}
}

15
kplayer/photo/MediaPhotoController.swift → 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() {

34
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.

22
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)
}
}

12
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()

14
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() {

Loading…
Cancel
Save