@vouchfor/embeds 0.0.0-experiment.019a8c5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,202 @@
1
+ import { html, LitElement } from 'lit';
2
+ import { customElement, property, state } from 'lit/decorators.js';
3
+ import { ifDefined } from 'lit/directives/if-defined.js';
4
+ import { createRef, ref } from 'lit/directives/ref.js';
5
+
6
+ import type { Scene, TemplateInstance } from '@vouchfor/canvas-video';
7
+ import type { MediaPlayer, MediaPlayerProps } from '@vouchfor/media-player';
8
+ import type { Ref } from 'lit/directives/ref.js';
9
+ import type { Environment } from '~/utils/env';
10
+
11
+ import { EventForwardController } from './controllers/event-forwarder';
12
+ import { FetcherController } from './controllers/fetcher';
13
+ import { TrackingController } from './controllers/tracking';
14
+
15
+ import '@vouchfor/media-player';
16
+
17
+ type EmbedProps = Pick<MediaPlayerProps, 'data' | 'aspectRatio' | 'preload' | 'autoplay' | 'controls'> & {
18
+ env: Environment;
19
+ apiKey: string;
20
+ disableTracking?: boolean;
21
+ trackingSource?: string;
22
+ vouchId?: string;
23
+ templateId?: string;
24
+ };
25
+
26
+ @customElement('vouch-embed')
27
+ class Embed extends LitElement {
28
+ private _mediaPlayerRef: Ref<MediaPlayer> = createRef();
29
+
30
+ @property({ type: Object, attribute: 'data' }) data: EmbedProps['data'];
31
+ @property({ type: String }) vouchId: EmbedProps['vouchId'];
32
+ @property({ type: String }) templateId: EmbedProps['templateId'];
33
+
34
+ @property({ type: String }) env: EmbedProps['env'] = 'prod';
35
+ @property({ type: String }) apiKey: EmbedProps['apiKey'] = '';
36
+ @property({ type: Boolean }) disableTracking: EmbedProps['disableTracking'] = false;
37
+ @property({ type: String }) trackingSource: EmbedProps['trackingSource'] = 'embed';
38
+
39
+ @property({ type: Array }) controls: EmbedProps['controls'];
40
+ @property({ type: String }) preload: EmbedProps['preload'] = 'auto';
41
+ @property({ type: Boolean }) autoplay: EmbedProps['autoplay'] = false;
42
+ @property({ type: Number }) aspectRatio: EmbedProps['aspectRatio'] = 0;
43
+
44
+ private eventController = new EventForwardController(this, [
45
+ 'durationchange',
46
+ 'ended',
47
+ 'error',
48
+ 'loadeddata',
49
+ 'pause',
50
+ 'stalled',
51
+ 'play',
52
+ 'playing',
53
+ 'ratechange',
54
+ 'scenechange',
55
+ 'seeking',
56
+ 'seeked',
57
+ 'timeupdate',
58
+ 'volumechange',
59
+ 'waiting',
60
+
61
+ 'video:loadeddata',
62
+ 'video:seeking',
63
+ 'video:seeked',
64
+ 'video:play',
65
+ 'video:playing',
66
+ 'video:pause',
67
+ 'video:stalled',
68
+ 'video:timeupdate',
69
+ 'video:ended',
70
+ 'video:error'
71
+ ]);
72
+ private _fetcherController = new FetcherController(this);
73
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
74
+ // @ts-ignore
75
+ private _trackingController = new TrackingController(this);
76
+
77
+ @state() vouch: EmbedProps['data'];
78
+ @state() template: TemplateInstance | undefined;
79
+
80
+ get fetching() {
81
+ return this._fetcherController.fetching;
82
+ }
83
+
84
+ get waiting() {
85
+ return this._mediaPlayerRef.value?.waiting;
86
+ }
87
+
88
+ get seeking() {
89
+ return this._mediaPlayerRef.value?.seeking;
90
+ }
91
+
92
+ get paused() {
93
+ return this._mediaPlayerRef.value?.paused;
94
+ }
95
+
96
+ get captions() {
97
+ return this._mediaPlayerRef.value?.captions;
98
+ }
99
+
100
+ get fullscreen() {
101
+ return this._mediaPlayerRef.value?.fullscreen;
102
+ }
103
+
104
+ get duration() {
105
+ return this._mediaPlayerRef.value?.duration;
106
+ }
107
+
108
+ set currentTime(value: number) {
109
+ if (this._mediaPlayerRef.value) {
110
+ this._mediaPlayerRef.value.currentTime = value;
111
+ }
112
+ }
113
+ get currentTime() {
114
+ return this._mediaPlayerRef.value?.currentTime ?? 0;
115
+ }
116
+
117
+ set playbackRate(value: number) {
118
+ if (this._mediaPlayerRef.value) {
119
+ this._mediaPlayerRef.value.playbackRate = value;
120
+ }
121
+ }
122
+ get playbackRate() {
123
+ return this._mediaPlayerRef.value?.playbackRate ?? 1;
124
+ }
125
+
126
+ set volume(value: number) {
127
+ if (this._mediaPlayerRef.value) {
128
+ this._mediaPlayerRef.value.volume = value;
129
+ }
130
+ }
131
+ get volume() {
132
+ return this._mediaPlayerRef.value?.volume ?? 1;
133
+ }
134
+
135
+ set muted(value: boolean) {
136
+ if (this._mediaPlayerRef.value) {
137
+ this._mediaPlayerRef.value.muted = value;
138
+ }
139
+ }
140
+ get muted() {
141
+ return this._mediaPlayerRef.value?.muted ?? false;
142
+ }
143
+
144
+ get scene(): Scene | null {
145
+ return this._mediaPlayerRef.value?.scene ?? null;
146
+ }
147
+
148
+ get scenes(): Scene[] {
149
+ return this._mediaPlayerRef.value?.scenes ?? [];
150
+ }
151
+
152
+ get videoState() {
153
+ return this._mediaPlayerRef.value?.videoState;
154
+ }
155
+
156
+ get mediaPlayer() {
157
+ return this._mediaPlayerRef.value;
158
+ }
159
+
160
+ play() {
161
+ this._mediaPlayerRef.value?.play();
162
+ }
163
+
164
+ pause() {
165
+ this._mediaPlayerRef.value?.pause();
166
+ }
167
+
168
+ setScene(index: number) {
169
+ this._mediaPlayerRef.value?.setScene(index);
170
+ }
171
+
172
+ render() {
173
+ return html`
174
+ <vmp-new-media-player
175
+ ${ref(this._mediaPlayerRef)}
176
+ ${this.eventController.register()}
177
+ ?autoplay=${this.autoplay}
178
+ ?loading=${this.fetching}
179
+ .data=${this.vouch}
180
+ .template=${this.template}
181
+ aspectRatio=${ifDefined(this.aspectRatio)}
182
+ preload=${ifDefined(this.preload)}
183
+ .controls=${this.controls}
184
+ ></vmp-new-media-player>
185
+ `;
186
+ }
187
+ }
188
+
189
+ declare global {
190
+ interface HTMLElementTagNameMap {
191
+ 'vouch-embed': Embed;
192
+ }
193
+
194
+ namespace JSX {
195
+ interface IntrinsicElements {
196
+ 'vouch-embed': Embed;
197
+ }
198
+ }
199
+ }
200
+
201
+ export { Embed };
202
+ export type { EmbedProps };
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { Embed } from '~/components/Embed';
@@ -0,0 +1,64 @@
1
+ type Environment = 'local' | 'dev' | 'staging' | 'prod';
2
+
3
+ type GetEnvUrlsReturn = {
4
+ videoUrl: string;
5
+ publicApiUrl: string;
6
+ embedApiUrl: string;
7
+ };
8
+
9
+ const devVideoUrl = 'https://d2rxhdlm2q91uk.cloudfront.net';
10
+ const stagingVideoUrl = 'https://d1ix11aj5kfygl.cloudfront.net';
11
+ const prodVideoUrl = 'https://d157jlwnudd93d.cloudfront.net';
12
+
13
+ const devPublicApiUrl = 'https://bshyfw4h5a.execute-api.ap-southeast-2.amazonaws.com/dev';
14
+ const stagingPublicApiUrl = 'https://gyzw7rpbq3.execute-api.ap-southeast-2.amazonaws.com/staging';
15
+ const prodPublicApiUrl = 'https://vfcjuim1l3.execute-api.ap-southeast-2.amazonaws.com/prod';
16
+
17
+ const localEmbedApiUrl = 'http://localhost:6060/v2';
18
+ const devEmbedApiUrl = 'https://embed-dev.vouchfor.com/v2';
19
+ const stagingEmbedApiUrl = 'https://embed-staging.vouchfor.com/v2';
20
+ const prodEmbedApiUrl = 'https://embed.vouchfor.com/v2';
21
+
22
+ // We are handling the case where env is an unknown string so the ts error is a lie
23
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
24
+ // @ts-ignore
25
+ function getEnvUrls(env: Environment): GetEnvUrlsReturn {
26
+ if (!['local', 'dev', 'staging', 'prod'].includes(env)) {
27
+ throw new Error(`Unknown environment: ${env}`);
28
+ }
29
+
30
+ if (env === 'local') {
31
+ return {
32
+ videoUrl: devVideoUrl,
33
+ publicApiUrl: devPublicApiUrl,
34
+ embedApiUrl: localEmbedApiUrl
35
+ };
36
+ }
37
+
38
+ if (env === 'dev') {
39
+ return {
40
+ videoUrl: devVideoUrl,
41
+ publicApiUrl: devPublicApiUrl,
42
+ embedApiUrl: devEmbedApiUrl
43
+ };
44
+ }
45
+
46
+ if (env === 'staging') {
47
+ return {
48
+ videoUrl: stagingVideoUrl,
49
+ publicApiUrl: stagingPublicApiUrl,
50
+ embedApiUrl: stagingEmbedApiUrl
51
+ };
52
+ }
53
+
54
+ if (env === 'prod') {
55
+ return {
56
+ videoUrl: prodVideoUrl,
57
+ publicApiUrl: prodPublicApiUrl,
58
+ embedApiUrl: prodEmbedApiUrl
59
+ };
60
+ }
61
+ }
62
+
63
+ export { devEmbedApiUrl, stagingEmbedApiUrl, prodEmbedApiUrl, getEnvUrls };
64
+ export type { Environment };
@@ -0,0 +1,13 @@
1
+ function forwardEvent(type: string, fromElement: HTMLElement, toElement: HTMLElement) {
2
+ function forwarder(event: Event) {
3
+ toElement.dispatchEvent(new CustomEvent(event.type, event));
4
+ }
5
+
6
+ fromElement.addEventListener(type, forwarder);
7
+
8
+ return () => {
9
+ fromElement.removeEventListener(type, forwarder);
10
+ };
11
+ }
12
+
13
+ export { forwardEvent };
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />