Skip to content

develop: YouTube playback is fully broken — four regressions since 5.0.0 (17 of 60 demo pages throw) #775

Description

@blogcastAI

Describe the bug

A build of current develop cannot play a YouTube video, and 17 of the repository's own 60 demo pages throw a JavaScript error during player initialization. We hit this while preparing to adopt the 5.1.0 line and traced it to four independent regressions, none of which exist in the released 5.0.0. Filing them together because two share an origin commit and the fixes overlap; happy to split into separate issues if you prefer.

We have working fixes for all four (plus a fifth, smaller Vimeo one) running in our fork, each on its own branch cut from develop, and we're glad to open them as PRs in whatever form suits you — after #770/#771/#773, we didn't want to stack more unrequested PRs, so this is a report first.

Version tested

Develop (the next release). Verified NOT present in v5.0.0 (details per item). Also worth noting: the committed build/ directory currently predates all of these (its banner says V5.0.0, last rebuilt in June), so testing against the checked-in bundles masks every one of them — they only appear after a fresh npm run build.


1. initSignLanguage throws for any media element with no <source> children — this alone breaks every YouTube demo

scripts/sign.js:9:

var hasLocalSrc = ( this.sources[0].getAttribute('data-sign-src') !== undefined &&  );

getSources() (scripts/initialize.js:377) returns [] when the media element has no <source> children — the normal markup for a YouTube-only embed, e.g. demos/youtube1.html:

<video id="video1" data-able-player preload="auto" data-youtube-nocookie="true"
       data-youtube-id="dhwpLACAls8" data-youtube-desc-id="Ck2TdVMhWcU" playsinline></video>

So this.sources[0] is undefined and the call throws:

TypeError: Cannot read properties of undefined (reading 'getAttribute')
    at AblePlayer.initSignLanguage
    at AblePlayer.recreatePlayer

initSignLanguage() is called unconditionally from recreatePlayer() (scripts/initialize.js:433) before initPlayer(), so the player is never built: the IFrame API is never requested, window.YT stays undefined, and the page degrades to a bare <video>. scripts/description.js:38 has the same unguarded read and throws next if only sign.js is patched (note the audio early-exit at description.js:31–33 resolves its deferred but doesn't return, so it falls through to that line).

Origin: 834d003 converted these reads from this.$sources.first().attr(…) — which returns undefined on an empty jQuery set — to this.sources[0].getAttribute(…), which throws.

Same commit also changed the absent-attribute sentinel: .attr() returned undefined for a missing attribute, getAttribute() returns null. The surrounding !== undefined / typeof !== 'undefined' tests therefore now read a missing attribute as present — e.g. every video without a described version still sets hasOpenDesc = true once execution gets that far.

2. All data-youtube-* attributes are silently ignored (wrong dataset keys)

scripts/ableplayer-base.js reads:

let youTubeId = options.youTubeId ?? data.youTubeId;

where data = media[0].dataset. But dataset keys are derived from the attribute name — data-youtube-id is dataset.youtubeId (one word, lowercase y, no capital T). data.youTubeId would correspond to a data-you-tube-id attribute, which doesn't exist. Same for youTubeDescId, youTubeSignId (5.0.0 read this from data-youtube-sign-src, so the correct key is youtubeSignSrc), and youTubeNoCookie (data-youtube-nocookieyoutubeNocookie).

Result: even with item 1 patched, every YouTube demo loads with no errors but no video — the instance reports player: 'html5', youTubeId undefined, youTubeNoCookie false, and zero network requests toward the IFrame API. This one is easy to miss precisely because it's silent.

Origin: 2d4a1c2 ("Get data attributes from dataset instead of jQuery object") — $(media).data('youtube-id') resolved the hyphenated name correctly; the dataset reads kept the API's youTube* spelling.

3. Constructor throws for a selector string or bare element

Same commit, same file: let data = media[0].dataset; indexes the constructor argument directly. For a selector string (new AblePlayer('#video1'), used by demos/translations.html) media[0] is the character #; for a bare element it's undefined. Both throw on .dataset. Only a jQuery object works, though all three forms are documented and the constructor's own guard two lines up already uses $(media). (demos/search2.html and demos/translations.html fail on this today.) Fix is one call: $(media)[0].dataset, matching the width reads at lines 330/334 of the same file.

4. syncTrackLanguages throws for any player without a transcript

scripts/control.js:

if ( ( ! this.$transcriptArea.is(':visible') && source === 'captions' ) || source === 'init' || source === 'transcript' ) {

$transcriptArea is only assigned when a transcript is built, and && evaluates left-to-right, so the .is() call runs before source is examined — including for source === 'init', i.e. normal player construction via initDefaultCaption. Any player with captions but no transcript throws here. Reordering the test (and using the same typeof this.$transcriptArea === 'undefined' idiom refreshControls() already uses at control.js:1618) fixes it. Origin: 05e9a22 ("Update language switching"); the line doesn't exist in 5.0.0.

5. (Smaller, Vimeo) getVimeoId throws on a bare ID string

scripts/vimeo.js:269 runs new URL(url) with only a typeof url === 'number' guard above it. Every caller passes a string read from data-vimeo-id/.attr(), so the documented data-vimeo-id="76979871" markup reaches new URL('76979871')TypeError: Failed to construct 'URL': Invalid URL. scripts/validate.js:244 already shows the safe pattern (try/catch + base origin). Both Vimeo demos fail on this today.


To Reproduce

  1. Fresh clone of develop; npm ci && npm run build (important — the committed build/ predates these regressions).
  2. Serve the repo root and open demos/youtube1.html with the console open.
  3. See the initSignLanguage TypeError (item 1). Patch item 1 alone and reload: no errors, but also no YouTube iframe and window.YT undefined (item 2). demos/translations.html and demos/vimeo1.html show items 3 and 5.

Measured across all 60 demo pages in headless Chromium (autoplay-policy errors excluded): 17 pages throw on develop; 0 throw with the five fixes applied. The full per-page breakdown: all 6 youtube demos + both vimeo demos + other-noa11y, other-width, search2, translations and 5 others.

Expected behavior

YouTube/Vimeo demos initialize and play as they do on v5.0.0; media elements without <source> children construct normally; all documented constructor argument forms work.

Desktop:

  • OS: Windows 11 / Linux (CI)
  • Browser: Chromium 145 (headless and headed) — but all five are environment-independent logic errors.

If it's useful: our fixes are live and testable at https://ableplayer.perkslocker.com/demos/ (our fork's develop plus these guards — every page loads clean there). Say the word and I'll open them as PRs, individually or as one branch, whichever you'd rather review.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions