ts-video-player 0.1.7 → 0.1.9
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 +74 -50
- package/dist/{chunk-24n6adw2.js → chunk-fvxawgp5.js} +714 -106
- package/dist/{chunk-ds1nj487.js → chunk-ndbfytd6.js} +1 -1
- package/dist/{chunk-rhykj0qy.js → chunk-pvq6e7gz.js} +17 -3
- package/dist/core/events.d.ts +3 -0
- 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/features/index.js +1 -1
- package/dist/index.js +30 -421
- package/dist/player.d.ts +6 -0
- package/dist/providers/vimeo.d.ts +6 -0
- package/package.json +1 -1
- package/src/core/events.ts +19 -3
- package/src/core/i18n.ts +173 -1
- package/src/elements/media-airplay-button.ts +4 -2
- package/src/elements/media-fullscreen-button.ts +5 -3
- package/src/elements/media-live-button.ts +4 -2
- package/src/elements/media-mute-button.ts +5 -3
- package/src/elements/media-pip-button.ts +5 -2
- package/src/elements/media-play-button.ts +5 -3
- package/src/elements/media-playback-rate-button.ts +5 -3
- package/src/elements/media-progress-bar.ts +5 -3
- package/src/elements/media-remote-playback-button.ts +4 -2
- package/src/elements/media-seek-button.ts +4 -3
- package/src/elements/media-settings-menu.ts +16 -14
- package/src/elements/media-time-display.ts +2 -2
- package/src/elements/media-volume-slider.ts +4 -2
- package/src/elements/utils.ts +40 -6
- package/src/elements/video-player.ts +3 -1
- package/src/player.ts +36 -14
- package/src/providers/vimeo.ts +15 -3
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
detectPipAvailability2,
|
|
17
17
|
enterPiP2,
|
|
18
18
|
exitPiP2
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-pvq6e7gz.js";
|
|
20
20
|
|
|
21
21
|
// src/core/media-session.ts
|
|
22
22
|
function isMediaSessionSupported2() {
|
|
@@ -1026,8 +1026,9 @@ class VimeoProvider2 extends BaseProvider2 {
|
|
|
1026
1026
|
return;
|
|
1027
1027
|
}
|
|
1028
1028
|
if (this.player) {
|
|
1029
|
-
await this.player.
|
|
1030
|
-
this.
|
|
1029
|
+
await this.player.loadVideo(parseInt(parsed.videoId, 10));
|
|
1030
|
+
await this.announceLoaded();
|
|
1031
|
+
return;
|
|
1031
1032
|
}
|
|
1032
1033
|
const playerOptions = {
|
|
1033
1034
|
id: parseInt(parsed.videoId, 10),
|
|
@@ -1051,6 +1052,11 @@ class VimeoProvider2 extends BaseProvider2 {
|
|
|
1051
1052
|
this.iframe.style.cssText = "position:absolute;inset:0;width:100%;height:100%;border:0";
|
|
1052
1053
|
}
|
|
1053
1054
|
this.attachVimeoEvents();
|
|
1055
|
+
await this.announceLoaded();
|
|
1056
|
+
}
|
|
1057
|
+
async announceLoaded() {
|
|
1058
|
+
if (!this.player)
|
|
1059
|
+
return;
|
|
1054
1060
|
this.events.emit("loadedmetadata");
|
|
1055
1061
|
this.events.emit("canplay");
|
|
1056
1062
|
this._duration = await this.player.getDuration();
|
|
@@ -2042,6 +2048,630 @@ function embedCover(state, dismissed) {
|
|
|
2042
2048
|
return { show: true, image: youtubeId ? `https://i.ytimg.com/vi/${youtubeId}/hqdefault.jpg` : "" };
|
|
2043
2049
|
}
|
|
2044
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
|
+
|
|
2045
2675
|
// src/player.ts
|
|
2046
2676
|
class Player2 {
|
|
2047
2677
|
_el;
|
|
@@ -2098,8 +2728,8 @@ class Player2 {
|
|
|
2098
2728
|
this._el.classList.add("ts-video-player");
|
|
2099
2729
|
this._el.setAttribute("tabindex", "0");
|
|
2100
2730
|
this._el.setAttribute("role", "region");
|
|
2101
|
-
this._el.setAttribute("aria-roledescription",
|
|
2102
|
-
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"));
|
|
2103
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");
|
|
2104
2734
|
const mediaContainer = document.createElement("div");
|
|
2105
2735
|
mediaContainer.className = "ts-video-player__container";
|
|
@@ -2123,7 +2753,7 @@ class Player2 {
|
|
|
2123
2753
|
const cover = document.createElement("button");
|
|
2124
2754
|
cover.type = "button";
|
|
2125
2755
|
cover.className = "ts-video-player__cover";
|
|
2126
|
-
cover.setAttribute("aria-label",
|
|
2756
|
+
cover.setAttribute("aria-label", this._options.title ? label(this._el, "playTitle", { title: this._options.title }) : label(this._el, "play"));
|
|
2127
2757
|
cover.hidden = true;
|
|
2128
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";
|
|
2129
2759
|
const button = document.createElement("span");
|
|
@@ -2218,6 +2848,8 @@ class Player2 {
|
|
|
2218
2848
|
toggleCaptions: () => this.toggleCaptions(),
|
|
2219
2849
|
seekBackward: () => this.seekBy(-5),
|
|
2220
2850
|
seekForward: () => this.seekBy(5),
|
|
2851
|
+
seekBackwardLong: () => this.seekBy(-10),
|
|
2852
|
+
seekForwardLong: () => this.seekBy(10),
|
|
2221
2853
|
volumeUp: () => this.setVolume(Math.min(1, this.state.volume + 0.1)),
|
|
2222
2854
|
volumeDown: () => this.setVolume(Math.max(0, this.state.volume - 0.1)),
|
|
2223
2855
|
speedUp: () => this.setPlaybackRate(Math.min(4, this.state.playbackRate + 0.25)),
|
|
@@ -2348,7 +2980,7 @@ class Player2 {
|
|
|
2348
2980
|
return;
|
|
2349
2981
|
}
|
|
2350
2982
|
this._coverDismissed = false;
|
|
2351
|
-
this._playRequested =
|
|
2983
|
+
this._playRequested = !!this._options.autoplay;
|
|
2352
2984
|
this._store.batch({
|
|
2353
2985
|
sources,
|
|
2354
2986
|
src: sources[0],
|
|
@@ -2408,7 +3040,7 @@ class Player2 {
|
|
|
2408
3040
|
});
|
|
2409
3041
|
if (this._playRequested) {
|
|
2410
3042
|
this._playRequested = false;
|
|
2411
|
-
this.
|
|
3043
|
+
this.startRequestedPlay(this._provider);
|
|
2412
3044
|
}
|
|
2413
3045
|
return;
|
|
2414
3046
|
} catch (error) {
|
|
@@ -2455,12 +3087,12 @@ class Player2 {
|
|
|
2455
3087
|
provider.on("play", () => {
|
|
2456
3088
|
this._store.batch({ paused: false, ended: false });
|
|
2457
3089
|
this._events.emit("play");
|
|
2458
|
-
this.announce("
|
|
3090
|
+
this.announce(label(this._el, "playing"));
|
|
2459
3091
|
});
|
|
2460
3092
|
provider.on("pause", () => {
|
|
2461
|
-
this._store.
|
|
3093
|
+
this._store.batch({ paused: true, playing: false, playbackState: "paused" });
|
|
2462
3094
|
this._events.emit("pause");
|
|
2463
|
-
this.announce("
|
|
3095
|
+
this.announce(label(this._el, "paused"));
|
|
2464
3096
|
});
|
|
2465
3097
|
provider.on("playing", () => {
|
|
2466
3098
|
this._store.batch({ playing: true, started: true, waiting: false, playbackState: "playing" });
|
|
@@ -2490,9 +3122,9 @@ class Player2 {
|
|
|
2490
3122
|
this._store.batch({ volume, muted });
|
|
2491
3123
|
this._events.emit("volumechange", volume, muted);
|
|
2492
3124
|
if (muted) {
|
|
2493
|
-
this.announce("
|
|
3125
|
+
this.announce(label(this._el, "muted"));
|
|
2494
3126
|
} else {
|
|
2495
|
-
this.announce(
|
|
3127
|
+
this.announce(label(this._el, "volumeLevel", { percent: Math.round(volume * 100) }));
|
|
2496
3128
|
}
|
|
2497
3129
|
});
|
|
2498
3130
|
provider.on("ratechange", (rate) => {
|
|
@@ -2509,7 +3141,7 @@ class Player2 {
|
|
|
2509
3141
|
provider.on("ended", () => {
|
|
2510
3142
|
this._store.batch({ ended: true, playing: false, playbackState: "ended" });
|
|
2511
3143
|
this._events.emit("ended");
|
|
2512
|
-
this.announce("
|
|
3144
|
+
this.announce(label(this._el, "ended"));
|
|
2513
3145
|
if (this.state.loop) {
|
|
2514
3146
|
this.seekTo(0);
|
|
2515
3147
|
this.play();
|
|
@@ -2518,7 +3150,7 @@ class Player2 {
|
|
|
2518
3150
|
provider.on("error", (error) => {
|
|
2519
3151
|
this._store.batch({ loadingState: "error", error });
|
|
2520
3152
|
this._events.emit("error", error);
|
|
2521
|
-
this.announce(
|
|
3153
|
+
this.announce(label(this._el, "errorMessage", { message: error.message }));
|
|
2522
3154
|
});
|
|
2523
3155
|
provider.on("statechange", (state) => {
|
|
2524
3156
|
this._store.batch(state);
|
|
@@ -2531,7 +3163,7 @@ class Player2 {
|
|
|
2531
3163
|
provider.on("fullscreenchange", (fullscreen) => {
|
|
2532
3164
|
this._store.set("fullscreen", fullscreen);
|
|
2533
3165
|
this._events.emit("fullscreenchange", fullscreen);
|
|
2534
|
-
this.announce(fullscreen ? "
|
|
3166
|
+
this.announce(label(this._el, fullscreen ? "enteredFullscreen" : "exitedFullscreen"));
|
|
2535
3167
|
});
|
|
2536
3168
|
provider.on("pipchange", (pip) => {
|
|
2537
3169
|
this._store.set("pictureInPicture", pip);
|
|
@@ -2547,6 +3179,14 @@ class Player2 {
|
|
|
2547
3179
|
this._events.emit("availabilitychange", feature, availability);
|
|
2548
3180
|
});
|
|
2549
3181
|
}
|
|
3182
|
+
async startRequestedPlay(provider) {
|
|
3183
|
+
await provider.play().catch(() => {});
|
|
3184
|
+
if (this._provider !== provider || this.state.error?.code !== 1 || this.state.muted)
|
|
3185
|
+
return;
|
|
3186
|
+
this._store.set("error", null);
|
|
3187
|
+
this.setMuted(true);
|
|
3188
|
+
await provider.play().catch(() => {});
|
|
3189
|
+
}
|
|
2550
3190
|
async play() {
|
|
2551
3191
|
if (!this._provider) {
|
|
2552
3192
|
this._playRequested = true;
|
|
@@ -2719,7 +3359,7 @@ class VideoPlayerElement2 extends HTMLElementBase {
|
|
|
2719
3359
|
this._disconnectId++;
|
|
2720
3360
|
if (this._player)
|
|
2721
3361
|
return;
|
|
2722
|
-
const shadow = this.shadowRoot ?? this.attachShadow({ mode: "open" });
|
|
3362
|
+
const shadow = this.shadowRoot ?? this.attachShadow({ mode: "open", delegatesFocus: true });
|
|
2723
3363
|
this._container = document.createElement("div");
|
|
2724
3364
|
this._container.setAttribute("part", "container");
|
|
2725
3365
|
this._container.style.cssText = "position:relative;width:100%;height:100%;";
|
|
@@ -2871,62 +3511,6 @@ class VideoPlayerElement2 extends HTMLElementBase {
|
|
|
2871
3511
|
}
|
|
2872
3512
|
}
|
|
2873
3513
|
}
|
|
2874
|
-
// src/elements/utils.ts
|
|
2875
|
-
function formatTime2(seconds, guide = 0) {
|
|
2876
|
-
if (!isFinite(seconds) || isNaN(seconds))
|
|
2877
|
-
return "0:00";
|
|
2878
|
-
const s = Math.floor(seconds);
|
|
2879
|
-
const h = Math.floor(s / 3600);
|
|
2880
|
-
const m = Math.floor(s % 3600 / 60);
|
|
2881
|
-
const sec = s % 60;
|
|
2882
|
-
const showHours = h > 0 || guide >= 3600;
|
|
2883
|
-
if (showHours) {
|
|
2884
|
-
return `${h}:${m.toString().padStart(2, "0")}:${sec.toString().padStart(2, "0")}`;
|
|
2885
|
-
}
|
|
2886
|
-
return `${m}:${sec.toString().padStart(2, "0")}`;
|
|
2887
|
-
}
|
|
2888
|
-
function formatTimePhrase2(seconds) {
|
|
2889
|
-
if (!isFinite(seconds) || isNaN(seconds))
|
|
2890
|
-
return "0 seconds";
|
|
2891
|
-
const s = Math.floor(seconds);
|
|
2892
|
-
const h = Math.floor(s / 3600);
|
|
2893
|
-
const m = Math.floor(s % 3600 / 60);
|
|
2894
|
-
const sec = s % 60;
|
|
2895
|
-
const parts = [];
|
|
2896
|
-
if (h > 0)
|
|
2897
|
-
parts.push(`${h} ${h === 1 ? "hour" : "hours"}`);
|
|
2898
|
-
if (m > 0)
|
|
2899
|
-
parts.push(`${m} ${m === 1 ? "minute" : "minutes"}`);
|
|
2900
|
-
if (sec > 0 || parts.length === 0)
|
|
2901
|
-
parts.push(`${sec} ${sec === 1 ? "second" : "seconds"}`);
|
|
2902
|
-
return parts.join(", ");
|
|
2903
|
-
}
|
|
2904
|
-
function toISODuration2(seconds) {
|
|
2905
|
-
if (!isFinite(seconds) || isNaN(seconds))
|
|
2906
|
-
return "PT0S";
|
|
2907
|
-
const s = Math.floor(seconds);
|
|
2908
|
-
const h = Math.floor(s / 3600);
|
|
2909
|
-
const m = Math.floor(s % 3600 / 60);
|
|
2910
|
-
const sec = s % 60;
|
|
2911
|
-
let result = "PT";
|
|
2912
|
-
if (h > 0)
|
|
2913
|
-
result += `${h}H`;
|
|
2914
|
-
if (m > 0)
|
|
2915
|
-
result += `${m}M`;
|
|
2916
|
-
if (sec > 0 || result === "PT")
|
|
2917
|
-
result += `${sec}S`;
|
|
2918
|
-
return result;
|
|
2919
|
-
}
|
|
2920
|
-
function resolvePlayer2(el) {
|
|
2921
|
-
const forId = el.getAttribute("for");
|
|
2922
|
-
if (forId) {
|
|
2923
|
-
const target = document.getElementById(forId);
|
|
2924
|
-
return target?.player ?? null;
|
|
2925
|
-
}
|
|
2926
|
-
const host = el.closest("video-player");
|
|
2927
|
-
return host?.player ?? null;
|
|
2928
|
-
}
|
|
2929
|
-
|
|
2930
3514
|
// src/elements/video-skin.ts
|
|
2931
3515
|
class VideoSkin2 extends HTMLElementBase {
|
|
2932
3516
|
_cleanups = [];
|
|
@@ -3061,8 +3645,10 @@ class MediaPlayButton2 extends HTMLElementBase {
|
|
|
3061
3645
|
background: transparent; border: none; color: inherit; cursor: pointer;
|
|
3062
3646
|
}
|
|
3063
3647
|
button:hover { opacity: 0.8; }
|
|
3648
|
+
/* 44px, the smallest a finger hits reliably, on a touch screen. */
|
|
3649
|
+
@media (pointer: coarse) { button { min-width: 44px; min-height: 44px; } }
|
|
3064
3650
|
</style>
|
|
3065
|
-
<button part="button" type="button" aria-label="
|
|
3651
|
+
<button part="button" type="button" aria-label="${label(this, "play")}">
|
|
3066
3652
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon">
|
|
3067
3653
|
<path d="${PLAY_ICON}"/>
|
|
3068
3654
|
</svg>
|
|
@@ -3088,7 +3674,7 @@ class MediaPlayButton2 extends HTMLElementBase {
|
|
|
3088
3674
|
btn.addEventListener("click", this._onClick);
|
|
3089
3675
|
const unsub = player.subscribe("paused", (state) => {
|
|
3090
3676
|
const paused = state.paused;
|
|
3091
|
-
btn.setAttribute("aria-label", paused ? "
|
|
3677
|
+
btn.setAttribute("aria-label", label(this, paused ? "play" : "pause"));
|
|
3092
3678
|
btn.setAttribute("aria-pressed", String(!paused));
|
|
3093
3679
|
const path = this.shadowRoot.querySelector("path");
|
|
3094
3680
|
path.setAttribute("d", paused ? PLAY_ICON : PAUSE_ICON);
|
|
@@ -3122,8 +3708,10 @@ class MediaMuteButton2 extends HTMLElementBase {
|
|
|
3122
3708
|
background: transparent; border: none; color: inherit; cursor: pointer;
|
|
3123
3709
|
}
|
|
3124
3710
|
button:hover { opacity: 0.8; }
|
|
3711
|
+
/* 44px, the smallest a finger hits reliably, on a touch screen. */
|
|
3712
|
+
@media (pointer: coarse) { button { min-width: 44px; min-height: 44px; } }
|
|
3125
3713
|
</style>
|
|
3126
|
-
<button part="button" type="button" aria-label="
|
|
3714
|
+
<button part="button" type="button" aria-label="${label(this, "mute")}">
|
|
3127
3715
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon">
|
|
3128
3716
|
<path d="${ICON_HIGH}"/>
|
|
3129
3717
|
</svg>
|
|
@@ -3144,7 +3732,7 @@ class MediaMuteButton2 extends HTMLElementBase {
|
|
|
3144
3732
|
btn.addEventListener("click", () => player.toggleMute());
|
|
3145
3733
|
const unsub = player.subscribe((state) => {
|
|
3146
3734
|
const icon = getVolumeIcon(state.muted, state.volume);
|
|
3147
|
-
btn.setAttribute("aria-label", state.muted ? "
|
|
3735
|
+
btn.setAttribute("aria-label", label(this, state.muted ? "unmute" : "mute"));
|
|
3148
3736
|
const path = this.shadowRoot.querySelector("path");
|
|
3149
3737
|
path.setAttribute("d", icon);
|
|
3150
3738
|
});
|
|
@@ -3171,8 +3759,10 @@ class MediaFullscreenButton2 extends HTMLElementBase {
|
|
|
3171
3759
|
}
|
|
3172
3760
|
button:hover { opacity: 0.8; }
|
|
3173
3761
|
button:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
3762
|
+
/* 44px, the smallest a finger hits reliably, on a touch screen. */
|
|
3763
|
+
@media (pointer: coarse) { button { min-width: 44px; min-height: 44px; } }
|
|
3174
3764
|
</style>
|
|
3175
|
-
<button part="button" type="button" aria-label="
|
|
3765
|
+
<button part="button" type="button" aria-label="${label(this, "enterFullscreen")}">
|
|
3176
3766
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon">
|
|
3177
3767
|
<path d="${ENTER_FS}"/>
|
|
3178
3768
|
</svg>
|
|
@@ -3200,7 +3790,7 @@ class MediaFullscreenButton2 extends HTMLElementBase {
|
|
|
3200
3790
|
}
|
|
3201
3791
|
btn.disabled = avail !== "available";
|
|
3202
3792
|
const fs = state.fullscreen;
|
|
3203
|
-
btn.setAttribute("aria-label", fs ? "
|
|
3793
|
+
btn.setAttribute("aria-label", label(this, fs ? "exitFullscreen" : "enterFullscreen"));
|
|
3204
3794
|
const path = this.shadowRoot.querySelector("path");
|
|
3205
3795
|
path.setAttribute("d", fs ? EXIT_FS : ENTER_FS);
|
|
3206
3796
|
});
|
|
@@ -3226,8 +3816,10 @@ class MediaPipButton2 extends HTMLElementBase {
|
|
|
3226
3816
|
}
|
|
3227
3817
|
button:hover { opacity: 0.8; }
|
|
3228
3818
|
button:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
3819
|
+
/* 44px, the smallest a finger hits reliably, on a touch screen. */
|
|
3820
|
+
@media (pointer: coarse) { button { min-width: 44px; min-height: 44px; } }
|
|
3229
3821
|
</style>
|
|
3230
|
-
<button part="button" type="button" aria-label="
|
|
3822
|
+
<button part="button" type="button" aria-label="${label(this, "enterPiP")}">
|
|
3231
3823
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon">
|
|
3232
3824
|
<path d="${PIP_ICON}"/>
|
|
3233
3825
|
</svg>
|
|
@@ -3254,6 +3846,7 @@ class MediaPipButton2 extends HTMLElementBase {
|
|
|
3254
3846
|
this.removeAttribute("hidden");
|
|
3255
3847
|
}
|
|
3256
3848
|
btn.disabled = avail !== "available";
|
|
3849
|
+
btn.setAttribute("aria-label", label(this, state.pictureInPicture ? "exitPiP" : "enterPiP"));
|
|
3257
3850
|
});
|
|
3258
3851
|
this._cleanup = unsub;
|
|
3259
3852
|
}
|
|
@@ -3284,7 +3877,7 @@ class MediaTimeDisplay2 extends HTMLElementBase {
|
|
|
3284
3877
|
time { color: inherit; }
|
|
3285
3878
|
.separator { margin: 0 2px; }
|
|
3286
3879
|
</style>
|
|
3287
|
-
<time part="time" datetime="PT0S" aria-valuetext="0
|
|
3880
|
+
<time part="time" datetime="PT0S" aria-valuetext="${formatTimePhrase2(0, this)}">0:00</time>
|
|
3288
3881
|
`;
|
|
3289
3882
|
}
|
|
3290
3883
|
this.addEventListener("click", this.handleClick);
|
|
@@ -3330,7 +3923,7 @@ class MediaTimeDisplay2 extends HTMLElementBase {
|
|
|
3330
3923
|
timeEl.textContent = formatTime2(seconds, state.duration);
|
|
3331
3924
|
}
|
|
3332
3925
|
timeEl.setAttribute("datetime", toISODuration2(seconds));
|
|
3333
|
-
timeEl.setAttribute("aria-valuetext", formatTimePhrase2(seconds));
|
|
3926
|
+
timeEl.setAttribute("aria-valuetext", formatTimePhrase2(seconds, this));
|
|
3334
3927
|
}
|
|
3335
3928
|
}
|
|
3336
3929
|
// src/elements/media-time-group.ts
|
|
@@ -3485,10 +4078,12 @@ class MediaProgressBar2 extends HTMLElementBase {
|
|
|
3485
4078
|
border-top-color: rgba(0,0,0,0.85);
|
|
3486
4079
|
}
|
|
3487
4080
|
.container:hover .tooltip { opacity: 1; }
|
|
4081
|
+
/* A finger needs more than the 20px a mouse does. */
|
|
4082
|
+
@media (pointer: coarse) { .container { height: 36px; } .thumb { width: 18px; height: 18px; } }
|
|
3488
4083
|
</style>
|
|
3489
4084
|
<div class="container" part="container" role="slider"
|
|
3490
4085
|
aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"
|
|
3491
|
-
aria-label="
|
|
4086
|
+
aria-label="${label(this, "seek")}" tabindex="0">
|
|
3492
4087
|
<div class="tooltip" part="tooltip">0:00</div>
|
|
3493
4088
|
<div class="track" part="track">
|
|
3494
4089
|
<div class="waveform" part="waveform" aria-hidden="true"></div>
|
|
@@ -3594,7 +4189,7 @@ class MediaProgressBar2 extends HTMLElementBase {
|
|
|
3594
4189
|
fill.style.width = `${percent}%`;
|
|
3595
4190
|
thumb.style.left = `${percent}%`;
|
|
3596
4191
|
container.setAttribute("aria-valuenow", String(Math.round(percent)));
|
|
3597
|
-
container.setAttribute("aria-valuetext",
|
|
4192
|
+
container.setAttribute("aria-valuetext", label(this, "timeOf", { current: formatTimePhrase2(state.currentTime, this), duration: formatTimePhrase2(duration, this) }));
|
|
3598
4193
|
const bufferedPct = (state.bufferedAmount || 0) * 100;
|
|
3599
4194
|
buffered.style.width = `${bufferedPct}%`;
|
|
3600
4195
|
});
|
|
@@ -3633,10 +4228,12 @@ class MediaVolumeSlider2 extends HTMLElementBase {
|
|
|
3633
4228
|
transition: transform 0.1s;
|
|
3634
4229
|
}
|
|
3635
4230
|
.container:hover .thumb { transform: translate(-50%, -50%) scale(1.2); }
|
|
4231
|
+
/* A finger needs more than the 20px a mouse does. */
|
|
4232
|
+
@media (pointer: coarse) { .container { height: 36px; } .thumb { width: 18px; height: 18px; } }
|
|
3636
4233
|
</style>
|
|
3637
4234
|
<div class="container" part="container" role="slider"
|
|
3638
4235
|
aria-valuemin="0" aria-valuemax="100" aria-valuenow="100"
|
|
3639
|
-
aria-label="
|
|
4236
|
+
aria-label="${label(this, "volume")}" tabindex="0">
|
|
3640
4237
|
<div class="track" part="track">
|
|
3641
4238
|
<div class="fill" part="fill"></div>
|
|
3642
4239
|
<div class="thumb" part="thumb"></div>
|
|
@@ -3829,9 +4426,11 @@ class MediaSettingsMenu2 extends HTMLElementBase {
|
|
|
3829
4426
|
.item[aria-checked="true"]::before { content: '\\2713'; }
|
|
3830
4427
|
.item[aria-checked="false"]::before { content: ''; min-width: 12px; display: inline-block; }
|
|
3831
4428
|
.back { font-weight: bold; border-bottom: 1px solid rgba(255,255,255,0.2); }
|
|
4429
|
+
/* 44px, the smallest a finger hits reliably, on a touch screen. */
|
|
4430
|
+
@media (pointer: coarse) { button { min-width: 44px; min-height: 44px; } }
|
|
3832
4431
|
</style>
|
|
3833
4432
|
<button class="trigger" part="trigger" type="button"
|
|
3834
|
-
aria-label="
|
|
4433
|
+
aria-label="${label(this, "settings")}" aria-haspopup="true" aria-expanded="false">
|
|
3835
4434
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon">
|
|
3836
4435
|
<path d="${GEAR_ICON}"/>
|
|
3837
4436
|
</svg>
|
|
@@ -3943,35 +4542,35 @@ class MediaSettingsMenu2 extends HTMLElementBase {
|
|
|
3943
4542
|
}
|
|
3944
4543
|
renderMain(menu, player) {
|
|
3945
4544
|
const state = player.state;
|
|
3946
|
-
this.addItem(menu,
|
|
4545
|
+
this.addItem(menu, `${label(this, "speed")}: ${state.playbackRate}x`, () => {
|
|
3947
4546
|
this._currentPanel = "speed";
|
|
3948
4547
|
this.renderPanel();
|
|
3949
4548
|
});
|
|
3950
4549
|
if (state.qualities.length > 0) {
|
|
3951
4550
|
const current = state.qualities.find((q) => q.selected);
|
|
3952
|
-
const
|
|
3953
|
-
this.addItem(menu,
|
|
4551
|
+
const label2 = state.autoQuality ? label(this, "auto") : current ? `${current.height}p` : label(this, "auto");
|
|
4552
|
+
this.addItem(menu, `${label(this, "quality")}: ${label2}`, () => {
|
|
3954
4553
|
this._currentPanel = "quality";
|
|
3955
4554
|
this.renderPanel();
|
|
3956
4555
|
});
|
|
3957
4556
|
}
|
|
3958
4557
|
if (state.textTracks.length > 0) {
|
|
3959
4558
|
const showing = state.textTracks.find((t) => t.mode === "showing");
|
|
3960
|
-
this.addItem(menu,
|
|
4559
|
+
this.addItem(menu, `${label(this, "captions")}: ${showing?.label || label(this, "captionsOff")}`, () => {
|
|
3961
4560
|
this._currentPanel = "captions";
|
|
3962
4561
|
this.renderPanel();
|
|
3963
4562
|
});
|
|
3964
4563
|
}
|
|
3965
4564
|
if (state.audioTracks.length > 1) {
|
|
3966
4565
|
const selected = state.audioTracks.find((track) => track.selected);
|
|
3967
|
-
this.addItem(menu,
|
|
4566
|
+
this.addItem(menu, `${label(this, "audio")}: ${selected?.label || label(this, "defaultTrack")}`, () => {
|
|
3968
4567
|
this._currentPanel = "audio";
|
|
3969
4568
|
this.renderPanel();
|
|
3970
4569
|
});
|
|
3971
4570
|
}
|
|
3972
4571
|
}
|
|
3973
4572
|
renderSpeed(menu, player) {
|
|
3974
|
-
this.addItem(menu, "
|
|
4573
|
+
this.addItem(menu, label(this, "back"), () => {
|
|
3975
4574
|
this._currentPanel = "main";
|
|
3976
4575
|
this.renderPanel();
|
|
3977
4576
|
}, false, true);
|
|
@@ -3984,11 +4583,11 @@ class MediaSettingsMenu2 extends HTMLElementBase {
|
|
|
3984
4583
|
}
|
|
3985
4584
|
}
|
|
3986
4585
|
renderQuality(menu, player) {
|
|
3987
|
-
this.addItem(menu, "
|
|
4586
|
+
this.addItem(menu, label(this, "back"), () => {
|
|
3988
4587
|
this._currentPanel = "main";
|
|
3989
4588
|
this.renderPanel();
|
|
3990
4589
|
}, false, true);
|
|
3991
|
-
this.addItem(menu, "
|
|
4590
|
+
this.addItem(menu, label(this, "auto"), () => {
|
|
3992
4591
|
player.setQuality("auto");
|
|
3993
4592
|
this.close();
|
|
3994
4593
|
}, player.state.autoQuality);
|
|
@@ -4000,12 +4599,12 @@ class MediaSettingsMenu2 extends HTMLElementBase {
|
|
|
4000
4599
|
}
|
|
4001
4600
|
}
|
|
4002
4601
|
renderCaptions(menu, player) {
|
|
4003
|
-
this.addItem(menu, "
|
|
4602
|
+
this.addItem(menu, label(this, "back"), () => {
|
|
4004
4603
|
this._currentPanel = "main";
|
|
4005
4604
|
this.renderPanel();
|
|
4006
4605
|
}, false, true);
|
|
4007
4606
|
const anyShowing = player.state.textTracks.some((t) => t.mode === "showing");
|
|
4008
|
-
this.addItem(menu, "
|
|
4607
|
+
this.addItem(menu, label(this, "captionsOff"), () => {
|
|
4009
4608
|
for (const t of player.state.textTracks) {
|
|
4010
4609
|
if (t.mode === "showing")
|
|
4011
4610
|
player.setTextTrack(t.id, "disabled");
|
|
@@ -4022,12 +4621,12 @@ class MediaSettingsMenu2 extends HTMLElementBase {
|
|
|
4022
4621
|
}
|
|
4023
4622
|
}
|
|
4024
4623
|
renderAudio(menu, player) {
|
|
4025
|
-
this.addItem(menu, "
|
|
4624
|
+
this.addItem(menu, label(this, "back"), () => {
|
|
4026
4625
|
this._currentPanel = "main";
|
|
4027
4626
|
this.renderPanel();
|
|
4028
4627
|
}, false, true);
|
|
4029
4628
|
for (const track of player.state.audioTracks) {
|
|
4030
|
-
this.addItem(menu, track.label || track.language ||
|
|
4629
|
+
this.addItem(menu, track.label || track.language || label(this, "audioTrack"), () => {
|
|
4031
4630
|
player.setAudioTrack(track.id);
|
|
4032
4631
|
this.close();
|
|
4033
4632
|
}, track.selected);
|
|
@@ -4058,6 +4657,8 @@ class MediaSeekButton2 extends HTMLElementBase {
|
|
|
4058
4657
|
button:hover { opacity: .8; }
|
|
4059
4658
|
button:focus-visible { outline: 2px solid currentColor; outline-offset: -2px; }
|
|
4060
4659
|
button:disabled { cursor: default; opacity: .45; }
|
|
4660
|
+
/* 44px, the smallest a finger hits reliably, on a touch screen. */
|
|
4661
|
+
@media (pointer: coarse) { button { min-width: 44px; min-height: 44px; } }
|
|
4061
4662
|
</style>
|
|
4062
4663
|
<button part="button" type="button"></button>
|
|
4063
4664
|
`;
|
|
@@ -4079,9 +4680,8 @@ class MediaSeekButton2 extends HTMLElementBase {
|
|
|
4079
4680
|
return;
|
|
4080
4681
|
const seconds = Number.parseFloat(this.getAttribute("seconds") ?? "10");
|
|
4081
4682
|
const offset = Number.isFinite(seconds) && seconds !== 0 ? seconds : 10;
|
|
4082
|
-
const label = offset > 0 ? `Forward ${offset} seconds` : `Back ${Math.abs(offset)} seconds`;
|
|
4083
4683
|
button.textContent = offset > 0 ? `+${offset}` : String(offset);
|
|
4084
|
-
button.setAttribute("aria-label", label);
|
|
4684
|
+
button.setAttribute("aria-label", label(this, offset > 0 ? "seekForward" : "seekBackward", { seconds: Math.abs(offset) }));
|
|
4085
4685
|
this.onClick = () => player.seekBy(offset);
|
|
4086
4686
|
button.addEventListener("click", this.onClick);
|
|
4087
4687
|
this.cleanup = player.subscribe((state) => {
|
|
@@ -4104,8 +4704,10 @@ class MediaPlaybackRateButton2 extends HTMLElementBase {
|
|
|
4104
4704
|
button { min-width: 42px; height: 40px; padding: 0 8px; border: 0; background: transparent; color: inherit; cursor: pointer; font: inherit; font-variant-numeric: tabular-nums; }
|
|
4105
4705
|
button:hover { opacity: .8; }
|
|
4106
4706
|
button:focus-visible { outline: 2px solid currentColor; outline-offset: -2px; }
|
|
4707
|
+
/* 44px, the smallest a finger hits reliably, on a touch screen. */
|
|
4708
|
+
@media (pointer: coarse) { button { min-width: 44px; min-height: 44px; } }
|
|
4107
4709
|
</style>
|
|
4108
|
-
<button part="button" type="button" aria-label="
|
|
4710
|
+
<button part="button" type="button" aria-label="${label(this, "speed")}"></button>
|
|
4109
4711
|
`;
|
|
4110
4712
|
}
|
|
4111
4713
|
queueMicrotask(() => this.attach());
|
|
@@ -4135,7 +4737,7 @@ class MediaPlaybackRateButton2 extends HTMLElementBase {
|
|
|
4135
4737
|
button.addEventListener("click", this.onClick);
|
|
4136
4738
|
this.cleanup = player.subscribe("playbackRate", (state) => {
|
|
4137
4739
|
button.textContent = `${state.playbackRate}x`;
|
|
4138
|
-
button.setAttribute("aria-label",
|
|
4740
|
+
button.setAttribute("aria-label", label(this, "playbackRate", { rate: state.playbackRate }));
|
|
4139
4741
|
});
|
|
4140
4742
|
}
|
|
4141
4743
|
}
|
|
@@ -4154,8 +4756,10 @@ class MediaAirplayButton2 extends HTMLElementBase {
|
|
|
4154
4756
|
button { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; padding: 8px; background: transparent; border: 0; color: inherit; cursor: pointer; }
|
|
4155
4757
|
button:hover { opacity: 0.8; }
|
|
4156
4758
|
:host([connected]) button { color: var(--media-airplay-active-color, #38bdf8); }
|
|
4759
|
+
/* 44px, the smallest a finger hits reliably, on a touch screen. */
|
|
4760
|
+
@media (pointer: coarse) { button { min-width: 44px; min-height: 44px; } }
|
|
4157
4761
|
</style>
|
|
4158
|
-
<button part="button" type="button" aria-label="
|
|
4762
|
+
<button part="button" type="button" aria-label="${label(this, "airPlayPlay")}">
|
|
4159
4763
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon"><path d="${AIRPLAY_ICON}"/></svg>
|
|
4160
4764
|
</button>
|
|
4161
4765
|
`;
|
|
@@ -4213,8 +4817,10 @@ class MediaLiveButton2 extends HTMLElementBase {
|
|
|
4213
4817
|
button { display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 8px; background: transparent; border: 0; color: inherit; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; }
|
|
4214
4818
|
i { width: 8px; height: 8px; border-radius: 9999px; background: #ef4444; }
|
|
4215
4819
|
:host(:not([at-live-edge])) button { opacity: 0.72; }
|
|
4820
|
+
/* 44px, the smallest a finger hits reliably, on a touch screen. */
|
|
4821
|
+
@media (pointer: coarse) { button { min-width: 44px; min-height: 44px; } }
|
|
4216
4822
|
</style>
|
|
4217
|
-
<button part="button" type="button" aria-label="
|
|
4823
|
+
<button part="button" type="button" aria-label="${label(this, "seekToLive")}"><i aria-hidden="true"></i><span>${label(this, "live")}</span></button>
|
|
4218
4824
|
`;
|
|
4219
4825
|
}
|
|
4220
4826
|
queueMicrotask(() => this.attach());
|
|
@@ -4309,8 +4915,10 @@ class MediaRemotePlaybackButton2 extends HTMLElementBase {
|
|
|
4309
4915
|
button { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; padding: 8px; background: transparent; border: 0; color: inherit; cursor: pointer; }
|
|
4310
4916
|
button:hover { opacity: 0.8; }
|
|
4311
4917
|
:host([connected]) button { color: var(--media-remote-active-color, #38bdf8); }
|
|
4918
|
+
/* 44px, the smallest a finger hits reliably, on a touch screen. */
|
|
4919
|
+
@media (pointer: coarse) { button { min-width: 44px; min-height: 44px; } }
|
|
4312
4920
|
</style>
|
|
4313
|
-
<button part="button" type="button" aria-label="
|
|
4921
|
+
<button part="button" type="button" aria-label="${label(this, "remotePlayback")}">
|
|
4314
4922
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" part="icon"><path d="${REMOTE_ICON}"/></svg>
|
|
4315
4923
|
</button>
|
|
4316
4924
|
`;
|
|
@@ -4413,4 +5021,4 @@ function registerElements2() {
|
|
|
4413
5021
|
}
|
|
4414
5022
|
}
|
|
4415
5023
|
|
|
4416
|
-
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,
|
|
5024
|
+
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 };
|