@rntp/player 5.0.0-beta.2 → 5.0.0-beta.4
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.
- package/RNTPPlayer.podspec +1 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/TrackPlayerModule.kt +60 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/TrackPlayerPlaybackService.kt +156 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/models/BrowseTree.kt +51 -20
- package/android/src/main/java/com/doublesymmetry/trackplayer/models/EmitEventType.kt +11 -0
- package/ios/CarPlay/BrowseTreeStore.swift +40 -0
- package/ios/CarPlay/RNTPCarPlaySceneDelegate.swift +283 -0
- package/ios/TrackPlayer.swift +135 -1
- package/ios/TrackPlayerBridge.mm +9 -0
- package/ios/models/EmitEvent.swift +10 -0
- package/lib/commonjs/NativeTrackPlayer.js.map +1 -1
- package/lib/commonjs/audio.js +76 -7
- package/lib/commonjs/audio.js.map +1 -1
- package/lib/commonjs/events/SleepTimerTriggered.js +2 -0
- package/lib/commonjs/events/SleepTimerTriggered.js.map +1 -0
- package/lib/commonjs/events/index.js +13 -0
- package/lib/commonjs/events/index.js.map +1 -1
- package/lib/module/NativeTrackPlayer.js.map +1 -1
- package/lib/module/audio.js +72 -7
- package/lib/module/audio.js.map +1 -1
- package/lib/module/events/SleepTimerTriggered.js +2 -0
- package/lib/module/events/SleepTimerTriggered.js.map +1 -0
- package/lib/module/events/index.js +2 -0
- package/lib/module/events/index.js.map +1 -1
- package/lib/typescript/src/NativeTrackPlayer.d.ts +4 -0
- package/lib/typescript/src/NativeTrackPlayer.d.ts.map +1 -1
- package/lib/typescript/src/audio.d.ts +48 -5
- package/lib/typescript/src/audio.d.ts.map +1 -1
- package/lib/typescript/src/events/SleepTimerTriggered.d.ts +5 -0
- package/lib/typescript/src/events/SleepTimerTriggered.d.ts.map +1 -0
- package/lib/typescript/src/events/index.d.ts +5 -1
- package/lib/typescript/src/events/index.d.ts.map +1 -1
- package/lib/typescript/src/interfaces/BrowseTree.d.ts +35 -5
- package/lib/typescript/src/interfaces/BrowseTree.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeTrackPlayer.ts +6 -0
- package/src/audio.ts +84 -8
- package/src/events/SleepTimerTriggered.ts +4 -0
- package/src/events/index.ts +4 -0
- package/src/interfaces/BrowseTree.ts +40 -5
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright (c) Double Symmetry GmbH
|
|
3
|
+
// Commercial use requires a license. See https://rntp.dev/pricing
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import CarPlay
|
|
7
|
+
import UIKit
|
|
8
|
+
|
|
9
|
+
@objc(RNTPCarPlaySceneDelegate)
|
|
10
|
+
class RNTPCarPlaySceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate {
|
|
11
|
+
|
|
12
|
+
private var interfaceController: CPInterfaceController?
|
|
13
|
+
private let imageCache = NSCache<NSString, UIImage>()
|
|
14
|
+
private var notificationObserver: NSObjectProtocol?
|
|
15
|
+
private var nowPlayingObserver: NSObjectProtocol?
|
|
16
|
+
/// All track list items keyed by mediaId, for updating isPlaying state.
|
|
17
|
+
private var listItemsByMediaId: [String: [CPListItem]] = [:]
|
|
18
|
+
|
|
19
|
+
// MARK: - CPTemplateApplicationSceneDelegate
|
|
20
|
+
|
|
21
|
+
func templateApplicationScene(
|
|
22
|
+
_ templateApplicationScene: CPTemplateApplicationScene,
|
|
23
|
+
didConnect interfaceController: CPInterfaceController
|
|
24
|
+
) {
|
|
25
|
+
self.interfaceController = interfaceController
|
|
26
|
+
rebuildTemplates()
|
|
27
|
+
|
|
28
|
+
notificationObserver = NotificationCenter.default.addObserver(
|
|
29
|
+
forName: BrowseTreeStore.didChangeNotification,
|
|
30
|
+
object: nil,
|
|
31
|
+
queue: .main
|
|
32
|
+
) { [weak self] _ in
|
|
33
|
+
self?.rebuildTemplates()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
nowPlayingObserver = NotificationCenter.default.addObserver(
|
|
37
|
+
forName: BrowseTreeStore.nowPlayingChangedNotification,
|
|
38
|
+
object: nil,
|
|
39
|
+
queue: .main
|
|
40
|
+
) { [weak self] _ in
|
|
41
|
+
self?.updateNowPlayingState()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
func templateApplicationScene(
|
|
46
|
+
_ templateApplicationScene: CPTemplateApplicationScene,
|
|
47
|
+
didDisconnect interfaceController: CPInterfaceController
|
|
48
|
+
) {
|
|
49
|
+
if let observer = notificationObserver {
|
|
50
|
+
NotificationCenter.default.removeObserver(observer)
|
|
51
|
+
notificationObserver = nil
|
|
52
|
+
}
|
|
53
|
+
if let observer = nowPlayingObserver {
|
|
54
|
+
NotificationCenter.default.removeObserver(observer)
|
|
55
|
+
nowPlayingObserver = nil
|
|
56
|
+
}
|
|
57
|
+
listItemsByMediaId = [:]
|
|
58
|
+
self.interfaceController = nil
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// MARK: - Template Construction
|
|
62
|
+
|
|
63
|
+
private func rebuildTemplates() {
|
|
64
|
+
guard let interfaceController = interfaceController else { return }
|
|
65
|
+
listItemsByMediaId = [:]
|
|
66
|
+
|
|
67
|
+
let allCategories = BrowseTreeStore.shared.categories
|
|
68
|
+
// Filter out empty categories
|
|
69
|
+
let categories = allCategories.filter { cat in
|
|
70
|
+
guard let items = cat["items"] as? [[String: Any]] else { return false }
|
|
71
|
+
return !items.isEmpty
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
guard !categories.isEmpty else {
|
|
75
|
+
interfaceController.setRootTemplate(CPNowPlayingTemplate.shared, animated: true, completion: nil)
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if categories.count == 1 {
|
|
80
|
+
let list = buildListTemplate(for: categories[0], categoryIndex: 0)
|
|
81
|
+
interfaceController.setRootTemplate(list, animated: true, completion: nil)
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let maxTabs = min(4, CPTabBarTemplate.maximumTabCount)
|
|
86
|
+
|
|
87
|
+
if categories.count <= maxTabs {
|
|
88
|
+
let tabs = categories.enumerated().map { (i, cat) in
|
|
89
|
+
buildListTemplate(for: cat, categoryIndex: i)
|
|
90
|
+
}
|
|
91
|
+
let tabBar = CPTabBarTemplate(templates: tabs)
|
|
92
|
+
interfaceController.setRootTemplate(tabBar, animated: true, completion: nil)
|
|
93
|
+
} else {
|
|
94
|
+
// First (maxTabs - 1) as direct tabs, rest under "More"
|
|
95
|
+
let directCount = maxTabs - 1
|
|
96
|
+
var tabs: [CPListTemplate] = []
|
|
97
|
+
for i in 0..<directCount {
|
|
98
|
+
tabs.append(buildListTemplate(for: categories[i], categoryIndex: i))
|
|
99
|
+
}
|
|
100
|
+
let moreTab = buildMoreTemplate(categories: Array(categories.dropFirst(directCount)),
|
|
101
|
+
startingCategoryIndex: directCount)
|
|
102
|
+
tabs.append(moreTab)
|
|
103
|
+
let tabBar = CPTabBarTemplate(templates: tabs)
|
|
104
|
+
interfaceController.setRootTemplate(tabBar, animated: true, completion: nil)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// MARK: - List Template Builders
|
|
109
|
+
|
|
110
|
+
private func buildListTemplate(for category: [String: Any], categoryIndex: Int) -> CPListTemplate {
|
|
111
|
+
let title = category["title"] as? String ?? "Untitled"
|
|
112
|
+
let items = category["items"] as? [[String: Any]] ?? []
|
|
113
|
+
|
|
114
|
+
let maxItems = CPListTemplate.maximumItemCount
|
|
115
|
+
let truncated = maxItems > 0 ? Array(items.prefix(maxItems)) : items
|
|
116
|
+
|
|
117
|
+
let listItems: [CPListItem] = truncated.enumerated().map { (itemIndex, item) in
|
|
118
|
+
buildListItem(item: item, parentItems: items, itemIndex: itemIndex)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let section = CPListSection(items: listItems)
|
|
122
|
+
let template = CPListTemplate(title: title, sections: [section])
|
|
123
|
+
template.tabTitle = title
|
|
124
|
+
return template
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private func buildMoreTemplate(categories: [[String: Any]], startingCategoryIndex: Int) -> CPListTemplate {
|
|
128
|
+
let listItems: [CPListItem] = categories.enumerated().map { (offset, cat) in
|
|
129
|
+
let catTitle = cat["title"] as? String ?? "Untitled"
|
|
130
|
+
let item = CPListItem(text: catTitle, detailText: nil)
|
|
131
|
+
let catIndex = startingCategoryIndex + offset
|
|
132
|
+
item.userInfo = ["type": "category", "categoryIndex": catIndex]
|
|
133
|
+
item.handler = { [weak self] _, completion in
|
|
134
|
+
self?.handleMoreCategorySelected(category: cat, categoryIndex: catIndex)
|
|
135
|
+
completion()
|
|
136
|
+
}
|
|
137
|
+
return item
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let section = CPListSection(items: listItems)
|
|
141
|
+
let template = CPListTemplate(title: "More", sections: [section])
|
|
142
|
+
template.tabTitle = "More"
|
|
143
|
+
template.tabImage = UIImage(systemName: "ellipsis.circle")
|
|
144
|
+
return template
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private func handleMoreCategorySelected(category: [String: Any], categoryIndex: Int) {
|
|
148
|
+
let detail = buildListTemplate(for: category, categoryIndex: categoryIndex)
|
|
149
|
+
interfaceController?.pushTemplate(detail, animated: true, completion: nil)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// MARK: - List Item Builder
|
|
153
|
+
|
|
154
|
+
private func buildListItem(item: [String: Any], parentItems: [[String: Any]], itemIndex: Int) -> CPListItem {
|
|
155
|
+
let title = item["title"] as? String ?? "Untitled"
|
|
156
|
+
let artist = item["artist"] as? String
|
|
157
|
+
let listItem = CPListItem(text: title, detailText: artist)
|
|
158
|
+
|
|
159
|
+
let hasUrl = item["url"] != nil
|
|
160
|
+
let children = item["children"] as? [[String: Any]]
|
|
161
|
+
let isBrowsable = children != nil && !hasUrl
|
|
162
|
+
|
|
163
|
+
if isBrowsable {
|
|
164
|
+
listItem.accessoryType = .disclosureIndicator
|
|
165
|
+
listItem.handler = { [weak self] _, completion in
|
|
166
|
+
self?.handleBrowsableSelected(item: item)
|
|
167
|
+
completion()
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
listItem.handler = { [weak self] _, completion in
|
|
171
|
+
self?.handlePlayableSelected(parentItems: parentItems, itemIndex: itemIndex)
|
|
172
|
+
completion()
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Track by mediaId for now-playing state updates
|
|
177
|
+
if let mediaId = item["mediaId"] as? String {
|
|
178
|
+
listItemsByMediaId[mediaId, default: []].append(listItem)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Mark as playing if this is the current item
|
|
182
|
+
if let mediaId = item["mediaId"] as? String,
|
|
183
|
+
mediaId == BrowseTreeStore.shared.currentMediaId {
|
|
184
|
+
listItem.isPlaying = true
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Load artwork async
|
|
188
|
+
if let artworkUrlString = item["artworkUrl"] as? String,
|
|
189
|
+
let artworkUrl = URL(string: artworkUrlString) {
|
|
190
|
+
loadImage(url: artworkUrl) { [weak listItem] image in
|
|
191
|
+
listItem?.setImage(image)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return listItem
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private func handleBrowsableSelected(item: [String: Any]) {
|
|
199
|
+
let title = item["title"] as? String ?? "Untitled"
|
|
200
|
+
let children = item["children"] as? [[String: Any]] ?? []
|
|
201
|
+
|
|
202
|
+
let maxItems = CPListTemplate.maximumItemCount
|
|
203
|
+
let truncated = maxItems > 0 ? Array(children.prefix(maxItems)) : children
|
|
204
|
+
|
|
205
|
+
let listItems = truncated.enumerated().map { (idx, child) in
|
|
206
|
+
buildListItem(item: child, parentItems: children, itemIndex: idx)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
let section = CPListSection(items: listItems)
|
|
210
|
+
let template = CPListTemplate(title: title, sections: [section])
|
|
211
|
+
interfaceController?.pushTemplate(template, animated: true, completion: nil)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// MARK: - Now Playing State
|
|
215
|
+
|
|
216
|
+
private func updateNowPlayingState() {
|
|
217
|
+
let currentMediaId = BrowseTreeStore.shared.currentMediaId
|
|
218
|
+
for (mediaId, items) in listItemsByMediaId {
|
|
219
|
+
let isPlaying = mediaId == currentMediaId
|
|
220
|
+
for item in items {
|
|
221
|
+
item.isPlaying = isPlaying
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// MARK: - Playback
|
|
227
|
+
|
|
228
|
+
private func handlePlayableSelected(parentItems: [[String: Any]], itemIndex: Int) {
|
|
229
|
+
guard let player = BrowseTreeStore.shared.player else { return }
|
|
230
|
+
|
|
231
|
+
// Collect only playable siblings (items with a url)
|
|
232
|
+
let playableItems = parentItems.filter { $0["url"] != nil }
|
|
233
|
+
let mediaItems = playableItems.compactMap { MediaItem(data: $0) }
|
|
234
|
+
guard !mediaItems.isEmpty else { return }
|
|
235
|
+
|
|
236
|
+
// Find the index of the selected item among playable siblings
|
|
237
|
+
let selectedMediaId = parentItems[itemIndex]["mediaId"] as? String
|
|
238
|
+
let playableIndex = playableItems.firstIndex { ($0["mediaId"] as? String) == selectedMediaId } ?? 0
|
|
239
|
+
|
|
240
|
+
player.clear()
|
|
241
|
+
player.add(items: mediaItems)
|
|
242
|
+
if playableIndex > 0 {
|
|
243
|
+
player.skipTo(index: playableIndex)
|
|
244
|
+
}
|
|
245
|
+
player.play()
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// MARK: - Artwork
|
|
249
|
+
|
|
250
|
+
private func loadImage(url: URL, completion: @escaping (UIImage) -> Void) {
|
|
251
|
+
let key = url.absoluteString as NSString
|
|
252
|
+
if let cached = imageCache.object(forKey: key) {
|
|
253
|
+
completion(cached)
|
|
254
|
+
return
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
|
|
258
|
+
guard let data = data, let image = UIImage(data: data) else { return }
|
|
259
|
+
|
|
260
|
+
// Scale to CarPlay max image size
|
|
261
|
+
let maxSize = CPListItem.maximumImageSize
|
|
262
|
+
let scaled = Self.scaleImage(image, to: maxSize)
|
|
263
|
+
|
|
264
|
+
self?.imageCache.setObject(scaled, forKey: key)
|
|
265
|
+
DispatchQueue.main.async {
|
|
266
|
+
completion(scaled)
|
|
267
|
+
}
|
|
268
|
+
}.resume()
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private static func scaleImage(_ image: UIImage, to maxSize: CGSize) -> UIImage {
|
|
272
|
+
let widthRatio = maxSize.width / image.size.width
|
|
273
|
+
let heightRatio = maxSize.height / image.size.height
|
|
274
|
+
let ratio = min(widthRatio, heightRatio, 1.0) // Don't upscale
|
|
275
|
+
if ratio >= 1.0 { return image }
|
|
276
|
+
|
|
277
|
+
let newSize = CGSize(width: image.size.width * ratio, height: image.size.height * ratio)
|
|
278
|
+
let renderer = UIGraphicsImageRenderer(size: newSize)
|
|
279
|
+
return renderer.image { _ in
|
|
280
|
+
image.draw(in: CGRect(origin: .zero, size: newSize))
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
package/ios/TrackPlayer.swift
CHANGED
|
@@ -22,6 +22,14 @@ class TrackPlayer: RCTEventEmitter {
|
|
|
22
22
|
private var progressSyncHttpUrl: String?
|
|
23
23
|
private var progressSyncHttpHeaders: [String: String]?
|
|
24
24
|
|
|
25
|
+
private var sleepTimerType: String? // "time" or "mediaItem"
|
|
26
|
+
private var sleepTimerRemainingSeconds: Double = 0
|
|
27
|
+
private var sleepTimerFadeOutSeconds: Double = 0
|
|
28
|
+
private var sleepTimerTargetIndex: Int?
|
|
29
|
+
private var sleepTimer: Timer?
|
|
30
|
+
private var sleepTimerPreFadeVolume: Float?
|
|
31
|
+
private var sleepTimerPreviousIndex: Int?
|
|
32
|
+
|
|
25
33
|
// MARK: - Initializers
|
|
26
34
|
|
|
27
35
|
override init() {
|
|
@@ -72,6 +80,7 @@ class TrackPlayer: RCTEventEmitter {
|
|
|
72
80
|
let handleNoisy = config["handleAudioBecomingNoisy"] as? Bool ?? true
|
|
73
81
|
player = AudioPlayer(handleAudioBecomingNoisy: handleNoisy, cache: cache)
|
|
74
82
|
bindPlayerCallbacks()
|
|
83
|
+
BrowseTreeStore.shared.player = player
|
|
75
84
|
lastEmittedStateString = nil
|
|
76
85
|
lastIsPlaying = false
|
|
77
86
|
|
|
@@ -224,6 +233,9 @@ class TrackPlayer: RCTEventEmitter {
|
|
|
224
233
|
@objc(clear)
|
|
225
234
|
func clear() {
|
|
226
235
|
player.clear()
|
|
236
|
+
if sleepTimerType == "mediaItem" {
|
|
237
|
+
cancelSleepTimerInternal(restoreVolume: false)
|
|
238
|
+
}
|
|
227
239
|
emitEvent(event: QueueChangedEvent())
|
|
228
240
|
}
|
|
229
241
|
|
|
@@ -399,10 +411,118 @@ class TrackPlayer: RCTEventEmitter {
|
|
|
399
411
|
player.shuffleEnabled = enabled
|
|
400
412
|
}
|
|
401
413
|
|
|
414
|
+
// MARK: - Sleep Timer
|
|
415
|
+
|
|
416
|
+
private func cancelSleepTimerInternal(restoreVolume: Bool) {
|
|
417
|
+
sleepTimer?.invalidate()
|
|
418
|
+
sleepTimer = nil
|
|
419
|
+
if restoreVolume, let preFadeVolume = sleepTimerPreFadeVolume {
|
|
420
|
+
player.volume = preFadeVolume
|
|
421
|
+
}
|
|
422
|
+
sleepTimerPreFadeVolume = nil
|
|
423
|
+
sleepTimerType = nil
|
|
424
|
+
sleepTimerRemainingSeconds = 0
|
|
425
|
+
sleepTimerFadeOutSeconds = 0
|
|
426
|
+
sleepTimerTargetIndex = nil
|
|
427
|
+
sleepTimerPreviousIndex = nil
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private func onSleepTimerTick() {
|
|
431
|
+
sleepTimerRemainingSeconds -= 1
|
|
432
|
+
|
|
433
|
+
// Handle fade-out (before zero-check so final tick sets volume to 0)
|
|
434
|
+
if sleepTimerFadeOutSeconds > 0 && sleepTimerRemainingSeconds < sleepTimerFadeOutSeconds {
|
|
435
|
+
if sleepTimerPreFadeVolume == nil {
|
|
436
|
+
sleepTimerPreFadeVolume = player.volume
|
|
437
|
+
}
|
|
438
|
+
let progress = max(0, sleepTimerRemainingSeconds) / sleepTimerFadeOutSeconds
|
|
439
|
+
player.volume = (sleepTimerPreFadeVolume ?? 1.0) * Float(progress)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if sleepTimerRemainingSeconds <= 0 {
|
|
443
|
+
sleepTimerRemainingSeconds = 0
|
|
444
|
+
player.pause()
|
|
445
|
+
emitEvent(event: SleepTimerTriggeredEvent(sleepType: "time"))
|
|
446
|
+
// Restore volume after pausing so next playback isn't muted
|
|
447
|
+
cancelSleepTimerInternal(restoreVolume: true)
|
|
448
|
+
return
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
private func startSleepCountdownTimer() {
|
|
453
|
+
sleepTimer?.invalidate()
|
|
454
|
+
let timer = Timer(timeInterval: 1.0, repeats: true) { [weak self] _ in
|
|
455
|
+
self?.onSleepTimerTick()
|
|
456
|
+
}
|
|
457
|
+
RunLoop.main.add(timer, forMode: .common)
|
|
458
|
+
sleepTimer = timer
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
private func pauseSleepCountdownTimer() {
|
|
462
|
+
sleepTimer?.invalidate()
|
|
463
|
+
sleepTimer = nil
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
@objc(sleepAfterTime:fadeOutSeconds:)
|
|
467
|
+
func sleepAfterTime(seconds: Double, fadeOutSeconds: Double) {
|
|
468
|
+
cancelSleepTimerInternal(restoreVolume: true)
|
|
469
|
+
sleepTimerType = "time"
|
|
470
|
+
sleepTimerRemainingSeconds = seconds
|
|
471
|
+
sleepTimerFadeOutSeconds = min(fadeOutSeconds, seconds)
|
|
472
|
+
|
|
473
|
+
if seconds <= 0 {
|
|
474
|
+
player.pause()
|
|
475
|
+
emitEvent(event: SleepTimerTriggeredEvent(sleepType: "time"))
|
|
476
|
+
cancelSleepTimerInternal(restoreVolume: true)
|
|
477
|
+
return
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
startSleepCountdownTimer()
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
@objc(sleepAfterMediaItemAtIndex:)
|
|
484
|
+
func sleepAfterMediaItemAtIndex(index: Double) {
|
|
485
|
+
cancelSleepTimerInternal(restoreVolume: true)
|
|
486
|
+
sleepTimerType = "mediaItem"
|
|
487
|
+
sleepTimerTargetIndex = Int(index)
|
|
488
|
+
sleepTimerPreviousIndex = player.currentIndex
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
@objc(getSleepTimer)
|
|
492
|
+
func getSleepTimer() -> [String: Any]? {
|
|
493
|
+
guard let type = sleepTimerType else { return nil }
|
|
494
|
+
if type == "time" {
|
|
495
|
+
return [
|
|
496
|
+
"type": "time",
|
|
497
|
+
"remainingSeconds": sleepTimerRemainingSeconds,
|
|
498
|
+
"fadeOutSeconds": sleepTimerFadeOutSeconds
|
|
499
|
+
]
|
|
500
|
+
} else {
|
|
501
|
+
return [
|
|
502
|
+
"type": "mediaItem",
|
|
503
|
+
"index": sleepTimerTargetIndex ?? 0
|
|
504
|
+
]
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
@objc(cancelSleepTimer)
|
|
509
|
+
func cancelSleepTimer() {
|
|
510
|
+
cancelSleepTimerInternal(restoreVolume: true)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// MARK: - Browse Tree
|
|
514
|
+
|
|
515
|
+
@objc(setBrowseTree:)
|
|
516
|
+
func setBrowseTree(_ categories: [[String: Any]]) {
|
|
517
|
+
BrowseTreeStore.shared.update(categories: categories)
|
|
518
|
+
}
|
|
519
|
+
|
|
402
520
|
// MARK: - Destroy
|
|
403
521
|
|
|
404
522
|
@objc(destroy)
|
|
405
523
|
func destroy() {
|
|
524
|
+
BrowseTreeStore.shared.clear()
|
|
525
|
+
cancelSleepTimerInternal(restoreVolume: false)
|
|
406
526
|
stopProgressSyncTimer(fireFinalTick: false)
|
|
407
527
|
let commandCenter = MPRemoteCommandCenter.shared()
|
|
408
528
|
commandCenter.togglePlayPauseCommand.removeTarget(nil)
|
|
@@ -459,7 +579,21 @@ class TrackPlayer: RCTEventEmitter {
|
|
|
459
579
|
}
|
|
460
580
|
|
|
461
581
|
func handleCurrentItemChanged(item: AudioItem?, index: Int) {
|
|
462
|
-
|
|
582
|
+
// Sleep timer: check if the target item just finished
|
|
583
|
+
if sleepTimerType == "mediaItem", let targetIndex = sleepTimerTargetIndex {
|
|
584
|
+
if sleepTimerPreviousIndex == targetIndex && index != targetIndex {
|
|
585
|
+
emitEvent(event: SleepTimerTriggeredEvent(sleepType: "mediaItem"))
|
|
586
|
+
cancelSleepTimerInternal(restoreVolume: false)
|
|
587
|
+
// Defer pause to next run loop — calling during transition gets overridden
|
|
588
|
+
DispatchQueue.main.async { [weak self] in
|
|
589
|
+
self?.player.pause()
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
sleepTimerPreviousIndex = index
|
|
594
|
+
let mediaItem = item as? MediaItem
|
|
595
|
+
let dict = mediaItem?.toDictionary()
|
|
596
|
+
BrowseTreeStore.shared.updateNowPlaying(mediaId: mediaItem?.mediaId)
|
|
463
597
|
emitEvent(event: MediaItemTransitionEvent(item: dict, index: index))
|
|
464
598
|
}
|
|
465
599
|
|
package/ios/TrackPlayerBridge.mm
CHANGED
|
@@ -71,6 +71,15 @@ RCT_EXTERN_METHOD(setCommands:(NSDictionary *)commands);
|
|
|
71
71
|
RCT_EXTERN_METHOD(setRepeatMode:(NSString *)mode);
|
|
72
72
|
RCT_EXTERN_METHOD(setShuffleEnabled:(BOOL)enabled);
|
|
73
73
|
|
|
74
|
+
// Browse Tree
|
|
75
|
+
RCT_EXTERN_METHOD(setBrowseTree:(NSArray *)categories);
|
|
76
|
+
|
|
77
|
+
// Sleep Timer
|
|
78
|
+
RCT_EXTERN_METHOD(sleepAfterTime:(double)seconds fadeOutSeconds:(double)fadeOutSeconds);
|
|
79
|
+
RCT_EXTERN_METHOD(sleepAfterMediaItemAtIndex:(double)index);
|
|
80
|
+
RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(getSleepTimer);
|
|
81
|
+
RCT_EXTERN_METHOD(cancelSleepTimer);
|
|
82
|
+
|
|
74
83
|
// Destroy
|
|
75
84
|
RCT_EXTERN_METHOD(destroy);
|
|
76
85
|
|
|
@@ -19,6 +19,7 @@ enum EmitEventType: String, CaseIterable {
|
|
|
19
19
|
case RemoteSkipForward = "event.remote-skip-forward"
|
|
20
20
|
case RemoteSkipBackward = "event.remote-skip-backward"
|
|
21
21
|
case PlaybackProgressUpdated = "event.playback-progress-updated"
|
|
22
|
+
case SleepTimerTriggered = "event.sleep-timer-triggered"
|
|
22
23
|
|
|
23
24
|
static func all() -> [String] {
|
|
24
25
|
return allCases.map { $0.rawValue }
|
|
@@ -155,3 +156,12 @@ struct PlaybackProgressUpdatedEvent: EmitEvent {
|
|
|
155
156
|
return ["mediaId": mediaId, "position": position, "duration": duration, "timestamp": timestamp]
|
|
156
157
|
}
|
|
157
158
|
}
|
|
159
|
+
|
|
160
|
+
struct SleepTimerTriggeredEvent: EmitEvent {
|
|
161
|
+
let sleepType: String // "time" or "mediaItem"
|
|
162
|
+
|
|
163
|
+
var eventType: EmitEventType { .SleepTimerTriggered }
|
|
164
|
+
var body: [String: Any] {
|
|
165
|
+
return ["type": sleepType]
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeTrackPlayer.ts"],"mappings":";;;;;;AAMA,IAAAA,YAAA,GAAAC,OAAA;AANA;AACA;AACA;AACA;AAHA,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeTrackPlayer.ts"],"mappings":";;;;;;AAMA,IAAAA,YAAA,GAAAC,OAAA;AANA;AACA;AACA;AACA;AAHA,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GA4FeC,gCAAmB,CAACC,YAAY,CAAO,aAAa,CAAC","ignoreList":[]}
|
package/lib/commonjs/audio.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.addEventListener = addEventListener;
|
|
7
7
|
exports.addMediaItem = addMediaItem;
|
|
8
8
|
exports.addMediaItems = addMediaItems;
|
|
9
|
+
exports.cancelSleepTimer = cancelSleepTimer;
|
|
9
10
|
exports.clear = clear;
|
|
10
11
|
exports.clearCache = clearCache;
|
|
11
12
|
exports.destroy = destroy;
|
|
@@ -16,6 +17,7 @@ exports.getPlaybackState = getPlaybackState;
|
|
|
16
17
|
exports.getProgress = getProgress;
|
|
17
18
|
exports.getQueue = getQueue;
|
|
18
19
|
exports.getRepeatMode = getRepeatMode;
|
|
20
|
+
exports.getSleepTimer = getSleepTimer;
|
|
19
21
|
exports.getVolume = getVolume;
|
|
20
22
|
exports.insertMediaItem = insertMediaItem;
|
|
21
23
|
exports.insertMediaItems = insertMediaItems;
|
|
@@ -43,6 +45,8 @@ exports.setupPlayer = setupPlayer;
|
|
|
43
45
|
exports.skipToIndex = skipToIndex;
|
|
44
46
|
exports.skipToNext = skipToNext;
|
|
45
47
|
exports.skipToPrevious = skipToPrevious;
|
|
48
|
+
exports.sleepAfterMediaItemAtIndex = sleepAfterMediaItemAtIndex;
|
|
49
|
+
exports.sleepAfterTime = sleepAfterTime;
|
|
46
50
|
exports.stop = stop;
|
|
47
51
|
exports.updateMetadata = updateMetadata;
|
|
48
52
|
exports.updateProgressSyncHeaders = updateProgressSyncHeaders;
|
|
@@ -399,26 +403,91 @@ function updateProgressSyncHeaders(headers) {
|
|
|
399
403
|
|
|
400
404
|
// ─── Browse Tree ─────────────────────────────────────
|
|
401
405
|
|
|
406
|
+
function resolveBrowseItem(item) {
|
|
407
|
+
return {
|
|
408
|
+
...item,
|
|
409
|
+
...(item.url != null ? {
|
|
410
|
+
url: resolveUrl(item.url)
|
|
411
|
+
} : {}),
|
|
412
|
+
...(item.artworkUrl != null ? {
|
|
413
|
+
artworkUrl: resolveUrl(item.artworkUrl)
|
|
414
|
+
} : {}),
|
|
415
|
+
...(item.children != null ? {
|
|
416
|
+
children: item.children.map(resolveBrowseItem)
|
|
417
|
+
} : {})
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
402
421
|
/**
|
|
403
|
-
* Set the media browse tree for Android Auto and
|
|
404
|
-
* Each category becomes a top-level browsable folder
|
|
422
|
+
* Set the media browse tree for Android Auto and CarPlay.
|
|
423
|
+
* Each category becomes a top-level browsable folder (Android Auto) or tab (CarPlay);
|
|
424
|
+
* its items can be playable tracks or browsable containers with children.
|
|
405
425
|
*
|
|
406
|
-
* When a user selects
|
|
407
|
-
* without JS intervention.
|
|
426
|
+
* When a user selects a playable item, the native player loads its siblings
|
|
427
|
+
* as the queue and starts playback without JS intervention.
|
|
408
428
|
*
|
|
409
429
|
* @remarks
|
|
410
|
-
* - On
|
|
430
|
+
* - On CarPlay, a maximum of 4 tabs are shown. If more than 4 categories are provided,
|
|
431
|
+
* the first 3 become tabs and the rest are grouped under a "More" tab.
|
|
432
|
+
* - Maximum nesting depth: 4 levels (matching CarPlay's navigation stack limit).
|
|
411
433
|
* - Call again to update the tree (e.g. after loading new content)
|
|
412
434
|
*/
|
|
413
435
|
function setBrowseTree(categories) {
|
|
414
|
-
if (_reactNative.Platform.OS !== 'android') return;
|
|
415
436
|
const resolved = categories.map(cat => ({
|
|
416
437
|
...cat,
|
|
417
|
-
items: cat.items.map(
|
|
438
|
+
items: cat.items.map(resolveBrowseItem)
|
|
418
439
|
}));
|
|
419
440
|
TrackPlayer.setBrowseTree(resolved);
|
|
420
441
|
}
|
|
421
442
|
|
|
443
|
+
// ─── Sleep Timer ─────────────────────────────────────
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Sets a countdown sleep timer. Playback pauses after `seconds` of wall clock time.
|
|
447
|
+
* The timer keeps counting even if playback is paused.
|
|
448
|
+
*
|
|
449
|
+
* @param seconds Duration in seconds before playback pauses.
|
|
450
|
+
* @param options.fadeOutSeconds Gradually reduce volume over the last N seconds.
|
|
451
|
+
* Clamped to `seconds` if it exceeds it. Defaults to 0 (no fade).
|
|
452
|
+
*
|
|
453
|
+
* @remarks Cancels any existing sleep timer (last one wins).
|
|
454
|
+
*/
|
|
455
|
+
function sleepAfterTime(seconds, options) {
|
|
456
|
+
TrackPlayer.sleepAfterTime(seconds, options?.fadeOutSeconds ?? 0);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Pauses playback after the media item at `index` finishes playing.
|
|
461
|
+
*
|
|
462
|
+
* @param index Queue index of the target media item. Defaults to the active item.
|
|
463
|
+
*
|
|
464
|
+
* @remarks
|
|
465
|
+
* - Cancels any existing sleep timer (last one wins).
|
|
466
|
+
* - Index is absolute — queue mutations after setting may shift which item it points to.
|
|
467
|
+
* - No fade-out support (no known time horizon).
|
|
468
|
+
*/
|
|
469
|
+
function sleepAfterMediaItemAtIndex(index) {
|
|
470
|
+
const resolvedIndex = index ?? getActiveMediaItemIndex() ?? 0;
|
|
471
|
+
TrackPlayer.sleepAfterMediaItemAtIndex(resolvedIndex);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Returns the current sleep timer state, or `null` if none is active.
|
|
476
|
+
*/
|
|
477
|
+
function getSleepTimer() {
|
|
478
|
+
const result = TrackPlayer.getSleepTimer();
|
|
479
|
+
if (result == null) return null;
|
|
480
|
+
return result;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Cancels the active sleep timer. If a volume fade is in progress,
|
|
485
|
+
* restores the original volume immediately.
|
|
486
|
+
*/
|
|
487
|
+
function cancelSleepTimer() {
|
|
488
|
+
TrackPlayer.cancelSleepTimer();
|
|
489
|
+
}
|
|
490
|
+
|
|
422
491
|
// ─── Destroy ─────────────────────────────────────────
|
|
423
492
|
|
|
424
493
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","_index","_index2","isTurboModuleEnabled","global","__turboModuleProxy","TrackPlayerModule","default","NativeModules","TrackPlayer","Proxy","get","Error","Platform","select","ios","NativeModule","OS","emitter","NativeEventEmitter","isPlayerSetup","resolveUrl","url","resolved","Image","resolveAssetSource","uri","resolveMediaItem","item","artworkUrl","normalizePlayerConfig","options","android","DEFAULT_ANDROID_PLAYER_CONFIG","cache","DEFAULT_CACHE_CONFIG","undefined","DEFAULT_PLAYER_CONFIG","contentType","handleAudioBecomingNoisy","progressSync","setupPlayer","registerBackgroundEventHandler","factory","AppRegistry","registerHeadlessTask","type","Event","QueueChanged","setImmediate","addEventListener","event","listener","addListener","play","pause","stop","seekTo","position","seekBy","offset","skipToNext","skipToPrevious","skipToIndex","index","retry","setPlaybackSpeed","speed","setVolume","volume","setMediaItem","mediaItem","setMediaItems","mediaItems","startIndex","map","addMediaItem","addMediaItems","insertMediaItem","insertMediaItems","removeMediaItem","removeMediaItems","fromIndex","toIndex","clear","clearCache","replaceMediaItem","moveMediaItem","updateMetadata","metadata","getPlaybackState","isPlaying","getProgress","result","duration","buffered","cached","getPlaybackSpeed","getVolume","getActiveMediaItem","getActiveMediaItemIndex","getQueue","getRepeatMode","isShuffleEnabled","setCommands","commands","setRepeatMode","mode","setShuffleEnabled","enabled","updateProgressSyncHeaders","headers","setBrowseTree","categories","cat","items","destroy"],"sourceRoot":"../../src","sources":["audio.ts"],"mappings":"
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_index","_index2","isTurboModuleEnabled","global","__turboModuleProxy","TrackPlayerModule","default","NativeModules","TrackPlayer","Proxy","get","Error","Platform","select","ios","NativeModule","OS","emitter","NativeEventEmitter","isPlayerSetup","resolveUrl","url","resolved","Image","resolveAssetSource","uri","resolveMediaItem","item","artworkUrl","normalizePlayerConfig","options","android","DEFAULT_ANDROID_PLAYER_CONFIG","cache","DEFAULT_CACHE_CONFIG","undefined","DEFAULT_PLAYER_CONFIG","contentType","handleAudioBecomingNoisy","progressSync","setupPlayer","registerBackgroundEventHandler","factory","AppRegistry","registerHeadlessTask","type","Event","QueueChanged","setImmediate","addEventListener","event","listener","addListener","play","pause","stop","seekTo","position","seekBy","offset","skipToNext","skipToPrevious","skipToIndex","index","retry","setPlaybackSpeed","speed","setVolume","volume","setMediaItem","mediaItem","setMediaItems","mediaItems","startIndex","map","addMediaItem","addMediaItems","insertMediaItem","insertMediaItems","removeMediaItem","removeMediaItems","fromIndex","toIndex","clear","clearCache","replaceMediaItem","moveMediaItem","updateMetadata","metadata","getPlaybackState","isPlaying","getProgress","result","duration","buffered","cached","getPlaybackSpeed","getVolume","getActiveMediaItem","getActiveMediaItemIndex","getQueue","getRepeatMode","isShuffleEnabled","setCommands","commands","setRepeatMode","mode","setShuffleEnabled","enabled","updateProgressSyncHeaders","headers","resolveBrowseItem","children","setBrowseTree","categories","cat","items","sleepAfterTime","seconds","fadeOutSeconds","sleepAfterMediaItemAtIndex","resolvedIndex","getSleepTimer","cancelSleepTimer","destroy"],"sourceRoot":"../../src","sources":["audio.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../../src","sources":["events/SleepTimerTriggered.ts"],"mappings":"","ignoreList":[]}
|