diff --git a/kplayer.xcodeproj/project.pbxproj b/kplayer.xcodeproj/project.pbxproj index e01775f..2aab7fb 100644 --- a/kplayer.xcodeproj/project.pbxproj +++ b/kplayer.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 1C73666A07CF2416B1B8D3F0 /* KSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736C94157754DE1C808173 /* KSettingsModel.swift */; }; 1C736690D123BD4B24874394 /* pathfinder.scpt in Sources */ = {isa = PBXBuildFile; fileRef = 1C7369BED02028D8564E82D5 /* pathfinder.scpt */; }; 1C7366A0CFD2B55BF8C3BAF0 /* NetworkDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7364F10BED5DA0F1C0423C /* NetworkDelegate.swift */; }; + 1C7366FE5C760C8D5117207F /* SVideoLoopPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360F9835128FC0A198ED0 /* SVideoLoopPlayer.swift */; }; 1C7367084839D2E8B180DB74 /* UIViewController+Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7360295486647982CFEACF /* UIViewController+Alert.swift */; }; 1C73671FC2CCCACAA2FFC153 /* ThumbnailCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736EA15A11AF7D57F85824 /* ThumbnailCache.swift */; }; 1C73675C34BE0990D44570BE /* ItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C736253AB7A95EA41B605B7 /* ItemModel.swift */; }; @@ -95,6 +96,7 @@ 1C7360A94DBECA685ED8602F /* ImageLoadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageLoadOperation.swift; sourceTree = ""; }; 1C7360B6D0757D4FB6433E7B /* AsyncImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncImage.swift; sourceTree = ""; }; 1C7360F9649E40B7C2EAB581 /* kplayer.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = kplayer.txt; sourceTree = ""; }; + 1C7360F9835128FC0A198ED0 /* SVideoLoopPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVideoLoopPlayer.swift; sourceTree = ""; }; 1C73611D226B48C24DB37535 /* MasterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; 1C73615FFA2AA98BD1C56CD4 /* links.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = links.html; sourceTree = ""; }; 1C7361F01841F546FA7AFD58 /* nspersistentcontainer-defaults-swift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "nspersistentcontainer-defaults-swift.swift"; sourceTree = ""; }; @@ -282,6 +284,7 @@ 1C73621E431C9BEC1440B936 /* SVideoPlayer.swift */, 1C73675F8DDFA82DEADB542E /* VideoPlayerView.swift */, 1C73661C3F9F4E53645551AD /* KToggleButton.swift */, + 1C7360F9835128FC0A198ED0 /* SVideoLoopPlayer.swift */, ); path = video; sourceTree = ""; @@ -594,6 +597,7 @@ 1C736C8DAD6C2FBB9A2EA625 /* SearchItemView.swift in Sources */, 1C736690D123BD4B24874394 /* pathfinder.scpt in Sources */, 1C736559059B6FBA1C661191 /* KToggleButton.swift in Sources */, + 1C7366FE5C760C8D5117207F /* SVideoLoopPlayer.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/kplayer/core/NetworkManager.swift b/kplayer/core/NetworkManager.swift index f75941d..1a56712 100644 --- a/kplayer/core/NetworkManager.swift +++ b/kplayer/core/NetworkManager.swift @@ -262,11 +262,24 @@ class NetworkManager { if let json = response.value { var hashes = Dictionary() + var items : MediaModel? + for b in json as! [String] { let p = NSURL(fileURLWithPath: b).lastPathComponent! - if p.contains("_thumb.jpg") { + if p.contains(".json") { + do { + let enc = b.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)! + let jurl = NetworkManager.sharedInstance.vidurl + enc.substringStartingFrom(10) + let jsonData = try Data(contentsOf: URL(string: jurl)!) + items = try JSONDecoder().decode(MediaModel.self, from: jsonData) + } + catch { + + } + } + else if p.contains("_thumb.jpg") { let ts = p.substringWithoutLast(10) hashes[ts] = b @@ -292,6 +305,18 @@ class NetworkManager { snap.parent = item snap.loaded = true + if let ci = items { + for mic in ci.children { + if snap.indexId == mic.indexId { + if mic.length > 0 { + snap.length = mic.length + snap.scale = mic.scale + snap.offset = mic.offset + } + } + } + } + item.children.append(snap) } @@ -394,6 +419,17 @@ class NetworkManager { } } } + + do { + let j = item.snapshotDirPathForVideo + "items.json" + let jsonEncoder = JSONEncoder() + let jsonData = try! jsonEncoder.encode(item.toMediaModel()) + let op = UploadOperation(baseUrl: self.nodeurl + "upload", data: jsonData, path: j) + self.operationQueue.addOperation(op) + } + catch { + + } } } diff --git a/kplayer/video/SVideoLoopPlayer.swift b/kplayer/video/SVideoLoopPlayer.swift new file mode 100644 index 0000000..f5ed919 --- /dev/null +++ b/kplayer/video/SVideoLoopPlayer.swift @@ -0,0 +1,54 @@ +// +// Created by Marco Schmickler on 03.04.22. +// Copyright (c) 2022 Marco Schmickler. All rights reserved. +// + +import Foundation +import SwiftUI +import AVKit + +struct SVideoLoopPlayer : View { + var completionHandler: () -> Void + var model : SVideoModel + + var player = AVQueuePlayer(items: [AVPlayerItem]()) + var playerLooper: AVPlayerLooper + + init(completionHandler: @escaping () -> Void, baseModel: SVideoModel) { + self.completionHandler = completionHandler + self.model = SVideoModel(allItems: [], currentSnapshot: baseModel.currentSnapshot, baseItem: baseModel.baseItem) + + var c = AVMutableComposition() + let tr = c.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) + + var currentTime = CMTime.zero + + do { + var urlAsset = AVURLAsset(url: baseModel.currentSnapshot.playerURL!) + + let range = CMTimeRangeMake(start: CMTime(seconds: baseModel.currentSnapshot.time, preferredTimescale: CMTimeScale(10000)), duration: CMTime(seconds: baseModel.currentSnapshot.length, preferredTimescale: CMTimeScale(10000))) + try tr!.insertTimeRange(range, of: urlAsset.tracks(withMediaType: AVMediaType.video)[0], at: CMTime.zero) + } catch { + print(error) + } + + let item = AVPlayerItem(asset: c) + player.insert(item, after: nil) + self.playerLooper = AVPlayerLooper(player: player, templateItem: item) + } + + var body: some View { + VideoPlayerView(model: model, + player: player) + .scaleEffect(model.scale) + .offset(model.dragOffset) + .onTapGesture(count: 2) { + completionHandler() + }.onAppear() { + player.play() + } + .onDisappear() { + player.pause() + } + } +} diff --git a/kplayer/video/SVideoPlayer.swift b/kplayer/video/SVideoPlayer.swift index dc69a88..a3a5cf4 100644 --- a/kplayer/video/SVideoPlayer.swift +++ b/kplayer/video/SVideoPlayer.swift @@ -207,6 +207,12 @@ struct SVideoPlayer: View, EditItemDelegate { KToggleButton(text: "zoom", binding: $model.zoomed).frame(height: 30) KToggleButton(text: "loop", binding: $model.loop).frame(height: 30) +// .fullScreenCover(isPresented: $model.loop) { +// SVideoLoopPlayer(completionHandler: { +// model.loop = false +// }, baseModel: model) +// } + KToggleButton(text: "flip", binding: $upsidedown).frame(height: 30) Button(action: {