@capgo/capacitor-video-player 8.2.14 → 8.3.0
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/README.md +68 -33
- package/android/src/main/java/com/capgo/videoplayer/FullscreenExoPlayerFragment.java +145 -53
- package/android/src/main/java/com/capgo/videoplayer/SubtitleOptionOverrides.java +84 -0
- package/android/src/main/java/com/capgo/videoplayer/VideoChapter.java +14 -0
- package/android/src/main/java/com/capgo/videoplayer/VideoPlayer.java +3 -0
- package/android/src/main/java/com/capgo/videoplayer/VideoPlayerPlugin.java +48 -2
- package/android/src/main/res/drawable/ic_chapters_white.xml +10 -0
- package/android/src/main/res/layout/exo_playback_control_view.xml +9 -0
- package/android/src/main/res/values/strings.xml +2 -0
- package/dist/docs.json +44 -5
- package/dist/esm/definitions.d.ts +58 -6
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/VideoPlayerPlugin/AVPlayerControlsVisibilityObserver.swift +13 -0
- package/ios/Sources/VideoPlayerPlugin/FullscreenVideoPlayer.swift +243 -33
- package/ios/Sources/VideoPlayerPlugin/SubtitleStyleOptions.swift +7 -0
- package/ios/Sources/VideoPlayerPlugin/VideoChapter.swift +45 -0
- package/ios/Sources/VideoPlayerPlugin/VideoPlayerAudioSessionCoordinator.swift +101 -0
- package/ios/Sources/VideoPlayerPlugin/VideoPlayerCastController.swift +23 -5
- package/ios/Sources/VideoPlayerPlugin/VideoPlayerPlugin.swift +49 -1
- package/ios/Tests/VideoPlayerPluginTests/VideoChapterTests.swift +30 -0
- package/ios/Tests/VideoPlayerPluginTests/VideoPlayerAudioSessionCategoryPolicyTests.swift +52 -0
- package/package.json +6 -4
|
@@ -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.
|
|
49
|
+
private final String pluginVersion = "8.3.0";
|
|
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";
|
|
@@ -90,6 +90,7 @@ public class VideoPlayerPlugin extends Plugin {
|
|
|
90
90
|
private String subtitle = "";
|
|
91
91
|
private String language = "";
|
|
92
92
|
private List<VideoSubtitleTrack> subtitleTracks = new ArrayList<>();
|
|
93
|
+
private List<VideoChapter> chapters = new ArrayList<>();
|
|
93
94
|
private JSObject subTitleOptions;
|
|
94
95
|
private JSObject drmOptions;
|
|
95
96
|
private final JSObject ret = new JSObject();
|
|
@@ -208,6 +209,7 @@ public class VideoPlayerPlugin extends Plugin {
|
|
|
208
209
|
language = call.getString("language");
|
|
209
210
|
}
|
|
210
211
|
subtitleTracks = parseSubtitleTracks(call);
|
|
212
|
+
chapters = parseChapters(call);
|
|
211
213
|
subTitleOptions = new JSObject();
|
|
212
214
|
if (call.getData().has("subtitleOptions")) {
|
|
213
215
|
subTitleOptions = call.getObject("subtitleOptions");
|
|
@@ -982,6 +984,7 @@ public class VideoPlayerPlugin extends Plugin {
|
|
|
982
984
|
showControls,
|
|
983
985
|
displayMode,
|
|
984
986
|
resolvedSubtitleTracks,
|
|
987
|
+
chapters,
|
|
985
988
|
subTitleOptions,
|
|
986
989
|
headers,
|
|
987
990
|
title,
|
|
@@ -1144,7 +1147,8 @@ public class VideoPlayerPlugin extends Plugin {
|
|
|
1144
1147
|
showControls,
|
|
1145
1148
|
displayMode,
|
|
1146
1149
|
new ArrayList<>(),
|
|
1147
|
-
|
|
1150
|
+
chapters,
|
|
1151
|
+
subTitleOptions,
|
|
1148
1152
|
headers,
|
|
1149
1153
|
title,
|
|
1150
1154
|
smallTitle,
|
|
@@ -1198,6 +1202,46 @@ public class VideoPlayerPlugin extends Plugin {
|
|
|
1198
1202
|
return tracks;
|
|
1199
1203
|
}
|
|
1200
1204
|
|
|
1205
|
+
private List<VideoChapter> parseChapters(PluginCall call) {
|
|
1206
|
+
List<VideoChapter> parsed = new ArrayList<>();
|
|
1207
|
+
if (!call.getData().has("chapters")) {
|
|
1208
|
+
return parsed;
|
|
1209
|
+
}
|
|
1210
|
+
JSArray chapterArray = call.getArray("chapters");
|
|
1211
|
+
if (chapterArray == null) {
|
|
1212
|
+
return parsed;
|
|
1213
|
+
}
|
|
1214
|
+
for (int i = 0; i < chapterArray.length(); i++) {
|
|
1215
|
+
JSONObject entry = chapterArray.optJSONObject(i);
|
|
1216
|
+
if (entry == null) {
|
|
1217
|
+
Log.w(TAG, "Skipping malformed chapter entry at index " + i);
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
Object rawTitle = entry.opt("title");
|
|
1221
|
+
if (!(rawTitle instanceof String)) {
|
|
1222
|
+
continue;
|
|
1223
|
+
}
|
|
1224
|
+
String chapterTitle = (String) rawTitle;
|
|
1225
|
+
if (chapterTitle.trim().isEmpty()) {
|
|
1226
|
+
continue;
|
|
1227
|
+
}
|
|
1228
|
+
if (!entry.has("startTime")) {
|
|
1229
|
+
continue;
|
|
1230
|
+
}
|
|
1231
|
+
double startTime = entry.optDouble("startTime", -1);
|
|
1232
|
+
if (Double.isNaN(startTime) || Double.isInfinite(startTime) || startTime < 0) {
|
|
1233
|
+
continue;
|
|
1234
|
+
}
|
|
1235
|
+
Double endTime = entry.has("endTime") ? entry.optDouble("endTime", -1) : null;
|
|
1236
|
+
if (endTime != null && (Double.isNaN(endTime) || Double.isInfinite(endTime) || endTime <= startTime)) {
|
|
1237
|
+
endTime = null;
|
|
1238
|
+
}
|
|
1239
|
+
parsed.add(new VideoChapter(chapterTitle.trim(), startTime, endTime));
|
|
1240
|
+
}
|
|
1241
|
+
parsed.sort((left, right) -> Double.compare(left.startTimeSeconds, right.startTimeSeconds));
|
|
1242
|
+
return parsed;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1201
1245
|
private List<VideoSubtitleTrack> resolveSubtitleTracks(List<VideoSubtitleTrack> tracks) {
|
|
1202
1246
|
List<VideoSubtitleTrack> resolved = new ArrayList<>();
|
|
1203
1247
|
if (tracks == null) {
|
|
@@ -1227,6 +1271,7 @@ public class VideoPlayerPlugin extends Plugin {
|
|
|
1227
1271
|
Boolean showControls,
|
|
1228
1272
|
String displayMode,
|
|
1229
1273
|
List<VideoSubtitleTrack> subtitleTracks,
|
|
1274
|
+
List<VideoChapter> chapters,
|
|
1230
1275
|
JSObject subTitleOptions,
|
|
1231
1276
|
JSObject headers,
|
|
1232
1277
|
String title,
|
|
@@ -1253,6 +1298,7 @@ public class VideoPlayerPlugin extends Plugin {
|
|
|
1253
1298
|
showControls,
|
|
1254
1299
|
displayMode,
|
|
1255
1300
|
subtitleTracks,
|
|
1301
|
+
chapters,
|
|
1256
1302
|
subTitleOptions,
|
|
1257
1303
|
headers,
|
|
1258
1304
|
title,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
android:width="24dp"
|
|
4
|
+
android:height="24dp"
|
|
5
|
+
android:viewportWidth="24"
|
|
6
|
+
android:viewportHeight="24">
|
|
7
|
+
<path
|
|
8
|
+
android:fillColor="#FFFFFFFF"
|
|
9
|
+
android:pathData="M4,10.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5 1.5,-0.67 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM4,4.5c-0.83,0 -1.5,0.67 -1.5,1.5S3.17,7.5 4,7.5 5.5,6.83 5.5,6 4.83,4.5 4,4.5zM4,16.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5 1.5,-0.67 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM7,19h14v-2H7v2zM7,13h14v-2H7v2zM7,5v2h14V5H7z" />
|
|
10
|
+
</vector>
|
|
@@ -115,6 +115,15 @@
|
|
|
115
115
|
android:background="?actionBarItemBackground"
|
|
116
116
|
android:visibility="gone"/>
|
|
117
117
|
|
|
118
|
+
<ImageButton
|
|
119
|
+
android:id="@+id/exo_chapters"
|
|
120
|
+
android:layout_width="48dp"
|
|
121
|
+
android:layout_height="48dp"
|
|
122
|
+
android:background="?actionBarItemBackground"
|
|
123
|
+
android:src="@drawable/ic_chapters_white"
|
|
124
|
+
android:visibility="gone"
|
|
125
|
+
android:contentDescription="@string/chapters_button"/>
|
|
126
|
+
|
|
118
127
|
<ImageButton
|
|
119
128
|
android:id="@+id/exo_pip"
|
|
120
129
|
android:layout_width="48dp"
|
package/dist/docs.json
CHANGED
|
@@ -431,6 +431,15 @@
|
|
|
431
431
|
],
|
|
432
432
|
"type": "VideoSubtitle[] | undefined"
|
|
433
433
|
},
|
|
434
|
+
{
|
|
435
|
+
"name": "chapters",
|
|
436
|
+
"tags": [],
|
|
437
|
+
"docs": "Chapter markers for long-form content (iOS, Android).\nShown as a chapter list in the native fullscreen player; selecting a chapter seeks to `startTime`.",
|
|
438
|
+
"complexTypes": [
|
|
439
|
+
"VideoChapter"
|
|
440
|
+
],
|
|
441
|
+
"type": "VideoChapter[] | undefined"
|
|
442
|
+
},
|
|
434
443
|
{
|
|
435
444
|
"name": "subtitleOptions",
|
|
436
445
|
"tags": [],
|
|
@@ -485,7 +494,7 @@
|
|
|
485
494
|
{
|
|
486
495
|
"name": "audioCategory",
|
|
487
496
|
"tags": [],
|
|
488
|
-
"docs": "iOS audio session category behavior (iOS).\n- \"ambient\": respects the iPhone silent switch
|
|
497
|
+
"docs": "iOS audio session category behavior (iOS).\n- \"ambient\": respects the iPhone silent switch\n- \"playback\": ignores the iPhone silent switch\n- \"moviePlayback\": playback optimized for video and long-form AirPlay.\n\nWhen omitted, the plugin resolves the category from other options: `\"playback\"` if\n`pipEnabled` or `bkmodeEnabled` is true (both default to true), otherwise `\"ambient\"`.",
|
|
489
498
|
"complexTypes": [],
|
|
490
499
|
"type": "'ambient' | 'playback' | 'moviePlayback' | undefined"
|
|
491
500
|
},
|
|
@@ -600,31 +609,61 @@
|
|
|
600
609
|
}
|
|
601
610
|
]
|
|
602
611
|
},
|
|
612
|
+
{
|
|
613
|
+
"name": "VideoChapter",
|
|
614
|
+
"slug": "videochapter",
|
|
615
|
+
"docs": "",
|
|
616
|
+
"tags": [],
|
|
617
|
+
"methods": [],
|
|
618
|
+
"properties": [
|
|
619
|
+
{
|
|
620
|
+
"name": "title",
|
|
621
|
+
"tags": [],
|
|
622
|
+
"docs": "Chapter title shown in the chapter list",
|
|
623
|
+
"complexTypes": [],
|
|
624
|
+
"type": "string"
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
"name": "startTime",
|
|
628
|
+
"tags": [],
|
|
629
|
+
"docs": "Start time in seconds",
|
|
630
|
+
"complexTypes": [],
|
|
631
|
+
"type": "number"
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
"name": "endTime",
|
|
635
|
+
"tags": [],
|
|
636
|
+
"docs": "End time in seconds (optional). Stored for future timeline markers; chapter jumps use `startTime` only in this release.",
|
|
637
|
+
"complexTypes": [],
|
|
638
|
+
"type": "number | undefined"
|
|
639
|
+
}
|
|
640
|
+
]
|
|
641
|
+
},
|
|
603
642
|
{
|
|
604
643
|
"name": "SubTitleOptions",
|
|
605
644
|
"slug": "subtitleoptions",
|
|
606
|
-
"docs": "",
|
|
645
|
+
"docs": "Optional styling for on-screen subtitles.\n\nOn iOS, colors and font size are applied through `AVPlayerItem`\n`textStyleRules`, which Apple documents for WebVTT only. IMSC1 and other\nin-manifest timed text formats are not styled through this API.\nInline WebVTT cue styles can take precedence over equivalent\n`subtitleOptions` values; the plugin sets text style rules as a platform\nfallback, not a guaranteed override of authored cue styling.",
|
|
607
646
|
"tags": [],
|
|
608
647
|
"methods": [],
|
|
609
648
|
"properties": [
|
|
610
649
|
{
|
|
611
650
|
"name": "foregroundColor",
|
|
612
651
|
"tags": [],
|
|
613
|
-
"docs": "Foreground
|
|
652
|
+
"docs": "Foreground color in RGBA. On Android, when the plugin applies subtitle\nstyling, omitted values fall back to `rgba(255,255,255,1)`. When\n`subtitleOptions` is absent, embedded cue colors from the media can\noverride that fallback. On iOS, omitted colors are not set by the plugin;\nthe platform uses the viewer's caption appearance settings instead of fixed\nplugin defaults.",
|
|
614
653
|
"complexTypes": [],
|
|
615
654
|
"type": "string | undefined"
|
|
616
655
|
},
|
|
617
656
|
{
|
|
618
657
|
"name": "backgroundColor",
|
|
619
658
|
"tags": [],
|
|
620
|
-
"docs": "Background
|
|
659
|
+
"docs": "Background color in RGBA. On Android, when the plugin applies subtitle\nstyling in fullscreen, omitted values fall back to `rgba(0,0,0,1)`. In\npicture-in-picture, omitted values fall back to transparent when the plugin\napplies its caption style (for example sidecar subtitles or non-empty\n`subtitleOptions` that include a color override). An empty\n`subtitleOptions` object alone does not select that fallback. With\nfont-size-only options, embedded cue styles stay enabled, so authored cue\nbackgrounds can remain visible in PiP. When `subtitleOptions` is absent,\nembedded cue colors from the media can override the fallback. On iOS,\nomitted colors are not set by the plugin; the platform uses the viewer's\ncaption appearance settings instead of fixed plugin defaults.",
|
|
621
660
|
"complexTypes": [],
|
|
622
661
|
"type": "string | undefined"
|
|
623
662
|
},
|
|
624
663
|
{
|
|
625
664
|
"name": "fontSize",
|
|
626
665
|
"tags": [],
|
|
627
|
-
"docs": "Font
|
|
666
|
+
"docs": "Font size in CSS pixels. On Android, supplied values are rounded to the\nnearest integer before applying. When omitted on embedded tracks without a\nsidecar subtitle URI, Android uses `SubtitleView.setUserDefaultTextSize()`\n(the user's system caption size), not a fixed 16 px size. Sidecar subtitles\nstill use a fixed default size when this property is omitted. On iOS,\nvalues map to AVFoundation relative size where 16 equals the system default\n(100%).",
|
|
628
667
|
"complexTypes": [],
|
|
629
668
|
"type": "number | undefined"
|
|
630
669
|
}
|
|
@@ -148,6 +148,11 @@ export interface capVideoPlayerOptions {
|
|
|
148
148
|
* When provided, takes precedence over `subtitle` / `language`.
|
|
149
149
|
*/
|
|
150
150
|
subtitles?: VideoSubtitle[];
|
|
151
|
+
/**
|
|
152
|
+
* Chapter markers for long-form content (iOS, Android).
|
|
153
|
+
* Shown as a chapter list in the native fullscreen player; selecting a chapter seeks to `startTime`.
|
|
154
|
+
*/
|
|
155
|
+
chapters?: VideoChapter[];
|
|
151
156
|
/**
|
|
152
157
|
* SubTitle Options
|
|
153
158
|
*/
|
|
@@ -182,10 +187,12 @@ export interface capVideoPlayerOptions {
|
|
|
182
187
|
bkmodeEnabled?: boolean;
|
|
183
188
|
/**
|
|
184
189
|
* iOS audio session category behavior (iOS).
|
|
185
|
-
* - "ambient": respects the iPhone silent switch
|
|
190
|
+
* - "ambient": respects the iPhone silent switch
|
|
186
191
|
* - "playback": ignores the iPhone silent switch
|
|
187
|
-
* - "moviePlayback": playback optimized for video and long-form AirPlay
|
|
188
|
-
*
|
|
192
|
+
* - "moviePlayback": playback optimized for video and long-form AirPlay.
|
|
193
|
+
*
|
|
194
|
+
* When omitted, the plugin resolves the category from other options: `"playback"` if
|
|
195
|
+
* `pipEnabled` or `bkmodeEnabled` is true (both default to true), otherwise `"ambient"`.
|
|
189
196
|
*/
|
|
190
197
|
audioCategory?: 'ambient' | 'playback' | 'moviePlayback';
|
|
191
198
|
/**
|
|
@@ -350,17 +357,62 @@ export interface VideoSubtitle {
|
|
|
350
357
|
*/
|
|
351
358
|
language?: string;
|
|
352
359
|
}
|
|
360
|
+
export interface VideoChapter {
|
|
361
|
+
/**
|
|
362
|
+
* Chapter title shown in the chapter list
|
|
363
|
+
*/
|
|
364
|
+
title: string;
|
|
365
|
+
/**
|
|
366
|
+
* Start time in seconds
|
|
367
|
+
*/
|
|
368
|
+
startTime: number;
|
|
369
|
+
/**
|
|
370
|
+
* End time in seconds (optional). Stored for future timeline markers; chapter jumps use `startTime` only in this release.
|
|
371
|
+
*/
|
|
372
|
+
endTime?: number;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Optional styling for on-screen subtitles.
|
|
376
|
+
*
|
|
377
|
+
* On iOS, colors and font size are applied through `AVPlayerItem`
|
|
378
|
+
* `textStyleRules`, which Apple documents for WebVTT only. IMSC1 and other
|
|
379
|
+
* in-manifest timed text formats are not styled through this API.
|
|
380
|
+
* Inline WebVTT cue styles can take precedence over equivalent
|
|
381
|
+
* `subtitleOptions` values; the plugin sets text style rules as a platform
|
|
382
|
+
* fallback, not a guaranteed override of authored cue styling.
|
|
383
|
+
*/
|
|
353
384
|
export interface SubTitleOptions {
|
|
354
385
|
/**
|
|
355
|
-
* Foreground
|
|
386
|
+
* Foreground color in RGBA. On Android, when the plugin applies subtitle
|
|
387
|
+
* styling, omitted values fall back to `rgba(255,255,255,1)`. When
|
|
388
|
+
* `subtitleOptions` is absent, embedded cue colors from the media can
|
|
389
|
+
* override that fallback. On iOS, omitted colors are not set by the plugin;
|
|
390
|
+
* the platform uses the viewer's caption appearance settings instead of fixed
|
|
391
|
+
* plugin defaults.
|
|
356
392
|
*/
|
|
357
393
|
foregroundColor?: string;
|
|
358
394
|
/**
|
|
359
|
-
* Background
|
|
395
|
+
* Background color in RGBA. On Android, when the plugin applies subtitle
|
|
396
|
+
* styling in fullscreen, omitted values fall back to `rgba(0,0,0,1)`. In
|
|
397
|
+
* picture-in-picture, omitted values fall back to transparent when the plugin
|
|
398
|
+
* applies its caption style (for example sidecar subtitles or non-empty
|
|
399
|
+
* `subtitleOptions` that include a color override). An empty
|
|
400
|
+
* `subtitleOptions` object alone does not select that fallback. With
|
|
401
|
+
* font-size-only options, embedded cue styles stay enabled, so authored cue
|
|
402
|
+
* backgrounds can remain visible in PiP. When `subtitleOptions` is absent,
|
|
403
|
+
* embedded cue colors from the media can override the fallback. On iOS,
|
|
404
|
+
* omitted colors are not set by the plugin; the platform uses the viewer's
|
|
405
|
+
* caption appearance settings instead of fixed plugin defaults.
|
|
360
406
|
*/
|
|
361
407
|
backgroundColor?: string;
|
|
362
408
|
/**
|
|
363
|
-
* Font
|
|
409
|
+
* Font size in CSS pixels. On Android, supplied values are rounded to the
|
|
410
|
+
* nearest integer before applying. When omitted on embedded tracks without a
|
|
411
|
+
* sidecar subtitle URI, Android uses `SubtitleView.setUserDefaultTextSize()`
|
|
412
|
+
* (the user's system caption size), not a fixed 16 px size. Sidecar subtitles
|
|
413
|
+
* still use a fixed default size when this property is omitted. On iOS,
|
|
414
|
+
* values map to AVFoundation relative size where 16 equals the system default
|
|
415
|
+
* (100%).
|
|
364
416
|
*/
|
|
365
417
|
fontSize?: number;
|
|
366
418
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface VideoPlayerPlugin {\n /**\n * Initialize a video player\n *\n */\n initPlayer(options: capVideoPlayerOptions): Promise<capVideoPlayerResult>;\n /**\n * Return if a given playerId is playing\n *\n */\n isPlaying(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Play the current video from a given playerId\n *\n */\n play(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Pause the current video from a given playerId\n *\n */\n pause(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Get the duration of the current video from a given playerId\n *\n */\n getDuration(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Get the current time of the current video from a given playerId\n *\n */\n getCurrentTime(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Set the current time to seek the current video to from a given playerId\n *\n */\n setCurrentTime(options: capVideoTimeOptions): Promise<capVideoPlayerResult>;\n /**\n * Get the volume of the current video from a given playerId\n *\n */\n getVolume(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Set the volume of the current video to from a given playerId\n *\n */\n setVolume(options: capVideoVolumeOptions): Promise<capVideoPlayerResult>;\n /**\n * Get the muted of the current video from a given playerId\n *\n */\n getMuted(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Set the muted of the current video to from a given playerId\n *\n */\n setMuted(options: capVideoMutedOptions): Promise<capVideoPlayerResult>;\n /**\n * Set the rate of the current video from a given playerId\n *\n */\n setRate(options: capVideoRateOptions): Promise<capVideoPlayerResult>;\n /**\n * Get the rate of the current video from a given playerId\n *\n */\n getRate(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Stop all players playing\n *\n */\n stopAllPlayers(): Promise<capVideoPlayerResult>;\n /**\n * Show controller\n *\n */\n showController(): Promise<capVideoPlayerResult>;\n /**\n * isControllerIsFullyVisible\n *\n */\n isControllerIsFullyVisible(): Promise<capVideoPlayerResult>;\n /**\n * Exit player\n *\n */\n exitPlayer(): Promise<capVideoPlayerResult>;\n /**\n * Hide the currently presented player UI without stopping playback (native fullscreen).\n *\n * Call `showPlayer()` to show it again.\n */\n hidePlayer(): Promise<capVideoPlayerResult>;\n /**\n * Show again a previously hidden player UI (native fullscreen).\n */\n showPlayer(): Promise<capVideoPlayerResult>;\n /**\n * Get the native Capacitor plugin version.\n * On web, the implementation returns `\"web\"`.\n *\n * @returns Promise resolving to the plugin version string for this build (`\"web\"` on web)\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\nexport interface capEchoOptions {\n /**\n * String to be echoed\n */\n\n value?: string;\n}\nexport interface capVideoPlayerOptions {\n /**\n * Player mode\n * - \"fullscreen\"\n * - \"embedded\" (Web only)\n */\n mode?: string;\n /**\n * The url of the video to play\n */\n url?: string;\n /**\n * Optional override URL used when casting to Chromecast (iOS, Android).\n *\n * This lets you cast an alternative rendition/manifest (e.g. MPEG-DASH + Widevine)\n * while keeping the on-device playback URL unchanged (e.g. HLS + FairPlay on iOS).\n */\n chromecastUrl?: string;\n /**\n * The url of subtitle associated with the video\n *\n * Prefer `subtitles` when providing more than one track.\n * Kept for backward compatibility.\n */\n subtitle?: string;\n /**\n * The language of subtitle\n * see https://github.com/libyal/libfwnt/wiki/Language-Code-identifiers\n *\n * Prefer `subtitles` when providing more than one track.\n * Kept for backward compatibility.\n */\n language?: string;\n /**\n * Multiple subtitle tracks (iOS, Android).\n * When provided, takes precedence over `subtitle` / `language`.\n */\n subtitles?: VideoSubtitle[];\n /**\n * SubTitle Options\n */\n subtitleOptions?: SubTitleOptions;\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Initial playing rate\n */\n rate?: number;\n /**\n * Exit on VideoEnd (iOS, Android)\n * default: true\n */\n exitOnEnd?: boolean;\n /**\n * Loop on VideoEnd when exitOnEnd false (iOS, Android)\n * default: false\n */\n loopOnEnd?: boolean;\n /**\n * Picture in Picture Enable (iOS, Android)\n * default: true\n */\n pipEnabled?: boolean;\n /**\n * Background Mode Enable (iOS, Android)\n * default: true\n */\n bkmodeEnabled?: boolean;\n /**\n * iOS audio session category behavior (iOS).\n * - \"ambient\": respects the iPhone silent switch (default)\n * - \"playback\": ignores the iPhone silent switch\n * - \"moviePlayback\": playback optimized for video and long-form AirPlay\n * default: \"ambient\"\n */\n audioCategory?: 'ambient' | 'playback' | 'moviePlayback';\n /**\n * Show Controls Enable (iOS, Android)\n * default: true\n */\n showControls?: boolean;\n /**\n * Display Mode [\"all\", \"portrait\", \"landscape\"] (iOS, Android)\n * default: \"all\"\n */\n displayMode?: string;\n /**\n * Component Tag or DOM Element Tag (React app)\n */\n componentTag?: string;\n /**\n * Player Width (mode \"embedded\" only)\n */\n width?: number;\n /**\n * Player height (mode \"embedded\" only)\n */\n height?: number;\n /**\n * Headers for the request (iOS, Android)\n * by Manuel García Marín (https://github.com/PhantomPainX)\n */\n headers?: {\n [key: string]: string;\n };\n /**\n * Title shown in the player and Chromecast metadata (iOS, Android)\n * by Manuel García Marín (https://github.com/PhantomPainX)\n */\n title?: string;\n /**\n * Subtitle shown below the title in the player and Chromecast metadata (iOS, Android)\n * by Manuel García Marín (https://github.com/PhantomPainX)\n */\n smallTitle?: string;\n /**\n * ExoPlayer Progress Bar and Spinner color (Android)\n * by Manuel García Marín (https://github.com/PhantomPainX)\n * Must be a valid hex color code\n * default: #FFFFFF\n */\n accentColor?: string;\n /**\n * Chromecast enable/disable (iOS, Android)\n * iOS requires Google Cast SDK setup and local network Info.plist keys.\n * by Manuel García Marín (https://github.com/PhantomPainX)\n * default: true\n */\n chromecast?: boolean;\n /**\n * Artwork url to be shown in Chromecast player (iOS, Android)\n * by Manuel García Marín (https://github.com/PhantomPainX)\n * default: \"\"\n */\n artwork?: string;\n /**\n * DRM configuration for protected content (iOS: FairPlay, Android: Widevine)\n *\n * When casting, Widevine's `certificateUrl` (license URL) is also forwarded to Chromecast\n * receivers as `media.customData.laurl`.\n */\n drm?: DrmOptions;\n}\nexport interface capVideoPlayerIdOptions {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n}\nexport interface capVideoRateOptions {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Rate value\n */\n rate?: number;\n}\nexport interface capVideoVolumeOptions {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Volume value between [0 - 1]\n */\n volume?: number;\n}\nexport interface capVideoTimeOptions {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Video time value you want to seek to\n */\n seektime?: number;\n}\nexport interface capVideoMutedOptions {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Muted value true or false\n */\n muted?: boolean;\n}\nexport interface capVideoListener {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Video current time when listener triggered\n */\n currentTime?: number;\n}\nexport interface capExitListener {\n /**\n * Dismiss value true or false\n */\n dismiss?: boolean;\n /**\n * Video current time when listener triggered\n */\n currentTime?: number;\n}\nexport interface capVideoPlayerResult {\n /**\n * result set to true when successful else false\n */\n result?: boolean;\n /**\n * method name\n */\n method?: string;\n /**\n * value returned\n */\n value?: any;\n /**\n * message string\n */\n message?: string;\n}\nexport interface VideoSubtitle {\n /**\n * The url of the subtitle file (vtt, srt, ...)\n */\n subtitle: string;\n /**\n * The language of the subtitle\n * see https://github.com/libyal/libfwnt/wiki/Language-Code-identifiers\n */\n language?: string;\n}\nexport interface SubTitleOptions {\n /**\n * Foreground Color in RGBA (default rgba(255,255,255,1)\n */\n foregroundColor?: string;\n /**\n * Background Color in RGBA (default rgba(0,0,0,1)\n */\n backgroundColor?: string;\n /**\n * Font Size in pixels (default 16)\n */\n fontSize?: number;\n}\nexport interface FairPlayDrmOptions {\n /**\n * The URL to fetch the FairPlay certificate\n */\n certificateUrl?: string;\n /**\n * The URL to send the SPC and receive the CKC license (FairPlay license server URL)\n */\n contentKeySpcUrl?: string;\n /**\n * Optional FairPlay asset identifier used when generating the SPC.\n * Defaults to the `skd://` content identifier from the key request.\n */\n assetId?: string;\n}\nexport interface PlayreadyDrmOptions {\n /**\n * The URL to fetch the PlayReady license\n */\n certificateUrl?: string;\n}\nexport interface WidevineDrmOptions {\n /**\n * The URL to fetch the Widevine license\n */\n certificateUrl?: string;\n}\nexport interface DrmOptions {\n /**\n * FairPlay DRM configuration (iOS)\n */\n fairplay?: FairPlayDrmOptions;\n /**\n * PlayReady DRM configuration\n */\n playready?: PlayreadyDrmOptions;\n /**\n * Widevine DRM configuration (Android)\n */\n widevine?: WidevineDrmOptions;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface VideoPlayerPlugin {\n /**\n * Initialize a video player\n *\n */\n initPlayer(options: capVideoPlayerOptions): Promise<capVideoPlayerResult>;\n /**\n * Return if a given playerId is playing\n *\n */\n isPlaying(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Play the current video from a given playerId\n *\n */\n play(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Pause the current video from a given playerId\n *\n */\n pause(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Get the duration of the current video from a given playerId\n *\n */\n getDuration(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Get the current time of the current video from a given playerId\n *\n */\n getCurrentTime(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Set the current time to seek the current video to from a given playerId\n *\n */\n setCurrentTime(options: capVideoTimeOptions): Promise<capVideoPlayerResult>;\n /**\n * Get the volume of the current video from a given playerId\n *\n */\n getVolume(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Set the volume of the current video to from a given playerId\n *\n */\n setVolume(options: capVideoVolumeOptions): Promise<capVideoPlayerResult>;\n /**\n * Get the muted of the current video from a given playerId\n *\n */\n getMuted(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Set the muted of the current video to from a given playerId\n *\n */\n setMuted(options: capVideoMutedOptions): Promise<capVideoPlayerResult>;\n /**\n * Set the rate of the current video from a given playerId\n *\n */\n setRate(options: capVideoRateOptions): Promise<capVideoPlayerResult>;\n /**\n * Get the rate of the current video from a given playerId\n *\n */\n getRate(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;\n /**\n * Stop all players playing\n *\n */\n stopAllPlayers(): Promise<capVideoPlayerResult>;\n /**\n * Show controller\n *\n */\n showController(): Promise<capVideoPlayerResult>;\n /**\n * isControllerIsFullyVisible\n *\n */\n isControllerIsFullyVisible(): Promise<capVideoPlayerResult>;\n /**\n * Exit player\n *\n */\n exitPlayer(): Promise<capVideoPlayerResult>;\n /**\n * Hide the currently presented player UI without stopping playback (native fullscreen).\n *\n * Call `showPlayer()` to show it again.\n */\n hidePlayer(): Promise<capVideoPlayerResult>;\n /**\n * Show again a previously hidden player UI (native fullscreen).\n */\n showPlayer(): Promise<capVideoPlayerResult>;\n /**\n * Get the native Capacitor plugin version.\n * On web, the implementation returns `\"web\"`.\n *\n * @returns Promise resolving to the plugin version string for this build (`\"web\"` on web)\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\nexport interface capEchoOptions {\n /**\n * String to be echoed\n */\n\n value?: string;\n}\nexport interface capVideoPlayerOptions {\n /**\n * Player mode\n * - \"fullscreen\"\n * - \"embedded\" (Web only)\n */\n mode?: string;\n /**\n * The url of the video to play\n */\n url?: string;\n /**\n * Optional override URL used when casting to Chromecast (iOS, Android).\n *\n * This lets you cast an alternative rendition/manifest (e.g. MPEG-DASH + Widevine)\n * while keeping the on-device playback URL unchanged (e.g. HLS + FairPlay on iOS).\n */\n chromecastUrl?: string;\n /**\n * The url of subtitle associated with the video\n *\n * Prefer `subtitles` when providing more than one track.\n * Kept for backward compatibility.\n */\n subtitle?: string;\n /**\n * The language of subtitle\n * see https://github.com/libyal/libfwnt/wiki/Language-Code-identifiers\n *\n * Prefer `subtitles` when providing more than one track.\n * Kept for backward compatibility.\n */\n language?: string;\n /**\n * Multiple subtitle tracks (iOS, Android).\n * When provided, takes precedence over `subtitle` / `language`.\n */\n subtitles?: VideoSubtitle[];\n /**\n * Chapter markers for long-form content (iOS, Android).\n * Shown as a chapter list in the native fullscreen player; selecting a chapter seeks to `startTime`.\n */\n chapters?: VideoChapter[];\n /**\n * SubTitle Options\n */\n subtitleOptions?: SubTitleOptions;\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Initial playing rate\n */\n rate?: number;\n /**\n * Exit on VideoEnd (iOS, Android)\n * default: true\n */\n exitOnEnd?: boolean;\n /**\n * Loop on VideoEnd when exitOnEnd false (iOS, Android)\n * default: false\n */\n loopOnEnd?: boolean;\n /**\n * Picture in Picture Enable (iOS, Android)\n * default: true\n */\n pipEnabled?: boolean;\n /**\n * Background Mode Enable (iOS, Android)\n * default: true\n */\n bkmodeEnabled?: boolean;\n /**\n * iOS audio session category behavior (iOS).\n * - \"ambient\": respects the iPhone silent switch\n * - \"playback\": ignores the iPhone silent switch\n * - \"moviePlayback\": playback optimized for video and long-form AirPlay.\n *\n * When omitted, the plugin resolves the category from other options: `\"playback\"` if\n * `pipEnabled` or `bkmodeEnabled` is true (both default to true), otherwise `\"ambient\"`.\n */\n audioCategory?: 'ambient' | 'playback' | 'moviePlayback';\n /**\n * Show Controls Enable (iOS, Android)\n * default: true\n */\n showControls?: boolean;\n /**\n * Display Mode [\"all\", \"portrait\", \"landscape\"] (iOS, Android)\n * default: \"all\"\n */\n displayMode?: string;\n /**\n * Component Tag or DOM Element Tag (React app)\n */\n componentTag?: string;\n /**\n * Player Width (mode \"embedded\" only)\n */\n width?: number;\n /**\n * Player height (mode \"embedded\" only)\n */\n height?: number;\n /**\n * Headers for the request (iOS, Android)\n * by Manuel García Marín (https://github.com/PhantomPainX)\n */\n headers?: {\n [key: string]: string;\n };\n /**\n * Title shown in the player and Chromecast metadata (iOS, Android)\n * by Manuel García Marín (https://github.com/PhantomPainX)\n */\n title?: string;\n /**\n * Subtitle shown below the title in the player and Chromecast metadata (iOS, Android)\n * by Manuel García Marín (https://github.com/PhantomPainX)\n */\n smallTitle?: string;\n /**\n * ExoPlayer Progress Bar and Spinner color (Android)\n * by Manuel García Marín (https://github.com/PhantomPainX)\n * Must be a valid hex color code\n * default: #FFFFFF\n */\n accentColor?: string;\n /**\n * Chromecast enable/disable (iOS, Android)\n * iOS requires Google Cast SDK setup and local network Info.plist keys.\n * by Manuel García Marín (https://github.com/PhantomPainX)\n * default: true\n */\n chromecast?: boolean;\n /**\n * Artwork url to be shown in Chromecast player (iOS, Android)\n * by Manuel García Marín (https://github.com/PhantomPainX)\n * default: \"\"\n */\n artwork?: string;\n /**\n * DRM configuration for protected content (iOS: FairPlay, Android: Widevine)\n *\n * When casting, Widevine's `certificateUrl` (license URL) is also forwarded to Chromecast\n * receivers as `media.customData.laurl`.\n */\n drm?: DrmOptions;\n}\nexport interface capVideoPlayerIdOptions {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n}\nexport interface capVideoRateOptions {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Rate value\n */\n rate?: number;\n}\nexport interface capVideoVolumeOptions {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Volume value between [0 - 1]\n */\n volume?: number;\n}\nexport interface capVideoTimeOptions {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Video time value you want to seek to\n */\n seektime?: number;\n}\nexport interface capVideoMutedOptions {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Muted value true or false\n */\n muted?: boolean;\n}\nexport interface capVideoListener {\n /**\n * Id of DIV Element parent of the player\n */\n playerId?: string;\n /**\n * Video current time when listener triggered\n */\n currentTime?: number;\n}\nexport interface capExitListener {\n /**\n * Dismiss value true or false\n */\n dismiss?: boolean;\n /**\n * Video current time when listener triggered\n */\n currentTime?: number;\n}\nexport interface capVideoPlayerResult {\n /**\n * result set to true when successful else false\n */\n result?: boolean;\n /**\n * method name\n */\n method?: string;\n /**\n * value returned\n */\n value?: any;\n /**\n * message string\n */\n message?: string;\n}\nexport interface VideoSubtitle {\n /**\n * The url of the subtitle file (vtt, srt, ...)\n */\n subtitle: string;\n /**\n * The language of the subtitle\n * see https://github.com/libyal/libfwnt/wiki/Language-Code-identifiers\n */\n language?: string;\n}\nexport interface VideoChapter {\n /**\n * Chapter title shown in the chapter list\n */\n title: string;\n /**\n * Start time in seconds\n */\n startTime: number;\n /**\n * End time in seconds (optional). Stored for future timeline markers; chapter jumps use `startTime` only in this release.\n */\n endTime?: number;\n}\n/**\n * Optional styling for on-screen subtitles.\n *\n * On iOS, colors and font size are applied through `AVPlayerItem`\n * `textStyleRules`, which Apple documents for WebVTT only. IMSC1 and other\n * in-manifest timed text formats are not styled through this API.\n * Inline WebVTT cue styles can take precedence over equivalent\n * `subtitleOptions` values; the plugin sets text style rules as a platform\n * fallback, not a guaranteed override of authored cue styling.\n */\nexport interface SubTitleOptions {\n /**\n * Foreground color in RGBA. On Android, when the plugin applies subtitle\n * styling, omitted values fall back to `rgba(255,255,255,1)`. When\n * `subtitleOptions` is absent, embedded cue colors from the media can\n * override that fallback. On iOS, omitted colors are not set by the plugin;\n * the platform uses the viewer's caption appearance settings instead of fixed\n * plugin defaults.\n */\n foregroundColor?: string;\n /**\n * Background color in RGBA. On Android, when the plugin applies subtitle\n * styling in fullscreen, omitted values fall back to `rgba(0,0,0,1)`. In\n * picture-in-picture, omitted values fall back to transparent when the plugin\n * applies its caption style (for example sidecar subtitles or non-empty\n * `subtitleOptions` that include a color override). An empty\n * `subtitleOptions` object alone does not select that fallback. With\n * font-size-only options, embedded cue styles stay enabled, so authored cue\n * backgrounds can remain visible in PiP. When `subtitleOptions` is absent,\n * embedded cue colors from the media can override the fallback. On iOS,\n * omitted colors are not set by the plugin; the platform uses the viewer's\n * caption appearance settings instead of fixed plugin defaults.\n */\n backgroundColor?: string;\n /**\n * Font size in CSS pixels. On Android, supplied values are rounded to the\n * nearest integer before applying. When omitted on embedded tracks without a\n * sidecar subtitle URI, Android uses `SubtitleView.setUserDefaultTextSize()`\n * (the user's system caption size), not a fixed 16 px size. Sidecar subtitles\n * still use a fixed default size when this property is omitted. On iOS,\n * values map to AVFoundation relative size where 16 equals the system default\n * (100%).\n */\n fontSize?: number;\n}\nexport interface FairPlayDrmOptions {\n /**\n * The URL to fetch the FairPlay certificate\n */\n certificateUrl?: string;\n /**\n * The URL to send the SPC and receive the CKC license (FairPlay license server URL)\n */\n contentKeySpcUrl?: string;\n /**\n * Optional FairPlay asset identifier used when generating the SPC.\n * Defaults to the `skd://` content identifier from the key request.\n */\n assetId?: string;\n}\nexport interface PlayreadyDrmOptions {\n /**\n * The URL to fetch the PlayReady license\n */\n certificateUrl?: string;\n}\nexport interface WidevineDrmOptions {\n /**\n * The URL to fetch the Widevine license\n */\n certificateUrl?: string;\n}\nexport interface DrmOptions {\n /**\n * FairPlay DRM configuration (iOS)\n */\n fairplay?: FairPlayDrmOptions;\n /**\n * PlayReady DRM configuration\n */\n playready?: PlayreadyDrmOptions;\n /**\n * Widevine DRM configuration (Android)\n */\n widevine?: WidevineDrmOptions;\n}\n"]}
|
|
@@ -221,7 +221,20 @@ enum VideoPlayerCastSeekSync {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
enum VideoPlayerCastOverlayLayout {
|
|
224
|
+
static let topRowOffset: CGFloat = 60
|
|
225
|
+
static let trailingInset: CGFloat = 16
|
|
226
|
+
static let controlSize: CGFloat = 44
|
|
227
|
+
static let verticalStackSpacing: CGFloat = 8
|
|
228
|
+
|
|
224
229
|
static func overlayView(for playerViewController: AVPlayerViewController) -> UIView? {
|
|
225
230
|
playerViewController.contentOverlayView
|
|
226
231
|
}
|
|
232
|
+
|
|
233
|
+
/// Cast uses the top trailing slot; chapter stacks below when Cast overlay is enabled.
|
|
234
|
+
static func chapterButtonTopOffset(chromecastEnabled: Bool) -> CGFloat {
|
|
235
|
+
guard chromecastEnabled else {
|
|
236
|
+
return topRowOffset
|
|
237
|
+
}
|
|
238
|
+
return topRowOffset + controlSize + verticalStackSpacing
|
|
239
|
+
}
|
|
227
240
|
}
|