It encapsulates and simplifies the use of requestVideoFrameCallback and
cancelVideoFrameCallback
---------
Co-authored-by: Wojciech Tyczyński <tykus160@gmail.com>
## Summary
- Adds a `customTrackLabel` callback to the UI configuration that allows
overriding track labels for both audio and text tracks
- The callback receives the default label (or `null` if the language was
unrecognized), the track object, and a type string (`'audio'` or
`'text'`)
- Returning a string overrides the label; returning falsy keeps the
default behavior
Fixes#9821
## Example usage
```javascript
ui.configure({
customTrackLabel: (defaultLabel, track, type) => {
if (track.language === 'fx') return 'Sound Effects';
return null; // use default
}
});
```
## Test plan
- Added integration tests verifying label override, null for
unrecognized languages, type argument, and fallback behavior
- Tests pass in both compiled and uncompiled modes
## AI Disclosure
As highlighted in the new `AGENT-ATTRIBUTION.md`, I've added Claude as a
co-author of the commit as I made use of it during this PR.
Signed-off-by: F1 MultiViewer <f1multiviewer@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
### Problem
Previously, click/drag in the seek bar relied on the browser's default
range entry event. The hover preview used 'getValueFromPosition()'
separately. This resulted in a mismatch between the hover timestamp and
the actual search position, This problem was particularly noticeable in
long videos.
### FIx
I modified to call `getValueFromPosition()` directory even when
click/drag. However click, drag, and touch all go through the same
function, so timestamp previews and navigation positions are always
sychronized.
In addition, I also fixed a bug where the tooltip moves instaneously
when clicking by reflecting the thumbWide correction when we reverse the
tooltip position to value in `onChange()`.
---------
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
## Problem
Previously, click/drag in the seek bar relied on the browser's default
range entry event. The hover preview used 'getValueFromPosition()'
separately. This resulted in a mismatch between the hover timestamp and
the actual search position, This problem was particularly noticeable in
long videos.
## Fix
When the mouse is down, 'e.Use preventDefault()` to block the browser's
default calculation, 'setBarValueForMouse_()' which follows the same
pattern as the existing 'setBarValueForTouch_()' Add a function to
directly call 'getValueFromPosition()' when clicking and dragging I did,
now hover, click, drag, touch all go through the same function, so
timestamp The preview and navigation positions are always synchronized.
In addition, the hard-coded 'thumbWide = 12' is 'thumbRadius = 6'
('range_elements.less') I modified it to the defined '@thumb-size') and
the browser changed the thumb [[rect.left + thumbRadius, rect.right -
thumbRadius]]' only within the range of '[rect.left + thumbRadius]',
Reflected the offset value when the click position was
reverse-calculated as a value.
---------
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
- Use EventManager instead of addEventListener
- Fix canvas resizing in edge cases
- Change default watermark type from static to dynamic
- Add smoother, configurable dynamic watermark animation
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.