JAVASCRIPT   104
audio player js
Guest on 13th June 2022 05:01:31 PM


  1. /**
  2.  * Audio player module
  3.  */
  4. ;
  5. ((Themify,doc)=>{
  6.     'use strict';
  7.     const _CLICK_=!Themify.isTouch?'click':(window.PointerEvent?'pointerdown':'touchstart'),
  8.                 _IS_IOS_=/iPhone|iPad|iPod|Mac OS/i.test(window.navigator.userAgent),
  9.                 humanTime=(time)=>{
  10.                         time=Infinity===time?0:time;
  11.                 const tmp = new Date(time*1000).toISOString().substr(11, 8).split(':');
  12.                         if(tmp[0]==='00'){
  13.                                 tmp.splice(0,1);
  14.                         }
  15.                         return tmp.join(':');
  16.                 },
  17.                 generateTracks=(opt,el)=>{
  18.                         const tracks=opt['tracks'],
  19.                                 showArtists=!!opt['artists'],
  20.                                 showImage=!!opt['images'],
  21.                                 showNumbers=!!opt['tracknumbers'],
  22.                                 currentClicked=doc.createElement('div'),
  23.                                 container=doc.createElement('div');
  24.                                 container.className='tf_audio_playlist';
  25.                                 currentClicked.className='tf_playlist_current';
  26.                                 for(let i=0,len=tracks.length;i<len;++i){
  27.                                         if(tracks[i].src){
  28.                                                 tracks[i].src=tracks[i].src.trim();
  29.                                                 let item=doc.createElement('div'),
  30.                                                 link=doc.createElement('a'),
  31.                                                 audio = new Audio(tracks[i].src),
  32.                                                 duration=doc.createElement('div'),
  33.                                                 title=doc.createElement('span');
  34.                                                 if(!tracks[i].type || audio.canPlayType(tracks[i].type)){
  35.                                                         item.className='tf_playlist_item tf_w tf_rel';
  36.                                                         link.href=tracks[i].src;
  37.                                                         link.className='tf_playlist_caption tf_w';
  38.                                                         duration.className='tf_playlist_length';
  39.                                                         if(!isNaN(audio.duration)|| (tracks[i].meta && tracks[i].meta.length_formatted)){
  40.                                                                 duration.textContent=!isNaN(audio.duration)?humanTime(audio.duration):tracks[i].meta.length_formatted;
  41.                                                                 audio=null;
  42.                                                         }
  43.                                                         else{
  44.                                                                 item.className+=' tf_lazy';
  45.                                                                 audio.addEventListener('durationchange',function(){
  46.                                                                         duration.textContent=humanTime(this.duration);
  47.                                                                         audio=null;
  48.                                                                         item.classList.remove('tf_lazy');
  49.                                                                 },{passive:true,once:true});
  50.                                                                
  51.                                                         }
  52.                                                         if(showNumbers===true){
  53.                                                                 link.textContent=(i+1)+'.';
  54.                                                         }
  55.                                                         title.className='tf_playlist_title';
  56.                                                
  57.                                                         if(tracks[i].caption){
  58.                                                                 title.textContent=tracks[i].caption;
  59.                                                         }
  60.                                                         else if(tracks[i].title){
  61.                                                                 title.textContent=tracks[i].title;
  62.                                                         }
  63.                                                         if(showArtists===true && tracks[i].meta && tracks[i].meta.artists){
  64.                                                                 let artists=doc.createElement('span');
  65.                                                                 artists.className='tf_playlist_artist';
  66.                                                                 artists.textContent='-'+tracks[i].meta.artists;
  67.                                                                 link.appendChild(artists);
  68.                                                         }
  69.                                                         link.appendChild(title);
  70.                                                         item.appendChild(link);
  71.                                                         item.appendChild(duration);
  72.                                                         container.appendChild(item);
  73.                                                 }
  74.                                                 else{
  75.                                                         tracks.slice(i,1);
  76.                                                 }
  77.                                         }
  78.                                         else{
  79.                                                 tracks.slice(i,1);
  80.                                         }
  81.                                 }
  82.                                 let firstClick=true;
  83.                                 container.addEventListener(_CLICK_,function(e){
  84.                                         const clicked=e.target.closest('.tf_playlist_caption'),
  85.                                                 isCurrent=clicked.parentNode.classList.contains('tf_audio_current');
  86.                                         if(clicked){
  87.                                                 e.preventDefault();
  88.                                                 e.stopPropagation();
  89.                                                 if(!isCurrent || el.paused){
  90.                                                         if(!isCurrent){
  91.                                                                 const prev =this.getElementsByClassName('tf_audio_current')[0],
  92.                                                                         index=Themify.convert(this.children).indexOf(clicked.parentNode),
  93.                                                                         caption=doc.createElement('div'),
  94.                                                                         title=doc.createElement('span');
  95.                                                                         caption.className='tf_playlist_caption';
  96.                                                                         title.className='tf_playlist_title';
  97.                                                                 if(firstClick===false){
  98.                                                                         el.pause();
  99.                                                                         el.addEventListener('loadedmetadata',function(){
  100.                                                                                 this.play();
  101.                                                                         },{passive:true,once:true});
  102.                                                                         el.setAttribute('src',clicked.getAttribute('href'));
  103.                                                                         el.load();
  104.                                                                 }
  105.                                                                 if(prev){
  106.                                                                         prev.classList.remove('tf_audio_current');
  107.                                                                 }
  108.                                                                 clicked.parentNode.classList.add('tf_audio_current');
  109.                                                                 currentClicked.innerHTML='';
  110.                                                                 if(tracks[index]){
  111.                                                                         const track=tracks[index];
  112.                                                                         if(showImage && track.thumb && track.thumb.src){
  113.                                                                                 const img = new Image();
  114.                                                                                 if(track.thumb.width!==undefined) img.width=track.thumb.width;
  115.                                                                                 if(track.thumb.height!==undefined) img.height=track.thumb.height;
  116.                                                                                 img.decode='async';
  117.                                                                                 img.src=track.thumb.src;
  118.                                                                                 const thumb = doc.createElement('div');
  119.                                                                                 thumb.className='post-image';
  120.                                                                                 img.decode().then(()=>{
  121.                                                                                         thumb.appendChild(img);
  122.                                                                                 });
  123.                                                                                 currentClicked.appendChild(thumb);
  124.                                                                         }
  125.                                                                         title.textContent=track.title?track.title:(track.caption?track.caption:'');
  126.                                                                         caption.appendChild(title);
  127.                                                                         if(tracks.meta){
  128.                                                                                 if(tracks.meta.album){
  129.                                                                                         const album =doc.createElement('span');
  130.                                                                                                 album.className=' tf_playlist_album';
  131.                                                                                                 album.textContent=tracks.meta.album;
  132.                                                                                                 caption.appendChild(album);
  133.                                                                                 }
  134.                                                                                 if(showArtists && tracks.meta.artists){
  135.                                                                                         const artist =doc.createElement('span');
  136.                                                                                         artist.className=' tf_playlist_artist';
  137.                                                                                         artist.textContent=tracks.meta.artists;
  138.                                                                                         caption.appendChild(artist);
  139.                                                                                 }
  140.                                                                         }
  141.                                                                         currentClicked.appendChild(caption);
  142.                                                                 }      
  143.                                                         }
  144.                                                         else{
  145.                                                                 el.play();
  146.                                                         }
  147.                                                 }
  148.                                                 firstClick=false;
  149.                                         }
  150.                                 });
  151.                                 el.parentNode.insertBefore(currentClicked,el);
  152.                                 Themify.triggerEvent(container.getElementsByClassName('tf_playlist_caption')[0],_CLICK_);
  153.                                 return container;
  154.                 },
  155.                 loadMetaData=(el,opt)=>{
  156.                         if(el.previousElementSibling && el.previousElementSibling.classList.contains('tf_audio_container')){
  157.                                 return;
  158.                         }
  159.                         const container = doc.createElement('div'),
  160.                                 wrap = doc.createElement('div'),
  161.                                 progressWrap=doc.createElement('div'),
  162.                                 progressLoaded=doc.createElement('div'),
  163.                                 progressCurrent=doc.createElement('div'),
  164.                                 progressWaiting=doc.createElement('div'),
  165.                                 hoverHandler=doc.createElement('div'),
  166.                                 range=doc.createElement('input'),
  167.                                 volumeRange=doc.createElement('input'),
  168.                                 volumeWrap=doc.createElement('div'),
  169.                                 volumeInner=doc.createElement('div'),
  170.                                 controls=doc.createElement('div'),
  171.                                 mute=doc.createElement('button'),
  172.                                 play=doc.createElement('button'),
  173.                                 currentTime = doc.createElement('div'),
  174.                                 trackWrap=el.parentNode.closest('.track'),
  175.                                 totalTime=doc.createElement('div'),
  176.                                 isPlayList=opt && opt['tracks'] && (true || opt['tracklist']);
  177.                                 let paused=true,//For error play-request-was-interrupted
  178.                                         sliding=false;
  179.                                
  180.                                 container.className='tf_audio_container tf_w tf_rel tf_box';
  181.                                 wrap.className='tf_audio_wrap tf_w tf_rel tf_box';
  182.                                 controls.className='tf_audio_controls';
  183.                                 progressWrap.className='tf_audio_progress_wrap tf_rel tf_textl';
  184.                                 progressLoaded.className='tf_audio_progress_loaded tf_w tf_h tf_abs';
  185.                                 progressCurrent.className='tf_audio_progress_current tf_w tf_h tf_abs';
  186.                                 range.className='tf_audio_progress_range tf_h tf_abs';
  187.                                 volumeRange.min=range.min=0;
  188.                                 volumeRange.max=range.max=100;
  189.                                 volumeRange.type=range.type='range';
  190.                                 range.value=0;
  191.                                 volumeRange.value='50%';
  192.                                 volumeWrap.className='tf_audio_volumn_wrap';
  193.                                 volumeInner.className='tf_audio_volumn_inner';
  194.                                 volumeRange.className='tf_audio_volumn_range tf_h tf_overflow';
  195.                                 mute.className='tf_audio_mute';
  196.                                 play.className='tf_auido_play';
  197.                                 play.tabIndex=mute.tabIndex=0;
  198.                                 play.type=mute.type='button';
  199.                                 if(el.muted){
  200.                                         mute.className+=' tf_muted';
  201.                                 }
  202.                                 currentTime.className='tf_audio_current_time';
  203.                                 totalTime.className='tf_audio_total_time';
  204.                                 hoverHandler.className='tf_audio_hover tf_abs tf_hide tf_box tf_textc';
  205.                                 currentTime.textContent=humanTime(el.currentTime);
  206.                                 totalTime.textContent=humanTime(el.duration);
  207.                                
  208.                                 play.addEventListener(_CLICK_,function(e){
  209.                                         if(e.type==='click'){
  210.                                                 e.preventDefault();
  211.                                                 e.stopPropagation();
  212.                                         }
  213.                                         if(el.paused){
  214.                                                 el.play();
  215.                                         }
  216.                                         else{
  217.                                                 el.pause();
  218.                                         }
  219.                                 },{passive:_CLICK_!=='click'});
  220.                                 if(trackWrap){
  221.                                         const trackTitle=trackWrap.getElementsByClassName('track-title')[0];
  222.                                         if(trackTitle){
  223.                                                 trackTitle.addEventListener(_CLICK_,function(e){
  224.                                                         e.preventDefault();
  225.                                                         Themify.triggerEvent(play,_CLICK_);
  226.                                                 });
  227.                                         }
  228.                                 }
  229.                                 mute.addEventListener(_CLICK_,function(e){
  230.                                         if(e.type==='click'){
  231.                                                 e.preventDefault();
  232.                                                 e.stopPropagation();
  233.                                         }
  234.                                         el.muted  =!el.muted;
  235.                                 },{passive:_CLICK_!=='click'});
  236.                                 if(!Themify.isTouch){
  237.                                         progressWrap.addEventListener('mouseenter',function(){
  238.                                                 if(!isNaN(el.duration)){
  239.                                                         hoverHandler.classList.remove('tf_hide');
  240.                                                         const w =this.clientWidth,
  241.                                                         hoverW=parseFloat(hoverHandler.clientWidth/2),
  242.                                                         duration=el.duration,
  243.                                                         move=function(e){
  244.                                                                 const X=e.layerX!==undefined?e.layerX:e.offsetX;
  245.                                                                 if((X-hoverW)>0 && e.layerX<=w){
  246.                                                                         hoverHandler.style['transform']='translateX('+(X-hoverW)+'px)';
  247.                                                                         hoverHandler.textContent=humanTime(parseFloat((X/w))*duration);
  248.                                                                 }
  249.                                                         };
  250.                                                         this.addEventListener('mouseleave',function(){
  251.                                                                 hoverHandler.classList.add('tf_hide');
  252.                                                                 this.removeEventListener('mousemove',move,{passive:true});
  253.                                                         },{passive:true,once:true});
  254.                                                         this.addEventListener('mousemove',move,{passive:true});
  255.                                                 }
  256.                                         },{passive:true});
  257.                                 }
  258.                                 range.addEventListener('input',function(e){
  259.                                         e.preventDefault();
  260.                                         e.stopPropagation();
  261.                                         if(!isNaN(el.duration)){
  262.                                                 if(!el.paused && paused===true){
  263.                                                         el.pause();
  264.                                                 }
  265.                                                 sliding=true;
  266.                                                 const v=parseInt(this.value);
  267.                                                 el.currentTime=v===100?(el.duration-1):parseFloat((v*el.duration)/100).toFixed(4);
  268.                                         }
  269.                                 });
  270.                                
  271.                                 range.addEventListener('change',function(e){
  272.                                         e.preventDefault();
  273.                                         e.stopPropagation();
  274.                                         if(!isNaN(el.duration)){
  275.                                                 sliding=paused=false;
  276.                                                 if(el.paused){
  277.                                                         el.play().then(_ => {
  278.                                                                 paused=true;
  279.                                                         }).catch(er => {
  280.                                                                  paused=true;
  281.                                                         });
  282.                                                 }
  283.                                         }
  284.                                 });
  285.                                
  286.                                 el.addEventListener('progress', function() {
  287.                                         if (this.buffered.length > 0) {
  288.                                                 progressLoaded.style['transform']='scaleX('+parseFloat((this.buffered.end(0))/this.duration).toFixed(4)+')';
  289.                                         }
  290.                                 },{passive:true});
  291.                                
  292.                                 el.addEventListener('durationchange',function() {
  293.                                         totalTime.textContent=humanTime(this.duration);
  294.                                 },{passive:true});
  295.                                
  296.                                 el.addEventListener('waiting', function() {
  297.                                         progressWrap.classList.add('tf_audio_waiting');
  298.                                         this.addEventListener('playing', function(){
  299.                                                 progressWrap.classList.remove('tf_audio_waiting');
  300.                                         },{passive:true,once:true});
  301.                                 },{passive:true});
  302.                                
  303.                                 el.addEventListener('emptied', function(){
  304.                                         progressWrap.classList.add('tf_audio_waiting');
  305.                                         this.addEventListener('playing', function(){
  306.                                                 progressWrap.classList.remove('tf_audio_waiting');
  307.                                         },{passive:true,once:true});
  308.                                 },{passive:true});
  309.                                
  310.                                 el.addEventListener('pause',function(){
  311.                                         play.classList.remove('tf_audio_playing');
  312.                                 },{passive:true});
  313.                                
  314.                                 el.addEventListener('play',function(){
  315.                                         play.classList.add('tf_audio_playing');
  316.                                         const allAudios = doc.getElementsByTagName('audio');
  317.                                         for(let i=allAudios.length-1;i>-1;--i){
  318.                                                 if(allAudios[i]!==this){
  319.                                                         allAudios[i].pause();
  320.                                                 }
  321.                                         }
  322.                                 },{passive:true});
  323.                                
  324.                                 el.addEventListener('timeupdate',function(){
  325.                                         if(!isNaN(this.duration)){
  326.                                                 currentTime.textContent=humanTime(this.currentTime);
  327.                                                 let v=parseFloat(this.currentTime/this.duration);
  328.                                                 progressCurrent.style['transform']='scaleX('+v.toFixed(4)+')';
  329.                                                 if(sliding===false){
  330.                                                         range.value=parseInt(v*100);
  331.                                                 }
  332.                                         }
  333.                                 },{passive:true});
  334.                                
  335.                                 el.addEventListener('volumechange',function(){
  336.                                         if(this.volume!==0){
  337.                                                 mute.classList.remove('tf_mute_disabled');
  338.                                         }
  339.                                         if(this.muted===true || this.volume===0){
  340.                                                 if(this.volume===0){
  341.                                                         mute.classList.add('tf_mute_disabled');
  342.                                                 }
  343.                                                 mute.classList.add('tf_muted');
  344.                                         }
  345.                                         else{
  346.                                                 mute.classList.remove('tf_muted');
  347.                                         }
  348.                                 },{passive:true});
  349.                                 progressWrap.appendChild(progressLoaded);
  350.                                 progressWrap.appendChild(progressCurrent);
  351.                                 progressWrap.appendChild(range);
  352.                                 progressWrap.appendChild(hoverHandler);
  353.                                 volumeWrap.appendChild(mute);
  354.                                 if(_IS_IOS_===false){
  355.                                         volumeRange.addEventListener('input',function(e){
  356.                                                 e.preventDefault();
  357.                                                 e.stopPropagation();
  358.                                                 el.volume=parseFloat(this.value/100).toFixed(3);
  359.                                         });
  360.                                         volumeInner.appendChild(volumeRange);
  361.                                         volumeWrap.appendChild(volumeInner);
  362.                                 }
  363.                                 wrap.appendChild(controls);
  364.                                 wrap.appendChild(currentTime);
  365.                                 wrap.appendChild(progressWrap);
  366.                                 wrap.appendChild(totalTime);
  367.                                 wrap.appendChild(volumeWrap);
  368.                                 container.appendChild(wrap);
  369.                                 if(isPlayList){
  370.                                         const playList = container.appendChild(generateTracks(opt,el)),
  371.                                                 prev=doc.createElement('button'),
  372.                                                 next=doc.createElement('button');
  373.                                         prev.className='tf_playlist_prev tf_play_disabled';
  374.                                         next.className='tf_playlist_next';
  375.                                         if(playList.children.length<=1){
  376.                                                 next.className+=' tf_play_disabled';
  377.                                         }
  378.                                         prev.tabIndex=next.tabIndex=0;
  379.                                         prev.type=next.type='button';
  380.                                         controls.addEventListener(_CLICK_,function(e){
  381.                                                 const clicked=e.target,
  382.                                                 cl=clicked.classList;
  383.                                                 if(!cl.contains('tf_play_disabled') && (cl.contains('tf_playlist_prev') ||cl.contains('tf_playlist_next'))){
  384.                                                         if(e.type==='click'){
  385.                                                                 e.preventDefault();
  386.                                                                 e.stopPropagation();
  387.                                                         }
  388.                                                         const current = playList.getElementsByClassName('tf_audio_current')[0];
  389.                                                         if(current){
  390.                                                                 const nextTrack = cl.contains('tf_playlist_prev')?current.previousElementSibling:current.nextElementSibling;
  391.                                                                 if(nextTrack){
  392.                                                                         Themify.triggerEvent(nextTrack.getElementsByClassName('tf_playlist_caption')[0],_CLICK_);
  393.                                                                         if(cl.contains('tf_playlist_prev')){
  394.                                                                                 next.classList.remove('tf_play_disabled');
  395.                                                                                 cl.toggle('tf_play_disabled',!nextTrack.previousElementSibling);
  396.                                                                         }
  397.                                                                         else{
  398.                                                                                 prev.classList.remove('tf_play_disabled');
  399.                                                                                 cl.toggle('tf_play_disabled',!nextTrack.nextElementSibling);
  400.                                                                         }
  401.                                                                 }
  402.                                                         }
  403.                                                 }
  404.                                         },{passive:_CLICK_!=='click'});
  405.                                         el.addEventListener('ended',function(){
  406.                                                 if(!next.classList.contains('tf_play_disabled')){
  407.                                                         Themify.triggerEvent(next,_CLICK_);
  408.                                                 }
  409.                                                 else if(this.hasAttribute('data-loop') || this.hasAttribute('loop')){
  410.                                                         const first = playList.getElementsByClassName('tf_playlist_caption')[0];
  411.                                                         if(first){
  412.                                                                 prev.classList.add('tf_play_disabled');
  413.                                                                 next.classList.toggle('tf_play_disabled',playList.children.length<=1);
  414.                                                                 Themify.triggerEvent(first,_CLICK_);
  415.                                                         }
  416.                                                 }
  417.                                                
  418.                                         },{passive:true});
  419.                                        
  420.                                         controls.appendChild(prev);
  421.                                         controls.appendChild(play);
  422.                                         controls.appendChild(next);
  423.                                 }
  424.                                 else{
  425.                                         controls.appendChild(play);
  426.                                 }
  427.                                 el.parentNode.classList.remove('tf_lazy');
  428.                                 el.parentNode.insertBefore(container,el);
  429.                 },
  430.                 init=(items,options)=>{
  431.                         for(let i=items.length-1;i>-1;--i){
  432.                                 let item=items[i];
  433.                                
  434.                                         if(!options){
  435.                                                 let p=item.parentNode.parentNode;
  436.                                                 if(p.classList.contains('wp-audio-playlist')){
  437.                                                         let playlist = p.getElementsByClassName('tf-playlist-script')[0];
  438.                                                         if(!playlist){
  439.                                                                 playlist=p.getElementsByClassName('wp-playlist-script')[0];
  440.                                                         }
  441.                                                         if(playlist){
  442.                                                                 options=JSON.parse(playlist.textContent);
  443.                                                                 if(options['type']!=='audio'){
  444.                                                                         options=false;
  445.                                                                 }
  446.                                                         }
  447.                                                 }
  448.                                         }
  449.                                         if(!item.hasAttribute('src') && !item.getElementsByTagName('source')[0]){
  450.                                                 if(!options || !options['tracks']){
  451.                                                     continue;
  452.                                                 }
  453.                                                 let track=options['tracks'][0]['src'];
  454.                                                 if(!track){
  455.                                                         for(let j=1,len=options['tracks'].length;j<len;++j){
  456.                                                                 if(options['tracks'][j]['src']){
  457.                                                                         track=options['tracks'][j]['src'];
  458.                                                                         break;
  459.                                                                 }
  460.                                                         }
  461.                                                 }
  462.                                                 if(!track){
  463.                                                         continue;
  464.                                                 }
  465.                                                 item.setAttribute('src',track);
  466.                                         }
  467.                                         if(item.readyState===4){
  468.                                                 loadMetaData(item,options);
  469.                                         }
  470.                                         else{
  471.                                             Themify.requestIdleCallback(()=>{
  472.                                                 item.addEventListener('loadedmetadata',function(){
  473.                                                     loadMetaData(this,options);
  474.                                                 },{passive:true,once:true});
  475.                                                 item.setAttribute('preload','metadata');
  476.                                                 if(_IS_IOS_===true){
  477.                                                         item.load();
  478.                                                 }
  479.                                             },200);
  480.                                         }
  481.                         }
  482.                 };
  483.     Themify.on('tf_audio_init',(items,options)=>{
  484.         if(items instanceof jQuery){
  485.            items=items.get();
  486.         }
  487.                 else if(items.length===undefined){
  488.                         items=[items];
  489.                 }
  490.        init(items,options);
  491.     });
  492.  
  493. })(Themify,document);

Raw Paste

Login or Register to edit or fork this paste. It's free.