@glitchlab/vue-video-player 1.0.2 → 1.1.1

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 CHANGED
@@ -100,6 +100,7 @@ Then use the component anywhere — no manual import required:
100
100
  | `muted` | `boolean` | `true` | Mute the video. Required for autoplay in most browsers. |
101
101
  | `loop` | `boolean` | `false` | Loop playback. |
102
102
  | `controls` | `boolean` | `false` | Show native browser controls. |
103
+ | `autoPlay` | `boolean` | `false` | Start playback as soon as the source is ready. Works for HLS (after `MANIFEST_PARSED`), native MP4/WebM (after `loadedmetadata`), and YouTube embeds. Browsers block sound-on autoplay, so this only fires when `muted` is also `true` (the default). |
103
104
  | `frameMaxWidth` | `{ desktop?: string; mobile?: string }` | `{ desktop: "960px", mobile: "420px" }` | Max width of the player in each device mode. |
104
105
  | `aspectRatio` | `{ desktop?: AspectRatio; mobile?: AspectRatio }` | `{ desktop: "16/9", mobile: "9/16" }` | Aspect ratio per device mode. `AspectRatio` is `` `${number}/${number}` ``. |
105
106
  | `hlsConfig` | `Hls.HlsConfig` | — | Optional hls.js config. Use a stable reference (e.g. `shallowRef`) to avoid HLS rebuilds.|
@@ -121,6 +122,39 @@ Then use the component anywhere — no manual import required:
121
122
 
122
123
  ---
123
124
 
