PageSourceSearch

https://wudang.academy/media-player-fixes-v13.js?v=13

js wudang.academy collected 2026-10-08 12:13:23 UTC 18,038 bytes, 381 lines download raw bytes

1/* AIO shared player fixes v12: preserve native media-ticket authorization; defer legacy probes until authorized; retain legacy subtitle behavior only for legacy players. */
2;(function(){
3  function cleanUrl(value){
4    return String(value||"").trim().replace(/^['"]|['"]$/g,"");
5  }
6  function renditionLabelFromUrl(value){
7    var clean=cleanUrl(value).split("?")[0].split("#")[0];
8    var match=clean.match(/-(360p|480p|720p|1080p|1440p|2160p|4K)(?:\.[^.]+)?$/i);
9    if(!match)return "";
10    var label=match[1];
11    return label.toLowerCase()==="4k"?"4K":label.toLowerCase();
12  }
13  function renditionRank(label){
14    return {"360p":1,"480p":2,"720p":3,"1080p":4,"1440p":5,"2160p":6,"4K":6}[String(label||"")]||99;
15  }
16  function comparableUrl(value){
17    var clean=cleanUrl(value);
18    if(!clean)return "";
19    try{return new URL(clean,window.location.href).href}catch(_e){return clean}
20  }
21  function normalizedVariants(value){
22    var seen={};
23    return (Array.isArray(value)?value:[]).map(function(variant){
24      var next=Object.assign({},variant||{});
25      next.url=cleanUrl(next.url||next.src);
26      next.label=String(next.label||renditionLabelFromUrl(next.url)||"").trim();
27      return next;
28    }).filter(function(variant){
29      var key=comparableUrl(variant.url);
30      if(!key||seen[key])return false;
31      seen[key]=true;
32      return true;
33    }).sort(function(left,right){
34      return renditionRank(left.label)-renditionRank(right.label);
35    });
36  }
37  function mediaBaseName(url){
38    var clean=cleanUrl(url).split("?")[0].split("#")[0];
39    var file=(clean.split("/").pop()||"").trim();
40    return file.replace(/\.[^.]+$/,"").replace(/-(?:360p|480p|720p|1080p|1440p|2160p|4K|raw)$/i,"");
41  }
42  function localAudioUrl(src){
43    var raw=cleanUrl(src);
44    var base=mediaBaseName(raw);
45    if(!base)return "";
46    if(raw.indexOf("/media/")===0)return "/media/"+base+"-audio.ogg";
47    return raw.replace(/\/[^/?#]+(?=([?#]|$))/,"/"+base+"-audio.ogg");
48  }
49  function isDerivedAudioUrl(url){
50    var clean=cleanUrl(url).split("?")[0].split("#")[0];
51    return /-audio\.ogg$/i.test(clean);
52  }
53  function isLocalMediaUrl(url){
54    var raw=cleanUrl(url);
55    if(!raw)return false;
56    if(raw.indexOf("/media/")===0)return true;
57    try{
58      var parsed=new URL(raw,window.location.href);
59      return parsed.origin===window.location.origin&&parsed.pathname.indexOf("/media/")===0;
60    }catch(_e){return false}
61  }
62  function isPermanentlyMissingResponse(response){
63    return !!response&&(response.status===404||response.status===410);
64  }
65  function normalizeOptions(opts){
66    var next=Object.assign({},opts||{});
67    if(next.mode==="video"&&next.src){
68      next.variants=normalizedVariants(next.variants);
69      var sourceUrl=comparableUrl(next.src);
70      var matchingVariant=next.variants.find(function(variant){return comparableUrl(variant.url)===sourceUrl});
71      var actualSourceLabel=matchingVariant&&matchingVariant.label||renditionLabelFromUrl(next.src);
72      if(actualSourceLabel)next.resolution=actualSourceLabel;
73      var base=mediaBaseName(next.src);
74      if(base){
75        if(!next.subtitleBase||/-(?:360p|480p|720p|1080p|1440p|2160p|4K|raw)$/i.test(next.subtitleBase))next.subtitleBase=base;
76        if(!next.audioSrc||isDerivedAudioUrl(next.audioSrc)){
77          next.derivedAudioSrc=localAudioUrl(next.src)||next.audioSrc||"";
78          if(isDerivedAudioUrl(next.audioSrc))next.audioSrc="";
79        }
80      }
81    }
82    return next;
83  }
84  function syncActualQualityLabel(player){
85    if(!player||!player.media||!player.qualityDisplayEl)return;
86    var current=comparableUrl(player.media.currentSrc||player.media.src||player.opts&&player.opts.src);
87    var variants=normalizedVariants(player.variants||player.opts&&player.opts.variants);
88    var match=variants.find(function(variant){return comparableUrl(variant.url)===current});
89    var label=match&&match.label||renditionLabelFromUrl(current)||player.__aioSelectedRendition&&player.__aioSelectedRendition.label||player.opts&&player.opts.resolution;
90    if(label)player.qualityDisplayEl.textContent=label;
91  }
92  function installRenditionFallback(player){
93    if(!player||player.__aioRenditionFallbackInstalled||!player.media||typeof player.media.addEventListener!=="function")return;
94    player.__aioRenditionFallbackInstalled=true;
95    var variants=normalizedVariants(player.variants||player.opts&&player.opts.variants);
96    if(!variants.length)return;
97    var selected=variants.find(function(variant){
98      return comparableUrl(variant.url)===comparableUrl(player.opts&&player.opts.src);
99    })||variants[variants.length-1];
100    player.__aioSelectedRendition=selected;
101    function fallBackFrom(failed){
102      var current=player.__aioSelectedRendition;
103      if(failed&&comparableUrl(current&&current.url)!==comparableUrl(failed.url))return null;
104      var index=variants.findIndex(function(variant){
105        return comparableUrl(variant.url)===comparableUrl(current&&current.url);
106      });
107      if(index<0)index=variants.length;
108      var fallback=index>0?variants[index-1]:null;
109      if(!fallback||!fallback.url)return null;
110      player.__aioSelectedRendition=fallback;
111      player.opts.src=fallback.url;
112      player.opts.resolution=fallback.label||renditionLabelFromUrl(fallback.url)||player.opts.resolution;
113      if(typeof player.setQuality==="function")player.setQuality(fallback.url,player.opts.resolution);
114      else{
115        player.media.src=fallback.url;
116        if(typeof player.media.load==="function")player.media.load();
117      }
118      syncActualQualityLabel(player);
119      return fallback;
120    }
121    function verifyLocalRendition(rendition){
122      if(!rendition||!isLocalMediaUrl(rendition.url))return;
123      fetch(rendition.url,{method:"HEAD",cache:"no-store"}).then(function(response){
124        if(!isPermanentlyMissingResponse(response))return;
125        var fallback=fallBackFrom(rendition);
126        if(fallback)verifyLocalRendition(fallback);
127      }).catch(function(){
128        /* A network-level HEAD failure is inconclusive; native media errors still drive fallback. */
129      });
130    }
131    player.media.addEventListener("error",function(){
132      fallBackFrom(player.__aioSelectedRendition);
133    });
134    verifyLocalRendition(selected);
135  }
136  function parseCueTime(value){
137    var m=String(value||"").trim().match(/(?:(\d{2,}):)?(\d{2}):(\d{2})[,.](\d{3})/);
138    if(!m)return NaN;
139    return (Number(m[1]||0)*3600)+(Number(m[2]||0)*60)+Number(m[3]||0)+Number(m[4]||0)/1000;
140  }
141  function parseSubtitleText(text){
142    var blocks=String(text||"").replace(/^\uFEFF/,"").replace(/^WEBVTT[^\n]*(?
142:\n|$)/i,"").trim().split(/\n\s*\n/);
143    var cues=[];
144    blocks.forEach(function(block){
145      var lines=block.trim().split(/\r?\n/).filter(Boolean);
146      if(!lines.length)return;
147      var timeIndex=lines.findIndex(function(line){return line.indexOf("-->")>=0;});
148      if(timeIndex<0)return;
149      var parts=lines[timeIndex].split("-->");
150      var start=parseCueTime(parts[0]);
151      var end=parseCueTime(parts[1]);
152      if(!isFinite(start)||!isFinite(end)||end<=start)return;
153      var body=lines.slice(timeIndex+1).join("\n").replace(/<[^>]+>/g,"").trim();
154      if(body)cues.push({start:start,end:end,text:body});
155    });
156    return cues;
157  }
158  async function fetchText(candidate){
159    var url=typeof candidate==="string"?candidate:candidate&&candidate.url;
160    var headers=typeof candidate==="object"&&candidate?candidate.headers:{};
161    var res=await fetch(url,{headers:headers||{},cache:"no-store"});
162    if(!res.ok)throw new Error("subtitle not found");
163    return await res.text();
164  }
165  async function robustLoadSubtitles(lang){
166    var base=this.opts&&this.opts.subtitleBase;
167    if(!base||!lang||lang==="off"||this._destroyed)return;
168    var generation=this._subtitleGeneration=(this._subtitleGeneration||0)+1;
169    this._subtitleLoadingLang=lang;
170    var enc=encodeURIComponent(base);
171    var path=this.opts.subtitlePath||"/media/";
172    var version=this._subtitleVersion||Date.now().toString(36);
173    var candidates=[];
174    try{
175      if(typeof API!=="undefined"&&typeof publicAuthHeaders==="function"){
176        var headers=publicAuthHeaders()||{};
177        if(headers.Authorization)candidates.push({url:API+"/media/subtitles/"+enc+"?lang="+encodeURIComponent(lang),headers:headers});
178      }
179    }catch(_e){}
180    var protectedUrl=typeof this._protectedSubtitleUrl==="function"?this._protectedSubtitleUrl(base+"."+lang+".srt"):"";
181    if(protectedUrl)candidates.push(protectedUrl);
182    else{
183      var publicUrl=path+enc+"."+lang+".srt";
184      publicUrl+=(publicUrl.indexOf("?")>=0?"&":"?")+"v="+encodeURIComponent(version);
185      candidates.push(publicUrl);
186      if(path.indexOf("/api/public/srt/")!==0){
187        var vttUrl=path+enc+"."+lang+".vtt";
188        vttUrl+=(vttUrl.indexOf("?")>=0?"&":"?")+"v="+encodeURIComponent(version);
189        candidates.push(vttUrl);
190      }
191    }
192    try{for(var i=0;i<candidates.length;i++){
193      try{
194        var text=await fetchText(candidates[i]);
195        if(this._destroyed||generation!==this._subtitleGeneration)return;
196        var cues=parseSubtitleText(text);
197        if(!cues.length&&typeof this._parseSrt==="function")cues=this._parseSrt(text)||[];
198        if(cues.length){
199          this.subtitleCues=cues;
200          this.subtitleLang=lang;
201          this.subtitleOn=true;
202          if(typeof this._buildCcMenu==="function")this._buildCcMenu();
203          if(typeof this._updateSubtitlePosition==="function")this._updateSubtitlePosition();
204          if(typeof this._updateSubtitle==="function")this._updateSubtitle();
205          return;
206        }
207      }catch(_err){if(this._destroyed||generation!==this._subtitleGeneration)return;}
208    }
209    if(this._destroyed||generation!==this._subtitleGeneration)return;
210    this.subtitleCues=null;
211    this.subtitleOn=false;
212    if(typeof this._hideSubtitle==="function")this._hideSubtitle();
213    if(typeof this._buildCcMenu==="function")this._buildCcMenu();
214    }finally{if(generation===this._subtitleGeneration)this._subtitleLoadingLang=null;}
215  }
216  function sizeWaveCanvas(canvas, player){
217    if(!canvas)return;
218    var dpr=window.devicePixelRatio||1;
219    var rect=typeof canvas.getBoundingClientRect==="function"?canvas.getBoundingClientRect():null;
220    var fallbackH=player&&player.mode==="audio"?64:player&&player.mode==="compact"?32:36;
221    var cssW=Math.max(1,Math.floor(((rect&&rect.width)||canvas.offsetWidth||200)*dpr));
222    var cssH=Math.max(1,Math.floor(((rect&&rect.height)||canvas.offsetHeight||fallbackH)*dpr));
223    if(Math.abs(canvas.width-cssW)>2||Math.abs(canvas.height-cssH)>2){
224      canvas.width=cssW;
225      canvas.height=cssH;
226    }
227  }
228  function patchWaveform(player){
229    if(!player||player.__aioWavePatched)return;
230    player.__aioWavePatched=true;
231    var origDecode=typeof player._decodeWaveformBuffer==="function"?player._decodeWaveformBuffer.bind(player):null;
232    if(origDecode){
233      player._decodeWaveformBuffer=function(buffer){
234        try{this.__aioWaveBuffer=buffer&&buffer.slice?buffer.slice(0):buffer}catch(_e){}
235        return origDecode(buffer);
236      };
237    }
238    var origDraw=typeof player._drawWave==="function"?player._drawWave.bind(player):null;
239    if(origDraw){
240      player._drawWave=function(progress){
241        sizeWaveCanvas(this.waveCanvas,this);
242        return origDraw(progress);
243      };
244    }
245    var origLoad=typeof player._loadWaveform==="function"?player._loadWaveform.bind(player):null;
246    if(origLoad){
247      player._loadWaveform=function(){
248        if(this._destroyed || (this.opts&&this.opts.deferMediaAccess&&!this._mediaAccessReady))return;
249        var videoSrc=(this.opts&&this.opts.src)||this.media&&this.media.src||"";
250        var audioSrc=(this.opts&&this.opts.audioSrc)||"";
251        if(this.mode==="video"&&isDerivedAudioUrl(audioSrc)&&isLocalMediaUrl(audioSrc)){
252          this.opts.audioSrc="";
253          audioSrc="";
254        }
255        if(this.mode==="video"&&!audioSrc&&isLocalMediaUrl(videoSrc)){
256          this._waveformFallback=videoSrc;
257          if(typeof this._fetchPartialWaveform==="function")return this._fetchPartialWaveform(videoSrc);
258          if(typeof this._generateSyntheticWaveform==="function")return this._generateSyntheticWaveform();
259          return;
260        }
261        return origLoad();
262      };
263    }
264    if(window.ResizeObserver&&player.waveCanvas){
265      var timer=null;
266      var resize=new ResizeObserver(function(){
267        clearTimeout(timer);
268        timer=setTimeout(function(){
269          if(player._destroyed)return;
270          try{
271            if(player.__aioWaveBuffer&&origDecode)origDecode(player.__aioWaveBuffer.slice(0));
272            else if(typeof player._generateSyntheticWaveform==="function")player._generateSyntheticWaveform();
273          }catch(_e){
274            try{player._drawWave(player.media&&player.media.duration?player.media.currentTime/player.media.duration:0)}catch(_e2){}
275          }
276        },120);
277      });
278      resize.observe(player.waveCanvas);
279      var oldDestroy=typeof player.destroy==="function"?player.destroy.bind(player):null;
280      if(oldDestroy){
281        player.destroy=function(){
282          try{resize.disconnect()}catch(_e){}
283          return oldDestroy();
284        };
285      }
286    }
287  }
288  function patchPlayer(player, opts){
289    if(!player||player.__aioPlayerFixes)return player;
290    player.__aioPlayerFixes=true;
291    player.opts=Object.assign({},player.opts||{},opts||{});
292    // v18 owns the native media-cookie exchange for subtitle paths. Never replace it.
293    var ticketAware=!!(player.opts.deferMediaAccess&&player._mediaTicketReady);
294    if(!ticketAware)player.loadSubtitles=robustLoadSubtitles;
295    patchWaveform(player);
296    if(!ticketAware&&typeof player.getPlaybackSnapshot!=="function")installRenditionFallback(player);
297    syncActualQualityLabel(player);
298    if(player.media&&typeof player.media.addEventListener==="function"){
299      player.media.addEventListener("loadedmetadata",function(){syncActualQualityLabel(player)});
300      player.media.addEventListener("canplay",function(){syncActualQualityLabel(player)});
301    }
302    function startAuxiliaryMedia(){
303      if(player._destroyed || (ticketAware&&!player._mediaAccessReady))return;
304      try{
305        syncActualQualityLabel(player);
306        if(player.opts&&player.opts.subtitleBase&&(!player.subtitleLangs||!player.subtitleLangs.length)&&typeof player._loadSubtitleLangs==="function")player._loadSubtitleLangs();
307        if(typeof player._loadWaveform==="function")player._loadWaveform();
308      }catch(_e){}
309    }
310    if(ticketAware)player._mediaTicketReady.then(function(ok){if(ok)startAuxiliaryMedia();}).catch(function(){});
311    else setTimeout(startAuxiliaryMedia,180);
312    return player;
313  }
314  function install(){
315    var original=window.initMediaPlayer;
316    if(typeof original!=="function"||original.__aioFixWrapped)return;
317    function wrappedInitMediaPlayer(container, opts){
318      var normalized=normalizeOptions(opts||{});
319      var variants=normalized.variants||[];
320      var player=original(container,normalized);
321      if(!player)return player;
322      player.variants=variants;
323      return patchPlayer(player,normalized);
324    }
325    wrappedInitMediaPlayer.__aioFixWrapped=true;
326    window.initMediaPlayer=wrappedInitMediaPlayer;
327  }
328  if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",install,{once:true});
329  install();
330})();
331
332/* At most one live streaming episode player per course accordion. */
333;(function(){
334  function install(){
335    var toggle=window.toggleEpisode,init=window.initStreamingEpisodePlayer;
336    if(typeof toggle!=="function"||typeof init!=="function"||typeof window.destroyStreamingEpisodePlayer!=="function"||toggle.__aioSingleEpisode)return;
337    function clearClosedPlayer(epId){
338      // v18 destroy replaces the container with a clone. Keep its data-* inputs
339      // for reopening, but discard the cloned empty media elements and controls.
340      var container=document.getElementById("mp-"+epId);
341      if(container)container.innerHTML="";
342    }
343    function closeOthers(current){
344      var scope=current.closest(".sp-episodes")||document;
345      scope.querySelectorAll(".sp-ep-content[id]").forEach(function(content){
346        if(content===current)return;
347        var player=typeof window.getMediaPlayer==="function"?window.getMediaPlayer("mp-"+content.id):null;
348        if(!content.classList.contains("open")&&!player)return;
349        // Existing teardown flushes this principal's progress before pausing,
350        // unloading media, removing timers and releasing its media-ticket paths.
351        window.destroyStreamingEpisodePlayer(content.id);
352        clearClosedPlayer(content.id);
353        content.classList.remove("open");
354        content.style.display="none";
355        var header=content.previousElementSibling;
356        if(header){header.setAttribute("aria-expanded","false");var svg=header.querySelector("svg");if(svg)svg.style.transform="";}
357      });
358    }
359    function singleEpisodeToggle(epId){
360      var content=document.getElementById(epId);
361      var wasOpen=content&&content.classList.contains("open");
362      if(content&&!wasOpen)closeOthers(content);
363      var result=toggle.apply(this,arguments);
364      if(wasOpen)clearClosedPlayer(epId);
365      return result;
366    }
367    function singleEpisodeInit(epId){
368      var content=document.getElementById(epId),container=document.getElementById("mp-"+epId);
369      if(!content||!container||!container.dataset.mpMode)return init.apply(this,arguments);
370      closeOthers(content);
371      var current=typeof window.getMediaPlayer==="function"?window.getMediaPlayer(container.id):null;
372      if(current&&!current._destroyed&&current.container===container)return current;
373      return init.apply(this,arguments);
374    }
375    singleEpisodeToggle.__aioSingleEpisode=true;
376    window.toggleEpisode=singleEpisodeToggle;
377    window.initStreamingEpisodePlayer=singleEpisodeInit;
378  }
379  install();
380  if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",install,{once:true});
381})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.