@symbiote-native/video 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +67 -2
- package/build/angular/index.d.ts +4 -0
- package/build/angular/index.js +5 -0
- package/build/angular/inject-video-player.d.ts +4 -0
- package/build/angular/inject-video-player.js +6 -0
- package/build/angular/video-airplay-button/index.d.ts +12 -0
- package/build/angular/video-airplay-button/index.js +78 -0
- package/build/angular/video-view/index.d.ts +17 -0
- package/build/angular/video-view/index.js +97 -0
- package/build/core/constants.d.ts +12 -0
- package/build/core/constants.js +13 -0
- package/build/core/index.d.ts +10 -0
- package/build/core/index.js +8 -0
- package/build/core/native-module.d.ts +10 -0
- package/build/core/native-module.js +3 -0
- package/build/core/player-types.d.ts +221 -0
- package/build/core/player-types.js +1 -0
- package/build/core/video-airplay-button.d.ts +4 -0
- package/build/core/video-airplay-button.js +29 -0
- package/build/core/video-module.d.ts +12 -0
- package/build/core/video-module.js +21 -0
- package/build/core/video-player-controller.d.ts +15 -0
- package/build/core/video-player-controller.js +21 -0
- package/build/core/video-player.d.ts +7 -0
- package/build/core/video-player.js +22 -0
- package/build/core/video-source.d.ts +3 -0
- package/build/core/video-source.js +20 -0
- package/build/core/video-thumbnail.d.ts +4 -0
- package/build/core/video-thumbnail.js +3 -0
- package/build/core/video-view.d.ts +18 -0
- package/build/core/video-view.js +63 -0
- package/build/core/view-types.d.ts +90 -0
- package/build/core/view-types.js +1 -0
- package/build/react/index.d.ts +4 -0
- package/build/react/index.js +4 -0
- package/build/react/use-video-player.d.ts +7 -0
- package/build/react/use-video-player.js +11 -0
- package/build/react/video-view.d.ts +13 -0
- package/build/react/video-view.js +10 -0
- package/build/solid/index.d.ts +3 -0
- package/build/solid/index.js +4 -0
- package/build/solid/use-video-player.d.ts +8 -0
- package/build/solid/use-video-player.js +11 -0
- package/build/solid/video-view.d.ts +33 -0
- package/build/solid/video-view.js +6 -0
- package/build/svelte/index.d.ts +5 -0
- package/build/svelte/index.js +5 -0
- package/build/svelte/use-video-player.svelte.d.ts +10 -0
- package/build/svelte/use-video-player.svelte.js +11 -0
- package/build/svelte/video-airplay-button.svelte +12 -0
- package/build/svelte/video-airplay-button.svelte.d.ts +4 -0
- package/build/svelte/video-view.svelte +25 -0
- package/build/svelte/video-view.svelte.d.ts +9 -0
- package/build/vue/index.d.ts +3 -0
- package/build/vue/index.js +4 -0
- package/build/vue/use-video-player.d.ts +8 -0
- package/build/vue/use-video-player.js +16 -0
- package/build/vue/video-view.d.ts +5 -0
- package/build/vue/video-view.js +14 -0
- package/build-ngc/angular/index.d.ts +4 -0
- package/build-ngc/angular/index.js +6 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/angular/inject-video-player.d.ts +4 -0
- package/build-ngc/angular/inject-video-player.js +7 -0
- package/build-ngc/angular/inject-video-player.js.map +1 -0
- package/build-ngc/angular/video-airplay-button/index.d.ts +15 -0
- package/build-ngc/angular/video-airplay-button/index.js +37 -0
- package/build-ngc/angular/video-airplay-button/index.js.map +1 -0
- package/build-ngc/angular/video-view/index.d.ts +20 -0
- package/build-ngc/angular/video-view/index.js +56 -0
- package/build-ngc/angular/video-view/index.js.map +1 -0
- package/build-ngc/core/constants.d.ts +12 -0
- package/build-ngc/core/constants.js +14 -0
- package/build-ngc/core/constants.js.map +1 -0
- package/build-ngc/core/index.d.ts +10 -0
- package/build-ngc/core/index.js +9 -0
- package/build-ngc/core/index.js.map +1 -0
- package/build-ngc/core/native-module.d.ts +10 -0
- package/build-ngc/core/native-module.js +4 -0
- package/build-ngc/core/native-module.js.map +1 -0
- package/build-ngc/core/player-types.d.ts +221 -0
- package/build-ngc/core/player-types.js +2 -0
- package/build-ngc/core/player-types.js.map +1 -0
- package/build-ngc/core/video-airplay-button.d.ts +4 -0
- package/build-ngc/core/video-airplay-button.js +30 -0
- package/build-ngc/core/video-airplay-button.js.map +1 -0
- package/build-ngc/core/video-module.d.ts +12 -0
- package/build-ngc/core/video-module.js +22 -0
- package/build-ngc/core/video-module.js.map +1 -0
- package/build-ngc/core/video-player-controller.d.ts +15 -0
- package/build-ngc/core/video-player-controller.js +22 -0
- package/build-ngc/core/video-player-controller.js.map +1 -0
- package/build-ngc/core/video-player.d.ts +7 -0
- package/build-ngc/core/video-player.js +23 -0
- package/build-ngc/core/video-player.js.map +1 -0
- package/build-ngc/core/video-source.d.ts +3 -0
- package/build-ngc/core/video-source.js +21 -0
- package/build-ngc/core/video-source.js.map +1 -0
- package/build-ngc/core/video-thumbnail.d.ts +4 -0
- package/build-ngc/core/video-thumbnail.js +4 -0
- package/build-ngc/core/video-thumbnail.js.map +1 -0
- package/build-ngc/core/video-view.d.ts +18 -0
- package/build-ngc/core/video-view.js +64 -0
- package/build-ngc/core/video-view.js.map +1 -0
- package/build-ngc/core/view-types.d.ts +90 -0
- package/build-ngc/core/view-types.js +2 -0
- package/build-ngc/core/view-types.js.map +1 -0
- package/native-link.json +31 -0
- package/package.json +144 -3
- package/src/angular/index.ts +6 -0
- package/src/angular/inject-video-player.ts +20 -0
- package/src/angular/video-airplay-button/index.ts +39 -0
- package/src/angular/video-view/index.ts +58 -0
- package/src/core/constants.ts +16 -0
- package/src/core/index.ts +56 -0
- package/src/core/native-module.ts +16 -0
- package/src/core/player-types.ts +245 -0
- package/src/core/video-airplay-button.ts +45 -0
- package/src/core/video-module.ts +25 -0
- package/src/core/video-player-controller.ts +50 -0
- package/src/core/video-player.ts +38 -0
- package/src/core/video-source.ts +21 -0
- package/src/core/video-thumbnail.ts +7 -0
- package/src/core/video-view.ts +107 -0
- package/src/core/view-types.ts +114 -0
- package/src/react/index.ts +6 -0
- package/src/react/use-video-player.ts +22 -0
- package/src/react/video-view.ts +33 -0
- package/src/solid/index.ts +5 -0
- package/src/solid/use-video-player.ts +24 -0
- package/src/solid/video-view.ts +22 -0
- package/src/svelte/index.ts +7 -0
- package/src/svelte/svelte-ambient.d.ts +3 -0
- package/src/svelte/svelte-compile.test-helper.ts +6 -0
- package/src/svelte/use-video-player.svelte.ts +27 -0
- package/src/svelte/video-airplay-button.svelte +12 -0
- package/src/svelte/video-view.svelte +25 -0
- package/src/vue/index.ts +5 -0
- package/src/vue/use-video-player.ts +31 -0
- package/src/vue/video-view.ts +21 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { expoVideo } from './native-module';
|
|
2
|
+
import { parseSource } from './video-source';
|
|
3
|
+
const SYNC_REPLACE_WARNING = 'On iOS `VideoPlayer.replace` loads the asset data synchronously on the main thread, which can lead to UI freezes and will be deprecated in a future release. Switch to `replaceAsync` for better user experience.';
|
|
4
|
+
// Upstream patches these two methods onto the native prototype at load, a subclass does the same
|
|
5
|
+
class SourceParsingVideoPlayer extends expoVideo.VideoPlayer {
|
|
6
|
+
replace(source, disableWarning = false) {
|
|
7
|
+
if (!disableWarning)
|
|
8
|
+
console.warn(SYNC_REPLACE_WARNING);
|
|
9
|
+
super.replace(parseSource(source));
|
|
10
|
+
}
|
|
11
|
+
replaceAsync(source) {
|
|
12
|
+
return super.replaceAsync(parseSource(source));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Creates a player that does not release automatically, call `release()` when done
|
|
17
|
+
*
|
|
18
|
+
* The adapter hooks release it on unmount
|
|
19
|
+
*/
|
|
20
|
+
export function createVideoPlayer(source, playerBuilderOptions) {
|
|
21
|
+
return new SourceParsingVideoPlayer(parseSource(source), false, playerBuilderOptions);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=video-player.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-player.js","sourceRoot":"","sources":["../../src/core/video-player.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAM5C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,oBAAoB,GACxB,mNAAmN,CAAC;AAEtN,iGAAiG;AACjG,MAAM,wBAAyB,SAAQ,SAAS,CAAC,WAAW;IACjD,OAAO,CAAC,MAAoB,EAAE,cAAc,GAAG,KAAK;QAC3D,IAAI,CAAC,cAAc;YAAE,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACxD,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IACrC,CAAC;IAEQ,YAAY,CAAC,MAAoB;QACxC,OAAO,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IACjD,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAoB,EACpB,oBAAiD;IAEjD,OAAO,IAAI,wBAAwB,CACjC,WAAW,CAAC,MAAM,CAAC,EACnB,KAAK,EACL,oBAAoB,CACrB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { resolveAssetSource } from '@symbiote-native/engine';
|
|
2
|
+
function uriOfAsset(assetId) {
|
|
3
|
+
const resolved = resolveAssetSource(assetId);
|
|
4
|
+
const uri = Reflect.get(Object(resolved), 'uri');
|
|
5
|
+
if (typeof uri !== 'string') {
|
|
6
|
+
throw new Error(`The asset ${assetId} could not be resolved`);
|
|
7
|
+
}
|
|
8
|
+
return uri;
|
|
9
|
+
}
|
|
10
|
+
/** What the native player takes: a `require`d asset and a string both become a uri */
|
|
11
|
+
export function parseSource(source) {
|
|
12
|
+
if (typeof source === 'number')
|
|
13
|
+
return { uri: uriOfAsset(source) };
|
|
14
|
+
if (typeof source === 'string')
|
|
15
|
+
return { uri: source };
|
|
16
|
+
if (typeof source?.assetId === 'number' && !source.uri) {
|
|
17
|
+
return { ...source, uri: uriOfAsset(source.assetId) };
|
|
18
|
+
}
|
|
19
|
+
return source;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=video-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-source.js","sourceRoot":"","sources":["../../src/core/video-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,SAAS,UAAU,CAAC,OAAe;IACjC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAY,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IAC1D,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,aAAa,OAAO,wBAAwB,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,WAAW,CAAC,MAAoB;IAC9C,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,EAAE,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;IACnE,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IACvD,IAAI,OAAO,MAAM,EAAE,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACvD,OAAO,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;IACxD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { VideoThumbnail as IVideoThumbnailInstance } from './player-types';
|
|
2
|
+
/** The native class of a thumbnail, `generateThumbnailsAsync` resolves to instances of it */
|
|
3
|
+
export declare const VideoThumbnail: typeof IVideoThumbnailInstance;
|
|
4
|
+
export type VideoThumbnail = IVideoThumbnailInstance;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-thumbnail.js","sourceRoot":"","sources":["../../src/core/video-thumbnail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC,cAAc,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
2
|
+
import type { ISymbioteNode } from '@symbiote-native/engine';
|
|
3
|
+
export type IVideoViewHandle = {
|
|
4
|
+
/** Always shows the native controls */
|
|
5
|
+
enterFullscreen(): Promise<void>;
|
|
6
|
+
/** On Android it works only from a native listener, the JS runtime sleeps in fullscreen */
|
|
7
|
+
exitFullscreen(): Promise<void>;
|
|
8
|
+
/** Needs `supportsPictureInPicture` of the app setup, one player at a time */
|
|
9
|
+
startPictureInPicture(): Promise<void>;
|
|
10
|
+
stopPictureInPicture(): Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
export type IVideoView = {
|
|
13
|
+
handle: IVideoViewHandle;
|
|
14
|
+
/** `null` means the view cannot register and the caller renders nothing */
|
|
15
|
+
render(props: object): IDescriptor | null;
|
|
16
|
+
};
|
|
17
|
+
/** One per mounted view, `getNode` answers the host node once it exists */
|
|
18
|
+
export declare function createVideoView(getNode: () => ISymbioteNode | null | undefined): IVideoView;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Ядро `VideoView`: нативный view плеера, функции вызываются через `ViewPrototypes`
|
|
2
|
+
import { Platform, requireNativeModule, requireNativeViewManager, } from 'expo-modules-core';
|
|
3
|
+
import { el } from '@symbiote-native/components';
|
|
4
|
+
import { defineExpoNativeViews, defineExpoViewMethods, getNativeTag, isDevBuild, } from '@symbiote-native/engine';
|
|
5
|
+
import { VIDEO_MODULE_NAME, VIDEO_VIEW_NAMES } from './constants';
|
|
6
|
+
import { expoVideo } from './native-module';
|
|
7
|
+
const VIEW_NAMES = {
|
|
8
|
+
video: VIDEO_VIEW_NAMES.video,
|
|
9
|
+
surface: VIDEO_VIEW_NAMES.surface,
|
|
10
|
+
texture: VIDEO_VIEW_NAMES.texture,
|
|
11
|
+
};
|
|
12
|
+
// Регистрация идёт при рендере: побочный эффект барреля теряется в release
|
|
13
|
+
const views = defineExpoNativeViews(requireNativeViewManager, VIDEO_MODULE_NAME, VIEW_NAMES);
|
|
14
|
+
const callers = {
|
|
15
|
+
video: defineExpoViewMethods(requireNativeModule, VIDEO_MODULE_NAME, VIEW_NAMES.video),
|
|
16
|
+
surface: defineExpoViewMethods(requireNativeModule, VIDEO_MODULE_NAME, VIEW_NAMES.surface),
|
|
17
|
+
texture: defineExpoViewMethods(requireNativeModule, VIDEO_MODULE_NAME, VIEW_NAMES.texture),
|
|
18
|
+
};
|
|
19
|
+
function viewKeyFor(surfaceType) {
|
|
20
|
+
return Platform.select({
|
|
21
|
+
android: surfaceType === 'textureView' ? 'texture' : 'surface',
|
|
22
|
+
default: 'video',
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
// The native view takes the id of the shared object, not the player itself
|
|
26
|
+
function playerIdOf(player) {
|
|
27
|
+
if (player instanceof expoVideo.VideoPlayer) {
|
|
28
|
+
const id = Reflect.get(player, '__expo_shared_object_id__');
|
|
29
|
+
return typeof id === 'number' ? id : null;
|
|
30
|
+
}
|
|
31
|
+
return typeof player === 'number' ? player : null;
|
|
32
|
+
}
|
|
33
|
+
/** One per mounted view, `getNode` answers the host node once it exists */
|
|
34
|
+
export function createVideoView(getNode) {
|
|
35
|
+
let renderedKey = viewKeyFor(undefined);
|
|
36
|
+
async function call(method) {
|
|
37
|
+
const node = getNode();
|
|
38
|
+
if (!node || getNativeTag(node) === undefined)
|
|
39
|
+
return;
|
|
40
|
+
await callers[renderedKey](node, method, []);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
handle: {
|
|
44
|
+
enterFullscreen: () => call('enterFullscreen'),
|
|
45
|
+
exitFullscreen: () => call('exitFullscreen'),
|
|
46
|
+
startPictureInPicture: () => call('startPictureInPicture'),
|
|
47
|
+
stopPictureInPicture: () => call('stopPictureInPicture'),
|
|
48
|
+
},
|
|
49
|
+
render: props => {
|
|
50
|
+
renderedKey = viewKeyFor(Reflect.get(props, 'surfaceType'));
|
|
51
|
+
const view = views[renderedKey];
|
|
52
|
+
if (!view.ensureRegistered()) {
|
|
53
|
+
if (isDevBuild())
|
|
54
|
+
console.warn("'VideoView' is not available.");
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return el(view.name(), {
|
|
58
|
+
...Object.fromEntries(Object.entries(props)),
|
|
59
|
+
player: playerIdOf(Reflect.get(props, 'player')),
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=video-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-view.js","sourceRoot":"","sources":["../../src/core/video-view.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { IAccessibilityProps, IAriaProps, IResponderProps } from '@symbiote-native/components';
|
|
2
|
+
import type { IColorValue, IStyleProp, ISymbioteEvent, IViewStyle } from '@symbiote-native/engine';
|
|
3
|
+
import type { VideoPlayer } from './player-types';
|
|
4
|
+
/** `fill` stretches the video, `cover` crops it, `contain` letterboxes it */
|
|
5
|
+
export type IVideoContentFit = 'contain' | 'cover' | 'fill';
|
|
6
|
+
/** Android only: `textureView` for overlapping views, `surfaceView` otherwise */
|
|
7
|
+
export type IVideoSurfaceType = 'textureView' | 'surfaceView';
|
|
8
|
+
/** Android only, which buttons the native controls show */
|
|
9
|
+
export type IVideoButtonOptions = {
|
|
10
|
+
/** `false` by default */
|
|
11
|
+
showNext?: boolean;
|
|
12
|
+
/** `false` by default */
|
|
13
|
+
showPrevious?: boolean;
|
|
14
|
+
/** `true` by default */
|
|
15
|
+
showSeekForward?: boolean;
|
|
16
|
+
/** `true` by default */
|
|
17
|
+
showSeekBackward?: boolean;
|
|
18
|
+
/** `true` always, `false` never, `null` only when subtitles exist */
|
|
19
|
+
showSubtitles?: boolean | null;
|
|
20
|
+
/** `true` by default */
|
|
21
|
+
showSettings?: boolean;
|
|
22
|
+
/** `true` by default */
|
|
23
|
+
showPlayPause?: boolean;
|
|
24
|
+
/** `true` by default, fullscreen shows it anyway */
|
|
25
|
+
showBottomBar?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export type IVideoFullscreenOrientation = 'default' | 'portrait' | 'portraitUp' | 'portraitDown' | 'landscape' | 'landscapeLeft' | 'landscapeRight';
|
|
28
|
+
export type IVideoKeepFullscreenOnPiPStop = 'always' | 'autoEnter' | 'never';
|
|
29
|
+
export type IVideoFullscreenOptions = {
|
|
30
|
+
/** Shows the fullscreen button, `true` by default */
|
|
31
|
+
enable: boolean;
|
|
32
|
+
orientation?: IVideoFullscreenOrientation;
|
|
33
|
+
/** Leaves fullscreen when the device turns away from `orientation` */
|
|
34
|
+
autoExitOnRotate?: boolean;
|
|
35
|
+
/** iOS only, `autoEnter` by default */
|
|
36
|
+
keepFullscreenOnPiPStop?: IVideoKeepFullscreenOnPiPStop;
|
|
37
|
+
};
|
|
38
|
+
export type IVideoViewProps = IAccessibilityProps & IAriaProps & IResponderProps & {
|
|
39
|
+
/** From `useVideoPlayer` */
|
|
40
|
+
player?: VideoPlayer | null;
|
|
41
|
+
/** Always on in fullscreen, `true` by default */
|
|
42
|
+
nativeControls?: boolean;
|
|
43
|
+
/** `contain` by default */
|
|
44
|
+
contentFit?: IVideoContentFit;
|
|
45
|
+
fullscreenOptions?: IVideoFullscreenOptions;
|
|
46
|
+
/** iOS only, `true` by default */
|
|
47
|
+
showsTimecodes?: boolean;
|
|
48
|
+
/** Forbids skipping, `false` by default */
|
|
49
|
+
requiresLinearPlayback?: boolean;
|
|
50
|
+
buttonOptions?: IVideoButtonOptions;
|
|
51
|
+
/** Android only, must not change at runtime */
|
|
52
|
+
surfaceType?: IVideoSurfaceType;
|
|
53
|
+
/** iOS only, `{ dx: 0, dy: 0 }` by default */
|
|
54
|
+
contentPosition?: {
|
|
55
|
+
dx?: number;
|
|
56
|
+
dy?: number;
|
|
57
|
+
};
|
|
58
|
+
onPictureInPictureStart?: () => void;
|
|
59
|
+
onPictureInPictureStop?: () => void;
|
|
60
|
+
/** Needs `supportsPictureInPicture` of the app setup */
|
|
61
|
+
allowsPictureInPicture?: boolean;
|
|
62
|
+
/** Android 12+ and iOS, `false` by default */
|
|
63
|
+
startsPictureInPictureAutomatically?: boolean;
|
|
64
|
+
/** iOS 16+, `true` by default */
|
|
65
|
+
allowsVideoFrameAnalysis?: boolean;
|
|
66
|
+
onFullscreenEnter?: () => void;
|
|
67
|
+
onFullscreenExit?: () => void;
|
|
68
|
+
/** The first frame is rendered, also when the video track changes */
|
|
69
|
+
onFirstFrameRender?: () => void;
|
|
70
|
+
/** Android only, `false` by default */
|
|
71
|
+
useExoShutter?: boolean;
|
|
72
|
+
style?: IStyleProp<IViewStyle>;
|
|
73
|
+
testID?: string;
|
|
74
|
+
nativeID?: string;
|
|
75
|
+
onLayout?: (event: ISymbioteEvent) => void;
|
|
76
|
+
};
|
|
77
|
+
export type IVideoAirPlayButtonProps = IAccessibilityProps & IAriaProps & {
|
|
78
|
+
/** The icon colour while AirPlay is not active */
|
|
79
|
+
tint?: IColorValue;
|
|
80
|
+
/** The icon colour while AirPlay is active */
|
|
81
|
+
activeTint?: IColorValue;
|
|
82
|
+
/** Lists the video outputs first, `true` by default */
|
|
83
|
+
prioritizeVideoDevices?: boolean;
|
|
84
|
+
onBeginPresentingRoutes?: () => void;
|
|
85
|
+
onEndPresentingRoutes?: () => void;
|
|
86
|
+
style?: IStyleProp<IViewStyle>;
|
|
87
|
+
testID?: string;
|
|
88
|
+
nativeID?: string;
|
|
89
|
+
onLayout?: (event: ISymbioteEvent) => void;
|
|
90
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-types.js","sourceRoot":"","sources":["../../src/core/view-types.ts"],"names":[],"mappings":""}
|
package/native-link.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"android": {
|
|
3
|
+
"gradleProjectName": "expo-video",
|
|
4
|
+
"modules": [
|
|
5
|
+
{
|
|
6
|
+
"importPath": "expo.modules.video.VideoModule",
|
|
7
|
+
"className": "VideoModule",
|
|
8
|
+
"nativeName": "ExpoVideo"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"optionalManifestBundles": [
|
|
12
|
+
{
|
|
13
|
+
"id": "backgroundPlayback",
|
|
14
|
+
"label": "Background video playback",
|
|
15
|
+
"warning": "Requesting FOREGROUND_SERVICE_MEDIA_PLAYBACK triggers Play Console policy review for a foreground service, Google asks for a justification before you can publish.",
|
|
16
|
+
"nextSteps": "Set `staysActiveInBackground` and `showNowPlayingNotification` on the player. On iOS add `audio` to UIBackgroundModes in Info.plist yourself.",
|
|
17
|
+
"manifestPermissions": [
|
|
18
|
+
"android.permission.FOREGROUND_SERVICE",
|
|
19
|
+
"android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"
|
|
20
|
+
],
|
|
21
|
+
"manifestServices": [
|
|
22
|
+
{
|
|
23
|
+
"name": "expo.modules.video.playbackService.ExpoVideoPlaybackService",
|
|
24
|
+
"foregroundServiceType": "mediaPlayback",
|
|
25
|
+
"intentFilterActions": ["androidx.media3.session.MediaSessionService"]
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,147 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/video",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "expo-video wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Video playback: the player, the view, thumbnails, the cache and the AirPlay button.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/OneEyed1366/symbiote-native.git",
|
|
9
|
+
"directory": "packages/video"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/OneEyed1366/symbiote-native/tree/master/packages/video#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/OneEyed1366/symbiote-native/issues"
|
|
14
|
+
},
|
|
15
|
+
"author": "Andrey Prokopenko <psevdoproger@gmail.com>",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react-native",
|
|
18
|
+
"symbiote-native",
|
|
19
|
+
"expo-video",
|
|
20
|
+
"react",
|
|
21
|
+
"vue",
|
|
22
|
+
"svelte",
|
|
23
|
+
"solid",
|
|
24
|
+
"angular",
|
|
25
|
+
"video"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "./build/core/index.js",
|
|
29
|
+
"module": "./build/core/index.js",
|
|
30
|
+
"types": "./build/core/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./build/core/index.d.ts",
|
|
34
|
+
"default": "./build/core/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./vue": {
|
|
37
|
+
"types": "./build/vue/index.d.ts",
|
|
38
|
+
"default": "./build/vue/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./react": {
|
|
41
|
+
"types": "./build/react/index.d.ts",
|
|
42
|
+
"default": "./build/react/index.js"
|
|
43
|
+
},
|
|
44
|
+
"./svelte": "./src/svelte/index.ts",
|
|
45
|
+
"./solid": {
|
|
46
|
+
"types": "./build/solid/index.d.ts",
|
|
47
|
+
"default": "./build/solid/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./angular": {
|
|
50
|
+
"types": "./build-ngc/angular/index.d.ts",
|
|
51
|
+
"react-native": "./build-ngc/angular/index.js",
|
|
52
|
+
"default": "./src/angular/index.ts"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"src",
|
|
57
|
+
"build",
|
|
58
|
+
"build-ngc",
|
|
59
|
+
"native-link.json",
|
|
60
|
+
"!src/**/*.test.*",
|
|
61
|
+
"!src/**/*.spec.*",
|
|
62
|
+
"!src/**/*.detox.*"
|
|
63
|
+
],
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"access": "public"
|
|
66
|
+
},
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"expo-video": "57.0.5",
|
|
69
|
+
"expo-modules-core": "57.0.20",
|
|
70
|
+
"@symbiote-native/components": "3.1.4"
|
|
71
|
+
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"@angular/core": ">=20",
|
|
74
|
+
"@vue/runtime-core": "^3.5.13",
|
|
75
|
+
"react": ">=19.0.0",
|
|
76
|
+
"react-native": ">=0.86",
|
|
77
|
+
"solid-js": ">=1.9.0",
|
|
78
|
+
"svelte": ">=5.56.0",
|
|
79
|
+
"vue": ">=3.5.0",
|
|
80
|
+
"@symbiote-native/engine": "^1.5.0",
|
|
81
|
+
"@symbiote-native/react": "^3.2.0",
|
|
82
|
+
"@symbiote-native/angular": "^3.2.0",
|
|
83
|
+
"@symbiote-native/svelte": "^3.1.0",
|
|
84
|
+
"@symbiote-native/vue": "^3.2.0",
|
|
85
|
+
"@symbiote-native/solid": "^3.1.0"
|
|
86
|
+
},
|
|
87
|
+
"peerDependenciesMeta": {
|
|
88
|
+
"@symbiote-native/angular": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"@symbiote-native/react": {
|
|
92
|
+
"optional": true
|
|
93
|
+
},
|
|
94
|
+
"@symbiote-native/solid": {
|
|
95
|
+
"optional": true
|
|
96
|
+
},
|
|
97
|
+
"@symbiote-native/svelte": {
|
|
98
|
+
"optional": true
|
|
99
|
+
},
|
|
100
|
+
"@symbiote-native/vue": {
|
|
101
|
+
"optional": true
|
|
102
|
+
},
|
|
103
|
+
"@angular/core": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
106
|
+
"@vue/runtime-core": {
|
|
107
|
+
"optional": true
|
|
108
|
+
},
|
|
109
|
+
"react": {
|
|
110
|
+
"optional": true
|
|
111
|
+
},
|
|
112
|
+
"solid-js": {
|
|
113
|
+
"optional": true
|
|
114
|
+
},
|
|
115
|
+
"svelte": {
|
|
116
|
+
"optional": true
|
|
117
|
+
},
|
|
118
|
+
"vue": {
|
|
119
|
+
"optional": true
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"devDependencies": {
|
|
123
|
+
"@angular/compiler": "~22.0.8",
|
|
124
|
+
"@angular/compiler-cli": "~22.0.8",
|
|
125
|
+
"@angular/core": "~22.0.8",
|
|
126
|
+
"@types/node": "^26.0.0",
|
|
127
|
+
"@types/react": "^19.2.0",
|
|
128
|
+
"@vue/runtime-core": "^3.5.13",
|
|
129
|
+
"react": "19.2.3",
|
|
130
|
+
"solid-js": "^1.9.14",
|
|
131
|
+
"svelte": "^5.56.0",
|
|
132
|
+
"typescript": "~6.0.0",
|
|
133
|
+
"@symbiote-native/react": "3.2.0",
|
|
134
|
+
"@symbiote-native/solid": "3.1.0",
|
|
135
|
+
"@symbiote-native/vue": "3.2.0",
|
|
136
|
+
"@symbiote-native/angular": "3.2.0",
|
|
137
|
+
"@symbiote-native/engine": "1.5.0",
|
|
138
|
+
"@symbiote-native/test-utils": "0.4.6",
|
|
139
|
+
"@symbiote-native/svelte": "3.1.0"
|
|
140
|
+
},
|
|
141
|
+
"scripts": {
|
|
142
|
+
"typecheck": "tsc --build",
|
|
143
|
+
"clean": "rm -rf build-ngc",
|
|
144
|
+
"ng:build": "pnpm run clean && ngc -p tsconfig.angular.json",
|
|
145
|
+
"format": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
146
|
+
}
|
|
6
147
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @symbiote-native/video/angular: плеер, view, миниатюры, кэш и кнопка AirPlay на общем ядре
|
|
2
|
+
|
|
3
|
+
export { VideoView } from './video-view';
|
|
4
|
+
export { VideoAirPlayButton } from './video-airplay-button';
|
|
5
|
+
export { injectVideoPlayer } from './inject-video-player';
|
|
6
|
+
export * from '../core';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Angular twin of `useVideoPlayer`, `injectX` shape matching `injectAudioPlayer`
|
|
2
|
+
|
|
3
|
+
import type { Signal } from '@angular/core';
|
|
4
|
+
import { createResourceHook } from '@symbiote-native/angular';
|
|
5
|
+
import { createVideoPlayerController } from '../core/video-player-controller';
|
|
6
|
+
import type {
|
|
7
|
+
IVideoPlayerBuilderOptions,
|
|
8
|
+
IVideoSource,
|
|
9
|
+
VideoPlayer,
|
|
10
|
+
} from '../core';
|
|
11
|
+
|
|
12
|
+
const injectPlayerResource = createResourceHook(createVideoPlayerController);
|
|
13
|
+
|
|
14
|
+
/** Released with the injection context, `setup` runs once on each new player */
|
|
15
|
+
export const injectVideoPlayer = (
|
|
16
|
+
source: () => IVideoSource,
|
|
17
|
+
setup?: (player: VideoPlayer) => void,
|
|
18
|
+
options?: () => IVideoPlayerBuilderOptions | undefined,
|
|
19
|
+
): Signal<VideoPlayer> =>
|
|
20
|
+
injectPlayerResource(() => [source(), options?.(), setup]);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
+
import { DescriptorOutlet, NativeViewBase } from '@symbiote-native/angular';
|
|
3
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
4
|
+
import { renderVideoAirPlayButton } from '../../core';
|
|
5
|
+
import type { IVideoAirPlayButtonProps } from '../../core';
|
|
6
|
+
|
|
7
|
+
// One list is the inputs of the component and the props it hands to the native view
|
|
8
|
+
const AIRPLAY_INPUTS = [
|
|
9
|
+
'tint',
|
|
10
|
+
'activeTint',
|
|
11
|
+
'prioritizeVideoDevices',
|
|
12
|
+
'onBeginPresentingRoutes',
|
|
13
|
+
'onEndPresentingRoutes',
|
|
14
|
+
] as const;
|
|
15
|
+
|
|
16
|
+
// Types the inputs for the template, the decorators that would do it are replaced by `inputs`
|
|
17
|
+
export interface VideoAirPlayButton
|
|
18
|
+
extends Partial<
|
|
19
|
+
Pick<IVideoAirPlayButtonProps, (typeof AIRPLAY_INPUTS)[number]>
|
|
20
|
+
> {}
|
|
21
|
+
|
|
22
|
+
/** Angular twin of `expo-video`'s `VideoAirPlayButton`, a plain view off iOS */
|
|
23
|
+
@Component({
|
|
24
|
+
selector: 'VideoAirPlayButton',
|
|
25
|
+
standalone: true,
|
|
26
|
+
imports: [DescriptorOutlet],
|
|
27
|
+
inputs: [...AIRPLAY_INPUTS],
|
|
28
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
29
|
+
template: `@if (descriptor; as node) {
|
|
30
|
+
<symbiote-descriptor-outlet [node]="node" />
|
|
31
|
+
}`,
|
|
32
|
+
})
|
|
33
|
+
export class VideoAirPlayButton extends NativeViewBase {
|
|
34
|
+
protected override readonly propNames = AIRPLAY_INPUTS;
|
|
35
|
+
|
|
36
|
+
protected override renderView(props: object): IDescriptor | null {
|
|
37
|
+
return renderVideoAirPlayButton(props);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
+
import { DescriptorOutlet, NativeViewBase } from '@symbiote-native/angular';
|
|
3
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
4
|
+
import { createVideoView } from '../../core';
|
|
5
|
+
import type { IVideoViewProps } from '../../core';
|
|
6
|
+
|
|
7
|
+
// One list is the inputs of the component and the props it hands to the native view
|
|
8
|
+
const VIDEO_VIEW_INPUTS = [
|
|
9
|
+
'player',
|
|
10
|
+
'nativeControls',
|
|
11
|
+
'contentFit',
|
|
12
|
+
'fullscreenOptions',
|
|
13
|
+
'showsTimecodes',
|
|
14
|
+
'requiresLinearPlayback',
|
|
15
|
+
'buttonOptions',
|
|
16
|
+
'surfaceType',
|
|
17
|
+
'contentPosition',
|
|
18
|
+
'onPictureInPictureStart',
|
|
19
|
+
'onPictureInPictureStop',
|
|
20
|
+
'allowsPictureInPicture',
|
|
21
|
+
'startsPictureInPictureAutomatically',
|
|
22
|
+
'allowsVideoFrameAnalysis',
|
|
23
|
+
'onFullscreenEnter',
|
|
24
|
+
'onFullscreenExit',
|
|
25
|
+
'onFirstFrameRender',
|
|
26
|
+
'useExoShutter',
|
|
27
|
+
] as const;
|
|
28
|
+
|
|
29
|
+
// Types the inputs for the template, the decorators that would do it are replaced by `inputs`
|
|
30
|
+
export interface VideoView
|
|
31
|
+
extends Partial<Pick<IVideoViewProps, (typeof VIDEO_VIEW_INPUTS)[number]>> {}
|
|
32
|
+
|
|
33
|
+
/** Angular twin of `expo-video`'s `VideoView` */
|
|
34
|
+
@Component({
|
|
35
|
+
selector: 'VideoView',
|
|
36
|
+
standalone: true,
|
|
37
|
+
imports: [DescriptorOutlet],
|
|
38
|
+
inputs: [...VIDEO_VIEW_INPUTS],
|
|
39
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
40
|
+
template: `@if (descriptor; as node) {
|
|
41
|
+
<symbiote-descriptor-outlet [node]="node" />
|
|
42
|
+
}`,
|
|
43
|
+
})
|
|
44
|
+
export class VideoView extends NativeViewBase {
|
|
45
|
+
private readonly view = createVideoView(() => this.hostNode());
|
|
46
|
+
|
|
47
|
+
// The functions of the view are members of the component, a `@ViewChild` reaches them
|
|
48
|
+
readonly enterFullscreen = this.view.handle.enterFullscreen;
|
|
49
|
+
readonly exitFullscreen = this.view.handle.exitFullscreen;
|
|
50
|
+
readonly startPictureInPicture = this.view.handle.startPictureInPicture;
|
|
51
|
+
readonly stopPictureInPicture = this.view.handle.stopPictureInPicture;
|
|
52
|
+
|
|
53
|
+
protected override readonly propNames = VIDEO_VIEW_INPUTS;
|
|
54
|
+
|
|
55
|
+
protected override renderView(props: object): IDescriptor | null {
|
|
56
|
+
return this.view.render(props);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Apart from `native-module`, which resolves the module on import: the views need the name too
|
|
2
|
+
|
|
3
|
+
export const VIDEO_MODULE_NAME = 'ExpoVideo';
|
|
4
|
+
|
|
5
|
+
/** Upstream's label for its `UnavailabilityError` */
|
|
6
|
+
export const VIDEO_PACKAGE_NAME = 'expo-video';
|
|
7
|
+
|
|
8
|
+
export const VIDEO_VIEW_NAMES = {
|
|
9
|
+
/** The one iOS view */
|
|
10
|
+
video: 'VideoView',
|
|
11
|
+
/** The Android default, renders into a `SurfaceView` */
|
|
12
|
+
surface: 'SurfaceVideoView',
|
|
13
|
+
/** Android, for overlapping views */
|
|
14
|
+
texture: 'TextureVideoView',
|
|
15
|
+
airPlayButton: 'VideoAirPlayButtonView',
|
|
16
|
+
} as const;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export { VIDEO_MODULE_NAME } from './constants';
|
|
2
|
+
export type {
|
|
3
|
+
IVideoAudioMixingMode,
|
|
4
|
+
IVideoAudioTrack,
|
|
5
|
+
IVideoBufferOptions,
|
|
6
|
+
IVideoContentType,
|
|
7
|
+
IVideoDrmOptions,
|
|
8
|
+
IVideoDrmType,
|
|
9
|
+
IVideoMetadata,
|
|
10
|
+
IVideoPlayerBuilderOptions,
|
|
11
|
+
IVideoPlayerError,
|
|
12
|
+
IVideoPlayerEvents,
|
|
13
|
+
IVideoPlayerStatus,
|
|
14
|
+
IVideoRange,
|
|
15
|
+
IVideoScrubbingModeOptions,
|
|
16
|
+
IVideoSeekTolerance,
|
|
17
|
+
IVideoSize,
|
|
18
|
+
IVideoSource,
|
|
19
|
+
IVideoSourceObject,
|
|
20
|
+
IVideoSubtitleTrack,
|
|
21
|
+
IVideoThumbnailOptions,
|
|
22
|
+
IVideoTrack,
|
|
23
|
+
VideoPlayer,
|
|
24
|
+
} from './player-types';
|
|
25
|
+
export { createVideoPlayer } from './video-player';
|
|
26
|
+
export {
|
|
27
|
+
createVideoPlayerController,
|
|
28
|
+
type IVideoPlayerController,
|
|
29
|
+
} from './video-player-controller';
|
|
30
|
+
export {
|
|
31
|
+
clearVideoCacheAsync,
|
|
32
|
+
getCurrentVideoCacheSize,
|
|
33
|
+
isPictureInPictureSupported,
|
|
34
|
+
setVideoCacheSizeAsync,
|
|
35
|
+
} from './video-module';
|
|
36
|
+
export { parseSource } from './video-source';
|
|
37
|
+
export { VideoThumbnail } from './video-thumbnail';
|
|
38
|
+
export {
|
|
39
|
+
createVideoView,
|
|
40
|
+
type IVideoView,
|
|
41
|
+
type IVideoViewHandle,
|
|
42
|
+
} from './video-view';
|
|
43
|
+
export {
|
|
44
|
+
renderVideoAirPlayButton,
|
|
45
|
+
videoAirPlayButtonViewName,
|
|
46
|
+
} from './video-airplay-button';
|
|
47
|
+
export type {
|
|
48
|
+
IVideoAirPlayButtonProps,
|
|
49
|
+
IVideoButtonOptions,
|
|
50
|
+
IVideoContentFit,
|
|
51
|
+
IVideoFullscreenOptions,
|
|
52
|
+
IVideoFullscreenOrientation,
|
|
53
|
+
IVideoKeepFullscreenOnPiPStop,
|
|
54
|
+
IVideoSurfaceType,
|
|
55
|
+
IVideoViewProps,
|
|
56
|
+
} from './view-types';
|