@guardvideo/player-sdk 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -17
- package/dist/index.esm.js +1186 -566
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1185 -565
- package/dist/index.js.map +1 -1
- package/dist/react/GuardVideoPlayer.d.ts +8 -5
- package/dist/react/GuardVideoPlayer.d.ts.map +1 -1
- package/dist/ui/PlayerUI.d.ts +95 -0
- package/dist/ui/PlayerUI.d.ts.map +1 -0
- package/dist/vanilla/guardvideo-player.js +1040 -328
- package/dist/vanilla/guardvideo-player.js.map +1 -1
- package/dist/vanilla/guardvideo-player.min.js +1 -1
- package/dist/vanilla/guardvideo-player.min.js.map +1 -1
- package/dist/vanilla/index.d.ts +25 -6
- package/dist/vanilla/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/vanilla/core/player.d.ts +0 -54
- package/dist/vanilla/core/player.d.ts.map +0 -1
- package/dist/vanilla/core/types.d.ts +0 -100
- package/dist/vanilla/core/types.d.ts.map +0 -1
- package/dist/vanilla/react/GuardVideoPlayer.d.ts +0 -21
- package/dist/vanilla/react/GuardVideoPlayer.d.ts.map +0 -1
- package/dist/vanilla/react/hooks.d.ts +0 -28
- package/dist/vanilla/react/hooks.d.ts.map +0 -1
- package/dist/vanilla/vanilla/index.d.ts +0 -118
- package/dist/vanilla/vanilla/index.d.ts.map +0 -1
|
@@ -37281,14 +37281,14 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
|
|
|
37281
37281
|
}
|
|
37282
37282
|
};
|
|
37283
37283
|
|
|
37284
|
-
function formatTime(
|
|
37285
|
-
if (!isFinite(
|
|
37284
|
+
function formatTime(s) {
|
|
37285
|
+
if (!isFinite(s) || isNaN(s))
|
|
37286
37286
|
return '0:00';
|
|
37287
|
-
const h = Math.floor(
|
|
37288
|
-
const m = Math.floor((
|
|
37289
|
-
const
|
|
37287
|
+
const h = Math.floor(s / 3600);
|
|
37288
|
+
const m = Math.floor((s % 3600) / 60);
|
|
37289
|
+
const sc = Math.floor(s % 60);
|
|
37290
37290
|
const mm = String(m).padStart(h > 0 ? 2 : 1, '0');
|
|
37291
|
-
const ss = String(
|
|
37291
|
+
const ss = String(sc).padStart(2, '0');
|
|
37292
37292
|
return h > 0 ? `${h}:${mm}:${ss}` : `${mm}:${ss}`;
|
|
37293
37293
|
}
|
|
37294
37294
|
function el(tag, cls, attrs) {
|
|
@@ -37296,15 +37296,17 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
|
|
|
37296
37296
|
if (cls)
|
|
37297
37297
|
e.className = cls;
|
|
37298
37298
|
if (attrs)
|
|
37299
|
-
|
|
37299
|
+
for (const [k, v] of Object.entries(attrs))
|
|
37300
|
+
e.setAttribute(k, v);
|
|
37300
37301
|
return e;
|
|
37301
37302
|
}
|
|
37302
|
-
function
|
|
37303
|
+
function svgEl(path, w = 20, h = 20) {
|
|
37303
37304
|
const s = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
37304
37305
|
s.setAttribute('width', String(w));
|
|
37305
37306
|
s.setAttribute('height', String(h));
|
|
37306
37307
|
s.setAttribute('viewBox', '0 0 24 24');
|
|
37307
37308
|
s.setAttribute('fill', 'currentColor');
|
|
37309
|
+
s.setAttribute('aria-hidden', 'true');
|
|
37308
37310
|
s.innerHTML = path;
|
|
37309
37311
|
return s;
|
|
37310
37312
|
}
|
|
@@ -37313,114 +37315,668 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
|
|
|
37313
37315
|
pause: '<rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/>',
|
|
37314
37316
|
replay: '<path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/>',
|
|
37315
37317
|
volHigh: '<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>',
|
|
37318
|
+
volMid: '<path d="M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z"/>',
|
|
37319
|
+
volLow: '<path d="M7 9v6h4l5 5V4l-5 5H7z"/>',
|
|
37316
37320
|
volMute: '<path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>',
|
|
37317
37321
|
fsEnter: '<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/>',
|
|
37318
37322
|
fsExit: '<path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"/>',
|
|
37319
37323
|
settings: '<path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94zM12,15.6c-1.98,0-3.6-1.62-3.6-3.6s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/>',
|
|
37320
|
-
shield: '<path fill="none" stroke="currentColor" stroke-width="2
|
|
37321
|
-
|
|
37324
|
+
shield: '<path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 12l2 2 4-4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'};
|
|
37325
|
+
const SPEEDS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
|
|
37322
37326
|
let _stylesInjected = false;
|
|
37323
|
-
function injectStyles(
|
|
37327
|
+
function injectStyles() {
|
|
37324
37328
|
if (_stylesInjected)
|
|
37325
37329
|
return;
|
|
37326
37330
|
_stylesInjected = true;
|
|
37327
37331
|
const css = `
|
|
37328
|
-
/* ── GuardVideo
|
|
37329
|
-
|
|
37330
|
-
|
|
37331
|
-
.
|
|
37332
|
+
/* ── GuardVideo Player UI v2 ──────────────────────────────── */
|
|
37333
|
+
|
|
37334
|
+
/* Google Font import — Outfit for labels, DM Mono for time */
|
|
37335
|
+
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&family=DM+Mono:wght@400;500&display=swap');
|
|
37336
|
+
|
|
37337
|
+
/* ── Root ─────────────────────────────────────────────────── */
|
|
37338
|
+
.gvp-root {
|
|
37339
|
+
--gvp-accent: #00e5a0;
|
|
37340
|
+
--gvp-accent-dim: rgba(0, 229, 160, 0.18);
|
|
37341
|
+
--gvp-accent-glow: rgba(0, 229, 160, 0.35);
|
|
37342
|
+
--gvp-glass-bg: rgba(8, 8, 14, 0.72);
|
|
37343
|
+
--gvp-glass-bdr: rgba(255,255,255,0.07);
|
|
37344
|
+
--gvp-text: rgba(255,255,255,0.92);
|
|
37345
|
+
--gvp-text-dim: rgba(255,255,255,0.45);
|
|
37346
|
+
--gvp-radius: 12px;
|
|
37347
|
+
--gvp-font: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
37348
|
+
--gvp-mono: 'DM Mono', 'SF Mono', 'Fira Mono', monospace;
|
|
37349
|
+
|
|
37350
|
+
position: relative;
|
|
37351
|
+
background: #050508;
|
|
37352
|
+
font-family: var(--gvp-font);
|
|
37353
|
+
border-radius: var(--gvp-radius);
|
|
37354
|
+
overflow: hidden;
|
|
37355
|
+
-webkit-user-select: none;
|
|
37356
|
+
-moz-user-select: none;
|
|
37357
|
+
-ms-user-select: none;
|
|
37358
|
+
user-select: none;
|
|
37359
|
+
outline: none;
|
|
37360
|
+
|
|
37361
|
+
/* Subtle inner vignette for cinema depth */
|
|
37362
|
+
box-shadow:
|
|
37363
|
+
inset 0 0 80px rgba(0,0,0,0.55),
|
|
37364
|
+
0 24px 80px rgba(0,0,0,0.6);
|
|
37365
|
+
}
|
|
37366
|
+
|
|
37367
|
+
.gvp-root:focus-visible {
|
|
37368
|
+
outline: 2px solid var(--gvp-accent);
|
|
37369
|
+
outline-offset: 2px;
|
|
37370
|
+
}
|
|
37371
|
+
|
|
37372
|
+
/* ── Video ────────────────────────────────────────────────── */
|
|
37373
|
+
.gvp-video {
|
|
37374
|
+
display: block;
|
|
37375
|
+
width: 100%;
|
|
37376
|
+
height: 100%;
|
|
37377
|
+
-o-object-fit: contain;
|
|
37378
|
+
object-fit: contain;
|
|
37379
|
+
}
|
|
37380
|
+
|
|
37381
|
+
/* ── Utility ──────────────────────────────────────────────── */
|
|
37382
|
+
.gvp-hidden { display: none !important; }
|
|
37383
|
+
.gvp-controls-hidden { opacity: 0; -webkit-transform: translateY(8px); transform: translateY(8px); pointer-events: none; }
|
|
37384
|
+
|
|
37385
|
+
/* ── Gradient overlay (top + bottom) ─────────────────────── */
|
|
37386
|
+
.gvp-root::before,
|
|
37387
|
+
.gvp-root::after {
|
|
37388
|
+
content: '';
|
|
37389
|
+
position: absolute;
|
|
37390
|
+
left: 0; right: 0;
|
|
37391
|
+
pointer-events: none;
|
|
37392
|
+
z-index: 2;
|
|
37393
|
+
}
|
|
37394
|
+
.gvp-root::before {
|
|
37395
|
+
top: 0;
|
|
37396
|
+
height: 90px;
|
|
37397
|
+
background: -webkit-linear-gradient(bottom, transparent, rgba(0,0,0,0.55));
|
|
37398
|
+
background: linear-gradient(to bottom, rgba(0,0,0,0.55), transparent);
|
|
37399
|
+
border-radius: var(--gvp-radius) var(--gvp-radius) 0 0;
|
|
37400
|
+
}
|
|
37401
|
+
.gvp-root::after {
|
|
37402
|
+
bottom: 0;
|
|
37403
|
+
height: 160px;
|
|
37404
|
+
background: -webkit-linear-gradient(top, transparent, rgba(0,0,0,0.88));
|
|
37405
|
+
background: linear-gradient(to bottom, transparent, rgba(0,0,0,0.88));
|
|
37406
|
+
border-radius: 0 0 var(--gvp-radius) var(--gvp-radius);
|
|
37407
|
+
}
|
|
37408
|
+
|
|
37409
|
+
/* ── Spinner ──────────────────────────────────────────────── */
|
|
37410
|
+
.gvp-spinner {
|
|
37411
|
+
position: absolute; inset: 0;
|
|
37412
|
+
display: -webkit-box; display: -ms-flexbox; display: flex;
|
|
37413
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37414
|
+
-webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
|
|
37415
|
+
pointer-events: none;
|
|
37416
|
+
z-index: 8;
|
|
37417
|
+
}
|
|
37418
|
+
.gvp-spinner-ring {
|
|
37419
|
+
width: 44px; height: 44px;
|
|
37420
|
+
border: 2.5px solid rgba(255,255,255,0.08);
|
|
37421
|
+
border-top-color: var(--gvp-accent);
|
|
37422
|
+
border-radius: 50%;
|
|
37423
|
+
-webkit-animation: gvp-spin 0.75s linear infinite;
|
|
37424
|
+
animation: gvp-spin 0.75s linear infinite;
|
|
37425
|
+
box-shadow: 0 0 16px var(--gvp-accent-glow);
|
|
37426
|
+
}
|
|
37427
|
+
@-webkit-keyframes gvp-spin { to { -webkit-transform: rotate(360deg); transform: rotate(360deg); } }
|
|
37428
|
+
@keyframes gvp-spin { to { -webkit-transform: rotate(360deg); transform: rotate(360deg); } }
|
|
37429
|
+
|
|
37430
|
+
/* ── Centre play overlay ──────────────────────────────────── */
|
|
37431
|
+
.gvp-center-play {
|
|
37432
|
+
position: absolute; inset: 0; z-index: 6;
|
|
37433
|
+
display: -webkit-box; display: -ms-flexbox; display: flex;
|
|
37434
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37435
|
+
-webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
|
|
37436
|
+
cursor: pointer;
|
|
37437
|
+
background: transparent;
|
|
37438
|
+
-webkit-transition: background 0.25s; transition: background 0.25s;
|
|
37439
|
+
border-radius: var(--gvp-radius);
|
|
37440
|
+
}
|
|
37441
|
+
.gvp-center-play:hover { background: rgba(0,0,0,0.22); }
|
|
37442
|
+
|
|
37443
|
+
.gvp-center-play-btn {
|
|
37444
|
+
position: relative;
|
|
37445
|
+
width: 76px; height: 76px;
|
|
37446
|
+
border-radius: 50%;
|
|
37447
|
+
display: -webkit-box; display: -ms-flexbox; display: flex;
|
|
37448
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37449
|
+
-webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
|
|
37450
|
+
color: #fff;
|
|
37451
|
+
/* Glass morphism */
|
|
37452
|
+
background: rgba(255,255,255,0.10);
|
|
37453
|
+
-webkit-backdrop-filter: blur(16px) saturate(180%);
|
|
37454
|
+
backdrop-filter: blur(16px) saturate(180%);
|
|
37455
|
+
border: 1px solid rgba(255,255,255,0.18);
|
|
37456
|
+
-webkit-transition: background 0.2s, -webkit-transform 0.2s, -webkit-box-shadow 0.2s;
|
|
37457
|
+
transition: background 0.2s, transform 0.2s, box-shadow 0.2s;
|
|
37458
|
+
box-shadow: 0 4px 32px rgba(0,0,0,0.45), 0 0 0 0 var(--gvp-accent-glow);
|
|
37459
|
+
}
|
|
37460
|
+
/* Ripple ring on hover */
|
|
37461
|
+
.gvp-center-play-btn::after {
|
|
37462
|
+
content: '';
|
|
37463
|
+
position: absolute; inset: -4px;
|
|
37464
|
+
border-radius: 50%;
|
|
37465
|
+
border: 1.5px solid rgba(255,255,255,0.12);
|
|
37466
|
+
-webkit-transition: border-color 0.2s, opacity 0.2s; transition: border-color 0.2s, opacity 0.2s;
|
|
37467
|
+
opacity: 0;
|
|
37468
|
+
}
|
|
37469
|
+
.gvp-center-play:hover .gvp-center-play-btn::after {
|
|
37470
|
+
opacity: 1;
|
|
37471
|
+
border-color: var(--gvp-accent);
|
|
37472
|
+
}
|
|
37473
|
+
.gvp-center-play:hover .gvp-center-play-btn {
|
|
37474
|
+
background: var(--gvp-accent-dim);
|
|
37475
|
+
-webkit-transform: scale(1.07);
|
|
37476
|
+
transform: scale(1.07);
|
|
37477
|
+
box-shadow: 0 4px 40px rgba(0,0,0,0.55), 0 0 28px var(--gvp-accent-glow);
|
|
37478
|
+
}
|
|
37479
|
+
|
|
37480
|
+
/* ── Click-to-toggle overlay ─────────────────────────────── */
|
|
37481
|
+
.gvp-click-area {
|
|
37482
|
+
position: absolute; inset: 0;
|
|
37483
|
+
cursor: pointer; z-index: 4;
|
|
37484
|
+
}
|
|
37485
|
+
|
|
37486
|
+
/* ── Ripple animation ─────────────────────────────────────── */
|
|
37487
|
+
.gvp-ripple {
|
|
37488
|
+
position: absolute; border-radius: 50%;
|
|
37489
|
+
-webkit-transform: scale(0); transform: scale(0);
|
|
37490
|
+
background: rgba(255,255,255,0.18);
|
|
37491
|
+
-webkit-animation: gvp-ripple-anim 0.55s cubic-bezier(0.22,1,0.36,1) forwards;
|
|
37492
|
+
animation: gvp-ripple-anim 0.55s cubic-bezier(0.22,1,0.36,1) forwards;
|
|
37493
|
+
pointer-events: none; z-index: 5;
|
|
37494
|
+
}
|
|
37495
|
+
@-webkit-keyframes gvp-ripple-anim { to { -webkit-transform: scale(5); transform: scale(5); opacity: 0; } }
|
|
37496
|
+
@keyframes gvp-ripple-anim { to { -webkit-transform: scale(5); transform: scale(5); opacity: 0; } }
|
|
37497
|
+
|
|
37498
|
+
/* ── Controls bar ─────────────────────────────────────────── */
|
|
37499
|
+
.gvp-controls {
|
|
37500
|
+
position: absolute;
|
|
37501
|
+
bottom: 0; left: 0; right: 0;
|
|
37502
|
+
z-index: 10;
|
|
37503
|
+
padding: 0 14px 14px;
|
|
37504
|
+
-webkit-transition: opacity 0.35s cubic-bezier(0.4,0,0.2,1),
|
|
37505
|
+
-webkit-transform 0.35s cubic-bezier(0.4,0,0.2,1);
|
|
37506
|
+
transition: opacity 0.35s cubic-bezier(0.4,0,0.2,1),
|
|
37507
|
+
transform 0.35s cubic-bezier(0.4,0,0.2,1);
|
|
37508
|
+
border-radius: 0 0 var(--gvp-radius) var(--gvp-radius);
|
|
37509
|
+
}
|
|
37510
|
+
|
|
37511
|
+
/* Inner glass pill that wraps all controls */
|
|
37512
|
+
.gvp-controls-inner {
|
|
37513
|
+
background: var(--gvp-glass-bg);
|
|
37514
|
+
-webkit-backdrop-filter: blur(24px) saturate(160%);
|
|
37515
|
+
backdrop-filter: blur(24px) saturate(160%);
|
|
37516
|
+
border: 1px solid var(--gvp-glass-bdr);
|
|
37517
|
+
border-radius: 10px;
|
|
37518
|
+
padding: 10px 12px 10px;
|
|
37519
|
+
-webkit-box-shadow: 0 8px 32px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.05);
|
|
37520
|
+
box-shadow: 0 8px 32px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.05);
|
|
37521
|
+
}
|
|
37522
|
+
|
|
37523
|
+
/* ── Seek row ─────────────────────────────────────────────── */
|
|
37524
|
+
.gvp-seek-row {
|
|
37525
|
+
display: -webkit-box; display: -ms-flexbox; display: flex;
|
|
37526
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37527
|
+
gap: 8px;
|
|
37528
|
+
margin-bottom: 8px;
|
|
37529
|
+
}
|
|
37530
|
+
|
|
37531
|
+
.gvp-seek-wrap {
|
|
37532
|
+
-webkit-box-flex: 1; -ms-flex: 1; flex: 1;
|
|
37533
|
+
position: relative;
|
|
37534
|
+
height: 4px;
|
|
37535
|
+
cursor: pointer;
|
|
37536
|
+
padding: 8px 0;
|
|
37537
|
+
margin: -8px 0;
|
|
37538
|
+
-webkit-box-sizing: content-box; box-sizing: content-box;
|
|
37539
|
+
touch-action: none;
|
|
37540
|
+
}
|
|
37541
|
+
|
|
37542
|
+
.gvp-seek-track {
|
|
37543
|
+
height: 3px;
|
|
37544
|
+
background: rgba(255,255,255,0.12);
|
|
37545
|
+
border-radius: 99px;
|
|
37546
|
+
position: relative;
|
|
37547
|
+
overflow: visible;
|
|
37548
|
+
-webkit-transition: height 0.15s; transition: height 0.15s;
|
|
37549
|
+
pointer-events: none;
|
|
37550
|
+
}
|
|
37551
|
+
.gvp-seek-wrap:hover .gvp-seek-track,
|
|
37552
|
+
.gvp-seek-wrap.gvp-dragging .gvp-seek-track { height: 5px; }
|
|
37553
|
+
|
|
37554
|
+
.gvp-seek-buffered {
|
|
37555
|
+
position: absolute; left: 0; top: 0; height: 100%;
|
|
37556
|
+
background: rgba(255,255,255,0.22);
|
|
37557
|
+
border-radius: 99px;
|
|
37558
|
+
pointer-events: none;
|
|
37559
|
+
-webkit-transition: width 0.3s; transition: width 0.3s;
|
|
37560
|
+
}
|
|
37561
|
+
|
|
37562
|
+
.gvp-seek-progress {
|
|
37563
|
+
position: absolute; left: 0; top: 0; height: 100%;
|
|
37564
|
+
background: -webkit-linear-gradient(left, var(--gvp-accent), color-mix(in srgb, var(--gvp-accent) 80%, #fff 20%));
|
|
37565
|
+
background: linear-gradient(to right, var(--gvp-accent), color-mix(in srgb, var(--gvp-accent) 80%, #fff 20%));
|
|
37566
|
+
border-radius: 99px;
|
|
37567
|
+
pointer-events: none;
|
|
37568
|
+
/* Glow on the progress fill */
|
|
37569
|
+
-webkit-box-shadow: 0 0 8px var(--gvp-accent-glow);
|
|
37570
|
+
box-shadow: 0 0 8px var(--gvp-accent-glow);
|
|
37571
|
+
}
|
|
37332
37572
|
|
|
37333
|
-
/*
|
|
37334
|
-
.gvp-
|
|
37335
|
-
|
|
37336
|
-
|
|
37337
|
-
|
|
37573
|
+
/* Thumb — visible on hover/drag */
|
|
37574
|
+
.gvp-seek-thumb {
|
|
37575
|
+
position: absolute; top: 50%;
|
|
37576
|
+
-webkit-transform: translate(-50%, -50%) scale(0);
|
|
37577
|
+
transform: translate(-50%, -50%) scale(0);
|
|
37578
|
+
width: 14px; height: 14px;
|
|
37579
|
+
background: #fff;
|
|
37580
|
+
border-radius: 50%;
|
|
37581
|
+
pointer-events: none;
|
|
37582
|
+
-webkit-box-shadow: 0 0 0 3px var(--gvp-accent-dim), 0 2px 6px rgba(0,0,0,0.5);
|
|
37583
|
+
box-shadow: 0 0 0 3px var(--gvp-accent-dim), 0 2px 6px rgba(0,0,0,0.5);
|
|
37584
|
+
-webkit-transition: -webkit-transform 0.15s cubic-bezier(0.34,1.56,0.64,1);
|
|
37585
|
+
transition: transform 0.15s cubic-bezier(0.34,1.56,0.64,1);
|
|
37586
|
+
}
|
|
37587
|
+
.gvp-seek-wrap:hover .gvp-seek-thumb,
|
|
37588
|
+
.gvp-seek-wrap.gvp-dragging .gvp-seek-thumb {
|
|
37589
|
+
-webkit-transform: translate(-50%,-50%) scale(1);
|
|
37590
|
+
transform: translate(-50%,-50%) scale(1);
|
|
37591
|
+
}
|
|
37338
37592
|
|
|
37339
|
-
/*
|
|
37340
|
-
.gvp-
|
|
37341
|
-
|
|
37342
|
-
|
|
37343
|
-
|
|
37344
|
-
|
|
37593
|
+
/* Seek tooltip */
|
|
37594
|
+
.gvp-seek-tooltip {
|
|
37595
|
+
position: absolute;
|
|
37596
|
+
bottom: 26px;
|
|
37597
|
+
-webkit-transform: translateX(-50%);
|
|
37598
|
+
transform: translateX(-50%);
|
|
37599
|
+
background: rgba(10,10,14,0.92);
|
|
37600
|
+
-webkit-backdrop-filter: blur(8px);
|
|
37601
|
+
backdrop-filter: blur(8px);
|
|
37602
|
+
border: 1px solid var(--gvp-glass-bdr);
|
|
37603
|
+
color: var(--gvp-text);
|
|
37604
|
+
font-family: var(--gvp-mono);
|
|
37605
|
+
font-size: 11px;
|
|
37606
|
+
font-weight: 500;
|
|
37607
|
+
padding: 3px 8px;
|
|
37608
|
+
border-radius: 5px;
|
|
37609
|
+
pointer-events: none;
|
|
37610
|
+
white-space: nowrap;
|
|
37611
|
+
opacity: 0;
|
|
37612
|
+
-webkit-transition: opacity 0.12s; transition: opacity 0.12s;
|
|
37613
|
+
-webkit-box-shadow: 0 4px 12px rgba(0,0,0,0.45); box-shadow: 0 4px 12px rgba(0,0,0,0.45);
|
|
37614
|
+
}
|
|
37615
|
+
.gvp-seek-wrap:hover .gvp-seek-tooltip { opacity: 1; }
|
|
37345
37616
|
|
|
37346
|
-
/*
|
|
37347
|
-
.gvp-
|
|
37348
|
-
|
|
37617
|
+
/* Caret below tooltip */
|
|
37618
|
+
.gvp-seek-tooltip::after {
|
|
37619
|
+
content: '';
|
|
37620
|
+
position: absolute; bottom: -5px; left: 50%;
|
|
37621
|
+
-webkit-transform: translateX(-50%); transform: translateX(-50%);
|
|
37622
|
+
border: 4px solid transparent;
|
|
37623
|
+
border-top-color: rgba(10,10,14,0.92);
|
|
37624
|
+
border-bottom-width: 0;
|
|
37625
|
+
}
|
|
37349
37626
|
|
|
37350
|
-
/*
|
|
37351
|
-
.gvp-
|
|
37352
|
-
|
|
37627
|
+
/* ── Button row ───────────────────────────────────────────── */
|
|
37628
|
+
.gvp-btn-row {
|
|
37629
|
+
display: -webkit-box; display: -ms-flexbox; display: flex;
|
|
37630
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37631
|
+
gap: 2px;
|
|
37632
|
+
}
|
|
37353
37633
|
|
|
37354
|
-
|
|
37355
|
-
|
|
37356
|
-
|
|
37634
|
+
.gvp-btn {
|
|
37635
|
+
background: none; border: none;
|
|
37636
|
+
color: rgba(255,255,255,0.75);
|
|
37637
|
+
cursor: pointer;
|
|
37638
|
+
padding: 6px;
|
|
37639
|
+
border-radius: 7px;
|
|
37640
|
+
display: -webkit-inline-box; display: -ms-inline-flexbox; display: inline-flex;
|
|
37641
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37642
|
+
-webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
|
|
37643
|
+
-webkit-transition: background 0.14s, color 0.14s, -webkit-transform 0.12s;
|
|
37644
|
+
transition: background 0.14s, color 0.14s, transform 0.12s;
|
|
37645
|
+
-webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0;
|
|
37646
|
+
line-height: 0;
|
|
37647
|
+
}
|
|
37648
|
+
.gvp-btn:hover {
|
|
37649
|
+
background: rgba(255,255,255,0.09);
|
|
37650
|
+
color: #fff;
|
|
37651
|
+
-webkit-transform: scale(1.08); transform: scale(1.08);
|
|
37652
|
+
}
|
|
37653
|
+
.gvp-btn:active {
|
|
37654
|
+
background: rgba(255,255,255,0.14);
|
|
37655
|
+
-webkit-transform: scale(0.96); transform: scale(0.96);
|
|
37656
|
+
}
|
|
37657
|
+
/* Accent highlight on play button */
|
|
37658
|
+
.gvp-btn-play:hover { background: var(--gvp-accent-dim); color: var(--gvp-accent); }
|
|
37357
37659
|
|
|
37358
|
-
/*
|
|
37359
|
-
.gvp-
|
|
37360
|
-
|
|
37361
|
-
|
|
37362
|
-
|
|
37363
|
-
|
|
37364
|
-
.gvp-
|
|
37365
|
-
|
|
37366
|
-
|
|
37367
|
-
|
|
37368
|
-
|
|
37660
|
+
/* ── Volume group ─────────────────────────────────────────── */
|
|
37661
|
+
.gvp-volume-wrap {
|
|
37662
|
+
display: -webkit-box; display: -ms-flexbox; display: flex;
|
|
37663
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37664
|
+
gap: 2px;
|
|
37665
|
+
}
|
|
37666
|
+
.gvp-volume-slider {
|
|
37667
|
+
-webkit-appearance: none;
|
|
37668
|
+
-moz-appearance: none;
|
|
37669
|
+
appearance: none;
|
|
37670
|
+
width: 0;
|
|
37671
|
+
max-width: 72px;
|
|
37672
|
+
height: 3px;
|
|
37673
|
+
background: rgba(255,255,255,0.18);
|
|
37674
|
+
border-radius: 99px;
|
|
37675
|
+
outline: none;
|
|
37676
|
+
cursor: pointer;
|
|
37677
|
+
overflow: visible;
|
|
37678
|
+
-webkit-transition: width 0.22s cubic-bezier(0.4,0,0.2,1), opacity 0.22s;
|
|
37679
|
+
transition: width 0.22s cubic-bezier(0.4,0,0.2,1), opacity 0.22s;
|
|
37680
|
+
opacity: 0;
|
|
37681
|
+
/* accent-color is supported in modern browsers */
|
|
37682
|
+
accent-color: var(--gvp-accent);
|
|
37683
|
+
}
|
|
37684
|
+
/* Show slider when volume-wrap is hovered */
|
|
37685
|
+
.gvp-volume-wrap:hover .gvp-volume-slider,
|
|
37686
|
+
.gvp-volume-wrap:focus-within .gvp-volume-slider {
|
|
37687
|
+
width: 72px;
|
|
37688
|
+
opacity: 1;
|
|
37689
|
+
}
|
|
37690
|
+
/* WebKit thumb */
|
|
37691
|
+
.gvp-volume-slider::-webkit-slider-thumb {
|
|
37692
|
+
-webkit-appearance: none;
|
|
37693
|
+
width: 12px; height: 12px;
|
|
37694
|
+
border-radius: 50%;
|
|
37695
|
+
background: #fff;
|
|
37696
|
+
cursor: pointer;
|
|
37697
|
+
-webkit-box-shadow: 0 1px 4px rgba(0,0,0,0.4);
|
|
37698
|
+
box-shadow: 0 1px 4px rgba(0,0,0,0.4);
|
|
37699
|
+
}
|
|
37700
|
+
/* Firefox thumb */
|
|
37701
|
+
.gvp-volume-slider::-moz-range-thumb {
|
|
37702
|
+
width: 12px; height: 12px;
|
|
37703
|
+
border-radius: 50%;
|
|
37704
|
+
background: #fff;
|
|
37705
|
+
cursor: pointer;
|
|
37706
|
+
border: none;
|
|
37707
|
+
box-shadow: 0 1px 4px rgba(0,0,0,0.4);
|
|
37708
|
+
}
|
|
37709
|
+
/* Firefox track */
|
|
37710
|
+
.gvp-volume-slider::-moz-range-track {
|
|
37711
|
+
background: rgba(255,255,255,0.18);
|
|
37712
|
+
border-radius: 99px;
|
|
37713
|
+
height: 3px;
|
|
37714
|
+
}
|
|
37715
|
+
/* Edge/IE thumb */
|
|
37716
|
+
.gvp-volume-slider::-ms-thumb {
|
|
37717
|
+
width: 12px; height: 12px;
|
|
37718
|
+
border-radius: 50%;
|
|
37719
|
+
background: #fff;
|
|
37720
|
+
cursor: pointer;
|
|
37721
|
+
border: none;
|
|
37722
|
+
}
|
|
37723
|
+
.gvp-volume-slider::-ms-track {
|
|
37724
|
+
background: rgba(255,255,255,0.18);
|
|
37725
|
+
border-color: transparent;
|
|
37726
|
+
color: transparent;
|
|
37727
|
+
height: 3px;
|
|
37728
|
+
}
|
|
37729
|
+
.gvp-volume-slider::-ms-fill-lower { background: var(--gvp-accent); border-radius: 99px; }
|
|
37369
37730
|
|
|
37370
|
-
/*
|
|
37371
|
-
.gvp-
|
|
37372
|
-
|
|
37373
|
-
|
|
37374
|
-
|
|
37731
|
+
/* ── Time display ──────────────────────────────────────────── */
|
|
37732
|
+
.gvp-time {
|
|
37733
|
+
font-family: var(--gvp-mono);
|
|
37734
|
+
font-size: 12px;
|
|
37735
|
+
font-weight: 500;
|
|
37736
|
+
color: var(--gvp-text);
|
|
37737
|
+
white-space: nowrap;
|
|
37738
|
+
letter-spacing: 0.04em;
|
|
37739
|
+
padding: 0 4px;
|
|
37740
|
+
/* Tabular numerals so digits don't shift width */
|
|
37741
|
+
font-variant-numeric: tabular-nums;
|
|
37742
|
+
-moz-font-feature-settings: "tnum";
|
|
37743
|
+
-webkit-font-feature-settings: "tnum";
|
|
37744
|
+
font-feature-settings: "tnum";
|
|
37745
|
+
}
|
|
37746
|
+
.gvp-time-sep { color: var(--gvp-text-dim); margin: 0 2px; }
|
|
37747
|
+
|
|
37748
|
+
.gvp-spacer { -webkit-box-flex: 1; -ms-flex: 1; flex: 1; }
|
|
37749
|
+
|
|
37750
|
+
/* ── Speed button ─────────────────────────────────────────── */
|
|
37751
|
+
.gvp-rate-label {
|
|
37752
|
+
font-family: var(--gvp-font);
|
|
37753
|
+
font-size: 11px; font-weight: 700;
|
|
37754
|
+
color: var(--gvp-text-dim);
|
|
37755
|
+
min-width: 30px; text-align: center;
|
|
37756
|
+
cursor: pointer;
|
|
37757
|
+
padding: 5px 4px;
|
|
37758
|
+
border-radius: 6px;
|
|
37759
|
+
-webkit-transition: background 0.14s, color 0.14s; transition: background 0.14s, color 0.14s;
|
|
37760
|
+
-webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0;
|
|
37761
|
+
letter-spacing: 0.01em;
|
|
37762
|
+
line-height: 1;
|
|
37763
|
+
}
|
|
37764
|
+
.gvp-rate-label:hover { background: rgba(255,255,255,0.09); color: #fff; }
|
|
37765
|
+
.gvp-rate-label-active { color: var(--gvp-accent); }
|
|
37766
|
+
|
|
37767
|
+
/* ── Popup menus ──────────────────────────────────────────── */
|
|
37768
|
+
.gvp-menu-wrap { position: relative; }
|
|
37769
|
+
|
|
37770
|
+
.gvp-menu {
|
|
37771
|
+
position: absolute;
|
|
37772
|
+
bottom: calc(100% + 10px);
|
|
37773
|
+
right: 0;
|
|
37774
|
+
background: rgba(12,12,18,0.96);
|
|
37775
|
+
-webkit-backdrop-filter: blur(20px) saturate(180%);
|
|
37776
|
+
backdrop-filter: blur(20px) saturate(180%);
|
|
37777
|
+
border: 1px solid var(--gvp-glass-bdr);
|
|
37778
|
+
border-radius: 10px;
|
|
37779
|
+
min-width: 148px;
|
|
37780
|
+
overflow: hidden;
|
|
37781
|
+
-webkit-box-shadow: 0 12px 40px rgba(0,0,0,0.65), 0 0 0 0.5px rgba(255,255,255,0.04);
|
|
37782
|
+
box-shadow: 0 12px 40px rgba(0,0,0,0.65), 0 0 0 0.5px rgba(255,255,255,0.04);
|
|
37783
|
+
-webkit-animation: gvp-menu-in 0.14s cubic-bezier(0.22,1,0.36,1);
|
|
37784
|
+
animation: gvp-menu-in 0.14s cubic-bezier(0.22,1,0.36,1);
|
|
37785
|
+
z-index: 20;
|
|
37786
|
+
}
|
|
37787
|
+
@-webkit-keyframes gvp-menu-in {
|
|
37788
|
+
from { opacity: 0; -webkit-transform: scale(0.92) translateY(6px); transform: scale(0.92) translateY(6px); }
|
|
37789
|
+
to { opacity: 1; -webkit-transform: none; transform: none; }
|
|
37790
|
+
}
|
|
37791
|
+
@keyframes gvp-menu-in {
|
|
37792
|
+
from { opacity: 0; -webkit-transform: scale(0.92) translateY(6px); transform: scale(0.92) translateY(6px); }
|
|
37793
|
+
to { opacity: 1; -webkit-transform: none; transform: none; }
|
|
37794
|
+
}
|
|
37795
|
+
|
|
37796
|
+
.gvp-menu-title {
|
|
37797
|
+
font-family: var(--gvp-font);
|
|
37798
|
+
font-size: 10px; font-weight: 700;
|
|
37799
|
+
text-transform: uppercase;
|
|
37800
|
+
letter-spacing: 0.12em;
|
|
37801
|
+
color: var(--gvp-text-dim);
|
|
37802
|
+
padding: 10px 13px 5px;
|
|
37803
|
+
}
|
|
37804
|
+
|
|
37805
|
+
.gvp-menu-item {
|
|
37806
|
+
display: -webkit-box; display: -ms-flexbox; display: flex;
|
|
37807
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37808
|
+
-webkit-box-pack: justify; -ms-flex-pack: justify; justify-content: space-between;
|
|
37809
|
+
padding: 7px 13px;
|
|
37810
|
+
font-family: var(--gvp-font);
|
|
37811
|
+
font-size: 13px; font-weight: 500;
|
|
37812
|
+
color: var(--gvp-text);
|
|
37813
|
+
cursor: pointer;
|
|
37814
|
+
-webkit-transition: background 0.1s; transition: background 0.1s;
|
|
37815
|
+
gap: 12px;
|
|
37816
|
+
}
|
|
37817
|
+
.gvp-menu-item:hover { background: rgba(255,255,255,0.06); }
|
|
37818
|
+
.gvp-menu-item-active { color: var(--gvp-accent); }
|
|
37819
|
+
|
|
37820
|
+
.gvp-menu-check {
|
|
37821
|
+
font-size: 13px;
|
|
37822
|
+
color: var(--gvp-accent);
|
|
37823
|
+
line-height: 1;
|
|
37824
|
+
/* Unicode checkmark — crisp on all platforms */
|
|
37825
|
+
}
|
|
37826
|
+
|
|
37827
|
+
.gvp-menu-sep {
|
|
37828
|
+
height: 1px;
|
|
37829
|
+
background: rgba(255,255,255,0.06);
|
|
37830
|
+
margin: 3px 0;
|
|
37831
|
+
}
|
|
37832
|
+
|
|
37833
|
+
/* ── Error overlay ────────────────────────────────────────── */
|
|
37834
|
+
.gvp-error {
|
|
37835
|
+
position: absolute; inset: 0; z-index: 15;
|
|
37836
|
+
display: -webkit-box; display: -ms-flexbox; display: flex;
|
|
37837
|
+
-webkit-box-orient: vertical; -webkit-box-direction: normal;
|
|
37838
|
+
-ms-flex-direction: column; flex-direction: column;
|
|
37839
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37840
|
+
-webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
|
|
37841
|
+
background: rgba(6,6,10,0.88);
|
|
37842
|
+
-webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
|
|
37843
|
+
color: #fff;
|
|
37844
|
+
gap: 10px;
|
|
37845
|
+
padding: 28px;
|
|
37846
|
+
border-radius: var(--gvp-radius);
|
|
37847
|
+
text-align: center;
|
|
37848
|
+
}
|
|
37849
|
+
.gvp-error-icon { font-size: 40px; line-height: 1; }
|
|
37850
|
+
.gvp-error-code {
|
|
37851
|
+
font-family: var(--gvp-mono);
|
|
37852
|
+
font-size: 10px; font-weight: 500;
|
|
37853
|
+
letter-spacing: 0.14em;
|
|
37854
|
+
color: #f87171;
|
|
37855
|
+
text-transform: uppercase;
|
|
37856
|
+
background: rgba(248,113,113,0.1);
|
|
37857
|
+
border: 1px solid rgba(248,113,113,0.25);
|
|
37858
|
+
padding: 3px 10px; border-radius: 4px;
|
|
37859
|
+
}
|
|
37860
|
+
.gvp-error-msg {
|
|
37861
|
+
font-family: var(--gvp-font);
|
|
37862
|
+
font-size: 14px; font-weight: 400;
|
|
37863
|
+
color: rgba(255,255,255,0.6);
|
|
37864
|
+
max-width: 320px; line-height: 1.6;
|
|
37865
|
+
}
|
|
37375
37866
|
|
|
37376
|
-
/*
|
|
37377
|
-
.gvp-
|
|
37378
|
-
|
|
37379
|
-
|
|
37380
|
-
|
|
37867
|
+
/* ── Secure badge ─────────────────────────────────────────── */
|
|
37868
|
+
.gvp-badge {
|
|
37869
|
+
position: absolute; top: 12px; right: 14px; z-index: 5;
|
|
37870
|
+
display: -webkit-inline-box; display: -ms-inline-flexbox; display: inline-flex;
|
|
37871
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37872
|
+
gap: 5px;
|
|
37873
|
+
background: rgba(8,8,14,0.60);
|
|
37874
|
+
-webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
|
|
37875
|
+
border: 1px solid rgba(255,255,255,0.08);
|
|
37876
|
+
border-radius: 99px;
|
|
37877
|
+
padding: 4px 10px 4px 7px;
|
|
37878
|
+
font-family: var(--gvp-font);
|
|
37879
|
+
font-size: 10px; font-weight: 700;
|
|
37880
|
+
color: var(--gvp-accent);
|
|
37881
|
+
pointer-events: none;
|
|
37882
|
+
letter-spacing: 0.06em;
|
|
37883
|
+
text-transform: uppercase;
|
|
37884
|
+
-webkit-transition: opacity 0.3s; transition: opacity 0.3s;
|
|
37885
|
+
-webkit-box-shadow: 0 2px 12px rgba(0,0,0,0.4), 0 0 0 0.5px rgba(255,255,255,0.05);
|
|
37886
|
+
box-shadow: 0 2px 12px rgba(0,0,0,0.4), 0 0 0 0.5px rgba(255,255,255,0.05);
|
|
37887
|
+
}
|
|
37888
|
+
.gvp-badge-hidden { opacity: 0; }
|
|
37381
37889
|
|
|
37382
|
-
/*
|
|
37383
|
-
.gvp-
|
|
37384
|
-
|
|
37890
|
+
/* ── Forensic watermark ───────────────────────────────────── */
|
|
37891
|
+
.gvp-watermark {
|
|
37892
|
+
position: absolute; inset: 0;
|
|
37893
|
+
pointer-events: none; overflow: hidden; z-index: 6;
|
|
37894
|
+
}
|
|
37895
|
+
.gvp-watermark-text {
|
|
37896
|
+
position: absolute;
|
|
37897
|
+
white-space: nowrap;
|
|
37898
|
+
font-family: var(--gvp-mono);
|
|
37899
|
+
font-size: 12px;
|
|
37900
|
+
color: rgba(255,255,255,0.055);
|
|
37901
|
+
-webkit-transform: rotate(-28deg); transform: rotate(-28deg);
|
|
37902
|
+
-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;
|
|
37903
|
+
pointer-events: none;
|
|
37904
|
+
letter-spacing: 0.06em;
|
|
37905
|
+
}
|
|
37385
37906
|
|
|
37386
|
-
/*
|
|
37387
|
-
.gvp-
|
|
37388
|
-
|
|
37389
|
-
|
|
37390
|
-
|
|
37391
|
-
|
|
37392
|
-
|
|
37393
|
-
|
|
37394
|
-
|
|
37395
|
-
|
|
37396
|
-
|
|
37907
|
+
/* ── Live dot (for live streams) ─────────────────────────── */
|
|
37908
|
+
.gvp-live-badge {
|
|
37909
|
+
display: -webkit-inline-box; display: -ms-inline-flexbox; display: inline-flex;
|
|
37910
|
+
-webkit-box-align: center; -ms-flex-align: center; align-items: center;
|
|
37911
|
+
gap: 5px;
|
|
37912
|
+
font-family: var(--gvp-font);
|
|
37913
|
+
font-size: 11px; font-weight: 700;
|
|
37914
|
+
color: #f87171;
|
|
37915
|
+
letter-spacing: 0.08em;
|
|
37916
|
+
text-transform: uppercase;
|
|
37917
|
+
}
|
|
37918
|
+
.gvp-live-dot {
|
|
37919
|
+
width: 7px; height: 7px;
|
|
37920
|
+
background: #f87171;
|
|
37921
|
+
border-radius: 50%;
|
|
37922
|
+
-webkit-animation: gvp-live-pulse 1.5s ease-in-out infinite;
|
|
37923
|
+
animation: gvp-live-pulse 1.5s ease-in-out infinite;
|
|
37924
|
+
}
|
|
37925
|
+
@-webkit-keyframes gvp-live-pulse {
|
|
37926
|
+
0%, 100% { opacity: 1; -webkit-transform: scale(1); transform: scale(1); }
|
|
37927
|
+
50% { opacity: 0.5; -webkit-transform: scale(0.7); transform: scale(0.7); }
|
|
37928
|
+
}
|
|
37929
|
+
@keyframes gvp-live-pulse {
|
|
37930
|
+
0%, 100% { opacity: 1; transform: scale(1); }
|
|
37931
|
+
50% { opacity: 0.5; transform: scale(0.7); }
|
|
37932
|
+
}
|
|
37397
37933
|
|
|
37398
|
-
/*
|
|
37399
|
-
.gvp-
|
|
37400
|
-
|
|
37401
|
-
.
|
|
37402
|
-
|
|
37403
|
-
|
|
37934
|
+
/* ── Divider between button groups ───────────────────────── */
|
|
37935
|
+
.gvp-divider {
|
|
37936
|
+
width: 1px; height: 18px;
|
|
37937
|
+
background: rgba(255,255,255,0.1);
|
|
37938
|
+
margin: 0 4px;
|
|
37939
|
+
-webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0;
|
|
37940
|
+
}
|
|
37404
37941
|
|
|
37405
|
-
/*
|
|
37406
|
-
.gvp-
|
|
37407
|
-
|
|
37942
|
+
/* ── Tooltip on buttons ───────────────────────────────────── */
|
|
37943
|
+
.gvp-btn[title]:hover::after {
|
|
37944
|
+
content: attr(title);
|
|
37945
|
+
position: absolute;
|
|
37946
|
+
bottom: calc(100% + 7px);
|
|
37947
|
+
left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%);
|
|
37948
|
+
background: rgba(10,10,14,0.95);
|
|
37949
|
+
border: 1px solid var(--gvp-glass-bdr);
|
|
37950
|
+
color: var(--gvp-text);
|
|
37951
|
+
font-family: var(--gvp-font);
|
|
37952
|
+
font-size: 11px; font-weight: 500;
|
|
37953
|
+
padding: 3px 8px; border-radius: 5px;
|
|
37954
|
+
white-space: nowrap;
|
|
37955
|
+
pointer-events: none;
|
|
37956
|
+
z-index: 30;
|
|
37957
|
+
}
|
|
37408
37958
|
|
|
37409
|
-
/*
|
|
37410
|
-
.gvp-
|
|
37411
|
-
.gvp-
|
|
37959
|
+
/* ── Focus ring (keyboard nav) ────────────────────────────── */
|
|
37960
|
+
.gvp-btn:focus-visible,
|
|
37961
|
+
.gvp-rate-label:focus-visible,
|
|
37962
|
+
.gvp-seek-wrap:focus-visible {
|
|
37963
|
+
outline: 2px solid var(--gvp-accent);
|
|
37964
|
+
outline-offset: 2px;
|
|
37965
|
+
}
|
|
37412
37966
|
|
|
37413
|
-
/*
|
|
37414
|
-
|
|
37415
|
-
.gvp-
|
|
37967
|
+
/* ── Responsive: hide volume slider text on tiny players ─── */
|
|
37968
|
+
@media (max-width: 380px) {
|
|
37969
|
+
.gvp-volume-slider { display: none; }
|
|
37970
|
+
.gvp-time { font-size: 11px; }
|
|
37971
|
+
.gvp-controls-inner { padding: 8px 10px; }
|
|
37972
|
+
}
|
|
37416
37973
|
`;
|
|
37417
37974
|
const tag = document.createElement('style');
|
|
37418
|
-
tag.setAttribute('data-guardvideo', 'player-ui-styles');
|
|
37975
|
+
tag.setAttribute('data-guardvideo', 'player-ui-styles-v2');
|
|
37419
37976
|
tag.textContent = css;
|
|
37420
37977
|
document.head.appendChild(tag);
|
|
37421
37978
|
}
|
|
37422
|
-
|
|
37423
|
-
class VanillaPlayerUI {
|
|
37979
|
+
class PlayerUI {
|
|
37424
37980
|
constructor(container, videoId, config) {
|
|
37425
37981
|
this.playerState = exports.PlayerState.IDLE;
|
|
37426
37982
|
this.duration = 0;
|
|
@@ -37430,198 +37986,285 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
|
|
|
37430
37986
|
this.playbackRate = 1;
|
|
37431
37987
|
this.openMenu = null;
|
|
37432
37988
|
this.hideTimer = null;
|
|
37433
|
-
this.watermarkText = null;
|
|
37434
37989
|
this.seekDragging = false;
|
|
37435
|
-
|
|
37436
|
-
|
|
37437
|
-
|
|
37438
|
-
injectStyles(this.accent);
|
|
37439
|
-
this.buildDOM(container, config.width ?? '100%', config.height ?? 'auto');
|
|
37440
|
-
this.wireEvents(videoId, config, forensic);
|
|
37441
|
-
if (forensic) {
|
|
37442
|
-
const wtxt = config.viewerEmail || config.viewerName || '';
|
|
37443
|
-
if (wtxt) {
|
|
37444
|
-
setTimeout(() => {
|
|
37445
|
-
this.watermarkText = wtxt;
|
|
37446
|
-
this.renderWatermark();
|
|
37447
|
-
}, 1500);
|
|
37448
|
-
}
|
|
37449
|
-
}
|
|
37450
|
-
}
|
|
37451
|
-
buildDOM(container, width, height) {
|
|
37990
|
+
const accent = config.branding?.accentColor ?? '#00e5a0';
|
|
37991
|
+
const brandName = config.branding?.name ?? 'GuardVideo';
|
|
37992
|
+
injectStyles();
|
|
37452
37993
|
container.innerHTML = '';
|
|
37453
37994
|
this.root = el('div', 'gvp-root');
|
|
37454
|
-
this.root.style.width = width;
|
|
37455
|
-
this.root.style.height = height;
|
|
37995
|
+
this.root.style.width = config.width ?? '100%';
|
|
37996
|
+
this.root.style.height = config.height ?? 'auto';
|
|
37997
|
+
this.root.style.setProperty('--gvp-accent', accent);
|
|
37998
|
+
this.root.style.setProperty('--gvp-accent-dim', this._hexToRgba(accent, 0.18));
|
|
37999
|
+
this.root.style.setProperty('--gvp-accent-glow', this._hexToRgba(accent, 0.35));
|
|
37456
38000
|
this.root.setAttribute('tabindex', '0');
|
|
38001
|
+
this.root.setAttribute('role', 'region');
|
|
38002
|
+
this.root.setAttribute('aria-label', `${brandName} video player`);
|
|
37457
38003
|
this.videoEl = el('video', 'gvp-video', { playsinline: '', preload: 'metadata' });
|
|
37458
38004
|
this.badge = el('div', 'gvp-badge');
|
|
37459
|
-
|
|
37460
|
-
|
|
37461
|
-
this.badge.appendChild(
|
|
37462
|
-
this.badge.appendChild(document.createTextNode(this.brandName));
|
|
38005
|
+
this.badge.setAttribute('aria-hidden', 'true');
|
|
38006
|
+
this.badge.appendChild(svgEl(ICON.shield, 13, 13));
|
|
38007
|
+
this.badge.appendChild(document.createTextNode(brandName));
|
|
37463
38008
|
this.watermarkDiv = el('div', 'gvp-watermark');
|
|
37464
|
-
this.
|
|
38009
|
+
this.watermarkDiv.setAttribute('aria-hidden', 'true');
|
|
38010
|
+
this.spinner = el('div', 'gvp-spinner gvp-hidden');
|
|
38011
|
+
this.spinner.setAttribute('aria-label', 'Loading');
|
|
38012
|
+
this.spinner.setAttribute('role', 'status');
|
|
37465
38013
|
this.spinner.appendChild(el('div', 'gvp-spinner-ring'));
|
|
37466
|
-
this.errorOverlay = el('div', 'gvp-error gvp-
|
|
38014
|
+
this.errorOverlay = el('div', 'gvp-error gvp-hidden');
|
|
38015
|
+
this.errorOverlay.setAttribute('role', 'alert');
|
|
37467
38016
|
const errIcon = el('div', 'gvp-error-icon');
|
|
37468
38017
|
errIcon.textContent = '⚠️';
|
|
38018
|
+
errIcon.setAttribute('aria-hidden', 'true');
|
|
37469
38019
|
const errCode = el('div', 'gvp-error-code');
|
|
37470
|
-
errCode.id = 'gvp-err-code';
|
|
37471
38020
|
const errMsg = el('div', 'gvp-error-msg');
|
|
37472
|
-
errMsg.id = 'gvp-err-msg';
|
|
37473
38021
|
this.errorOverlay.append(errIcon, errCode, errMsg);
|
|
37474
38022
|
this.centerPlay = el('div', 'gvp-center-play');
|
|
38023
|
+
this.centerPlay.setAttribute('role', 'button');
|
|
38024
|
+
this.centerPlay.setAttribute('aria-label', 'Play');
|
|
37475
38025
|
this.centerPlayBtn = el('div', 'gvp-center-play-btn');
|
|
37476
|
-
this.centerPlayBtn.appendChild(
|
|
38026
|
+
this.centerPlayBtn.appendChild(svgEl(ICON.play, 30, 30));
|
|
37477
38027
|
this.centerPlay.appendChild(this.centerPlayBtn);
|
|
37478
|
-
this.clickArea = el('div', 'gvp-click-area gvp-
|
|
38028
|
+
this.clickArea = el('div', 'gvp-click-area gvp-hidden');
|
|
38029
|
+
this.clickArea.setAttribute('aria-hidden', 'true');
|
|
37479
38030
|
this.controls = el('div', 'gvp-controls');
|
|
38031
|
+
const inner = el('div', 'gvp-controls-inner');
|
|
37480
38032
|
const seekRow = el('div', 'gvp-seek-row');
|
|
37481
38033
|
this.seekWrap = el('div', 'gvp-seek-wrap');
|
|
38034
|
+
this.seekWrap.setAttribute('role', 'slider');
|
|
38035
|
+
this.seekWrap.setAttribute('aria-label', 'Seek');
|
|
38036
|
+
this.seekWrap.setAttribute('aria-valuemin', '0');
|
|
38037
|
+
this.seekWrap.setAttribute('aria-valuemax', '100');
|
|
38038
|
+
this.seekWrap.setAttribute('aria-valuenow', '0');
|
|
38039
|
+
this.seekWrap.setAttribute('aria-valuetext', '0:00 of 0:00');
|
|
38040
|
+
this.seekWrap.setAttribute('tabindex', '0');
|
|
37482
38041
|
const seekTrack = el('div', 'gvp-seek-track');
|
|
37483
38042
|
this.seekBuffered = el('div', 'gvp-seek-buffered');
|
|
37484
38043
|
this.seekProgress = el('div', 'gvp-seek-progress');
|
|
37485
38044
|
this.seekThumb = el('div', 'gvp-seek-thumb');
|
|
37486
38045
|
this.seekTooltip = el('div', 'gvp-seek-tooltip');
|
|
38046
|
+
this.seekTooltip.setAttribute('aria-hidden', 'true');
|
|
37487
38047
|
seekTrack.append(this.seekBuffered, this.seekProgress);
|
|
37488
38048
|
this.seekWrap.append(seekTrack, this.seekThumb, this.seekTooltip);
|
|
37489
38049
|
seekRow.appendChild(this.seekWrap);
|
|
37490
|
-
|
|
38050
|
+
inner.appendChild(seekRow);
|
|
37491
38051
|
const btnRow = el('div', 'gvp-btn-row');
|
|
37492
|
-
this.playBtn = el('button', 'gvp-btn');
|
|
38052
|
+
this.playBtn = el('button', 'gvp-btn gvp-btn-play');
|
|
38053
|
+
this.playBtn.type = 'button';
|
|
38054
|
+
this.playBtn.setAttribute('aria-label', 'Play');
|
|
37493
38055
|
this.playBtn.title = 'Play (k)';
|
|
37494
|
-
this.playBtn.appendChild(
|
|
38056
|
+
this.playBtn.appendChild(svgEl(ICON.play));
|
|
37495
38057
|
const volWrap = el('div', 'gvp-volume-wrap');
|
|
37496
38058
|
this.volBtn = el('button', 'gvp-btn');
|
|
38059
|
+
this.volBtn.type = 'button';
|
|
38060
|
+
this.volBtn.setAttribute('aria-label', 'Mute');
|
|
37497
38061
|
this.volBtn.title = 'Mute (m)';
|
|
37498
|
-
this.volBtn.appendChild(
|
|
38062
|
+
this.volBtn.appendChild(svgEl(ICON.volHigh, 18, 18));
|
|
37499
38063
|
this.volSlider = el('input', 'gvp-volume-slider');
|
|
37500
|
-
this.volSlider
|
|
37501
|
-
this.volSlider.
|
|
37502
|
-
this.volSlider.max = '1';
|
|
37503
|
-
this.volSlider.step = '0.02';
|
|
37504
|
-
this.volSlider.value = '1';
|
|
37505
|
-
this.volSlider.title = 'Volume';
|
|
38064
|
+
Object.assign(this.volSlider, { type: 'range', min: '0', max: '1', step: '0.02', value: '1' });
|
|
38065
|
+
this.volSlider.setAttribute('aria-label', 'Volume');
|
|
37506
38066
|
volWrap.append(this.volBtn, this.volSlider);
|
|
37507
38067
|
this.timeEl = el('span', 'gvp-time');
|
|
38068
|
+
this.timeEl.setAttribute('aria-live', 'off');
|
|
37508
38069
|
this.timeEl.textContent = '0:00 / 0:00';
|
|
37509
38070
|
const spacer = el('div', 'gvp-spacer');
|
|
38071
|
+
const divider = el('div', 'gvp-divider');
|
|
38072
|
+
divider.setAttribute('aria-hidden', 'true');
|
|
37510
38073
|
const speedWrap = el('div', 'gvp-menu-wrap');
|
|
37511
38074
|
this.speedLabel = el('span', 'gvp-rate-label');
|
|
37512
38075
|
this.speedLabel.textContent = '1×';
|
|
37513
|
-
this.speedLabel.
|
|
37514
|
-
this.
|
|
38076
|
+
this.speedLabel.setAttribute('role', 'button');
|
|
38077
|
+
this.speedLabel.setAttribute('aria-label', 'Playback speed');
|
|
38078
|
+
this.speedLabel.setAttribute('aria-haspopup', 'menu');
|
|
38079
|
+
this.speedLabel.setAttribute('tabindex', '0');
|
|
38080
|
+
this.speedMenu = el('div', 'gvp-menu gvp-hidden');
|
|
38081
|
+
this.speedMenu.setAttribute('role', 'menu');
|
|
38082
|
+
this.speedMenu.setAttribute('aria-label', 'Playback speed');
|
|
37515
38083
|
const speedTitle = el('div', 'gvp-menu-title');
|
|
38084
|
+
speedTitle.setAttribute('aria-hidden', 'true');
|
|
37516
38085
|
speedTitle.textContent = 'Speed';
|
|
37517
38086
|
this.speedMenu.appendChild(speedTitle);
|
|
37518
38087
|
SPEEDS.forEach(r => {
|
|
37519
|
-
const
|
|
37520
|
-
item
|
|
38088
|
+
const active = r === 1;
|
|
38089
|
+
const item = el('div', active ? 'gvp-menu-item gvp-menu-item-active' : 'gvp-menu-item');
|
|
38090
|
+
item.setAttribute('role', 'menuitemradio');
|
|
38091
|
+
item.setAttribute('aria-checked', active ? 'true' : 'false');
|
|
37521
38092
|
item.dataset['speed'] = String(r);
|
|
38093
|
+
item.textContent = r === 1 ? 'Normal' : `${r}×`;
|
|
38094
|
+
if (active) {
|
|
38095
|
+
const check = el('span', 'gvp-menu-check');
|
|
38096
|
+
check.setAttribute('aria-hidden', 'true');
|
|
38097
|
+
check.textContent = '✓';
|
|
38098
|
+
item.appendChild(check);
|
|
38099
|
+
}
|
|
37522
38100
|
this.speedMenu.appendChild(item);
|
|
37523
38101
|
});
|
|
37524
38102
|
speedWrap.append(this.speedLabel, this.speedMenu);
|
|
37525
38103
|
const qualWrap = el('div', 'gvp-menu-wrap');
|
|
37526
38104
|
this.settingsBtn = el('button', 'gvp-btn');
|
|
37527
|
-
this.settingsBtn.
|
|
37528
|
-
this.settingsBtn.
|
|
37529
|
-
this.settingsBtn.
|
|
37530
|
-
this.
|
|
38105
|
+
this.settingsBtn.type = 'button';
|
|
38106
|
+
this.settingsBtn.setAttribute('aria-label', 'Quality settings');
|
|
38107
|
+
this.settingsBtn.setAttribute('aria-haspopup', 'menu');
|
|
38108
|
+
this.settingsBtn.title = 'Quality';
|
|
38109
|
+
this.settingsBtn.appendChild(svgEl(ICON.settings, 18, 18));
|
|
38110
|
+
this.settingsBtn.classList.add('gvp-hidden');
|
|
38111
|
+
this.qualityMenu = el('div', 'gvp-menu gvp-hidden');
|
|
38112
|
+
this.qualityMenu.setAttribute('role', 'menu');
|
|
38113
|
+
this.qualityMenu.setAttribute('aria-label', 'Video quality');
|
|
37531
38114
|
qualWrap.append(this.settingsBtn, this.qualityMenu);
|
|
37532
38115
|
this.fsBtn = el('button', 'gvp-btn');
|
|
38116
|
+
this.fsBtn.type = 'button';
|
|
38117
|
+
this.fsBtn.setAttribute('aria-label', 'Enter fullscreen');
|
|
37533
38118
|
this.fsBtn.title = 'Fullscreen (f)';
|
|
37534
|
-
this.fsBtn.appendChild(
|
|
37535
|
-
btnRow.append(this.playBtn, volWrap, this.timeEl, spacer, speedWrap, qualWrap, this.fsBtn);
|
|
37536
|
-
|
|
38119
|
+
this.fsBtn.appendChild(svgEl(ICON.fsEnter, 18, 18));
|
|
38120
|
+
btnRow.append(this.playBtn, volWrap, this.timeEl, spacer, speedWrap, divider, qualWrap, this.fsBtn);
|
|
38121
|
+
inner.appendChild(btnRow);
|
|
38122
|
+
this.controls.appendChild(inner);
|
|
37537
38123
|
this.root.append(this.videoEl, this.badge, this.watermarkDiv, this.spinner, this.errorOverlay, this.centerPlay, this.clickArea, this.controls);
|
|
37538
38124
|
container.appendChild(this.root);
|
|
37539
|
-
|
|
37540
|
-
|
|
38125
|
+
this._onFsChangeBound = () => this._onFsChange();
|
|
38126
|
+
this._seekMouseMoveBound = (e) => { if (this.seekDragging)
|
|
38127
|
+
this._seekTo(e.clientX); };
|
|
38128
|
+
this._seekMouseUpBound = () => this._endSeekDrag();
|
|
38129
|
+
this._seekTouchMoveBound = (e) => {
|
|
38130
|
+
if (!this.seekDragging)
|
|
38131
|
+
return;
|
|
38132
|
+
e.preventDefault();
|
|
38133
|
+
this._seekTo(e.touches[0].clientX);
|
|
38134
|
+
};
|
|
38135
|
+
this._seekTouchEndBound = () => this._endSeekDrag();
|
|
38136
|
+
this._wireEvents(videoId, config);
|
|
38137
|
+
if (config.forensicWatermark !== false) {
|
|
38138
|
+
const wmText = config.viewerEmail || config.viewerName || '';
|
|
38139
|
+
if (wmText)
|
|
38140
|
+
this._renderWatermark(wmText);
|
|
38141
|
+
}
|
|
38142
|
+
}
|
|
38143
|
+
_hexToRgba(hex, alpha) {
|
|
38144
|
+
const clean = hex.replace('#', '');
|
|
38145
|
+
const full = clean.length === 3
|
|
38146
|
+
? clean.split('').map(c => c + c).join('')
|
|
38147
|
+
: clean;
|
|
38148
|
+
const r = parseInt(full.substring(0, 2), 16);
|
|
38149
|
+
const g = parseInt(full.substring(2, 4), 16);
|
|
38150
|
+
const b = parseInt(full.substring(4, 6), 16);
|
|
38151
|
+
if (isNaN(r) || isNaN(g) || isNaN(b))
|
|
38152
|
+
return `rgba(0,229,160,${alpha})`;
|
|
38153
|
+
return `rgba(${r},${g},${b},${alpha})`;
|
|
38154
|
+
}
|
|
38155
|
+
_wireEvents(videoId, config) {
|
|
37541
38156
|
const video = this.videoEl;
|
|
37542
38157
|
this.corePlayer = new GuardVideoPlayer$1(video, videoId, {
|
|
37543
38158
|
...config,
|
|
37544
38159
|
controls: false,
|
|
37545
|
-
forensicWatermark,
|
|
38160
|
+
forensicWatermark: config.forensicWatermark !== false,
|
|
37546
38161
|
onReady: () => {
|
|
37547
38162
|
config.onReady?.();
|
|
37548
|
-
|
|
37549
|
-
|
|
37550
|
-
this.
|
|
37551
|
-
|
|
38163
|
+
const levels = this.corePlayer.getQualityLevels();
|
|
38164
|
+
if (levels.length) {
|
|
38165
|
+
this.qualityLevels = levels;
|
|
38166
|
+
this._buildQualityMenu();
|
|
38167
|
+
}
|
|
38168
|
+
else {
|
|
38169
|
+
setTimeout(() => {
|
|
38170
|
+
this.qualityLevels = this.corePlayer.getQualityLevels();
|
|
38171
|
+
if (this.qualityLevels.length)
|
|
38172
|
+
this._buildQualityMenu();
|
|
38173
|
+
}, 100);
|
|
38174
|
+
}
|
|
37552
38175
|
},
|
|
37553
38176
|
onError: (err) => {
|
|
37554
|
-
this.
|
|
38177
|
+
this._showError(err);
|
|
37555
38178
|
config.onError?.(err);
|
|
37556
38179
|
},
|
|
37557
38180
|
onQualityChange: (quality) => {
|
|
37558
38181
|
const idx = this.qualityLevels.findIndex(l => l.name === quality);
|
|
37559
38182
|
this.currentQualityIdx = idx;
|
|
37560
|
-
this.
|
|
38183
|
+
this._refreshQualityMenu();
|
|
37561
38184
|
config.onQualityChange?.(quality);
|
|
37562
38185
|
},
|
|
37563
38186
|
onStateChange: (state) => {
|
|
37564
|
-
this.
|
|
38187
|
+
this._onStateChange(state);
|
|
37565
38188
|
config.onStateChange?.(state);
|
|
37566
38189
|
},
|
|
37567
38190
|
});
|
|
37568
|
-
video.addEventListener('timeupdate', () =>
|
|
37569
|
-
|
|
37570
|
-
|
|
38191
|
+
video.addEventListener('timeupdate', () => {
|
|
38192
|
+
config.onTimeUpdate?.(video.currentTime);
|
|
38193
|
+
this._onTimeUpdate();
|
|
38194
|
+
});
|
|
38195
|
+
video.addEventListener('loadedmetadata', () => {
|
|
38196
|
+
this.duration = video.duration || 0;
|
|
38197
|
+
this._onTimeUpdate();
|
|
38198
|
+
});
|
|
38199
|
+
video.addEventListener('durationchange', () => {
|
|
38200
|
+
this.duration = video.duration || 0;
|
|
38201
|
+
});
|
|
37571
38202
|
video.addEventListener('progress', () => {
|
|
37572
38203
|
if (video.buffered.length > 0) {
|
|
37573
38204
|
this.bufferedEnd = video.buffered.end(video.buffered.length - 1);
|
|
37574
|
-
this.
|
|
38205
|
+
this._updateSeekBar();
|
|
37575
38206
|
}
|
|
37576
38207
|
});
|
|
37577
|
-
video.addEventListener('volumechange', () => this.
|
|
38208
|
+
video.addEventListener('volumechange', () => this._onVolumeChange());
|
|
37578
38209
|
video.addEventListener('ended', () => {
|
|
37579
|
-
|
|
37580
|
-
this.
|
|
38210
|
+
config.onEnded?.();
|
|
38211
|
+
this._showControls(true);
|
|
38212
|
+
this._renderPlayBtn();
|
|
37581
38213
|
});
|
|
37582
38214
|
video.addEventListener('ratechange', () => {
|
|
37583
38215
|
this.playbackRate = video.playbackRate;
|
|
37584
|
-
|
|
38216
|
+
const isNormal = this.playbackRate === 1;
|
|
38217
|
+
this.speedLabel.textContent = isNormal ? '1×' : `${this.playbackRate}×`;
|
|
38218
|
+
this.speedLabel.classList.toggle('gvp-rate-label-active', !isNormal);
|
|
37585
38219
|
});
|
|
37586
|
-
this.playBtn.addEventListener('click', (e) => { e.stopPropagation(); this.
|
|
37587
|
-
this.volBtn.addEventListener('click', (e) => { e.stopPropagation(); this.
|
|
38220
|
+
this.playBtn.addEventListener('click', (e) => { e.stopPropagation(); this._togglePlay(); });
|
|
38221
|
+
this.volBtn.addEventListener('click', (e) => { e.stopPropagation(); this._toggleMute(); });
|
|
37588
38222
|
this.volSlider.addEventListener('input', () => {
|
|
37589
38223
|
video.volume = parseFloat(this.volSlider.value);
|
|
37590
38224
|
video.muted = video.volume === 0;
|
|
37591
38225
|
});
|
|
37592
|
-
this.seekWrap.addEventListener('click', (e) => {
|
|
37593
|
-
e.stopPropagation();
|
|
37594
|
-
this.seekTo(e);
|
|
37595
|
-
this.resetHideTimer();
|
|
37596
|
-
});
|
|
37597
|
-
this.seekWrap.addEventListener('mousemove', (e) => this.onSeekHover(e));
|
|
37598
|
-
this.seekWrap.addEventListener('mouseleave', () => { this.seekTooltip.style.opacity = '0'; });
|
|
37599
38226
|
this.seekWrap.addEventListener('mousedown', (e) => {
|
|
37600
|
-
|
|
37601
|
-
this.
|
|
37602
|
-
|
|
37603
|
-
|
|
37604
|
-
|
|
37605
|
-
window.addEventListener('mousemove', onMove);
|
|
37606
|
-
window.addEventListener('mouseup', onUp);
|
|
38227
|
+
e.preventDefault();
|
|
38228
|
+
this._startSeekDrag();
|
|
38229
|
+
this._seekTo(e.clientX);
|
|
38230
|
+
window.addEventListener('mousemove', this._seekMouseMoveBound);
|
|
38231
|
+
window.addEventListener('mouseup', this._seekMouseUpBound);
|
|
37607
38232
|
});
|
|
37608
|
-
this.
|
|
37609
|
-
|
|
37610
|
-
this.
|
|
38233
|
+
this.seekWrap.addEventListener('mousemove', (e) => this._onSeekHover(e.clientX));
|
|
38234
|
+
this.seekWrap.addEventListener('mouseleave', () => {
|
|
38235
|
+
this.seekTooltip.style.opacity = '0';
|
|
38236
|
+
});
|
|
38237
|
+
this.seekWrap.addEventListener('touchstart', (e) => {
|
|
38238
|
+
e.preventDefault();
|
|
38239
|
+
this._startSeekDrag();
|
|
38240
|
+
this._seekTo(e.touches[0].clientX);
|
|
38241
|
+
window.addEventListener('touchmove', this._seekTouchMoveBound, { passive: false });
|
|
38242
|
+
window.addEventListener('touchend', this._seekTouchEndBound);
|
|
38243
|
+
}, { passive: false });
|
|
38244
|
+
this.seekWrap.addEventListener('keydown', (e) => {
|
|
38245
|
+
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight')
|
|
38246
|
+
return;
|
|
38247
|
+
e.preventDefault();
|
|
38248
|
+
const delta = e.key === 'ArrowLeft' ? -5 : 5;
|
|
38249
|
+
this.corePlayer.seek(Math.max(0, Math.min(this.duration, video.currentTime + delta)));
|
|
38250
|
+
this._resetHideTimer();
|
|
38251
|
+
});
|
|
38252
|
+
this.speedLabel.addEventListener('click', (e) => { e.stopPropagation(); this._toggleMenu('speed'); });
|
|
38253
|
+
this.speedLabel.addEventListener('keydown', (e) => {
|
|
38254
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
38255
|
+
e.preventDefault();
|
|
38256
|
+
this._toggleMenu('speed');
|
|
38257
|
+
}
|
|
37611
38258
|
});
|
|
37612
38259
|
this.speedMenu.addEventListener('click', (e) => {
|
|
37613
38260
|
e.stopPropagation();
|
|
37614
38261
|
const item = e.target.closest('[data-speed]');
|
|
37615
38262
|
if (!item)
|
|
37616
38263
|
return;
|
|
37617
|
-
|
|
37618
|
-
|
|
37619
|
-
this.closeMenus();
|
|
37620
|
-
});
|
|
37621
|
-
this.settingsBtn.addEventListener('click', (e) => {
|
|
37622
|
-
e.stopPropagation();
|
|
37623
|
-
this.toggleMenu('quality');
|
|
38264
|
+
video.playbackRate = parseFloat(item.dataset['speed']);
|
|
38265
|
+
this._closeMenus();
|
|
37624
38266
|
});
|
|
38267
|
+
this.settingsBtn.addEventListener('click', (e) => { e.stopPropagation(); this._toggleMenu('quality'); });
|
|
37625
38268
|
this.qualityMenu.addEventListener('click', (e) => {
|
|
37626
38269
|
e.stopPropagation();
|
|
37627
38270
|
const item = e.target.closest('[data-quality]');
|
|
@@ -37630,132 +38273,122 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
|
|
|
37630
38273
|
const idx = parseInt(item.dataset['quality']);
|
|
37631
38274
|
this.corePlayer.setQuality(idx);
|
|
37632
38275
|
this.currentQualityIdx = idx;
|
|
37633
|
-
this.
|
|
37634
|
-
this.
|
|
37635
|
-
});
|
|
37636
|
-
this.clickArea.addEventListener('click', (e) => {
|
|
37637
|
-
this.addRipple(e);
|
|
37638
|
-
this.togglePlay();
|
|
38276
|
+
this._refreshQualityMenu();
|
|
38277
|
+
this._closeMenus();
|
|
37639
38278
|
});
|
|
37640
|
-
this.
|
|
37641
|
-
this.
|
|
37642
|
-
|
|
37643
|
-
|
|
38279
|
+
this.clickArea.addEventListener('click', (e) => { this._addRipple(e); this._togglePlay(); });
|
|
38280
|
+
this.centerPlay.addEventListener('click', (e) => { e.stopPropagation(); this._togglePlay(); });
|
|
38281
|
+
this.fsBtn.addEventListener('click', (e) => { e.stopPropagation(); this._toggleFullscreen(); });
|
|
38282
|
+
document.addEventListener('fullscreenchange', this._onFsChangeBound);
|
|
38283
|
+
document.addEventListener('webkitfullscreenchange', this._onFsChangeBound);
|
|
38284
|
+
document.addEventListener('mozfullscreenchange', this._onFsChangeBound);
|
|
38285
|
+
document.addEventListener('MSFullscreenChange', this._onFsChangeBound);
|
|
38286
|
+
this.root.addEventListener('mousemove', () => this._resetHideTimer());
|
|
38287
|
+
this.root.addEventListener('touchstart', () => this._resetHideTimer(), { passive: true });
|
|
37644
38288
|
this.root.addEventListener('mouseleave', () => {
|
|
37645
38289
|
if (this.playerState === exports.PlayerState.PLAYING)
|
|
37646
|
-
this.
|
|
37647
|
-
});
|
|
37648
|
-
this.root.addEventListener('click', () => this.closeMenus());
|
|
37649
|
-
this.root.addEventListener('keydown', (e) => {
|
|
37650
|
-
switch (e.code) {
|
|
37651
|
-
case 'Space':
|
|
37652
|
-
case 'KeyK':
|
|
37653
|
-
e.preventDefault();
|
|
37654
|
-
this.togglePlay();
|
|
37655
|
-
break;
|
|
37656
|
-
case 'ArrowLeft':
|
|
37657
|
-
e.preventDefault();
|
|
37658
|
-
this.corePlayer.seek(Math.max(0, video.currentTime - 5));
|
|
37659
|
-
break;
|
|
37660
|
-
case 'ArrowRight':
|
|
37661
|
-
e.preventDefault();
|
|
37662
|
-
this.corePlayer.seek(Math.min(this.duration, video.currentTime + 5));
|
|
37663
|
-
break;
|
|
37664
|
-
case 'ArrowUp':
|
|
37665
|
-
e.preventDefault();
|
|
37666
|
-
video.volume = Math.min(1, video.volume + 0.1);
|
|
37667
|
-
break;
|
|
37668
|
-
case 'ArrowDown':
|
|
37669
|
-
e.preventDefault();
|
|
37670
|
-
video.volume = Math.max(0, video.volume - 0.1);
|
|
37671
|
-
break;
|
|
37672
|
-
case 'KeyM':
|
|
37673
|
-
e.preventDefault();
|
|
37674
|
-
this.toggleMute();
|
|
37675
|
-
break;
|
|
37676
|
-
case 'KeyF':
|
|
37677
|
-
e.preventDefault();
|
|
37678
|
-
this.toggleFullscreen();
|
|
37679
|
-
break;
|
|
37680
|
-
}
|
|
38290
|
+
this._showControls(false);
|
|
37681
38291
|
});
|
|
38292
|
+
this.root.addEventListener('click', () => this._closeMenus());
|
|
38293
|
+
this.root.addEventListener('keydown', (e) => this._onKeyDown(e));
|
|
37682
38294
|
}
|
|
37683
|
-
|
|
38295
|
+
_onStateChange(state) {
|
|
37684
38296
|
this.playerState = state;
|
|
37685
38297
|
const loading = state === exports.PlayerState.LOADING || state === exports.PlayerState.BUFFERING;
|
|
37686
38298
|
const idle = state === exports.PlayerState.IDLE;
|
|
37687
38299
|
const ended = this.videoEl.ended;
|
|
37688
|
-
this.spinner.classList.toggle('gvp-
|
|
38300
|
+
this.spinner.classList.toggle('gvp-hidden', !loading);
|
|
37689
38301
|
const showCenter = (idle || ended) && !loading;
|
|
37690
|
-
this.centerPlay.classList.toggle('gvp-
|
|
38302
|
+
this.centerPlay.classList.toggle('gvp-hidden', !showCenter);
|
|
37691
38303
|
if (showCenter) {
|
|
37692
38304
|
this.centerPlayBtn.innerHTML = '';
|
|
37693
|
-
this.centerPlayBtn.appendChild(
|
|
38305
|
+
this.centerPlayBtn.appendChild(svgEl(ended ? ICON.replay : ICON.play, 30, 30));
|
|
38306
|
+
this.centerPlay.setAttribute('aria-label', ended ? 'Replay' : 'Play');
|
|
37694
38307
|
}
|
|
37695
|
-
this.clickArea.classList.toggle('gvp-
|
|
38308
|
+
this.clickArea.classList.toggle('gvp-hidden', idle);
|
|
37696
38309
|
if (state !== exports.PlayerState.PLAYING) {
|
|
37697
|
-
this.
|
|
38310
|
+
this._showControls(true);
|
|
37698
38311
|
if (this.hideTimer) {
|
|
37699
38312
|
clearTimeout(this.hideTimer);
|
|
37700
38313
|
this.hideTimer = null;
|
|
37701
38314
|
}
|
|
37702
38315
|
}
|
|
37703
38316
|
else {
|
|
37704
|
-
this.
|
|
38317
|
+
this._resetHideTimer();
|
|
37705
38318
|
}
|
|
37706
|
-
this.
|
|
38319
|
+
this._renderPlayBtn();
|
|
37707
38320
|
}
|
|
37708
|
-
|
|
37709
|
-
const
|
|
37710
|
-
if (
|
|
38321
|
+
_togglePlay() {
|
|
38322
|
+
const v = this.videoEl;
|
|
38323
|
+
if (v.paused || v.ended) {
|
|
37711
38324
|
this.corePlayer.play().catch(() => { });
|
|
37712
38325
|
}
|
|
37713
38326
|
else {
|
|
37714
38327
|
this.corePlayer.pause();
|
|
37715
38328
|
}
|
|
37716
|
-
this.
|
|
38329
|
+
this._resetHideTimer();
|
|
37717
38330
|
}
|
|
37718
|
-
|
|
37719
|
-
const
|
|
37720
|
-
const ended = video.ended;
|
|
38331
|
+
_renderPlayBtn() {
|
|
38332
|
+
const ended = this.videoEl.ended;
|
|
37721
38333
|
const playing = this.playerState === exports.PlayerState.PLAYING;
|
|
38334
|
+
const icon = ended ? ICON.replay : playing ? ICON.pause : ICON.play;
|
|
38335
|
+
const label = playing ? 'Pause' : 'Play';
|
|
37722
38336
|
this.playBtn.innerHTML = '';
|
|
37723
|
-
this.playBtn.appendChild(
|
|
37724
|
-
this.playBtn.
|
|
37725
|
-
|
|
37726
|
-
|
|
37727
|
-
|
|
37728
|
-
|
|
37729
|
-
|
|
37730
|
-
const
|
|
37731
|
-
const muted =
|
|
38337
|
+
this.playBtn.appendChild(svgEl(icon));
|
|
38338
|
+
this.playBtn.setAttribute('aria-label', label);
|
|
38339
|
+
this.playBtn.title = `${label} (k)`;
|
|
38340
|
+
}
|
|
38341
|
+
_toggleMute() { this.videoEl.muted = !this.videoEl.muted; }
|
|
38342
|
+
_onVolumeChange() {
|
|
38343
|
+
const v = this.videoEl;
|
|
38344
|
+
const vol = v.muted ? 0 : v.volume;
|
|
38345
|
+
const muted = vol === 0;
|
|
38346
|
+
const icon = muted ? ICON.volMute : vol < 0.4 ? ICON.volLow : vol < 0.75 ? ICON.volMid : ICON.volHigh;
|
|
37732
38347
|
this.volBtn.innerHTML = '';
|
|
37733
|
-
this.volBtn.appendChild(
|
|
37734
|
-
this.
|
|
38348
|
+
this.volBtn.appendChild(svgEl(icon, 18, 18));
|
|
38349
|
+
this.volBtn.setAttribute('aria-label', muted ? 'Unmute' : 'Mute');
|
|
38350
|
+
this.volBtn.title = muted ? 'Unmute (m)' : 'Mute (m)';
|
|
38351
|
+
this.volSlider.value = String(vol);
|
|
38352
|
+
}
|
|
38353
|
+
_startSeekDrag() {
|
|
38354
|
+
this.seekDragging = true;
|
|
38355
|
+
this.seekWrap.classList.add('gvp-dragging');
|
|
37735
38356
|
}
|
|
37736
|
-
|
|
38357
|
+
_endSeekDrag() {
|
|
38358
|
+
this.seekDragging = false;
|
|
38359
|
+
this.seekWrap.classList.remove('gvp-dragging');
|
|
38360
|
+
window.removeEventListener('mousemove', this._seekMouseMoveBound);
|
|
38361
|
+
window.removeEventListener('mouseup', this._seekMouseUpBound);
|
|
38362
|
+
window.removeEventListener('touchmove', this._seekTouchMoveBound);
|
|
38363
|
+
window.removeEventListener('touchend', this._seekTouchEndBound);
|
|
38364
|
+
this._resetHideTimer();
|
|
38365
|
+
}
|
|
38366
|
+
_seekTo(clientX) {
|
|
37737
38367
|
if (!this.duration)
|
|
37738
38368
|
return;
|
|
37739
38369
|
const rect = this.seekWrap.getBoundingClientRect();
|
|
37740
|
-
const pct = Math.max(0, Math.min(1, (
|
|
38370
|
+
const pct = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
37741
38371
|
this.corePlayer.seek(pct * this.duration);
|
|
37742
38372
|
}
|
|
37743
|
-
|
|
38373
|
+
_onSeekHover(clientX) {
|
|
37744
38374
|
if (!this.duration)
|
|
37745
38375
|
return;
|
|
37746
38376
|
const rect = this.seekWrap.getBoundingClientRect();
|
|
37747
|
-
const pct = Math.max(0, Math.min(1, (
|
|
38377
|
+
const pct = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
37748
38378
|
this.seekTooltip.textContent = formatTime(pct * this.duration);
|
|
37749
38379
|
this.seekTooltip.style.left = `${pct * 100}%`;
|
|
37750
38380
|
this.seekTooltip.style.opacity = '1';
|
|
37751
38381
|
}
|
|
37752
|
-
|
|
37753
|
-
const
|
|
37754
|
-
const
|
|
37755
|
-
this.timeEl.textContent = `${formatTime(ct)} / ${formatTime(
|
|
37756
|
-
this.
|
|
38382
|
+
_onTimeUpdate() {
|
|
38383
|
+
const ct = this.videoEl.currentTime;
|
|
38384
|
+
const dur = this.duration;
|
|
38385
|
+
this.timeEl.textContent = `${formatTime(ct)} / ${formatTime(dur)}`;
|
|
38386
|
+
this._updateSeekBar();
|
|
38387
|
+
const pct = dur > 0 ? Math.round((ct / dur) * 100) : 0;
|
|
38388
|
+
this.seekWrap.setAttribute('aria-valuenow', String(pct));
|
|
38389
|
+
this.seekWrap.setAttribute('aria-valuetext', `${formatTime(ct)} of ${formatTime(dur)}`);
|
|
37757
38390
|
}
|
|
37758
|
-
|
|
38391
|
+
_updateSeekBar() {
|
|
37759
38392
|
const ct = this.videoEl.currentTime;
|
|
37760
38393
|
const dur = this.duration;
|
|
37761
38394
|
if (!dur)
|
|
@@ -37766,128 +38399,196 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
|
|
|
37766
38399
|
this.seekBuffered.style.width = `${bPct}%`;
|
|
37767
38400
|
this.seekThumb.style.left = `${pPct}%`;
|
|
37768
38401
|
}
|
|
37769
|
-
|
|
38402
|
+
_buildQualityMenu() {
|
|
37770
38403
|
if (!this.qualityLevels.length)
|
|
37771
38404
|
return;
|
|
37772
|
-
this.settingsBtn.
|
|
38405
|
+
this.settingsBtn.classList.remove('gvp-hidden');
|
|
37773
38406
|
this.qualityMenu.innerHTML = '';
|
|
37774
38407
|
const title = el('div', 'gvp-menu-title');
|
|
38408
|
+
title.setAttribute('aria-hidden', 'true');
|
|
37775
38409
|
title.textContent = 'Quality';
|
|
37776
38410
|
const autoItem = el('div', 'gvp-menu-item gvp-menu-item-active');
|
|
38411
|
+
autoItem.setAttribute('role', 'menuitemradio');
|
|
38412
|
+
autoItem.setAttribute('aria-checked', 'true');
|
|
37777
38413
|
autoItem.dataset['quality'] = '-1';
|
|
37778
38414
|
autoItem.textContent = 'Auto';
|
|
37779
|
-
const
|
|
37780
|
-
|
|
37781
|
-
|
|
37782
|
-
|
|
37783
|
-
this.qualityMenu.append(title, autoItem, sep);
|
|
38415
|
+
const checkEl = el('span', 'gvp-menu-check');
|
|
38416
|
+
checkEl.setAttribute('aria-hidden', 'true');
|
|
38417
|
+
checkEl.textContent = '✓';
|
|
38418
|
+
autoItem.appendChild(checkEl);
|
|
38419
|
+
this.qualityMenu.append(title, autoItem, el('div', 'gvp-menu-sep'));
|
|
37784
38420
|
[...this.qualityLevels].reverse().forEach(q => {
|
|
37785
38421
|
const item = el('div', 'gvp-menu-item');
|
|
38422
|
+
item.setAttribute('role', 'menuitemradio');
|
|
38423
|
+
item.setAttribute('aria-checked', 'false');
|
|
37786
38424
|
item.dataset['quality'] = String(q.index);
|
|
37787
38425
|
item.textContent = q.name;
|
|
37788
38426
|
this.qualityMenu.appendChild(item);
|
|
37789
38427
|
});
|
|
37790
38428
|
this.currentQualityIdx = -1;
|
|
37791
38429
|
}
|
|
37792
|
-
|
|
38430
|
+
_refreshQualityMenu() {
|
|
37793
38431
|
this.qualityMenu.querySelectorAll('[data-quality]').forEach(item => {
|
|
37794
|
-
const
|
|
37795
|
-
|
|
37796
|
-
item.
|
|
38432
|
+
const active = parseInt(item.dataset['quality']) === this.currentQualityIdx;
|
|
38433
|
+
item.className = active ? 'gvp-menu-item gvp-menu-item-active' : 'gvp-menu-item';
|
|
38434
|
+
item.setAttribute('aria-checked', String(active));
|
|
37797
38435
|
const existing = item.querySelector('.gvp-menu-check');
|
|
37798
38436
|
if (active && !existing) {
|
|
37799
|
-
const
|
|
37800
|
-
|
|
37801
|
-
|
|
38437
|
+
const c = el('span', 'gvp-menu-check');
|
|
38438
|
+
c.setAttribute('aria-hidden', 'true');
|
|
38439
|
+
c.textContent = '✓';
|
|
38440
|
+
item.appendChild(c);
|
|
37802
38441
|
}
|
|
37803
38442
|
else if (!active && existing) {
|
|
37804
38443
|
existing.remove();
|
|
37805
38444
|
}
|
|
37806
38445
|
});
|
|
37807
38446
|
}
|
|
37808
|
-
|
|
38447
|
+
_refreshSpeedMenu() {
|
|
37809
38448
|
this.speedMenu.querySelectorAll('[data-speed]').forEach(item => {
|
|
37810
|
-
const
|
|
37811
|
-
item.className =
|
|
38449
|
+
const active = parseFloat(item.dataset['speed']) === this.playbackRate;
|
|
38450
|
+
item.className = active ? 'gvp-menu-item gvp-menu-item-active' : 'gvp-menu-item';
|
|
38451
|
+
item.setAttribute('aria-checked', String(active));
|
|
38452
|
+
const existing = item.querySelector('.gvp-menu-check');
|
|
38453
|
+
if (active && !existing) {
|
|
38454
|
+
const c = el('span', 'gvp-menu-check');
|
|
38455
|
+
c.setAttribute('aria-hidden', 'true');
|
|
38456
|
+
c.textContent = '✓';
|
|
38457
|
+
item.appendChild(c);
|
|
38458
|
+
}
|
|
38459
|
+
else if (!active && existing) {
|
|
38460
|
+
existing.remove();
|
|
38461
|
+
}
|
|
37812
38462
|
});
|
|
37813
38463
|
}
|
|
37814
|
-
|
|
38464
|
+
_toggleMenu(which) {
|
|
37815
38465
|
const same = this.openMenu === which;
|
|
37816
|
-
this.
|
|
38466
|
+
this._closeMenus();
|
|
37817
38467
|
if (!same) {
|
|
37818
38468
|
this.openMenu = which;
|
|
37819
38469
|
if (which === 'speed') {
|
|
37820
|
-
this.
|
|
37821
|
-
this.speedMenu.classList.remove('gvp-
|
|
38470
|
+
this._refreshSpeedMenu();
|
|
38471
|
+
this.speedMenu.classList.remove('gvp-hidden');
|
|
37822
38472
|
}
|
|
37823
38473
|
else {
|
|
37824
|
-
this.
|
|
37825
|
-
this.qualityMenu.classList.remove('gvp-
|
|
38474
|
+
this._refreshQualityMenu();
|
|
38475
|
+
this.qualityMenu.classList.remove('gvp-hidden');
|
|
37826
38476
|
}
|
|
37827
38477
|
}
|
|
37828
38478
|
}
|
|
37829
|
-
|
|
38479
|
+
_closeMenus() {
|
|
37830
38480
|
this.openMenu = null;
|
|
37831
|
-
this.speedMenu.classList.add('gvp-
|
|
37832
|
-
this.qualityMenu.classList.add('gvp-
|
|
38481
|
+
this.speedMenu.classList.add('gvp-hidden');
|
|
38482
|
+
this.qualityMenu.classList.add('gvp-hidden');
|
|
37833
38483
|
}
|
|
37834
|
-
|
|
38484
|
+
_showControls(visible) {
|
|
37835
38485
|
this.controls.classList.toggle('gvp-controls-hidden', !visible);
|
|
37836
38486
|
this.badge.classList.toggle('gvp-badge-hidden', !visible);
|
|
37837
38487
|
}
|
|
37838
|
-
|
|
37839
|
-
this.
|
|
38488
|
+
_resetHideTimer() {
|
|
38489
|
+
this._showControls(true);
|
|
37840
38490
|
if (this.hideTimer)
|
|
37841
38491
|
clearTimeout(this.hideTimer);
|
|
37842
38492
|
this.hideTimer = setTimeout(() => {
|
|
37843
|
-
if (this.playerState === exports.PlayerState.PLAYING)
|
|
37844
|
-
this.
|
|
38493
|
+
if (this.playerState === exports.PlayerState.PLAYING && !this.openMenu) {
|
|
38494
|
+
this._showControls(false);
|
|
38495
|
+
}
|
|
37845
38496
|
}, 2800);
|
|
37846
38497
|
}
|
|
37847
|
-
|
|
37848
|
-
|
|
37849
|
-
|
|
38498
|
+
_toggleFullscreen() {
|
|
38499
|
+
const doc = document;
|
|
38500
|
+
const root = this.root;
|
|
38501
|
+
const isFs = !!(document.fullscreenElement ||
|
|
38502
|
+
doc.webkitFullscreenElement ||
|
|
38503
|
+
doc.mozFullScreenElement ||
|
|
38504
|
+
doc.msFullscreenElement);
|
|
38505
|
+
if (isFs) {
|
|
38506
|
+
(document.exitFullscreen?.() ||
|
|
38507
|
+
doc.webkitExitFullscreen?.() ||
|
|
38508
|
+
doc.mozCancelFullScreen?.() ||
|
|
38509
|
+
(doc.msExitFullscreen?.(), Promise.resolve()))
|
|
38510
|
+
?.catch?.(() => { });
|
|
37850
38511
|
}
|
|
37851
38512
|
else {
|
|
37852
|
-
|
|
37853
|
-
|
|
37854
|
-
|
|
37855
|
-
|
|
37856
|
-
|
|
38513
|
+
(root.requestFullscreen?.() ||
|
|
38514
|
+
root.webkitRequestFullscreen?.() ||
|
|
38515
|
+
root.mozRequestFullScreen?.() ||
|
|
38516
|
+
(root.msRequestFullscreen?.(), Promise.resolve()))
|
|
38517
|
+
?.catch?.(() => { });
|
|
38518
|
+
}
|
|
38519
|
+
}
|
|
38520
|
+
_onFsChange() {
|
|
38521
|
+
const doc = document;
|
|
38522
|
+
const fs = !!(document.fullscreenElement ||
|
|
38523
|
+
doc.webkitFullscreenElement ||
|
|
38524
|
+
doc.mozFullScreenElement ||
|
|
38525
|
+
doc.msFullscreenElement);
|
|
37857
38526
|
this.fsBtn.innerHTML = '';
|
|
37858
|
-
this.fsBtn.appendChild(
|
|
37859
|
-
this.fsBtn.
|
|
37860
|
-
|
|
37861
|
-
|
|
37862
|
-
|
|
37863
|
-
|
|
37864
|
-
|
|
37865
|
-
|
|
37866
|
-
|
|
37867
|
-
|
|
37868
|
-
|
|
37869
|
-
this.controls.style.display = 'none';
|
|
37870
|
-
}
|
|
37871
|
-
renderWatermark() {
|
|
37872
|
-
if (!this.watermarkText)
|
|
37873
|
-
return;
|
|
38527
|
+
this.fsBtn.appendChild(svgEl(fs ? ICON.fsExit : ICON.fsEnter, 18, 18));
|
|
38528
|
+
this.fsBtn.setAttribute('aria-label', fs ? 'Exit fullscreen' : 'Enter fullscreen');
|
|
38529
|
+
this.fsBtn.title = fs ? 'Exit fullscreen (f)' : 'Enter fullscreen (f)';
|
|
38530
|
+
}
|
|
38531
|
+
_showError(err) {
|
|
38532
|
+
this.errorOverlay.children[1].textContent = err.code;
|
|
38533
|
+
this.errorOverlay.children[2].textContent = err.message;
|
|
38534
|
+
this.errorOverlay.classList.remove('gvp-hidden');
|
|
38535
|
+
this.controls.classList.add('gvp-hidden');
|
|
38536
|
+
}
|
|
38537
|
+
_renderWatermark(text) {
|
|
37874
38538
|
this.watermarkDiv.innerHTML = '';
|
|
37875
38539
|
for (let i = 0; i < 20; i++) {
|
|
37876
38540
|
const span = el('span', 'gvp-watermark-text');
|
|
37877
|
-
span.textContent =
|
|
38541
|
+
span.textContent = text;
|
|
37878
38542
|
span.style.left = `${(i % 4) * 26 + (Math.floor(i / 4) % 2) * 13}%`;
|
|
37879
38543
|
span.style.top = `${Math.floor(i / 4) * 22}%`;
|
|
37880
38544
|
this.watermarkDiv.appendChild(span);
|
|
37881
38545
|
}
|
|
37882
38546
|
}
|
|
37883
|
-
|
|
38547
|
+
_addRipple(e) {
|
|
37884
38548
|
const rect = this.root.getBoundingClientRect();
|
|
37885
38549
|
const d = document.createElement('div');
|
|
37886
38550
|
d.className = 'gvp-ripple';
|
|
37887
|
-
const
|
|
37888
|
-
d.style.cssText = `width:${
|
|
38551
|
+
const sz = 60;
|
|
38552
|
+
d.style.cssText = `width:${sz}px;height:${sz}px;left:${e.clientX - rect.left - sz / 2}px;top:${e.clientY - rect.top - sz / 2}px`;
|
|
37889
38553
|
this.root.appendChild(d);
|
|
37890
|
-
setTimeout(() => d.remove(),
|
|
38554
|
+
setTimeout(() => d.remove(), 650);
|
|
38555
|
+
}
|
|
38556
|
+
_onKeyDown(e) {
|
|
38557
|
+
switch (e.code) {
|
|
38558
|
+
case 'Space':
|
|
38559
|
+
case 'KeyK':
|
|
38560
|
+
e.preventDefault();
|
|
38561
|
+
this._togglePlay();
|
|
38562
|
+
break;
|
|
38563
|
+
case 'ArrowLeft':
|
|
38564
|
+
if (document.activeElement !== this.seekWrap) {
|
|
38565
|
+
e.preventDefault();
|
|
38566
|
+
this.corePlayer.seek(Math.max(0, this.videoEl.currentTime - 5));
|
|
38567
|
+
}
|
|
38568
|
+
break;
|
|
38569
|
+
case 'ArrowRight':
|
|
38570
|
+
if (document.activeElement !== this.seekWrap) {
|
|
38571
|
+
e.preventDefault();
|
|
38572
|
+
this.corePlayer.seek(Math.min(this.duration, this.videoEl.currentTime + 5));
|
|
38573
|
+
}
|
|
38574
|
+
break;
|
|
38575
|
+
case 'ArrowUp':
|
|
38576
|
+
e.preventDefault();
|
|
38577
|
+
this.videoEl.volume = Math.min(1, this.videoEl.volume + 0.1);
|
|
38578
|
+
break;
|
|
38579
|
+
case 'ArrowDown':
|
|
38580
|
+
e.preventDefault();
|
|
38581
|
+
this.videoEl.volume = Math.max(0, this.videoEl.volume - 0.1);
|
|
38582
|
+
break;
|
|
38583
|
+
case 'KeyM':
|
|
38584
|
+
e.preventDefault();
|
|
38585
|
+
this._toggleMute();
|
|
38586
|
+
break;
|
|
38587
|
+
case 'KeyF':
|
|
38588
|
+
e.preventDefault();
|
|
38589
|
+
this._toggleFullscreen();
|
|
38590
|
+
break;
|
|
38591
|
+
}
|
|
37891
38592
|
}
|
|
37892
38593
|
play() { return this.corePlayer.play(); }
|
|
37893
38594
|
pause() { return this.corePlayer.pause(); }
|
|
@@ -37904,22 +38605,32 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
|
|
|
37904
38605
|
destroy() {
|
|
37905
38606
|
if (this.hideTimer)
|
|
37906
38607
|
clearTimeout(this.hideTimer);
|
|
38608
|
+
document.removeEventListener('fullscreenchange', this._onFsChangeBound);
|
|
38609
|
+
document.removeEventListener('webkitfullscreenchange', this._onFsChangeBound);
|
|
38610
|
+
document.removeEventListener('mozfullscreenchange', this._onFsChangeBound);
|
|
38611
|
+
document.removeEventListener('MSFullscreenChange', this._onFsChangeBound);
|
|
38612
|
+
window.removeEventListener('mousemove', this._seekMouseMoveBound);
|
|
38613
|
+
window.removeEventListener('mouseup', this._seekMouseUpBound);
|
|
38614
|
+
window.removeEventListener('touchmove', this._seekTouchMoveBound);
|
|
38615
|
+
window.removeEventListener('touchend', this._seekTouchEndBound);
|
|
37907
38616
|
this.corePlayer.destroy();
|
|
37908
38617
|
this.root.remove();
|
|
37909
38618
|
}
|
|
37910
38619
|
}
|
|
38620
|
+
|
|
37911
38621
|
class GuardVideoPlayer {
|
|
37912
38622
|
constructor(ui) {
|
|
37913
38623
|
this.ui = ui;
|
|
37914
38624
|
}
|
|
37915
38625
|
static create(containerId, videoId, config) {
|
|
37916
38626
|
const container = document.getElementById(containerId);
|
|
37917
|
-
if (!container)
|
|
37918
|
-
throw new Error(`
|
|
37919
|
-
|
|
38627
|
+
if (!container) {
|
|
38628
|
+
throw new Error(`GuardVideoPlayer: element '#${containerId}' not found`);
|
|
38629
|
+
}
|
|
38630
|
+
return new GuardVideoPlayer(new PlayerUI(container, videoId, config));
|
|
37920
38631
|
}
|
|
37921
38632
|
static createInElement(container, videoId, config) {
|
|
37922
|
-
return new GuardVideoPlayer(new
|
|
38633
|
+
return new GuardVideoPlayer(new PlayerUI(container, videoId, config));
|
|
37923
38634
|
}
|
|
37924
38635
|
play() { return this.ui.play(); }
|
|
37925
38636
|
pause() { return this.ui.pause(); }
|
|
@@ -37941,6 +38652,7 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
|
|
|
37941
38652
|
}
|
|
37942
38653
|
|
|
37943
38654
|
exports.GuardVideoPlayer = GuardVideoPlayer;
|
|
38655
|
+
exports.PlayerUI = PlayerUI;
|
|
37944
38656
|
|
|
37945
38657
|
return exports;
|
|
37946
38658
|
|