ts-video-player 0.1.6 → 0.1.8
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/cdn.min.js +70 -50
- package/dist/{chunk-fvz33zn4.js → chunk-hvjcmbfn.js} +765 -114
- package/dist/core/i18n.d.ts +24 -0
- package/dist/elements/index.js +2 -2
- package/dist/elements/utils.d.ts +16 -2
- package/dist/index.js +28 -419
- package/dist/player.d.ts +12 -0
- package/dist/providers/vimeo.d.ts +6 -0
- package/dist/providers/youtube.d.ts +6 -0
- package/package.json +1 -1
- package/src/core/i18n.ts +173 -1
- package/src/elements/media-airplay-button.ts +2 -2
- package/src/elements/media-fullscreen-button.ts +3 -3
- package/src/elements/media-live-button.ts +2 -2
- package/src/elements/media-mute-button.ts +3 -3
- package/src/elements/media-pip-button.ts +3 -2
- package/src/elements/media-play-button.ts +3 -3
- package/src/elements/media-playback-rate-button.ts +3 -3
- package/src/elements/media-progress-bar.ts +3 -3
- package/src/elements/media-remote-playback-button.ts +2 -2
- package/src/elements/media-seek-button.ts +2 -3
- package/src/elements/media-settings-menu.ts +14 -14
- package/src/elements/media-time-display.ts +2 -2
- package/src/elements/media-volume-slider.ts +2 -2
- package/src/elements/utils.ts +40 -6
- package/src/elements/video-skin.ts +21 -1
- package/src/player.ts +76 -18
- package/src/providers/vimeo.ts +15 -3
- package/src/providers/youtube.ts +27 -5
|
@@ -625,6 +625,7 @@ class YouTubeProvider2 extends BaseProvider2 {
|
|
|
625
625
|
endTime;
|
|
626
626
|
timeUpdateInterval = null;
|
|
627
627
|
lastState = -1;
|
|
628
|
+
pendingPlay = false;
|
|
628
629
|
get mediaElement() {
|
|
629
630
|
return this.iframe;
|
|
630
631
|
}
|
|
@@ -702,6 +703,7 @@ class YouTubeProvider2 extends BaseProvider2 {
|
|
|
702
703
|
this.player?.destroy();
|
|
703
704
|
this.player = null;
|
|
704
705
|
this.playerReady = false;
|
|
706
|
+
this.pendingPlay = false;
|
|
705
707
|
this.iframe = null;
|
|
706
708
|
}
|
|
707
709
|
onReady() {
|
|
@@ -714,8 +716,12 @@ class YouTubeProvider2 extends BaseProvider2 {
|
|
|
714
716
|
this.events.emit("loadedmetadata");
|
|
715
717
|
this.events.emit("canplay");
|
|
716
718
|
if (this.pendingVideoId) {
|
|
717
|
-
|
|
719
|
+
const videoId = this.pendingVideoId;
|
|
718
720
|
this.pendingVideoId = null;
|
|
721
|
+
this.loadVideo(videoId, this.startTime, this.endTime);
|
|
722
|
+
} else if (this.pendingPlay) {
|
|
723
|
+
this.pendingPlay = false;
|
|
724
|
+
this.player?.playVideo();
|
|
719
725
|
}
|
|
720
726
|
}
|
|
721
727
|
onStateChange(event) {
|
|
@@ -727,6 +733,8 @@ class YouTubeProvider2 extends BaseProvider2 {
|
|
|
727
733
|
this.events.emit("loadstart");
|
|
728
734
|
break;
|
|
729
735
|
case PlayerState.PLAYING:
|
|
736
|
+
if (this.getDuration() > 0)
|
|
737
|
+
this.events.emit("durationchange", this.getDuration());
|
|
730
738
|
this.events.emit("play");
|
|
731
739
|
this.events.emit("playing");
|
|
732
740
|
this.events.emit("statechange", { paused: false, playing: true, waiting: false });
|
|
@@ -787,7 +795,8 @@ class YouTubeProvider2 extends BaseProvider2 {
|
|
|
787
795
|
loadVideo(videoId, startTime, endTime) {
|
|
788
796
|
if (!this.player)
|
|
789
797
|
return;
|
|
790
|
-
if (this.options.autoplay) {
|
|
798
|
+
if (this.options.autoplay || this.pendingPlay) {
|
|
799
|
+
this.pendingPlay = false;
|
|
791
800
|
this.player.loadVideoById({
|
|
792
801
|
videoId,
|
|
793
802
|
startSeconds: startTime,
|
|
@@ -802,13 +811,21 @@ class YouTubeProvider2 extends BaseProvider2 {
|
|
|
802
811
|
}
|
|
803
812
|
}
|
|
804
813
|
async play() {
|
|
805
|
-
this.player
|
|
814
|
+
if (!this.player || !this.playerReady || this.pendingVideoId) {
|
|
815
|
+
this.pendingPlay = true;
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
this.player.playVideo();
|
|
806
819
|
}
|
|
807
820
|
pause() {
|
|
808
|
-
this.
|
|
821
|
+
this.pendingPlay = false;
|
|
822
|
+
if (this.playerReady)
|
|
823
|
+
this.player?.pauseVideo();
|
|
809
824
|
}
|
|
810
825
|
stop() {
|
|
811
|
-
this.
|
|
826
|
+
this.pendingPlay = false;
|
|
827
|
+
if (this.playerReady)
|
|
828
|
+
this.player?.stopVideo();
|
|
812
829
|
}
|
|
813
830
|
seekTo(time) {
|
|
814
831
|
this.player?.seekTo(time, true);
|
|
@@ -1009,8 +1026,9 @@ class VimeoProvider2 extends BaseProvider2 {
|
|
|
1009
1026
|
return;
|
|
1010
1027
|
}
|
|
1011
1028
|
if (this.player) {
|
|
1012
|
-
await this.player.
|
|
1013
|
-
this.
|
|
1029
|
+
await this.player.loadVideo(parseInt(parsed.videoId, 10));
|
|
1030
|
+
await this.announceLoaded();
|
|
1031
|
+
return;
|
|
1014
1032
|
}
|
|
1015
1033
|
const playerOptions = {
|
|
1016
1034
|
id: parseInt(parsed.videoId, 10),
|
|
@@ -1034,6 +1052,11 @@ class VimeoProvider2 extends BaseProvider2 {
|
|
|
1034
1052
|
this.iframe.style.cssText = "position:absolute;inset:0;width:100%;height:100%;border:0";
|
|
1035
1053
|
}
|
|
1036
1054
|
this.attachVimeoEvents();
|
|
1055
|
+
await this.announceLoaded();
|
|
1056
|
+
}
|
|
1057
|
+
async announceLoaded() {
|
|
1058
|
+
if (!this.player)
|
|
1059
|
+
return;
|
|
1037
1060
|
this.events.emit("loadedmetadata");
|
|
1038
1061
|
this.events.emit("canplay");
|
|
1039
1062
|
this._duration = await this.player.getDuration();
|
|
@@ -2025,6 +2048,630 @@ function embedCover(state, dismissed) {
|
|
|
2025
2048
|
return { show: true, image: youtubeId ? `https://i.ytimg.com/vi/${youtubeId}/hqdefault.jpg` : "" };
|
|
2026
2049
|
}
|
|
2027
2050
|
|
|
2051
|
+
// src/core/i18n.ts
|
|
2052
|
+
var englishStrings2 = {
|
|
2053
|
+
play: "Play",
|
|
2054
|
+
pause: "Pause",
|
|
2055
|
+
replay: "Replay",
|
|
2056
|
+
mute: "Mute",
|
|
2057
|
+
unmute: "Unmute",
|
|
2058
|
+
volume: "Volume",
|
|
2059
|
+
seekBackward: "Seek backward {seconds} seconds",
|
|
2060
|
+
seekForward: "Seek forward {seconds} seconds",
|
|
2061
|
+
seekTo: "Seek to {time}",
|
|
2062
|
+
duration: "Duration",
|
|
2063
|
+
currentTime: "Current time",
|
|
2064
|
+
played: "Played",
|
|
2065
|
+
buffered: "Buffered",
|
|
2066
|
+
enterFullscreen: "Enter fullscreen",
|
|
2067
|
+
exitFullscreen: "Exit fullscreen",
|
|
2068
|
+
enterPiP: "Enter picture-in-picture",
|
|
2069
|
+
exitPiP: "Exit picture-in-picture",
|
|
2070
|
+
enableCaptions: "Enable captions",
|
|
2071
|
+
disableCaptions: "Disable captions",
|
|
2072
|
+
captions: "Captions",
|
|
2073
|
+
captionsOff: "Off",
|
|
2074
|
+
settings: "Settings",
|
|
2075
|
+
quality: "Quality",
|
|
2076
|
+
auto: "Auto",
|
|
2077
|
+
speed: "Speed",
|
|
2078
|
+
normal: "Normal",
|
|
2079
|
+
loop: "Loop",
|
|
2080
|
+
loopEnabled: "Loop enabled",
|
|
2081
|
+
loopDisabled: "Loop disabled",
|
|
2082
|
+
audioBoost: "Audio boost",
|
|
2083
|
+
audioTrack: "Audio track",
|
|
2084
|
+
live: "LIVE",
|
|
2085
|
+
liveEdge: "At live edge",
|
|
2086
|
+
seekToLive: "Seek to live edge",
|
|
2087
|
+
behindLive: "{seconds}s behind",
|
|
2088
|
+
networkError: "A network error occurred",
|
|
2089
|
+
mediaError: "The media could not be loaded",
|
|
2090
|
+
unknownError: "An unknown error occurred",
|
|
2091
|
+
loading: "Loading",
|
|
2092
|
+
buffering: "Buffering",
|
|
2093
|
+
chapters: "Chapters",
|
|
2094
|
+
airPlay: "AirPlay",
|
|
2095
|
+
googleCast: "Cast",
|
|
2096
|
+
casting: "Casting to {device}",
|
|
2097
|
+
download: "Download",
|
|
2098
|
+
share: "Share",
|
|
2099
|
+
close: "Close",
|
|
2100
|
+
menu: "Menu",
|
|
2101
|
+
back: "Back",
|
|
2102
|
+
seek: "Seek",
|
|
2103
|
+
playbackRate: "Playback speed {rate}x",
|
|
2104
|
+
airPlayPlay: "Play on AirPlay",
|
|
2105
|
+
remotePlayback: "Play on another device",
|
|
2106
|
+
videoPlayer: "Video player",
|
|
2107
|
+
videoRole: "video player",
|
|
2108
|
+
playTitle: "Play {title}",
|
|
2109
|
+
audio: "Audio",
|
|
2110
|
+
defaultTrack: "Default",
|
|
2111
|
+
playing: "Playing",
|
|
2112
|
+
paused: "Paused",
|
|
2113
|
+
muted: "Muted",
|
|
2114
|
+
volumeLevel: "Volume {percent}%",
|
|
2115
|
+
ended: "Playback ended",
|
|
2116
|
+
enteredFullscreen: "Entered fullscreen",
|
|
2117
|
+
exitedFullscreen: "Exited fullscreen",
|
|
2118
|
+
errorMessage: "Error: {message}",
|
|
2119
|
+
timeOf: "{current} of {duration}",
|
|
2120
|
+
hourOne: "{n} hour",
|
|
2121
|
+
hourOther: "{n} hours",
|
|
2122
|
+
minuteOne: "{n} minute",
|
|
2123
|
+
minuteOther: "{n} minutes",
|
|
2124
|
+
secondOne: "{n} second",
|
|
2125
|
+
secondOther: "{n} seconds"
|
|
2126
|
+
};
|
|
2127
|
+
var spanishStrings2 = {
|
|
2128
|
+
play: "Reproducir",
|
|
2129
|
+
pause: "Pausar",
|
|
2130
|
+
replay: "Repetir",
|
|
2131
|
+
mute: "Silenciar",
|
|
2132
|
+
unmute: "Activar sonido",
|
|
2133
|
+
volume: "Volumen",
|
|
2134
|
+
seekBackward: "Retroceder {seconds} segundos",
|
|
2135
|
+
seekForward: "Avanzar {seconds} segundos",
|
|
2136
|
+
seekTo: "Ir a {time}",
|
|
2137
|
+
duration: "Duración",
|
|
2138
|
+
currentTime: "Tiempo actual",
|
|
2139
|
+
played: "Reproducido",
|
|
2140
|
+
buffered: "Almacenado",
|
|
2141
|
+
enterFullscreen: "Pantalla completa",
|
|
2142
|
+
exitFullscreen: "Salir de pantalla completa",
|
|
2143
|
+
enterPiP: "Imagen en imagen",
|
|
2144
|
+
exitPiP: "Salir de imagen en imagen",
|
|
2145
|
+
enableCaptions: "Activar subtítulos",
|
|
2146
|
+
disableCaptions: "Desactivar subtítulos",
|
|
2147
|
+
captions: "Subtítulos",
|
|
2148
|
+
captionsOff: "Desactivados",
|
|
2149
|
+
settings: "Ajustes",
|
|
2150
|
+
quality: "Calidad",
|
|
2151
|
+
auto: "Automático",
|
|
2152
|
+
speed: "Velocidad",
|
|
2153
|
+
normal: "Normal",
|
|
2154
|
+
loop: "Bucle",
|
|
2155
|
+
loopEnabled: "Bucle activado",
|
|
2156
|
+
loopDisabled: "Bucle desactivado",
|
|
2157
|
+
audioBoost: "Aumento de audio",
|
|
2158
|
+
audioTrack: "Pista de audio",
|
|
2159
|
+
live: "EN VIVO",
|
|
2160
|
+
liveEdge: "En vivo",
|
|
2161
|
+
seekToLive: "Ir al directo",
|
|
2162
|
+
behindLive: "{seconds}s de retraso",
|
|
2163
|
+
networkError: "Error de red",
|
|
2164
|
+
mediaError: "No se pudo cargar el medio",
|
|
2165
|
+
unknownError: "Error desconocido",
|
|
2166
|
+
loading: "Cargando",
|
|
2167
|
+
buffering: "Almacenando",
|
|
2168
|
+
chapters: "Capítulos",
|
|
2169
|
+
airPlay: "AirPlay",
|
|
2170
|
+
googleCast: "Enviar",
|
|
2171
|
+
casting: "Enviando a {device}",
|
|
2172
|
+
download: "Descargar",
|
|
2173
|
+
share: "Compartir",
|
|
2174
|
+
close: "Cerrar",
|
|
2175
|
+
menu: "Menú",
|
|
2176
|
+
back: "Volver",
|
|
2177
|
+
seek: "Buscar",
|
|
2178
|
+
playbackRate: "Velocidad de reproducción {rate}x",
|
|
2179
|
+
airPlayPlay: "Reproducir con AirPlay",
|
|
2180
|
+
remotePlayback: "Reproducir en otro dispositivo",
|
|
2181
|
+
videoPlayer: "Reproductor de vídeo",
|
|
2182
|
+
videoRole: "reproductor de vídeo",
|
|
2183
|
+
playTitle: "Reproducir {title}",
|
|
2184
|
+
audio: "Audio",
|
|
2185
|
+
defaultTrack: "Predeterminado",
|
|
2186
|
+
playing: "Reproduciendo",
|
|
2187
|
+
paused: "En pausa",
|
|
2188
|
+
muted: "Silenciado",
|
|
2189
|
+
volumeLevel: "Volumen {percent}%",
|
|
2190
|
+
ended: "Reproducción finalizada",
|
|
2191
|
+
enteredFullscreen: "Pantalla completa activada",
|
|
2192
|
+
exitedFullscreen: "Pantalla completa desactivada",
|
|
2193
|
+
errorMessage: "Error: {message}",
|
|
2194
|
+
timeOf: "{current} de {duration}",
|
|
2195
|
+
hourOne: "{n} hora",
|
|
2196
|
+
hourOther: "{n} horas",
|
|
2197
|
+
minuteOne: "{n} minuto",
|
|
2198
|
+
minuteOther: "{n} minutos",
|
|
2199
|
+
secondOne: "{n} segundo",
|
|
2200
|
+
secondOther: "{n} segundos"
|
|
2201
|
+
};
|
|
2202
|
+
var frenchStrings2 = {
|
|
2203
|
+
play: "Lecture",
|
|
2204
|
+
pause: "Pause",
|
|
2205
|
+
replay: "Relire",
|
|
2206
|
+
mute: "Muet",
|
|
2207
|
+
unmute: "Son activé",
|
|
2208
|
+
volume: "Volume",
|
|
2209
|
+
seekBackward: "Reculer de {seconds} secondes",
|
|
2210
|
+
seekForward: "Avancer de {seconds} secondes",
|
|
2211
|
+
seekTo: "Aller à {time}",
|
|
2212
|
+
duration: "Durée",
|
|
2213
|
+
currentTime: "Temps actuel",
|
|
2214
|
+
played: "Joué",
|
|
2215
|
+
buffered: "Mis en mémoire tampon",
|
|
2216
|
+
enterFullscreen: "Plein écran",
|
|
2217
|
+
exitFullscreen: "Quitter le plein écran",
|
|
2218
|
+
enterPiP: "Image dans l'image",
|
|
2219
|
+
exitPiP: "Quitter l'image dans l'image",
|
|
2220
|
+
enableCaptions: "Activer les sous-titres",
|
|
2221
|
+
disableCaptions: "Désactiver les sous-titres",
|
|
2222
|
+
captions: "Sous-titres",
|
|
2223
|
+
captionsOff: "Désactivés",
|
|
2224
|
+
settings: "Paramètres",
|
|
2225
|
+
quality: "Qualité",
|
|
2226
|
+
auto: "Auto",
|
|
2227
|
+
speed: "Vitesse",
|
|
2228
|
+
normal: "Normal",
|
|
2229
|
+
loop: "Boucle",
|
|
2230
|
+
loopEnabled: "Boucle activée",
|
|
2231
|
+
loopDisabled: "Boucle désactivée",
|
|
2232
|
+
audioBoost: "Amplification audio",
|
|
2233
|
+
audioTrack: "Piste audio",
|
|
2234
|
+
live: "EN DIRECT",
|
|
2235
|
+
liveEdge: "En direct",
|
|
2236
|
+
seekToLive: "Aller au direct",
|
|
2237
|
+
behindLive: "{seconds}s de retard",
|
|
2238
|
+
networkError: "Erreur réseau",
|
|
2239
|
+
mediaError: "Le média n'a pas pu être chargé",
|
|
2240
|
+
unknownError: "Erreur inconnue",
|
|
2241
|
+
loading: "Chargement",
|
|
2242
|
+
buffering: "Mise en mémoire tampon",
|
|
2243
|
+
chapters: "Chapitres",
|
|
2244
|
+
airPlay: "AirPlay",
|
|
2245
|
+
googleCast: "Caster",
|
|
2246
|
+
casting: "Diffusion sur {device}",
|
|
2247
|
+
download: "Télécharger",
|
|
2248
|
+
share: "Partager",
|
|
2249
|
+
close: "Fermer",
|
|
2250
|
+
menu: "Menu",
|
|
2251
|
+
back: "Retour",
|
|
2252
|
+
seek: "Rechercher",
|
|
2253
|
+
playbackRate: "Vitesse de lecture {rate}x",
|
|
2254
|
+
airPlayPlay: "Lire avec AirPlay",
|
|
2255
|
+
remotePlayback: "Lire sur un autre appareil",
|
|
2256
|
+
videoPlayer: "Lecteur vidéo",
|
|
2257
|
+
videoRole: "lecteur vidéo",
|
|
2258
|
+
playTitle: "Lire {title}",
|
|
2259
|
+
audio: "Audio",
|
|
2260
|
+
defaultTrack: "Par défaut",
|
|
2261
|
+
playing: "Lecture",
|
|
2262
|
+
paused: "En pause",
|
|
2263
|
+
muted: "Son coupé",
|
|
2264
|
+
volumeLevel: "Volume {percent} %",
|
|
2265
|
+
ended: "Lecture terminée",
|
|
2266
|
+
enteredFullscreen: "Plein écran activé",
|
|
2267
|
+
exitedFullscreen: "Plein écran désactivé",
|
|
2268
|
+
errorMessage: "Erreur : {message}",
|
|
2269
|
+
timeOf: "{current} sur {duration}",
|
|
2270
|
+
hourOne: "{n} heure",
|
|
2271
|
+
hourOther: "{n} heures",
|
|
2272
|
+
minuteOne: "{n} minute",
|
|
2273
|
+
minuteOther: "{n} minutes",
|
|
2274
|
+
secondOne: "{n} seconde",
|
|
2275
|
+
secondOther: "{n} secondes"
|
|
2276
|
+
};
|
|
2277
|
+
var germanStrings2 = {
|
|
2278
|
+
play: "Abspielen",
|
|
2279
|
+
pause: "Pause",
|
|
2280
|
+
replay: "Wiederholen",
|
|
2281
|
+
mute: "Stumm",
|
|
2282
|
+
unmute: "Ton an",
|
|
2283
|
+
volume: "Lautstärke",
|
|
2284
|
+
seekBackward: "{seconds} Sekunden zurück",
|
|
2285
|
+
seekForward: "{seconds} Sekunden vor",
|
|
2286
|
+
seekTo: "Zu {time} springen",
|
|
2287
|
+
duration: "Dauer",
|
|
2288
|
+
currentTime: "Aktuelle Zeit",
|
|
2289
|
+
played: "Abgespielt",
|
|
2290
|
+
buffered: "Gepuffert",
|
|
2291
|
+
enterFullscreen: "Vollbild",
|
|
2292
|
+
exitFullscreen: "Vollbild beenden",
|
|
2293
|
+
enterPiP: "Bild-in-Bild",
|
|
2294
|
+
exitPiP: "Bild-in-Bild beenden",
|
|
2295
|
+
enableCaptions: "Untertitel aktivieren",
|
|
2296
|
+
disableCaptions: "Untertitel deaktivieren",
|
|
2297
|
+
captions: "Untertitel",
|
|
2298
|
+
captionsOff: "Aus",
|
|
2299
|
+
settings: "Einstellungen",
|
|
2300
|
+
quality: "Qualität",
|
|
2301
|
+
auto: "Auto",
|
|
2302
|
+
speed: "Geschwindigkeit",
|
|
2303
|
+
normal: "Normal",
|
|
2304
|
+
loop: "Schleife",
|
|
2305
|
+
loopEnabled: "Schleife aktiviert",
|
|
2306
|
+
loopDisabled: "Schleife deaktiviert",
|
|
2307
|
+
audioBoost: "Audio-Verstärkung",
|
|
2308
|
+
audioTrack: "Audiospur",
|
|
2309
|
+
live: "LIVE",
|
|
2310
|
+
liveEdge: "Am Live-Punkt",
|
|
2311
|
+
seekToLive: "Zum Live-Punkt",
|
|
2312
|
+
behindLive: "{seconds}s hinter Live",
|
|
2313
|
+
networkError: "Netzwerkfehler",
|
|
2314
|
+
mediaError: "Medium konnte nicht geladen werden",
|
|
2315
|
+
unknownError: "Unbekannter Fehler",
|
|
2316
|
+
loading: "Wird geladen",
|
|
2317
|
+
buffering: "Puffern",
|
|
2318
|
+
chapters: "Kapitel",
|
|
2319
|
+
airPlay: "AirPlay",
|
|
2320
|
+
googleCast: "Streamen",
|
|
2321
|
+
casting: "Streame zu {device}",
|
|
2322
|
+
download: "Herunterladen",
|
|
2323
|
+
share: "Teilen",
|
|
2324
|
+
close: "Schließen",
|
|
2325
|
+
menu: "Menü",
|
|
2326
|
+
back: "Zurück",
|
|
2327
|
+
seek: "Spulen",
|
|
2328
|
+
playbackRate: "Wiedergabegeschwindigkeit {rate}x",
|
|
2329
|
+
airPlayPlay: "Über AirPlay abspielen",
|
|
2330
|
+
remotePlayback: "Auf einem anderen Gerät abspielen",
|
|
2331
|
+
videoPlayer: "Videoplayer",
|
|
2332
|
+
videoRole: "Videoplayer",
|
|
2333
|
+
playTitle: "{title} abspielen",
|
|
2334
|
+
audio: "Audio",
|
|
2335
|
+
defaultTrack: "Standard",
|
|
2336
|
+
playing: "Wird abgespielt",
|
|
2337
|
+
paused: "Pausiert",
|
|
2338
|
+
muted: "Stumm",
|
|
2339
|
+
volumeLevel: "Lautstärke {percent} %",
|
|
2340
|
+
ended: "Wiedergabe beendet",
|
|
2341
|
+
enteredFullscreen: "Vollbild an",
|
|
2342
|
+
exitedFullscreen: "Vollbild aus",
|
|
2343
|
+
errorMessage: "Fehler: {message}",
|
|
2344
|
+
timeOf: "{current} von {duration}",
|
|
2345
|
+
hourOne: "{n} Stunde",
|
|
2346
|
+
hourOther: "{n} Stunden",
|
|
2347
|
+
minuteOne: "{n} Minute",
|
|
2348
|
+
minuteOther: "{n} Minuten",
|
|
2349
|
+
secondOne: "{n} Sekunde",
|
|
2350
|
+
secondOther: "{n} Sekunden"
|
|
2351
|
+
};
|
|
2352
|
+
var japaneseStrings2 = {
|
|
2353
|
+
play: "再生",
|
|
2354
|
+
pause: "一時停止",
|
|
2355
|
+
replay: "リプレイ",
|
|
2356
|
+
mute: "ミュート",
|
|
2357
|
+
unmute: "ミュート解除",
|
|
2358
|
+
volume: "音量",
|
|
2359
|
+
seekBackward: "{seconds}秒戻る",
|
|
2360
|
+
seekForward: "{seconds}秒進む",
|
|
2361
|
+
seekTo: "{time}にシーク",
|
|
2362
|
+
duration: "長さ",
|
|
2363
|
+
currentTime: "現在の時間",
|
|
2364
|
+
played: "再生済み",
|
|
2365
|
+
buffered: "バッファ済み",
|
|
2366
|
+
enterFullscreen: "フルスクリーン",
|
|
2367
|
+
exitFullscreen: "フルスクリーン終了",
|
|
2368
|
+
enterPiP: "ピクチャーインピクチャー",
|
|
2369
|
+
exitPiP: "ピクチャーインピクチャー終了",
|
|
2370
|
+
enableCaptions: "字幕を有効化",
|
|
2371
|
+
disableCaptions: "字幕を無効化",
|
|
2372
|
+
captions: "字幕",
|
|
2373
|
+
captionsOff: "オフ",
|
|
2374
|
+
settings: "設定",
|
|
2375
|
+
quality: "画質",
|
|
2376
|
+
auto: "自動",
|
|
2377
|
+
speed: "再生速度",
|
|
2378
|
+
normal: "通常",
|
|
2379
|
+
loop: "ループ",
|
|
2380
|
+
loopEnabled: "ループ有効",
|
|
2381
|
+
loopDisabled: "ループ無効",
|
|
2382
|
+
audioBoost: "オーディオブースト",
|
|
2383
|
+
audioTrack: "オーディオトラック",
|
|
2384
|
+
live: "ライブ",
|
|
2385
|
+
liveEdge: "ライブ中",
|
|
2386
|
+
seekToLive: "ライブに移動",
|
|
2387
|
+
behindLive: "{seconds}秒遅れ",
|
|
2388
|
+
networkError: "ネットワークエラー",
|
|
2389
|
+
mediaError: "メディアを読み込めません",
|
|
2390
|
+
unknownError: "不明なエラー",
|
|
2391
|
+
loading: "読み込み中",
|
|
2392
|
+
buffering: "バッファリング",
|
|
2393
|
+
chapters: "チャプター",
|
|
2394
|
+
airPlay: "AirPlay",
|
|
2395
|
+
googleCast: "キャスト",
|
|
2396
|
+
casting: "{device}にキャスト中",
|
|
2397
|
+
download: "ダウンロード",
|
|
2398
|
+
share: "共有",
|
|
2399
|
+
close: "閉じる",
|
|
2400
|
+
menu: "メニュー",
|
|
2401
|
+
back: "戻る",
|
|
2402
|
+
seek: "シーク",
|
|
2403
|
+
playbackRate: "再生速度 {rate}x",
|
|
2404
|
+
airPlayPlay: "AirPlayで再生",
|
|
2405
|
+
remotePlayback: "別のデバイスで再生",
|
|
2406
|
+
videoPlayer: "動画プレーヤー",
|
|
2407
|
+
videoRole: "動画プレーヤー",
|
|
2408
|
+
playTitle: "{title}を再生",
|
|
2409
|
+
audio: "音声",
|
|
2410
|
+
defaultTrack: "デフォルト",
|
|
2411
|
+
playing: "再生中",
|
|
2412
|
+
paused: "一時停止中",
|
|
2413
|
+
muted: "ミュート",
|
|
2414
|
+
volumeLevel: "音量 {percent}%",
|
|
2415
|
+
ended: "再生終了",
|
|
2416
|
+
enteredFullscreen: "全画面表示",
|
|
2417
|
+
exitedFullscreen: "全画面表示を終了",
|
|
2418
|
+
errorMessage: "エラー: {message}",
|
|
2419
|
+
timeOf: "{current} / {duration}",
|
|
2420
|
+
hourOne: "{n}時間",
|
|
2421
|
+
hourOther: "{n}時間",
|
|
2422
|
+
minuteOne: "{n}分",
|
|
2423
|
+
minuteOther: "{n}分",
|
|
2424
|
+
secondOne: "{n}秒",
|
|
2425
|
+
secondOther: "{n}秒"
|
|
2426
|
+
};
|
|
2427
|
+
var chineseStrings2 = {
|
|
2428
|
+
play: "播放",
|
|
2429
|
+
pause: "暂停",
|
|
2430
|
+
replay: "重播",
|
|
2431
|
+
mute: "静音",
|
|
2432
|
+
unmute: "取消静音",
|
|
2433
|
+
volume: "音量",
|
|
2434
|
+
seekBackward: "后退{seconds}秒",
|
|
2435
|
+
seekForward: "前进{seconds}秒",
|
|
2436
|
+
seekTo: "跳转到{time}",
|
|
2437
|
+
duration: "时长",
|
|
2438
|
+
currentTime: "当前时间",
|
|
2439
|
+
played: "已播放",
|
|
2440
|
+
buffered: "已缓冲",
|
|
2441
|
+
enterFullscreen: "全屏",
|
|
2442
|
+
exitFullscreen: "退出全屏",
|
|
2443
|
+
enterPiP: "画中画",
|
|
2444
|
+
exitPiP: "退出画中画",
|
|
2445
|
+
enableCaptions: "开启字幕",
|
|
2446
|
+
disableCaptions: "关闭字幕",
|
|
2447
|
+
captions: "字幕",
|
|
2448
|
+
captionsOff: "关闭",
|
|
2449
|
+
settings: "设置",
|
|
2450
|
+
quality: "画质",
|
|
2451
|
+
auto: "自动",
|
|
2452
|
+
speed: "播放速度",
|
|
2453
|
+
normal: "正常",
|
|
2454
|
+
loop: "循环",
|
|
2455
|
+
loopEnabled: "循环已开启",
|
|
2456
|
+
loopDisabled: "循环已关闭",
|
|
2457
|
+
audioBoost: "音频增强",
|
|
2458
|
+
audioTrack: "音轨",
|
|
2459
|
+
live: "直播",
|
|
2460
|
+
liveEdge: "直播中",
|
|
2461
|
+
seekToLive: "跳转到直播",
|
|
2462
|
+
behindLive: "落后{seconds}秒",
|
|
2463
|
+
networkError: "网络错误",
|
|
2464
|
+
mediaError: "无法加载媒体",
|
|
2465
|
+
unknownError: "未知错误",
|
|
2466
|
+
loading: "加载中",
|
|
2467
|
+
buffering: "缓冲中",
|
|
2468
|
+
chapters: "章节",
|
|
2469
|
+
airPlay: "AirPlay",
|
|
2470
|
+
googleCast: "投射",
|
|
2471
|
+
casting: "正在投射到{device}",
|
|
2472
|
+
download: "下载",
|
|
2473
|
+
share: "分享",
|
|
2474
|
+
close: "关闭",
|
|
2475
|
+
menu: "菜单",
|
|
2476
|
+
back: "返回",
|
|
2477
|
+
seek: "跳转",
|
|
2478
|
+
playbackRate: "播放速度 {rate}x",
|
|
2479
|
+
airPlayPlay: "通过 AirPlay 播放",
|
|
2480
|
+
remotePlayback: "在其他设备上播放",
|
|
2481
|
+
videoPlayer: "视频播放器",
|
|
2482
|
+
videoRole: "视频播放器",
|
|
2483
|
+
playTitle: "播放{title}",
|
|
2484
|
+
audio: "音频",
|
|
2485
|
+
defaultTrack: "默认",
|
|
2486
|
+
playing: "正在播放",
|
|
2487
|
+
paused: "已暂停",
|
|
2488
|
+
muted: "已静音",
|
|
2489
|
+
volumeLevel: "音量 {percent}%",
|
|
2490
|
+
ended: "播放结束",
|
|
2491
|
+
enteredFullscreen: "已进入全屏",
|
|
2492
|
+
exitedFullscreen: "已退出全屏",
|
|
2493
|
+
errorMessage: "错误:{message}",
|
|
2494
|
+
timeOf: "{current} / {duration}",
|
|
2495
|
+
hourOne: "{n}小时",
|
|
2496
|
+
hourOther: "{n}小时",
|
|
2497
|
+
minuteOne: "{n}分钟",
|
|
2498
|
+
minuteOther: "{n}分钟",
|
|
2499
|
+
secondOne: "{n}秒",
|
|
2500
|
+
secondOther: "{n}秒"
|
|
2501
|
+
};
|
|
2502
|
+
var defaultTranslations2 = {
|
|
2503
|
+
en: englishStrings2,
|
|
2504
|
+
es: spanishStrings2,
|
|
2505
|
+
fr: frenchStrings2,
|
|
2506
|
+
de: germanStrings2,
|
|
2507
|
+
ja: japaneseStrings2,
|
|
2508
|
+
zh: chineseStrings2
|
|
2509
|
+
};
|
|
2510
|
+
|
|
2511
|
+
class I18n2 {
|
|
2512
|
+
language;
|
|
2513
|
+
fallbackLanguage;
|
|
2514
|
+
translations;
|
|
2515
|
+
interpolationPattern;
|
|
2516
|
+
constructor(config = {}) {
|
|
2517
|
+
this.translations = { ...defaultTranslations2 };
|
|
2518
|
+
this.language = config.language || this.detectLanguage() || "en";
|
|
2519
|
+
this.fallbackLanguage = config.fallbackLanguage || "en";
|
|
2520
|
+
if (config.translations) {
|
|
2521
|
+
for (const [lang, strings] of Object.entries(config.translations)) {
|
|
2522
|
+
if (strings) {
|
|
2523
|
+
this.translations[lang] = { ...this.translations[lang], ...strings };
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
this.interpolationPattern = config.interpolationPattern || /\{(\w+)\}/g;
|
|
2528
|
+
}
|
|
2529
|
+
detectLanguage() {
|
|
2530
|
+
if (typeof navigator === "undefined")
|
|
2531
|
+
return null;
|
|
2532
|
+
const lang = navigator.language || navigator.userLanguage;
|
|
2533
|
+
if (!lang)
|
|
2534
|
+
return null;
|
|
2535
|
+
if (this.translations[lang]) {
|
|
2536
|
+
return lang;
|
|
2537
|
+
}
|
|
2538
|
+
const baseLang = lang.split("-")[0];
|
|
2539
|
+
if (this.translations[baseLang]) {
|
|
2540
|
+
return baseLang;
|
|
2541
|
+
}
|
|
2542
|
+
return null;
|
|
2543
|
+
}
|
|
2544
|
+
getLanguage() {
|
|
2545
|
+
return this.language;
|
|
2546
|
+
}
|
|
2547
|
+
setLanguage(language) {
|
|
2548
|
+
this.language = language;
|
|
2549
|
+
}
|
|
2550
|
+
t(key, params) {
|
|
2551
|
+
let str = this.translations[this.language]?.[key];
|
|
2552
|
+
if (!str) {
|
|
2553
|
+
str = this.translations[this.fallbackLanguage]?.[key];
|
|
2554
|
+
}
|
|
2555
|
+
if (!str) {
|
|
2556
|
+
return key;
|
|
2557
|
+
}
|
|
2558
|
+
if (params) {
|
|
2559
|
+
str = str.replace(this.interpolationPattern, (match, paramKey) => {
|
|
2560
|
+
const value = params[paramKey];
|
|
2561
|
+
return value !== undefined ? String(value) : match;
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2564
|
+
return str;
|
|
2565
|
+
}
|
|
2566
|
+
addTranslations(language, strings) {
|
|
2567
|
+
this.translations[language] = {
|
|
2568
|
+
...this.translations[language],
|
|
2569
|
+
...strings
|
|
2570
|
+
};
|
|
2571
|
+
}
|
|
2572
|
+
getTranslations(language) {
|
|
2573
|
+
return this.translations[language];
|
|
2574
|
+
}
|
|
2575
|
+
getAvailableLanguages() {
|
|
2576
|
+
return Object.keys(this.translations);
|
|
2577
|
+
}
|
|
2578
|
+
hasLanguage(language) {
|
|
2579
|
+
return language in this.translations;
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
var globalI18n = null;
|
|
2583
|
+
function createI18n2(config) {
|
|
2584
|
+
return new I18n2(config);
|
|
2585
|
+
}
|
|
2586
|
+
function getI18n2(config) {
|
|
2587
|
+
if (!globalI18n) {
|
|
2588
|
+
globalI18n = createI18n2(config);
|
|
2589
|
+
}
|
|
2590
|
+
return globalI18n;
|
|
2591
|
+
}
|
|
2592
|
+
function setI18n2(i18n) {
|
|
2593
|
+
globalI18n = i18n;
|
|
2594
|
+
}
|
|
2595
|
+
function t2(key, params) {
|
|
2596
|
+
return getI18n2().t(key, params);
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2599
|
+
// src/elements/utils.ts
|
|
2600
|
+
function languageOf(el) {
|
|
2601
|
+
let node = el;
|
|
2602
|
+
while (node) {
|
|
2603
|
+
const tagged = node.closest?.("[lang]")?.getAttribute("lang");
|
|
2604
|
+
if (tagged)
|
|
2605
|
+
return tagged.toLowerCase();
|
|
2606
|
+
const root = node.getRootNode?.();
|
|
2607
|
+
node = root && root.host ? root.host : null;
|
|
2608
|
+
}
|
|
2609
|
+
if (typeof navigator !== "undefined" && navigator.language)
|
|
2610
|
+
return navigator.language.toLowerCase();
|
|
2611
|
+
return "en";
|
|
2612
|
+
}
|
|
2613
|
+
function label(el, key, params) {
|
|
2614
|
+
const lang = languageOf(el);
|
|
2615
|
+
const i18n = getI18n2();
|
|
2616
|
+
const text = i18n.getTranslations(lang)?.[key] || i18n.getTranslations(lang.split("-")[0])?.[key] || englishStrings2[key] || key;
|
|
2617
|
+
return params ? text.replace(/\{(\w+)\}/g, (match, name) => params[name] !== undefined ? String(params[name]) : match) : text;
|
|
2618
|
+
}
|
|
2619
|
+
function formatTime2(seconds, guide = 0) {
|
|
2620
|
+
if (!isFinite(seconds) || isNaN(seconds))
|
|
2621
|
+
return "0:00";
|
|
2622
|
+
const s = Math.floor(seconds);
|
|
2623
|
+
const h = Math.floor(s / 3600);
|
|
2624
|
+
const m = Math.floor(s % 3600 / 60);
|
|
2625
|
+
const sec = s % 60;
|
|
2626
|
+
const showHours = h > 0 || guide >= 3600;
|
|
2627
|
+
if (showHours) {
|
|
2628
|
+
return `${h}:${m.toString().padStart(2, "0")}:${sec.toString().padStart(2, "0")}`;
|
|
2629
|
+
}
|
|
2630
|
+
return `${m}:${sec.toString().padStart(2, "0")}`;
|
|
2631
|
+
}
|
|
2632
|
+
function formatTimePhrase2(seconds, el) {
|
|
2633
|
+
const say = (n, one, other) => label(el, n === 1 ? one : other, { n });
|
|
2634
|
+
if (!isFinite(seconds) || isNaN(seconds))
|
|
2635
|
+
return say(0, "secondOne", "secondOther");
|
|
2636
|
+
const s = Math.floor(seconds);
|
|
2637
|
+
const h = Math.floor(s / 3600);
|
|
2638
|
+
const m = Math.floor(s % 3600 / 60);
|
|
2639
|
+
const sec = s % 60;
|
|
2640
|
+
const parts = [];
|
|
2641
|
+
if (h > 0)
|
|
2642
|
+
parts.push(say(h, "hourOne", "hourOther"));
|
|
2643
|
+
if (m > 0)
|
|
2644
|
+
parts.push(say(m, "minuteOne", "minuteOther"));
|
|
2645
|
+
if (sec > 0 || parts.length === 0)
|
|
2646
|
+
parts.push(say(sec, "secondOne", "secondOther"));
|
|
2647
|
+
return parts.join(", ");
|
|
2648
|
+
}
|
|
2649
|
+
function toISODuration2(seconds) {
|
|
2650
|
+
if (!isFinite(seconds) || isNaN(seconds))
|
|
2651
|
+
return "PT0S";
|
|
2652
|
+
const s = Math.floor(seconds);
|
|
2653
|
+
const h = Math.floor(s / 3600);
|
|
2654
|
+
const m = Math.floor(s % 3600 / 60);
|
|
2655
|
+
const sec = s % 60;
|
|
2656
|
+
let result = "PT";
|
|
2657
|
+
if (h > 0)
|
|
2658
|
+
result += `${h}H`;
|
|
2659
|
+
if (m > 0)
|
|
2660
|
+
result += `${m}M`;
|
|
2661
|
+
if (sec > 0 || result === "PT")
|
|
2662
|
+
result += `${sec}S`;
|
|
2663
|
+
return result;
|
|
2664
|
+
}
|
|
2665
|
+
function resolvePlayer2(el) {
|
|
2666
|
+
const forId = el.getAttribute("for");
|
|
2667
|
+
if (forId) {
|
|
2668
|
+
const target = document.getElementById(forId);
|
|
2669
|
+
return target?.player ?? null;
|
|
2670
|
+
}
|
|
2671
|
+
const host = el.closest("video-player");
|
|
2672
|
+
return host?.player ?? null;
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2028
2675
|
// src/player.ts
|
|
2029
2676
|
class Player2 {
|
|
2030
2677
|
_el;
|
|
@@ -2040,6 +2687,7 @@ class Player2 {
|
|
|
2040
2687
|
_cover = null;
|
|
2041
2688
|
_coverDismissed = false;
|
|
2042
2689
|
_coverTimer = null;
|
|
2690
|
+
_playRequested = false;
|
|
2043
2691
|
constructor(container, options = {}) {
|
|
2044
2692
|
if (typeof container === "string") {
|
|
2045
2693
|
const el = document.querySelector(container);
|
|
@@ -2080,8 +2728,8 @@ class Player2 {
|
|
|
2080
2728
|
this._el.classList.add("ts-video-player");
|
|
2081
2729
|
this._el.setAttribute("tabindex", "0");
|
|
2082
2730
|
this._el.setAttribute("role", "region");
|
|
2083
|
-
this._el.setAttribute("aria-roledescription",
|
|
2084
|
-
this._el.setAttribute("aria-label", this._options.title ||
|
|
2731
|
+
this._el.setAttribute("aria-roledescription", label(this._el, "videoRole"));
|
|
2732
|
+
this._el.setAttribute("aria-label", this._options.title || label(this._el, "videoPlayer"));
|
|
2085
2733
|
this._el.setAttribute("aria-keyshortcuts", "Space K M F I C ArrowLeft ArrowRight J L ArrowUp ArrowDown Home End 0 1 2 3 4 5 6 7 8 9");
|
|
2086
2734
|
const mediaContainer = document.createElement("div");
|
|
2087
2735
|
mediaContainer.className = "ts-video-player__container";
|
|
@@ -2105,27 +2753,43 @@ class Player2 {
|
|
|
2105
2753
|
const cover = document.createElement("button");
|
|
2106
2754
|
cover.type = "button";
|
|
2107
2755
|
cover.className = "ts-video-player__cover";
|
|
2108
|
-
cover.setAttribute("aria-label",
|
|
2756
|
+
cover.setAttribute("aria-label", this._options.title ? label(this._el, "playTitle", { title: this._options.title }) : label(this._el, "play"));
|
|
2109
2757
|
cover.hidden = true;
|
|
2110
2758
|
cover.style.cssText = "position:absolute;inset:0;z-index:2;display:none;align-items:center;justify-content:center;width:100%;height:100%;margin:0;padding:0;border:0;border-radius:inherit;background:#000 center/cover no-repeat;cursor:pointer;-webkit-tap-highlight-color:transparent";
|
|
2111
2759
|
const button = document.createElement("span");
|
|
2112
2760
|
button.setAttribute("aria-hidden", "true");
|
|
2113
2761
|
button.style.cssText = "display:flex;align-items:center;justify-content:center;width:64px;height:64px;border-radius:50%;background:rgba(255,255,255,0.92);box-shadow:0 4px 18px rgba(0,0,0,0.35)";
|
|
2114
2762
|
const triangle = document.createElement("span");
|
|
2763
|
+
triangle.className = "ts-video-player__cover-play";
|
|
2115
2764
|
triangle.style.cssText = "width:22px;height:24px;margin-left:5px;background:#0f172a;clip-path:polygon(0 0,100% 50%,0 100%)";
|
|
2116
2765
|
button.appendChild(triangle);
|
|
2117
2766
|
cover.appendChild(button);
|
|
2118
2767
|
cover.addEventListener("click", (event) => {
|
|
2119
2768
|
event.stopPropagation();
|
|
2769
|
+
if (!cover.dataset.loading) {
|
|
2770
|
+
cover.dataset.loading = "";
|
|
2771
|
+
triangle.style.display = "none";
|
|
2772
|
+
const ring = document.createElement("span");
|
|
2773
|
+
ring.className = "ts-video-player__cover-spinner";
|
|
2774
|
+
ring.style.cssText = "width:26px;height:26px;border-radius:50%;border:3px solid rgba(15,23,42,0.2);border-top-color:#0f172a";
|
|
2775
|
+
button.appendChild(ring);
|
|
2776
|
+
ring.animate?.([{ transform: "rotate(0deg)" }, { transform: "rotate(360deg)" }], { duration: 800, iterations: Infinity });
|
|
2777
|
+
}
|
|
2120
2778
|
this.play().catch(() => {});
|
|
2121
2779
|
if (this._coverTimer)
|
|
2122
2780
|
clearTimeout(this._coverTimer);
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2781
|
+
let waits = 0;
|
|
2782
|
+
const settle = () => {
|
|
2783
|
+
this._coverTimer = setTimeout(() => {
|
|
2784
|
+
if (this.state.started)
|
|
2785
|
+
return;
|
|
2786
|
+
if (!this.state.canPlay && ++waits < 10)
|
|
2787
|
+
return settle();
|
|
2788
|
+
this._coverDismissed = true;
|
|
2789
|
+
this.updateCover(this.state);
|
|
2790
|
+
}, 2000);
|
|
2791
|
+
};
|
|
2792
|
+
settle();
|
|
2129
2793
|
});
|
|
2130
2794
|
this._el.appendChild(cover);
|
|
2131
2795
|
this._cover = cover;
|
|
@@ -2145,6 +2809,13 @@ class Player2 {
|
|
|
2145
2809
|
if (cover.style.backgroundImage !== background)
|
|
2146
2810
|
cover.style.backgroundImage = background;
|
|
2147
2811
|
}
|
|
2812
|
+
if (!show && cover.dataset.loading !== undefined) {
|
|
2813
|
+
delete cover.dataset.loading;
|
|
2814
|
+
cover.querySelector(".ts-video-player__cover-spinner")?.remove();
|
|
2815
|
+
const triangle = cover.querySelector(".ts-video-player__cover-play");
|
|
2816
|
+
if (triangle)
|
|
2817
|
+
triangle.style.display = "";
|
|
2818
|
+
}
|
|
2148
2819
|
cover.hidden = !show;
|
|
2149
2820
|
cover.style.display = show ? "flex" : "none";
|
|
2150
2821
|
}
|
|
@@ -2307,6 +2978,7 @@ class Player2 {
|
|
|
2307
2978
|
return;
|
|
2308
2979
|
}
|
|
2309
2980
|
this._coverDismissed = false;
|
|
2981
|
+
this._playRequested = !!this._options.autoplay;
|
|
2310
2982
|
this._store.batch({
|
|
2311
2983
|
sources,
|
|
2312
2984
|
src: sources[0],
|
|
@@ -2364,6 +3036,10 @@ class Player2 {
|
|
|
2364
3036
|
mediaType: loader.mediaType(candidate.src),
|
|
2365
3037
|
providerType: loader.type
|
|
2366
3038
|
});
|
|
3039
|
+
if (this._playRequested) {
|
|
3040
|
+
this._playRequested = false;
|
|
3041
|
+
this.startRequestedPlay(this._provider);
|
|
3042
|
+
}
|
|
2367
3043
|
return;
|
|
2368
3044
|
} catch (error) {
|
|
2369
3045
|
lastError = error;
|
|
@@ -2409,12 +3085,12 @@ class Player2 {
|
|
|
2409
3085
|
provider.on("play", () => {
|
|
2410
3086
|
this._store.batch({ paused: false, ended: false });
|
|
2411
3087
|
this._events.emit("play");
|
|
2412
|
-
this.announce("
|
|
3088
|
+
this.announce(label(this._el, "playing"));
|
|
2413
3089
|
});
|
|
2414
3090
|
provider.on("pause", () => {
|
|
2415
3091
|
this._store.set("paused", true);
|
|
2416
3092
|
this._events.emit("pause");
|
|
2417
|
-
this.announce("
|
|
3093
|
+
this.announce(label(this._el, "paused"));
|
|
2418
3094
|
});
|
|
2419
3095
|
provider.on("playing", () => {
|
|
2420
3096
|
this._store.batch({ playing: true, started: true, waiting: false, playbackState: "playing" });
|
|
@@ -2444,9 +3120,9 @@ class Player2 {
|
|
|
2444
3120
|
this._store.batch({ volume, muted });
|
|
2445
3121
|
this._events.emit("volumechange", volume, muted);
|
|
2446
3122
|
if (muted) {
|
|
2447
|
-
this.announce("
|
|
3123
|
+
this.announce(label(this._el, "muted"));
|
|
2448
3124
|
} else {
|
|
2449
|
-
this.announce(
|
|
3125
|
+
this.announce(label(this._el, "volumeLevel", { percent: Math.round(volume * 100) }));
|
|
2450
3126
|
}
|
|
2451
3127
|
});
|
|
2452
3128
|
provider.on("ratechange", (rate) => {
|
|
@@ -2463,7 +3139,7 @@ class Player2 {
|
|
|
2463
3139
|
provider.on("ended", () => {
|
|
2464
3140
|
this._store.batch({ ended: true, playing: false, playbackState: "ended" });
|
|
2465
3141
|
this._events.emit("ended");
|
|
2466
|
-
this.announce("
|
|
3142
|
+
this.announce(label(this._el, "ended"));
|
|
2467
3143
|
if (this.state.loop) {
|
|
2468
3144
|
this.seekTo(0);
|
|
2469
3145
|
this.play();
|
|
@@ -2472,7 +3148,7 @@ class Player2 {
|
|
|
2472
3148
|
provider.on("error", (error) => {
|
|
2473
3149
|
this._store.batch({ loadingState: "error", error });
|
|
2474
3150
|
this._events.emit("error", error);
|
|
2475
|
-
this.announce(
|
|
3151
|
+
this.announce(label(this._el, "errorMessage", { message: error.message }));
|
|
2476
3152
|
});
|
|
2477
3153
|
provider.on("statechange", (state) => {
|
|
2478
3154
|
this._store.batch(state);
|
|
@@ -2485,7 +3161,7 @@ class Player2 {
|
|
|
2485
3161
|
provider.on("fullscreenchange", (fullscreen) => {
|
|
2486
3162
|
this._store.set("fullscreen", fullscreen);
|
|
2487
3163
|
this._events.emit("fullscreenchange", fullscreen);
|
|
2488
|
-
this.announce(fullscreen ? "
|
|
3164
|
+
this.announce(label(this._el, fullscreen ? "enteredFullscreen" : "exitedFullscreen"));
|
|
2489
3165
|
});
|
|
2490
3166
|
provider.on("pipchange", (pip) => {
|
|
2491
3167
|
this._store.set("pictureInPicture", pip);
|
|
@@ -2501,12 +3177,23 @@ class Player2 {
|
|
|
2501
3177
|
this._events.emit("availabilitychange", feature, availability);
|
|
2502
3178
|
});
|
|
2503
3179
|
}
|
|
3180
|
+
async startRequestedPlay(provider) {
|
|
3181
|
+
await provider.play().catch(() => {});
|
|
3182
|
+
if (this._provider !== provider || this.state.error?.code !== 1 || this.state.muted)
|
|
3183
|
+
return;
|
|
3184
|
+
this._store.set("error", null);
|
|
3185
|
+
this.setMuted(true);
|
|
3186
|
+
await provider.play().catch(() => {});
|
|
3187
|
+
}
|
|
2504
3188
|
async play() {
|
|
2505
|
-
if (!this._provider)
|
|
3189
|
+
if (!this._provider) {
|
|
3190
|
+
this._playRequested = true;
|
|
2506
3191
|
return;
|
|
3192
|
+
}
|
|
2507
3193
|
await this._provider.play();
|
|
2508
3194
|
}
|
|
2509
3195
|
pause() {
|
|
3196
|
+
this._playRequested = false;
|
|
2510
3197
|
this._provider?.pause();
|
|
2511
3198
|
}
|
|
2512
3199
|
togglePlay() {
|
|
@@ -2822,62 +3509,6 @@ class VideoPlayerElement2 extends HTMLElementBase {
|
|
|
2822
3509
|
}
|
|
2823
3510
|
}
|
|
2824
3511
|
}
|
|
2825
|
-
// src/elements/utils.ts
|
|
2826
|
-
function formatTime2(seconds, guide = 0) {
|
|
2827
|
-
if (!isFinite(seconds) || isNaN(seconds))
|
|
2828
|
-
return "0:00";
|
|
2829
|
-
const s = Math.floor(seconds);
|
|
2830
|
-
const h = Math.floor(s / 3600);
|
|
2831
|
-
const m = Math.floor(s % 3600 / 60);
|
|
2832
|
-
const sec = s % 60;
|
|
2833
|
-
const showHours = h > 0 || guide >= 3600;
|
|
2834
|
-
if (showHours) {
|
|
2835
|
-
return `${h}:${m.toString().padStart(2, "0")}:${sec.toString().padStart(2, "0")}`;
|
|
2836
|
-
}
|
|
2837
|
-
return `${m}:${sec.toString().padStart(2, "0")}`;
|
|
2838
|
-
}
|
|
2839
|
-
function formatTimePhrase2(seconds) {
|
|
2840
|
-
if (!isFinite(seconds) || isNaN(seconds))
|
|
2841
|
-
return "0 seconds";
|
|
2842
|
-
const s = Math.floor(seconds);
|
|
2843
|
-
const h = Math.floor(s / 3600);
|
|
2844
|
-
const m = Math.floor(s % 3600 / 60);
|
|
2845
|
-
const sec = s % 60;
|
|
2846
|
-
const parts = [];
|
|
2847
|
-
if (h > 0)
|
|
2848
|
-
parts.push(`${h} ${h === 1 ? "hour" : "hours"}`);
|
|
2849
|
-
if (m > 0)
|
|
2850
|
-
parts.push(`${m} ${m === 1 ? "minute" : "minutes"}`);
|
|
2851
|
-
if (sec > 0 || parts.length === 0)
|
|
2852
|
-
parts.push(`${sec} ${sec === 1 ? "second" : "seconds"}`);
|
|
2853
|
-
return parts.join(", ");
|
|
2854
|
-
}
|
|
2855
|
-
function toISODuration2(seconds) {
|
|
2856
|
-
if (!isFinite(seconds) || isNaN(seconds))
|
|
2857
|
-
return "PT0S";
|
|
2858
|
-
const s = Math.floor(seconds);
|
|
2859
|
-
const h = Math.floor(s / 3600);
|
|
2860
|
-
const m = Math.floor(s % 3600 / 60);
|
|
2861
|
-
const sec = s % 60;
|
|
2862
|
-
let result = "PT";
|
|
2863
|
-
if (h > 0)
|
|
2864
|
-
result += `${h}H`;
|
|
2865
|
-
if (m > 0)
|
|
2866
|
-
result += `${m}M`;
|
|
2867
|
-
if (sec > 0 || result === "PT")
|
|
2868
|
-
result += `${sec}S`;
|
|
2869
|
-
return result;
|
|
2870
|
-
}
|
|
2871
|
-
function resolvePlayer2(el) {
|
|
2872
|
-
const forId = el.getAttribute("for");
|
|
2873
|
-
if (forId) {
|
|
2874
|
-
const target = document.getElementById(forId);
|
|
2875
|
-
return target?.player ?? null;
|
|
2876
|
-
}
|
|
2877
|
-
const host = el.closest("video-player");
|
|
2878
|
-
return host?.player ?? null;
|
|
2879
|
-
}
|
|
2880
|
-
|
|
2881
3512
|
// src/elements/video-skin.ts
|
|
2882
3513
|
class VideoSkin2 extends HTMLElementBase {
|
|
2883
3514
|
_cleanups = [];
|
|
@@ -2896,6 +3527,7 @@ class VideoSkin2 extends HTMLElementBase {
|
|
|
2896
3527
|
color: white;
|
|
2897
3528
|
font-family: system-ui, -apple-system, sans-serif;
|
|
2898
3529
|
font-size: 14px;
|
|
3530
|
+
container-type: inline-size;
|
|
2899
3531
|
}
|
|
2900
3532
|
|
|
2901
3533
|
/* Click-to-play overlay */
|
|
@@ -2923,6 +3555,25 @@ class VideoSkin2 extends HTMLElementBase {
|
|
|
2923
3555
|
visibility: hidden;
|
|
2924
3556
|
}
|
|
2925
3557
|
|
|
3558
|
+
/* The time and the progress bar. One row with the buttons on a
|
|
3559
|
+
wide player; a phone-width one gives the progress bar a row of
|
|
3560
|
+
its own, where it would otherwise be squeezed to a dot between
|
|
3561
|
+
the buttons. */
|
|
3562
|
+
.center { display: contents; }
|
|
3563
|
+
@container (max-width: 520px) {
|
|
3564
|
+
.controls { flex-wrap: wrap; row-gap: 0; padding: 4px 10px 6px; }
|
|
3565
|
+
.center { display: flex; order: -1; flex: 1 0 100%; align-items: center; gap: 10px; min-width: 0; font-size: 12px; }
|
|
3566
|
+
/* Speed is in the settings menu too; one button fewer keeps the
|
|
3567
|
+
rest on one row. */
|
|
3568
|
+
::slotted(media-playback-rate-button) { display: none; }
|
|
3569
|
+
}
|
|
3570
|
+
|
|
3571
|
+
/* A touch screen sets the volume with its own buttons, and iOS
|
|
3572
|
+
ignores a page's volume altogether: no slider there. */
|
|
3573
|
+
@media (pointer: coarse) {
|
|
3574
|
+
::slotted(media-volume-slider) { display: none; }
|
|
3575
|
+
}
|
|
3576
|
+
|
|
2926
3577
|
/* Spacer pushes right-aligned controls */
|
|
2927
3578
|
.spacer {
|
|
2928
3579
|
flex: 1;
|
|
@@ -2938,7 +3589,7 @@ class VideoSkin2 extends HTMLElementBase {
|
|
|
2938
3589
|
</div>
|
|
2939
3590
|
<div class="controls" part="controls">
|
|
2940
3591
|
<slot name="left"></slot>
|
|
2941
|
-
<slot name="center"></slot>
|
|
3592
|
+
<div class="center" part="center"><slot name="center"></slot></div>
|
|
2942
3593
|
<div class="spacer"></div>
|
|
2943
3594
|
<slot name="right"></slot>
|
|
2944
3595
|
<slot></slot>
|
|
@@ -2993,7 +3644,7 @@ class MediaPlayButton2 extends HTMLElementBase {
|
|
|
2993
3644
|
}
|
|
2994
3645
|
button:hover { opacity: 0.8; }
|
|
2995
3646
|
</style>
|
|
2996
|
-
<button part="button" type="button" aria-label="
|
|
3647
|
+
<button part="button" type="button" aria-label="${label(this, "play")}">
|
|
2997
3648
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon">
|
|
2998
3649
|
<path d="${PLAY_ICON}"/>
|
|
2999
3650
|
</svg>
|
|
@@ -3019,7 +3670,7 @@ class MediaPlayButton2 extends HTMLElementBase {
|
|
|
3019
3670
|
btn.addEventListener("click", this._onClick);
|
|
3020
3671
|
const unsub = player.subscribe("paused", (state) => {
|
|
3021
3672
|
const paused = state.paused;
|
|
3022
|
-
btn.setAttribute("aria-label", paused ? "
|
|
3673
|
+
btn.setAttribute("aria-label", label(this, paused ? "play" : "pause"));
|
|
3023
3674
|
btn.setAttribute("aria-pressed", String(!paused));
|
|
3024
3675
|
const path = this.shadowRoot.querySelector("path");
|
|
3025
3676
|
path.setAttribute("d", paused ? PLAY_ICON : PAUSE_ICON);
|
|
@@ -3054,7 +3705,7 @@ class MediaMuteButton2 extends HTMLElementBase {
|
|
|
3054
3705
|
}
|
|
3055
3706
|
button:hover { opacity: 0.8; }
|
|
3056
3707
|
</style>
|
|
3057
|
-
<button part="button" type="button" aria-label="
|
|
3708
|
+
<button part="button" type="button" aria-label="${label(this, "mute")}">
|
|
3058
3709
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon">
|
|
3059
3710
|
<path d="${ICON_HIGH}"/>
|
|
3060
3711
|
</svg>
|
|
@@ -3075,7 +3726,7 @@ class MediaMuteButton2 extends HTMLElementBase {
|
|
|
3075
3726
|
btn.addEventListener("click", () => player.toggleMute());
|
|
3076
3727
|
const unsub = player.subscribe((state) => {
|
|
3077
3728
|
const icon = getVolumeIcon(state.muted, state.volume);
|
|
3078
|
-
btn.setAttribute("aria-label", state.muted ? "
|
|
3729
|
+
btn.setAttribute("aria-label", label(this, state.muted ? "unmute" : "mute"));
|
|
3079
3730
|
const path = this.shadowRoot.querySelector("path");
|
|
3080
3731
|
path.setAttribute("d", icon);
|
|
3081
3732
|
});
|
|
@@ -3103,7 +3754,7 @@ class MediaFullscreenButton2 extends HTMLElementBase {
|
|
|
3103
3754
|
button:hover { opacity: 0.8; }
|
|
3104
3755
|
button:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
3105
3756
|
</style>
|
|
3106
|
-
<button part="button" type="button" aria-label="
|
|
3757
|
+
<button part="button" type="button" aria-label="${label(this, "enterFullscreen")}">
|
|
3107
3758
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon">
|
|
3108
3759
|
<path d="${ENTER_FS}"/>
|
|
3109
3760
|
</svg>
|
|
@@ -3131,7 +3782,7 @@ class MediaFullscreenButton2 extends HTMLElementBase {
|
|
|
3131
3782
|
}
|
|
3132
3783
|
btn.disabled = avail !== "available";
|
|
3133
3784
|
const fs = state.fullscreen;
|
|
3134
|
-
btn.setAttribute("aria-label", fs ? "
|
|
3785
|
+
btn.setAttribute("aria-label", label(this, fs ? "exitFullscreen" : "enterFullscreen"));
|
|
3135
3786
|
const path = this.shadowRoot.querySelector("path");
|
|
3136
3787
|
path.setAttribute("d", fs ? EXIT_FS : ENTER_FS);
|
|
3137
3788
|
});
|
|
@@ -3158,7 +3809,7 @@ class MediaPipButton2 extends HTMLElementBase {
|
|
|
3158
3809
|
button:hover { opacity: 0.8; }
|
|
3159
3810
|
button:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
3160
3811
|
</style>
|
|
3161
|
-
<button part="button" type="button" aria-label="
|
|
3812
|
+
<button part="button" type="button" aria-label="${label(this, "enterPiP")}">
|
|
3162
3813
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon">
|
|
3163
3814
|
<path d="${PIP_ICON}"/>
|
|
3164
3815
|
</svg>
|
|
@@ -3185,6 +3836,7 @@ class MediaPipButton2 extends HTMLElementBase {
|
|
|
3185
3836
|
this.removeAttribute("hidden");
|
|
3186
3837
|
}
|
|
3187
3838
|
btn.disabled = avail !== "available";
|
|
3839
|
+
btn.setAttribute("aria-label", label(this, state.pictureInPicture ? "exitPiP" : "enterPiP"));
|
|
3188
3840
|
});
|
|
3189
3841
|
this._cleanup = unsub;
|
|
3190
3842
|
}
|
|
@@ -3215,7 +3867,7 @@ class MediaTimeDisplay2 extends HTMLElementBase {
|
|
|
3215
3867
|
time { color: inherit; }
|
|
3216
3868
|
.separator { margin: 0 2px; }
|
|
3217
3869
|
</style>
|
|
3218
|
-
<time part="time" datetime="PT0S" aria-valuetext="0
|
|
3870
|
+
<time part="time" datetime="PT0S" aria-valuetext="${formatTimePhrase2(0, this)}">0:00</time>
|
|
3219
3871
|
`;
|
|
3220
3872
|
}
|
|
3221
3873
|
this.addEventListener("click", this.handleClick);
|
|
@@ -3261,7 +3913,7 @@ class MediaTimeDisplay2 extends HTMLElementBase {
|
|
|
3261
3913
|
timeEl.textContent = formatTime2(seconds, state.duration);
|
|
3262
3914
|
}
|
|
3263
3915
|
timeEl.setAttribute("datetime", toISODuration2(seconds));
|
|
3264
|
-
timeEl.setAttribute("aria-valuetext", formatTimePhrase2(seconds));
|
|
3916
|
+
timeEl.setAttribute("aria-valuetext", formatTimePhrase2(seconds, this));
|
|
3265
3917
|
}
|
|
3266
3918
|
}
|
|
3267
3919
|
// src/elements/media-time-group.ts
|
|
@@ -3419,7 +4071,7 @@ class MediaProgressBar2 extends HTMLElementBase {
|
|
|
3419
4071
|
</style>
|
|
3420
4072
|
<div class="container" part="container" role="slider"
|
|
3421
4073
|
aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"
|
|
3422
|
-
aria-label="
|
|
4074
|
+
aria-label="${label(this, "seek")}" tabindex="0">
|
|
3423
4075
|
<div class="tooltip" part="tooltip">0:00</div>
|
|
3424
4076
|
<div class="track" part="track">
|
|
3425
4077
|
<div class="waveform" part="waveform" aria-hidden="true"></div>
|
|
@@ -3525,7 +4177,7 @@ class MediaProgressBar2 extends HTMLElementBase {
|
|
|
3525
4177
|
fill.style.width = `${percent}%`;
|
|
3526
4178
|
thumb.style.left = `${percent}%`;
|
|
3527
4179
|
container.setAttribute("aria-valuenow", String(Math.round(percent)));
|
|
3528
|
-
container.setAttribute("aria-valuetext",
|
|
4180
|
+
container.setAttribute("aria-valuetext", label(this, "timeOf", { current: formatTimePhrase2(state.currentTime, this), duration: formatTimePhrase2(duration, this) }));
|
|
3529
4181
|
const bufferedPct = (state.bufferedAmount || 0) * 100;
|
|
3530
4182
|
buffered.style.width = `${bufferedPct}%`;
|
|
3531
4183
|
});
|
|
@@ -3567,7 +4219,7 @@ class MediaVolumeSlider2 extends HTMLElementBase {
|
|
|
3567
4219
|
</style>
|
|
3568
4220
|
<div class="container" part="container" role="slider"
|
|
3569
4221
|
aria-valuemin="0" aria-valuemax="100" aria-valuenow="100"
|
|
3570
|
-
aria-label="
|
|
4222
|
+
aria-label="${label(this, "volume")}" tabindex="0">
|
|
3571
4223
|
<div class="track" part="track">
|
|
3572
4224
|
<div class="fill" part="fill"></div>
|
|
3573
4225
|
<div class="thumb" part="thumb"></div>
|
|
@@ -3762,7 +4414,7 @@ class MediaSettingsMenu2 extends HTMLElementBase {
|
|
|
3762
4414
|
.back { font-weight: bold; border-bottom: 1px solid rgba(255,255,255,0.2); }
|
|
3763
4415
|
</style>
|
|
3764
4416
|
<button class="trigger" part="trigger" type="button"
|
|
3765
|
-
aria-label="
|
|
4417
|
+
aria-label="${label(this, "settings")}" aria-haspopup="true" aria-expanded="false">
|
|
3766
4418
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon">
|
|
3767
4419
|
<path d="${GEAR_ICON}"/>
|
|
3768
4420
|
</svg>
|
|
@@ -3874,35 +4526,35 @@ class MediaSettingsMenu2 extends HTMLElementBase {
|
|
|
3874
4526
|
}
|
|
3875
4527
|
renderMain(menu, player) {
|
|
3876
4528
|
const state = player.state;
|
|
3877
|
-
this.addItem(menu,
|
|
4529
|
+
this.addItem(menu, `${label(this, "speed")}: ${state.playbackRate}x`, () => {
|
|
3878
4530
|
this._currentPanel = "speed";
|
|
3879
4531
|
this.renderPanel();
|
|
3880
4532
|
});
|
|
3881
4533
|
if (state.qualities.length > 0) {
|
|
3882
4534
|
const current = state.qualities.find((q) => q.selected);
|
|
3883
|
-
const
|
|
3884
|
-
this.addItem(menu,
|
|
4535
|
+
const label2 = state.autoQuality ? label(this, "auto") : current ? `${current.height}p` : label(this, "auto");
|
|
4536
|
+
this.addItem(menu, `${label(this, "quality")}: ${label2}`, () => {
|
|
3885
4537
|
this._currentPanel = "quality";
|
|
3886
4538
|
this.renderPanel();
|
|
3887
4539
|
});
|
|
3888
4540
|
}
|
|
3889
4541
|
if (state.textTracks.length > 0) {
|
|
3890
4542
|
const showing = state.textTracks.find((t) => t.mode === "showing");
|
|
3891
|
-
this.addItem(menu,
|
|
4543
|
+
this.addItem(menu, `${label(this, "captions")}: ${showing?.label || label(this, "captionsOff")}`, () => {
|
|
3892
4544
|
this._currentPanel = "captions";
|
|
3893
4545
|
this.renderPanel();
|
|
3894
4546
|
});
|
|
3895
4547
|
}
|
|
3896
4548
|
if (state.audioTracks.length > 1) {
|
|
3897
4549
|
const selected = state.audioTracks.find((track) => track.selected);
|
|
3898
|
-
this.addItem(menu,
|
|
4550
|
+
this.addItem(menu, `${label(this, "audio")}: ${selected?.label || label(this, "defaultTrack")}`, () => {
|
|
3899
4551
|
this._currentPanel = "audio";
|
|
3900
4552
|
this.renderPanel();
|
|
3901
4553
|
});
|
|
3902
4554
|
}
|
|
3903
4555
|
}
|
|
3904
4556
|
renderSpeed(menu, player) {
|
|
3905
|
-
this.addItem(menu, "
|
|
4557
|
+
this.addItem(menu, label(this, "back"), () => {
|
|
3906
4558
|
this._currentPanel = "main";
|
|
3907
4559
|
this.renderPanel();
|
|
3908
4560
|
}, false, true);
|
|
@@ -3915,11 +4567,11 @@ class MediaSettingsMenu2 extends HTMLElementBase {
|
|
|
3915
4567
|
}
|
|
3916
4568
|
}
|
|
3917
4569
|
renderQuality(menu, player) {
|
|
3918
|
-
this.addItem(menu, "
|
|
4570
|
+
this.addItem(menu, label(this, "back"), () => {
|
|
3919
4571
|
this._currentPanel = "main";
|
|
3920
4572
|
this.renderPanel();
|
|
3921
4573
|
}, false, true);
|
|
3922
|
-
this.addItem(menu, "
|
|
4574
|
+
this.addItem(menu, label(this, "auto"), () => {
|
|
3923
4575
|
player.setQuality("auto");
|
|
3924
4576
|
this.close();
|
|
3925
4577
|
}, player.state.autoQuality);
|
|
@@ -3931,12 +4583,12 @@ class MediaSettingsMenu2 extends HTMLElementBase {
|
|
|
3931
4583
|
}
|
|
3932
4584
|
}
|
|
3933
4585
|
renderCaptions(menu, player) {
|
|
3934
|
-
this.addItem(menu, "
|
|
4586
|
+
this.addItem(menu, label(this, "back"), () => {
|
|
3935
4587
|
this._currentPanel = "main";
|
|
3936
4588
|
this.renderPanel();
|
|
3937
4589
|
}, false, true);
|
|
3938
4590
|
const anyShowing = player.state.textTracks.some((t) => t.mode === "showing");
|
|
3939
|
-
this.addItem(menu, "
|
|
4591
|
+
this.addItem(menu, label(this, "captionsOff"), () => {
|
|
3940
4592
|
for (const t of player.state.textTracks) {
|
|
3941
4593
|
if (t.mode === "showing")
|
|
3942
4594
|
player.setTextTrack(t.id, "disabled");
|
|
@@ -3953,12 +4605,12 @@ class MediaSettingsMenu2 extends HTMLElementBase {
|
|
|
3953
4605
|
}
|
|
3954
4606
|
}
|
|
3955
4607
|
renderAudio(menu, player) {
|
|
3956
|
-
this.addItem(menu, "
|
|
4608
|
+
this.addItem(menu, label(this, "back"), () => {
|
|
3957
4609
|
this._currentPanel = "main";
|
|
3958
4610
|
this.renderPanel();
|
|
3959
4611
|
}, false, true);
|
|
3960
4612
|
for (const track of player.state.audioTracks) {
|
|
3961
|
-
this.addItem(menu, track.label || track.language ||
|
|
4613
|
+
this.addItem(menu, track.label || track.language || label(this, "audioTrack"), () => {
|
|
3962
4614
|
player.setAudioTrack(track.id);
|
|
3963
4615
|
this.close();
|
|
3964
4616
|
}, track.selected);
|
|
@@ -4010,9 +4662,8 @@ class MediaSeekButton2 extends HTMLElementBase {
|
|
|
4010
4662
|
return;
|
|
4011
4663
|
const seconds = Number.parseFloat(this.getAttribute("seconds") ?? "10");
|
|
4012
4664
|
const offset = Number.isFinite(seconds) && seconds !== 0 ? seconds : 10;
|
|
4013
|
-
const label = offset > 0 ? `Forward ${offset} seconds` : `Back ${Math.abs(offset)} seconds`;
|
|
4014
4665
|
button.textContent = offset > 0 ? `+${offset}` : String(offset);
|
|
4015
|
-
button.setAttribute("aria-label", label);
|
|
4666
|
+
button.setAttribute("aria-label", label(this, offset > 0 ? "seekForward" : "seekBackward", { seconds: Math.abs(offset) }));
|
|
4016
4667
|
this.onClick = () => player.seekBy(offset);
|
|
4017
4668
|
button.addEventListener("click", this.onClick);
|
|
4018
4669
|
this.cleanup = player.subscribe((state) => {
|
|
@@ -4036,7 +4687,7 @@ class MediaPlaybackRateButton2 extends HTMLElementBase {
|
|
|
4036
4687
|
button:hover { opacity: .8; }
|
|
4037
4688
|
button:focus-visible { outline: 2px solid currentColor; outline-offset: -2px; }
|
|
4038
4689
|
</style>
|
|
4039
|
-
<button part="button" type="button" aria-label="
|
|
4690
|
+
<button part="button" type="button" aria-label="${label(this, "speed")}"></button>
|
|
4040
4691
|
`;
|
|
4041
4692
|
}
|
|
4042
4693
|
queueMicrotask(() => this.attach());
|
|
@@ -4066,7 +4717,7 @@ class MediaPlaybackRateButton2 extends HTMLElementBase {
|
|
|
4066
4717
|
button.addEventListener("click", this.onClick);
|
|
4067
4718
|
this.cleanup = player.subscribe("playbackRate", (state) => {
|
|
4068
4719
|
button.textContent = `${state.playbackRate}x`;
|
|
4069
|
-
button.setAttribute("aria-label",
|
|
4720
|
+
button.setAttribute("aria-label", label(this, "playbackRate", { rate: state.playbackRate }));
|
|
4070
4721
|
});
|
|
4071
4722
|
}
|
|
4072
4723
|
}
|
|
@@ -4086,7 +4737,7 @@ class MediaAirplayButton2 extends HTMLElementBase {
|
|
|
4086
4737
|
button:hover { opacity: 0.8; }
|
|
4087
4738
|
:host([connected]) button { color: var(--media-airplay-active-color, #38bdf8); }
|
|
4088
4739
|
</style>
|
|
4089
|
-
<button part="button" type="button" aria-label="
|
|
4740
|
+
<button part="button" type="button" aria-label="${label(this, "airPlayPlay")}">
|
|
4090
4741
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon"><path d="${AIRPLAY_ICON}"/></svg>
|
|
4091
4742
|
</button>
|
|
4092
4743
|
`;
|
|
@@ -4145,7 +4796,7 @@ class MediaLiveButton2 extends HTMLElementBase {
|
|
|
4145
4796
|
i { width: 8px; height: 8px; border-radius: 9999px; background: #ef4444; }
|
|
4146
4797
|
:host(:not([at-live-edge])) button { opacity: 0.72; }
|
|
4147
4798
|
</style>
|
|
4148
|
-
<button part="button" type="button" aria-label="
|
|
4799
|
+
<button part="button" type="button" aria-label="${label(this, "seekToLive")}"><i aria-hidden="true"></i><span>${label(this, "live")}</span></button>
|
|
4149
4800
|
`;
|
|
4150
4801
|
}
|
|
4151
4802
|
queueMicrotask(() => this.attach());
|
|
@@ -4241,7 +4892,7 @@ class MediaRemotePlaybackButton2 extends HTMLElementBase {
|
|
|
4241
4892
|
button:hover { opacity: 0.8; }
|
|
4242
4893
|
:host([connected]) button { color: var(--media-remote-active-color, #38bdf8); }
|
|
4243
4894
|
</style>
|
|
4244
|
-
<button part="button" type="button" aria-label="
|
|
4895
|
+
<button part="button" type="button" aria-label="${label(this, "remotePlayback")}">
|
|
4245
4896
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon"><path d="${REMOTE_ICON}"/></svg>
|
|
4246
4897
|
</button>
|
|
4247
4898
|
`;
|
|
@@ -4344,4 +4995,4 @@ function registerElements2() {
|
|
|
4344
4995
|
}
|
|
4345
4996
|
}
|
|
4346
4997
|
|
|
4347
|
-
export { isMediaSessionSupported2, createMediaSession2, updateMetadata2, isOrientationLockSupported2, lockOrientation2, unlockOrientation2, BaseProvider2, isHTML5Source2, HTML5Provider2, html5Loader2, extractYouTubeId2, isYouTubeSource2, YouTubeProvider2, youtubeLoader2, extractVimeoId2, extractVimeoHash2, isVimeoSource2, VimeoProvider2, vimeoLoader2, isHLSSource2, isNativeHLSSupported2, HLSProvider2, hlsLoader2, isDASHSource2, DASHProvider2, dashLoader2, defaultLoaders2, findLoader2, detectMediaType2, getPreconnectHints2,
|
|
4998
|
+
export { isMediaSessionSupported2, createMediaSession2, updateMetadata2, isOrientationLockSupported2, lockOrientation2, unlockOrientation2, BaseProvider2, isHTML5Source2, HTML5Provider2, html5Loader2, extractYouTubeId2, isYouTubeSource2, YouTubeProvider2, youtubeLoader2, extractVimeoId2, extractVimeoHash2, isVimeoSource2, VimeoProvider2, vimeoLoader2, isHLSSource2, isNativeHLSSupported2, HLSProvider2, hlsLoader2, isDASHSource2, DASHProvider2, dashLoader2, defaultLoaders2, findLoader2, detectMediaType2, getPreconnectHints2, englishStrings2, spanishStrings2, frenchStrings2, germanStrings2, japaneseStrings2, chineseStrings2, defaultTranslations2, I18n2, createI18n2, getI18n2, setI18n2, t2, formatTime2, formatTimePhrase2, toISODuration2, resolvePlayer2, Player2, createPlayer2, getPlayer2, VideoPlayerElement2, VideoSkin2, MediaPlayButton2, MediaMuteButton2, MediaFullscreenButton2, MediaPipButton2, MediaTimeDisplay2, MediaTimeGroup2, MediaTimeSeparator2, MediaPreviewTime2, MediaProgressBar2, MediaVolumeSlider2, computePosition2, applyPosition2, MediaSettingsMenu2, MediaSeekButton2, MediaPlaybackRateButton2, MediaAirplayButton2, MediaLiveButton2, MediaErrorDisplay2, MediaRemotePlaybackButton2, registerElements2 };
|