capacitor-plugin-playlist 0.1.18 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/android/src/main/java/org/dwbn/plugins/playlist/PlaylistPlugin.kt +4 -8
  2. package/android/src/main/java/org/dwbn/plugins/playlist/RmxAudioPlayer.java +397 -385
  3. package/android/src/main/java/org/dwbn/plugins/playlist/manager/PlaylistManager.kt +17 -12
  4. package/android/src/main/java/org/dwbn/plugins/playlist/notification/PlaylistNotificationProvider.kt +5 -1
  5. package/android/src/main/java/org/dwbn/plugins/playlist/service/MediaService.kt +1 -2
  6. package/dist/docs.json +5 -23
  7. package/dist/esm/Constants.js.map +1 -1
  8. package/dist/esm/RmxAudioPlayer.d.ts +4 -10
  9. package/dist/esm/RmxAudioPlayer.js +19 -22
  10. package/dist/esm/RmxAudioPlayer.js.map +1 -1
  11. package/dist/esm/definitions.d.ts +5 -4
  12. package/dist/esm/index.d.ts +1 -1
  13. package/dist/esm/index.js +1 -1
  14. package/dist/esm/index.js.map +1 -1
  15. package/dist/esm/plugin.js +1 -0
  16. package/dist/esm/plugin.js.map +1 -1
  17. package/dist/esm/utils.d.ts +1 -1
  18. package/dist/esm/utils.js.map +1 -1
  19. package/dist/esm/web.d.ts +3 -3
  20. package/dist/esm/web.js +32 -27
  21. package/dist/esm/web.js.map +1 -1
  22. package/dist/plugin.cjs.js +47 -44
  23. package/dist/plugin.cjs.js.map +1 -1
  24. package/dist/plugin.js +48 -45
  25. package/dist/plugin.js.map +1 -1
  26. package/ios/Plugin/AVBidirectionalQueuePlayer.swift +18 -4
  27. package/ios/Plugin/AudioTrack.swift +0 -1
  28. package/ios/Plugin/DispatchQueue.swift +3 -3
  29. package/ios/Plugin/RmxAudioPlayer.swift +77 -108
  30. package/package.json +1 -1
  31. package/android/.gitignore +0 -1
  32. package/android/.npmignore +0 -1
  33. package/ios/.DS_Store +0 -0
