vidply 1.0.7 → 1.0.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/vidply.js CHANGED
@@ -5489,6 +5489,9 @@ var VidPly = (() => {
5489
5489
  this.audioDescriptionSrc = this.options.audioDescriptionSrc;
5490
5490
  this.signLanguageSrc = this.options.signLanguageSrc;
5491
5491
  this.signLanguageVideo = null;
5492
+ this.audioDescriptionSourceElement = null;
5493
+ this.originalAudioDescriptionSource = null;
5494
+ this.audioDescriptionCaptionTracks = [];
5492
5495
  this.container = null;
5493
5496
  this.renderer = null;
5494
5497
  this.controlBar = null;
@@ -5643,6 +5646,53 @@ var VidPly = (() => {
5643
5646
  if (!src) {
5644
5647
  throw new Error("No media source found");
5645
5648
  }
5649
+ const sourceElements = this.element.querySelectorAll("source");
5650
+ for (const sourceEl of sourceElements) {
5651
+ const descSrc = sourceEl.getAttribute("data-desc-src");
5652
+ const origSrc = sourceEl.getAttribute("data-orig-src");
5653
+ if (descSrc || origSrc) {
5654
+ if (!this.audioDescriptionSourceElement) {
5655
+ this.audioDescriptionSourceElement = sourceEl;
5656
+ }
5657
+ if (origSrc) {
5658
+ if (!this.originalAudioDescriptionSource) {
5659
+ this.originalAudioDescriptionSource = origSrc;
5660
+ }
5661
+ if (!this.originalSrc) {
5662
+ this.originalSrc = origSrc;
5663
+ }
5664
+ } else {
5665
+ const currentSrcAttr = sourceEl.getAttribute("src");
5666
+ if (!this.originalAudioDescriptionSource && currentSrcAttr) {
5667
+ this.originalAudioDescriptionSource = currentSrcAttr;
5668
+ }
5669
+ if (!this.originalSrc && currentSrcAttr) {
5670
+ this.originalSrc = currentSrcAttr;
5671
+ }
5672
+ }
5673
+ if (descSrc && !this.audioDescriptionSrc) {
5674
+ this.audioDescriptionSrc = descSrc;
5675
+ }
5676
+ }
5677
+ }
5678
+ const trackElements = this.element.querySelectorAll("track");
5679
+ trackElements.forEach((trackEl) => {
5680
+ const trackKind = trackEl.getAttribute("kind");
5681
+ const trackDescSrc = trackEl.getAttribute("data-desc-src");
5682
+ if (trackKind === "captions" || trackKind === "subtitles" || trackKind === "chapters") {
5683
+ if (trackDescSrc) {
5684
+ this.audioDescriptionCaptionTracks.push({
5685
+ trackElement: trackEl,
5686
+ originalSrc: trackEl.getAttribute("src"),
5687
+ describedSrc: trackDescSrc,
5688
+ originalTrackSrc: trackEl.getAttribute("data-orig-src") || trackEl.getAttribute("src"),
5689
+ explicit: true
5690
+ // Explicitly defined, so we should validate it
5691
+ });
5692
+ this.log(`Found explicit described ${trackKind} track: ${trackEl.getAttribute("src")} -> ${trackDescSrc}`);
5693
+ }
5694
+ }
5695
+ });
5646
5696
  if (!this.originalSrc) {
5647
5697
  this.originalSrc = src;
5648
5698
  }
@@ -5927,15 +5977,396 @@ var VidPly = (() => {
5927
5977
  this.enableCaptions();
5928
5978
  }
5929
5979
  }
5980
+ /**
5981
+ * Check if a track file exists
5982
+ * @param {string} url - Track file URL
5983
+ * @returns {Promise<boolean>} - True if file exists
5984
+ */
5985
+ async validateTrackExists(url) {
5986
+ try {
5987
+ const response = await fetch(url, { method: "HEAD", cache: "no-cache" });
5988
+ return response.ok;
5989
+ } catch (error) {
5990
+ return false;
5991
+ }
5992
+ }
5930
5993
  // Audio Description
5931
5994
  async enableAudioDescription() {
5932
- if (!this.audioDescriptionSrc) {
5933
- console.warn("VidPly: No audio description source provided");
5995
+ const hasSourceElementsWithDesc = Array.from(this.element.querySelectorAll("source")).some((el) => el.getAttribute("data-desc-src"));
5996
+ const hasTracksWithDesc = this.audioDescriptionCaptionTracks.length > 0;
5997
+ if (!this.audioDescriptionSrc && !hasSourceElementsWithDesc && !hasTracksWithDesc) {
5998
+ console.warn("VidPly: No audio description source, source elements, or tracks provided");
5934
5999
  return;
5935
6000
  }
5936
6001
  const currentTime = this.state.currentTime;
5937
6002
  const wasPlaying = this.state.playing;
5938
- this.element.src = this.audioDescriptionSrc;
6003
+ let swappedTracksForTranscript = [];
6004
+ if (this.audioDescriptionSourceElement) {
6005
+ const currentSrc = this.element.currentSrc || this.element.src;
6006
+ const sourceElements = Array.from(this.element.querySelectorAll("source"));
6007
+ let sourceElementToUpdate = null;
6008
+ let descSrc = this.audioDescriptionSrc;
6009
+ for (const sourceEl of sourceElements) {
6010
+ const sourceSrc = sourceEl.getAttribute("src");
6011
+ const descSrcAttr = sourceEl.getAttribute("data-desc-src");
6012
+ const sourceFilename = sourceSrc ? sourceSrc.split("/").pop() : "";
6013
+ const currentFilename = currentSrc ? currentSrc.split("/").pop() : "";
6014
+ if (currentSrc && (currentSrc === sourceSrc || currentSrc.includes(sourceSrc) || currentSrc.includes(sourceFilename) || sourceFilename && currentFilename === sourceFilename)) {
6015
+ sourceElementToUpdate = sourceEl;
6016
+ if (descSrcAttr) {
6017
+ descSrc = descSrcAttr;
6018
+ } else if (sourceSrc) {
6019
+ descSrc = this.audioDescriptionSrc || descSrc;
6020
+ }
6021
+ break;
6022
+ }
6023
+ }
6024
+ if (!sourceElementToUpdate) {
6025
+ sourceElementToUpdate = this.audioDescriptionSourceElement;
6026
+ const storedDescSrc = sourceElementToUpdate.getAttribute("data-desc-src");
6027
+ if (storedDescSrc) {
6028
+ descSrc = storedDescSrc;
6029
+ }
6030
+ }
6031
+ if (this.audioDescriptionCaptionTracks.length > 0) {
6032
+ const validationPromises = this.audioDescriptionCaptionTracks.map(async (trackInfo) => {
6033
+ if (trackInfo.trackElement && trackInfo.describedSrc) {
6034
+ if (trackInfo.explicit === true) {
6035
+ try {
6036
+ const exists = await this.validateTrackExists(trackInfo.describedSrc);
6037
+ return { trackInfo, exists };
6038
+ } catch (error) {
6039
+ return { trackInfo, exists: false };
6040
+ }
6041
+ } else {
6042
+ return { trackInfo, exists: false };
6043
+ }
6044
+ }
6045
+ return { trackInfo, exists: false };
6046
+ });
6047
+ const validationResults = await Promise.all(validationPromises);
6048
+ const tracksToSwap = validationResults.filter((result) => result.exists);
6049
+ if (tracksToSwap.length > 0) {
6050
+ const trackModes = /* @__PURE__ */ new Map();
6051
+ tracksToSwap.forEach(({ trackInfo }) => {
6052
+ const textTrack = trackInfo.trackElement.track;
6053
+ if (textTrack) {
6054
+ trackModes.set(trackInfo, {
6055
+ wasShowing: textTrack.mode === "showing",
6056
+ wasHidden: textTrack.mode === "hidden"
6057
+ });
6058
+ } else {
6059
+ trackModes.set(trackInfo, {
6060
+ wasShowing: false,
6061
+ wasHidden: false
6062
+ });
6063
+ }
6064
+ });
6065
+ const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {
6066
+ const oldSrc = trackInfo.trackElement.getAttribute("src");
6067
+ const parent = trackInfo.trackElement.parentNode;
6068
+ const nextSibling = trackInfo.trackElement.nextSibling;
6069
+ const attributes = {};
6070
+ Array.from(trackInfo.trackElement.attributes).forEach((attr) => {
6071
+ attributes[attr.name] = attr.value;
6072
+ });
6073
+ return {
6074
+ trackInfo,
6075
+ oldSrc,
6076
+ parent,
6077
+ nextSibling,
6078
+ attributes
6079
+ };
6080
+ });
6081
+ tracksToReadd.forEach(({ trackInfo }) => {
6082
+ trackInfo.trackElement.remove();
6083
+ });
6084
+ this.element.load();
6085
+ setTimeout(() => {
6086
+ tracksToReadd.forEach(({ trackInfo, oldSrc, parent, nextSibling, attributes }) => {
6087
+ swappedTracksForTranscript.push(trackInfo);
6088
+ const newTrackElement = document.createElement("track");
6089
+ newTrackElement.setAttribute("src", trackInfo.describedSrc);
6090
+ Object.keys(attributes).forEach((attrName) => {
6091
+ if (attrName !== "src" && attrName !== "data-desc-src") {
6092
+ newTrackElement.setAttribute(attrName, attributes[attrName]);
6093
+ }
6094
+ });
6095
+ if (nextSibling && nextSibling.parentNode) {
6096
+ parent.insertBefore(newTrackElement, nextSibling);
6097
+ } else {
6098
+ parent.appendChild(newTrackElement);
6099
+ }
6100
+ trackInfo.trackElement = newTrackElement;
6101
+ });
6102
+ this.element.load();
6103
+ const setupNewTracks = () => {
6104
+ setTimeout(() => {
6105
+ swappedTracksForTranscript.forEach((trackInfo) => {
6106
+ const trackElement = trackInfo.trackElement;
6107
+ const newTextTrack = trackElement.track;
6108
+ if (newTextTrack) {
6109
+ const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };
6110
+ newTextTrack.mode = "hidden";
6111
+ const restoreMode = () => {
6112
+ if (modeInfo.wasShowing) {
6113
+ newTextTrack.mode = "hidden";
6114
+ } else if (modeInfo.wasHidden) {
6115
+ newTextTrack.mode = "hidden";
6116
+ } else {
6117
+ newTextTrack.mode = "disabled";
6118
+ }
6119
+ };
6120
+ if (newTextTrack.readyState >= 2) {
6121
+ restoreMode();
6122
+ } else {
6123
+ newTextTrack.addEventListener("load", restoreMode, { once: true });
6124
+ newTextTrack.addEventListener("error", restoreMode, { once: true });
6125
+ }
6126
+ }
6127
+ });
6128
+ }, 300);
6129
+ };
6130
+ if (this.element.readyState >= 1) {
6131
+ setTimeout(setupNewTracks, 200);
6132
+ } else {
6133
+ this.element.addEventListener("loadedmetadata", setupNewTracks, { once: true });
6134
+ setTimeout(setupNewTracks, 2e3);
6135
+ }
6136
+ }, 100);
6137
+ const skippedCount = validationResults.length - tracksToSwap.length;
6138
+ }
6139
+ }
6140
+ const allSourceElements = Array.from(this.element.querySelectorAll("source"));
6141
+ const sourcesToUpdate = [];
6142
+ allSourceElements.forEach((sourceEl) => {
6143
+ const descSrcAttr = sourceEl.getAttribute("data-desc-src");
6144
+ const currentSrc2 = sourceEl.getAttribute("src");
6145
+ if (descSrcAttr) {
6146
+ const type = sourceEl.getAttribute("type");
6147
+ let origSrc = sourceEl.getAttribute("data-orig-src");
6148
+ if (!origSrc) {
6149
+ origSrc = currentSrc2;
6150
+ }
6151
+ sourcesToUpdate.push({
6152
+ src: descSrcAttr,
6153
+ // Use described version
6154
+ type,
6155
+ origSrc,
6156
+ descSrc: descSrcAttr
6157
+ });
6158
+ } else {
6159
+ const type = sourceEl.getAttribute("type");
6160
+ const src = sourceEl.getAttribute("src");
6161
+ sourcesToUpdate.push({
6162
+ src,
6163
+ type,
6164
+ origSrc: null,
6165
+ descSrc: null
6166
+ });
6167
+ }
6168
+ });
6169
+ allSourceElements.forEach((sourceEl) => {
6170
+ sourceEl.remove();
6171
+ });
6172
+ sourcesToUpdate.forEach((sourceInfo) => {
6173
+ const newSource = document.createElement("source");
6174
+ newSource.setAttribute("src", sourceInfo.src);
6175
+ if (sourceInfo.type) {
6176
+ newSource.setAttribute("type", sourceInfo.type);
6177
+ }
6178
+ if (sourceInfo.origSrc) {
6179
+ newSource.setAttribute("data-orig-src", sourceInfo.origSrc);
6180
+ }
6181
+ if (sourceInfo.descSrc) {
6182
+ newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
6183
+ }
6184
+ this.element.appendChild(newSource);
6185
+ });
6186
+ this.element.load();
6187
+ await new Promise((resolve) => {
6188
+ const onLoadedMetadata = () => {
6189
+ this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
6190
+ resolve();
6191
+ };
6192
+ this.element.addEventListener("loadedmetadata", onLoadedMetadata);
6193
+ });
6194
+ await new Promise((resolve) => setTimeout(resolve, 300));
6195
+ if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
6196
+ if (this.element.readyState >= 1) {
6197
+ this.element.currentTime = 1e-3;
6198
+ setTimeout(() => {
6199
+ this.element.currentTime = 0;
6200
+ }, 10);
6201
+ }
6202
+ }
6203
+ this.seek(currentTime);
6204
+ if (wasPlaying) {
6205
+ this.play();
6206
+ }
6207
+ this.state.audioDescriptionEnabled = true;
6208
+ this.emit("audiodescriptionenabled");
6209
+ } else {
6210
+ if (this.audioDescriptionCaptionTracks.length > 0) {
6211
+ const validationPromises = this.audioDescriptionCaptionTracks.map(async (trackInfo) => {
6212
+ if (trackInfo.trackElement && trackInfo.describedSrc) {
6213
+ if (trackInfo.explicit === true) {
6214
+ try {
6215
+ const exists = await this.validateTrackExists(trackInfo.describedSrc);
6216
+ return { trackInfo, exists };
6217
+ } catch (error) {
6218
+ return { trackInfo, exists: false };
6219
+ }
6220
+ } else {
6221
+ return { trackInfo, exists: false };
6222
+ }
6223
+ }
6224
+ return { trackInfo, exists: false };
6225
+ });
6226
+ const validationResults = await Promise.all(validationPromises);
6227
+ const tracksToSwap = validationResults.filter((result) => result.exists);
6228
+ if (tracksToSwap.length > 0) {
6229
+ const trackModes = /* @__PURE__ */ new Map();
6230
+ tracksToSwap.forEach(({ trackInfo }) => {
6231
+ const textTrack = trackInfo.trackElement.track;
6232
+ if (textTrack) {
6233
+ trackModes.set(trackInfo, {
6234
+ wasShowing: textTrack.mode === "showing",
6235
+ wasHidden: textTrack.mode === "hidden"
6236
+ });
6237
+ } else {
6238
+ trackModes.set(trackInfo, {
6239
+ wasShowing: false,
6240
+ wasHidden: false
6241
+ });
6242
+ }
6243
+ });
6244
+ const tracksToReadd = tracksToSwap.map(({ trackInfo }) => {
6245
+ const oldSrc = trackInfo.trackElement.getAttribute("src");
6246
+ const parent = trackInfo.trackElement.parentNode;
6247
+ const nextSibling = trackInfo.trackElement.nextSibling;
6248
+ const attributes = {};
6249
+ Array.from(trackInfo.trackElement.attributes).forEach((attr) => {
6250
+ attributes[attr.name] = attr.value;
6251
+ });
6252
+ return {
6253
+ trackInfo,
6254
+ oldSrc,
6255
+ parent,
6256
+ nextSibling,
6257
+ attributes
6258
+ };
6259
+ });
6260
+ tracksToReadd.forEach(({ trackInfo }) => {
6261
+ trackInfo.trackElement.remove();
6262
+ });
6263
+ this.element.load();
6264
+ setTimeout(() => {
6265
+ tracksToReadd.forEach(({ trackInfo, oldSrc, parent, nextSibling, attributes }) => {
6266
+ swappedTracksForTranscript.push(trackInfo);
6267
+ const newTrackElement = document.createElement("track");
6268
+ newTrackElement.setAttribute("src", trackInfo.describedSrc);
6269
+ Object.keys(attributes).forEach((attrName) => {
6270
+ if (attrName !== "src" && attrName !== "data-desc-src") {
6271
+ newTrackElement.setAttribute(attrName, attributes[attrName]);
6272
+ }
6273
+ });
6274
+ if (nextSibling && nextSibling.parentNode) {
6275
+ parent.insertBefore(newTrackElement, nextSibling);
6276
+ } else {
6277
+ parent.appendChild(newTrackElement);
6278
+ }
6279
+ trackInfo.trackElement = newTrackElement;
6280
+ });
6281
+ this.element.load();
6282
+ const setupNewTracks = () => {
6283
+ setTimeout(() => {
6284
+ swappedTracksForTranscript.forEach((trackInfo) => {
6285
+ const trackElement = trackInfo.trackElement;
6286
+ const newTextTrack = trackElement.track;
6287
+ if (newTextTrack) {
6288
+ const modeInfo = trackModes.get(trackInfo) || { wasShowing: false, wasHidden: false };
6289
+ newTextTrack.mode = "hidden";
6290
+ const restoreMode = () => {
6291
+ if (modeInfo.wasShowing) {
6292
+ newTextTrack.mode = "hidden";
6293
+ } else if (modeInfo.wasHidden) {
6294
+ newTextTrack.mode = "hidden";
6295
+ } else {
6296
+ newTextTrack.mode = "disabled";
6297
+ }
6298
+ };
6299
+ if (newTextTrack.readyState >= 2) {
6300
+ restoreMode();
6301
+ } else {
6302
+ newTextTrack.addEventListener("load", restoreMode, { once: true });
6303
+ newTextTrack.addEventListener("error", restoreMode, { once: true });
6304
+ }
6305
+ }
6306
+ });
6307
+ }, 300);
6308
+ };
6309
+ if (this.element.readyState >= 1) {
6310
+ setTimeout(setupNewTracks, 200);
6311
+ } else {
6312
+ this.element.addEventListener("loadedmetadata", setupNewTracks, { once: true });
6313
+ setTimeout(setupNewTracks, 2e3);
6314
+ }
6315
+ }, 100);
6316
+ }
6317
+ }
6318
+ const fallbackSourceElements = Array.from(this.element.querySelectorAll("source"));
6319
+ const hasSourceElementsWithDesc2 = fallbackSourceElements.some((el) => el.getAttribute("data-desc-src"));
6320
+ if (hasSourceElementsWithDesc2) {
6321
+ const fallbackSourcesToUpdate = [];
6322
+ fallbackSourceElements.forEach((sourceEl) => {
6323
+ const descSrcAttr = sourceEl.getAttribute("data-desc-src");
6324
+ const currentSrc = sourceEl.getAttribute("src");
6325
+ if (descSrcAttr) {
6326
+ const type = sourceEl.getAttribute("type");
6327
+ let origSrc = sourceEl.getAttribute("data-orig-src");
6328
+ if (!origSrc) {
6329
+ origSrc = currentSrc;
6330
+ }
6331
+ fallbackSourcesToUpdate.push({
6332
+ src: descSrcAttr,
6333
+ type,
6334
+ origSrc,
6335
+ descSrc: descSrcAttr
6336
+ });
6337
+ } else {
6338
+ const type = sourceEl.getAttribute("type");
6339
+ const src = sourceEl.getAttribute("src");
6340
+ fallbackSourcesToUpdate.push({
6341
+ src,
6342
+ type,
6343
+ origSrc: null,
6344
+ descSrc: null
6345
+ });
6346
+ }
6347
+ });
6348
+ fallbackSourceElements.forEach((sourceEl) => {
6349
+ sourceEl.remove();
6350
+ });
6351
+ fallbackSourcesToUpdate.forEach((sourceInfo) => {
6352
+ const newSource = document.createElement("source");
6353
+ newSource.setAttribute("src", sourceInfo.src);
6354
+ if (sourceInfo.type) {
6355
+ newSource.setAttribute("type", sourceInfo.type);
6356
+ }
6357
+ if (sourceInfo.origSrc) {
6358
+ newSource.setAttribute("data-orig-src", sourceInfo.origSrc);
6359
+ }
6360
+ if (sourceInfo.descSrc) {
6361
+ newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
6362
+ }
6363
+ this.element.appendChild(newSource);
6364
+ });
6365
+ this.element.load();
6366
+ } else {
6367
+ this.element.src = this.audioDescriptionSrc;
6368
+ }
6369
+ }
5939
6370
  await new Promise((resolve) => {
5940
6371
  const onLoadedMetadata = () => {
5941
6372
  this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
@@ -5943,10 +6374,183 @@ var VidPly = (() => {
5943
6374
  };
5944
6375
  this.element.addEventListener("loadedmetadata", onLoadedMetadata);
5945
6376
  });
6377
+ if (this.element.tagName === "VIDEO" && currentTime === 0 && !wasPlaying) {
6378
+ if (this.element.readyState >= 1) {
6379
+ this.element.currentTime = 1e-3;
6380
+ setTimeout(() => {
6381
+ this.element.currentTime = 0;
6382
+ }, 10);
6383
+ }
6384
+ }
5946
6385
  this.seek(currentTime);
5947
6386
  if (wasPlaying) {
5948
6387
  this.play();
5949
6388
  }
6389
+ if (swappedTracksForTranscript.length > 0 && this.captionManager) {
6390
+ const wasCaptionsEnabled = this.state.captionsEnabled;
6391
+ let currentTrackInfo = null;
6392
+ if (this.captionManager.currentTrack) {
6393
+ const currentTrackIndex = this.captionManager.tracks.findIndex((t) => t.track === this.captionManager.currentTrack.track);
6394
+ if (currentTrackIndex >= 0) {
6395
+ currentTrackInfo = {
6396
+ language: this.captionManager.tracks[currentTrackIndex].language,
6397
+ kind: this.captionManager.tracks[currentTrackIndex].kind
6398
+ };
6399
+ }
6400
+ }
6401
+ setTimeout(() => {
6402
+ this.captionManager.tracks = [];
6403
+ this.captionManager.loadTracks();
6404
+ if (wasCaptionsEnabled && currentTrackInfo && this.captionManager.tracks.length > 0) {
6405
+ const matchingTrackIndex = this.captionManager.tracks.findIndex(
6406
+ (t) => t.language === currentTrackInfo.language && t.kind === currentTrackInfo.kind
6407
+ );
6408
+ if (matchingTrackIndex >= 0) {
6409
+ this.captionManager.enable(matchingTrackIndex);
6410
+ } else if (this.captionManager.tracks.length > 0) {
6411
+ this.captionManager.enable(0);
6412
+ }
6413
+ }
6414
+ }, 600);
6415
+ }
6416
+ if (this.transcriptManager && this.transcriptManager.isVisible) {
6417
+ const swappedTracks = typeof swappedTracksForTranscript !== "undefined" ? swappedTracksForTranscript : [];
6418
+ if (swappedTracks.length > 0) {
6419
+ const onMetadataLoaded = () => {
6420
+ const allTextTracks = Array.from(this.element.textTracks);
6421
+ const freshTracks = swappedTracks.map((trackInfo) => {
6422
+ const trackEl = trackInfo.trackElement;
6423
+ const expectedSrc = trackEl.getAttribute("src");
6424
+ const srclang = trackEl.getAttribute("srclang");
6425
+ const kind = trackEl.getAttribute("kind");
6426
+ let foundTrack = allTextTracks.find((track) => trackEl.track === track);
6427
+ if (!foundTrack) {
6428
+ foundTrack = allTextTracks.find((track) => {
6429
+ if (track.language === srclang && (track.kind === kind || kind === "captions" && track.kind === "subtitles")) {
6430
+ const trackElementForTrack = Array.from(this.element.querySelectorAll("track")).find(
6431
+ (el) => el.track === track
6432
+ );
6433
+ if (trackElementForTrack) {
6434
+ const actualSrc = trackElementForTrack.getAttribute("src");
6435
+ if (actualSrc === expectedSrc) {
6436
+ return true;
6437
+ }
6438
+ }
6439
+ }
6440
+ return false;
6441
+ });
6442
+ }
6443
+ if (foundTrack) {
6444
+ const trackElement = Array.from(this.element.querySelectorAll("track")).find(
6445
+ (el) => el.track === foundTrack
6446
+ );
6447
+ if (trackElement && trackElement.getAttribute("src") !== expectedSrc) {
6448
+ return null;
6449
+ }
6450
+ }
6451
+ return foundTrack;
6452
+ }).filter(Boolean);
6453
+ if (freshTracks.length === 0) {
6454
+ setTimeout(() => {
6455
+ if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
6456
+ this.transcriptManager.loadTranscriptData();
6457
+ }
6458
+ }, 1e3);
6459
+ return;
6460
+ }
6461
+ freshTracks.forEach((track) => {
6462
+ if (track.mode === "disabled") {
6463
+ track.mode = "hidden";
6464
+ }
6465
+ });
6466
+ let loadedCount = 0;
6467
+ const checkLoaded = () => {
6468
+ loadedCount++;
6469
+ if (loadedCount >= freshTracks.length) {
6470
+ setTimeout(() => {
6471
+ if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
6472
+ const allTextTracks2 = Array.from(this.element.textTracks);
6473
+ const swappedTrackSrcs = swappedTracks.map((t) => t.describedSrc);
6474
+ const hasCorrectTracks = freshTracks.some((track) => {
6475
+ const trackEl = Array.from(this.element.querySelectorAll("track")).find(
6476
+ (el) => el.track === track
6477
+ );
6478
+ return trackEl && swappedTrackSrcs.includes(trackEl.getAttribute("src"));
6479
+ });
6480
+ if (hasCorrectTracks || freshTracks.length > 0) {
6481
+ this.transcriptManager.loadTranscriptData();
6482
+ }
6483
+ }
6484
+ }, 800);
6485
+ }
6486
+ };
6487
+ freshTracks.forEach((track) => {
6488
+ if (track.mode === "disabled") {
6489
+ track.mode = "hidden";
6490
+ }
6491
+ const trackElementForTrack = Array.from(this.element.querySelectorAll("track")).find(
6492
+ (el) => el.track === track
6493
+ );
6494
+ const actualSrc = trackElementForTrack ? trackElementForTrack.getAttribute("src") : null;
6495
+ const expectedTrackInfo = swappedTracks.find((t) => {
6496
+ const tEl = t.trackElement;
6497
+ return tEl && (tEl.track === track || tEl.getAttribute("srclang") === track.language && tEl.getAttribute("kind") === track.kind);
6498
+ });
6499
+ const expectedSrc = expectedTrackInfo ? expectedTrackInfo.describedSrc : null;
6500
+ if (expectedSrc && actualSrc && actualSrc !== expectedSrc) {
6501
+ checkLoaded();
6502
+ return;
6503
+ }
6504
+ if (track.readyState >= 2 && track.cues && track.cues.length > 0) {
6505
+ checkLoaded();
6506
+ } else {
6507
+ if (track.mode === "disabled") {
6508
+ track.mode = "hidden";
6509
+ }
6510
+ const onTrackLoad = () => {
6511
+ setTimeout(checkLoaded, 300);
6512
+ };
6513
+ if (track.readyState >= 2) {
6514
+ setTimeout(() => {
6515
+ if (track.cues && track.cues.length > 0) {
6516
+ checkLoaded();
6517
+ } else {
6518
+ track.addEventListener("load", onTrackLoad, { once: true });
6519
+ }
6520
+ }, 100);
6521
+ } else {
6522
+ track.addEventListener("load", onTrackLoad, { once: true });
6523
+ track.addEventListener("error", () => {
6524
+ checkLoaded();
6525
+ }, { once: true });
6526
+ }
6527
+ }
6528
+ });
6529
+ };
6530
+ const waitForTracks = () => {
6531
+ setTimeout(() => {
6532
+ if (this.element.readyState >= 1) {
6533
+ onMetadataLoaded();
6534
+ } else {
6535
+ this.element.addEventListener("loadedmetadata", onMetadataLoaded, { once: true });
6536
+ setTimeout(onMetadataLoaded, 2e3);
6537
+ }
6538
+ }, 500);
6539
+ };
6540
+ waitForTracks();
6541
+ setTimeout(() => {
6542
+ if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
6543
+ this.transcriptManager.loadTranscriptData();
6544
+ }
6545
+ }, 5e3);
6546
+ } else {
6547
+ setTimeout(() => {
6548
+ if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
6549
+ this.transcriptManager.loadTranscriptData();
6550
+ }
6551
+ }, 800);
6552
+ }
6553
+ }
5950
6554
  this.state.audioDescriptionEnabled = true;
5951
6555
  this.emit("audiodescriptionenabled");
5952
6556
  }
