@capgo/capacitor-video-player 8.2.1 → 8.2.2

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.
@@ -156,6 +156,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
156
156
  private Uri uri = null;
157
157
  private Uri sturi = null;
158
158
  private List<Uri> subtitleUris = new ArrayList<>();
159
+ private List<String> subtitleLanguages = new ArrayList<>();
159
160
  private ProgressBar Pbar;
160
161
  private View view;
161
162
  private ImageButton closeBtn;
@@ -178,7 +179,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
178
179
  private String stBackColor = "";
179
180
  private Integer stFontSize = 16;
180
181
  private boolean isInPictureInPictureMode = false;
181
- private TrackSelector trackSelector;
182
+ private DefaultTrackSelector trackSelector;
182
183
  // Current playback position (in milliseconds).
183
184
  private int mCurrentPosition;
184
185
  private int mDuration;
@@ -400,10 +401,12 @@ public class FullscreenExoPlayerFragment extends Fragment {
400
401
  if (!isInternal) {
401
402
  uri = Uri.parse(videoPath);
402
403
  subtitleUris = new ArrayList<>();
404
+ subtitleLanguages = new ArrayList<>();
403
405
  if (subtitleTracks != null) {
404
406
  for (VideoSubtitleTrack track : subtitleTracks) {
405
407
  if (track != null && track.url != null && !track.url.isEmpty()) {
406
408
  subtitleUris.add(Uri.parse(track.url));
409
+ subtitleLanguages.add(track.language != null ? track.language : "");
407
410
  }
408
411
  }
409
412
  }
@@ -411,6 +414,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
411
414
  if (sturi == null && subTitle != null && !subTitle.isEmpty()) {
412
415
  sturi = Uri.parse(subTitle);
413
416
  subtitleUris.add(sturi);
417
+ subtitleLanguages.add(language != null ? language : "en");
414
418
  }
415
419
 
416
420
  stForeColor = subTitleOptions != null && subTitleOptions.has("foregroundColor")
@@ -892,6 +896,12 @@ public class FullscreenExoPlayerFragment extends Fragment {
892
896
  DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build();
893
897
  ExoTrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory();
894
898
  trackSelector = new DefaultTrackSelector(context, videoTrackSelectionFactory);
899
+ if (!subtitleUris.isEmpty()) {
900
+ String preferred = languageForTrack(0);
901
+ trackSelector.setParameters(
902
+ trackSelector.buildUponParameters().setPreferredTextLanguage(preferred).setSelectUndeterminedTextLanguage(true)
903
+ );
904
+ }
895
905
  LoadControl loadControl = new DefaultLoadControl();
896
906
  player = new ExoPlayer.Builder(context)
897
907
  .setSeekBackIncrementMs(10000)
@@ -946,11 +956,10 @@ public class FullscreenExoPlayerFragment extends Fragment {
946
956
 
947
957
  private void updateSubtitleButtonVisibility(Tracks tracks) {
948
958
  if (styledPlayerView == null) return;
949
- if (sturi != null) {
950
- styledPlayerView.setShowSubtitleButton(true);
951
- return;
952
- }
953
- styledPlayerView.setShowSubtitleButton(hasSupportedTextTrack(tracks));
959
+ boolean hasSidecar = !subtitleUris.isEmpty() || sturi != null;
960
+ boolean hasText = hasSidecar || hasSupportedTextTrack(tracks);
961
+ // CC button opens ExoPlayer's text-track picker when multiple languages exist.
962
+ styledPlayerView.setShowSubtitleButton(hasText);
954
963
  }
955
964
 
956
965
  private boolean hasSupportedTextTrack(Tracks tracks) {
@@ -1622,8 +1631,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
1622
1631
  }
1623
1632
 
1624
1633
  private String languageForTrack(int index) {
1625
- if (subtitleTracks != null && index >= 0 && index < subtitleTracks.size()) {
1626
- String trackLanguage = subtitleTracks.get(index).language;
1634
+ // subtitleLanguages is built in lockstep with subtitleUris — never re-index raw subtitleTracks.
1635
+ if (index >= 0 && index < subtitleLanguages.size()) {
1636
+ String trackLanguage = subtitleLanguages.get(index);
1627
1637
  if (trackLanguage != null && !trackLanguage.isEmpty()) {
1628
1638
  return trackLanguage;
1629
1639
  }
@@ -46,7 +46,7 @@ import org.json.JSONObject;
46
46
  )
47
47
  public class VideoPlayerPlugin extends Plugin {
48
48
 
49
- private final String pluginVersion = "8.2.1";
49
+ private final String pluginVersion = "8.2.2";
50
50
 
51
51
  // Permission alias constants
52
52
  private static final String PERMISSION_DENIED_ERROR = "Unable to access media videos, user denied permission request";
@@ -100,8 +100,15 @@ class FullscreenVideoPlayer: NSObject {
100
100
  return
101
101
  }
102
102
 
103
- if HLSVideoAssetFactory.isHLSStream(url) {
104
- let asset = makeVideoAsset(url: url, subtitleTracks: subtitleTracks)
103
+ // Prefer the resource-loader path for any video with sidecar subtitles.
104
+ // That exposes selectable tracks in AVPlayerViewController (composition does not).
105
+ let assetResult = HLSVideoAssetFactory.makeAsset(
106
+ videoURL: url,
107
+ subtitleTracks: subtitleTracks
108
+ )
109
+ hlsResourceLoader = assetResult.resourceLoader
110
+ if assetResult.resourceLoader != nil {
111
+ let asset = applyFairPlayIfNeeded(to: assetResult.asset)
105
112
  configurePlayer(with: AVPlayerItem(asset: asset))
106
113
  completion()
107
114
  return
@@ -126,8 +133,10 @@ class FullscreenVideoPlayer: NSObject {
126
133
  subtitleTracks: subtitleTracks
127
134
  )
128
135
  hlsResourceLoader = result.resourceLoader
129
- let asset = result.asset
136
+ return applyFairPlayIfNeeded(to: result.asset)
137
+ }
130
138
 
139
+ private func applyFairPlayIfNeeded(to asset: AVURLAsset) -> AVURLAsset {
131
140
  if let certUrl = fairplayCertificateUrl, !certUrl.isEmpty,
132
141
  let spcUrl = fairplayContentKeySpcUrl, !spcUrl.isEmpty {
133
142
  let session = AVContentKeySession(keySystem: .fairPlayStreaming)
@@ -135,7 +144,6 @@ class FullscreenVideoPlayer: NSObject {
135
144
  session.addContentKeyRecipient(asset)
136
145
  self.contentKeySession = session
137
146
  }
138
-
139
147
  return asset
140
148
  }
141
149
 
@@ -24,13 +24,18 @@ enum HLSVideoAssetFactory {
24
24
  resolvedTracks.append((url: subtitleURL, language: track.language ?? "en"))
25
25
  }
26
26
 
27
- guard !resolvedTracks.isEmpty, isHLSStream(videoURL) else {
27
+ // Use the resource loader whenever sidecar subtitles are present so
28
+ // AVPlayerViewController can expose a native multi-language picker.
29
+ // AVMutableComposition can play one track but does not reliably expose
30
+ // selectable legible media-selection options.
31
+ guard !resolvedTracks.isEmpty else {
28
32
  return (AVURLAsset(url: videoURL), nil)
29
33
  }
30
34
 
31
35
  let resourceLoader = HLSSubtitleResourceLoader(
32
36
  videoURL: videoURL,
33
- subtitleTracks: resolvedTracks.map { HLSSubtitleTrack(url: $0.url, language: $0.language) }
37
+ subtitleTracks: resolvedTracks.map { HLSSubtitleTrack(url: $0.url, language: $0.language) },
38
+ isProgressive: !isHLSStream(videoURL)
34
39
  )
35
40
  guard let assetURL = HLSSubtitleResourceLoader.assetURL(for: videoURL) else {
36
41
  return (AVURLAsset(url: videoURL), nil)
@@ -47,27 +52,37 @@ struct HLSSubtitleTrack {
47
52
  let language: String
48
53
  }
49
54
 
50
- /// Injects external WebVTT subtitles into HLS master playlists via AVAssetResourceLoaderDelegate.
51
- /// AVMutableComposition cannot demux HLS tracks, so sidecar subtitles must be wired through the manifest.
55
+ /// Injects external WebVTT subtitles into playlists via AVAssetResourceLoaderDelegate.
56
+ ///
57
+ /// - HLS multivariant playlists: inject `#EXT-X-MEDIA` subtitle tags.
58
+ /// - HLS media playlists: wrap in a synthetic multivariant playlist that references the media playlist.
59
+ /// - Progressive MP4/WebM: synthesize a multivariant + media playlist so multiple sidecar
60
+ /// tracks appear in AVPlayerViewController's subtitle options.
52
61
  final class HLSSubtitleResourceLoader: NSObject, AVAssetResourceLoaderDelegate {
53
62
  static let videoScheme = "capgohls"
63
+ static let mediaPlaylistScheme = "capgohls-media"
54
64
  static let subtitlePlaylistScheme = "capgohls-sub"
55
65
  private static let subtitleGroupID = "capgosubs"
56
66
  private static let mpegURLContentType = UTType.m3uPlaylist.identifier
67
+ private static let progressiveSegmentDuration = 86400.0
57
68
 
58
69
  private let originalVideoURL: URL
59
70
  private let subtitleTracks: [HLSSubtitleTrack]
71
+ private let isProgressive: Bool
60
72
 
61
73
  private struct LoadedResource {
62
74
  let data: Data
63
75
  let contentType: String?
64
76
  }
65
77
 
66
- init(videoURL: URL, subtitleTracks: [HLSSubtitleTrack]) {
78
+ init(videoURL: URL, subtitleTracks: [HLSSubtitleTrack], isProgressive: Bool = false) {
67
79
  self.originalVideoURL = videoURL
68
80
  self.subtitleTracks = subtitleTracks
81
+ self.isProgressive = isProgressive
69
82
  }
70
83
 
84
+ deinit {}
85
+
71
86
  static func assetURL(for videoURL: URL) -> URL? {
72
87
  guard var components = URLComponents(url: videoURL, resolvingAgainstBaseURL: false) else {
73
88
  return nil
@@ -76,6 +91,14 @@ final class HLSSubtitleResourceLoader: NSObject, AVAssetResourceLoaderDelegate {
76
91
  return components.url
77
92
  }
78
93
 
94
+ static func mediaPlaylistURL(for videoURL: URL) -> URL? {
95
+ guard var components = URLComponents(url: videoURL, resolvingAgainstBaseURL: false) else {
96
+ return nil
97
+ }
98
+ components.scheme = mediaPlaylistScheme
99
+ return components.url
100
+ }
101
+
79
102
  static func subtitlePlaylistURL(for videoURL: URL, index: Int) -> URL? {
80
103
  guard var components = URLComponents(url: videoURL, resolvingAgainstBaseURL: false) else {
81
104
  return nil
@@ -111,10 +134,25 @@ final class HLSSubtitleResourceLoader: NSObject, AVAssetResourceLoaderDelegate {
111
134
  if requestURL.scheme == Self.subtitlePlaylistScheme {
112
135
  let index = subtitleIndex(from: requestURL) ?? 0
113
136
  let track = subtitleTracks[min(max(index, 0), subtitleTracks.count - 1)]
114
- let data = Data(subtitleMediaPlaylist(for: track.url).utf8)
137
+ let data = Data(Self.subtitleMediaPlaylist(for: track.url).utf8)
115
138
  return LoadedResource(data: data, contentType: Self.mpegURLContentType)
116
139
  }
117
140
 
141
+ if requestURL.scheme == Self.mediaPlaylistScheme {
142
+ let data = Data(Self.progressiveMediaPlaylist(for: originalVideoURL).utf8)
143
+ return LoadedResource(data: data, contentType: Self.mpegURLContentType)
144
+ }
145
+
146
+ if isProgressive {
147
+ let playlist = Self.multivariantPlaylist(
148
+ mediaURI: Self.mediaPlaylistURL(for: originalVideoURL)?.absoluteString
149
+ ?? originalVideoURL.absoluteString,
150
+ subtitleTracks: subtitleTracks,
151
+ videoURL: originalVideoURL
152
+ )
153
+ return LoadedResource(data: Data(playlist.utf8), contentType: Self.mpegURLContentType)
154
+ }
155
+
118
156
  let fetchURL = originalURL(for: requestURL)
119
157
  let (data, response) = try await URLSession.shared.data(from: fetchURL)
120
158
  if let http = response as? HTTPURLResponse, !(200...299).contains(http.statusCode) {
@@ -123,16 +161,22 @@ final class HLSSubtitleResourceLoader: NSObject, AVAssetResourceLoaderDelegate {
123
161
 
124
162
  let manifest = String(data: data, encoding: .utf8) ?? ""
125
163
 
126
- guard hasStreamInfTags(manifest) else {
127
- let contentType = Self.contentTypeIdentifier(from: response)
128
- return LoadedResource(data: data, contentType: contentType)
164
+ if hasStreamInfTags(manifest) {
165
+ let modified = injectSubtitles(
166
+ into: manifest,
167
+ baseURL: response.url ?? fetchURL
168
+ )
169
+ return LoadedResource(data: Data(modified.utf8), contentType: Self.mpegURLContentType)
129
170
  }
130
171
 
131
- let modified = injectSubtitles(
132
- into: manifest,
133
- baseURL: response.url ?? fetchURL
172
+ // Media playlist (no variants): wrap in a multivariant playlist so subtitle tags are selectable.
173
+ let mediaURI = (response.url ?? fetchURL).absoluteString
174
+ let playlist = Self.multivariantPlaylist(
175
+ mediaURI: mediaURI,
176
+ subtitleTracks: subtitleTracks,
177
+ videoURL: originalVideoURL
134
178
  )
135
- return LoadedResource(data: Data(modified.utf8), contentType: Self.mpegURLContentType)
179
+ return LoadedResource(data: Data(playlist.utf8), contentType: Self.mpegURLContentType)
136
180
  }
137
181
 
138
182
  private func subtitleIndex(from requestURL: URL) -> Int? {
@@ -157,13 +201,6 @@ final class HLSSubtitleResourceLoader: NSObject, AVAssetResourceLoaderDelegate {
157
201
  manifest.contains("#EXT-X-STREAM-INF")
158
202
  }
159
203
 
160
- private static func contentTypeIdentifier(from response: URLResponse) -> String? {
161
- guard let mimeType = (response as? HTTPURLResponse)?.mimeType else {
162
- return nil
163
- }
164
- return UTType(mimeType: mimeType)?.identifier
165
- }
166
-
167
204
  private func absoluteURI(for uri: String, relativeTo baseURL: URL) -> String {
168
205
  let trimmed = uri.trimmingCharacters(in: .whitespacesAndNewlines)
169
206
  guard let url = URL(string: trimmed, relativeTo: baseURL)?.absoluteURL else {
@@ -172,18 +209,60 @@ final class HLSSubtitleResourceLoader: NSObject, AVAssetResourceLoaderDelegate {
172
209
  return url.absoluteString
173
210
  }
174
211
 
175
- private func injectSubtitles(into manifest: String, baseURL: URL) -> String {
176
- let mediaTags = subtitleTracks.enumerated().compactMap { index, track -> String? in
177
- guard let subtitlePlaylistURI = Self.subtitlePlaylistURL(for: originalVideoURL, index: index)?.absoluteString else {
212
+ static func multivariantPlaylist(
213
+ mediaURI: String,
214
+ subtitleTracks: [HLSSubtitleTrack],
215
+ videoURL: URL
216
+ ) -> String {
217
+ var lines: [String] = ["#EXTM3U", "#EXT-X-VERSION:3"]
218
+ lines.append(contentsOf: subtitleMediaTags(subtitleTracks: subtitleTracks, videoURL: videoURL))
219
+ lines.append("#EXT-X-STREAM-INF:BANDWIDTH=2500000,SUBTITLES=\"\(subtitleGroupID)\"")
220
+ lines.append(mediaURI)
221
+ return lines.joined(separator: "\n") + "\n"
222
+ }
223
+
224
+ static func progressiveMediaPlaylist(for videoURL: URL) -> String {
225
+ """
226
+ #EXTM3U
227
+ #EXT-X-VERSION:3
228
+ #EXT-X-TARGETDURATION:\(Int(progressiveSegmentDuration))
229
+ #EXT-X-MEDIA-SEQUENCE:0
230
+ #EXT-X-PLAYLIST-TYPE:VOD
231
+ #EXTINF:\(progressiveSegmentDuration),
232
+ \(videoURL.absoluteString)
233
+ #EXT-X-ENDLIST
234
+ """
235
+ }
236
+
237
+ static func subtitleMediaPlaylist(for subtitleURL: URL) -> String {
238
+ """
239
+ #EXTM3U
240
+ #EXT-X-VERSION:3
241
+ #EXT-X-TARGETDURATION:\(Int(progressiveSegmentDuration))
242
+ #EXT-X-MEDIA-SEQUENCE:0
243
+ #EXT-X-PLAYLIST-TYPE:VOD
244
+ #EXTINF:\(progressiveSegmentDuration),
245
+ \(subtitleURL.absoluteString)
246
+ #EXT-X-ENDLIST
247
+ """
248
+ }
249
+
250
+ static func subtitleMediaTags(subtitleTracks: [HLSSubtitleTrack], videoURL: URL) -> [String] {
251
+ subtitleTracks.enumerated().compactMap { index, track -> String? in
252
+ guard let subtitlePlaylistURI = subtitlePlaylistURL(for: videoURL, index: index)?.absoluteString else {
178
253
  return nil
179
254
  }
180
255
  let isDefault = index == 0 ? "YES" : "NO"
181
256
  let displayName = Locale(identifier: track.language).localizedString(forLanguageCode: track.language)
182
257
  ?? track.language
183
258
  return """
184
- #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="\(Self.subtitleGroupID)",NAME="\(displayName)",DEFAULT=\(isDefault),AUTOSELECT=YES,FORCED=NO,LANGUAGE="\(track.language)",URI="\(subtitlePlaylistURI)"
259
+ #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="\(subtitleGroupID)",NAME="\(displayName)",DEFAULT=\(isDefault),AUTOSELECT=YES,FORCED=NO,LANGUAGE="\(track.language)",URI="\(subtitlePlaylistURI)"
185
260
  """
186
261
  }
262
+ }
263
+
264
+ private func injectSubtitles(into manifest: String, baseURL: URL) -> String {
265
+ let mediaTags = Self.subtitleMediaTags(subtitleTracks: subtitleTracks, videoURL: originalVideoURL)
187
266
 
188
267
  guard !mediaTags.isEmpty else {
189
268
  return manifest
@@ -226,19 +305,6 @@ final class HLSSubtitleResourceLoader: NSObject, AVAssetResourceLoaderDelegate {
226
305
  return result.joined(separator: "\n")
227
306
  }
228
307
 
229
- private func subtitleMediaPlaylist(for subtitleURL: URL) -> String {
230
- """
231
- #EXTM3U
232
- #EXT-X-VERSION:3
233
- #EXT-X-TARGETDURATION:600
234
- #EXT-X-MEDIA-SEQUENCE:0
235
- #EXT-X-PLAYLIST-TYPE:VOD
236
- #EXTINF:600.0,
237
- \(subtitleURL.absoluteString)
238
- #EXT-X-ENDLIST
239
- """
240
- }
241
-
242
308
  private func fulfill(_ loadingRequest: AVAssetResourceLoadingRequest, with resource: LoadedResource) {
243
309
  if let contentRequest = loadingRequest.contentInformationRequest {
244
310
  if let contentType = resource.contentType {
@@ -8,7 +8,7 @@ import AVKit
8
8
  */
9
9
  @objc(VideoPlayerPlugin)
10
10
  public class VideoPlayerPlugin: CAPPlugin, CAPBridgedPlugin {
11
- private let pluginVersion: String = "8.2.1"
11
+ private let pluginVersion: String = "8.2.2"
12
12
  public let identifier = "VideoPlayerPlugin"
13
13
  public let jsName = "VideoPlayer"
14
14
  public let pluginMethods: [CAPPluginMethod] = [
@@ -0,0 +1,65 @@
1
+ import XCTest
2
+ @testable import VideoPlayerPlugin
3
+
4
+ final class HLSSubtitlePlaylistTests: XCTestCase {
5
+ func testMultivariantPlaylistIncludesAllSubtitleLanguages() {
6
+ let videoURL = URL(string: "https://example.com/video.mp4")!
7
+ let tracks = [
8
+ HLSSubtitleTrack(url: URL(string: "https://example.com/en.vtt")!, language: "en"),
9
+ HLSSubtitleTrack(url: URL(string: "https://example.com/fr.vtt")!, language: "fr"),
10
+ HLSSubtitleTrack(url: URL(string: "https://example.com/es.vtt")!, language: "es")
11
+ ]
12
+
13
+ let playlist = HLSSubtitleResourceLoader.multivariantPlaylist(
14
+ mediaURI: "capgohls-media://example.com/video.mp4",
15
+ subtitleTracks: tracks,
16
+ videoURL: videoURL
17
+ )
18
+
19
+ XCTAssertTrue(playlist.contains("#EXTM3U"))
20
+ XCTAssertTrue(playlist.contains("LANGUAGE=\"en\""))
21
+ XCTAssertTrue(playlist.contains("LANGUAGE=\"fr\""))
22
+ XCTAssertTrue(playlist.contains("LANGUAGE=\"es\""))
23
+ XCTAssertTrue(playlist.contains("DEFAULT=YES"))
24
+ XCTAssertTrue(playlist.contains("SUBTITLES=\"capgosubs\""))
25
+ XCTAssertTrue(playlist.contains("capgohls-media://example.com/video.mp4"))
26
+ XCTAssertEqual(playlist.components(separatedBy: "TYPE=SUBTITLES").count - 1, 3)
27
+ }
28
+
29
+ func testProgressiveMediaPlaylistPointsAtSourceVideo() {
30
+ let videoURL = URL(string: "https://example.com/movie.mp4")!
31
+ let playlist = HLSSubtitleResourceLoader.progressiveMediaPlaylist(for: videoURL)
32
+ let subtitle = HLSSubtitleResourceLoader.subtitleMediaPlaylist(
33
+ for: URL(string: "https://example.com/en.vtt")!
34
+ )
35
+
36
+ XCTAssertTrue(playlist.contains("#EXT-X-PLAYLIST-TYPE:VOD"))
37
+ XCTAssertTrue(playlist.contains(videoURL.absoluteString))
38
+ XCTAssertTrue(playlist.contains("#EXT-X-ENDLIST"))
39
+ XCTAssertTrue(playlist.contains("#EXT-X-TARGETDURATION:86400"))
40
+ XCTAssertTrue(playlist.contains("#EXTINF:86400.0,"))
41
+ XCTAssertTrue(subtitle.contains("#EXT-X-TARGETDURATION:86400"))
42
+ XCTAssertTrue(subtitle.contains("#EXTINF:86400.0,"))
43
+ }
44
+
45
+ func testMakeAssetUsesResourceLoaderForProgressiveSubtitles() {
46
+ let videoURL = URL(string: "https://example.com/movie.mp4")!
47
+ let tracks = [
48
+ VideoSubtitleTrack(url: "https://example.com/en.vtt", language: "en"),
49
+ VideoSubtitleTrack(url: "https://example.com/fr.vtt", language: "fr")
50
+ ]
51
+
52
+ let result = HLSVideoAssetFactory.makeAsset(videoURL: videoURL, subtitleTracks: tracks)
53
+
54
+ XCTAssertNotNil(result.resourceLoader)
55
+ XCTAssertEqual(result.asset.url.scheme, HLSSubtitleResourceLoader.videoScheme)
56
+ }
57
+
58
+ func testMakeAssetSkipsResourceLoaderWithoutSubtitles() {
59
+ let videoURL = URL(string: "https://example.com/movie.mp4")!
60
+ let result = HLSVideoAssetFactory.makeAsset(videoURL: videoURL, subtitleTracks: [])
61
+
62
+ XCTAssertNil(result.resourceLoader)
63
+ XCTAssertEqual(result.asset.url, videoURL)
64
+ }
65
+ }
@@ -3,13 +3,25 @@ import XCTest
3
3
 
4
4
  class VideoPlayerTests: XCTestCase {
5
5
  func testEcho() {
6
- // This is an example of a functional test case for a plugin.
7
- // Use XCTAssert and related functions to verify your tests produce the correct results.
8
-
9
6
  let implementation = VideoPlayer()
10
7
  let value = "Hello, World!"
11
8
  let result = implementation.echo(value)
12
-
13
9
  XCTAssertEqual(value, result)
14
10
  }
11
+
12
+ func testSubtitleTrackParserPrefersSubtitlesArray() {
13
+ let tracks = VideoSubtitleTrackParser.parse(
14
+ from: [
15
+ ["subtitle": "https://example.com/en.vtt", "language": "en"],
16
+ ["subtitle": "https://example.com/fr.vtt", "language": "fr"]
17
+ ],
18
+ legacySubtitle: "https://example.com/legacy.vtt",
19
+ legacyLanguage: "de"
20
+ )
21
+
22
+ XCTAssertEqual(tracks.count, 2)
23
+ XCTAssertEqual(tracks[0].url, "https://example.com/en.vtt")
24
+ XCTAssertEqual(tracks[0].language, "en")
25
+ XCTAssertEqual(tracks[1].language, "fr")
26
+ }
15
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-video-player",
3
- "version": "8.2.1",
3
+ "version": "8.2.2",
4
4
  "description": "Capacitor plugin to play video in native player",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",