diff --git a/Podfile b/Podfile index dba01d7..6ac0cd7 100644 --- a/Podfile +++ b/Podfile @@ -8,9 +8,7 @@ target 'kplayer' do pod 'HanekeSwift', :git => 'https://github.com/Haneke/HanekeSwift.git' pod 'Nimbus/Photos' pod 'Nimbus/PagingScrollView' - # pod 'BMPlayer' #, '0.8.6'# pod 'NVActivityIndicatorView' - pod 'SnapKit' pod 'WebBrowser' pod 'FileBrowser' pod 'ZIPFoundation' diff --git a/kplayer.xcodeproj/project.pbxproj b/kplayer.xcodeproj/project.pbxproj index df9bcf8..ad6048f 100644 --- a/kplayer.xcodeproj/project.pbxproj +++ b/kplayer.xcodeproj/project.pbxproj @@ -490,7 +490,6 @@ "${BUILT_PRODUCTS_DIR}/HanekeSwift/Haneke.framework", "${BUILT_PRODUCTS_DIR}/NVActivityIndicatorView/NVActivityIndicatorView.framework", "${BUILT_PRODUCTS_DIR}/Nimbus/Nimbus.framework", - "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework", "${BUILT_PRODUCTS_DIR}/WebBrowser/WebBrowser.framework", "${BUILT_PRODUCTS_DIR}/ZIPFoundation/ZIPFoundation.framework", ); @@ -501,7 +500,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Haneke.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NVActivityIndicatorView.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimbus.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WebBrowser.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZIPFoundation.framework", ); diff --git a/kplayer/core/DatabaseManager.swift b/kplayer/core/DatabaseManager.swift index c6e80aa..e5d3df4 100644 --- a/kplayer/core/DatabaseManager.swift +++ b/kplayer/core/DatabaseManager.swift @@ -37,6 +37,7 @@ class DatabaseManager { for c in item.children { if s.index == c.indexId { + c.objectID = s.objectID c.time = s.time c.length = s.length c.loop = s.loop @@ -60,6 +61,17 @@ class DatabaseManager { } func getKItem(_ item: MediaItem) -> KItem { + if let oid = item.objectID { + do { + let i = try managedObjectContext.existingObject(with: oid) + + if i != nil { + return i as! KItem + } + } catch { + } + } + let fetchRequest = KItem.fetchRequest() fetchRequest.predicate = NSPredicate(format: "name == %@ AND path == %@ AND root == %@", item.name, item.path, item.root) @@ -95,6 +107,22 @@ class DatabaseManager { } func saveItemMetaData(_ item: MediaItem) { + if (item.type == ItemType.SNAPSHOT) { + if let oid = item.objectID { + do { + let i = try managedObjectContext.existingObject(with: oid) + + if i != nil { + let snap = i as! KSnapshot + updateSnapshot(snap: snap, c: item) + print("DB -- Update snapshot at \(item.indexId)") + + } + } catch { + } + } + } + if (item.type == ItemType.VIDEO) { let k = getKItem(item) @@ -112,17 +140,8 @@ class DatabaseManager { for c in item.children { if !kstimes.contains(Int32(c.indexId)) { let snap = KSnapshot(context: managedObjectContext) - snap.time = c.time snap.index = Int32(c.indexId) - snap.length = c.length - snap.loop = c.loop - snap.offx = Int16(c.offset.x) - snap.offy = Int16(c.offset.y) - snap.sizex = Int16(c.size.width) - snap.sizey = Int16(c.size.height) - snap.scale = c.scale - snap.rating = Int16(c.rating) - snap.thumb = c.thumbUrl + updateSnapshot(snap: snap, c: c) k.addToSnapshots(snap) print("DB -- Insert snapshot at \(c.indexId)") @@ -130,42 +149,47 @@ class DatabaseManager { else { for snap in ksitems { if snap.index == c.indexId { - snap.time = c.time - snap.length = c.length - snap.loop = c.loop - snap.offx = Int16(c.offset.x) - snap.offy = Int16(c.offset.y) - snap.sizex = Int16(c.size.width) - snap.sizey = Int16(c.size.height) - snap.scale = c.scale - snap.rating = Int16(c.rating) - snap.thumb = c.thumbUrl - - var ct = [String](c.tags) - - for t in snap.tags as! Set { - if !c.tags.contains(t.name!) { - snap.removeFromTags(t) - print("remove \(t.name!)") - } - else { - ct.removeAll(where: { e in e == t.name!}) - } - } - - for a in ct { - addTag(a, snapshot: snap) - print("add \(a)") - } - + updateSnapshot(snap: snap, c: c) print("DB -- Update snapshot at \(c.indexId)") } } } } + } + + save() + } - save() + private func updateSnapshot(snap: KSnapshot, c: MediaItem) { + snap.time = c.time + snap.length = c.length + snap.loop = c.loop + snap.offx = Int16(c.offset.x) + snap.offy = Int16(c.offset.y) + snap.sizex = Int16(c.size.width) + snap.sizey = Int16(c.size.height) + snap.scale = c.scale + snap.rating = Int16(c.rating) + + snap.thumb = c.thumbUrl + + var ct = [String](c.tags) + + for t in snap.tags as! Set { + if !c.tags.contains(t.name!) { + snap.removeFromTags(t) + print("remove \(t.name!)") + } + else { + ct.removeAll(where: { e in e == t.name!}) + } } + + for a in ct { + addTag(a, snapshot: snap) + print("add \(a)") + } + } func createTag(_ answer: String) { @@ -263,6 +287,8 @@ class DatabaseManager { let i = s.item! let sitem = MediaItem(name: i.name!, path: i.path!, root: i.root!, type: ItemType.VIDEO) sitem.loaded = true + sitem.compilation = true + sitem.objectID = i.objectID let c = MediaItem(name: i.name!, path: i.path!, root: i.root!, type: ItemType.SNAPSHOT) c.time = s.time @@ -274,9 +300,18 @@ class DatabaseManager { c.offset.y = CGFloat(s.offy) c.scale = s.scale c.rating = Int(s.rating) - c.thumbUrl = s.thumb + + if s.thumb != nil { + c.thumbUrl = s.thumb + } + else { + c.thumbUrl = c.snapshotDirPathForVideo + "\(s.index)_thumb.jpg" + print("Thumb " + c.thumbUrl!) + } + c.indexId = Int(s.index) c.parent = sitem + c.objectID = s.objectID for t in s.tags as! Set { c.tags.append(t.name!) diff --git a/kplayer/core/MediaItem.swift b/kplayer/core/MediaItem.swift index 81f2c0e..911a66c 100644 --- a/kplayer/core/MediaItem.swift +++ b/kplayer/core/MediaItem.swift @@ -6,6 +6,7 @@ import Foundation import UIKit import Combine +import CoreData /** Repräsentiert ein Item eines der festgelegten Typen. @@ -77,6 +78,10 @@ class MediaItem: CustomDebugStringConvertible, ObservableObject, Identifiable { var favorite = false + var compilation = false + + var objectID : NSManagedObjectID? + @Published var scale = 0.0 @Published @@ -101,6 +106,7 @@ class MediaItem: CustomDebugStringConvertible, ObservableObject, Identifiable { self.loaded = true self.local = true self.indexId = model.indexId + self.tags = model.tags for m in model.children { let item = MediaItem(model: m) @@ -121,7 +127,6 @@ class MediaItem: CustomDebugStringConvertible, ObservableObject, Identifiable { } var model: MediaModel = MediaModel(name: name, path: path, root: root, children: c, type: type) - model.time = time model.loop = loop model.length = length @@ -132,6 +137,7 @@ class MediaItem: CustomDebugStringConvertible, ObservableObject, Identifiable { model.scale = scale model.favorite = favorite model.indexId = indexId + model.tags = tags return model } @@ -324,6 +330,7 @@ class MediaItem: CustomDebugStringConvertible, ObservableObject, Identifiable { func clone() -> MediaItem { let m = MediaItem(model: toMediaModel()) m.local = local + m.compilation = compilation for c in m.children { c.local = local diff --git a/kplayer/core/MediaModel.swift b/kplayer/core/MediaModel.swift index ab8f21c..b1433ef 100644 --- a/kplayer/core/MediaModel.swift +++ b/kplayer/core/MediaModel.swift @@ -25,4 +25,5 @@ public struct MediaModel : Codable { var children: [MediaModel] let type: ItemType + var tags = [String]() } diff --git a/kplayer/core/NetworkManager.swift b/kplayer/core/NetworkManager.swift index 781cd7c..f75941d 100644 --- a/kplayer/core/NetworkManager.swift +++ b/kplayer/core/NetworkManager.swift @@ -344,6 +344,7 @@ class NetworkManager { func saveItem(_ item: MediaItem) { var ch = item.children // print(ch) + DatabaseManager.sharedInstance.saveItemMetaData(item) if (item.local) { return @@ -353,9 +354,7 @@ class NetworkManager { return } - DatabaseManager.sharedInstance.saveItemMetaData(item) - - let url = baseurl + "/service/listfiles" + item.snapshotDirPathForVideo + let url = nodeurl + "listfiles" + item.snapshotDirPathForVideo print(url) @@ -401,7 +400,7 @@ class NetworkManager { func loadPicDetails(items: MediaItem, result: @escaping ([MediaItem]) -> () ) { let len = items.root.count - let url = NetworkManager.sharedInstance.baseurl + "/service/listfiles" + items.fullPath + let url = nodeurl + "listfiles" + items.fullPath print(items) print(url) diff --git a/kplayer/detail/DetailViewController+Show.swift b/kplayer/detail/DetailViewController+Show.swift index 367ebdb..65f8fb0 100644 --- a/kplayer/detail/DetailViewController+Show.swift +++ b/kplayer/detail/DetailViewController+Show.swift @@ -64,6 +64,15 @@ extension DetailViewController { baseItem = selectedItem.parent! } + if baseItem.compilation && mode { + baseItem.compilation = false + baseItem.children.removeAll() + baseItem.loaded = false + baseItem.parent = nil + NetworkManager.sharedInstance.loadItem(baseItem, index: 0) + return + } + children = baseItem.children clonedChildren = baseItem.clone().children @@ -116,6 +125,7 @@ extension DetailViewController { func showAllVideos(_ item: MediaItem) { let composition = MediaItem(name: item.name, path: item.path, root: item.root, type: ItemType.VIDEO) + composition.compilation = true for d in item.children { if d.children.isEmpty { diff --git a/kplayer/detail/DetailViewController.swift b/kplayer/detail/DetailViewController.swift index 7d48af9..c70ecfb 100644 --- a/kplayer/detail/DetailViewController.swift +++ b/kplayer/detail/DetailViewController.swift @@ -35,6 +35,9 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout var defaultItemSize = CGSize(width: (15 * 16) - 6, height: 15 * 9) + var modeButton: UIBarButtonItem? + var mode = false + var detailItem: MediaItem? { didSet { // print(detailItem!.children) @@ -88,11 +91,12 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout lpgr.delaysTouchesBegan = true self.collectionView.addGestureRecognizer(lpgr); + modeButton = UIBarButtonItem(barButtonSystemItem: .search , target: self, action: #selector(switchMode)); let settingsButton = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(settings)); let overviewButton = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(overview)); let favButton = UIBarButtonItem(barButtonSystemItem: .bookmarks, target: self, action: #selector(favorites)); let browserButton = UIBarButtonItem(barButtonSystemItem: .organize, target: self, action: #selector(fileBrowser)); - navigationItem.rightBarButtonItems = [settingsButton, favButton, overviewButton,browserButton] + navigationItem.rightBarButtonItems = [settingsButton, favButton, overviewButton,browserButton,modeButton!] if detailItem != nil { if detailItem!.children != nil { var d = detailItem!.children @@ -101,6 +105,13 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout } } + @objc func switchMode() { + mode = !mode + if let b = modeButton { + b.isSelected = mode + } + } + // https://github.com/marmelroy/FileBrowser @objc func fileBrowser() { let d = FileHelper.getDocumentsDirectory() diff --git a/kplayer/detail/ItemCell.swift b/kplayer/detail/ItemCell.swift index 49529b2..4d7c342 100644 --- a/kplayer/detail/ItemCell.swift +++ b/kplayer/detail/ItemCell.swift @@ -14,6 +14,7 @@ class ItemCell: UICollectionViewCell { var image: UIImageView! var fav: UIImageView! + var loop: UIImageView! var progress: UIProgressView! required init?(coder aDecoder: NSCoder) { @@ -34,6 +35,13 @@ class ItemCell: UICollectionViewCell { image.addSubview(fav) fav.isHidden = true + let ci = UIImage(systemName: "repeat.circle") + loop = UIImageView(image: ci) + // fav.contentMode = UIView.ContentMode.scaleAspectFill + + image.addSubview(loop) + loop.isHidden = true + progress = UIProgressView(progressViewStyle: .default) progress.progressTintColor = .red progress.trackTintColor = .lightGray @@ -61,6 +69,8 @@ class ItemCell: UICollectionViewCell { fav.isHidden = !f + loop.isHidden = item.length == 0.0 + if let _ = item.thumbUrl, let nsurl = URL(string: item.thumbUrlAbsolute) { image.hnk_setImageFromURL(nsurl, placeholder: defaultImage) } else { diff --git a/kplayer/master/NetworkDelegate.swift b/kplayer/master/NetworkDelegate.swift index 4bff6bb..101debb 100644 --- a/kplayer/master/NetworkDelegate.swift +++ b/kplayer/master/NetworkDelegate.swift @@ -122,6 +122,9 @@ class NetworkDelegate: MasterDelegate, DetailDelegate { if let name = item.externalURL { LocalManager.sharedInstance.saveFavDir(url: URL(string: name)!, item: item) } + else { + DatabaseManager.sharedInstance.saveItemMetaData(item) + } } else { NetworkManager.sharedInstance.saveItem(selectedItem) diff --git a/kplayer/photo/PhotoController.swift b/kplayer/photo/PhotoController.swift index 9be21c5..7154945 100644 --- a/kplayer/photo/PhotoController.swift +++ b/kplayer/photo/PhotoController.swift @@ -169,7 +169,7 @@ class MediaPhotoController: NIToolbarPhotoViewController, NIPhotoAlbumScrollView let items = currentItem let len = items.root.count - let url = NetworkManager.sharedInstance.baseurl + "/service/listfiles" + items.root + "/" + items.path + "/" + items.name + let url = NetworkManager.sharedInstance.nodeurl + "listfiles" + items.root + "/" + items.path + "/" + items.name print(items) print(url) diff --git a/kplayer/video/SVideoPlayer.swift b/kplayer/video/SVideoPlayer.swift index d1976a0..753b3ec 100644 --- a/kplayer/video/SVideoPlayer.swift +++ b/kplayer/video/SVideoPlayer.swift @@ -10,7 +10,6 @@ import AVKit struct SVideoPlayer: View, EditItemDelegate { // url: URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")! var player = AVQueuePlayer(items: [AVPlayerItem]()) - var secondPlayer = AVQueuePlayer(items: [AVPlayerItem]()) var playerLooper : AVPlayerLooper var completionHandler: ((Bool) -> Void)? @@ -135,12 +134,14 @@ struct SVideoPlayer: View, EditItemDelegate { Spacer() - Button(action: { model.edit = true }, label: { + Button(action: { model.edit.toggle() }, label: { Text("edit") }).buttonStyle(BorderlessButtonStyle()); - Button(action: doSnapshot, label: { - Text("snap") - }).buttonStyle(BorderlessButtonStyle()); + if !model.baseItem.compilation { + Button(action: doSnapshot, label: { + Text("snap") + }).buttonStyle(BorderlessButtonStyle()); + } }.frame(height: 50) GeometryReader { geometry in @@ -268,6 +269,22 @@ struct SVideoPlayer: View, EditItemDelegate { } private func move(_ dragged: CGSize, start: CGPoint) -> Bool { + if dragged.height > 100 { + if timeCounter == 0 { + if let i = model.allItems.index(where: { m in m === model.currentSnapshot }) { + if i + 1 < model.allItems.count { + gotoSnapshot(model.allItems[i+1]) + } + else { + gotoSnapshot(model.allItems[0]) + } + timeCounter = 15 + print("jump") + } + } + return false + } + if model.paused { if let time = getCurrentTime() { if smoothTime < 0 { @@ -317,17 +334,6 @@ struct SVideoPlayer: View, EditItemDelegate { // model.seeking = sk } - if dragged.height > 100 && timeCounter == 0 { - if let i = model.allItems.index(where: { m in m === model.currentSnapshot }) { - if i + 1 < model.allItems.count { - gotoSnapshot(model.allItems[i+1]) - } - else { - gotoSnapshot(model.allItems[0]) - } - timeCounter = 20 - } - } return false } @@ -338,6 +344,10 @@ struct SVideoPlayer: View, EditItemDelegate { func seekTime(_ time: Double) { print("Seek \(time)") + + if (time == 30.0) { + print("catch") + } self.model.seeking = true player.pause() // player.cancelPendingPrerolls()