Skip to content

Commit 7672f65

Browse files
committed
update
1 parent ab49399 commit 7672f65

File tree

3 files changed

+79
-51
lines changed

3 files changed

+79
-51
lines changed

Sources/swiftui-loop-videoplayer/protocol/player/AbstractPlayer.swift

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,64 @@ extension AbstractPlayer{
135135
func pause() {
136136
player?.pause()
137137
}
138+
139+
/// Clears all items from the player's queue.
140+
func clearPlayerQueue() {
141+
guard let items = player?.items() else { return }
142+
for item in items {
143+
player?.remove(item)
144+
}
145+
}
146+
147+
/// Updates the current playback asset, settings, and initializes playback or a specific action when the asset is ready.
148+
///
149+
/// This method sets a new asset to be played, optionally loops it, and can automatically start playback.
150+
/// If provided, a callback is executed when the asset is ready to play.
151+
///
152+
/// - Parameters:
153+
/// - asset: The AVURLAsset to be loaded into the player.
154+
/// - loop: A Boolean value indicating whether the video should loop.
155+
/// - autoPlay: A Boolean value indicating whether playback should start automatically. Default is true.
156+
/// - callback: An optional closure to be called when the asset is ready to play.
157+
func update(asset: AVURLAsset, loop: Bool, autoPlay: Bool = true, callback: (() -> Void)? = nil) {
158+
159+
guard let player = player else { return }
160+
161+
let wasPlaying = player.rate != 0
162+
163+
if wasPlaying {
164+
pause()
165+
}
166+
167+
if !player.items().isEmpty {
168+
// Cleaning
169+
unloop()
170+
clearPlayerQueue()
171+
removeAllFilters()
172+
}
173+
174+
let newItem = AVPlayerItem(asset: asset)
175+
player.insert(newItem, after: nil)
176+
177+
if loop {
178+
self.loop()
179+
}
180+
181+
if let callback{
182+
var token: NSKeyValueObservation?
183+
token = newItem.observe(\.status, options: [.new, .old]) { item, change in
184+
if item.status == .readyToPlay {
185+
callback()
186+
token?.invalidate() // Invalidate token to stop observing
187+
token = nil
188+
}
189+
}
190+
}
191+
192+
if autoPlay{
193+
player.play()
194+
}
195+
}
138196

139197
/// Seeks the video to a specific time.
140198
/// This method moves the playback position to the specified time with precise accuracy.
@@ -146,6 +204,18 @@ extension AbstractPlayer{
146204
return
147205
}
148206

207+
guard player.currentItem?.status == .readyToPlay else{
208+
if let asset = currentAsset{
209+
update(asset: asset , loop: false, autoPlay: false){[weak self] in
210+
self?.seek(to: time)
211+
}
212+
return
213+
}
214+
215+
delegate?.didSeek(value: false, currentTime: time)
216+
return
217+
}
218+
149219
guard duration.value != 0 else{
150220
delegate?.didSeek(value: false, currentTime: time)
151221
return
@@ -414,3 +484,4 @@ internal func cleanUp(player: inout AVQueuePlayer?, playerLooper: inout AVPlayer
414484
print("Cleaned up.")
415485
#endif
416486
}
487+

Sources/swiftui-loop-videoplayer/protocol/player/LoopingPlayerProtocol.swift

Lines changed: 7 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public protocol LoopingPlayerProtocol: AbstractPlayer, LayerMakerProtocol{
5151
/// - Parameters:
5252
/// - item: The AVPlayerItem to observe for status changes.
5353
/// - player: The AVQueuePlayer to observe for errors.
54-
func setupObservers(for item: AVPlayerItem, player: AVQueuePlayer)
54+
func setupObservers(for player: AVQueuePlayer)
5555

5656
/// Responds to errors reported by the AVQueuePlayer.
5757
///
@@ -61,34 +61,6 @@ public protocol LoopingPlayerProtocol: AbstractPlayer, LayerMakerProtocol{
6161

6262
internal extension LoopingPlayerProtocol {
6363

64-
/// Updates the player to play a new asset and handles the playback state.
65-
///
66-
/// - Parameters:
67-
/// - asset: The AVURLAsset to load into the player.
68-
func update(asset: AVURLAsset, loop : Bool){
69-
70-
guard let player = player else { return }
71-
72-
let wasPlaying = player.rate != 0
73-
74-
if wasPlaying {
75-
pause()
76-
}
77-
78-
// Cleaning
79-
unloop()
80-
clearPlayerQueue()
81-
removeAllFilters()
82-
83-
// Replace the current item
84-
let newItem = AVPlayerItem(asset: asset)
85-
player.insert(newItem, after: nil)
86-
if loop{
87-
self.loop()
88-
}
89-
play()
90-
}
91-
9264
/// Sets up the player components with the specified media asset, display properties, and optional time publishing interval.
9365
///
9466
/// - Parameters:
@@ -101,14 +73,15 @@ internal extension LoopingPlayerProtocol {
10173
timePublishing: CMTime?,
10274
loop: Bool
10375
) {
104-
let item = AVPlayerItem(asset: asset)
10576

106-
let player = AVQueuePlayer(items: [item])
77+
let player = AVQueuePlayer(items: [])
10778
self.player = player
10879

80+
update(asset: asset, loop: loop)
81+
10982
configurePlayer(player, gravity: gravity, timePublishing: timePublishing, loop: loop)
11083

111-
setupObservers(for: item, player: player)
84+
setupObservers(for: player)
11285
}
11386

11487
/// Configures the provided AVQueuePlayer with specific properties for video playback.
@@ -140,31 +113,21 @@ internal extension LoopingPlayerProtocol {
140113
#endif
141114
compositeLayer.frame = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height)
142115

143-
if loop{
144-
self.loop()
145-
}
146-
147-
if !filters.isEmpty{ // have an idea for the feature
148-
applyVideoComposition()
149-
}
150-
151116
if let timePublishing{
152117
timeObserverToken = player.addPeriodicTimeObserver(forInterval: timePublishing, queue: .main) { [weak self] time in
153118
guard let self = self else{ return }
154119

155120
self.delegate?.didPassedTime(seconds: time.seconds)
156121
}
157122
}
158-
159-
player.play()
160123
}
161124

162125
/// Sets up observers on the player item and the player to track their status and error states.
163126
///
164127
/// - Parameters:
165128
/// - item: The player item to observe.
166129
/// - player: The player to observe.
167-
func setupObservers(for item: AVPlayerItem, player: AVQueuePlayer) {
130+
func setupObservers(for player: AVQueuePlayer) {
168131
errorObserver = player.observe(\.error, options: [.new]) { [weak self] player, _ in
169132
self?.handlePlayerError(player)
170133
}
@@ -190,13 +153,7 @@ internal extension LoopingPlayerProtocol {
190153
delegate?.didReceiveError(.remoteVideoError(error))
191154
}
192155

193-
/// Clears all items from the player's queue.
194-
func clearPlayerQueue() {
195-
guard let items = player?.items() else { return }
196-
for item in items {
197-
player?.remove(item)
198-
}
199-
}
156+
200157

201158
/// Sets the playback command for the video player.
202159
/// - Parameter value: The `PlaybackCommand` to set. This can be one of the following:

Sources/swiftui-loop-videoplayer/view/main/LoopPlayerMultiPlatform.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ extension LoopPlayerMultiPlatform: NSViewRepresentable{
178178
fileprivate func getAssetIfChanged(for settings: VideoSettings, and asset: AVURLAsset?) -> AVURLAsset?{
179179
let newAsset = assetFor(settings)
180180

181-
guard asset != nil else{
181+
if asset == nil {
182182
return newAsset
183183
}
184184

0 commit comments

Comments
 (0)