react-native-audio-browser 0.2.0-next.31 → 0.2.0-next.33

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 (44) hide show
  1. package/ios/AVPlayerEngine.swift +4 -8
  2. package/ios/Browser/BrowserConfig.swift +0 -5
  3. package/ios/Browser/BrowserError.swift +16 -0
  4. package/ios/Browser/BrowserManager.swift +36 -141
  5. package/ios/Browser/BrowserPathHelper.swift +25 -12
  6. package/ios/Browser/FavoriteSet.swift +46 -0
  7. package/ios/Browser/JsonModels.swift +172 -381
  8. package/ios/Browser/PageResolver.swift +16 -96
  9. package/ios/Browser/RequestLayer.swift +97 -2
  10. package/ios/Browser/RequestPipeline.swift +78 -227
  11. package/ios/Browser/SectionScope.swift +25 -0
  12. package/ios/Browser/SimpleRouter.swift +73 -144
  13. package/ios/Extension/SearchParams+Query.swift +28 -0
  14. package/ios/Extension/Track+Copying.swift +3 -1
  15. package/ios/Extension/Track+Identity.swift +7 -0
  16. package/ios/Http/HttpClient.swift +12 -30
  17. package/ios/HybridAudioBrowser+Browser.swift +5 -21
  18. package/ios/HybridAudioBrowser+Player.swift +3 -3
  19. package/ios/Model/NitroTypeStubs.swift +78 -0
  20. package/ios/Player/AudioSessionController.swift +2 -0
  21. package/ios/Player/ErrorStatus.swift +25 -2
  22. package/ios/Player/MediaLoader.swift +23 -71
  23. package/ios/Player/NowPlayingLines.swift +36 -0
  24. package/ios/Player/NowPlayingUpdater.swift +27 -85
  25. package/ios/Player/Player.swift +108 -261
  26. package/ios/Player/RetryLoop.swift +26 -0
  27. package/ios/Player/SleepTimerManager.swift +13 -15
  28. package/ios/Player/VolumeFader.swift +5 -0
  29. package/ios/Tests/BrowserPathHelperTests.swift +33 -0
  30. package/ios/Tests/ErrorStatusTests.swift +50 -0
  31. package/ios/Tests/FavoriteSetTests.swift +60 -0
  32. package/ios/Tests/JsonModelsTests.swift +30 -0
  33. package/ios/Tests/MediaLoaderTests.swift +26 -21
  34. package/ios/Tests/NowPlayingLinesTests.swift +43 -0
  35. package/ios/Tests/PlayerPolicyTests.swift +19 -3
  36. package/ios/Tests/PlayerTests.swift +81 -74
  37. package/ios/Tests/RequestLayerTests.swift +116 -0
  38. package/ios/Tests/RetryLoopTests.swift +35 -0
  39. package/ios/Tests/SearchParamsQueryTests.swift +48 -0
  40. package/ios/Tests/SectionScopeTests.swift +53 -0
  41. package/ios/Tests/SimpleRouterTests.swift +38 -3
  42. package/ios/Tests/SleepTimerManagerTests.swift +65 -41
  43. package/ios/Tests/Support/TestTypes.swift +2 -2
  44. package/package.json +1 -1
