@banou/media-player 0.8.11 → 0.8.12
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/dist/index.js
CHANGED
|
@@ -117,14 +117,26 @@ var ae = {
|
|
|
117
117
|
ready: !1
|
|
118
118
|
});
|
|
119
119
|
let u = (t, n) => {
|
|
120
|
-
let r =
|
|
121
|
-
|
|
120
|
+
let r = Date.now(), i = R(t), o = fe(t), s = a.playbackErrors, c = s[s.length - 1];
|
|
121
|
+
if (c && c.message === i && c.detail === o && c.recovered === n) {
|
|
122
|
+
let e = {
|
|
123
|
+
...c,
|
|
124
|
+
count: c.count + 1,
|
|
125
|
+
lastAt: r
|
|
126
|
+
};
|
|
127
|
+
a.setSourceState({ playbackErrors: [...s.slice(0, -1), e] });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
let l = {
|
|
131
|
+
at: r,
|
|
132
|
+
lastAt: r,
|
|
133
|
+
count: 1,
|
|
122
134
|
atMediaTime: Number.isFinite(e.currentTime) ? e.currentTime : void 0,
|
|
123
|
-
message:
|
|
124
|
-
detail:
|
|
135
|
+
message: i,
|
|
136
|
+
detail: o,
|
|
125
137
|
recovered: n
|
|
126
138
|
};
|
|
127
|
-
a.setSourceState({ playbackErrors: [...
|
|
139
|
+
a.setSourceState({ playbackErrors: [...s, l] });
|
|
128
140
|
}, d = (e) => {
|
|
129
141
|
if (r) return;
|
|
130
142
|
let t = n(e);
|
|
@@ -1046,6 +1058,12 @@ ${X}
|
|
|
1046
1058
|
.when {
|
|
1047
1059
|
color: #bbb;
|
|
1048
1060
|
${V.bSmall.regular}
|
|
1061
|
+
|
|
1062
|
+
/* the one part of the line worth scanning for, so it is the one part at full brightness */
|
|
1063
|
+
.count {
|
|
1064
|
+
margin-left: 6px;
|
|
1065
|
+
color: #fff;
|
|
1066
|
+
}
|
|
1049
1067
|
}
|
|
1050
1068
|
|
|
1051
1069
|
.what {
|
|
@@ -1062,21 +1080,21 @@ ${X}
|
|
|
1062
1080
|
}
|
|
1063
1081
|
}
|
|
1064
1082
|
}
|
|
1065
|
-
`, Me = (e) => new Date(e).toLocaleTimeString(), Q = (e) => e === void 0 || !Number.isFinite(e) ? void 0 : K(Math.max(0, e)), Ne = (e) => e.map((e, t) => {
|
|
1066
|
-
let n = Q(e.atMediaTime);
|
|
1083
|
+
`, Me = (e) => new Date(e).toLocaleTimeString(), Q = (e) => e === void 0 || !Number.isFinite(e) ? void 0 : K(Math.max(0, e)), Ne = (e) => e.reduce((e, t) => e + t.count, 0), Pe = (e) => e.map((e, t) => {
|
|
1084
|
+
let n = Q(e.atMediaTime), r = e.count > 1 ? `${new Date(e.at).toISOString()} to ${new Date(e.lastAt).toISOString()} ×${e.count}` : new Date(e.at).toISOString();
|
|
1067
1085
|
return [
|
|
1068
|
-
`${t + 1}. ${
|
|
1086
|
+
`${t + 1}. ${r}${n ? ` (at ${n})` : ""}${e.recovered ? " [recovered]" : ""}`,
|
|
1069
1087
|
e.message,
|
|
1070
1088
|
e.detail
|
|
1071
1089
|
].filter(Boolean).join("\n");
|
|
1072
|
-
}).join("\n\n"),
|
|
1090
|
+
}).join("\n\n"), Fe = () => {
|
|
1073
1091
|
let e = L((e) => e.playbackErrors), { open: t, toggle: n, containerRef: r } = Z(), [i, a] = m(!1);
|
|
1074
1092
|
if (e.length === 0) return null;
|
|
1075
1093
|
let o = () => {
|
|
1076
|
-
navigator.clipboard?.writeText(
|
|
1094
|
+
navigator.clipboard?.writeText(Pe(e)).then(() => {
|
|
1077
1095
|
a(!0), setTimeout(() => a(!1), 2e3);
|
|
1078
1096
|
}, (e) => console.warn("[media-player] could not copy the errors:", e));
|
|
1079
|
-
}, s = `Playback errors (${e
|
|
1097
|
+
}, s = `Playback errors (${Ne(e)})`;
|
|
1080
1098
|
return /* @__PURE__ */ w("div", {
|
|
1081
1099
|
css: je,
|
|
1082
1100
|
ref: r,
|
|
@@ -1110,8 +1128,13 @@ ${X}
|
|
|
1110
1128
|
className: "when",
|
|
1111
1129
|
children: [
|
|
1112
1130
|
Me(e.at),
|
|
1131
|
+
e.count > 1 ? ` to ${Me(e.lastAt)}` : "",
|
|
1113
1132
|
Q(e.atMediaTime) ? ` at ${Q(e.atMediaTime)}` : "",
|
|
1114
|
-
e.recovered ? " recovered" : ""
|
|
1133
|
+
e.recovered ? " recovered" : "",
|
|
1134
|
+
e.count > 1 ? /* @__PURE__ */ C("span", {
|
|
1135
|
+
className: "count",
|
|
1136
|
+
children: `×${e.count}`
|
|
1137
|
+
}) : null
|
|
1115
1138
|
]
|
|
1116
1139
|
}),
|
|
1117
1140
|
/* @__PURE__ */ C("span", {
|
|
@@ -1126,7 +1149,7 @@ ${X}
|
|
|
1126
1149
|
}, `${e.at}-${t}`))]
|
|
1127
1150
|
})]
|
|
1128
1151
|
});
|
|
1129
|
-
},
|
|
1152
|
+
}, Ie = h`
|
|
1130
1153
|
display: flex;
|
|
1131
1154
|
align-items: center;
|
|
1132
1155
|
justify-content: center;
|
|
@@ -1179,7 +1202,7 @@ width: 100%;
|
|
|
1179
1202
|
}
|
|
1180
1203
|
}
|
|
1181
1204
|
}
|
|
1182
|
-
`,
|
|
1205
|
+
`, Le = () => {
|
|
1183
1206
|
let e = L(), t = L((e) => e.playbackRate), n = p(null), r = p(null), i = .25, a = 3 - i, o = (e, t = .05) => Math.round(e / t) * t, s = o(t || 1), c = (e) => (e - i) / a * 100, l = (e) => o(i + e * a), { handlers: u } = J({
|
|
1184
1207
|
ref: r,
|
|
1185
1208
|
onChange: (t) => e.setPlaybackRate(l(t))
|
|
@@ -1196,7 +1219,7 @@ width: 100%;
|
|
|
1196
1219
|
}, [t]);
|
|
1197
1220
|
let m = c(s);
|
|
1198
1221
|
return /* @__PURE__ */ w("div", {
|
|
1199
|
-
css:
|
|
1222
|
+
css: Ie,
|
|
1200
1223
|
children: [/* @__PURE__ */ w("div", { children: [s.toFixed(2), "x"] }), /* @__PURE__ */ C("div", {
|
|
1201
1224
|
className: "playback-slider",
|
|
1202
1225
|
ref: n,
|
|
@@ -1214,7 +1237,7 @@ width: 100%;
|
|
|
1214
1237
|
})
|
|
1215
1238
|
})]
|
|
1216
1239
|
});
|
|
1217
|
-
},
|
|
1240
|
+
}, Re = h`
|
|
1218
1241
|
/* Deliberately NOT a containing block. The menu anchors to the control bar instead, which is exactly
|
|
1219
1242
|
as wide as the player box and can therefore be clamped to it. The outside-click check uses
|
|
1220
1243
|
\`contains\` on the ref, which is DOM containment and needs no position, and the bar's other
|
|
@@ -1273,7 +1296,7 @@ ${X}
|
|
|
1273
1296
|
}
|
|
1274
1297
|
}
|
|
1275
1298
|
|
|
1276
|
-
`,
|
|
1299
|
+
`, ze = () => {
|
|
1277
1300
|
let e = L(), t = L((e) => e.playbackRate), n = L((e) => e.audioTracks), r = L((e) => e.selectedAudioTrack), i = L((e) => e.selectAudioTrack), [a, o] = m(0), { open: s, toggle: c, containerRef: l, pending: u, failed: d, runSelect: f } = Z({ onReset: () => o(0) }), p = (t) => {
|
|
1278
1301
|
e.setPlaybackRate(t), o(0);
|
|
1279
1302
|
}, h = (e) => {
|
|
@@ -1282,7 +1305,7 @@ ${X}
|
|
|
1282
1305
|
o(e);
|
|
1283
1306
|
};
|
|
1284
1307
|
return /* @__PURE__ */ w("div", {
|
|
1285
|
-
css:
|
|
1308
|
+
css: Re,
|
|
1286
1309
|
ref: l,
|
|
1287
1310
|
children: [
|
|
1288
1311
|
/* @__PURE__ */ C(q, {
|
|
@@ -1321,7 +1344,7 @@ ${X}
|
|
|
1321
1344
|
}),
|
|
1322
1345
|
/* @__PURE__ */ C("div", {
|
|
1323
1346
|
className: "slider no-hover",
|
|
1324
|
-
children: /* @__PURE__ */ C(
|
|
1347
|
+
children: /* @__PURE__ */ C(Le, {})
|
|
1325
1348
|
}),
|
|
1326
1349
|
/* @__PURE__ */ w("div", {
|
|
1327
1350
|
className: "options no-hover",
|
|
@@ -1357,7 +1380,7 @@ ${X}
|
|
|
1357
1380
|
})
|
|
1358
1381
|
]
|
|
1359
1382
|
});
|
|
1360
|
-
},
|
|
1383
|
+
}, Be = h`
|
|
1361
1384
|
/* Not a containing block, for the reason given on popoverStyle: the menu anchors to the control bar,
|
|
1362
1385
|
which is the width of the player box, so it can be clamped to it. */
|
|
1363
1386
|
position: static;
|
|
@@ -1374,12 +1397,12 @@ position: static;
|
|
|
1374
1397
|
}
|
|
1375
1398
|
|
|
1376
1399
|
${X}
|
|
1377
|
-
`,
|
|
1400
|
+
`, Ve = () => {
|
|
1378
1401
|
let e = L((e) => e.subtitleTracks), t = L((e) => e.selectedSubtitleTrack), n = L((e) => e.selectSubtitleTrack), r = L((e) => e.subtitleOffLabel), { open: i, toggle: a, containerRef: o, pending: s, failed: c, runSelect: l } = Z();
|
|
1379
1402
|
if (e.length === 0) return null;
|
|
1380
1403
|
let u = t !== void 0;
|
|
1381
1404
|
return /* @__PURE__ */ w("div", {
|
|
1382
|
-
css:
|
|
1405
|
+
css: Be,
|
|
1383
1406
|
ref: o,
|
|
1384
1407
|
children: [/* @__PURE__ */ C(q, {
|
|
1385
1408
|
id: "subtitles",
|
|
@@ -1404,14 +1427,14 @@ ${X}
|
|
|
1404
1427
|
failed: c
|
|
1405
1428
|
})]
|
|
1406
1429
|
});
|
|
1407
|
-
},
|
|
1430
|
+
}, He = {
|
|
1408
1431
|
primary: "#EAEBEE",
|
|
1409
1432
|
secondary: "#D0D0D9",
|
|
1410
1433
|
hover: "rgba(255, 255, 255, 0.13)",
|
|
1411
1434
|
accent: "#6EA8FE",
|
|
1412
1435
|
borderPrimary: "#384F70",
|
|
1413
1436
|
backgroundTooltip: "#222222"
|
|
1414
|
-
},
|
|
1437
|
+
}, Ue = h`
|
|
1415
1438
|
display: flex;
|
|
1416
1439
|
align-items: center;
|
|
1417
1440
|
|
|
@@ -1454,7 +1477,7 @@ ${X}
|
|
|
1454
1477
|
width: 10px;
|
|
1455
1478
|
height: 10px;
|
|
1456
1479
|
}
|
|
1457
|
-
`,
|
|
1480
|
+
`, We = ({ value: e, onChange: t }) => {
|
|
1458
1481
|
let n = L((e) => e.volume), r = L((e) => e.muted), i = p(null), a = p(null), { handlers: o } = J({
|
|
1459
1482
|
ref: a,
|
|
1460
1483
|
onChange: t
|
|
@@ -1474,7 +1497,7 @@ ${X}
|
|
|
1474
1497
|
id: "volume-slider",
|
|
1475
1498
|
text: /* @__PURE__ */ C("div", {
|
|
1476
1499
|
ref: i,
|
|
1477
|
-
css:
|
|
1500
|
+
css: Ue,
|
|
1478
1501
|
...o,
|
|
1479
1502
|
children: /* @__PURE__ */ C("div", {
|
|
1480
1503
|
ref: a,
|
|
@@ -1493,7 +1516,7 @@ ${X}
|
|
|
1493
1516
|
children: [l, "%"]
|
|
1494
1517
|
})
|
|
1495
1518
|
});
|
|
1496
|
-
},
|
|
1519
|
+
}, Ge = h`
|
|
1497
1520
|
position: relative;
|
|
1498
1521
|
display: flex;
|
|
1499
1522
|
align-items: center;
|
|
@@ -1556,10 +1579,10 @@ ${X}
|
|
|
1556
1579
|
}
|
|
1557
1580
|
}
|
|
1558
1581
|
|
|
1559
|
-
`,
|
|
1582
|
+
`, Ke = ({ ref: e }) => {
|
|
1560
1583
|
let t = L(), n = L((e) => e.volume), r = L((e) => e.muted), i = f(() => G(n), [n]);
|
|
1561
1584
|
return /* @__PURE__ */ w("div", {
|
|
1562
|
-
css:
|
|
1585
|
+
css: Ge,
|
|
1563
1586
|
children: [/* @__PURE__ */ C(q, {
|
|
1564
1587
|
id: "sound",
|
|
1565
1588
|
text: /* @__PURE__ */ C("button", {
|
|
@@ -1579,7 +1602,7 @@ ${X}
|
|
|
1579
1602
|
className: "volume-slider-container",
|
|
1580
1603
|
children: /* @__PURE__ */ C("div", {
|
|
1581
1604
|
className: "volume-slider-background",
|
|
1582
|
-
children: /* @__PURE__ */ C(
|
|
1605
|
+
children: /* @__PURE__ */ C(We, {
|
|
1583
1606
|
value: r ? 0 : i,
|
|
1584
1607
|
onChange: (e) => {
|
|
1585
1608
|
t.setVolume(W(e));
|
|
@@ -1588,7 +1611,7 @@ ${X}
|
|
|
1588
1611
|
})
|
|
1589
1612
|
})]
|
|
1590
1613
|
});
|
|
1591
|
-
}, $ = .05,
|
|
1614
|
+
}, $ = .05, qe = 5, Je = h`
|
|
1592
1615
|
display: flex;
|
|
1593
1616
|
flex-direction: column;
|
|
1594
1617
|
gap: calc(0.4 * var(--mp-unit));
|
|
@@ -1599,7 +1622,7 @@ ${X}
|
|
|
1599
1622
|
opacity: 0.72;
|
|
1600
1623
|
font-size: 0.9em;
|
|
1601
1624
|
}
|
|
1602
|
-
`,
|
|
1625
|
+
`, Ye = h`
|
|
1603
1626
|
position: absolute;
|
|
1604
1627
|
bottom: 0;
|
|
1605
1628
|
width: 100%;
|
|
@@ -1664,7 +1687,7 @@ ${X}
|
|
|
1664
1687
|
* drawn in the hover colour is invisible exactly when it is being looked for.
|
|
1665
1688
|
*/
|
|
1666
1689
|
button[aria-pressed='true'] svg {
|
|
1667
|
-
stroke: ${
|
|
1690
|
+
stroke: ${He.accent};
|
|
1668
1691
|
}
|
|
1669
1692
|
|
|
1670
1693
|
.play, .sound, .time, .errors, .subtitles, .settings, .picture-in-picture, .full-screen {
|
|
@@ -1699,7 +1722,7 @@ ${X}
|
|
|
1699
1722
|
cursor: pointer;
|
|
1700
1723
|
|
|
1701
1724
|
:hover {
|
|
1702
|
-
background-color: ${
|
|
1725
|
+
background-color: ${He.hover};
|
|
1703
1726
|
}
|
|
1704
1727
|
|
|
1705
1728
|
/* the hit area grows, the icon does not, keyed on the pointer because a narrow desktop
|
|
@@ -1737,7 +1760,7 @@ ${X}
|
|
|
1737
1760
|
}
|
|
1738
1761
|
}
|
|
1739
1762
|
}
|
|
1740
|
-
`,
|
|
1763
|
+
`, Xe = () => {
|
|
1741
1764
|
let e = L(), t = L((e) => e.paused), n = L((e) => e.currentTime), r = L((e) => e.duration), i = L((e) => e.fullscreen), a = L((e) => e.hideUI), o = L((e) => e.togglePictureInPicture), s = L((e) => e.pictureInPictureMode), c = L((e) => e.burnedInSubtitles), l = L((e) => e.subtitleTracks), [f, p] = m(null), h = s === "burn-in", g = l.length > 0, _ = r > 0 && n === r, v = u(({ direction: t, stepSize: n }) => {
|
|
1742
1765
|
let r = G(e.volume), i = t === "up" ? n : -n, a = Math.max(0, Math.min(1, r + i)), o = e.muted;
|
|
1743
1766
|
e.setVolume(W(a)), o && !e.muted && e.toggleMuted();
|
|
@@ -1761,8 +1784,8 @@ ${X}
|
|
|
1761
1784
|
});
|
|
1762
1785
|
else if (t.key === "ArrowRight") {
|
|
1763
1786
|
if (!e.duration) return;
|
|
1764
|
-
e.seek(Math.min(e.currentTime +
|
|
1765
|
-
} else t.key === "ArrowLeft" ? e.seek(Math.max(e.currentTime -
|
|
1787
|
+
e.seek(Math.min(e.currentTime + qe, e.duration));
|
|
1788
|
+
} else t.key === "ArrowLeft" ? e.seek(Math.max(e.currentTime - qe, 0)) : r = !1;
|
|
1766
1789
|
r && t.preventDefault();
|
|
1767
1790
|
};
|
|
1768
1791
|
return window.addEventListener("keydown", t), () => window.removeEventListener("keydown", t);
|
|
@@ -1779,7 +1802,7 @@ ${X}
|
|
|
1779
1802
|
return d(() => {
|
|
1780
1803
|
if (f) return f.addEventListener("wheel", y, { passive: !1 }), () => f.removeEventListener("wheel", y);
|
|
1781
1804
|
}, [f, y]), /* @__PURE__ */ w("div", {
|
|
1782
|
-
css:
|
|
1805
|
+
css: Ye,
|
|
1783
1806
|
style: { ...a ? {
|
|
1784
1807
|
opacity: "0",
|
|
1785
1808
|
pointerEvents: "none"
|
|
@@ -1801,7 +1824,7 @@ ${X}
|
|
|
1801
1824
|
}),
|
|
1802
1825
|
toolTipText: /* @__PURE__ */ C("span", { children: _ ? "Replay (k)" : t ? "Play (k)" : "Pause (k)" })
|
|
1803
1826
|
}),
|
|
1804
|
-
/* @__PURE__ */ C(
|
|
1827
|
+
/* @__PURE__ */ C(Ke, { ref: p }),
|
|
1805
1828
|
/* @__PURE__ */ C("div", {
|
|
1806
1829
|
className: "time",
|
|
1807
1830
|
children: Se(n, r)
|
|
@@ -1810,9 +1833,9 @@ ${X}
|
|
|
1810
1833
|
}), /* @__PURE__ */ w("div", {
|
|
1811
1834
|
className: "right",
|
|
1812
1835
|
children: [
|
|
1813
|
-
/* @__PURE__ */ C(
|
|
1814
|
-
/* @__PURE__ */ C(
|
|
1815
|
-
/* @__PURE__ */ C(
|
|
1836
|
+
/* @__PURE__ */ C(Fe, {}),
|
|
1837
|
+
/* @__PURE__ */ C(Ve, {}),
|
|
1838
|
+
/* @__PURE__ */ C(ze, {}),
|
|
1816
1839
|
o ? /* @__PURE__ */ C(q, {
|
|
1817
1840
|
id: "picture-in-picture",
|
|
1818
1841
|
tooltipPlace: "top-end",
|
|
@@ -1829,7 +1852,7 @@ ${X}
|
|
|
1829
1852
|
})
|
|
1830
1853
|
}),
|
|
1831
1854
|
toolTipText: /* @__PURE__ */ w("span", {
|
|
1832
|
-
css:
|
|
1855
|
+
css: Je,
|
|
1833
1856
|
children: [/* @__PURE__ */ C("span", {
|
|
1834
1857
|
className: "lead",
|
|
1835
1858
|
children: h ? g ? c ? "Subtitles are in the picture" : "Put the subtitles in the picture" : "This file has no subtitles" : "Picture in picture"
|
|
@@ -1856,7 +1879,7 @@ ${X}
|
|
|
1856
1879
|
})]
|
|
1857
1880
|
})]
|
|
1858
1881
|
});
|
|
1859
|
-
},
|
|
1882
|
+
}, Ze = 9e3, Qe = h`
|
|
1860
1883
|
position: absolute;
|
|
1861
1884
|
inset: 0;
|
|
1862
1885
|
z-index: 2;
|
|
@@ -1910,7 +1933,7 @@ ${X}
|
|
|
1910
1933
|
line-height: 1;
|
|
1911
1934
|
color: #6EA8FE;
|
|
1912
1935
|
}
|
|
1913
|
-
`,
|
|
1936
|
+
`, $e = () => {
|
|
1914
1937
|
let e = L((e) => e.burnedInSubtitles), t = L((e) => e.pictureInPictureMode), [n, r] = m(!1);
|
|
1915
1938
|
return d(() => {
|
|
1916
1939
|
if (t !== "burn-in" || !e) {
|
|
@@ -1918,10 +1941,10 @@ ${X}
|
|
|
1918
1941
|
return;
|
|
1919
1942
|
}
|
|
1920
1943
|
r(!0);
|
|
1921
|
-
let n = setTimeout(() => r(!1),
|
|
1944
|
+
let n = setTimeout(() => r(!1), Ze);
|
|
1922
1945
|
return () => clearTimeout(n);
|
|
1923
1946
|
}, [t, e]), t !== "burn-in" || !e ? null : /* @__PURE__ */ C("div", {
|
|
1924
|
-
css:
|
|
1947
|
+
css: Qe,
|
|
1925
1948
|
className: n ? "show" : "",
|
|
1926
1949
|
role: "status",
|
|
1927
1950
|
children: /* @__PURE__ */ w("div", {
|
|
@@ -1942,7 +1965,7 @@ ${X}
|
|
|
1942
1965
|
})]
|
|
1943
1966
|
})
|
|
1944
1967
|
});
|
|
1945
|
-
},
|
|
1968
|
+
}, et = 3e3, tt = h`
|
|
1946
1969
|
position: absolute;
|
|
1947
1970
|
inset: 0;
|
|
1948
1971
|
z-index: 2;
|
|
@@ -1953,7 +1976,7 @@ ${X}
|
|
|
1953
1976
|
hoverable while faded out, popping a tooltip over nothing. It cascades where pointer-events does
|
|
1954
1977
|
not, and transitioning it holds the item on screen for the length of the fade. */
|
|
1955
1978
|
transition: opacity 0.1s cubic-bezier(.4,0,1,1), visibility 0.1s;
|
|
1956
|
-
`,
|
|
1979
|
+
`, nt = h`
|
|
1957
1980
|
position: relative;
|
|
1958
1981
|
background-color: black;
|
|
1959
1982
|
display: flex;
|
|
@@ -1985,20 +2008,20 @@ ${X}
|
|
|
1985
2008
|
&.hide {
|
|
1986
2009
|
cursor: none;
|
|
1987
2010
|
}
|
|
1988
|
-
`,
|
|
2011
|
+
`, rt = (e, t = "") => s.toArray(e).flatMap((e, n) => {
|
|
1989
2012
|
let r = `${t}${l(e) && e.key != null ? e.key : n}`;
|
|
1990
|
-
return l(e) && e.type === c ?
|
|
2013
|
+
return l(e) && e.type === c ? rt(e.props.children, `${r}/`) : [{
|
|
1991
2014
|
key: r,
|
|
1992
2015
|
item: e
|
|
1993
2016
|
}];
|
|
1994
|
-
}),
|
|
2017
|
+
}), it = ({ ref: e, onVideoRef: t, onCanvasRef: n, overlay: r, controls: i, children: a }) => {
|
|
1995
2018
|
let o = L(), s = L((e) => e.hideUI), c = L((e) => e.setHideUI), l = p(void 0), u = p("mouse");
|
|
1996
2019
|
d(() => () => clearTimeout(l.current), []);
|
|
1997
2020
|
let f = () => {
|
|
1998
|
-
c(!1), clearTimeout(l.current), l.current = setTimeout(() => c(!0),
|
|
2021
|
+
c(!1), clearTimeout(l.current), l.current = setTimeout(() => c(!0), et);
|
|
1999
2022
|
};
|
|
2000
2023
|
return /* @__PURE__ */ w("div", {
|
|
2001
|
-
css:
|
|
2024
|
+
css: nt,
|
|
2002
2025
|
ref: e,
|
|
2003
2026
|
onPointerMove: (e) => {
|
|
2004
2027
|
u.current = e.pointerType, e.pointerType === "mouse" && f();
|
|
@@ -2015,8 +2038,8 @@ ${X}
|
|
|
2015
2038
|
className: s ? "hide" : "",
|
|
2016
2039
|
children: [
|
|
2017
2040
|
/* @__PURE__ */ C(xe, { onCanvasRef: n }),
|
|
2018
|
-
|
|
2019
|
-
css:
|
|
2041
|
+
rt(r).map(({ key: e, item: t }) => /* @__PURE__ */ C("div", {
|
|
2042
|
+
css: tt,
|
|
2020
2043
|
style: { ...s ? {
|
|
2021
2044
|
opacity: "0",
|
|
2022
2045
|
visibility: "hidden",
|
|
@@ -2024,8 +2047,8 @@ ${X}
|
|
|
2024
2047
|
} : {} },
|
|
2025
2048
|
children: t
|
|
2026
2049
|
}, e)),
|
|
2027
|
-
i === !1 ? null : /* @__PURE__ */ C(
|
|
2028
|
-
/* @__PURE__ */ C(
|
|
2050
|
+
i === !1 ? null : /* @__PURE__ */ C(Xe, {}),
|
|
2051
|
+
/* @__PURE__ */ C($e, {}),
|
|
2029
2052
|
/* @__PURE__ */ w("div", {
|
|
2030
2053
|
className: "video",
|
|
2031
2054
|
onClick: () => {
|
|
@@ -2042,7 +2065,7 @@ ${X}
|
|
|
2042
2065
|
})
|
|
2043
2066
|
]
|
|
2044
2067
|
});
|
|
2045
|
-
},
|
|
2068
|
+
}, at = ({ options: e, children: t }) => {
|
|
2046
2069
|
let n = "media" in e ? e : null, r = n ? null : e, { title: i } = e, { size: a, downloadedRanges: o, publicPath: s, libavWorkerUrl: c, read: l, thumbnailRead: u, thumbnailsEnabled: f } = r ?? {}, p = y(), h = v(), [g, _] = m(null), [b, x] = m(null), S = n?.media ?? g;
|
|
2047
2070
|
d(() => (p?.(S), () => p?.(null)), [S, p]), pe(g, b, r);
|
|
2048
2071
|
let w = z({
|
|
@@ -2103,7 +2126,7 @@ ${X}
|
|
|
2103
2126
|
selectedAudioTrack: M.selectedId ?? void 0,
|
|
2104
2127
|
selectAudioTrack: (e) => M.select(String(e))
|
|
2105
2128
|
});
|
|
2106
|
-
}, [k, M]), /* @__PURE__ */ C(
|
|
2129
|
+
}, [k, M]), /* @__PURE__ */ C(it, {
|
|
2107
2130
|
ref: h,
|
|
2108
2131
|
onVideoRef: n ? void 0 : _,
|
|
2109
2132
|
onCanvasRef: x,
|
|
@@ -2111,7 +2134,7 @@ ${X}
|
|
|
2111
2134
|
controls: e.controls,
|
|
2112
2135
|
children: t
|
|
2113
2136
|
});
|
|
2114
|
-
},
|
|
2137
|
+
}, ot = h`
|
|
2115
2138
|
/**
|
|
2116
2139
|
* The chrome's whole scale, in one place.
|
|
2117
2140
|
*
|
|
@@ -2181,17 +2204,17 @@ ${X}
|
|
|
2181
2204
|
height: 100%;
|
|
2182
2205
|
width: 100%;
|
|
2183
2206
|
overflow: hidden;
|
|
2184
|
-
`,
|
|
2185
|
-
css:
|
|
2186
|
-
children: /* @__PURE__ */ C(I.Provider, { children: /* @__PURE__ */ C(
|
|
2207
|
+
`, st = (e) => /* @__PURE__ */ C("div", {
|
|
2208
|
+
css: ot,
|
|
2209
|
+
children: /* @__PURE__ */ C(I.Provider, { children: /* @__PURE__ */ C(at, {
|
|
2187
2210
|
options: e,
|
|
2188
2211
|
children: e.children
|
|
2189
2212
|
}) })
|
|
2190
|
-
}),
|
|
2213
|
+
}), ct = (e) => !!e && typeof e == "object" && "at" in e, lt = (e) => !!e && typeof e == "object" && "selection" in e, ut = ({ blob: e, name: t }) => ({
|
|
2191
2214
|
length: e.size,
|
|
2192
2215
|
name: t ?? (e instanceof File ? e.name : void 0),
|
|
2193
2216
|
read: (t, n) => e.slice(t, t + n).arrayBuffer()
|
|
2194
|
-
}),
|
|
2217
|
+
}), dt = async (e, t) => {
|
|
2195
2218
|
let n = await fetch(e, {
|
|
2196
2219
|
headers: { Range: "bytes=0-1" },
|
|
2197
2220
|
credentials: t
|
|
@@ -2201,8 +2224,8 @@ ${X}
|
|
|
2201
2224
|
if (!Number.isFinite(i) || i <= 0) throw Error("The source did not report its length");
|
|
2202
2225
|
if (!r && n.status !== 206) throw Error("The source does not support range requests");
|
|
2203
2226
|
return i;
|
|
2204
|
-
},
|
|
2205
|
-
let i = t ?? await
|
|
2227
|
+
}, ft = async ({ url: e, length: t, name: n, credentials: r }) => {
|
|
2228
|
+
let i = t ?? await dt(e, r);
|
|
2206
2229
|
return {
|
|
2207
2230
|
length: i,
|
|
2208
2231
|
name: n,
|
|
@@ -2215,9 +2238,9 @@ ${X}
|
|
|
2215
2238
|
return a.arrayBuffer();
|
|
2216
2239
|
}
|
|
2217
2240
|
};
|
|
2218
|
-
},
|
|
2219
|
-
if ("blob" in e) return
|
|
2220
|
-
if ("url" in e) return
|
|
2241
|
+
}, pt = async (e) => {
|
|
2242
|
+
if ("blob" in e) return ut(e);
|
|
2243
|
+
if ("url" in e) return ft(e);
|
|
2221
2244
|
if ("read" in e) return {
|
|
2222
2245
|
length: e.length,
|
|
2223
2246
|
name: e.name,
|
|
@@ -2226,4 +2249,4 @@ ${X}
|
|
|
2226
2249
|
throw Error(`Unknown source type: ${e}`);
|
|
2227
2250
|
};
|
|
2228
2251
|
//#endregion
|
|
2229
|
-
export {
|
|
2252
|
+
export { st as MediaPlayer, st as default, I as Player, e as SUBTITLES_OFF, a as createPictureInPicture, o as createSubtitleRenderer, r as createThumbnailGenerator, pt as inputToRemuxerInput, lt as isDelegatedTracks, ct as isExternalThumbnails, F as sourceFeature, i as startPlayback, B as usePictureInPicture, L as usePlayer, z as useSeekThumbnails };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { PlaybackErrorEntry } from '../source-feature';
|
|
2
|
+
/** How many failures there have been, which is not how many rows: a repeat folds into its row. */
|
|
3
|
+
export declare const countErrors: (errors: PlaybackErrorEntry[]) => number;
|
|
2
4
|
/** What lands on the clipboard: the same thing the panel shows, in the order it happened. */
|
|
3
5
|
export declare const formatErrors: (errors: PlaybackErrorEntry[]) => string;
|
|
4
6
|
/**
|
|
@@ -26,9 +26,20 @@ export type TrackChoice = {
|
|
|
26
26
|
* `cause` may be a `MediaError` that reads differently once the element has moved on.
|
|
27
27
|
*/
|
|
28
28
|
export type PlaybackErrorEntry = {
|
|
29
|
-
/** Wall clock, so the report can be read next to a console log
|
|
29
|
+
/** Wall clock of the FIRST of them, so the report can be read next to a console log. */
|
|
30
30
|
at: number;
|
|
31
|
-
/**
|
|
31
|
+
/** Wall clock of the most recent one. Equal to `at` until a repeat has folded into this row. */
|
|
32
|
+
lastAt: number;
|
|
33
|
+
/**
|
|
34
|
+
* How many times in a row this exact failure happened.
|
|
35
|
+
*
|
|
36
|
+
* A source that stays broken reports the same sentence every few seconds for as long as it stays
|
|
37
|
+
* broken, so consecutive identical failures fold into one row rather than filling the panel with a
|
|
38
|
+
* wall of one message. This is also what keeps the list from growing without end in that case,
|
|
39
|
+
* since there is no ceiling on how many failures are kept.
|
|
40
|
+
*/
|
|
41
|
+
count: number;
|
|
42
|
+
/** Seconds into the media, at the first of them, which is usually the first question asked. */
|
|
32
43
|
atMediaTime?: number;
|
|
33
44
|
message: string;
|
|
34
45
|
/** The `cause` chain, already unwound, one line per level. */
|
package/package.json
CHANGED
|
@@ -77,6 +77,12 @@ ${popoverStyle}
|
|
|
77
77
|
.when {
|
|
78
78
|
color: #bbb;
|
|
79
79
|
${fonts.bSmall.regular}
|
|
80
|
+
|
|
81
|
+
/* the one part of the line worth scanning for, so it is the one part at full brightness */
|
|
82
|
+
.count {
|
|
83
|
+
margin-left: 6px;
|
|
84
|
+
color: #fff;
|
|
85
|
+
}
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
.what {
|
|
@@ -101,12 +107,21 @@ const clock = (at: number) => new Date(at).toLocaleTimeString()
|
|
|
101
107
|
const mediaTime = (seconds: number | undefined) =>
|
|
102
108
|
seconds === undefined || !Number.isFinite(seconds) ? undefined : formatTime(Math.max(0, seconds))
|
|
103
109
|
|
|
110
|
+
/** How many failures there have been, which is not how many rows: a repeat folds into its row. */
|
|
111
|
+
export const countErrors = (errors: PlaybackErrorEntry[]) =>
|
|
112
|
+
errors.reduce((total, entry) => total + entry.count, 0)
|
|
113
|
+
|
|
104
114
|
/** What lands on the clipboard: the same thing the panel shows, in the order it happened. */
|
|
105
115
|
export const formatErrors = (errors: PlaybackErrorEntry[]) =>
|
|
106
116
|
errors
|
|
107
117
|
.map((entry, index) => {
|
|
108
118
|
const at = mediaTime(entry.atMediaTime)
|
|
109
|
-
|
|
119
|
+
// A repeat carries the span it covers, so "40 times over two minutes" and "40 times in one
|
|
120
|
+
// second" are distinguishable in a report. Both happen, and they are different faults.
|
|
121
|
+
const when = entry.count > 1
|
|
122
|
+
? `${new Date(entry.at).toISOString()} to ${new Date(entry.lastAt).toISOString()} ×${entry.count}`
|
|
123
|
+
: new Date(entry.at).toISOString()
|
|
124
|
+
const head = `${index + 1}. ${when}${at ? ` (at ${at})` : ''}${entry.recovered ? ' [recovered]' : ''}`
|
|
110
125
|
return [head, entry.message, entry.detail].filter(Boolean).join('\n')
|
|
111
126
|
})
|
|
112
127
|
.join('\n\n')
|
|
@@ -142,7 +157,8 @@ export const ErrorsAction = () => {
|
|
|
142
157
|
)
|
|
143
158
|
}
|
|
144
159
|
|
|
145
|
-
|
|
160
|
+
// counted in failures rather than in rows, because a row that says ×40 is forty of them
|
|
161
|
+
const label = `Playback errors (${countErrors(errors)})`
|
|
146
162
|
|
|
147
163
|
return (
|
|
148
164
|
<div css={style} ref={containerRef}>
|
|
@@ -177,8 +193,11 @@ export const ErrorsAction = () => {
|
|
|
177
193
|
<div className='entry no-hover' key={`${entry.at}-${index}`}>
|
|
178
194
|
<span className='when'>
|
|
179
195
|
{clock(entry.at)}
|
|
196
|
+
{/* the span, so a row that is still growing is distinguishable from one that stopped */}
|
|
197
|
+
{entry.count > 1 ? ` to ${clock(entry.lastAt)}` : ''}
|
|
180
198
|
{mediaTime(entry.atMediaTime) ? ` at ${mediaTime(entry.atMediaTime)}` : ''}
|
|
181
199
|
{entry.recovered ? ' recovered' : ''}
|
|
200
|
+
{entry.count > 1 ? <span className='count'>{`×${entry.count}`}</span> : null}
|
|
182
201
|
</span>
|
|
183
202
|
<span className='what'>{entry.message}</span>
|
|
184
203
|
{entry.detail ? <span className='cause'>{entry.detail}</span> : null}
|
|
@@ -158,14 +158,33 @@ export const usePlayback = (
|
|
|
158
158
|
* `playbackError` null and would otherwise erase the only evidence that anything went wrong.
|
|
159
159
|
*/
|
|
160
160
|
const record = (error: unknown, recovered: boolean) => {
|
|
161
|
+
const at = Date.now()
|
|
162
|
+
const message = messageOf(error)
|
|
163
|
+
const detail = causeChain(error)
|
|
164
|
+
const errors = player.playbackErrors
|
|
165
|
+
const last = errors[errors.length - 1]
|
|
166
|
+
|
|
167
|
+
// A source that stays broken repeats one sentence for as long as it stays broken, so a
|
|
168
|
+
// consecutive repeat folds into the row it repeats rather than adding another. Only
|
|
169
|
+
// CONSECUTIVE ones: an identical failure either side of a different one is a second episode,
|
|
170
|
+
// and collapsing the two would lose the order that makes a report readable.
|
|
171
|
+
if (last && last.message === message && last.detail === detail && last.recovered === recovered) {
|
|
172
|
+
const folded: PlaybackErrorEntry = { ...last, count: last.count + 1, lastAt: at }
|
|
173
|
+
player.setSourceState({ playbackErrors: [...errors.slice(0, -1), folded] })
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
|
|
161
177
|
const entry: PlaybackErrorEntry = {
|
|
162
|
-
at
|
|
178
|
+
at,
|
|
179
|
+
lastAt: at,
|
|
180
|
+
count: 1,
|
|
181
|
+
// where it STARTED, kept as the row grows, because that is the position worth reporting
|
|
163
182
|
atMediaTime: Number.isFinite(video.currentTime) ? video.currentTime : undefined,
|
|
164
|
-
message
|
|
165
|
-
detail
|
|
183
|
+
message,
|
|
184
|
+
detail,
|
|
166
185
|
recovered,
|
|
167
186
|
}
|
|
168
|
-
player.setSourceState({ playbackErrors: [...
|
|
187
|
+
player.setSourceState({ playbackErrors: [...errors, entry] })
|
|
169
188
|
}
|
|
170
189
|
const fail = (error: unknown) => {
|
|
171
190
|
if (cancelled) return
|
|
@@ -30,9 +30,20 @@ export type TrackChoice = {
|
|
|
30
30
|
* `cause` may be a `MediaError` that reads differently once the element has moved on.
|
|
31
31
|
*/
|
|
32
32
|
export type PlaybackErrorEntry = {
|
|
33
|
-
/** Wall clock, so the report can be read next to a console log
|
|
33
|
+
/** Wall clock of the FIRST of them, so the report can be read next to a console log. */
|
|
34
34
|
at: number
|
|
35
|
-
/**
|
|
35
|
+
/** Wall clock of the most recent one. Equal to `at` until a repeat has folded into this row. */
|
|
36
|
+
lastAt: number
|
|
37
|
+
/**
|
|
38
|
+
* How many times in a row this exact failure happened.
|
|
39
|
+
*
|
|
40
|
+
* A source that stays broken reports the same sentence every few seconds for as long as it stays
|
|
41
|
+
* broken, so consecutive identical failures fold into one row rather than filling the panel with a
|
|
42
|
+
* wall of one message. This is also what keeps the list from growing without end in that case,
|
|
43
|
+
* since there is no ceiling on how many failures are kept.
|
|
44
|
+
*/
|
|
45
|
+
count: number
|
|
46
|
+
/** Seconds into the media, at the first of them, which is usually the first question asked. */
|
|
36
47
|
atMediaTime?: number
|
|
37
48
|
message: string
|
|
38
49
|
/** The `cause` chain, already unwound, one line per level. */
|