@neoskola/auto-play 0.3.3 → 0.3.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.
|
@@ -19,6 +19,9 @@ class NowPlayingTemplate: AutoPlayTemplate {
|
|
|
19
19
|
private var didFinishObserver: NSObjectProtocol?
|
|
20
20
|
private var statusObservation: NSKeyValueObservation?
|
|
21
21
|
private var completionFired = false
|
|
22
|
+
private var downloadTask: URLSessionDownloadTask?
|
|
23
|
+
private var localAudioFileURL: URL?
|
|
24
|
+
private var pendingStartFrom: Double = 0
|
|
22
25
|
|
|
23
26
|
var autoDismissMs: Double? {
|
|
24
27
|
return config.autoDismissMs
|
|
@@ -60,6 +63,7 @@ class NowPlayingTemplate: AutoPlayTemplate {
|
|
|
60
63
|
cleanupPlayer()
|
|
61
64
|
completionFired = false
|
|
62
65
|
lastReportedSecond = Int(startFrom)
|
|
66
|
+
pendingStartFrom = startFrom
|
|
63
67
|
|
|
64
68
|
guard let audioURL = URL(string: url) else {
|
|
65
69
|
print("[NowPlayingTemplate] Invalid audio URL: \(url)")
|
|
@@ -71,8 +75,50 @@ class NowPlayingTemplate: AutoPlayTemplate {
|
|
|
71
75
|
updateNowPlayingInfo()
|
|
72
76
|
MPNowPlayingInfoCenter.default().playbackState = .playing
|
|
73
77
|
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
print("[NowPlayingTemplate] Downloading audio: \(url)")
|
|
79
|
+
|
|
80
|
+
// Download file first, then play from local — R2/Cloudflare CDN streaming
|
|
81
|
+
// causes FigFilePlayer errors with AVPlayer, local playback is reliable
|
|
82
|
+
downloadTask = URLSession.shared.downloadTask(with: audioURL) { [weak self] tempURL, response, error in
|
|
83
|
+
guard let self = self else { return }
|
|
84
|
+
|
|
85
|
+
if let error = error {
|
|
86
|
+
print("[NowPlayingTemplate] Download failed: \(error.localizedDescription)")
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
guard let tempURL = tempURL else {
|
|
91
|
+
print("[NowPlayingTemplate] Download returned no file")
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Move to a persistent temp location (URLSession deletes the file after this block)
|
|
96
|
+
let localURL = FileManager.default.temporaryDirectory
|
|
97
|
+
.appendingPathComponent("carplay_audio_\(UUID().uuidString).mp3")
|
|
98
|
+
|
|
99
|
+
do {
|
|
100
|
+
if let oldFile = self.localAudioFileURL {
|
|
101
|
+
try? FileManager.default.removeItem(at: oldFile)
|
|
102
|
+
}
|
|
103
|
+
try FileManager.default.moveItem(at: tempURL, to: localURL)
|
|
104
|
+
self.localAudioFileURL = localURL
|
|
105
|
+
print("[NowPlayingTemplate] Audio downloaded to: \(localURL.lastPathComponent)")
|
|
106
|
+
} catch {
|
|
107
|
+
print("[NowPlayingTemplate] Failed to move downloaded file: \(error)")
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
DispatchQueue.main.async { [weak self] in
|
|
112
|
+
self?.startPlaybackFromLocalFile(localURL: localURL, startFrom: self?.pendingStartFrom ?? 0)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
downloadTask?.resume()
|
|
116
|
+
|
|
117
|
+
return true
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private func startPlaybackFromLocalFile(localURL: URL, startFrom: Double) {
|
|
121
|
+
let asset = AVURLAsset(url: localURL)
|
|
76
122
|
playerItem = AVPlayerItem(asset: asset)
|
|
77
123
|
|
|
78
124
|
// KVO: detect duration as soon as asset loads (critical for progress bar)
|
|
@@ -96,14 +142,11 @@ class NowPlayingTemplate: AutoPlayTemplate {
|
|
|
96
142
|
|
|
97
143
|
player = AVPlayer(playerItem: playerItem)
|
|
98
144
|
|
|
99
|
-
// Seek to start position
|
|
100
145
|
if startFrom > 0 {
|
|
101
146
|
let time = CMTime(seconds: startFrom, preferredTimescale: 600)
|
|
102
147
|
player?.seek(to: time)
|
|
103
148
|
}
|
|
104
149
|
|
|
105
|
-
player?.play()
|
|
106
|
-
|
|
107
150
|
// Periodic time observer (every 1 second) for MPNowPlayingInfoCenter updates
|
|
108
151
|
let interval = CMTime(seconds: 1.0, preferredTimescale: 600)
|
|
109
152
|
timeObserver = player?.addPeriodicTimeObserver(
|
|
@@ -113,14 +156,6 @@ class NowPlayingTemplate: AutoPlayTemplate {
|
|
|
113
156
|
self?.handleTimeUpdate(time: time)
|
|
114
157
|
}
|
|
115
158
|
|
|
116
|
-
// Progress report timer (every 30 seconds) — calls JS callback for backend reporting
|
|
117
|
-
progressReportTimer = Timer.scheduledTimer(
|
|
118
|
-
withTimeInterval: 30.0,
|
|
119
|
-
repeats: true
|
|
120
|
-
) { [weak self] _ in
|
|
121
|
-
self?.reportProgress()
|
|
122
|
-
}
|
|
123
|
-
|
|
124
159
|
// Playback finished notification
|
|
125
160
|
didFinishObserver = NotificationCenter.default.addObserver(
|
|
126
161
|
forName: .AVPlayerItemDidPlayToEndTime,
|
|
@@ -130,8 +165,18 @@ class NowPlayingTemplate: AutoPlayTemplate {
|
|
|
130
165
|
self?.handlePlaybackFinished()
|
|
131
166
|
}
|
|
132
167
|
|
|
133
|
-
|
|
134
|
-
|
|
168
|
+
// Progress report timer (every 30 seconds) — calls JS callback for backend reporting
|
|
169
|
+
progressReportTimer = Timer.scheduledTimer(
|
|
170
|
+
withTimeInterval: 30.0,
|
|
171
|
+
repeats: true
|
|
172
|
+
) { [weak self] _ in
|
|
173
|
+
self?.reportProgress()
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
player?.play()
|
|
177
|
+
MPNowPlayingInfoCenter.default().playbackState = .playing
|
|
178
|
+
|
|
179
|
+
print("[NowPlayingTemplate] Playback started from local file")
|
|
135
180
|
}
|
|
136
181
|
|
|
137
182
|
private func handleTimeUpdate(time: CMTime) {
|
|
@@ -230,6 +275,8 @@ class NowPlayingTemplate: AutoPlayTemplate {
|
|
|
230
275
|
}
|
|
231
276
|
|
|
232
277
|
private func cleanupPlayer() {
|
|
278
|
+
downloadTask?.cancel()
|
|
279
|
+
downloadTask = nil
|
|
233
280
|
statusObservation?.invalidate()
|
|
234
281
|
statusObservation = nil
|
|
235
282
|
if let timeObserver = timeObserver {
|
|
@@ -245,6 +292,10 @@ class NowPlayingTemplate: AutoPlayTemplate {
|
|
|
245
292
|
player?.pause()
|
|
246
293
|
player = nil
|
|
247
294
|
playerItem = nil
|
|
295
|
+
if let localFile = localAudioFileURL {
|
|
296
|
+
try? FileManager.default.removeItem(at: localFile)
|
|
297
|
+
localAudioFileURL = nil
|
|
298
|
+
}
|
|
248
299
|
}
|
|
249
300
|
|
|
250
301
|
// MARK: - CarPlay UI
|