@@ -75,35 +75,17 @@ extension JsonArtwork {
75
75
  /// payload). `init(from:)` therefore never throws, and unknown enum values
76
76
  /// map to nil at `toNitro` time.
77
77
  struct JsonStyle: Codable, Equatable {
78
- let display: String?
79
- let gridWrap: Bool?
80
- let gridTile: String?
81
- let artworkRendering: String?
82
- let imageShape: String?
83
- let accessorySymbol: String?
84
- let cardTint: String?
85
- let cardImage: String?
86
-
87
- init(
88
- display: String? = nil,
89
- gridWrap: Bool? = nil,
90
- gridTile: String? = nil,
91
- artworkRendering: String? = nil,
92
- imageShape: String? = nil,
93
- accessorySymbol: String? = nil,
94
- cardTint: String? = nil,
95
- cardImage: String? = nil,
96
- ) {
97
- self.display = display
98
- self.gridWrap = gridWrap
99
- self.gridTile = gridTile
100
- self.artworkRendering = artworkRendering
101
- self.imageShape = imageShape
102
- self.accessorySymbol = accessorySymbol
103
- self.cardTint = cardTint
104
- self.cardImage = cardImage
105
- }
78
+ var display: String? = nil
79
+ var gridWrap: Bool? = nil
80
+ var gridTile: String? = nil
81
+ var artworkRendering: String? = nil
82
+ var imageShape: String? = nil
83
+ var accessorySymbol: String? = nil
84
+ var cardTint: String? = nil
85
+ var cardImage: String? = nil
86
+ }
106
87
 
88
+ extension JsonStyle {
107
89
  init(from decoder: Decoder) throws {
108
90
  // A non-object value (the retired `style: 'grid'` string) decodes as an
109
91
  // empty block rather than failing the parent.
@@ -132,61 +114,51 @@ extension JsonStyle {
132
114
  /// maps to nil, so "no declaration" has one shape on every platform
133
115
  /// (Android's lenient mapper makes the same collapse).
134
116
  func toTrackStyle() -> TrackStyle? {
135
- let display = display.flatMap { StyleDisplay(fromString: $0.lowercased()) }
136
- let artworkRendering = artworkRendering.flatMap { ArtworkRendering(fromString: $0.lowercased()) }
137
- let imageShape = imageShape.flatMap { ImageShape(fromString: $0.lowercased()) }
138
- // The 'none' sentinel is a legitimate value; only emptiness collapses.
139
- let accessorySymbol = accessorySymbol?.isEmpty == false ? accessorySymbol : nil
140
- let cardTint = cardTint?.isEmpty == false ? cardTint : nil
141
- let cardImage = cardImage.flatMap { CardImage(fromString: $0.lowercased()) }
142
- guard display != nil || artworkRendering != nil || imageShape != nil
143
- || accessorySymbol != nil || cardTint != nil || cardImage != nil
144
- else { return nil }
145
- return TrackStyle(
146
- display: display,
147
- artworkRendering: artworkRendering,
148
- imageShape: imageShape,
149
- accessorySymbol: accessorySymbol,
150
- cardTint: cardTint,
151
- cardImage: cardImage,
152
- )
117
+ let declarations = trackDeclarations
118
+ return Self.declaresAnything(declarations) ? declarations : nil
153
119
  }
154
120
 
155
121
  func toSectionStyle() -> SectionStyle? {
156
- let display = display.flatMap { StyleDisplay(fromString: $0.lowercased()) }
122
+ let declarations = trackDeclarations
157
123
  let gridTile = gridTile.flatMap { GridTile(fromString: $0.lowercased()) }
158
- let artworkRendering = artworkRendering.flatMap { ArtworkRendering(fromString: $0.lowercased()) }
159
- let imageShape = imageShape.flatMap { ImageShape(fromString: $0.lowercased()) }
160
- let accessorySymbol = accessorySymbol?.isEmpty == false ? accessorySymbol : nil
161
- let cardTint = cardTint?.isEmpty == false ? cardTint : nil
162
- let cardImage = cardImage.flatMap { CardImage(fromString: $0.lowercased()) }
163
- guard display != nil || artworkRendering != nil || gridWrap != nil
164
- || gridTile != nil || imageShape != nil || accessorySymbol != nil
165
- || cardTint != nil || cardImage != nil
166
- else { return nil }
124
+ guard Self.declaresAnything(declarations) || gridWrap != nil || gridTile != nil else { return nil }
167
125
  // Argument order is the generated init's (own properties before
168
126
  // inherited ones — Nitro flattens `extends` own-props-first).
169
127
  return SectionStyle(
170
128
  gridWrap: gridWrap,
171
129
  gridTile: gridTile,
172
- display: display,
173
- artworkRendering: artworkRendering,
174
- imageShape: imageShape,
175
- accessorySymbol: accessorySymbol,
176
- cardTint: cardTint,
177
- cardImage: cardImage,
130
+ display: declarations.display,
131
+ artworkRendering: declarations.artworkRendering,
132
+ imageShape: declarations.imageShape,
133
+ accessorySymbol: declarations.accessorySymbol,
134
+ cardTint: declarations.cardTint,
135
+ cardImage: declarations.cardImage,
136
+ )
137
+ }
138
+
139
+ /// The declarations a section shares with a track, each nil when absent or unknown.
140
+ private var trackDeclarations: TrackStyle {
141
+ TrackStyle(
142
+ display: display.flatMap { StyleDisplay(fromString: $0.lowercased()) },
143
+ artworkRendering: artworkRendering.flatMap { ArtworkRendering(fromString: $0.lowercased()) },
144
+ imageShape: imageShape.flatMap { ImageShape(fromString: $0.lowercased()) },
145
+ // The 'none' sentinel is a legitimate value; only emptiness collapses.
146
+ accessorySymbol: accessorySymbol?.isEmpty == false ? accessorySymbol : nil,
147
+ cardTint: cardTint?.isEmpty == false ? cardTint : nil,
148
+ cardImage: cardImage.flatMap { CardImage(fromString: $0.lowercased()) },
178
149
  )
179
150
  }
180
151
 
152
+ private static func declaresAnything(_ style: TrackStyle) -> Bool {
153
+ style.display != nil || style.artworkRendering != nil || style.imageShape != nil
154
+ || style.accessorySymbol != nil || style.cardTint != nil || style.cardImage != nil
155
+ }
156
+
181
157
  /// Snapshot a live track block back to its JSON model (for persistence).
182
158
  /// An all-nil block snapshots as no block — the decoders collapse it to
183
159
  /// "no declaration" anyway, so never persist the distinction.
184
160
  init?(_ style: TrackStyle?) {
185
- guard let style,
186
- style.display != nil || style.artworkRendering != nil
187
- || style.imageShape != nil || style.accessorySymbol != nil
188
- || style.cardTint != nil || style.cardImage != nil
189
- else { return nil }
161
+ guard let style, Self.declaresAnything(style) else { return nil }
190
162
  self.init(
191
163
  display: Self.string(style.display),
192
164
  artworkRendering: Self.string(style.artworkRendering),
@@ -234,22 +206,10 @@ extension JsonStyle {
234
206
  /// keys in payloads are simply unknown to these models and decode as
235
207
  /// ignored dead weight.
236
208
  struct JsonSection: Codable {
237
- let title: String?
238
- let style: JsonStyle?
239
- let path: String?
240
- let children: [JsonTrack]
241
-
242
- init(
243
- title: String? = nil,
244
- style: JsonStyle? = nil,
245
- path: String? = nil,
246
- children: [JsonTrack],
247
- ) {
248
- self.title = title
249
- self.style = style
250
- self.path = path
251
- self.children = children
252
- }
209
+ var title: String? = nil
210
+ var style: JsonStyle? = nil
211
+ var path: String? = nil
212
+ var children: [JsonTrack]
253
213
  }
254
214
 
255
215
  /// JSON model for per-track HTTP request configuration.
@@ -258,324 +218,155 @@ struct JsonTrackRequest: Codable {
258
218
  let headers: [String: String]?
259
219
  let query: [String: String]?
260
220
 
261
- #if canImport(NitroModules)
262
- func toNitro() -> TrackRequest {
263
- TrackRequest(userAgent: userAgent, headers: headers, query: query)
264
- }
265
- #endif
221
+ func toNitro() -> TrackRequest {
222
+ TrackRequest(userAgent: userAgent, headers: headers, query: query)
223
+ }
266
224
  }
267
225
 
268
226
  /// JSON model for resolved track (container with children).
269
227
  struct JsonResolvedTrack: Codable {
270
- let id: String?
271
- let path: String
272
- let title: String
273
- let subtitle: String?
274
- let artwork: JsonArtwork?
275
- let artist: String?
276
- let albumPath: String?
277
- let album: String?
278
- let description: String?
279
- let genre: String?
280
- let duration: Double?
281
- let sections: [JsonSection]?
282
- let children: [JsonTrack]?
283
- let src: String?
284
- let style: JsonStyle?
285
- let disabled: Bool?
286
- let live: Bool?
287
- let icyCharset: String?
288
- let carPlaySiriListButton: String?
289
-
290
- init(
291
- id: String? = nil,
292
- path: String,
293
- title: String,
294
- subtitle: String? = nil,
295
- artwork: JsonArtwork? = nil,
296
- artist: String? = nil,
297
- albumPath: String? = nil,
298
- album: String? = nil,
299
- description: String? = nil,
300
- genre: String? = nil,
301
- duration: Double? = nil,
302
- sections: [JsonSection]? = nil,
303
- children: [JsonTrack]? = nil,
304
- src: String? = nil,
305
- style: JsonStyle? = nil,
306
- disabled: Bool? = nil,
307
- live: Bool? = nil,
308
- icyCharset: String? = nil,
309
- carPlaySiriListButton: String? = nil,
310
- ) {
311
- self.path = path
312
- self.title = title
313
- self.subtitle = subtitle
314
- self.artwork = artwork
315
- self.artist = artist
316
- self.albumPath = albumPath
317
- self.album = album
318
- self.description = description
319
- self.genre = genre
320
- self.duration = duration
321
- self.sections = sections
322
- self.children = children
323
- self.src = src
324
- self.style = style
325
- self.disabled = disabled
326
- self.live = live
327
- self.icyCharset = icyCharset
328
- self.carPlaySiriListButton = carPlaySiriListButton
329
- self.id = id
330
- }
228
+ var id: String? = nil
229
+ var path: String
230
+ var title: String
231
+ var subtitle: String? = nil
232
+ var artwork: JsonArtwork? = nil
233
+ var artist: String? = nil
234
+ var albumPath: String? = nil
235
+ var album: String? = nil
236
+ var description: String? = nil
237
+ var genre: String? = nil
238
+ var duration: Double? = nil
239
+ var sections: [JsonSection]? = nil
240
+ var children: [JsonTrack]? = nil
241
+ var src: String? = nil
242
+ var style: JsonStyle? = nil
243
+ var disabled: Bool? = nil
244
+ var live: Bool? = nil
245
+ var icyCharset: String? = nil
246
+ var carPlaySiriListButton: String? = nil
331
247
  }
332
248
 
333
249
  /// JSON model for individual tracks.
334
250
  struct JsonTrack: Codable {
335
- let id: String?
336
- let path: String?
337
- let title: String
338
- let subtitle: String?
339
- let artwork: JsonArtwork?
340
- let artist: String?
341
- let albumPath: String?
342
- let album: String?
343
- let description: String?
344
- let genre: String?
345
- let duration: Double?
346
- let src: String?
347
- let request: JsonTrackRequest?
348
- let style: JsonStyle?
349
- let disabled: Bool?
350
- let live: Bool?
351
- let icyCharset: String?
352
-
353
- init(
354
- id: String? = nil,
355
- path: String? = nil,
356
- title: String,
357
- subtitle: String? = nil,
358
- artwork: JsonArtwork? = nil,
359
- artist: String? = nil,
360
- albumPath: String? = nil,
361
- album: String? = nil,
362
- description: String? = nil,
363
- genre: String? = nil,
364
- duration: Double? = nil,
365
- src: String? = nil,
366
- request: JsonTrackRequest? = nil,
367
- style: JsonStyle? = nil,
368
- disabled: Bool? = nil,
369
- live: Bool? = nil,
370
- icyCharset: String? = nil,
371
- ) {
372
- self.path = path
373
- self.title = title
374
- self.subtitle = subtitle
375
- self.artwork = artwork
376
- self.artist = artist
377
- self.albumPath = albumPath
378
- self.album = album
379
- self.description = description
380
- self.genre = genre
381
- self.duration = duration
382
- self.src = src
383
- self.request = request
384
- self.style = style
385
- self.disabled = disabled
386
- self.live = live
387
- self.icyCharset = icyCharset
388
- self.id = id
389
- }
251
+ var id: String? = nil
252
+ var path: String? = nil
253
+ var title: String
254
+ var subtitle: String? = nil
255
+ var artwork: JsonArtwork? = nil
256
+ var artist: String? = nil
257
+ var albumPath: String? = nil
258
+ var album: String? = nil
259
+ var description: String? = nil
260
+ var genre: String? = nil
261
+ var duration: Double? = nil
262
+ var src: String? = nil
263
+ var request: JsonTrackRequest? = nil
264
+ var style: JsonStyle? = nil
265
+ var disabled: Bool? = nil
266
+ var live: Bool? = nil
267
+ var icyCharset: String? = nil
390
268
  }
391
269
 
392
270
  // MARK: - Snapshot live Nitro types back to JSON models (for persistence)
393
271
 
394
- #if canImport(NitroModules)
395
-
396
- extension JsonTrackRequest {
397
- /// Snapshot a live TrackRequest back to its JSON model.
398
- init(from request: TrackRequest) {
399
- self.init(userAgent: request.userAgent, headers: request.headers, query: request.query)
400
- }
401
- }
402
-
403
- extension JsonTrack {
404
- /// Snapshot the persistable subset of a live Track (inverse of `toNitro()`).
405
- /// The track's own declared style block and `disabled` persist (ADR 0011);
406
- /// section/page-inherited values are never stamped onto tracks and
407
- /// re-resolve at render, exactly as they do live.
408
- init(from track: Track) {
409
- self.init(
410
- id: track.id,
411
- path: track.path,
412
- title: track.title,
413
- subtitle: track.subtitle,
414
- artwork: JsonArtwork(track.artwork),
415
- artist: track.artist,
416
- albumPath: track.albumPath,
417
- album: track.album,
418
- description: track.description,
419
- genre: track.genre,
420
- duration: track.duration,
421
- src: track.src,
422
- request: track.request.map(JsonTrackRequest.init(from:)),
423
- style: JsonStyle(track.style),
424
- disabled: track.disabled,
425
- live: track.live,
426
- icyCharset: track.icyCharset,
427
- )
428
- }
429
- }
430
-
431
- #else
432
-
433
- extension JsonTrackRequest {
434
- /// Snapshot a live TrackRequest back to its JSON model (SPM test-target stub).
435
- init(from request: TrackRequest) {
436
- self.init(userAgent: request.userAgent, headers: request.headers, query: request.query)
437
- }
272
+ extension JsonTrackRequest {
273
+ /// Snapshot a live TrackRequest back to its JSON model.
274
+ init(from request: TrackRequest) {
275
+ self.init(userAgent: request.userAgent, headers: request.headers, query: request.query)
438
276
  }
277
+ }
439
278
 
440
- extension JsonTrack {
441
- /// Snapshot the persistable subset of a live Track (inverse of `toNitro()`).
442
- /// SPM test-target stub — only fields present on the minimal `Track` stub.
443
- init(from track: Track) {
444
- self.init(
445
- id: track.id,
446
- path: track.path,
447
- title: track.title,
448
- artwork: JsonArtwork(track.artwork),
449
- artist: track.artist,
450
- albumPath: track.albumPath,
451
- album: track.album,
452
- src: track.src,
453
- request: track.request.map(JsonTrackRequest.init(from:)),
454
- style: JsonStyle(track.style),
455
- disabled: track.disabled,
456
- live: track.live,
457
- icyCharset: track.icyCharset,
458
- )
459
- }
279
+ extension JsonTrack {
280
+ /// Snapshot the persistable subset of a live Track (inverse of `toNitro()`).
281
+ /// The track's own declared style block and `disabled` persist (ADR 0011);
282
+ /// section/page-inherited values are never stamped onto tracks and
283
+ /// re-resolve at render, exactly as they do live.
284
+ init(from track: Track) {
285
+ self.init(
286
+ id: track.id,
287
+ path: track.path,
288
+ title: track.title,
289
+ subtitle: track.subtitle,
290
+ artwork: JsonArtwork(track.artwork),
291
+ artist: track.artist,
292
+ albumPath: track.albumPath,
293
+ album: track.album,
294
+ description: track.description,
295
+ genre: track.genre,
296
+ duration: track.duration,
297
+ src: track.src,
298
+ request: track.request.map(JsonTrackRequest.init(from:)),
299
+ style: JsonStyle(track.style),
300
+ disabled: track.disabled,
301
+ live: track.live,
302
+ icyCharset: track.icyCharset,
303
+ )
460
304
  }
461
-
462
- #endif
305
+ }
463
306
 
464
307
  // MARK: - Convert JSON models to Nitro types
465
308
 
466
- #if canImport(NitroModules)
467
-
468
- extension JsonSection {
469
- func toNitro() -> Section {
470
- Section(
471
- title: title,
472
- style: style?.toSectionStyle(),
473
- path: path,
474
- children: children.map { $0.toNitro() },
475
- )
476
- }
477
- }
478
-
479
- extension JsonResolvedTrack {
480
- func toNitro() -> ResolvedTrack {
481
- ResolvedTrack(
482
- path: path,
483
- style: style?.toSectionStyle(),
484
- sections: sections?.map { $0.toNitro() },
485
- children: children?.map { $0.toNitro() },
486
- carPlaySiriListButton: carPlaySiriListButton.flatMap { CarPlaySiriListButtonPosition(fromString: $0) },
487
- id: id,
488
- src: src,
489
- artwork: artwork?.toNitro(),
490
- artworkSource: nil, request: nil,
491
- title: title,
492
- subtitle: subtitle,
493
- artist: artist,
494
- albumPath: albumPath,
495
- album: album,
496
- description: description,
497
- genre: genre,
498
- duration: duration,
499
- disabled: disabled,
500
- favorited: nil,
501
- live: live,
502
- icyCharset: icyCharset,
503
- )
504
- }
505
- }
506
-
507
- extension JsonTrack {
508
- func toNitro() -> Track {
509
- Track(
510
- id: id,
511
- path: path,
512
- src: src,
513
- artwork: artwork?.toNitro(),
514
- artworkSource: nil,
515
- request: request?.toNitro(),
516
- title: title,
517
- subtitle: subtitle,
518
- artist: artist,
519
- albumPath: albumPath,
520
- album: album,
521
- description: description,
522
- genre: genre,
523
- duration: duration,
524
- style: style?.toTrackStyle(),
525
- disabled: disabled,
526
- favorited: nil,
527
- live: live,
528
- icyCharset: icyCharset,
529
- )
530
- }
531
- }
532
-
533
- #else
534
-
535
- // Test-only path: construct minimal stubs for SPM test builds.
536
- extension JsonTrack {
537
- func toNitro() -> Track {
538
- Track(
539
- id: id ?? "",
540
- path: path,
541
- src: src,
542
- artwork: artwork?.toNitro(),
543
- request: request.map { TrackRequest(userAgent: $0.userAgent, headers: $0.headers, query: $0.query) },
544
- title: title,
545
- artist: artist,
546
- albumPath: albumPath,
547
- album: album,
548
- style: style?.toTrackStyle(),
549
- disabled: disabled,
550
- live: live,
551
- icyCharset: icyCharset,
552
- )
553
- }
309
+ extension JsonSection {
310
+ func toNitro() -> Section {
311
+ Section(
312
+ title: title,
313
+ style: style?.toSectionStyle(),
314
+ path: path,
315
+ children: children.map { $0.toNitro() },
316
+ )
554
317
  }
318
+ }
555
319
 
556
- extension JsonSection {
557
- func toNitro() -> Section {
558
- Section(
559
- title: title,
560
- style: style?.toSectionStyle(),
561
- path: path,
562
- children: children.map { $0.toNitro() },
563
- )
564
- }
320
+ extension JsonResolvedTrack {
321
+ func toNitro() -> ResolvedTrack {
322
+ ResolvedTrack(
323
+ path: path,
324
+ style: style?.toSectionStyle(),
325
+ sections: sections?.map { $0.toNitro() },
326
+ children: children?.map { $0.toNitro() },
327
+ carPlaySiriListButton: carPlaySiriListButton.flatMap { CarPlaySiriListButtonPosition(fromString: $0) },
328
+ id: id,
329
+ src: src,
330
+ artwork: artwork?.toNitro(),
331
+ artworkSource: nil, request: nil,
332
+ title: title,
333
+ subtitle: subtitle,
334
+ artist: artist,
335
+ albumPath: albumPath,
336
+ album: album,
337
+ description: description,
338
+ genre: genre,
339
+ duration: duration,
340
+ disabled: disabled,
341
+ favorited: nil,
342
+ live: live,
343
+ icyCharset: icyCharset,
344
+ )
565
345
  }
346
+ }
566
347
 
567
- extension JsonResolvedTrack {
568
- func toNitro() -> ResolvedTrack {
569
- ResolvedTrack(
570
- path: path,
571
- style: style?.toSectionStyle(),
572
- sections: sections?.map { $0.toNitro() },
573
- children: children?.map { $0.toNitro() },
574
- artwork: artwork?.toNitro(),
575
- title: title,
576
- disabled: disabled,
577
- )
578
- }
348
+ extension JsonTrack {
349
+ func toNitro() -> Track {
350
+ Track(
351
+ id: id,
352
+ path: path,
353
+ src: src,
354
+ artwork: artwork?.toNitro(),
355
+ artworkSource: nil,
356
+ request: request?.toNitro(),
357
+ title: title,
358
+ subtitle: subtitle,
359
+ artist: artist,
360
+ albumPath: albumPath,
361
+ album: album,
362
+ description: description,
363
+ genre: genre,
364
+ duration: duration,
365
+ style: style?.toTrackStyle(),
366
+ disabled: disabled,
367
+ favorited: nil,
368
+ live: live,
369
+ icyCharset: icyCharset,
370
+ )
579
371
  }
580
-
581
- #endif
372
+ }