The hidden seek button has custom behavior that causes it to attempt to
"delay" touch events on it, to wait to see
if they are a double-tap or not.
This interacted with the double click to fullscreen behavior
unfortunately; a single touch was registered, then it was
registered again 500ms later, causing it to be detected as a double-tap
by the controls container.
This PR changes the hidden seek button to ignore `touchend` events that
happen while the controls are transparent, and changes the initial
`touchend` event on the hidden seek button to not propagate down, thus
preventing the doubling behavior without introducing any lag on the
controls appearing.
Fixes#9705
I went ahead and implemented the full structured preference system that
was discussed in
https://github.com/shaka-project/shaka-player/issues/1591.
Instead of just expanding languages to arrays, I replaced all 14
individual preference fields with 3 structured arrays:
```tsx
preferredAudio (language, role, label, channelCount, codec, spatialAudio)
preferredText (language, role, format, forced)
preferredVideo (label, role, codec, hdrLevel, layout)
```
Each array entry works as an AND filter - so you can say things like "I
want Korean with 5.1 surround, but if not available, English is fine
too":
```tsx
player.configure('preferredAudio', [
{language: 'ko', channelCount: 6},
{language: 'ko'},
{language: 'en'},
]);
```
<img width="1728" height="965" alt="image"
src="https://github.com/user-attachments/assets/7b088150-139b-475e-bdba-5bc77dd4e524"
/>
**Config** - Replaced the 14 individual fields with 3 arrays of typed
preference objects (AudioPreference, TextPreference, VideoPreference).
The old fields still work at runtime with a deprecation warning, so
existing apps won't break immediately.
**Demo** - The demo config UI now shows inline expandable preference
lists instead of flat text inputs. You can add/remove entries and
configure each field per entry. URL hash serialization was updated to
use JSON format, with legacy param fallbacks preserved.
- Replace split(':') with startsWith('data:') for scheme validation
- Use indexOf(',') instead of split(',') to avoid unnecessary
allocations
- Remove window dependency from decodeURIComponent
- Normalize base64 detection using toLowerCase()
UITextDisplayer was triggering:
"ResizeObserver loop completed with undelivered notifications"
This happened because updateCaptions_() mutates the DOM inside the
ResizeObserver callback, which can cause synchronous layout feedback
loops.
This change:
- Observes videoContainer_ instead of textContainer_
- Defers updateCaptions_() using requestAnimationFrame
- Coalesces multiple resize events using a pendingResize_ flag
- Ensures updates only run when captions are visible
This prevents layout feedback loops while preserving correct caption
re-rendering behavior.
Fixes https://github.com/shaka-project/shaka-player/issues/9721
This should have been removed in version 5, but we did it wrong, so we
have to add it back.
I'm removing the deprecated log and throwing an `alwaysWarn` because
this change could break many more applications than we want, given that
the second parameter is `videoContainer` and we could do something
wrong.
This change is feat! because it no longer allows modifying the
`currentTime` of the mediaElement in the streaming event. With this
change, only `updateStartTime` can be called to update the time, and the
user should always use the `canupdatestarttime` event instead of
`streaming` event when they need it.
Fixes https://github.com/shaka-project/shaka-player/issues/9661
We previously deprecated setTextTrackVisibility, this PR removes it from
the public API.
This'll allow us to further strip down the distinction between selecting
a text track and toggling its visibility internally. Atleast we'll no
longer have users rely on this API from v5 onwards.
---------
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
So basically, when a license request fails (eg. network Error, server
down whatever), apps can now retry from scratch by calling
`player.retryLicensing()`. This was tricky to implement because of EME
spec limitations: `generateRequest()` can only be called once per
session. So if it fails, it would be stuck.
So I close the old session and create a brand new one with the same
`initData`
> Will Video element throw an error during this process?
we were worried that closing the session would leave the video without
keys for a brief moment, potentially triggering errors. But in practice,
the transition is fast enough( I added a 0.1s delay for CDM clean up)
and the video element handles it gracefully
> Will new encrypted event fire? If not, will it limit this feature?
The encrypted event only fires when the browser first encounters
encrypted content. When we close and recreate a session, the content is
already loaded, so no new event
Solutions: In `CreateSession()` metadata store `initData` and
`initDataType` in the session metadata when the session is first
created. So when `retryLicensing()`is called, we just grab the stored
data and pass it to `generateRequest()` on the new session. No need to
wait for an `encrypted` event at all.
---------
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
Co-authored-by: Wojciech Tyczyński <tykus160@gmail.com>
Tests fixed:
```
UI Customization
✗ big buttons only created when configured [Safari 3.0 (Tizen 3.0)]
Error: Expected 1 to be 0.
at <Jasmine>
at Function.confirmElementMissing (test/test/util/ui_utils.js:70:29 <- test/test/util/ui_utils.js:139:31)
at _callee6$ (test/ui/ui_customization_unit.js:86:13 <- test/ui/ui_customization_unit.js:152:21)
at tryCatch (node_modules/@babel/polyfill/dist/polyfill.js:6473:40)
UI
controls
controls-button-panel
✗ has default elements [Safari 3.0 (Tizen 3.0)]
Error: Expected 1 to be 0.
at <Jasmine>
at Function.confirmElementMissing (test/test/util/ui_utils.js:70:29 <- test/test/util/ui_utils.js:139:31)
at _callee15$ (test/ui/ui_unit.js:425:19 <- test/ui/ui_unit.js:506:27)
at tryCatch (node_modules/@babel/polyfill/dist/polyfill.js:6473:40)
```