@@ -5956,7 +6560,64 @@ var VidPly = (() => {
5956
6560
  }
5957
6561
  const currentTime = this.state.currentTime;
5958
6562
  const wasPlaying = this.state.playing;
5959
- this.element.src = this.originalSrc;
6563
+ if (this.audioDescriptionCaptionTracks.length > 0) {
6564
+ this.audioDescriptionCaptionTracks.forEach((trackInfo) => {
6565
+ if (trackInfo.trackElement && trackInfo.originalTrackSrc) {
6566
+ trackInfo.trackElement.setAttribute("src", trackInfo.originalTrackSrc);
6567
+ }
6568
+ });
6569
+ }
6570
+ const allSourceElements = Array.from(this.element.querySelectorAll("source"));
6571
+ const hasSourceElementsToSwap = allSourceElements.some((el) => el.getAttribute("data-orig-src"));
6572
+ if (hasSourceElementsToSwap) {
6573
+ const sourcesToRestore = [];
6574
+ allSourceElements.forEach((sourceEl) => {
6575
+ const origSrcAttr = sourceEl.getAttribute("data-orig-src");
6576
+ const descSrcAttr = sourceEl.getAttribute("data-desc-src");
6577
+ if (origSrcAttr) {
6578
+ const type = sourceEl.getAttribute("type");
6579
+ sourcesToRestore.push({
6580
+ src: origSrcAttr,
6581
+ // Use original version
6582
+ type,
6583
+ origSrc: origSrcAttr,
6584
+ descSrc: descSrcAttr
6585
+ // Keep data-desc-src for future swaps
6586
+ });
6587
+ } else {
6588
+ const type = sourceEl.getAttribute("type");
6589
+ const src = sourceEl.getAttribute("src");
6590
+ sourcesToRestore.push({
6591
+ src,
6592
+ type,
6593
+ origSrc: null,
6594
+ descSrc: descSrcAttr
6595
+ });
6596
+ }
6597
+ });
6598
+ allSourceElements.forEach((sourceEl) => {
6599
+ sourceEl.remove();
6600
+ });
6601
+ sourcesToRestore.forEach((sourceInfo) => {
6602
+ const newSource = document.createElement("source");
6603
+ newSource.setAttribute("src", sourceInfo.src);
6604
+ if (sourceInfo.type) {
6605
+ newSource.setAttribute("type", sourceInfo.type);
6606
+ }
6607
+ if (sourceInfo.origSrc) {
6608
+ newSource.setAttribute("data-orig-src", sourceInfo.origSrc);
6609
+ }
6610
+ if (sourceInfo.descSrc) {
6611
+ newSource.setAttribute("data-desc-src", sourceInfo.descSrc);
6612
+ }
6613
+ this.element.appendChild(newSource);
6614
+ });
6615
+ this.element.load();
6616
+ } else {
6617
+ const originalSrcToUse = this.originalAudioDescriptionSource || this.originalSrc;
6618
+ this.element.src = originalSrcToUse;
6619
+ this.element.load();
6620
+ }
5960
6621
  await new Promise((resolve) => {
5961
6622
  const onLoadedMetadata = () => {
5962
6623
  this.element.removeEventListener("loadedmetadata", onLoadedMetadata);
@@ -5968,13 +6629,29 @@ var VidPly = (() => {
5968
6629
  if (wasPlaying) {
5969
6630
  this.play();
5970
6631
  }
6632
+ if (this.transcriptManager && this.transcriptManager.isVisible) {
6633
+ setTimeout(() => {
6634
+ if (this.transcriptManager && this.transcriptManager.loadTranscriptData) {
6635
+ this.transcriptManager.loadTranscriptData();
6636
+ }
6637
+ }, 500);
6638
+ }
5971
6639
  this.state.audioDescriptionEnabled = false;
5972
6640
  this.emit("audiodescriptiondisabled");
5973
6641
  }
5974
6642
  async toggleAudioDescription() {
5975
6643
  const textTracks = Array.from(this.element.textTracks || []);
5976
6644
  const descriptionTrack = textTracks.find((track) => track.kind === "descriptions");
5977
- if (descriptionTrack) {
6645
+ const hasAudioDescriptionSrc = this.audioDescriptionSrc || Array.from(this.element.querySelectorAll("source")).some((el) => el.getAttribute("data-desc-src"));
6646
+ if (descriptionTrack && hasAudioDescriptionSrc) {
6647
+ if (this.state.audioDescriptionEnabled) {
6648
+ descriptionTrack.mode = "hidden";
6649
+ await this.disableAudioDescription();
6650
+ } else {
6651
+ await this.enableAudioDescription();
6652
+ descriptionTrack.mode = "showing";
6653
+ }
6654
+ } else if (descriptionTrack) {
5978
6655
  if (descriptionTrack.mode === "showing") {
5979
6656
  descriptionTrack.mode = "hidden";
5980
6657
  this.state.audioDescriptionEnabled = false;
@@ -5984,7 +6661,7 @@ var VidPly = (() => {
5984
6661
  this.state.audioDescriptionEnabled = true;
5985
6662
  this.emit("audiodescriptionenabled");
5986
6663
  }
5987
- } else if (this.audioDescriptionSrc) {
6664
+ } else if (hasAudioDescriptionSrc) {
5988
6665
  if (this.state.audioDescriptionEnabled) {
5989
6666
  await this.disableAudioDescription();
5990
6667
  } else {