diff --git a/kplayer.xcodeproj/project.pbxproj b/kplayer.xcodeproj/project.pbxproj index 8547cc4..1581f6e 100644 --- a/kplayer.xcodeproj/project.pbxproj +++ b/kplayer.xcodeproj/project.pbxproj @@ -46,6 +46,7 @@ 1C736A06A2AD75B8C14EEBBE /* HtmlParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736DBB6986A8B62963FBB3 /* HtmlParser.swift */; }; 1C736A5FA5BA53B2597F2ED7 /* Kirschkeks-256x256.png in Resources */ = {isa = PBXBuildFile; fileRef = 1C736059262A57AADE6AB761 /* Kirschkeks-256x256.png */; }; 1C736A622876405F3EE2D043 /* EditItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7366C09381DC0052B52B69 /* EditItemView.swift */; }; + 1C736A78C1F8F41E2AEEF278 /* KVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736E2CD0C1780F4F5AE0C4 /* KVideoPlayer.swift */; }; 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 */; }; @@ -137,6 +138,7 @@ 1C736DBB6986A8B62963FBB3 /* HtmlParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HtmlParser.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 = ""; }; + 1C736E2CD0C1780F4F5AE0C4 /* KVideoPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVideoPlayer.swift; sourceTree = ""; }; 1C736E51F1A03E3A1200BDB6 /* BMPlayerControlView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BMPlayerControlView.swift; sourceTree = ""; }; 1C736EA15A11AF7D57F85824 /* ThumbnailCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailCache.swift; sourceTree = ""; }; 1C736F9338CE36708244D42A /* DataLoadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataLoadOperation.swift; sourceTree = ""; }; @@ -267,6 +269,7 @@ 1C7360AE55EB115762C42EB9 /* BMTimeSlider.swift */, 1C7360D6580FB5D09C2BBCCB /* BMPlayerManager.swift */, 1C73610B997EBA367C806C1B /* BMPlayerCompositionResourceDefinition.swift */, + 1C736E2CD0C1780F4F5AE0C4 /* KVideoPlayer.swift */, ); path = video; sourceTree = ""; @@ -584,6 +587,7 @@ 1C736A622876405F3EE2D043 /* EditItemView.swift in Sources */, 1C73613562EB375F53A0BD03 /* ServerDownloadDelegate.swift in Sources */, 1C736EC45EE7DA5F7FCE63DA /* LocalManager.swift in Sources */, + 1C736A78C1F8F41E2AEEF278 /* KVideoPlayer.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/kplayer/core/LocalManager.swift b/kplayer/core/LocalManager.swift index 328ce04..37ccf46 100644 --- a/kplayer/core/LocalManager.swift +++ b/kplayer/core/LocalManager.swift @@ -86,9 +86,12 @@ class LocalManager { let json = item.toJSON() do { - print(url) - try json.write(to: url.appendingPathExtension("json"), atomically: true, encoding: .utf8) - let input = try String(contentsOf: url) + var jsonurl = url + if url.pathExtension != "json" { + jsonurl = url.appendingPathExtension("json") + } + try json.write(to: jsonurl, atomically: true, encoding: .utf8) + let input = try String(contentsOf: jsonurl) print(input) } catch { print(json) @@ -181,6 +184,7 @@ class LocalManager { let item = try JSONDecoder().decode(MediaModel.self, from: jsonData) let mediaItem = MediaItem(model: item) mediaItem.externalURL = fileURL.absoluteString + mediaItem.localURL = jsonURL mediaItem.local = true for i in mediaItem.children { i.externalURL = fileURL.absoluteString @@ -253,9 +257,15 @@ class LocalManager { } if path!.contains("file://") { - let p = path!.substringAfter("/Documents/") - let fixed = FileHelper.getDocumentsDirectory().appendingPathComponent(p) - return fixed.absoluteString + if path!.contains("/Application") { + let p = path!.substringAfter("/Documents/") + let fixed = FileHelper.getDocumentsDirectory().appendingPathComponent(p) + return fixed.absoluteString + } + else { + let p = path!.substringAfter("/Documents") + return externalURL + p + } } return path } diff --git a/kplayer/core/MediaItem.swift b/kplayer/core/MediaItem.swift index 34e4ff7..98edee4 100644 --- a/kplayer/core/MediaItem.swift +++ b/kplayer/core/MediaItem.swift @@ -5,6 +5,7 @@ import Foundation import UIKit +import Combine /** Repräsentiert ein Item eines der festgelegten Typen. @@ -38,8 +39,18 @@ class MediaItem: CustomDebugStringConvertible, ObservableObject { // Nutzinhalt var image: UIImage? + // let didChange = PassthroughSubject() + @Published var time: TimeInterval = 0.0 +// +// { +// willSet { +// // print(newValue) +// // didChange.send(self) +// self.objectWillChange.send() +// } +// } @Published var length: TimeInterval = 0.0 @@ -49,13 +60,14 @@ class MediaItem: CustomDebugStringConvertible, ObservableObject { var thumbUrl: String? var externalURL: String? + var localURL: URL? var local = false var external = false var leaf = false var cancelled = false - var scale = 0.0 + var scale = 1.0 var offset = CGPoint() var size = CGSize() diff --git a/kplayer/detail/DetailViewController.swift b/kplayer/detail/DetailViewController.swift index 4cffc28..625fad4 100644 --- a/kplayer/detail/DetailViewController.swift +++ b/kplayer/detail/DetailViewController.swift @@ -307,7 +307,7 @@ class DetailViewController: UIViewController, UICollectionViewDelegateFlowLayout } } else if items.local { - self.delegate!.deleteLocal(selectedItem: items) + // self.delegate!.deleteLocal(selectedItem: items) } })) diff --git a/kplayer/detail/EditItemView.swift b/kplayer/detail/EditItemView.swift index a96b347..fa65936 100644 --- a/kplayer/detail/EditItemView.swift +++ b/kplayer/detail/EditItemView.swift @@ -6,41 +6,70 @@ import Foundation import SwiftUI -struct EditItemView : View { +struct EditItemView: View { @ObservedObject - var item : MediaItem + var item: MediaItem + + var len: Double + + var seek: (Double) -> Void + var capture: (MediaItem) -> Void var body: some View { Form { Section(header: Text("K Settings")) { VStack { - Text("Size") - Slider(value: $item.time, in: 0...1000) - Slider(value: $item.length, in: 0...1000) + Slider(value: Binding( + get: { item.time }, + set: { + item.time = $0 + seek(item.time) + } + ), in: 0...len) + Text("Start \(item.time, specifier: "%.1f") Length \(item.length, specifier: "%.1f")") + Slider(value: Binding( + get: { item.length }, + set: { + item.length = $0 + seek(item.time + item.length) + } + ), in: 1...500) Toggle(isOn: $item.loop, label: { Text("Loop") }) - } - } - Button(action: { - - }, label: { - Text("ok") - }); - Button(action: { - - }, label: { - Text("cancel") - }) + Text("Zoom \(item.scale, specifier: "%.1f") X \(item.offset.x, specifier: "%.1f") Y \(item.offset.y, specifier: "%.1f") ") + HStack { + Button(action: { + capture(item) + item.objectWillChange.send() + }, label: { + Text("Zoom") + }); +// Button(action: { +// item.scale = 1.0 +// item.offset = CGPoint(x: 0,y: 0) +// item.objectWillChange.send() +// }, label: { +// Text("Reset") +// }); + } + }.background(Color.clear) + }.background(Color.clear) } .onAppear { + UITableView.appearance().backgroundColor = .clear + } + .onDisappear { + UITableView.appearance().backgroundColor = .systemBackground } + .frame(height: 350, alignment: .top) + //Spacer() } } struct EditItemView_Previews: PreviewProvider { static var previews: some View { - EditItemView(item: MediaItem(name: "extern", path:"", root: "", type: ItemType.FAVROOT)) + EditItemView(item: MediaItem(name: "extern", path: "", root: "", type: ItemType.FAVROOT), len: 1000, seek: { v in }, capture: { v in }) } } diff --git a/kplayer/detail/VideoController.swift b/kplayer/detail/VideoController.swift index 9202dfa..eb0f740 100644 --- a/kplayer/detail/VideoController.swift +++ b/kplayer/detail/VideoController.swift @@ -36,7 +36,6 @@ class VideoController: UIViewController, ItemController, BMPlayerDelegate { var downloadDelegate: DownloadDelegate? var loopStart = 0.0 - var loopEnd = 0.0 var completionHandler: (() -> Void)? @@ -56,11 +55,11 @@ class VideoController: UIViewController, ItemController, BMPlayerDelegate { var aspect = 1 - var loopOption = 0 + var loopMode = false var thumbnailTime: TimeInterval = 0.0 - var edit = true + var edit = false var allowEdit = true var index = 0 @@ -74,7 +73,7 @@ class VideoController: UIViewController, ItemController, BMPlayerDelegate { barbutton = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(VideoController.captureThumbnail)); navigationItem.rightBarButtonItems = [barbutton!] - backButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(VideoController.back(_:))) + backButton = UIBarButtonItem(title: "0:00", style:UIBarButtonItem.Style.plain, 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(_:))) @@ -86,11 +85,11 @@ class VideoController: UIViewController, ItemController, BMPlayerDelegate { view.addSubview(player) player.snp.makeConstraints { (make) in - // make.top.equalTo(self.view).offset(100) + // make.top.equalTo(self.view).offset(100) make.left.right.equalTo(self.view) make.height.equalTo(self.view) // Note here, the aspect ratio 16:9 priority is lower than 1000 on the line, because the 4S iPhone aspect ratio is not 16:9 - // make.height.equalTo(player.snp.width).multipliedBy(9.0/16.0).priority(750) + // make.height.equalTo(player.snp.width).multipliedBy(9.0/16.0).priority(750) } player.delegate = self @@ -102,20 +101,41 @@ class VideoController: UIViewController, ItemController, BMPlayerDelegate { if let c = currentItem, let url = c.playerURL { print(url) play(url as URL) - // player.playerLayer!.player!.volume = 0.0 + // player.playerLayer!.player!.volume = 0.0 update() } + loopMode = detailDelegate!.settings().autoloop updateLoop() } func editItem() { - let kv = EditItemView(item: currentSnapshot!) + let currentItem = player.playerLayer?.player?.currentItem + let totalTime : Double + + if let playerItem = currentItem { + totalTime = TimeInterval(playerItem.duration.value) / TimeInterval(playerItem.duration.timescale) + } + else { + totalTime = 1000 + } + + let kv = EditItemView(item: currentSnapshot!, len: totalTime, seek: + { value in + print(value) + self.player.seekSmoothlyToTime(newChaseTime: value) + }, capture: { item in + item.scale = Double(self.player.zoom) + item.offset = CGPoint(x: self.player.xpos, y: self.player.ypos) + }) + let pc = UIHostingController(rootView: kv) + pc.view.backgroundColor = .clear let navController = UINavigationController(rootViewController: pc) // Creating a navigation controller with pc at the root of the navigation stack. - // navController.modalPresentationStyle = .fullScreen +// navController.modalPresentationStyle = .popover present(navController, animated: false, completion: nil) + } @@ -146,6 +166,8 @@ class VideoController: UIViewController, ItemController, BMPlayerDelegate { } else { edit = true + loopMode = false + updateLoop() reviewButton!.tintColor = UIColor.yellow } } @@ -235,7 +257,7 @@ class VideoController: UIViewController, ItemController, BMPlayerDelegate { file = file.appendingPathExtension("mp4") } print (file) - var dur = loopEnd - loopStart + var dur = player.loopEnd - loopStart if (dur < 0) { return } @@ -278,45 +300,31 @@ class VideoController: UIViewController, ItemController, BMPlayerDelegate { } else { if player.isPlayToTheEnd { - player.seek(0, completion: {[weak self] in - self!.player.play() - }) + player.seekSmoothlyToTime(newChaseTime: 0) player.isPlayToTheEnd = false } player.play() } -print("play") + print("play") } @objc func loop(_ sender: AnyObject) { - loopOption += 1 - if loopOption >= 2 { - loopOption = 0 + if edit { + loopMode = false } - - if loopOption == 1 { - let t = player.playerLayer!.player!.currentTime() - loopEnd = (Double(t.value) / Double(t.timescale)) - 2.0 + else { + loopMode = !loopMode } updateLoop() } func updateLoop() { - if loopOption == 1 { - var dur = loopEnd - loopStart - - if dur > 0 { - loopButton!.title = "(\(dur))" - } - else { - loopButton!.title = "cont" - } - + if loopMode { + loopButton!.title = "loop" } else { - loopButton!.title = "loop" + loopButton!.title = "cont" } - } @objc func aspect(_ sender: AnyObject) { @@ -325,9 +333,9 @@ print("play") aspect = 1 } switch aspect { - case 1: - player.aspectx = 1.0 - player.aspecty = 1.0 + case 1: + player.aspectx = 1.0 + player.aspecty = 1.0 case 2: player.aspectx = 0.9 player.aspecty = 1.0 @@ -337,7 +345,7 @@ print("play") default: print("aspect") } - // todo player.verticalMoved(0) + // todo player.verticalMoved(0) player.transformLayer() aspectButton!.title = "\(aspect)" } @@ -388,7 +396,7 @@ print("play") } } let asset = BMPlayerResource(name: "video", definitions: def) - // let asset = BMPlayerResource(url: url) + // let asset = BMPlayerResource(url: url) player.setVideo(resource: asset, definitionIndex: index) player.playerLayer!.player!.automaticallyWaitsToMinimizeStalling = false @@ -400,8 +408,8 @@ print("play") } func playerItemDidReachEnd(_ note: Notification) { -print("finish") - // Timer.scheduledTimer(timeInterval: 0.6, target: self, selector: #selector(update), userInfo: nil, repeats: false) + print("finish") + // Timer.scheduledTimer(timeInterval: 0.6, target: self, selector: #selector(update), userInfo: nil, repeats: false) } @@ -439,52 +447,62 @@ print("finish") } @objc func thumbnailClicked(_ source: UIButton) { - currentSnapshot = buttons[source] - player.seek(buttons[source]!.time) - loopStart = buttons[source]!.time - loopOption = 0 - loopButton!.title = "loop" + if let currentSnapshot = buttons[source] { + gotoSnapshot(currentSnapshot: currentSnapshot) - if (edit) { - // editItem() + if (edit) { + editItem() + } + } + // moviePlayer!.currentPlaybackRate = Float(speedOptions[speedOption]) + + // print("goto \(buttons[source]!.time!) is \(moviePlayer!.currentPlaybackTime)") + } + + private func gotoSnapshot(currentSnapshot: MediaItem) { + player.seekSmoothlyToTime(newChaseTime: currentSnapshot.time) + loopStart = currentSnapshot.time + player.loopEnd = loopStart + currentSnapshot.length + + if loopMode && currentSnapshot.scale > 0 { + player.zoom = Float(currentSnapshot.scale) + player.xpos = currentSnapshot.offset.x + player.ypos = currentSnapshot.offset.y + player.transformLayer() } - // moviePlayer!.currentPlaybackRate = Float(speedOptions[speedOption]) - // print("goto \(buttons[source]!.time!) is \(moviePlayer!.currentPlaybackTime)") + self.currentSnapshot = currentSnapshot } @objc func update() { - reviewButton!.title = currentItem!.name + reviewButton!.title = currentItem!.name - if currentItem!.type == ItemType.SNAPSHOT { - player.seek(currentItem!.time) - if detailDelegate!.settings().autoloop && currentItem!.loop { - loopStart = currentItem!.time - loopEnd = currentItem!.time + currentItem!.length - loopOption = 1 - } - currentItem = currentItem!.parent - } else { - if !currentItem!.children.isEmpty { - player.seek(currentItem!.children[0].time) - } - else { - let duration = player.playerLayer!.playerItem!.duration - if !duration.isIndefinite { - print(duration) - player.seek(duration.seconds / 2.0) - } + if currentItem!.type == ItemType.SNAPSHOT { + player.seek(currentItem!.time) + loopStart = currentItem!.time + player.loopEnd = currentItem!.time + currentItem!.length + currentItem = currentItem!.parent + } else { + if !currentItem!.children.isEmpty { + player.seekSmoothlyToTime(newChaseTime: currentItem!.children[0].time) + } + else { + let duration = player.playerLayer!.playerItem!.duration + if !duration.isIndefinite { + print(duration) + player.seekSmoothlyToTime(newChaseTime: duration.seconds / 2.0) } } + } - navigationItem.rightBarButtonItems = [barbutton!] + navigationItem.rightBarButtonItems = [barbutton!] - for c in currentItem!.children { - addItemButton(c) - } + for c in currentItem!.children { + addItemButton(c) + } - player.play() + player.play() } @@ -535,38 +553,38 @@ print("finish") @objc func swipeUp() { print("u") - print("Type: \(currentItem!.type) Count: \(currentItem!.children.count) Index: \(index) Current: \(currentItem!.index)") + print("Type: \(currentItem!.type) Count: \(currentItem!.children.count) Index: \(index) Current: \(currentItem!.index)") - if !edit && (currentItem!.children.isEmpty || !(index < currentItem!.children.count - 1)) { - print ("switch") - var newIndex = currentItem!.index + 1 + if !edit && (currentItem!.children.isEmpty || !(index < currentItem!.children.count - 1)) { + print ("switch") + var newIndex = currentItem!.index + 1 - if currentItem!.parent!.children.count <= newIndex { - newIndex = 0 - } + if currentItem!.parent!.children.count <= newIndex { + newIndex = 0 + } - currentItem = currentItem!.parent!.children[newIndex] + currentItem = currentItem!.parent!.children[newIndex] - print("'Switched Type: \(currentItem!.type) Count: \(currentItem!.children.count) Index: \(index) Current: \(currentItem!.index)") + print("'Switched Type: \(currentItem!.type) Count: \(currentItem!.children.count) Index: \(index) Current: \(currentItem!.index)") - index = 0 - // player.playWithURL(currentItem!.playerURL) - Timer.scheduledTimer(timeInterval: 1.2, target: self, selector: #selector(update), userInfo: nil, repeats: false) + index = 0 + // player.playWithURL(currentItem!.playerURL) + Timer.scheduledTimer(timeInterval: 1.2, target: self, selector: #selector(update), userInfo: nil, repeats: false) - return - } + return + } - if !(currentItem!.children.isEmpty) { - print ("switch internal") - if index < currentItem!.children.count - 1 { - index+=1; - } else { - index = 0; - } - let child = currentItem!.children[index] - // player.currentPlaybackTime = child.time! - // player.currentPlaybackRate = Float(speedOptions[speedOption]) + if !(currentItem!.children.isEmpty) { + print ("switch internal") + if index < currentItem!.children.count - 1 { + index+=1; + } else { + index = 0; } + let child = currentItem!.children[index] + // player.currentPlaybackTime = child.time! + // player.currentPlaybackRate = Float(speedOptions[speedOption]) + } } @@ -585,28 +603,28 @@ print("finish") @objc func swipeDown() { print("d") - if !edit { - var newIndex = currentItem!.index - 1 + if !edit { + var newIndex = currentItem!.index - 1 - if newIndex < 0 { - newIndex = 0 - } + if newIndex < 0 { + newIndex = 0 + } - currentItem = currentItem!.parent!.children[newIndex] - index = 0; + currentItem = currentItem!.parent!.children[newIndex] + index = 0; - // player.contentURL = currentItem!.playerURL - player.play() - Timer.scheduledTimer(timeInterval: 1.2, target: self, selector: #selector(update), userInfo: nil, repeats: false) + // player.contentURL = currentItem!.playerURL + player.play() + Timer.scheduledTimer(timeInterval: 1.2, target: self, selector: #selector(update), userInfo: nil, repeats: false) - return - } - // player.currentPlaybackTime = player.currentPlaybackTime + 10.0 - Timer.scheduledTimer(timeInterval: 0.9, - target: self, - selector: #selector(resumePlay), - userInfo: nil, - repeats: false) + return + } + // player.currentPlaybackTime = player.currentPlaybackTime + 10.0 + Timer.scheduledTimer(timeInterval: 0.9, + target: self, + selector: #selector(resumePlay), + userInfo: nil, + repeats: false) } @@ -615,11 +633,11 @@ print("finish") print("l") // player.currentPlaybackRate = Float(0.0) // player.currentPlaybackTime = player.currentPlaybackTime + 30.0 - Timer.scheduledTimer(timeInterval: 0.9, - target: self, - selector: #selector(resumePlay), - userInfo: nil, - repeats: false) + Timer.scheduledTimer(timeInterval: 0.9, + target: self, + selector: #selector(resumePlay), + userInfo: nil, + repeats: false) } @@ -645,7 +663,7 @@ print("finish") } catch let error { print("*** Error generating thumbnail: \(error.localizedDescription)") } - // thumbnailTime = player.currentPlaybackTime + // thumbnailTime = player.currentPlaybackTime print("tap \(thumbnailTime)") // moviePlayer!.requestThumbnailImages(atTimes: [thumbnailTime], // timeOption: MPMovieTimeOption.exact); @@ -667,6 +685,61 @@ print("finish") addItemButton(newItem) } + + func moveUp() { + let t = Date().timeIntervalSince1970 + if lastMove + 2 > t { + return + } + lastMove = t + + if let c = currentItem?.children { + if !c.isEmpty{ + if let s = currentSnapshot { + if var i = c.firstIndex { x in x===s } { + print(i) + i+=1 + if i >= c.count { + i = 0 + } + gotoSnapshot(currentSnapshot: c[i]) + } + } + else { + gotoSnapshot(currentSnapshot: c[0]) + } + } + } + } + + var lastMove = 0.0 + + func moveDown() { + let t = Date().timeIntervalSince1970 + if lastMove + 2 > t { + return + } + lastMove = t + + if let c = currentItem?.children { + if !c.isEmpty{ + if let s = currentSnapshot { + if var i = c.firstIndex { x in x===s } { + print(i) + i-=1 + if i < 0 { + i = c.count-1 + } + gotoSnapshot(currentSnapshot: c[i]) + } + } + else { + gotoSnapshot(currentSnapshot: c[0]) + } + } + } + } + func bmPlayer(player: BMPlayer) { let speed = Float(speedOptions[speedOption]) if let pl = player.playerLayer!.player { @@ -680,16 +753,20 @@ print("finish") } func bmPlayer(player: BMPlayer, loadedTimeDidChange loadedDuration: TimeInterval, totalDuration: TimeInterval) { - // print("load") + // print("load") } func bmPlayer(player: BMPlayer, playTimeDidChange currentTime: TimeInterval, totalTime: TimeInterval) { - if loopOption == 1 { - if currentTime > loopEnd { - player.seek(loopStart) + if loopMode { + if currentTime > player.loopEnd && loopStart < player.loopEnd { + player.chaseTime = CMTime.zero + player.seekSmoothlyToTime(newChaseTime: loopStart) } } - // print("Time") + + if let b = backButton { + b.title = BMPlayer.formatSecondsToString(currentTime) + } } func bmPlayer(player: BMPlayer, playerIsPlaying playing: Bool) { diff --git a/kplayer/master/NetworkDelegate.swift b/kplayer/master/NetworkDelegate.swift index ec7c377..47d5cc4 100644 --- a/kplayer/master/NetworkDelegate.swift +++ b/kplayer/master/NetworkDelegate.swift @@ -81,13 +81,25 @@ class NetworkDelegate: MasterDelegate, DetailDelegate { } func deleteThumb(selectedItem c: MediaItem) { - let t = c.time - let ms = Int(t * 1000) - let p = c.snapshotDirPathForVideo + "\(ms).jpg" - let pt = c.snapshotDirPathForVideo + "\(ms)_thumb.jpg" + if c.local { + if let url = c.parent?.localURL { + do { + try FileManager.default.removeItem(atPath: c.thumbUrl!) + } catch { + print(c.thumbUrl) + } + LocalManager.sharedInstance.saveFavDir(url: url, item: c.parent!) + } + } + else { + 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) + NetworkManager.sharedInstance.deleteThumb(p) + NetworkManager.sharedInstance.deleteThumb(pt) + } } func saveItem(selectedItem: MediaItem) { diff --git a/kplayer/video/BMPlayer.swift b/kplayer/video/BMPlayer.swift index f1002bd..b3c72a2 100644 --- a/kplayer/video/BMPlayer.swift +++ b/kplayer/video/BMPlayer.swift @@ -18,6 +18,8 @@ public protocol BMPlayerDelegate : class { func bmPlayer(player: BMPlayer, playTimeDidChange currentTime : TimeInterval, totalTime: TimeInterval) func bmPlayer(player: BMPlayer, playerIsPlaying playing: Bool) func bmPlayer(player: BMPlayer, playerOrientChanged isFullscreen: Bool) + func moveUp() + func moveDown() } /** @@ -37,6 +39,7 @@ open class BMPlayer: UIView { open var aspecty = Float(1.0) var xpos = 0.0 var ypos = 0.0 + var loopEnd = 0.0 open var pinchGesture: UIPinchGestureRecognizer! open var moveGesture: UIPanGestureRecognizer! @@ -74,6 +77,12 @@ open class BMPlayer: UIView { if gestureRecognizer.state == .began || gestureRecognizer.state == .changed { zoom *= Float(gestureRecognizer.scale) + if zoom < 0.1 { + zoom = 1.0 + xpos = 0 + ypos = 0 + } + gestureRecognizer.scale = 1.0 transformLayer() @@ -259,6 +268,7 @@ open class BMPlayer: UIView { - parameter to: target time */ open func seek(_ to:TimeInterval, completion: (()->Void)? = nil) { + chaseTime = CMTime(value: Int64(to * 10000), timescale: CMTimeScale(10000)) playerLayer?.seek(to: to, completion: completion) } @@ -306,7 +316,11 @@ open class BMPlayer: UIView { } // https://gist.github.com/shaps80/ac16b906938ad256e1f47b52b4809512 - private func seekSmoothlyToTime(newChaseTime: CMTime) { + public func seekSmoothlyToTime(newChaseTime: Double) { + seekSmoothlyToTime(newChaseTime: CMTime(value: Int64(newChaseTime * 10000), timescale: CMTimeScale(10000))) + } + + public func seekSmoothlyToTime(newChaseTime: CMTime) { if CMTimeCompare(newChaseTime, chaseTime) != 0 { chaseTime = newChaseTime @@ -425,6 +439,10 @@ open class BMPlayer: UIView { print(skipAmount) if (skipAmount > 1500) { self.sumTime += TimeInterval(30) + + if sumTime > loopEnd { + loopEnd = 1000000; + } } else if skipAmount > 0 { self.sumTime += TimeInterval(10) } else if skipAmount > -1500 { @@ -469,6 +487,12 @@ open class BMPlayer: UIView { open func verticalMoved(_ value: CGFloat) { print(value) if (value < -100) { + delegate?.moveDown() + // controlView(controlView: controlView, didChooseDefinition: currentDefinition+1); + } + + if (value > 100) { + delegate?.moveUp() // controlView(controlView: controlView, didChooseDefinition: currentDefinition+1); } diff --git a/kplayer/video/KVideoPlayer.swift b/kplayer/video/KVideoPlayer.swift new file mode 100644 index 0000000..7449a78 --- /dev/null +++ b/kplayer/video/KVideoPlayer.swift @@ -0,0 +1,30 @@ +// +// Created by Marco Schmickler on 14.11.21. +// Copyright (c) 2021 Marco Schmickler. All rights reserved. +// + + +import SwiftUI +import AVKit + +struct KVideoPlayer: View { + private let player = AVPlayer(url: URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!) + + var body: some View { + VideoPlayer(player: player) + .onAppear() { + // Start the player going, otherwise controls don't appear + player.play() + } + .onDisappear() { + // Stop the player when the view disappears + player.pause() + } + } +} + +struct KVideoPlayer_Previews: PreviewProvider { + static var previews: some View { + KVideoPlayer() + } +}