125
+ ## YouTube URLs
126
+
127
+ Pass any common YouTube URL as `src` and the player swaps the `<video>` element for a privacy-enhanced (`youtube-nocookie.com`) embed inside the same styled frame — no extra prop needed:
128
+
129
+ ```vue
130
+ <VueVideoPlayer src="https://www.youtube.com/watch?v=dQw4w9WgXcQ" />
131
+ <VueVideoPlayer src="https://youtu.be/dQw4w9WgXcQ?t=90" :auto-play="true" />
132
+ <VueVideoPlayer src="https://www.youtube.com/shorts/dQw4w9WgXcQ" />
133
+ ```
134
+
135
+ Recognised forms: `youtube.com/watch?v=ID`, `youtu.be/ID`, `youtube.com/embed/ID`, `youtube.com/shorts/ID`, `youtube.com/live/ID`, `music.youtube.com/watch?v=ID`, and bare 11-character IDs. A `?t=` / `?start=` timestamp in the URL is honored.
136
+
137
+ ### Which props work over YouTube
138
+
139
+ | Prop | YouTube behavior |
140
+ |---------------------------------------|---------------------------------------------------------------------------------------------------|
141
+ | `muted` | ✅ Mutes the embed (`mute=1`). |
142
+ | `loop` | ✅ Loops the single video (`loop=1` + `playlist=<id>`, YouTube's required workaround). |
143
+ | `controls` | ✅ Shows/hides YouTube's controls (`controls=1` / `controls=0`). |
144
+ | `autoPlay` | ✅ Autoplays (`autoplay=1`). YouTube + browsers force muted autoplay, so `mute=1` is set too — even if `:muted="false"`. |
145
+ | `showDeviceToggle` / `defaultDevice` | ✅ The desktop/mobile aspect-ratio toggle still works. |
146
+ | `closable` / `@close` | ✅ The close button still renders and emits. |
147
+ | `class` / `frameMaxWidth` / `aspectRatio` | ✅ Frame styling, sizing, and aspect ratio all apply. |
148
+ | `hoverPlay` | ❌ **No effect.** Hover-to-play needs programmatic pause, which requires the YouTube IFrame Player API (not loaded). YouTube's own controls handle starting playback. |
149
+ | `tooltipText` | ❌ **No effect.** The tooltip is attached to the centered play-button overlay, which isn't rendered for YouTube. |
150
+ | `poster` | ❌ **No effect.** YouTube shows its own video thumbnail; a custom poster would require an overlay layer. |
151
+ | `default` slot (`<track>` captions) | ❌ **No effect.** There's no `<video>` element to attach `<track>` to — use YouTube's own caption settings. |
152
+ | `hlsConfig` / `isHls` | ❌ **No effect.** Not an HLS stream. |
153
+
154
+ > If you need `hoverPlay`, a custom poster, or a play-button overlay over a YouTube video, you'd need the YouTube IFrame Player API integrated — that's not in this build (it'd add a ~30 KB external script). Open an issue if it matters for your use case.
155
+
156
+ ---
157
+
124
158
  ## Examples
125
159
 
126
160
  ### Looping background video, no UI chrome
@@ -130,10 +164,22 @@ Then use the component anywhere — no manual import required:
130
164
  src="/videos/hero.m3u8"
131
165
  :muted="true"
132
166
  :loop="true"
167
+ :auto-play="true"
133
168
  :show-device-toggle="false"
134
169
  />
135
170
  ```
136
171
 
172
+ ### Autoplay an HLS stream
173
+
174
+ ```vue
175
+ <VueVideoPlayer
176
+ src="https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8"
177
+ :auto-play="true"
178
+ />
179
+ ```
180
+
181
+ > `autoPlay` waits for the manifest to parse (HLS) or for `loadedmetadata` (native), then calls `.play()` for you. Browsers reject sound-on autoplay without a prior user gesture — `muted` (the default) is the reliable path.
182
+
137
183
  ### Hover-to-play with a tooltip
138
184
 
139
185
  ```vue
@@ -10,6 +10,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
10
10
  muted?: boolean;
11
11
  loop?: boolean;
12
12
  controls?: boolean;
13
+ autoPlay?: boolean;
13
14
  playsInline?: boolean;
14
15
  preload?: string;
15
16
  poster?: string;
@@ -18,6 +19,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
18
19
  muted: boolean;
19
20
  loop: boolean;
20
21
  controls: boolean;
22
+ autoPlay: boolean;
21
23
  playsInline: boolean;
22
24
  preload: string;
23
25
  }>>, {
@@ -32,6 +34,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
32
34
  muted?: boolean;
33
35
  loop?: boolean;
34
36
  controls?: boolean;
37
+ autoPlay?: boolean;
35
38
  playsInline?: boolean;
36
39
  preload?: string;
37
40
  poster?: string;
@@ -40,6 +43,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
40
43
  muted: boolean;
41
44
  loop: boolean;
42
45
  controls: boolean;
46
+ autoPlay: boolean;
43
47
  playsInline: boolean;
44
48
  preload: string;
45
49
  }>>> & Readonly<{
@@ -49,6 +53,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
49
53
  muted: boolean;
50
54
  loop: boolean;
51
55
  controls: boolean;
56
+ autoPlay: boolean;
52
57
  playsInline: boolean;
53
58
  preload: string;
54
59
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
@@ -1 +1 @@
1
- {"version":3,"file":"HLSPlayer.vue.d.ts","sourceRoot":"","sources":["../src/HLSPlayer.vue"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAoGxC,iBAAS,cAAc;qBAoDO,GAAG;EAGhC;AAsBD,QAAA,MAAM,eAAe;SAOZ,MAAM;gBACC,SAAS;YACb,OAAO;YACP,OAAO;WACR,OAAO;eACH,OAAO;kBACJ,OAAO;cACX,MAAM;aACP,MAAM;YACP,MAAM;;;;;;;;;;;;;SATT,MAAM;gBACC,SAAS;YACb,OAAO;YACP,OAAO;WACR,OAAO;eACH,OAAO;kBACJ,OAAO;cACX,MAAM;aACP,MAAM;YACP,MAAM;;;;;;;;;;;WANN,OAAO;UACR,OAAO;cACH,OAAO;iBACJ,OAAO;aACX,MAAM;4EAKlB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAAvG,wBAAwG;AACxG,KAAK,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,KAAK,6BAA6B,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE;CAAE,CAAC;AAC9M,KAAK,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI;KAE1B,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;QACxE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;KACb,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AACN,KAAK,cAAc,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC;AACxD,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAAE,QAAO;QAClD,MAAM,EAAE,CAAC,CAAC;KACT,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"HLSPlayer.vue.d.ts","sourceRoot":"","sources":["../src/HLSPlayer.vue"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AA0HxC,iBAAS,cAAc;qBAoDO,GAAG;EAGhC;AAuBD,QAAA,MAAM,eAAe;SAOZ,MAAM;gBACC,SAAS;YACb,OAAO;YACP,OAAO;WACR,OAAO;eACH,OAAO;eACP,OAAO;kBACJ,OAAO;cACX,MAAM;aACP,MAAM;YACP,MAAM;;;;;;;;;;;;;;SAVT,MAAM;gBACC,SAAS;YACb,OAAO;YACP,OAAO;WACR,OAAO;eACH,OAAO;eACP,OAAO;kBACJ,OAAO;cACX,MAAM;aACP,MAAM;YACP,MAAM;;;;;;;;;;;;WAPN,OAAO;UACR,OAAO;cACH,OAAO;cACP,OAAO;iBACJ,OAAO;aACX,MAAM;4EAKlB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAAvG,wBAAwG;AACxG,KAAK,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,KAAK,6BAA6B,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE;CAAE,CAAC;AAC9M,KAAK,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI;KAE1B,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;QACxE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;KACb,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AACN,KAAK,cAAc,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC;AACxD,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAAE,QAAO;QAClD,MAAM,EAAE,CAAC,CAAC;KACT,CAAA;CAAE,CAAC"}
@@ -13,6 +13,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
13
13
  muted: boolean;
14
14
  loop: boolean;
15
15
  controls: boolean;
16
+ autoPlay: boolean;
16
17
  closable: boolean;
17
18
  class: string;
18
19
  }>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
@@ -29,6 +30,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
29
30
  muted: boolean;
30
31
  loop: boolean;
31
32
  controls: boolean;
33
+ autoPlay: boolean;
32
34
  closable: boolean;
33
35
  class: string;
34
36
  }>>> & Readonly<{
@@ -39,6 +41,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
39
41
  muted: boolean;
40
42
  loop: boolean;
41
43
  controls: boolean;
44
+ autoPlay: boolean;
42
45
  class: string;
43
46
  showDeviceToggle: boolean;
44
47
  defaultDevice: DeviceMode;
@@ -1 +1 @@
1
- {"version":3,"file":"VideoPlayer.vue.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.vue"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAsHlE,iBAAS,cAAc;qBAwRO,GAAG;EAGhC;AAwBD,QAAA,MAAM,eAAe;YAKsE,MAAM;eAAa,OAAO;;;;;;;;;;;;;;;YAA1B,MAAM;eAAa,OAAO;;;;;;;;;;;;;;;;;;WAA1B,MAAM;;;;cAAa,OAAO;4EAEnH,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAAvG,wBAAwG;AACxG,KAAK,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,KAAK,6BAA6B,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE;CAAE,CAAC;AAC9M,KAAK,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI;KAE1B,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;QACxE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;KACb,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AACN,KAAK,cAAc,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC;AACxD,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAAE,QAAO;QAClD,MAAM,EAAE,CAAC,CAAC;KACT,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"VideoPlayer.vue.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.vue"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAuIlE,iBAAS,cAAc;qBAiTO,GAAG;EAGhC;AA0BD,QAAA,MAAM,eAAe;YAKsE,MAAM;eAAa,OAAO;;;;;;;;;;;;;;;;YAA1B,MAAM;eAAa,OAAO;;;;;;;;;;;;;;;;;;;;WAA1B,MAAM;;;;cAAa,OAAO;4EAEnH,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAAvG,wBAAwG;AACxG,KAAK,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,KAAK,6BAA6B,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE;CAAE,CAAC;AAC9M,KAAK,kBAAkB,CAAC,CAAC,EAAE,CAAC,IAAI;KAE1B,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;QACxE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;KACb,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AACN,KAAK,cAAc,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC;AACxD,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAAE,QAAO;QAClD,MAAM,EAAE,CAAC,CAAC;KACT,CAAA;CAAE,CAAC"}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),k=require("hls.js"),b=["muted","loop","controls","playsinline","preload","poster"],w=e.defineComponent({__name:"HLSPlayer",props:{src:{},hlsConfig:{},isHls:{type:Boolean},muted:{type:Boolean,default:!0},loop:{type:Boolean,default:!1},controls:{type:Boolean,default:!1},playsInline:{type:Boolean,default:!0},preload:{default:"metadata"},poster:{},class:{}},emits:["play","pause"],setup(o,{expose:c,emit:a}){const l=o,m=a,r=e.ref(null),i=e.ref(null),p=globalThis.window!==void 0&&k.isSupported(),v=n=>!!l.isHls||p&&n.endsWith(".m3u8");function C(){i.value&&(i.value.destroy(),i.value=null);const n=r.value;if(n){for(n.pause(),n.removeAttribute("src");n.firstChild;)n.firstChild.remove();n.load()}}function y(n){const u=r.value;if(!(!u||!n))if(C(),v(n)){const d=new k(l.hlsConfig);i.value=d,d.attachMedia(u),d.loadSource(n),d.on(k.Events.ERROR,(h,g)=>{g.fatal&&(d.destroy(),i.value=null)})}else u.src=n,u.load()}return e.onMounted(()=>{l.src&&y(l.src)}),e.watch(()=>l.src,n=>{n&&y(n)}),e.onUnmounted(C),c({videoEl:r}),(n,u)=>(e.openBlock(),e.createElementBlock("video",{ref_key:"videoEl",ref:r,muted:o.muted,loop:o.loop,controls:o.controls,playsinline:o.playsInline,preload:o.preload,poster:o.poster,class:e.normalizeClass(l.class),onPlay:u[0]||(u[0]=d=>m("play")),onPause:u[1]||(u[1]=d=>m("pause"))},[e.renderSlot(n.$slots,"default")],42,b))}}),M={name:"IconDesktop"},N=e.defineComponent({...M,props:{class:{}},setup(o){const c=o;return(a,l)=>(e.openBlock(),e.createElementBlock("svg",{class:e.normalizeClass(["gvp-icon",c.class]),width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},[...l[0]||(l[0]=[e.createElementVNode("path",{d:"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),e.createElementVNode("path",{d:"M11 15H13",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round","stroke-linejoin":"round"},null,-1),e.createElementVNode("path",{d:"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),e.createElementVNode("path",{d:"M7 22H17",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1)])],2))}}),x={name:"IconMobile"},P=e.defineComponent({...x,props:{class:{}},setup(o){const c=o;return(a,l)=>(e.openBlock(),e.createElementBlock("svg",{class:e.normalizeClass(["gvp-icon",c.class]),width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},[...l[0]||(l[0]=[e.createElementVNode("path",{d:"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round"},null,-1),e.createElementVNode("path",{d:"M11 19H13",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1),e.createElementVNode("path",{d:"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2",stroke:"currentColor","stroke-width":"2","stroke-linejoin":"round"},null,-1)])],2))}}),$={name:"IconPlay"},L=e.defineComponent({...$,props:{class:{}},setup(o){const c=o;return(a,l)=>(e.openBlock(),e.createElementBlock("svg",{class:e.normalizeClass(["gvp-icon",c.class]),width:"22",height:"22",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},[...l[0]||(l[0]=[e.createElementVNode("path",{d:"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z",fill:"currentColor"},null,-1)])],2))}}),H={name:"IconX"},S=e.defineComponent({...H,props:{class:{}},setup(o){const c=o;return(a,l)=>(e.openBlock(),e.createElementBlock("svg",{class:e.normalizeClass(["gvp-icon",c.class]),width:"14",height:"14",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},[...l[0]||(l[0]=[e.createElementVNode("path",{d:"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z",fill:"currentColor"},null,-1)])],2))}}),R={key:0,class:"gvp-toggle"},z={class:"gvp-toggle-pill"},T=["aria-pressed"],D=["aria-pressed"],I={key:2,class:"gvp-play-wrap"},W={key:0,class:"gvp-tooltip",role:"tooltip"},j=e.defineComponent({__name:"VideoPlayer",props:{src:{},poster:{},showDeviceToggle:{type:Boolean,default:!0},defaultDevice:{default:"desktop"},hoverPlay:{type:Boolean,default:!1},tooltipText:{},muted:{type:Boolean,default:!0},loop:{type:Boolean,default:!1},controls:{type:Boolean,default:!1},frameMaxWidth:{},aspectRatio:{},hlsConfig:{},isHls:{type:Boolean},class:{default:""},closable:{type:Boolean,default:!1}},emits:["close","play","pause"],setup(o,{emit:c}){const a=o,l=c,m=e.ref(null),r=e.ref(a.defaultDevice),i=e.ref(!1),p=e.ref(!1),v=e.ref(null),C=e.computed(()=>{var s,t;return r.value==="mobile"?((s=a.aspectRatio)==null?void 0:s.mobile)??"9/16":((t=a.aspectRatio)==null?void 0:t.desktop)??"16/9"}),y=e.computed(()=>{var s,t;return r.value==="mobile"?((s=a.frameMaxWidth)==null?void 0:s.mobile)??"420px":((t=a.frameMaxWidth)==null?void 0:t.desktop)??"960px"}),n=e.computed(()=>{var s;return((s=m.value)==null?void 0:s.videoEl)??null});async function u(){const s=n.value;if(s)try{s.readyState<2&&s.load();const t=s.play();v.value=t,await t,i.value=!0}catch{i.value=!1}finally{v.value=null}}async function d(){const s=n.value;if(s){if(v.value)try{await v.value}catch{}s.pause()}}async function h(){a.hoverPlay&&await u()}async function g(){a.hoverPlay&&(await d(),i.value=!1)}async function B(){const s=n.value;s&&(s.paused?await u():(await d(),i.value=!1))}function E(){p.value=!0,h()}function V(){p.value=!1,g()}return(s,t)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["gvp-root",a.class]),style:e.normalizeStyle({width:y.value,aspectRatio:C.value}),onMouseenter:E,onMouseleave:V},[e.createVNode(w,{ref_key:"hlsPlayerRef",ref:m,controls:o.controls,"hls-config":o.hlsConfig,"is-hls":o.isHls,loop:o.loop,muted:o.muted,"plays-inline":!0,poster:o.poster,src:o.src,class:"gvp-video",preload:"metadata",onPause:t[0]||(t[0]=f=>{i.value=!1,l("pause")}),onPlay:t[1]||(t[1]=f=>{i.value=!0,l("play")})},{default:e.withCtx(()=>[e.renderSlot(s.$slots,"default")]),_:3},8,["controls","hls-config","is-hls","loop","muted","poster","src"]),t[8]||(t[8]=e.createElementVNode("div",{class:"gvp-vignette"},null,-1)),o.showDeviceToggle?(e.openBlock(),e.createElementBlock("div",R,[e.createElementVNode("div",z,[e.createElementVNode("button",{"aria-pressed":r.value==="desktop",class:e.normalizeClass(["gvp-toggle-btn",{"is-active":r.value==="desktop"}]),"aria-label":"Desktop view",type:"button",onClick:t[2]||(t[2]=f=>r.value="desktop")},[e.createVNode(N)],10,T),t[7]||(t[7]=e.createElementVNode("div",{class:"gvp-toggle-divider"},null,-1)),e.createElementVNode("button",{"aria-pressed":r.value==="mobile",class:e.normalizeClass(["gvp-toggle-btn",{"is-active":r.value==="mobile"}]),"aria-label":"Mobile view",type:"button",onClick:t[3]||(t[3]=f=>r.value="mobile")},[e.createVNode(P)],10,D)])])):e.createCommentVNode("",!0),o.closable?(e.openBlock(),e.createElementBlock("button",{key:1,"aria-label":"Close",class:"gvp-close",type:"button",onClick:t[4]||(t[4]=f=>l("close"))},[e.createVNode(S)])):e.createCommentVNode("",!0),i.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",I,[e.createElementVNode("button",{"aria-label":"Play",class:"gvp-play",type:"button",onClick:B,onMouseenter:t[5]||(t[5]=f=>p.value=!0),onMouseleave:t[6]||(t[6]=f=>p.value=!1)},[e.createVNode(L),o.tooltipText&&p.value?(e.openBlock(),e.createElementBlock("span",W,e.toDisplayString(o.tooltipText),1)):e.createCommentVNode("",!0)],32)])),t[9]||(t[9]=e.createElementVNode("div",{class:"gvp-bottom-fade"},null,-1))],38))}});exports.HLSPlayer=w;exports.VueVideoPlayer=j;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),g=require("hls.js"),S=["muted","loop","controls","autoplay","playsinline","preload","poster"],B=e.defineComponent({__name:"HLSPlayer",props:{src:{},hlsConfig:{},isHls:{type:Boolean},muted:{type:Boolean,default:!0},loop:{type:Boolean,default:!1},controls:{type:Boolean,default:!1},autoPlay:{type:Boolean,default:!1},playsInline:{type:Boolean,default:!0},preload:{default:"metadata"},poster:{},class:{}},emits:["play","pause"],setup(t,{expose:n,emit:l}){const o=t,p=l,c=e.ref(null),u=e.ref(null),i=globalThis.window!==void 0&&g.isSupported(),C=r=>!!o.isHls||i&&r.endsWith(".m3u8");let m;function v(){m==null||m(),m=void 0,u.value&&(u.value.destroy(),u.value=null);const r=c.value;if(r){for(r.pause(),r.removeAttribute("src");r.firstChild;)r.firstChild.remove();r.load()}}function k(r){const d=c.value;if(!d||!r)return;v();const f=()=>{o.autoPlay&&d.play().catch(()=>{})};if(C(r)){const y=new g(o.hlsConfig);u.value=y,y.attachMedia(d),y.loadSource(r),y.on(g.Events.MANIFEST_PARSED,f),y.on(g.Events.ERROR,(w,b)=>{b.fatal&&(y.destroy(),u.value=null)})}else d.src=r,d.load(),d.addEventListener("loadedmetadata",f,{once:!0}),m=()=>{d.removeEventListener("loadedmetadata",f)}}return e.onMounted(()=>{o.src&&k(o.src)}),e.watch(()=>o.src,r=>{r&&k(r)}),e.onUnmounted(v),n({videoEl:c}),(r,d)=>(e.openBlock(),e.createElementBlock("video",{ref_key:"videoEl",ref:c,muted:t.muted,loop:t.loop,controls:t.controls,autoplay:t.autoPlay,playsinline:t.playsInline,preload:t.preload,poster:t.poster,class:e.normalizeClass(o.class),onPlay:d[0]||(d[0]=f=>p("play")),onPause:d[1]||(d[1]=f=>p("pause"))},[e.renderSlot(r.$slots,"default")],42,S))}}),L={name:"IconDesktop"},T=e.defineComponent({...L,props:{class:{}},setup(t){const n=t;return(l,o)=>(e.openBlock(),e.createElementBlock("svg",{class:e.normalizeClass(["gvp-icon",n.class]),width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},[...o[0]||(o[0]=[e.createElementVNode("path",{d:"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),e.createElementVNode("path",{d:"M11 15H13",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round","stroke-linejoin":"round"},null,-1),e.createElementVNode("path",{d:"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1),e.createElementVNode("path",{d:"M7 22H17",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round"},null,-1)])],2))}}),I={name:"IconMobile"},H=e.defineComponent({...I,props:{class:{}},setup(t){const n=t;return(l,o)=>(e.openBlock(),e.createElementBlock("svg",{class:e.normalizeClass(["gvp-icon",n.class]),width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},[...o[0]||(o[0]=[e.createElementVNode("path",{d:"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round"},null,-1),e.createElementVNode("path",{d:"M11 19H13",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1),e.createElementVNode("path",{d:"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2",stroke:"currentColor","stroke-width":"2","stroke-linejoin":"round"},null,-1)])],2))}}),R={name:"IconPlay"},z=e.defineComponent({...R,props:{class:{}},setup(t){const n=t;return(l,o)=>(e.openBlock(),e.createElementBlock("svg",{class:e.normalizeClass(["gvp-icon",n.class]),width:"22",height:"22",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},[...o[0]||(o[0]=[e.createElementVNode("path",{d:"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z",fill:"currentColor"},null,-1)])],2))}}),A={name:"IconX"},D=e.defineComponent({...A,props:{class:{}},setup(t){const n=t;return(l,o)=>(e.openBlock(),e.createElementBlock("svg",{class:e.normalizeClass(["gvp-icon",n.class]),width:"14",height:"14",viewBox:"0 0 14 14",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},[...o[0]||(o[0]=[e.createElementVNode("path",{d:"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z",fill:"currentColor"},null,-1)])],2))}});function E(t){if(!t)return null;if(/^[A-Za-z0-9_-]{11}$/.test(t))return t;let n;try{n=new URL(t)}catch{return null}const l=n.hostname.replace(/^www\./,"");if(l==="youtu.be"){const o=n.pathname.slice(1).split("/")[0];return/^[A-Za-z0-9_-]{11}$/.test(o)?o:null}if(l==="youtube.com"||l==="m.youtube.com"||l==="music.youtube.com"||l==="youtube-nocookie.com"){const o=n.searchParams.get("v");if(o&&/^[A-Za-z0-9_-]{11}$/.test(o))return o;const p=/^\/(?:embed|shorts|v|live)\/([A-Za-z0-9_-]{11})/.exec(n.pathname);if(p)return p[1]}return null}function P(t){try{const n=new URL(t),l=n.searchParams.get("t")??n.searchParams.get("start");if(!l)return null;if(/^\d+s?$/.test(l))return Number.parseInt(l,10);const o=/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/.exec(l);if(o){const p=Number.parseInt(o[1]??"0",10),c=Number.parseInt(o[2]??"0",10),u=Number.parseInt(o[3]??"0",10),i=p*3600+c*60+u;return i>0?i:null}}catch{}return null}function V(t,n={}){const{autoPlay:l=!1,muted:o=!0,loop:p=!1,controls:c=!0,startSeconds:u}=n,i=new URLSearchParams({rel:"0",modestbranding:"1",playsinline:"1",controls:c?"1":"0"});return l?(i.set("autoplay","1"),i.set("mute","1")):o&&i.set("mute","1"),p&&(i.set("loop","1"),i.set("playlist",t)),u&&u>0&&i.set("start",String(u)),`https://www.youtube-nocookie.com/embed/${t}?${i.toString()}`}const U=["src"],Z={key:2,class:"gvp-vignette"},Y={key:3,class:"gvp-toggle"},W={class:"gvp-toggle-pill"},_=["aria-pressed"],j=["aria-pressed"],q={key:5,class:"gvp-play-wrap"},O={key:0,class:"gvp-tooltip",role:"tooltip"},F={key:6,class:"gvp-bottom-fade"},J=e.defineComponent({__name:"VideoPlayer",props:{src:{},poster:{},showDeviceToggle:{type:Boolean,default:!0},defaultDevice:{default:"desktop"},hoverPlay:{type:Boolean,default:!1},tooltipText:{},muted:{type:Boolean,default:!0},loop:{type:Boolean,default:!1},controls:{type:Boolean,default:!1},autoPlay:{type:Boolean,default:!1},frameMaxWidth:{},aspectRatio:{},hlsConfig:{},isHls:{type:Boolean},class:{default:""},closable:{type:Boolean,default:!1}},emits:["close","play","pause"],setup(t,{emit:n}){const l=t,o=n,p=e.ref(null),c=e.ref(l.defaultDevice),u=e.ref(!1),i=e.ref(!1),C=e.ref(null),m=e.computed(()=>E(l.src)),v=e.computed(()=>m.value!==null),k=e.computed(()=>m.value?V(m.value,{autoPlay:l.autoPlay,muted:l.muted,loop:l.loop,controls:l.controls,startSeconds:P(l.src)}):null),r=e.computed(()=>{var s,a;return c.value==="mobile"?((s=l.aspectRatio)==null?void 0:s.mobile)??"9/16":((a=l.aspectRatio)==null?void 0:a.desktop)??"16/9"}),d=e.computed(()=>{var s,a;return c.value==="mobile"?((s=l.frameMaxWidth)==null?void 0:s.mobile)??"420px":((a=l.frameMaxWidth)==null?void 0:a.desktop)??"960px"}),f=e.computed(()=>{var s;return((s=p.value)==null?void 0:s.videoEl)??null});async function y(){const s=f.value;if(s)try{s.readyState<2&&s.load();const a=s.play();C.value=a,await a,u.value=!0}catch{u.value=!1}finally{C.value=null}}async function w(){const s=f.value;if(s){if(C.value)try{await C.value}catch{}s.pause()}}async function b(){!l.hoverPlay||v.value||await y()}async function N(){!l.hoverPlay||v.value||(await w(),u.value=!1)}async function $(){const s=f.value;s&&(s.paused?await y():(await w(),u.value=!1))}function x(){i.value=!0,b()}function M(){i.value=!1,N()}return(s,a)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["gvp-root",l.class]),style:e.normalizeStyle({width:d.value,aspectRatio:r.value}),onMouseenter:x,onMouseleave:M},[v.value?(e.openBlock(),e.createElementBlock("iframe",{key:0,class:"gvp-video gvp-youtube",src:k.value??void 0,title:"YouTube video player",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",allowfullscreen:"",referrerpolicy:"strict-origin-when-cross-origin"},null,8,U)):(e.openBlock(),e.createBlock(B,{key:1,ref_key:"hlsPlayerRef",ref:p,controls:t.controls,"hls-config":t.hlsConfig,"is-hls":t.isHls,loop:t.loop,muted:t.muted,"auto-play":t.autoPlay,"plays-inline":!0,poster:t.poster,src:t.src,class:"gvp-video",preload:"metadata",onPause:a[0]||(a[0]=h=>{u.value=!1,o("pause")}),onPlay:a[1]||(a[1]=h=>{u.value=!0,o("play")})},{default:e.withCtx(()=>[e.renderSlot(s.$slots,"default")]),_:3},8,["controls","hls-config","is-hls","loop","muted","auto-play","poster","src"])),v.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",Z)),t.showDeviceToggle?(e.openBlock(),e.createElementBlock("div",Y,[e.createElementVNode("div",W,[e.createElementVNode("button",{"aria-pressed":c.value==="desktop",class:e.normalizeClass(["gvp-toggle-btn",{"is-active":c.value==="desktop"}]),"aria-label":"Desktop view",type:"button",onClick:a[2]||(a[2]=h=>c.value="desktop")},[e.createVNode(T)],10,_),a[7]||(a[7]=e.createElementVNode("div",{class:"gvp-toggle-divider"},null,-1)),e.createElementVNode("button",{"aria-pressed":c.value==="mobile",class:e.normalizeClass(["gvp-toggle-btn",{"is-active":c.value==="mobile"}]),"aria-label":"Mobile view",type:"button",onClick:a[3]||(a[3]=h=>c.value="mobile")},[e.createVNode(H)],10,j)])])):e.createCommentVNode("",!0),t.closable?(e.openBlock(),e.createElementBlock("button",{key:4,"aria-label":"Close",class:"gvp-close",type:"button",onClick:a[4]||(a[4]=h=>o("close"))},[e.createVNode(D)])):e.createCommentVNode("",!0),!v.value&&!u.value?(e.openBlock(),e.createElementBlock("div",q,[e.createElementVNode("button",{"aria-label":"Play",class:"gvp-play",type:"button",onClick:$,onMouseenter:a[5]||(a[5]=h=>i.value=!0),onMouseleave:a[6]||(a[6]=h=>i.value=!1)},[e.createVNode(z),t.tooltipText&&i.value?(e.openBlock(),e.createElementBlock("span",O,e.toDisplayString(t.tooltipText),1)):e.createCommentVNode("",!0)],32)])):e.createCommentVNode("",!0),v.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",F))],38))}});exports.HLSPlayer=B;exports.VueVideoPlayer=J;exports.parseYouTubeId=E;exports.parseYouTubeStart=P;exports.youTubeEmbedUrl=V;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/HLSPlayer.vue","../src/components/IconDesktop.vue","../src/components/IconMobile.vue","../src/components/IconPlay.vue","../src/components/IconX.vue","../src/VideoPlayer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport Hls from \"hls.js\";\nimport { onMounted, onUnmounted, ref, watch } from \"vue\";\nimport type { HlsConfig } from \"hls.js\";\n\nconst props = withDefaults(\n defineProps<{\n src: string;\n hlsConfig?: HlsConfig;\n isHls?: boolean;\n muted?: boolean;\n loop?: boolean;\n controls?: boolean;\n playsInline?: boolean;\n preload?: string;\n poster?: string;\n class?: string;\n }>(),\n {\n muted: true,\n loop: false,\n controls: false,\n playsInline: true,\n preload: \"metadata\"\n }\n);\n\nconst emit = defineEmits<{\n play: [];\n pause: [];\n}>();\n\nconst videoEl = ref<HTMLVideoElement | null>(null);\nconst hlsInstance = ref<Hls | null>(null);\n\nconst canUseHlsJs = globalThis.window !== undefined && Hls.isSupported();\nconst shouldUseHls = (src: string) =>\n Boolean(props.isHls) || (canUseHlsJs && src.endsWith(\".m3u8\"));\n\nfunction cleanup() {\n if (hlsInstance.value) {\n hlsInstance.value.destroy();\n hlsInstance.value = null;\n }\n const el = videoEl.value;\n if (!el) return;\n el.pause();\n el.removeAttribute(\"src\");\n while (el.firstChild) el.firstChild.remove();\n el.load();\n}\n\nfunction initPlayer(src: string) {\n const el = videoEl.value;\n if (!el || !src) return;\n\n cleanup();\n\n if (shouldUseHls(src)) {\n const hls = new Hls(props.hlsConfig);\n hlsInstance.value = hls;\n hls.attachMedia(el);\n hls.loadSource(src);\n hls.on(Hls.Events.ERROR, (_evt, data) => {\n if (data.fatal) {\n hls.destroy();\n hlsInstance.value = null;\n }\n });\n } else {\n el.src = src;\n el.load();\n }\n}\n\nonMounted(() => {\n if (props.src) initPlayer(props.src);\n});\n\nwatch(\n () => props.src,\n (src) => {\n if (src) initPlayer(src);\n }\n);\n\nonUnmounted(cleanup);\n\ndefineExpose({ videoEl });\n</script>\n\n<template>\n <video\n ref=\"videoEl\"\n :muted=\"muted\"\n :loop=\"loop\"\n :controls=\"controls\"\n :playsinline=\"playsInline\"\n :preload=\"preload\"\n :poster=\"poster\"\n :class=\"props.class\"\n @play=\"emit('play')\"\n @pause=\"emit('pause')\"\n >\n <slot />\n </video>\n</template>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M11 15H13\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M7 22H17\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconDesktop\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M11 19H13\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linejoin=\"round\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconMobile\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z\"\n fill=\"currentColor\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconPlay\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z\"\n fill=\"currentColor\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconX\" };\n</script>\n","<script lang=\"ts\" setup>\nimport { computed, ref } from \"vue\";\nimport HLSPlayer from \"./HLSPlayer.vue\";\nimport IconDesktop from \"./components/IconDesktop.vue\";\nimport IconMobile from \"./components/IconMobile.vue\";\nimport IconPlay from \"./components/IconPlay.vue\";\nimport IconX from \"./components/IconX.vue\";\nimport type { DeviceMode, VideoPlayerProps } from \"./utils/types\";\n\nconst props = withDefaults(\n defineProps<VideoPlayerProps & { class?: string; closable?: boolean }>(),\n {\n showDeviceToggle: true,\n defaultDevice: \"desktop\",\n hoverPlay: false,\n muted: true,\n loop: false,\n controls: false,\n closable: false,\n class: \"\"\n }\n);\n\nconst emit = defineEmits<{\n close: [];\n play: [];\n pause: [];\n}>();\n\nconst hlsPlayerRef = ref<InstanceType<typeof HLSPlayer> | null>(null);\nconst device = ref<DeviceMode>(props.defaultDevice);\nconst isPlaying = ref(false);\nconst showTooltip = ref(false);\nconst playPromise = ref<Promise<void> | null>(null);\n\nconst aspectRatio = computed(() =>\n device.value === \"mobile\"\n ? (props.aspectRatio?.mobile ?? \"9/16\")\n : (props.aspectRatio?.desktop ?? \"16/9\")\n);\n\nconst frameMaxWidth = computed(() =>\n device.value === \"mobile\"\n ? (props.frameMaxWidth?.mobile ?? \"420px\")\n : (props.frameMaxWidth?.desktop ?? \"960px\")\n);\n\nconst videoEl = computed(() => hlsPlayerRef.value?.videoEl ?? null);\n\nasync function safePlay() {\n const el = videoEl.value;\n if (!el) return;\n try {\n if (el.readyState < 2) el.load();\n const p = el.play();\n playPromise.value = p;\n await p;\n isPlaying.value = true;\n } catch {\n isPlaying.value = false;\n } finally {\n playPromise.value = null;\n }\n}\n\nasync function safePause() {\n const el = videoEl.value;\n if (!el) return;\n if (playPromise.value) {\n try {\n await playPromise.value;\n } catch {\n /* play was interrupted; nothing to await */\n }\n }\n el.pause();\n}\n\nasync function hoverStart() {\n if (!props.hoverPlay) return;\n await safePlay();\n}\n\nasync function hoverStop() {\n if (!props.hoverPlay) return;\n await safePause();\n isPlaying.value = false;\n}\n\nasync function togglePlay() {\n const el = videoEl.value;\n if (!el) return;\n if (el.paused) {\n await safePlay();\n } else {\n await safePause();\n isPlaying.value = false;\n }\n}\n\nfunction onMouseEnter() {\n showTooltip.value = true;\n void hoverStart();\n}\n\nfunction onMouseLeave() {\n showTooltip.value = false;\n void hoverStop();\n}\n</script>\n\n<template>\n <div\n :class=\"['gvp-root', props.class]\"\n :style=\"{ width: frameMaxWidth, aspectRatio }\"\n @mouseenter=\"onMouseEnter\"\n @mouseleave=\"onMouseLeave\"\n >\n <HLSPlayer\n ref=\"hlsPlayerRef\"\n :controls=\"controls\"\n :hls-config=\"hlsConfig\"\n :is-hls=\"isHls\"\n :loop=\"loop\"\n :muted=\"muted\"\n :plays-inline=\"true\"\n :poster=\"poster\"\n :src=\"src\"\n class=\"gvp-video\"\n preload=\"metadata\"\n @pause=\"\n isPlaying = false;\n emit('pause');\n \"\n @play=\"\n isPlaying = true;\n emit('play');\n \"\n >\n <slot />\n </HLSPlayer>\n\n <div class=\"gvp-vignette\" />\n\n <div v-if=\"showDeviceToggle\" class=\"gvp-toggle\">\n <div class=\"gvp-toggle-pill\">\n <button\n :aria-pressed=\"device === 'desktop'\"\n :class=\"['gvp-toggle-btn', { 'is-active': device === 'desktop' }]\"\n aria-label=\"Desktop view\"\n type=\"button\"\n @click=\"device = 'desktop'\"\n >\n <IconDesktop />\n </button>\n\n <div class=\"gvp-toggle-divider\" />\n\n <button\n :aria-pressed=\"device === 'mobile'\"\n :class=\"['gvp-toggle-btn', { 'is-active': device === 'mobile' }]\"\n aria-label=\"Mobile view\"\n type=\"button\"\n @click=\"device = 'mobile'\"\n >\n <IconMobile />\n </button>\n </div>\n </div>\n\n <button\n v-if=\"closable\"\n aria-label=\"Close\"\n class=\"gvp-close\"\n type=\"button\"\n @click=\"emit('close')\"\n >\n <IconX />\n </button>\n\n <div v-if=\"!isPlaying\" class=\"gvp-play-wrap\">\n <button\n aria-label=\"Play\"\n class=\"gvp-play\"\n type=\"button\"\n @click=\"togglePlay\"\n @mouseenter=\"showTooltip = true\"\n @mouseleave=\"showTooltip = false\"\n >\n <IconPlay />\n <span v-if=\"tooltipText && showTooltip\" class=\"gvp-tooltip\" role=\"tooltip\">\n {{ tooltipText }}\n </span>\n </button>\n </div>\n\n <div class=\"gvp-bottom-fade\" />\n </div>\n</template>\n"],"names":["props","__props","emit","__emit","videoEl","ref","hlsInstance","canUseHlsJs","Hls","shouldUseHls","src","cleanup","el","initPlayer","hls","_evt","data","onMounted","watch","onUnmounted","__expose","_createElementBlock","_normalizeClass","_renderSlot","_ctx","__default__","_createElementVNode","hlsPlayerRef","device","isPlaying","showTooltip","playPromise","aspectRatio","computed","_a","_b","frameMaxWidth","safePlay","p","safePause","hoverStart","hoverStop","togglePlay","onMouseEnter","onMouseLeave","_normalizeStyle","_createVNode","HLSPlayer","_cache","$event","_openBlock","_hoisted_1","_hoisted_2","IconDesktop","IconMobile","IconX","_hoisted_5","IconPlay","_hoisted_6","_toDisplayString"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/HLSPlayer.vue","../src/components/IconDesktop.vue","../src/components/IconMobile.vue","../src/components/IconPlay.vue","../src/components/IconX.vue","../src/utils/youtube.ts","../src/VideoPlayer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport Hls from \"hls.js\";\nimport { onMounted, onUnmounted, ref, watch } from \"vue\";\nimport type { HlsConfig } from \"hls.js\";\n\nconst props = withDefaults(\n defineProps<{\n src: string;\n hlsConfig?: HlsConfig;\n isHls?: boolean;\n muted?: boolean;\n loop?: boolean;\n controls?: boolean;\n autoPlay?: boolean;\n playsInline?: boolean;\n preload?: string;\n poster?: string;\n class?: string;\n }>(),\n {\n muted: true,\n loop: false,\n controls: false,\n autoPlay: false,\n playsInline: true,\n preload: \"metadata\"\n }\n);\n\nconst emit = defineEmits<{\n play: [];\n pause: [];\n}>();\n\nconst videoEl = ref<HTMLVideoElement | null>(null);\nconst hlsInstance = ref<Hls | null>(null);\n\nconst canUseHlsJs = globalThis.window !== undefined && Hls.isSupported();\nconst shouldUseHls = (src: string) =>\n Boolean(props.isHls) || (canUseHlsJs && src.endsWith(\".m3u8\"));\n\nlet detachLoadedMetadata: (() => void) | undefined;\n\nfunction cleanup() {\n detachLoadedMetadata?.();\n detachLoadedMetadata = undefined;\n if (hlsInstance.value) {\n hlsInstance.value.destroy();\n hlsInstance.value = null;\n }\n const el = videoEl.value;\n if (!el) return;\n el.pause();\n el.removeAttribute(\"src\");\n while (el.firstChild) el.firstChild.remove();\n el.load();\n}\n\nfunction initPlayer(src: string) {\n const el = videoEl.value;\n if (!el || !src) return;\n\n cleanup();\n\n // Tries to start playback once the stream is ready. Browsers only honor\n // sound-on autoplay after a user gesture, so this is best effort — silently\n // swallows the NotAllowedError when blocked.\n const tryAutoPlay = () => {\n if (!props.autoPlay) return;\n el.play().catch(() => {\n /* autoplay blocked; user gesture required */\n });\n };\n\n if (shouldUseHls(src)) {\n const hls = new Hls(props.hlsConfig);\n hlsInstance.value = hls;\n hls.attachMedia(el);\n hls.loadSource(src);\n hls.on(Hls.Events.MANIFEST_PARSED, tryAutoPlay);\n hls.on(Hls.Events.ERROR, (_evt, data) => {\n if (data.fatal) {\n hls.destroy();\n hlsInstance.value = null;\n }\n });\n } else {\n el.src = src;\n el.load();\n el.addEventListener(\"loadedmetadata\", tryAutoPlay, { once: true });\n detachLoadedMetadata = () => {\n el.removeEventListener(\"loadedmetadata\", tryAutoPlay);\n };\n }\n}\n\nonMounted(() => {\n if (props.src) initPlayer(props.src);\n});\n\nwatch(\n () => props.src,\n (src) => {\n if (src) initPlayer(src);\n }\n);\n\nonUnmounted(cleanup);\n\ndefineExpose({ videoEl });\n</script>\n\n<template>\n <video\n ref=\"videoEl\"\n :muted=\"muted\"\n :loop=\"loop\"\n :controls=\"controls\"\n :autoplay=\"autoPlay\"\n :playsinline=\"playsInline\"\n :preload=\"preload\"\n :poster=\"poster\"\n :class=\"props.class\"\n @play=\"emit('play')\"\n @pause=\"emit('pause')\"\n >\n <slot />\n </video>\n</template>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M11 15H13\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M7 22H17\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconDesktop\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M11 19H13\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linejoin=\"round\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconMobile\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z\"\n fill=\"currentColor\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconPlay\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z\"\n fill=\"currentColor\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconX\" };\n</script>\n","/**\n * Extract a YouTube video ID from any common URL form, or `null` if the URL\n * isn't a YouTube link.\n *\n * Recognised:\n * - https://www.youtube.com/watch?v=ID\n * - https://youtube.com/watch?v=ID&t=42\n * - https://youtu.be/ID\n * - https://youtu.be/ID?t=42\n * - https://www.youtube.com/embed/ID\n * - https://www.youtube.com/shorts/ID\n * - https://music.youtube.com/watch?v=ID\n * - bare 11-character video IDs\n */\nexport function parseYouTubeId(input: string): string | null {\n if (!input) return null;\n\n if (/^[A-Za-z0-9_-]{11}$/.test(input)) return input;\n\n let url: URL;\n try {\n url = new URL(input);\n } catch {\n return null;\n }\n\n const host = url.hostname.replace(/^www\\./, \"\");\n\n if (host === \"youtu.be\") {\n const id = url.pathname.slice(1).split(\"/\")[0];\n return /^[A-Za-z0-9_-]{11}$/.test(id) ? id : null;\n }\n\n if (\n host === \"youtube.com\" ||\n host === \"m.youtube.com\" ||\n host === \"music.youtube.com\" ||\n host === \"youtube-nocookie.com\"\n ) {\n const v = url.searchParams.get(\"v\");\n if (v && /^[A-Za-z0-9_-]{11}$/.test(v)) return v;\n\n const m = /^\\/(?:embed|shorts|v|live)\\/([A-Za-z0-9_-]{11})/.exec(\n url.pathname\n );\n if (m) return m[1];\n }\n\n return null;\n}\n\n/** Extract a `t`/`start` timestamp (in seconds) from a YouTube URL, if present. */\nexport function parseYouTubeStart(input: string): number | null {\n try {\n const url = new URL(input);\n const t = url.searchParams.get(\"t\") ?? url.searchParams.get(\"start\");\n if (!t) return null;\n if (/^\\d+s?$/.test(t)) return Number.parseInt(t, 10);\n const m = /^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/.exec(t);\n if (m) {\n const h = Number.parseInt(m[1] ?? \"0\", 10);\n const min = Number.parseInt(m[2] ?? \"0\", 10);\n const s = Number.parseInt(m[3] ?? \"0\", 10);\n const total = h * 3600 + min * 60 + s;\n return total > 0 ? total : null;\n }\n } catch {\n /* not a URL */\n }\n return null;\n}\n\nexport interface YouTubeEmbedOptions {\n /** Start playback immediately. Forces `mute` on, since browsers block sound-on autoplay. */\n autoPlay?: boolean;\n /** Mute the player. */\n muted?: boolean;\n /** Loop the video. */\n loop?: boolean;\n /** Show YouTube's player controls. Defaults to `true`. */\n controls?: boolean;\n /** Start offset in seconds. */\n startSeconds?: number | null;\n}\n\n/**\n * Build a privacy-enhanced YouTube embed URL from a video ID and player options.\n *\n * Notes on YouTube's quirks:\n * - `autoplay=1` only takes effect if `mute=1` is also set (browser policy).\n * - single-video loop requires `loop=1` **and** `playlist=<id>`.\n */\nexport function youTubeEmbedUrl(\n id: string,\n opts: YouTubeEmbedOptions = {}\n): string {\n const {\n autoPlay = false,\n muted = true,\n loop = false,\n controls = true,\n startSeconds\n } = opts;\n\n const params = new URLSearchParams({\n rel: \"0\",\n modestbranding: \"1\",\n playsinline: \"1\",\n controls: controls ? \"1\" : \"0\"\n });\n\n if (autoPlay) {\n params.set(\"autoplay\", \"1\");\n params.set(\"mute\", \"1\"); // required for autoplay to actually fire\n } else if (muted) {\n params.set(\"mute\", \"1\");\n }\n\n if (loop) {\n params.set(\"loop\", \"1\");\n params.set(\"playlist\", id); // YouTube needs this for single-video loop\n }\n\n if (startSeconds && startSeconds > 0) {\n params.set(\"start\", String(startSeconds));\n }\n\n return `https://www.youtube-nocookie.com/embed/${id}?${params.toString()}`;\n}\n","<script lang=\"ts\" setup>\nimport { computed, ref } from \"vue\";\nimport HLSPlayer from \"./HLSPlayer.vue\";\nimport IconDesktop from \"./components/IconDesktop.vue\";\nimport IconMobile from \"./components/IconMobile.vue\";\nimport IconPlay from \"./components/IconPlay.vue\";\nimport IconX from \"./components/IconX.vue\";\nimport type { DeviceMode, VideoPlayerProps } from \"./utils/types\";\nimport { parseYouTubeId, parseYouTubeStart, youTubeEmbedUrl } from \"./utils/youtube\";\n\nconst props = withDefaults(\n defineProps<VideoPlayerProps & { class?: string; closable?: boolean }>(),\n {\n showDeviceToggle: true,\n defaultDevice: \"desktop\",\n hoverPlay: false,\n muted: true,\n loop: false,\n controls: false,\n autoPlay: false,\n closable: false,\n class: \"\"\n }\n);\n\nconst emit = defineEmits<{\n close: [];\n play: [];\n pause: [];\n}>();\n\nconst hlsPlayerRef = ref<InstanceType<typeof HLSPlayer> | null>(null);\nconst device = ref<DeviceMode>(props.defaultDevice);\nconst isPlaying = ref(false);\nconst showTooltip = ref(false);\nconst playPromise = ref<Promise<void> | null>(null);\n\nconst youTubeId = computed(() => parseYouTubeId(props.src));\nconst isYouTube = computed(() => youTubeId.value !== null);\nconst youTubeSrc = computed(() =>\n youTubeId.value\n ? youTubeEmbedUrl(youTubeId.value, {\n autoPlay: props.autoPlay,\n muted: props.muted,\n loop: props.loop,\n controls: props.controls,\n startSeconds: parseYouTubeStart(props.src)\n })\n : null\n);\n\nconst aspectRatio = computed(() =>\n device.value === \"mobile\"\n ? (props.aspectRatio?.mobile ?? \"9/16\")\n : (props.aspectRatio?.desktop ?? \"16/9\")\n);\n\nconst frameMaxWidth = computed(() =>\n device.value === \"mobile\"\n ? (props.frameMaxWidth?.mobile ?? \"420px\")\n : (props.frameMaxWidth?.desktop ?? \"960px\")\n);\n\nconst videoEl = computed(() => hlsPlayerRef.value?.videoEl ?? null);\n\nasync function safePlay() {\n const el = videoEl.value;\n if (!el) return;\n try {\n if (el.readyState < 2) el.load();\n const p = el.play();\n playPromise.value = p;\n await p;\n isPlaying.value = true;\n } catch {\n isPlaying.value = false;\n } finally {\n playPromise.value = null;\n }\n}\n\nasync function safePause() {\n const el = videoEl.value;\n if (!el) return;\n if (playPromise.value) {\n try {\n await playPromise.value;\n } catch {\n /* play was interrupted; nothing to await */\n }\n }\n el.pause();\n}\n\nasync function hoverStart() {\n if (!props.hoverPlay || isYouTube.value) return;\n await safePlay();\n}\n\nasync function hoverStop() {\n if (!props.hoverPlay || isYouTube.value) return;\n await safePause();\n isPlaying.value = false;\n}\n\nasync function togglePlay() {\n const el = videoEl.value;\n if (!el) return;\n if (el.paused) {\n await safePlay();\n } else {\n await safePause();\n isPlaying.value = false;\n }\n}\n\nfunction onMouseEnter() {\n showTooltip.value = true;\n void hoverStart();\n}\n\nfunction onMouseLeave() {\n showTooltip.value = false;\n void hoverStop();\n}\n</script>\n\n<template>\n <div\n :class=\"['gvp-root', props.class]\"\n :style=\"{ width: frameMaxWidth, aspectRatio }\"\n @mouseenter=\"onMouseEnter\"\n @mouseleave=\"onMouseLeave\"\n >\n <iframe\n v-if=\"isYouTube\"\n class=\"gvp-video gvp-youtube\"\n :src=\"youTubeSrc ?? undefined\"\n title=\"YouTube video player\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowfullscreen\n referrerpolicy=\"strict-origin-when-cross-origin\"\n />\n <HLSPlayer\n v-else\n ref=\"hlsPlayerRef\"\n :controls=\"controls\"\n :hls-config=\"hlsConfig\"\n :is-hls=\"isHls\"\n :loop=\"loop\"\n :muted=\"muted\"\n :auto-play=\"autoPlay\"\n :plays-inline=\"true\"\n :poster=\"poster\"\n :src=\"src\"\n class=\"gvp-video\"\n preload=\"metadata\"\n @pause=\"\n isPlaying = false;\n emit('pause');\n \"\n @play=\"\n isPlaying = true;\n emit('play');\n \"\n >\n <slot />\n </HLSPlayer>\n\n <div v-if=\"!isYouTube\" class=\"gvp-vignette\" />\n\n <div v-if=\"showDeviceToggle\" class=\"gvp-toggle\">\n <div class=\"gvp-toggle-pill\">\n <button\n :aria-pressed=\"device === 'desktop'\"\n :class=\"['gvp-toggle-btn', { 'is-active': device === 'desktop' }]\"\n aria-label=\"Desktop view\"\n type=\"button\"\n @click=\"device = 'desktop'\"\n >\n <IconDesktop />\n </button>\n\n <div class=\"gvp-toggle-divider\" />\n\n <button\n :aria-pressed=\"device === 'mobile'\"\n :class=\"['gvp-toggle-btn', { 'is-active': device === 'mobile' }]\"\n aria-label=\"Mobile view\"\n type=\"button\"\n @click=\"device = 'mobile'\"\n >\n <IconMobile />\n </button>\n </div>\n </div>\n\n <button\n v-if=\"closable\"\n aria-label=\"Close\"\n class=\"gvp-close\"\n type=\"button\"\n @click=\"emit('close')\"\n >\n <IconX />\n </button>\n\n <div v-if=\"!isYouTube && !isPlaying\" class=\"gvp-play-wrap\">\n <button\n aria-label=\"Play\"\n class=\"gvp-play\"\n type=\"button\"\n @click=\"togglePlay\"\n @mouseenter=\"showTooltip = true\"\n @mouseleave=\"showTooltip = false\"\n >\n <IconPlay />\n <span v-if=\"tooltipText && showTooltip\" class=\"gvp-tooltip\" role=\"tooltip\">\n {{ tooltipText }}\n </span>\n </button>\n </div>\n\n <div v-if=\"!isYouTube\" class=\"gvp-bottom-fade\" />\n </div>\n</template>\n"],"names":["props","__props","emit","__emit","videoEl","ref","hlsInstance","canUseHlsJs","Hls","shouldUseHls","src","detachLoadedMetadata","cleanup","el","initPlayer","tryAutoPlay","hls","_evt","data","onMounted","watch","onUnmounted","__expose","_createElementBlock","_normalizeClass","_renderSlot","_ctx","__default__","_createElementVNode","parseYouTubeId","input","url","host","id","v","m","parseYouTubeStart","t","h","min","s","total","youTubeEmbedUrl","opts","autoPlay","muted","loop","controls","startSeconds","params","hlsPlayerRef","device","isPlaying","showTooltip","playPromise","youTubeId","computed","isYouTube","youTubeSrc","aspectRatio","_a","_b","frameMaxWidth","safePlay","p","safePause","hoverStart","hoverStop","togglePlay","onMouseEnter","onMouseLeave","_normalizeStyle","_createBlock","HLSPlayer","_cache","$event","_openBlock","_hoisted_2","_hoisted_3","_hoisted_4","_createVNode","IconDesktop","IconMobile","IconX","_hoisted_7","IconPlay","_hoisted_8","_toDisplayString","_hoisted_9"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,4 +2,5 @@
2
2
  export { default as VueVideoPlayer } from './VideoPlayer.vue';
3
3
  export { default as HLSPlayer } from './HLSPlayer.vue';
4
4
  export type { VideoPlayerProps, HLSPlayerProps, DeviceMode, AspectRatio } from './utils/types';
5
+ export { parseYouTubeId, parseYouTubeStart, youTubeEmbedUrl } from './utils/youtube';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAEtB,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EACV,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAC1D,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAEtB,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,YAAY,EACV,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAC1D,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { defineComponent as h, ref as y, onMounted as V, watch as D, onUnmounted as I, openBlock as c, createElementBlock as v, normalizeClass as f, renderSlot as H, createElementVNode as n, computed as $, normalizeStyle as T, createVNode as k, withCtx as W, createCommentVNode as M, toDisplayString as Z } from "vue";
2
- import B from "hls.js";
3
- const j = ["muted", "loop", "controls", "playsinline", "preload", "poster"], N = /* @__PURE__ */ h({
1
+ import { defineComponent as x, ref as w, onMounted as A, watch as D, onUnmounted as N, openBlock as d, createElementBlock as v, normalizeClass as C, renderSlot as T, createElementVNode as p, computed as P, normalizeStyle as Z, createBlock as U, withCtx as z, createCommentVNode as $, createVNode as B, toDisplayString as W } from "vue";
2
+ import L from "hls.js";
3
+ const _ = ["muted", "loop", "controls", "autoplay", "playsinline", "preload", "poster"], Y = /* @__PURE__ */ x({
4
4
  __name: "HLSPlayer",
5
5
  props: {
6
6
  src: {},
@@ -9,92 +9,102 @@ const j = ["muted", "loop", "controls", "playsinline", "preload", "poster"], N =
9
9
  muted: { type: Boolean, default: !0 },
10
10
  loop: { type: Boolean, default: !1 },
11
11
  controls: { type: Boolean, default: !1 },
12
+ autoPlay: { type: Boolean, default: !1 },
12
13
  playsInline: { type: Boolean, default: !0 },
13
14
  preload: { default: "metadata" },
14
15
  poster: {},
15
16
  class: {}
16
17
  },
17
18
  emits: ["play", "pause"],
18
- setup(t, { expose: d, emit: a }) {
19
- const l = t, w = a, i = y(null), r = y(null), C = globalThis.window !== void 0 && B.isSupported(), m = (o) => !!l.isHls || C && o.endsWith(".m3u8");
20
- function b() {
21
- r.value && (r.value.destroy(), r.value = null);
22
- const o = i.value;
23
- if (o) {
24
- for (o.pause(), o.removeAttribute("src"); o.firstChild; ) o.firstChild.remove();
25
- o.load();
19
+ setup(e, { expose: s, emit: o }) {
20
+ const t = e, f = o, i = w(null), r = w(null), u = globalThis.window !== void 0 && L.isSupported(), b = (n) => !!t.isHls || u && n.endsWith(".m3u8");
21
+ let y;
22
+ function m() {
23
+ y == null || y(), y = void 0, r.value && (r.value.destroy(), r.value = null);
24
+ const n = i.value;
25
+ if (n) {
26
+ for (n.pause(), n.removeAttribute("src"); n.firstChild; ) n.firstChild.remove();
27
+ n.load();
26
28
  }
27
29
  }
28
- function x(o) {
29
- const u = i.value;
30
- if (!(!u || !o))
31
- if (b(), m(o)) {
32
- const p = new B(l.hlsConfig);
33
- r.value = p, p.attachMedia(u), p.loadSource(o), p.on(B.Events.ERROR, (L, P) => {
34
- P.fatal && (p.destroy(), r.value = null);
35
- });
36
- } else
37
- u.src = o, u.load();
30
+ function M(n) {
31
+ const c = i.value;
32
+ if (!c || !n) return;
33
+ m();
34
+ const h = () => {
35
+ t.autoPlay && c.play().catch(() => {
36
+ });
37
+ };
38
+ if (b(n)) {
39
+ const g = new L(t.hlsConfig);
40
+ r.value = g, g.attachMedia(c), g.loadSource(n), g.on(L.Events.MANIFEST_PARSED, h), g.on(L.Events.ERROR, (S, E) => {
41
+ E.fatal && (g.destroy(), r.value = null);
42
+ });
43
+ } else
44
+ c.src = n, c.load(), c.addEventListener("loadedmetadata", h, { once: !0 }), y = () => {
45
+ c.removeEventListener("loadedmetadata", h);
46
+ };
38
47
  }
39
- return V(() => {
40
- l.src && x(l.src);
48
+ return A(() => {
49
+ t.src && M(t.src);
41
50
  }), D(
42
- () => l.src,
43
- (o) => {
44
- o && x(o);
51
+ () => t.src,
52
+ (n) => {
53
+ n && M(n);
45
54
  }
46
- ), I(b), d({ videoEl: i }), (o, u) => (c(), v("video", {
55
+ ), N(m), s({ videoEl: i }), (n, c) => (d(), v("video", {
47
56
  ref_key: "videoEl",
48
57
  ref: i,
49
- muted: t.muted,
50
- loop: t.loop,
51
- controls: t.controls,
52
- playsinline: t.playsInline,
53
- preload: t.preload,
54
- poster: t.poster,
55
- class: f(l.class),
56
- onPlay: u[0] || (u[0] = (p) => w("play")),
57
- onPause: u[1] || (u[1] = (p) => w("pause"))
58
+ muted: e.muted,
59
+ loop: e.loop,
60
+ controls: e.controls,
61
+ autoplay: e.autoPlay,
62
+ playsinline: e.playsInline,
63
+ preload: e.preload,
64
+ poster: e.poster,
65
+ class: C(t.class),
66
+ onPlay: c[0] || (c[0] = (h) => f("play")),
67
+ onPause: c[1] || (c[1] = (h) => f("pause"))
58
68
  }, [
59
- H(o.$slots, "default")
60
- ], 42, j));
69
+ T(n.$slots, "default")
70
+ ], 42, _));
61
71
  }
62
- }), U = { name: "IconDesktop" }, z = /* @__PURE__ */ h({
63
- ...U,
72
+ }), j = { name: "IconDesktop" }, F = /* @__PURE__ */ x({
73
+ ...j,
64
74
  props: {
65
75
  class: {}
66
76
  },
67
- setup(t) {
68
- const d = t;
69
- return (a, l) => (c(), v("svg", {
70
- class: f(["gvp-icon", d.class]),
77
+ setup(e) {
78
+ const s = e;
79
+ return (o, t) => (d(), v("svg", {
80
+ class: C(["gvp-icon", s.class]),
71
81
  width: "20",
72
82
  height: "20",
73
83
  viewBox: "0 0 24 24",
74
84
  fill: "none",
75
85
  xmlns: "http://www.w3.org/2000/svg",
76
86
  "aria-hidden": "true"
77
- }, [...l[0] || (l[0] = [
78
- n("path", {
87
+ }, [...t[0] || (t[0] = [
88
+ p("path", {
79
89
  d: "M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z",
80
90
  stroke: "currentColor",
81
91
  "stroke-width": "1.5",
82
92
  "stroke-linecap": "round"
83
93
  }, null, -1),
84
- n("path", {
94
+ p("path", {
85
95
  d: "M11 15H13",
86
96
  stroke: "currentColor",
87
97
  "stroke-width": "1.5",
88
98
  "stroke-linecap": "round",
89
99
  "stroke-linejoin": "round"
90
100
  }, null, -1),
91
- n("path", {
101
+ p("path", {
92
102
  d: "M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18",
93
103
  stroke: "currentColor",
94
104
  "stroke-width": "1.5",
95
105
  "stroke-linecap": "round"
96
106
  }, null, -1),
97
- n("path", {
107
+ p("path", {
98
108
  d: "M7 22H17",
99
109
  stroke: "currentColor",
100
110
  "stroke-width": "1.5",
@@ -102,36 +112,36 @@ const j = ["muted", "loop", "controls", "playsinline", "preload", "poster"], N =
102
112
  }, null, -1)
103
113
  ])], 2));
104
114
  }
105
- }), A = { name: "IconMobile" }, J = /* @__PURE__ */ h({
106
- ...A,
115
+ }), J = { name: "IconMobile" }, O = /* @__PURE__ */ x({
116
+ ...J,
107
117
  props: {
108
118
  class: {}
109
119
  },
110
- setup(t) {
111
- const d = t;
112
- return (a, l) => (c(), v("svg", {
113
- class: f(["gvp-icon", d.class]),
120
+ setup(e) {
121
+ const s = e;
122
+ return (o, t) => (d(), v("svg", {
123
+ class: C(["gvp-icon", s.class]),
114
124
  width: "20",
115
125
  height: "20",
116
126
  viewBox: "0 0 24 24",
117
127
  fill: "none",
118
128
  xmlns: "http://www.w3.org/2000/svg",
119
129
  "aria-hidden": "true"
120
- }, [...l[0] || (l[0] = [
121
- n("path", {
130
+ }, [...t[0] || (t[0] = [
131
+ p("path", {
122
132
  d: "M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z",
123
133
  stroke: "currentColor",
124
134
  "stroke-width": "2",
125
135
  "stroke-linecap": "round"
126
136
  }, null, -1),
127
- n("path", {
137
+ p("path", {
128
138
  d: "M11 19H13",
129
139
  stroke: "currentColor",
130
140
  "stroke-width": "2",
131
141
  "stroke-linecap": "round",
132
142
  "stroke-linejoin": "round"
133
143
  }, null, -1),
134
- n("path", {
144
+ p("path", {
135
145
  d: "M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2",
136
146
  stroke: "currentColor",
137
147
  "stroke-width": "2",
@@ -139,61 +149,121 @@ const j = ["muted", "loop", "controls", "playsinline", "preload", "poster"], N =
139
149
  }, null, -1)
140
150
  ])], 2));
141
151
  }
142
- }), O = { name: "IconPlay" }, X = /* @__PURE__ */ h({
143
- ...O,
152
+ }), X = { name: "IconPlay" }, q = /* @__PURE__ */ x({
153
+ ...X,
144
154
  props: {
145
155
  class: {}
146
156
  },
147
- setup(t) {
148
- const d = t;
149
- return (a, l) => (c(), v("svg", {
150
- class: f(["gvp-icon", d.class]),
157
+ setup(e) {
158
+ const s = e;
159
+ return (o, t) => (d(), v("svg", {
160
+ class: C(["gvp-icon", s.class]),
151
161
  width: "22",
152
162
  height: "22",
153
163
  viewBox: "0 0 16 16",
154
164
  fill: "none",
155
165
  xmlns: "http://www.w3.org/2000/svg",
156
166
  "aria-hidden": "true"
157
- }, [...l[0] || (l[0] = [
158
- n("path", {
167
+ }, [...t[0] || (t[0] = [
168
+ p("path", {
159
169
  d: "M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z",
160
170
  fill: "currentColor"
161
171
  }, null, -1)
162
172
  ])], 2));
163
173
  }
164
- }), q = { name: "IconX" }, F = /* @__PURE__ */ h({
165
- ...q,
174
+ }), G = { name: "IconX" }, K = /* @__PURE__ */ x({
175
+ ...G,
166
176
  props: {
167
177
  class: {}
168
178
  },
169
- setup(t) {
170
- const d = t;
171
- return (a, l) => (c(), v("svg", {
172
- class: f(["gvp-icon", d.class]),
179
+ setup(e) {
180
+ const s = e;
181
+ return (o, t) => (d(), v("svg", {
182
+ class: C(["gvp-icon", s.class]),
173
183
  width: "14",
174
184
  height: "14",
175
185
  viewBox: "0 0 14 14",
176
186
  fill: "none",
177
187
  xmlns: "http://www.w3.org/2000/svg",
178
188
  "aria-hidden": "true"
179
- }, [...l[0] || (l[0] = [
180
- n("path", {
189
+ }, [...t[0] || (t[0] = [
190
+ p("path", {
181
191
  d: "M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z",
182
192
  fill: "currentColor"
183
193
  }, null, -1)
184
194
  ])], 2));
185
195
  }
186
- }), G = {
187
- key: 0,
188
- class: "gvp-toggle"
189
- }, K = { class: "gvp-toggle-pill" }, Q = ["aria-pressed"], Y = ["aria-pressed"], _ = {
196
+ });
197
+ function Q(e) {
198
+ if (!e) return null;
199
+ if (/^[A-Za-z0-9_-]{11}$/.test(e)) return e;
200
+ let s;
201
+ try {
202
+ s = new URL(e);
203
+ } catch {
204
+ return null;
205
+ }
206
+ const o = s.hostname.replace(/^www\./, "");
207
+ if (o === "youtu.be") {
208
+ const t = s.pathname.slice(1).split("/")[0];
209
+ return /^[A-Za-z0-9_-]{11}$/.test(t) ? t : null;
210
+ }
211
+ if (o === "youtube.com" || o === "m.youtube.com" || o === "music.youtube.com" || o === "youtube-nocookie.com") {
212
+ const t = s.searchParams.get("v");
213
+ if (t && /^[A-Za-z0-9_-]{11}$/.test(t)) return t;
214
+ const f = /^\/(?:embed|shorts|v|live)\/([A-Za-z0-9_-]{11})/.exec(
215
+ s.pathname
216
+ );
217
+ if (f) return f[1];
218
+ }
219
+ return null;
220
+ }
221
+ function ee(e) {
222
+ try {
223
+ const s = new URL(e), o = s.searchParams.get("t") ?? s.searchParams.get("start");
224
+ if (!o) return null;
225
+ if (/^\d+s?$/.test(o)) return Number.parseInt(o, 10);
226
+ const t = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/.exec(o);
227
+ if (t) {
228
+ const f = Number.parseInt(t[1] ?? "0", 10), i = Number.parseInt(t[2] ?? "0", 10), r = Number.parseInt(t[3] ?? "0", 10), u = f * 3600 + i * 60 + r;
229
+ return u > 0 ? u : null;
230
+ }
231
+ } catch {
232
+ }
233
+ return null;
234
+ }
235
+ function te(e, s = {}) {
236
+ const {
237
+ autoPlay: o = !1,
238
+ muted: t = !0,
239
+ loop: f = !1,
240
+ controls: i = !0,
241
+ startSeconds: r
242
+ } = s, u = new URLSearchParams({
243
+ rel: "0",
244
+ modestbranding: "1",
245
+ playsinline: "1",
246
+ controls: i ? "1" : "0"
247
+ });
248
+ return o ? (u.set("autoplay", "1"), u.set("mute", "1")) : t && u.set("mute", "1"), f && (u.set("loop", "1"), u.set("playlist", e)), r && r > 0 && u.set("start", String(r)), `https://www.youtube-nocookie.com/embed/${e}?${u.toString()}`;
249
+ }
250
+ const oe = ["src"], le = {
190
251
  key: 2,
252
+ class: "gvp-vignette"
253
+ }, se = {
254
+ key: 3,
255
+ class: "gvp-toggle"
256
+ }, ae = { class: "gvp-toggle-pill" }, ne = ["aria-pressed"], re = ["aria-pressed"], ue = {
257
+ key: 5,
191
258
  class: "gvp-play-wrap"
192
- }, ee = {
259
+ }, ie = {
193
260
  key: 0,
194
261
  class: "gvp-tooltip",
195
262
  role: "tooltip"
196
- }, oe = /* @__PURE__ */ h({
263
+ }, ce = {
264
+ key: 6,
265
+ class: "gvp-bottom-fade"
266
+ }, ve = /* @__PURE__ */ x({
197
267
  __name: "VideoPlayer",
198
268
  props: {
199
269
  src: {},
@@ -205,6 +275,7 @@ const j = ["muted", "loop", "controls", "playsinline", "preload", "poster"], N =
205
275
  muted: { type: Boolean, default: !0 },
206
276
  loop: { type: Boolean, default: !1 },
207
277
  controls: { type: Boolean, default: !1 },
278
+ autoPlay: { type: Boolean, default: !1 },
208
279
  frameMaxWidth: {},
209
280
  aspectRatio: {},
210
281
  hlsConfig: {},
@@ -213,144 +284,165 @@ const j = ["muted", "loop", "controls", "playsinline", "preload", "poster"], N =
213
284
  closable: { type: Boolean, default: !1 }
214
285
  },
215
286
  emits: ["close", "play", "pause"],
216
- setup(t, { emit: d }) {
217
- const a = t, l = d, w = y(null), i = y(a.defaultDevice), r = y(!1), C = y(!1), m = y(null), b = $(
287
+ setup(e, { emit: s }) {
288
+ const o = e, t = s, f = w(null), i = w(o.defaultDevice), r = w(!1), u = w(!1), b = w(null), y = P(() => Q(o.src)), m = P(() => y.value !== null), M = P(
289
+ () => y.value ? te(y.value, {
290
+ autoPlay: o.autoPlay,
291
+ muted: o.muted,
292
+ loop: o.loop,
293
+ controls: o.controls,
294
+ startSeconds: ee(o.src)
295
+ }) : null
296
+ ), n = P(
218
297
  () => {
219
- var s, e;
220
- return i.value === "mobile" ? ((s = a.aspectRatio) == null ? void 0 : s.mobile) ?? "9/16" : ((e = a.aspectRatio) == null ? void 0 : e.desktop) ?? "16/9";
298
+ var a, l;
299
+ return i.value === "mobile" ? ((a = o.aspectRatio) == null ? void 0 : a.mobile) ?? "9/16" : ((l = o.aspectRatio) == null ? void 0 : l.desktop) ?? "16/9";
221
300
  }
222
- ), x = $(
301
+ ), c = P(
223
302
  () => {
224
- var s, e;
225
- return i.value === "mobile" ? ((s = a.frameMaxWidth) == null ? void 0 : s.mobile) ?? "420px" : ((e = a.frameMaxWidth) == null ? void 0 : e.desktop) ?? "960px";
303
+ var a, l;
304
+ return i.value === "mobile" ? ((a = o.frameMaxWidth) == null ? void 0 : a.mobile) ?? "420px" : ((l = o.frameMaxWidth) == null ? void 0 : l.desktop) ?? "960px";
226
305
  }
227
- ), o = $(() => {
228
- var s;
229
- return ((s = w.value) == null ? void 0 : s.videoEl) ?? null;
306
+ ), h = P(() => {
307
+ var a;
308
+ return ((a = f.value) == null ? void 0 : a.videoEl) ?? null;
230
309
  });
231
- async function u() {
232
- const s = o.value;
233
- if (s)
310
+ async function g() {
311
+ const a = h.value;
312
+ if (a)
234
313
  try {
235
- s.readyState < 2 && s.load();
236
- const e = s.play();
237
- m.value = e, await e, r.value = !0;
314
+ a.readyState < 2 && a.load();
315
+ const l = a.play();
316
+ b.value = l, await l, r.value = !0;
238
317
  } catch {
239
318
  r.value = !1;
240
319
  } finally {
241
- m.value = null;
320
+ b.value = null;
242
321
  }
243
322
  }
244
- async function p() {
245
- const s = o.value;
246
- if (s) {
247
- if (m.value)
323
+ async function S() {
324
+ const a = h.value;
325
+ if (a) {
326
+ if (b.value)
248
327
  try {
249
- await m.value;
328
+ await b.value;
250
329
  } catch {
251
330
  }
252
- s.pause();
331
+ a.pause();
253
332
  }
254
333
  }
255
- async function L() {
256
- a.hoverPlay && await u();
334
+ async function E() {
335
+ !o.hoverPlay || m.value || await g();
257
336
  }
258
- async function P() {
259
- a.hoverPlay && (await p(), r.value = !1);
337
+ async function H() {
338
+ !o.hoverPlay || m.value || (await S(), r.value = !1);
260
339
  }
261
- async function R() {
262
- const s = o.value;
263
- s && (s.paused ? await u() : (await p(), r.value = !1));
340
+ async function I() {
341
+ const a = h.value;
342
+ a && (a.paused ? await g() : (await S(), r.value = !1));
264
343
  }
265
- function S() {
266
- C.value = !0, L();
344
+ function R() {
345
+ u.value = !0, E();
267
346
  }
268
- function E() {
269
- C.value = !1, P();
347
+ function V() {
348
+ u.value = !1, H();
270
349
  }
271
- return (s, e) => (c(), v("div", {
272
- class: f(["gvp-root", a.class]),
273
- style: T({ width: x.value, aspectRatio: b.value }),
274
- onMouseenter: S,
275
- onMouseleave: E
350
+ return (a, l) => (d(), v("div", {
351
+ class: C(["gvp-root", o.class]),
352
+ style: Z({ width: c.value, aspectRatio: n.value }),
353
+ onMouseenter: R,
354
+ onMouseleave: V
276
355
  }, [
277
- k(N, {
356
+ m.value ? (d(), v("iframe", {
357
+ key: 0,
358
+ class: "gvp-video gvp-youtube",
359
+ src: M.value ?? void 0,
360
+ title: "YouTube video player",
361
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",
362
+ allowfullscreen: "",
363
+ referrerpolicy: "strict-origin-when-cross-origin"
364
+ }, null, 8, oe)) : (d(), U(Y, {
365
+ key: 1,
278
366
  ref_key: "hlsPlayerRef",
279
- ref: w,
280
- controls: t.controls,
281
- "hls-config": t.hlsConfig,
282
- "is-hls": t.isHls,
283
- loop: t.loop,
284
- muted: t.muted,
367
+ ref: f,
368
+ controls: e.controls,
369
+ "hls-config": e.hlsConfig,
370
+ "is-hls": e.isHls,
371
+ loop: e.loop,
372
+ muted: e.muted,
373
+ "auto-play": e.autoPlay,
285
374
  "plays-inline": !0,
286
- poster: t.poster,
287
- src: t.src,
375
+ poster: e.poster,
376
+ src: e.src,
288
377
  class: "gvp-video",
289
378
  preload: "metadata",
290
- onPause: e[0] || (e[0] = (g) => {
291
- r.value = !1, l("pause");
379
+ onPause: l[0] || (l[0] = (k) => {
380
+ r.value = !1, t("pause");
292
381
  }),
293
- onPlay: e[1] || (e[1] = (g) => {
294
- r.value = !0, l("play");
382
+ onPlay: l[1] || (l[1] = (k) => {
383
+ r.value = !0, t("play");
295
384
  })
296
385
  }, {
297
- default: W(() => [
298
- H(s.$slots, "default")
386
+ default: z(() => [
387
+ T(a.$slots, "default")
299
388
  ]),
300
389
  _: 3
301
- }, 8, ["controls", "hls-config", "is-hls", "loop", "muted", "poster", "src"]),
302
- e[8] || (e[8] = n("div", { class: "gvp-vignette" }, null, -1)),
303
- t.showDeviceToggle ? (c(), v("div", G, [
304
- n("div", K, [
305
- n("button", {
390
+ }, 8, ["controls", "hls-config", "is-hls", "loop", "muted", "auto-play", "poster", "src"])),
391
+ m.value ? $("", !0) : (d(), v("div", le)),
392
+ e.showDeviceToggle ? (d(), v("div", se, [
393
+ p("div", ae, [
394
+ p("button", {
306
395
  "aria-pressed": i.value === "desktop",
307
- class: f(["gvp-toggle-btn", { "is-active": i.value === "desktop" }]),
396
+ class: C(["gvp-toggle-btn", { "is-active": i.value === "desktop" }]),
308
397
  "aria-label": "Desktop view",
309
398
  type: "button",
310
- onClick: e[2] || (e[2] = (g) => i.value = "desktop")
399
+ onClick: l[2] || (l[2] = (k) => i.value = "desktop")
311
400
  }, [
312
- k(z)
313
- ], 10, Q),
314
- e[7] || (e[7] = n("div", { class: "gvp-toggle-divider" }, null, -1)),
315
- n("button", {
401
+ B(F)
402
+ ], 10, ne),
403
+ l[7] || (l[7] = p("div", { class: "gvp-toggle-divider" }, null, -1)),
404
+ p("button", {
316
405
  "aria-pressed": i.value === "mobile",
317
- class: f(["gvp-toggle-btn", { "is-active": i.value === "mobile" }]),
406
+ class: C(["gvp-toggle-btn", { "is-active": i.value === "mobile" }]),
318
407
  "aria-label": "Mobile view",
319
408
  type: "button",
320
- onClick: e[3] || (e[3] = (g) => i.value = "mobile")
409
+ onClick: l[3] || (l[3] = (k) => i.value = "mobile")
321
410
  }, [
322
- k(J)
323
- ], 10, Y)
411
+ B(O)
412
+ ], 10, re)
324
413
  ])
325
- ])) : M("", !0),
326
- t.closable ? (c(), v("button", {
327
- key: 1,
414
+ ])) : $("", !0),
415
+ e.closable ? (d(), v("button", {
416
+ key: 4,
328
417
  "aria-label": "Close",
329
418
  class: "gvp-close",
330
419
  type: "button",
331
- onClick: e[4] || (e[4] = (g) => l("close"))
420
+ onClick: l[4] || (l[4] = (k) => t("close"))
332
421
  }, [
333
- k(F)
334
- ])) : M("", !0),
335
- r.value ? M("", !0) : (c(), v("div", _, [
336
- n("button", {
422
+ B(K)
423
+ ])) : $("", !0),
424
+ !m.value && !r.value ? (d(), v("div", ue, [
425
+ p("button", {
337
426
  "aria-label": "Play",
338
427
  class: "gvp-play",
339
428
  type: "button",
340
- onClick: R,
341
- onMouseenter: e[5] || (e[5] = (g) => C.value = !0),
342
- onMouseleave: e[6] || (e[6] = (g) => C.value = !1)
429
+ onClick: I,
430
+ onMouseenter: l[5] || (l[5] = (k) => u.value = !0),
431
+ onMouseleave: l[6] || (l[6] = (k) => u.value = !1)
343
432
  }, [
344
- k(X),
345
- t.tooltipText && C.value ? (c(), v("span", ee, Z(t.tooltipText), 1)) : M("", !0)
433
+ B(q),
434
+ e.tooltipText && u.value ? (d(), v("span", ie, W(e.tooltipText), 1)) : $("", !0)
346
435
  ], 32)
347
- ])),
348
- e[9] || (e[9] = n("div", { class: "gvp-bottom-fade" }, null, -1))
436
+ ])) : $("", !0),
437
+ m.value ? $("", !0) : (d(), v("div", ce))
349
438
  ], 38));
350
439
  }
351
440
  });
352
441
  export {
353
- N as HLSPlayer,
354
- oe as VueVideoPlayer
442
+ Y as HLSPlayer,
443
+ ve as VueVideoPlayer,
444
+ Q as parseYouTubeId,
445
+ ee as parseYouTubeStart,
446
+ te as youTubeEmbedUrl
355
447
  };
356
448
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/HLSPlayer.vue","../src/components/IconDesktop.vue","../src/components/IconMobile.vue","../src/components/IconPlay.vue","../src/components/IconX.vue","../src/VideoPlayer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport Hls from \"hls.js\";\nimport { onMounted, onUnmounted, ref, watch } from \"vue\";\nimport type { HlsConfig } from \"hls.js\";\n\nconst props = withDefaults(\n defineProps<{\n src: string;\n hlsConfig?: HlsConfig;\n isHls?: boolean;\n muted?: boolean;\n loop?: boolean;\n controls?: boolean;\n playsInline?: boolean;\n preload?: string;\n poster?: string;\n class?: string;\n }>(),\n {\n muted: true,\n loop: false,\n controls: false,\n playsInline: true,\n preload: \"metadata\"\n }\n);\n\nconst emit = defineEmits<{\n play: [];\n pause: [];\n}>();\n\nconst videoEl = ref<HTMLVideoElement | null>(null);\nconst hlsInstance = ref<Hls | null>(null);\n\nconst canUseHlsJs = globalThis.window !== undefined && Hls.isSupported();\nconst shouldUseHls = (src: string) =>\n Boolean(props.isHls) || (canUseHlsJs && src.endsWith(\".m3u8\"));\n\nfunction cleanup() {\n if (hlsInstance.value) {\n hlsInstance.value.destroy();\n hlsInstance.value = null;\n }\n const el = videoEl.value;\n if (!el) return;\n el.pause();\n el.removeAttribute(\"src\");\n while (el.firstChild) el.firstChild.remove();\n el.load();\n}\n\nfunction initPlayer(src: string) {\n const el = videoEl.value;\n if (!el || !src) return;\n\n cleanup();\n\n if (shouldUseHls(src)) {\n const hls = new Hls(props.hlsConfig);\n hlsInstance.value = hls;\n hls.attachMedia(el);\n hls.loadSource(src);\n hls.on(Hls.Events.ERROR, (_evt, data) => {\n if (data.fatal) {\n hls.destroy();\n hlsInstance.value = null;\n }\n });\n } else {\n el.src = src;\n el.load();\n }\n}\n\nonMounted(() => {\n if (props.src) initPlayer(props.src);\n});\n\nwatch(\n () => props.src,\n (src) => {\n if (src) initPlayer(src);\n }\n);\n\nonUnmounted(cleanup);\n\ndefineExpose({ videoEl });\n</script>\n\n<template>\n <video\n ref=\"videoEl\"\n :muted=\"muted\"\n :loop=\"loop\"\n :controls=\"controls\"\n :playsinline=\"playsInline\"\n :preload=\"preload\"\n :poster=\"poster\"\n :class=\"props.class\"\n @play=\"emit('play')\"\n @pause=\"emit('pause')\"\n >\n <slot />\n </video>\n</template>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M11 15H13\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M7 22H17\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconDesktop\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M11 19H13\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linejoin=\"round\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconMobile\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z\"\n fill=\"currentColor\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconPlay\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z\"\n fill=\"currentColor\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconX\" };\n</script>\n","<script lang=\"ts\" setup>\nimport { computed, ref } from \"vue\";\nimport HLSPlayer from \"./HLSPlayer.vue\";\nimport IconDesktop from \"./components/IconDesktop.vue\";\nimport IconMobile from \"./components/IconMobile.vue\";\nimport IconPlay from \"./components/IconPlay.vue\";\nimport IconX from \"./components/IconX.vue\";\nimport type { DeviceMode, VideoPlayerProps } from \"./utils/types\";\n\nconst props = withDefaults(\n defineProps<VideoPlayerProps & { class?: string; closable?: boolean }>(),\n {\n showDeviceToggle: true,\n defaultDevice: \"desktop\",\n hoverPlay: false,\n muted: true,\n loop: false,\n controls: false,\n closable: false,\n class: \"\"\n }\n);\n\nconst emit = defineEmits<{\n close: [];\n play: [];\n pause: [];\n}>();\n\nconst hlsPlayerRef = ref<InstanceType<typeof HLSPlayer> | null>(null);\nconst device = ref<DeviceMode>(props.defaultDevice);\nconst isPlaying = ref(false);\nconst showTooltip = ref(false);\nconst playPromise = ref<Promise<void> | null>(null);\n\nconst aspectRatio = computed(() =>\n device.value === \"mobile\"\n ? (props.aspectRatio?.mobile ?? \"9/16\")\n : (props.aspectRatio?.desktop ?? \"16/9\")\n);\n\nconst frameMaxWidth = computed(() =>\n device.value === \"mobile\"\n ? (props.frameMaxWidth?.mobile ?? \"420px\")\n : (props.frameMaxWidth?.desktop ?? \"960px\")\n);\n\nconst videoEl = computed(() => hlsPlayerRef.value?.videoEl ?? null);\n\nasync function safePlay() {\n const el = videoEl.value;\n if (!el) return;\n try {\n if (el.readyState < 2) el.load();\n const p = el.play();\n playPromise.value = p;\n await p;\n isPlaying.value = true;\n } catch {\n isPlaying.value = false;\n } finally {\n playPromise.value = null;\n }\n}\n\nasync function safePause() {\n const el = videoEl.value;\n if (!el) return;\n if (playPromise.value) {\n try {\n await playPromise.value;\n } catch {\n /* play was interrupted; nothing to await */\n }\n }\n el.pause();\n}\n\nasync function hoverStart() {\n if (!props.hoverPlay) return;\n await safePlay();\n}\n\nasync function hoverStop() {\n if (!props.hoverPlay) return;\n await safePause();\n isPlaying.value = false;\n}\n\nasync function togglePlay() {\n const el = videoEl.value;\n if (!el) return;\n if (el.paused) {\n await safePlay();\n } else {\n await safePause();\n isPlaying.value = false;\n }\n}\n\nfunction onMouseEnter() {\n showTooltip.value = true;\n void hoverStart();\n}\n\nfunction onMouseLeave() {\n showTooltip.value = false;\n void hoverStop();\n}\n</script>\n\n<template>\n <div\n :class=\"['gvp-root', props.class]\"\n :style=\"{ width: frameMaxWidth, aspectRatio }\"\n @mouseenter=\"onMouseEnter\"\n @mouseleave=\"onMouseLeave\"\n >\n <HLSPlayer\n ref=\"hlsPlayerRef\"\n :controls=\"controls\"\n :hls-config=\"hlsConfig\"\n :is-hls=\"isHls\"\n :loop=\"loop\"\n :muted=\"muted\"\n :plays-inline=\"true\"\n :poster=\"poster\"\n :src=\"src\"\n class=\"gvp-video\"\n preload=\"metadata\"\n @pause=\"\n isPlaying = false;\n emit('pause');\n \"\n @play=\"\n isPlaying = true;\n emit('play');\n \"\n >\n <slot />\n </HLSPlayer>\n\n <div class=\"gvp-vignette\" />\n\n <div v-if=\"showDeviceToggle\" class=\"gvp-toggle\">\n <div class=\"gvp-toggle-pill\">\n <button\n :aria-pressed=\"device === 'desktop'\"\n :class=\"['gvp-toggle-btn', { 'is-active': device === 'desktop' }]\"\n aria-label=\"Desktop view\"\n type=\"button\"\n @click=\"device = 'desktop'\"\n >\n <IconDesktop />\n </button>\n\n <div class=\"gvp-toggle-divider\" />\n\n <button\n :aria-pressed=\"device === 'mobile'\"\n :class=\"['gvp-toggle-btn', { 'is-active': device === 'mobile' }]\"\n aria-label=\"Mobile view\"\n type=\"button\"\n @click=\"device = 'mobile'\"\n >\n <IconMobile />\n </button>\n </div>\n </div>\n\n <button\n v-if=\"closable\"\n aria-label=\"Close\"\n class=\"gvp-close\"\n type=\"button\"\n @click=\"emit('close')\"\n >\n <IconX />\n </button>\n\n <div v-if=\"!isPlaying\" class=\"gvp-play-wrap\">\n <button\n aria-label=\"Play\"\n class=\"gvp-play\"\n type=\"button\"\n @click=\"togglePlay\"\n @mouseenter=\"showTooltip = true\"\n @mouseleave=\"showTooltip = false\"\n >\n <IconPlay />\n <span v-if=\"tooltipText && showTooltip\" class=\"gvp-tooltip\" role=\"tooltip\">\n {{ tooltipText }}\n </span>\n </button>\n </div>\n\n <div class=\"gvp-bottom-fade\" />\n </div>\n</template>\n"],"names":["props","__props","emit","__emit","videoEl","ref","hlsInstance","canUseHlsJs","Hls","shouldUseHls","src","cleanup","el","initPlayer","hls","_evt","data","onMounted","watch","onUnmounted","__expose","_createElementBlock","_normalizeClass","_renderSlot","_ctx","__default__","_createElementVNode","hlsPlayerRef","device","isPlaying","showTooltip","playPromise","aspectRatio","computed","_a","_b","frameMaxWidth","safePlay","p","safePause","hoverStart","hoverStop","togglePlay","onMouseEnter","onMouseLeave","_normalizeStyle","_createVNode","HLSPlayer","_cache","$event","_openBlock","_hoisted_1","_hoisted_2","IconDesktop","IconMobile","IconX","_hoisted_5","IconPlay","_hoisted_6","_toDisplayString"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/HLSPlayer.vue","../src/components/IconDesktop.vue","../src/components/IconMobile.vue","../src/components/IconPlay.vue","../src/components/IconX.vue","../src/utils/youtube.ts","../src/VideoPlayer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport Hls from \"hls.js\";\nimport { onMounted, onUnmounted, ref, watch } from \"vue\";\nimport type { HlsConfig } from \"hls.js\";\n\nconst props = withDefaults(\n defineProps<{\n src: string;\n hlsConfig?: HlsConfig;\n isHls?: boolean;\n muted?: boolean;\n loop?: boolean;\n controls?: boolean;\n autoPlay?: boolean;\n playsInline?: boolean;\n preload?: string;\n poster?: string;\n class?: string;\n }>(),\n {\n muted: true,\n loop: false,\n controls: false,\n autoPlay: false,\n playsInline: true,\n preload: \"metadata\"\n }\n);\n\nconst emit = defineEmits<{\n play: [];\n pause: [];\n}>();\n\nconst videoEl = ref<HTMLVideoElement | null>(null);\nconst hlsInstance = ref<Hls | null>(null);\n\nconst canUseHlsJs = globalThis.window !== undefined && Hls.isSupported();\nconst shouldUseHls = (src: string) =>\n Boolean(props.isHls) || (canUseHlsJs && src.endsWith(\".m3u8\"));\n\nlet detachLoadedMetadata: (() => void) | undefined;\n\nfunction cleanup() {\n detachLoadedMetadata?.();\n detachLoadedMetadata = undefined;\n if (hlsInstance.value) {\n hlsInstance.value.destroy();\n hlsInstance.value = null;\n }\n const el = videoEl.value;\n if (!el) return;\n el.pause();\n el.removeAttribute(\"src\");\n while (el.firstChild) el.firstChild.remove();\n el.load();\n}\n\nfunction initPlayer(src: string) {\n const el = videoEl.value;\n if (!el || !src) return;\n\n cleanup();\n\n // Tries to start playback once the stream is ready. Browsers only honor\n // sound-on autoplay after a user gesture, so this is best effort — silently\n // swallows the NotAllowedError when blocked.\n const tryAutoPlay = () => {\n if (!props.autoPlay) return;\n el.play().catch(() => {\n /* autoplay blocked; user gesture required */\n });\n };\n\n if (shouldUseHls(src)) {\n const hls = new Hls(props.hlsConfig);\n hlsInstance.value = hls;\n hls.attachMedia(el);\n hls.loadSource(src);\n hls.on(Hls.Events.MANIFEST_PARSED, tryAutoPlay);\n hls.on(Hls.Events.ERROR, (_evt, data) => {\n if (data.fatal) {\n hls.destroy();\n hlsInstance.value = null;\n }\n });\n } else {\n el.src = src;\n el.load();\n el.addEventListener(\"loadedmetadata\", tryAutoPlay, { once: true });\n detachLoadedMetadata = () => {\n el.removeEventListener(\"loadedmetadata\", tryAutoPlay);\n };\n }\n}\n\nonMounted(() => {\n if (props.src) initPlayer(props.src);\n});\n\nwatch(\n () => props.src,\n (src) => {\n if (src) initPlayer(src);\n }\n);\n\nonUnmounted(cleanup);\n\ndefineExpose({ videoEl });\n</script>\n\n<template>\n <video\n ref=\"videoEl\"\n :muted=\"muted\"\n :loop=\"loop\"\n :controls=\"controls\"\n :autoplay=\"autoPlay\"\n :playsinline=\"playsInline\"\n :preload=\"preload\"\n :poster=\"poster\"\n :class=\"props.class\"\n @play=\"emit('play')\"\n @pause=\"emit('pause')\"\n >\n <slot />\n </video>\n</template>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M14 2H10C6.72077 2 5.08116 2 3.91891 2.81382C3.48891 3.1149 3.1149 3.48891 2.81382 3.91891C2 5.08116 2 6.72077 2 10C2 13.2792 2 14.9188 2.81382 16.0811C3.1149 16.5111 3.48891 16.8851 3.91891 17.1862C5.08116 18 6.72077 18 10 18H14C17.2792 18 18.9188 18 20.0811 17.1862C20.5111 16.8851 20.8851 16.5111 21.1862 16.0811C22 14.9188 22 13.2792 22 10C22 6.72077 22 5.08116 21.1862 3.91891C20.8851 3.48891 20.5111 3.1149 20.0811 2.81382C18.9188 2 17.2792 2 14 2Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M11 15H13\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M14.5 22L14.1845 21.5811C13.4733 20.6369 13.2969 19.1944 13.7468 18M9.5 22L9.8155 21.5811C10.5267 20.6369 10.7031 19.1944 10.2532 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M7 22H17\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconDesktop\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 9C5 5.70017 5 4.05025 6.02513 3.02513C7.05025 2 8.70017 2 12 2C15.2998 2 16.9497 2 17.9749 3.02513C19 4.05025 19 5.70017 19 9V15C19 18.2998 19 19.9497 17.9749 20.9749C16.9497 22 15.2998 22 12 22C8.70017 22 7.05025 22 6.02513 20.9749C5 19.9497 5 18.2998 5 15V9Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n />\n <path\n d=\"M11 19H13\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M9 2L9.089 2.53402C9.28188 3.69129 9.37832 4.26993 9.77519 4.62204C10.1892 4.98934 10.7761 5 12 5C13.2239 5 13.8108 4.98934 14.2248 4.62204C14.6217 4.26993 14.7181 3.69129 14.911 2.53402L15 2\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linejoin=\"round\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconMobile\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.3335 11.45V4.54997C5.3335 4.36108 5.40016 4.20275 5.5335 4.07497C5.66683 3.94719 5.82238 3.8833 6.00016 3.8833C6.05572 3.8833 6.11405 3.89163 6.17516 3.9083C6.23627 3.92497 6.29461 3.94997 6.35016 3.9833L11.7835 7.4333C11.8835 7.49997 11.9585 7.5833 12.0085 7.6833C12.0585 7.7833 12.0835 7.88886 12.0835 7.99997C12.0835 8.11108 12.0585 8.21663 12.0085 8.31663C11.9585 8.41663 11.8835 8.49997 11.7835 8.56663L6.35016 12.0166C6.29461 12.05 6.23627 12.075 6.17516 12.0916C6.11405 12.1083 6.05572 12.1166 6.00016 12.1166C5.82238 12.1166 5.66683 12.0527 5.5335 11.925C5.40016 11.7972 5.3335 11.6389 5.3335 11.45Z\"\n fill=\"currentColor\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconPlay\" };\n</script>\n","<script setup lang=\"ts\">\nconst props = defineProps<{ class?: string }>();\n</script>\n\n<template>\n <svg\n :class=\"['gvp-icon', props.class]\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.94994 5.53594L12.1929 0.292938C12.5834 -0.0975275 13.2165 -0.0975279 13.6069 0.292938C13.9974 0.683403 13.9974 1.31647 13.6069 1.70694L8.36394 6.94994L13.6069 12.1929C13.9974 12.5834 13.9974 13.2165 13.6069 13.6069C13.2165 13.9974 12.5834 13.9974 12.1929 13.6069L6.94994 8.36394L1.70694 13.6069C1.31647 13.9974 0.683403 13.9974 0.292938 13.6069C-0.0975279 13.2165 -0.0975277 12.5834 0.292938 12.1929L5.53594 6.94994L0.292938 1.70694C-0.0975279 1.31647 -0.0975279 0.683403 0.292938 0.292938C0.683403 -0.0975279 1.31647 -0.0975277 1.70694 0.292938L6.94994 5.53594Z\"\n fill=\"currentColor\"\n />\n </svg>\n</template>\n\n<script lang=\"ts\">\nexport default { name: \"IconX\" };\n</script>\n","/**\n * Extract a YouTube video ID from any common URL form, or `null` if the URL\n * isn't a YouTube link.\n *\n * Recognised:\n * - https://www.youtube.com/watch?v=ID\n * - https://youtube.com/watch?v=ID&t=42\n * - https://youtu.be/ID\n * - https://youtu.be/ID?t=42\n * - https://www.youtube.com/embed/ID\n * - https://www.youtube.com/shorts/ID\n * - https://music.youtube.com/watch?v=ID\n * - bare 11-character video IDs\n */\nexport function parseYouTubeId(input: string): string | null {\n if (!input) return null;\n\n if (/^[A-Za-z0-9_-]{11}$/.test(input)) return input;\n\n let url: URL;\n try {\n url = new URL(input);\n } catch {\n return null;\n }\n\n const host = url.hostname.replace(/^www\\./, \"\");\n\n if (host === \"youtu.be\") {\n const id = url.pathname.slice(1).split(\"/\")[0];\n return /^[A-Za-z0-9_-]{11}$/.test(id) ? id : null;\n }\n\n if (\n host === \"youtube.com\" ||\n host === \"m.youtube.com\" ||\n host === \"music.youtube.com\" ||\n host === \"youtube-nocookie.com\"\n ) {\n const v = url.searchParams.get(\"v\");\n if (v && /^[A-Za-z0-9_-]{11}$/.test(v)) return v;\n\n const m = /^\\/(?:embed|shorts|v|live)\\/([A-Za-z0-9_-]{11})/.exec(\n url.pathname\n );\n if (m) return m[1];\n }\n\n return null;\n}\n\n/** Extract a `t`/`start` timestamp (in seconds) from a YouTube URL, if present. */\nexport function parseYouTubeStart(input: string): number | null {\n try {\n const url = new URL(input);\n const t = url.searchParams.get(\"t\") ?? url.searchParams.get(\"start\");\n if (!t) return null;\n if (/^\\d+s?$/.test(t)) return Number.parseInt(t, 10);\n const m = /^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/.exec(t);\n if (m) {\n const h = Number.parseInt(m[1] ?? \"0\", 10);\n const min = Number.parseInt(m[2] ?? \"0\", 10);\n const s = Number.parseInt(m[3] ?? \"0\", 10);\n const total = h * 3600 + min * 60 + s;\n return total > 0 ? total : null;\n }\n } catch {\n /* not a URL */\n }\n return null;\n}\n\nexport interface YouTubeEmbedOptions {\n /** Start playback immediately. Forces `mute` on, since browsers block sound-on autoplay. */\n autoPlay?: boolean;\n /** Mute the player. */\n muted?: boolean;\n /** Loop the video. */\n loop?: boolean;\n /** Show YouTube's player controls. Defaults to `true`. */\n controls?: boolean;\n /** Start offset in seconds. */\n startSeconds?: number | null;\n}\n\n/**\n * Build a privacy-enhanced YouTube embed URL from a video ID and player options.\n *\n * Notes on YouTube's quirks:\n * - `autoplay=1` only takes effect if `mute=1` is also set (browser policy).\n * - single-video loop requires `loop=1` **and** `playlist=<id>`.\n */\nexport function youTubeEmbedUrl(\n id: string,\n opts: YouTubeEmbedOptions = {}\n): string {\n const {\n autoPlay = false,\n muted = true,\n loop = false,\n controls = true,\n startSeconds\n } = opts;\n\n const params = new URLSearchParams({\n rel: \"0\",\n modestbranding: \"1\",\n playsinline: \"1\",\n controls: controls ? \"1\" : \"0\"\n });\n\n if (autoPlay) {\n params.set(\"autoplay\", \"1\");\n params.set(\"mute\", \"1\"); // required for autoplay to actually fire\n } else if (muted) {\n params.set(\"mute\", \"1\");\n }\n\n if (loop) {\n params.set(\"loop\", \"1\");\n params.set(\"playlist\", id); // YouTube needs this for single-video loop\n }\n\n if (startSeconds && startSeconds > 0) {\n params.set(\"start\", String(startSeconds));\n }\n\n return `https://www.youtube-nocookie.com/embed/${id}?${params.toString()}`;\n}\n","<script lang=\"ts\" setup>\nimport { computed, ref } from \"vue\";\nimport HLSPlayer from \"./HLSPlayer.vue\";\nimport IconDesktop from \"./components/IconDesktop.vue\";\nimport IconMobile from \"./components/IconMobile.vue\";\nimport IconPlay from \"./components/IconPlay.vue\";\nimport IconX from \"./components/IconX.vue\";\nimport type { DeviceMode, VideoPlayerProps } from \"./utils/types\";\nimport { parseYouTubeId, parseYouTubeStart, youTubeEmbedUrl } from \"./utils/youtube\";\n\nconst props = withDefaults(\n defineProps<VideoPlayerProps & { class?: string; closable?: boolean }>(),\n {\n showDeviceToggle: true,\n defaultDevice: \"desktop\",\n hoverPlay: false,\n muted: true,\n loop: false,\n controls: false,\n autoPlay: false,\n closable: false,\n class: \"\"\n }\n);\n\nconst emit = defineEmits<{\n close: [];\n play: [];\n pause: [];\n}>();\n\nconst hlsPlayerRef = ref<InstanceType<typeof HLSPlayer> | null>(null);\nconst device = ref<DeviceMode>(props.defaultDevice);\nconst isPlaying = ref(false);\nconst showTooltip = ref(false);\nconst playPromise = ref<Promise<void> | null>(null);\n\nconst youTubeId = computed(() => parseYouTubeId(props.src));\nconst isYouTube = computed(() => youTubeId.value !== null);\nconst youTubeSrc = computed(() =>\n youTubeId.value\n ? youTubeEmbedUrl(youTubeId.value, {\n autoPlay: props.autoPlay,\n muted: props.muted,\n loop: props.loop,\n controls: props.controls,\n startSeconds: parseYouTubeStart(props.src)\n })\n : null\n);\n\nconst aspectRatio = computed(() =>\n device.value === \"mobile\"\n ? (props.aspectRatio?.mobile ?? \"9/16\")\n : (props.aspectRatio?.desktop ?? \"16/9\")\n);\n\nconst frameMaxWidth = computed(() =>\n device.value === \"mobile\"\n ? (props.frameMaxWidth?.mobile ?? \"420px\")\n : (props.frameMaxWidth?.desktop ?? \"960px\")\n);\n\nconst videoEl = computed(() => hlsPlayerRef.value?.videoEl ?? null);\n\nasync function safePlay() {\n const el = videoEl.value;\n if (!el) return;\n try {\n if (el.readyState < 2) el.load();\n const p = el.play();\n playPromise.value = p;\n await p;\n isPlaying.value = true;\n } catch {\n isPlaying.value = false;\n } finally {\n playPromise.value = null;\n }\n}\n\nasync function safePause() {\n const el = videoEl.value;\n if (!el) return;\n if (playPromise.value) {\n try {\n await playPromise.value;\n } catch {\n /* play was interrupted; nothing to await */\n }\n }\n el.pause();\n}\n\nasync function hoverStart() {\n if (!props.hoverPlay || isYouTube.value) return;\n await safePlay();\n}\n\nasync function hoverStop() {\n if (!props.hoverPlay || isYouTube.value) return;\n await safePause();\n isPlaying.value = false;\n}\n\nasync function togglePlay() {\n const el = videoEl.value;\n if (!el) return;\n if (el.paused) {\n await safePlay();\n } else {\n await safePause();\n isPlaying.value = false;\n }\n}\n\nfunction onMouseEnter() {\n showTooltip.value = true;\n void hoverStart();\n}\n\nfunction onMouseLeave() {\n showTooltip.value = false;\n void hoverStop();\n}\n</script>\n\n<template>\n <div\n :class=\"['gvp-root', props.class]\"\n :style=\"{ width: frameMaxWidth, aspectRatio }\"\n @mouseenter=\"onMouseEnter\"\n @mouseleave=\"onMouseLeave\"\n >\n <iframe\n v-if=\"isYouTube\"\n class=\"gvp-video gvp-youtube\"\n :src=\"youTubeSrc ?? undefined\"\n title=\"YouTube video player\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowfullscreen\n referrerpolicy=\"strict-origin-when-cross-origin\"\n />\n <HLSPlayer\n v-else\n ref=\"hlsPlayerRef\"\n :controls=\"controls\"\n :hls-config=\"hlsConfig\"\n :is-hls=\"isHls\"\n :loop=\"loop\"\n :muted=\"muted\"\n :auto-play=\"autoPlay\"\n :plays-inline=\"true\"\n :poster=\"poster\"\n :src=\"src\"\n class=\"gvp-video\"\n preload=\"metadata\"\n @pause=\"\n isPlaying = false;\n emit('pause');\n \"\n @play=\"\n isPlaying = true;\n emit('play');\n \"\n >\n <slot />\n </HLSPlayer>\n\n <div v-if=\"!isYouTube\" class=\"gvp-vignette\" />\n\n <div v-if=\"showDeviceToggle\" class=\"gvp-toggle\">\n <div class=\"gvp-toggle-pill\">\n <button\n :aria-pressed=\"device === 'desktop'\"\n :class=\"['gvp-toggle-btn', { 'is-active': device === 'desktop' }]\"\n aria-label=\"Desktop view\"\n type=\"button\"\n @click=\"device = 'desktop'\"\n >\n <IconDesktop />\n </button>\n\n <div class=\"gvp-toggle-divider\" />\n\n <button\n :aria-pressed=\"device === 'mobile'\"\n :class=\"['gvp-toggle-btn', { 'is-active': device === 'mobile' }]\"\n aria-label=\"Mobile view\"\n type=\"button\"\n @click=\"device = 'mobile'\"\n >\n <IconMobile />\n </button>\n </div>\n </div>\n\n <button\n v-if=\"closable\"\n aria-label=\"Close\"\n class=\"gvp-close\"\n type=\"button\"\n @click=\"emit('close')\"\n >\n <IconX />\n </button>\n\n <div v-if=\"!isYouTube && !isPlaying\" class=\"gvp-play-wrap\">\n <button\n aria-label=\"Play\"\n class=\"gvp-play\"\n type=\"button\"\n @click=\"togglePlay\"\n @mouseenter=\"showTooltip = true\"\n @mouseleave=\"showTooltip = false\"\n >\n <IconPlay />\n <span v-if=\"tooltipText && showTooltip\" class=\"gvp-tooltip\" role=\"tooltip\">\n {{ tooltipText }}\n </span>\n </button>\n </div>\n\n <div v-if=\"!isYouTube\" class=\"gvp-bottom-fade\" />\n </div>\n</template>\n"],"names":["props","__props","emit","__emit","videoEl","ref","hlsInstance","canUseHlsJs","Hls","shouldUseHls","src","detachLoadedMetadata","cleanup","el","initPlayer","tryAutoPlay","hls","_evt","data","onMounted","watch","onUnmounted","__expose","_createElementBlock","_normalizeClass","_renderSlot","_ctx","__default__","_createElementVNode","parseYouTubeId","input","url","host","id","v","m","parseYouTubeStart","t","h","min","s","total","youTubeEmbedUrl","opts","autoPlay","muted","loop","controls","startSeconds","params","hlsPlayerRef","device","isPlaying","showTooltip","playPromise","youTubeId","computed","isYouTube","youTubeSrc","aspectRatio","_a","_b","frameMaxWidth","safePlay","p","safePause","hoverStart","hoverStop","togglePlay","onMouseEnter","onMouseLeave","_normalizeStyle","_createBlock","HLSPlayer","_cache","$event","_openBlock","_hoisted_2","_hoisted_3","_hoisted_4","_createVNode","IconDesktop","IconMobile","IconX","_hoisted_7","IconPlay","_hoisted_8","_toDisplayString","_hoisted_9"],"mappings":";;;;;;;;;;;;;;;;;;;AAKA,UAAMA,IAAQC,GAwBRC,IAAOC,GAKPC,IAAUC,EAA6B,IAAI,GAC3CC,IAAcD,EAAgB,IAAI,GAElCE,IAAc,WAAW,WAAW,UAAaC,EAAI,YAAA,GACrDC,IAAe,CAACC,MACpB,EAAQV,EAAM,SAAWO,KAAeG,EAAI,SAAS,OAAO;AAE9D,QAAIC;AAEJ,aAASC,IAAU;AACjB,MAAAD,KAAA,QAAAA,KACAA,IAAuB,QACnBL,EAAY,UACdA,EAAY,MAAM,QAAA,GAClBA,EAAY,QAAQ;AAEtB,YAAMO,IAAKT,EAAQ;AACnB,UAAKS,GAGL;AAAA,aAFAA,EAAG,MAAA,GACHA,EAAG,gBAAgB,KAAK,GACjBA,EAAG,aAAY,CAAAA,EAAG,WAAW,OAAA;AACpC,QAAAA,EAAG,KAAA;AAAA;AAAA,IACL;AAEA,aAASC,EAAWJ,GAAa;AAC/B,YAAMG,IAAKT,EAAQ;AACnB,UAAI,CAACS,KAAM,CAACH,EAAK;AAEjB,MAAAE,EAAA;AAKA,YAAMG,IAAc,MAAM;AACxB,QAAKf,EAAM,YACXa,EAAG,OAAO,MAAM,MAAM;AAAA,QAEtB,CAAC;AAAA,MACH;AAEA,UAAIJ,EAAaC,CAAG,GAAG;AACrB,cAAMM,IAAM,IAAIR,EAAIR,EAAM,SAAS;AACnC,QAAAM,EAAY,QAAQU,GACpBA,EAAI,YAAYH,CAAE,GAClBG,EAAI,WAAWN,CAAG,GAClBM,EAAI,GAAGR,EAAI,OAAO,iBAAiBO,CAAW,GAC9CC,EAAI,GAAGR,EAAI,OAAO,OAAO,CAACS,GAAMC,MAAS;AACvC,UAAIA,EAAK,UACPF,EAAI,QAAA,GACJV,EAAY,QAAQ;AAAA,QAExB,CAAC;AAAA,MACH;AACE,QAAAO,EAAG,MAAMH,GACTG,EAAG,KAAA,GACHA,EAAG,iBAAiB,kBAAkBE,GAAa,EAAE,MAAM,IAAM,GACjEJ,IAAuB,MAAM;AAC3B,UAAAE,EAAG,oBAAoB,kBAAkBE,CAAW;AAAA,QACtD;AAAA,IAEJ;AAEA,WAAAI,EAAU,MAAM;AACd,MAAInB,EAAM,OAAKc,EAAWd,EAAM,GAAG;AAAA,IACrC,CAAC,GAEDoB;AAAA,MACE,MAAMpB,EAAM;AAAA,MACZ,CAACU,MAAQ;AACP,QAAIA,OAAgBA,CAAG;AAAA,MACzB;AAAA,IAAA,GAGFW,EAAYT,CAAO,GAEnBU,EAAa,EAAE,SAAAlB,GAAS,mBAItBmB,EAcQ,SAAA;AAAA,eAbF;AAAA,MAAJ,KAAInB;AAAA,MACH,OAAOH,EAAA;AAAA,MACP,MAAMA,EAAA;AAAA,MACN,UAAUA,EAAA;AAAA,MACV,UAAUA,EAAA;AAAA,MACV,aAAaA,EAAA;AAAA,MACb,SAASA,EAAA;AAAA,MACT,QAAQA,EAAA;AAAA,MACR,OAAKuB,EAAExB,EAAM,KAAK;AAAA,MAClB,+BAAME,EAAI,MAAA;AAAA,MACV,gCAAOA,EAAI,OAAA;AAAA,IAAA;MAEZuB,EAAQC,EAAA,QAAA,SAAA;AAAA,IAAA;;ICnFZC,IAAe,EAAE,MAAM,cAAA;;;;;;AA1CvB,UAAM3B,IAAQC;2BAIZsB,EAkCM,OAAA;AAAA,MAjCH,OAAKC,EAAA,CAAA,YAAexB,EAAM,KAAK,CAAA;AAAA,MAChC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,eAAY;AAAA,IAAA;MAEZ4B,EAKE,QAAA;AAAA,QAJA,GAAE;AAAA,QACF,QAAO;AAAA,QACP,gBAAa;AAAA,QACb,kBAAe;AAAA,MAAA;MAEjBA,EAME,QAAA;AAAA,QALA,GAAE;AAAA,QACF,QAAO;AAAA,QACP,gBAAa;AAAA,QACb,kBAAe;AAAA,QACf,mBAAgB;AAAA,MAAA;MAElBA,EAKE,QAAA;AAAA,QAJA,GAAE;AAAA,QACF,QAAO;AAAA,QACP,gBAAa;AAAA,QACb,kBAAe;AAAA,MAAA;MAEjBA,EAKE,QAAA;AAAA,QAJA,GAAE;AAAA,QACF,QAAO;AAAA,QACP,gBAAa;AAAA,QACb,kBAAe;AAAA,MAAA;;;ICArBD,IAAe,EAAE,MAAM,aAAA;;;;;;AApCvB,UAAM3B,IAAQC;2BAIZsB,EA4BM,OAAA;AAAA,MA3BH,OAAKC,EAAA,CAAA,YAAexB,EAAM,KAAK,CAAA;AAAA,MAChC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,eAAY;AAAA,IAAA;MAEZ4B,EAKE,QAAA;AAAA,QAJA,GAAE;AAAA,QACF,QAAO;AAAA,QACP,gBAAa;AAAA,QACb,kBAAe;AAAA,MAAA;MAEjBA,EAME,QAAA;AAAA,QALA,GAAE;AAAA,QACF,QAAO;AAAA,QACP,gBAAa;AAAA,QACb,kBAAe;AAAA,QACf,mBAAgB;AAAA,MAAA;MAElBA,EAKE,QAAA;AAAA,QAJA,GAAE;AAAA,QACF,QAAO;AAAA,QACP,gBAAa;AAAA,QACb,mBAAgB;AAAA,MAAA;;;ICTtBD,IAAe,EAAE,MAAM,WAAA;;;;;;AArBvB,UAAM3B,IAAQC;2BAIZsB,EAaM,OAAA;AAAA,MAZH,OAAKC,EAAA,CAAA,YAAexB,EAAM,KAAK,CAAA;AAAA,MAChC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,eAAY;AAAA,IAAA;MAEZ4B,EAGE,QAAA;AAAA,QAFA,GAAE;AAAA,QACF,MAAK;AAAA,MAAA;;;ICMXD,IAAe,EAAE,MAAM,QAAA;;;;;;AArBvB,UAAM3B,IAAQC;2BAIZsB,EAaM,OAAA;AAAA,MAZH,OAAKC,EAAA,CAAA,YAAexB,EAAM,KAAK,CAAA;AAAA,MAChC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAM;AAAA,MACN,eAAY;AAAA,IAAA;MAEZ4B,EAGE,QAAA;AAAA,QAFA,GAAE;AAAA,QACF,MAAK;AAAA,MAAA;;;;ACFJ,SAASC,EAAeC,GAA8B;AAC3D,MAAI,CAACA,EAAO,QAAO;AAEnB,MAAI,sBAAsB,KAAKA,CAAK,EAAG,QAAOA;AAE9C,MAAIC;AACJ,MAAI;AACF,IAAAA,IAAM,IAAI,IAAID,CAAK;AAAA,EACrB,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAME,IAAOD,EAAI,SAAS,QAAQ,UAAU,EAAE;AAE9C,MAAIC,MAAS,YAAY;AACvB,UAAMC,IAAKF,EAAI,SAAS,MAAM,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC;AAC7C,WAAO,sBAAsB,KAAKE,CAAE,IAAIA,IAAK;AAAA,EAC/C;AAEA,MACED,MAAS,iBACTA,MAAS,mBACTA,MAAS,uBACTA,MAAS,wBACT;AACA,UAAME,IAAIH,EAAI,aAAa,IAAI,GAAG;AAClC,QAAIG,KAAK,sBAAsB,KAAKA,CAAC,EAAG,QAAOA;AAE/C,UAAMC,IAAI,kDAAkD;AAAA,MAC1DJ,EAAI;AAAA,IAAA;AAEN,QAAII,EAAG,QAAOA,EAAE,CAAC;AAAA,EACnB;AAEA,SAAO;AACT;AAGO,SAASC,GAAkBN,GAA8B;AAC9D,MAAI;AACF,UAAMC,IAAM,IAAI,IAAID,CAAK,GACnBO,IAAIN,EAAI,aAAa,IAAI,GAAG,KAAKA,EAAI,aAAa,IAAI,OAAO;AACnE,QAAI,CAACM,EAAG,QAAO;AACf,QAAI,UAAU,KAAKA,CAAC,UAAU,OAAO,SAASA,GAAG,EAAE;AACnD,UAAMF,IAAI,sCAAsC,KAAKE,CAAC;AACtD,QAAIF,GAAG;AACL,YAAMG,IAAI,OAAO,SAASH,EAAE,CAAC,KAAK,KAAK,EAAE,GACnCI,IAAM,OAAO,SAASJ,EAAE,CAAC,KAAK,KAAK,EAAE,GACrCK,IAAI,OAAO,SAASL,EAAE,CAAC,KAAK,KAAK,EAAE,GACnCM,IAAQH,IAAI,OAAOC,IAAM,KAAKC;AACpC,aAAOC,IAAQ,IAAIA,IAAQ;AAAA,IAC7B;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAsBO,SAASC,GACdT,GACAU,IAA4B,IACpB;AACR,QAAM;AAAA,IACJ,UAAAC,IAAW;AAAA,IACX,OAAAC,IAAQ;AAAA,IACR,MAAAC,IAAO;AAAA,IACP,UAAAC,IAAW;AAAA,IACX,cAAAC;AAAA,EAAA,IACEL,GAEEM,IAAS,IAAI,gBAAgB;AAAA,IACjC,KAAK;AAAA,IACL,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,UAAUF,IAAW,MAAM;AAAA,EAAA,CAC5B;AAED,SAAIH,KACFK,EAAO,IAAI,YAAY,GAAG,GAC1BA,EAAO,IAAI,QAAQ,GAAG,KACbJ,KACTI,EAAO,IAAI,QAAQ,GAAG,GAGpBH,MACFG,EAAO,IAAI,QAAQ,GAAG,GACtBA,EAAO,IAAI,YAAYhB,CAAE,IAGvBe,KAAgBA,IAAe,KACjCC,EAAO,IAAI,SAAS,OAAOD,CAAY,CAAC,GAGnC,0CAA0Cf,CAAE,IAAIgB,EAAO,UAAU;AAC1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtHA,UAAMjD,IAAQC,GAeRC,IAAOC,GAMP+C,IAAe7C,EAA2C,IAAI,GAC9D8C,IAAS9C,EAAgBL,EAAM,aAAa,GAC5CoD,IAAY/C,EAAI,EAAK,GACrBgD,IAAchD,EAAI,EAAK,GACvBiD,IAAcjD,EAA0B,IAAI,GAE5CkD,IAAYC,EAAS,MAAM3B,EAAe7B,EAAM,GAAG,CAAC,GACpDyD,IAAYD,EAAS,MAAMD,EAAU,UAAU,IAAI,GACnDG,IAAaF;AAAA,MAAS,MAC1BD,EAAU,QACNb,GAAgBa,EAAU,OAAO;AAAA,QAC/B,UAAUvD,EAAM;AAAA,QAChB,OAAOA,EAAM;AAAA,QACb,MAAMA,EAAM;AAAA,QACZ,UAAUA,EAAM;AAAA,QAChB,cAAcoC,GAAkBpC,EAAM,GAAG;AAAA,MAAA,CAC1C,IACD;AAAA,IAAA,GAGA2D,IAAcH;AAAA,MAAS,MAAA;;AAC3B,eAAAL,EAAO,UAAU,aACZS,IAAA5D,EAAM,gBAAN,gBAAA4D,EAAmB,WAAU,WAC7BC,IAAA7D,EAAM,gBAAN,gBAAA6D,EAAmB,YAAW;AAAA;AAAA,IAAA,GAG/BC,IAAgBN;AAAA,MAAS,MAAA;;AAC7B,eAAAL,EAAO,UAAU,aACZS,IAAA5D,EAAM,kBAAN,gBAAA4D,EAAqB,WAAU,YAC/BC,IAAA7D,EAAM,kBAAN,gBAAA6D,EAAqB,YAAW;AAAA;AAAA,IAAA,GAGjCzD,IAAUoD,EAAS,MAAA;;AAAM,eAAAI,IAAAV,EAAa,UAAb,gBAAAU,EAAoB,YAAW;AAAA,KAAI;AAElE,mBAAeG,IAAW;AACxB,YAAMlD,IAAKT,EAAQ;AACnB,UAAKS;AACL,YAAI;AACF,UAAIA,EAAG,aAAa,KAAGA,EAAG,KAAA;AAC1B,gBAAMmD,IAAInD,EAAG,KAAA;AACb,UAAAyC,EAAY,QAAQU,GACpB,MAAMA,GACNZ,EAAU,QAAQ;AAAA,QACpB,QAAQ;AACN,UAAAA,EAAU,QAAQ;AAAA,QACpB,UAAA;AACE,UAAAE,EAAY,QAAQ;AAAA,QACtB;AAAA,IACF;AAEA,mBAAeW,IAAY;AACzB,YAAMpD,IAAKT,EAAQ;AACnB,UAAKS,GACL;AAAA,YAAIyC,EAAY;AACd,cAAI;AACF,kBAAMA,EAAY;AAAA,UACpB,QAAQ;AAAA,UAER;AAEF,QAAAzC,EAAG,MAAA;AAAA;AAAA,IACL;AAEA,mBAAeqD,IAAa;AAC1B,MAAI,CAAClE,EAAM,aAAayD,EAAU,SAClC,MAAMM,EAAA;AAAA,IACR;AAEA,mBAAeI,IAAY;AACzB,MAAI,CAACnE,EAAM,aAAayD,EAAU,UAClC,MAAMQ,EAAA,GACNb,EAAU,QAAQ;AAAA,IACpB;AAEA,mBAAegB,IAAa;AAC1B,YAAMvD,IAAKT,EAAQ;AACnB,MAAKS,MACDA,EAAG,SACL,MAAMkD,EAAA,KAEN,MAAME,EAAA,GACNb,EAAU,QAAQ;AAAA,IAEtB;AAEA,aAASiB,IAAe;AACtB,MAAAhB,EAAY,QAAQ,IACfa,EAAA;AAAA,IACP;AAEA,aAASI,IAAe;AACtB,MAAAjB,EAAY,QAAQ,IACfc,EAAA;AAAA,IACP;2BAIE5C,EAgGM,OAAA;AAAA,MA/FH,OAAKC,EAAA,CAAA,YAAexB,EAAM,KAAK,CAAA;AAAA,MAC/B,OAAKuE,EAAA,EAAA,OAAWT,EAAA,OAAa,aAAEH,EAAA,OAAW;AAAA,MAC1C,cAAYU;AAAA,MACZ,cAAYC;AAAA,IAAA;MAGLb,EAAA,cADRlC,EAQE,UAAA;AAAA;QANA,OAAM;AAAA,QACL,KAAKmC,EAAA,SAAc;AAAA,QACpB,OAAM;AAAA,QACN,OAAM;AAAA,QACN,iBAAA;AAAA,QACA,gBAAe;AAAA,MAAA,yBAEjBc,EAwBYC,GAAA;AAAA;iBAtBN;AAAA,QAAJ,KAAIvB;AAAA,QACH,UAAUjD,EAAA;AAAA,QACV,cAAYA,EAAA;AAAA,QACZ,UAAQA,EAAA;AAAA,QACR,MAAMA,EAAA;AAAA,QACN,OAAOA,EAAA;AAAA,QACP,aAAWA,EAAA;AAAA,QACX,gBAAc;AAAA,QACd,QAAQA,EAAA;AAAA,QACR,KAAKA,EAAA;AAAA,QACN,OAAM;AAAA,QACN,SAAQ;AAAA,QACP,SAAKyE,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAC,MAAA;AAAW,UAAAvB,EAAA,QAAS,IAAkBlD,EAAI,OAAA;AAAA;QAI/C,QAAIwE,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAC,MAAA;AAAW,UAAAvB,EAAA,QAAS,IAAiBlD,EAAI,MAAA;AAAA;;mBAK9C,MAAQ;AAAA,UAARuB,EAAQC,EAAA,QAAA,SAAA;AAAA,QAAA;;;MAGE+B,EAAA,qBAAZmB,EAAA,GAAArD,EAA8C,OAA9CsD,EAA8C;AAAA,MAEnC5E,EAAA,oBAAX2E,EAAA,GAAArD,EAwBM,OAxBNuD,IAwBM;AAAA,QAvBJlD,EAsBM,OAtBNmD,IAsBM;AAAA,UArBJnD,EAQS,UAAA;AAAA,YAPN,gBAAcuB,EAAA,UAAM;AAAA,YACpB,2CAAyCA,EAAA,UAAM,UAAA,CAAA,CAAA;AAAA,YAChD,cAAW;AAAA,YACX,MAAK;AAAA,YACJ,gCAAOA,EAAA,QAAM;AAAA,UAAA;YAEd6B,EAAeC,CAAA;AAAA,UAAA;0BAGjBrD,EAAkC,OAAA,EAA7B,OAAM,qBAAA,GAAoB,MAAA,EAAA;AAAA,UAE/BA,EAQS,UAAA;AAAA,YAPN,gBAAcuB,EAAA,UAAM;AAAA,YACpB,2CAAyCA,EAAA,UAAM,SAAA,CAAA,CAAA;AAAA,YAChD,cAAW;AAAA,YACX,MAAK;AAAA,YACJ,gCAAOA,EAAA,QAAM;AAAA,UAAA;YAEd6B,EAAcE,CAAA;AAAA,UAAA;;;MAMZjF,EAAA,iBADRsB,EAQS,UAAA;AAAA;QANP,cAAW;AAAA,QACX,OAAM;AAAA,QACN,MAAK;AAAA,QACJ,gCAAOrB,EAAI,OAAA;AAAA,MAAA;QAEZ8E,EAASG,CAAA;AAAA,MAAA;MAGC,CAAA1B,EAAA,UAAcL,EAAA,SAA1BwB,KAAArD,EAcM,OAdN6D,IAcM;AAAA,QAbJxD,EAYS,UAAA;AAAA,UAXP,cAAW;AAAA,UACX,OAAM;AAAA,UACN,MAAK;AAAA,UACJ,SAAOwC;AAAA,UACP,qCAAYf,EAAA,QAAW;AAAA,UACvB,qCAAYA,EAAA,QAAW;AAAA,QAAA;UAExB2B,EAAYK,CAAA;AAAA,UACApF,EAAA,eAAeoD,EAAA,cAA3B9B,EAEO,QAFP+D,IAEOC,EADFtF,EAAA,WAAW,GAAA,CAAA;;;MAKRwD,EAAA,qBAAZmB,KAAArD,EAAiD,OAAjDiE,EAAiD;AAAA;;;"}
package/dist/style.css CHANGED
@@ -1,4 +1,4 @@
1
1
  /*!
2
2
  * @glitchlab/vue-video-player styles
3
3
  * Scoped under .gvp-root — no global resets, no theme tokens, safe for any host.
4
- */.gvp-root{position:relative;overflow:hidden;border-radius:1.5rem;background-color:#1717174d;box-shadow:0 25px 50px -12px #00000040;outline:1px solid rgb(255 255 255 / .1);outline-offset:-1px;margin-left:auto;margin-right:auto;width:100%;box-sizing:border-box}.gvp-root *,.gvp-root *:before,.gvp-root *:after{box-sizing:border-box}.gvp-video{height:100%;width:100%;object-fit:cover;display:block}.gvp-vignette{pointer-events:none;position:absolute;top:0;right:0;bottom:0;left:0;background-image:linear-gradient(to top right,#00000059,#0000,#00000059)}.gvp-bottom-fade{pointer-events:none;position:absolute;bottom:0;left:0;right:0;height:4rem;background-image:linear-gradient(to top,rgb(0 0 0 / .35),transparent)}.gvp-toggle{position:absolute;left:1rem;top:1rem}.gvp-toggle-pill{display:flex;align-items:center;overflow:hidden;border-radius:1rem;background-color:#fffffff2;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;outline:1px solid rgb(0 0 0 / .05);outline-offset:-1px}.gvp-toggle-btn{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;font-weight:600;cursor:pointer;background:transparent;border:0;color:#737373;transition:color .15s ease;font-family:inherit}.gvp-toggle-btn:hover{color:#404040}.gvp-toggle-btn.is-active{color:#5b21b6}.gvp-toggle-divider{height:1.75rem;width:1px;background-color:#e5e5e5}.gvp-close{position:absolute;right:1rem;top:1rem;display:grid;place-items:center;height:2.5rem;width:2.5rem;border:0;border-radius:9999px;background-color:#00000059;color:#fff;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);outline:1px solid rgb(255 255 255 / .15);outline-offset:-1px;cursor:pointer;z-index:10;transition:background-color .15s ease}.gvp-close:hover{background-color:#00000080}.gvp-play-wrap{position:absolute;top:0;right:0;bottom:0;left:0;display:grid;place-items:center}.gvp-play{position:relative;display:grid;place-items:center;height:3.5rem;width:3.5rem;border:0;border-radius:9999px;cursor:pointer;outline:1px solid rgb(255 255 255 / .15);outline-offset:-1px;background-color:#5b21b680;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a;transition:background-color .2s ease,opacity .2s ease;color:#fff}.gvp-play:hover{background-color:#5b21b6e6}.gvp-tooltip{position:absolute;top:-3rem;left:50%;transform:translate(-50%);white-space:nowrap;border-radius:.75rem;background-color:#000000b3;padding:.375rem .75rem;font-size:.75rem;line-height:1rem;color:#fff;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;outline:1px solid rgb(255 255 255 / .1);outline-offset:-1px;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.gvp-icon{display:block}
4
+ */.gvp-root{position:relative;overflow:hidden;border-radius:1.5rem;background-color:#1717174d;box-shadow:0 25px 50px -12px #00000040;outline:1px solid rgb(255 255 255 / .1);outline-offset:-1px;margin-left:auto;margin-right:auto;width:100%;box-sizing:border-box}.gvp-root *,.gvp-root *:before,.gvp-root *:after{box-sizing:border-box}.gvp-video{height:100%;width:100%;object-fit:cover;display:block}.gvp-youtube{border:0;object-fit:contain}.gvp-vignette{pointer-events:none;position:absolute;top:0;right:0;bottom:0;left:0;background-image:linear-gradient(to top right,#00000059,#0000,#00000059)}.gvp-bottom-fade{pointer-events:none;position:absolute;bottom:0;left:0;right:0;height:4rem;background-image:linear-gradient(to top,rgb(0 0 0 / .35),transparent)}.gvp-toggle{position:absolute;left:1rem;top:1rem}.gvp-toggle-pill{display:flex;align-items:center;overflow:hidden;border-radius:1rem;background-color:#fffffff2;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;outline:1px solid rgb(0 0 0 / .05);outline-offset:-1px}.gvp-toggle-btn{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;font-weight:600;cursor:pointer;background:transparent;border:0;color:#737373;transition:color .15s ease;font-family:inherit}.gvp-toggle-btn:hover{color:#404040}.gvp-toggle-btn.is-active{color:#5b21b6}.gvp-toggle-divider{height:1.75rem;width:1px;background-color:#e5e5e5}.gvp-close{position:absolute;right:1rem;top:1rem;display:grid;place-items:center;height:2.5rem;width:2.5rem;border:0;border-radius:9999px;background-color:#00000059;color:#fff;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);outline:1px solid rgb(255 255 255 / .15);outline-offset:-1px;cursor:pointer;z-index:10;transition:background-color .15s ease}.gvp-close:hover{background-color:#00000080}.gvp-play-wrap{position:absolute;top:0;right:0;bottom:0;left:0;display:grid;place-items:center}.gvp-play{position:relative;display:grid;place-items:center;height:3.5rem;width:3.5rem;border:0;border-radius:9999px;cursor:pointer;outline:1px solid rgb(255 255 255 / .15);outline-offset:-1px;background-color:#5b21b680;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a;transition:background-color .2s ease,opacity .2s ease;color:#fff}.gvp-play:hover{background-color:#5b21b6e6}.gvp-tooltip{position:absolute;top:-3rem;left:50%;transform:translate(-50%);white-space:nowrap;border-radius:.75rem;background-color:#000000b3;padding:.375rem .75rem;font-size:.75rem;line-height:1rem;color:#fff;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;outline:1px solid rgb(255 255 255 / .1);outline-offset:-1px;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.gvp-icon{display:block}
@@ -21,6 +21,12 @@ export interface VideoPlayerProps {
21
21
  loop?: boolean;
22
22
  /** Show native browser controls. Defaults to `false`. */
23
23
  controls?: boolean;
24
+ /**
25
+ * Start playback as soon as the source loads. Defaults to `false`.
26
+ * Browsers block sound-on autoplay, so this only autoplays when `muted`
27
+ * is also `true` (which is the default).
28
+ */
29
+ autoPlay?: boolean;
24
30
  /** Maximum width of the player in each device mode. */
25
31
  frameMaxWidth?: {
26
32
  desktop?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9C,MAAM,MAAM,WAAW,GAAG,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;AAEhD,MAAM,WAAW,gBAAgB;IAC/B,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oDAAoD;IACpD,aAAa,CAAC,EAAE,UAAU,CAAC;IAE3B,gFAAgF;IAChF,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,uDAAuD;IACvD,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IAEF,wCAAwC;IACxC,WAAW,CAAC,EAAE;QACZ,OAAO,CAAC,EAAE,WAAW,CAAC;QACtB,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,CAAC;IAEF;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9C,MAAM,MAAM,WAAW,GAAG,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;AAEhD,MAAM,WAAW,gBAAgB;IAC/B,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oDAAoD;IACpD,aAAa,CAAC,EAAE,UAAU,CAAC;IAE3B,gFAAgF;IAChF,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,uDAAuD;IACvD,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IAEF,wCAAwC;IACxC,WAAW,CAAC,EAAE;QACZ,OAAO,CAAC,EAAE,WAAW,CAAC;QACtB,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,CAAC;IAEF;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Extract a YouTube video ID from any common URL form, or `null` if the URL
3
+ * isn't a YouTube link.
4
+ *
5
+ * Recognised:
6
+ * - https://www.youtube.com/watch?v=ID
7
+ * - https://youtube.com/watch?v=ID&t=42
8
+ * - https://youtu.be/ID
9
+ * - https://youtu.be/ID?t=42
10
+ * - https://www.youtube.com/embed/ID
11
+ * - https://www.youtube.com/shorts/ID
12
+ * - https://music.youtube.com/watch?v=ID
13
+ * - bare 11-character video IDs
14
+ */
15
+ export declare function parseYouTubeId(input: string): string | null;
16
+ /** Extract a `t`/`start` timestamp (in seconds) from a YouTube URL, if present. */
17
+ export declare function parseYouTubeStart(input: string): number | null;
18
+ export interface YouTubeEmbedOptions {
19
+ /** Start playback immediately. Forces `mute` on, since browsers block sound-on autoplay. */
20
+ autoPlay?: boolean;
21
+ /** Mute the player. */
22
+ muted?: boolean;
23
+ /** Loop the video. */
24
+ loop?: boolean;
25
+ /** Show YouTube's player controls. Defaults to `true`. */
26
+ controls?: boolean;
27
+ /** Start offset in seconds. */
28
+ startSeconds?: number | null;
29
+ }
30
+ /**
31
+ * Build a privacy-enhanced YouTube embed URL from a video ID and player options.
32
+ *
33
+ * Notes on YouTube's quirks:
34
+ * - `autoplay=1` only takes effect if `mute=1` is also set (browser policy).
35
+ * - single-video loop requires `loop=1` **and** `playlist=<id>`.
36
+ */
37
+ export declare function youTubeEmbedUrl(id: string, opts?: YouTubeEmbedOptions): string;
38
+ //# sourceMappingURL=youtube.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"youtube.d.ts","sourceRoot":"","sources":["../../src/utils/youtube.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmC3D;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkB9D;AAED,MAAM,WAAW,mBAAmB;IAClC,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uBAAuB;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sBAAsB;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,mBAAwB,GAC7B,MAAM,CAiCR"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glitchlab/vue-video-player",
3
- "version": "1.0.2",
3
+ "version": "1.1.1",
4
4
  "description": "Vue 3 / Nuxt 3 video player with HLS support, device-mode toggle, hover-to-play, and zero global CSS side-effects.",
5
5
  "license": "MIT",
6
6
  "author": "im-fahad",