@@ -12,7 +12,7 @@ public extension DispatchQueue {
12
12
  - action: The closure to be executed
13
13
  Delays a closure execution and ensures no other executions are made during deadline
14
14
  */
15
- public func throttle(deadline: DispatchTime, context: AnyHashable? = nil, action: @escaping () -> Void) {
15
+ func throttle(deadline: DispatchTime, context: AnyHashable? = nil, action: @escaping () -> Void) {
16
16
  let worker = DispatchWorkItem {
17
17
  defer { throttleWorkItems.removeValue(forKey: context ?? nilContext) }
18
18
  action()
@@ -31,7 +31,7 @@ public extension DispatchQueue {
31
31
  - action: The closure to be executed
32
32
  Executes a closure and ensures no other executions will be made during the interval.
33
33
  */
34
- public func debounce(interval: Double, context: AnyHashable? = nil, action: @escaping () -> Void) {
34
+ func debounce(interval: Double, context: AnyHashable? = nil, action: @escaping () -> Void) {
35
35
  if let last = lastDebounceCallTimes[context ?? nilContext], last + interval > .now() {
36
36
  return
37
37
  }
@@ -44,4 +44,4 @@ public extension DispatchQueue {
44
44
  lastDebounceCallTimes.removeValue(forKey: context ?? nilContext)
45
45
  }
46
46
  }
47
- }
47
+ }
@@ -29,6 +29,8 @@ final class RmxAudioPlayer: NSObject {
29
29
 
30
30
  private let avQueuePlayer = AVBidirectionalQueuePlayer(items: [])
31
31
 
32
+ private var lastTrackId: String? = nil
33
+ private var lastRate: Float? = nil
32
34
  override init() {
33
35
  super.init()
34
36
 
@@ -140,7 +142,7 @@ final class RmxAudioPlayer: NSObject {
140
142
 
141
143
  func clearAllItems() {
142
144
  print("RmxAudioPlayer.execute=clearAllItems")
143
- removeAllTracks(false)
145
+ removeAllTracks()
144
146
  }
145
147
 
146
148
  func playTrack(index: Int, positionTime: Float?) throws {
@@ -385,7 +387,7 @@ final class RmxAudioPlayer: NSObject {
385
387
  }
386
388
  }
387
389
 
388
- func removeAllTracks(_ isCommand: Bool) {
390
+ func removeAllTracks() {
389
391
  for item in avQueuePlayer.queuedAudioTracks {
390
392
  removeTrackObservers(item)
391
393
  }
@@ -393,15 +395,6 @@ final class RmxAudioPlayer: NSObject {
393
395
  avQueuePlayer.removeAllItems()
394
396
  wasPlayingInterrupted = false
395
397
 
396
- print("RmxAudioPlayer, removeAllTracks, ==> RMXSTATUS_PLAYLIST_CLEARED")
397
- onStatus(.rmxstatus_PLAYLIST_CLEARED, trackId: "INVALID", param: nil)
398
-
399
- // a.t.m there's no way for this to be triggered from within the plugin,
400
- // but it might get added at some point.
401
- if isCommand {
402
- let action = "music-controls-clear"
403
- print("\(action)")
404
- }
405
398
  }
406
399
 
407
400
  // MARK: - remote control events
@@ -454,7 +447,6 @@ final class RmxAudioPlayer: NSObject {
454
447
  let trackStatus = getStatusItem(playerItem)
455
448
 
456
449
  onStatus(.rmxstatus_STALLED, trackId: playerItem?.trackId, param: trackStatus)
457
- onStatus(.rmxstatus_PAUSE, trackId: playerItem?.trackId, param: trackStatus)
458
450
  }
459
451
 
460
452
  @objc func playerItemDidReachEnd(_ notification: Notification?) {
@@ -521,7 +513,6 @@ final class RmxAudioPlayer: NSObject {
521
513
  if avQueuePlayer.isPlaying {
522
514
  let trackStatus = getStatusItem(playerItem)
523
515
  onStatus(.rmxstatus_PLAYBACK_POSITION, trackId: playerItem.trackId, param: trackStatus)
524
- // NSLog(@" . %.5f / %.5f sec (%.1f %%) [%@]", currentTime, duration, (currentTime / duration)*100.0, name);
525
516
  }
526
517
  }
527
518
 
@@ -529,50 +520,55 @@ final class RmxAudioPlayer: NSObject {
529
520
  }
530
521
 
531
522
  override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
532
- print("observing \(String(describing: keyPath))")
533
- print("observing \(String(describing: change))")
534
- if (keyPath == "currentItem") {
523
+ guard let change = change else {
524
+ return
525
+ }
526
+
527
+ switch keyPath {
528
+ case "currentItem":
529
+ // only fire on real change!
535
530
  let player = object as? AVBidirectionalQueuePlayer
536
531
  let playerItem = player?.currentAudioTrack
532
+ guard lastTrackId != playerItem?.trackId else {
533
+ return // todo should call super instead or?
534
+ }
535
+ lastTrackId = playerItem?.trackId
537
536
  handleCurrentItemChanged(playerItem)
538
- return
539
- }
540
-
541
- if (keyPath == "rate") {
542
- DispatchQueue.main.debounce(interval: 0.2, context: self, action: { [self] in
543
- let player = object as? AVBidirectionalQueuePlayer
544
-
545
- guard let playerItem = player?.currentAudioTrack else { return }
546
-
547
- let trackStatus = getStatusItem(playerItem)
548
- print("Playback rate changed: \(1), is playing: \(player?.isPlaying ?? false)")
549
-
550
- if player?.isPlaying ?? false {
551
- onStatus(.rmxstatus_PLAYING, trackId: playerItem.trackId, param: trackStatus)
552
- } else {
553
- onStatus(.rmxstatus_PAUSE, trackId: playerItem.trackId, param: trackStatus)
554
- }
555
- })
537
+ case "rate":
538
+ guard lastRate != change[.newKey] as? Float else {
539
+ return // todo should call super instead or?
540
+ }
541
+ self.lastRate = change[.newKey] as? Float
542
+ let player = object as? AVBidirectionalQueuePlayer
556
543
 
557
- return
558
- }
544
+ guard let playerItem = player?.currentAudioTrack else { return }
545
+
546
+ let trackStatus = getStatusItem(playerItem)
547
+ print("Playback rate changed: \(String(describing: change[.newKey])), is playing: \(player?.isPlaying ?? false)")
559
548
 
560
- if (keyPath == "status") {
549
+ if player?.isPlaying ?? false {
550
+ onStatus(.rmxstatus_PLAYING, trackId: playerItem.trackId, param: trackStatus)
551
+ } else {
552
+ onStatus(.rmxstatus_PAUSE, trackId: playerItem.trackId, param: trackStatus)
553
+ }
554
+ case "status":
561
555
  DispatchQueue.main.debounce(interval: 0.2, context: self, action: { [self] in
562
556
  let playerItem = object as? AudioTrack
563
557
  handleTrackStatusEvent(playerItem)
564
558
  })
565
- return
566
- }
567
-
568
- if (keyPath == "timeControlStatus") {
559
+ case "timeControlStatus":
569
560
  DispatchQueue.main.debounce(interval: 0.2, context: self, action: { [self] in
570
561
  let player = object as? AVBidirectionalQueuePlayer
571
562
 
572
- guard let playerItem = player?.currentAudioTrack else { return }
563
+ guard let playerItem = player?.currentAudioTrack else {
564
+ return
565
+ }
566
+ guard lastTrackId != playerItem.trackId else {
567
+ return // todo should call super instead or?
568
+ }
573
569
 
574
570
  let trackStatus = getStatusItem(playerItem)
575
- print("Playback rate changed: \(1), is playing: \(player?.isPlaying ?? false)")
571
+ print("TCSPlayback rate changed: \(String(describing: change[.newKey])), is playing: \(player?.isPlaying ?? false)")
576
572
 
577
573
  if player?.timeControlStatus == .playing {
578
574
  onStatus(.rmxstatus_PLAYING, trackId: playerItem.trackId, param: trackStatus)
@@ -582,36 +578,28 @@ final class RmxAudioPlayer: NSObject {
582
578
  onStatus(.rmxstatus_PAUSE, trackId: playerItem.trackId, param: trackStatus)
583
579
  }
584
580
  })
585
- return
586
- }
587
-
588
- if (keyPath == "duration") {
581
+ case "duration":
589
582
  DispatchQueue.main.debounce(interval: 0.5, context: self, action: { [self] in
590
583
  let playerItem = object as? AudioTrack
591
584
  handleTrackDuration(playerItem)
592
585
  })
593
- return
594
- }
595
-
596
- if (keyPath == "loadedTimeRanges") {
586
+ case "loadedTimeRanges":
597
587
  DispatchQueue.main.debounce(interval: 0.2, context: self, action: { [self] in
598
588
  let playerItem = object as? AudioTrack
599
589
  handleTrackBuffering(playerItem)
600
590
  })
601
- return
591
+ default:
592
+ super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
602
593
  }
603
-
604
- super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
605
- return
606
594
  }
607
595
 
608
596
  func updateNowPlayingTrackInfo(_ playerItem: AudioTrack?, updateTrackData: Bool) {
597
+
609
598
  let currentItem = playerItem ?? avQueuePlayer.currentAudioTrack
610
-
611
599
  let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
612
600
  if updatedNowPlayingInfo == nil {
613
601
  let nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo
614
- updatedNowPlayingInfo = nowPlayingInfo
602
+ updatedNowPlayingInfo = nowPlayingInfo ?? [:]
615
603
  }
616
604
 
617
605
  var currentTime: Float? = nil
@@ -627,70 +615,52 @@ final class RmxAudioPlayer: NSObject {
627
615
  }
628
616
 
629
617
  if updateTrackData {
630
- updatedNowPlayingInfo?[MPMediaItemPropertyArtist] = currentItem?.artist
631
- updatedNowPlayingInfo?[MPMediaItemPropertyTitle] = currentItem?.title
632
- updatedNowPlayingInfo?[MPMediaItemPropertyAlbumTitle] = currentItem?.album
633
- let mediaItemArtwork = createCoverArtwork(currentItem?.albumArt?.absoluteString)
618
+ updatedNowPlayingInfo![MPMediaItemPropertyArtist] = currentItem?.artist
619
+ updatedNowPlayingInfo![MPMediaItemPropertyTitle] = currentItem?.title
620
+ updatedNowPlayingInfo![MPMediaItemPropertyAlbumTitle] = currentItem?.album
634
621
 
635
- if let mediaItemArtwork = mediaItemArtwork {
636
- updatedNowPlayingInfo?[MPMediaItemPropertyArtwork] = mediaItemArtwork
622
+ if let mediaItemArtwork = createCoverArtwork(currentItem?.albumArt?.absoluteString) {
623
+ updatedNowPlayingInfo![MPMediaItemPropertyArtwork] = mediaItemArtwork
637
624
  }
638
625
  }
626
+ updatedNowPlayingInfo![MPMediaItemPropertyPlaybackDuration] = duration ?? 0.0
627
+ updatedNowPlayingInfo![MPNowPlayingInfoPropertyElapsedPlaybackTime] = currentTime ?? 0.0
628
+ updatedNowPlayingInfo![MPNowPlayingInfoPropertyPlaybackRate] = 1.0
639
629
 
640
- updatedNowPlayingInfo?[MPMediaItemPropertyPlaybackDuration] = NSNumber(value: duration ?? 0.0)
641
- updatedNowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = NSNumber(value: currentTime ?? 0.0)
642
- updatedNowPlayingInfo?[MPNowPlayingInfoPropertyPlaybackRate] = NSNumber(value: 1.0)
643
-
644
- nowPlayingInfoCenter.nowPlayingInfo = updatedNowPlayingInfo
645
-
630
+ MPNowPlayingInfoCenter.default().nowPlayingInfo = updatedNowPlayingInfo
631
+
646
632
  let commandCenter = MPRemoteCommandCenter.shared()
647
633
  commandCenter.nextTrackCommand.isEnabled = !avQueuePlayer.isAtEnd
648
634
  commandCenter.previousTrackCommand.isEnabled = !avQueuePlayer.isAtBeginning
649
635
  }
650
636
 
651
- func createCoverArtwork(_ coverUri: String?) -> MPMediaItemArtwork? {
652
- print("Creating cover art : \(String(describing: coverUri))")
653
- var coverImage: UIImage? = nil
654
- if coverUri == nil {
637
+ func createCoverArtwork(_ coverUriOrNil: String?) -> MPMediaItemArtwork? {
638
+ guard let coverUri = coverUriOrNil else {
655
639
  return nil
656
640
  }
657
-
658
- if coverUri?.lowercased().hasPrefix("file://") ?? false {
659
- let fullCoverImagePath = coverUri?.replacingOccurrences(of: "file://", with: "")
660
-
661
- if FileManager.default.fileExists(atPath: fullCoverImagePath ?? "") {
662
- coverImage = UIImage(contentsOfFile: fullCoverImagePath ?? "")
663
- }
664
- } else if coverUri?.hasPrefix("http://") ?? false || coverUri?.hasPrefix("https://") ?? false {
665
- let coverImageUrl = URL(string: coverUri ?? "")
641
+
642
+ var coverImage: UIImage? = nil
643
+ if coverUri.hasPrefix("http://") || coverUri.hasPrefix("https://") {
644
+ let coverImageUrl = URL(string: coverUri)!
666
645
 
667
- var coverImageData: Data? = nil
668
- if let coverImageUrl = coverImageUrl {
669
- do {
670
- coverImageData = try Data(contentsOf: coverImageUrl)
671
- } catch {
672
- print("Error creating the coverImageData");
673
- }
674
- }
675
- if let coverImageData = coverImageData {
646
+ do {
647
+ let coverImageData = try Data(contentsOf: coverImageUrl)
676
648
  coverImage = UIImage(data: coverImageData)
677
- }
678
- } else if !(coverUri == "") {
679
- let baseCoverImagePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).map(\.path)[0]
680
- let fullCoverImagePath = "\(baseCoverImagePath)\(coverUri ?? "")"
681
- if FileManager.default.fileExists(atPath: fullCoverImagePath) {
682
- coverImage = UIImage(named: fullCoverImagePath)
649
+ } catch {
650
+ print("Error creating the coverImageData");
683
651
  }
684
652
  } else {
685
- coverImage = UIImage(named: "none")
653
+ if FileManager.default.fileExists(atPath: coverUri) {
654
+ coverImage = UIImage(contentsOfFile: coverUri)
655
+ }
686
656
  }
687
- if let coverImage = coverImage {
688
- return isCoverImageValid(coverImage) ? MPMediaItemArtwork.init(boundsSize: coverImage.size, requestHandler: { (size) -> UIImage in
689
- return coverImage
690
- }): nil
691
-
657
+
658
+ if isCoverImageValid(coverImage) {
659
+ return MPMediaItemArtwork.init(boundsSize: coverImage!.size, requestHandler: { (size) -> UIImage in
660
+ return coverImage!
661
+ })
692
662
  }
693
- return nil
663
+ return nil;
694
664
  }
695
665
 
696
666
  func downloadImage(url: URL, completion: @escaping ((_ image: UIImage?) -> Void)){
@@ -720,7 +690,7 @@ final class RmxAudioPlayer: NSObject {
720
690
  print("New item ID: \(playerItem.trackId ?? "")")
721
691
  print("Queue is at end: \(avQueuePlayer.isAtEnd ? "YES" : "NO")")
722
692
  // When an item starts, immediately scrub it back to the beginning
723
- playerItem.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero, completionHandler: nil)
693
+ //playerItem.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero, completionHandler: nil)
724
694
  // Update the command center
725
695
  updateNowPlayingTrackInfo(playerItem, updateTrackData: true)
726
696
  } else if loop {
@@ -880,7 +850,7 @@ final class RmxAudioPlayer: NSObject {
880
850
  }
881
851
 
882
852
  if avQueuePlayer.currentItem == currentItem {
883
- if avQueuePlayer.rate != 0 {
853
+ if avQueuePlayer.rate != 0.0 {
884
854
  status = "playing"
885
855
 
886
856
  if position <= 0 && (bufferInfo?["bufferPercent"] as? NSNumber)?.floatValue ?? 0.0 == 0.0 {
@@ -1010,7 +980,6 @@ final class RmxAudioPlayer: NSObject {
1010
980
  listener.addObserver(self, selector: #selector(itemStalledPlaying(_:)), name: .AVPlayerItemPlaybackStalled, object: playerItem)
1011
981
 
1012
982
  onStatus(.rmxstatus_ITEM_ADDED, trackId: playerItem?.trackId, param: playerItem?.toDict())
1013
- onStatus(.rmxstatus_LOADING, trackId: playerItem?.trackId, param: nil)
1014
983
  }
1015
984
 
1016
985
  @objc func queueCleared(_ notification: Notification?) {
@@ -1123,7 +1092,7 @@ final class RmxAudioPlayer: NSObject {
1123
1092
  avQueuePlayer.removeObserver(self as NSObject, forKeyPath: "timeControlStatus")
1124
1093
  deregisterMusicControlsEventListener()
1125
1094
 
1126
- removeAllTracks(false)
1095
+ removeAllTracks()
1127
1096
 
1128
1097
  playbackTimeObserver = nil
1129
1098
  isWaitingToStartPlayback = false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-plugin-playlist",
3
- "version": "0.1.18",
3
+ "version": "0.1.22",
4
4
  "description": "Playlist ",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -1 +0,0 @@
1
- /build
@@ -1 +0,0 @@
1
- /build
package/ios/.DS_Store DELETED
Binary file