1(function (window){ 2 3 var HAPUtils = function(){}; 4 5 HAPUtils.isEmpty = function(str){ 6 return str.replace(/^s+|s+$/g, '').length == 0; 7 } 8 9 HAPUtils.strip = function(str){ 10 return str.replace(/^\s+|\s+$/g,""); 11 } 12 13 HAPUtils.isNumber = function(n){ 14 return !isNaN(parseFloat(n)) && isFinite(n); 15 } 16 17 HAPUtils.isMobile = function(){ 18 return (/Android|webOS|iPhone|iPad|iPod|sony|BlackBerry/i.test(navigator.userAgent)); 19 } 20 21 HAPUtils.isChrome = function(){ 22 return !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime) 23 } 24 25 HAPUtils.isSafari = function() { 26 return isSafari = navigator.vendor.match(/apple/i) && 27 !navigator.userAgent.match(/crios/i) && 28 !navigator.userAgent.match(/fxios/i) && 29 !navigator.userAgent.match(/Opera|OPT\//); 30 } 31 32 HAPUtils.isIE = function(){ 33 var ie_check = getInternetExplorerVersion(); 34 if (ie_check != -1)return true; 35 else return false; 36 } 37 38 function getInternetExplorerVersion(){ 39 var rv = -1; 40 if(navigator.appName == 'Microsoft Internet Explorer'){ 41 var ua = navigator.userAgent; 42 var re = new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})"); 43 if(re.exec(ua) != null)rv = parseFloat( RegExp.$1 ); 44 }else if(navigator.appName == 'Netscape'){ 45 var ua = navigator.userAgent; 46 var re = new RegExp("Trident/.*rv:([0-9]{1,}[.0-9]{0,})"); 47 if(re.exec(ua) != null)rv = parseFloat( RegExp.$1 ); 48 } 49 return rv; 50 } 51 52 HAPUtils.htmlToElement = function(html) { 53 var template = document.createElement('template'); 54 html = html.trim(); // Never return a text node of whitespace as the result 55 template.innerHTML = html; 56 return template.content.firstChild; 57 } 58 59 60 HAPUtils.insertAfter = function(newNode, referenceNode) { 61 referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); 62 } 63 64 HAPUtils.isIOS = function(){ 65 return navigator.userAgent.match(/(iPad|iPhone|iPod)/g); 66 } 67 68 HAPUtils.isAndroid = function() { 69 return navigator.userAgent.indexOf("Android") > -1; 70 } 71 72 HAPUtils.hasDownloadSupport = function(){ 73 return ("download" in document.createElement("a")); 74 } 75 76 HAPUtils.qualifyURL = function(url) { 77 var a = document.createElement('a'); 78 a.href = url; 79 return a.href; 80 } 81 82 HAPUtils.relativePath = function(s){ 83 //https://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative 84 var r = new RegExp('^(?:[a-z]+:)?//', 'i'); 85 return r.test(s); 86 } 87 88 HAPUtils.closestNumber = function(arr, goal){ 89 var closest = arr.reduce(function(prev, curr) { 90 return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev); 91 }); 92 return closest; 93 } 94 95 HAPUtils.b64DecodeUnicode = function(str) { 96 // Going backwards: from bytestream, to percent-encoding, to original string. 97 return decodeURIComponent(atob(str).split('').map(function(c) { 98 return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); 99 }).join('')); 100 }; 101 102 HAPUtils.hasLocalStorage = function() { 103 try{ 104 return 'localStorage' in window && window['localStorage'] !== null; 105 }catch(e){ 106 return false; 107 } 108 } 109 110 HAPUtils.volumeCanBeSet = function() { 111 var audio = document.createElement("audio"); 112 if(!audio) return false; 113 audio.volume = 0; 114 return audio.volume == 0 ? true : false; 115 }; 116 117 HAPUtils.arrayContainsAnotherArray = function(needle, haystack){ 118 var i, len = needle.length; 119 for(i = 0; i < len; i++){ 120 if(haystack.indexOf(needle[i]) > -1)return true; 121 } 122 return false; 123 } 124 125 HAPUtils.randomiseArray = function(num) { 126 var arr = [], randomArr = [], i, j, randomIndex; 127 for(i = 0; i < num; i++){ 128 arr[i] = i; 129 } 130 for(j = 0; j < num; j++){ 131 randomIndex = Math.round(Math.random()*(arr.length-1)); 132 randomArr[j] = arr[randomIndex]; 133 arr.splice(randomIndex, 1); 134 } 135 return randomArr; 136 } 137 138 HAPUtils.valueLimit = function(val, min, max) { 139 return val < min ? min : (val > max ? max : val); 140 } 141 142 HAPUtils.sortArray = function(arr, sortArr) { 143 var i, len = arr.length, result = []; 144 for(i=0; i<len; i++) { 145 result[i] = arr[sortArr[i]]; 146 } 147 return result; 148 } 149 150 HAPUtils.sortNumericArray = function(arr) { 151 arr.sort(function(a, b) { 152 return a - b; 153 }); 154 } 155 156 HAPUtils.shuffleArray = function(a) { 157 for (let i = a.length - 1; i > 0; i--) { 158 const j = Math.floor(Math.random() * (i + 1)); 159 [a[i], a[j]] = [a[j], a[i]]; 160 } 161 return a; 162 } 163 164 HAPUtils.keysrt = function(arr, key, reverse) { 165 var order = 1; 166 if(reverse)order = -1; 167 return arr.sort(function(a, b) { 168 var x = a[key]; var y = b[key]; 169 return order * ((x < y) ? -1 : ((x > y) ? 1 : 0)); 170 }); 171 } 172 173 HAPUtils.keysrt2 = function(arr, prop, key, reverse) { 174 var sortOrder = 1; 175 if(reverse)sortOrder = -1; 176 return arr.sort(function(a, b) { 177 var x = a[prop][key]; var y = b[prop][key]; 178 return sortOrder * ((x < y) ? -1 : ((x > y) ? 1 : 0)); 179 }); 180 } 181 182 HAPUtils.keysrt3 = function(array, order, key) { 183 184 array.sort( function (a, b) { 185 var A = a[key], B = b[key]; 186 187 if (order.indexOf(A) > order.indexOf(B)) { 188 return 1; 189 } else { 190 return -1; 191 } 192 193 }); 194 195 return array; 196 }; 197 198 HAPUtils.keysrt4 = function(arr, key, reverse) { 199 var order = 1; 200 if(reverse)order = -1; 201 return arr.sort(function(a, b) { 202 var x = a; var y = b; 203 return order * ((x < y) ? -1 : ((x > y) ? 1 : 0)); 204 }); 205 } 206 207 208 HAPUtils.parseXML = function(xml) { 209 if(window.ActiveXObject && window.GetObject) { 210 var dom = new ActiveXObject('Microsoft.XMLDOM'); 211 dom.loadXML(xml); 212 return dom; 213 } 214 if(window.DOMParser){ 215 return new DOMParser().parseFromString(xml, 'text/xml'); 216 }else{ 217 throw new Error('No XML parser available'); 218 } 219 } 220 221 HAPUtils.formatTime = function(seconds) { 222 var sec_num = Math.round(seconds, 10); 223 var hours = Math.floor(sec_num / 3600); 224 var minutes = Math.floor((sec_num - (hours * 3600)) / 60); 225 var seconds = sec_num - (hours * 3600) - (minutes * 60); 226 if(hours > 0){ 227 if (hours < 10) {hours = "0"+hours;} 228 if (minutes < 10) {minutes = "0"+minutes;} 229 if (seconds < 10) {seconds = "0"+seconds;} 230 return hours+':'+minutes+':'+seconds; 231 }else{ 232 if (minutes < 10) {minutes = "0"+minutes;} 233 if (seconds < 10) {seconds = "0"+seconds;} 234 return minutes+':'+seconds; 235 } 236 } 237 238 HAPUtils.formatTimeWithMiliseconds = function(str){ 239 var hours = parseInt(str.split(':')[0]); 240 var minutes = parseInt(str.split(':')[1]); 241 var seconds = parseInt(str.split(':')[2]); 242 var millisesconds = parseInt(str.split(',')[1] || str.split('.')[1]); 243 var t = (hours*60*60) + (minutes*60) + seconds + (millisesconds/1000); 244 t = Math.round(t*100)/100; 245 return t; 246 }; 247 248 HAPUtils.toSeconds = function(n){ 249 var a = n.split(/[.:,]+/), 250 seconds = (+a[0]) * 60 * 60 + (+a[1]) * 60 + (+a[2]); 251 return Number(seconds); 252 } 253 254 HAPUtils.formatNumber = function(i) { 255 var s; 256 if(i < 9)s = "0" + (i + 1); 257 else s = i + 1; 258 return s; 259 } 260 261 HAPUtils.nFormatter = function(num, digits) { 262 var si = [ 263 { value: 1E18, symbol: "E" }, 264 { value: 1E15, symbol: "P" }, 265 { value: 1E12, symbol: "T" }, 266 { value: 1E9, symbol: "G" }, 267 { value: 1E6, symbol: "M" }, 268 { value: 1E3, symbol: "k" } 269 ], rx = /\.0+$|(\.[0-9]*[1-9])0+$/, i; 270 271 for (i = 0; i < si.length; i++) { 272 if (num >= si[i].value) { 273 return (num / si[i].value).toFixed(digits).replace(rx, "$1") + si[i].symbol; 274 } 275 } 276 return num.toFixed(digits).replace(rx, "$1"); 277 } 278 279 HAPUtils.hmsToSecondsOnly = function(str) {//This function handels "HH:MM:SS" as well as "MM:SS" or "SS". 280 var p = str.split(':'), 281 s = 0, m = 1; 282 while (p.length > 0) { 283 s += m * parseInt(p.pop()); 284 m *= 60; 285 } 286 return s; 287 } 288 289 HAPUtils.canPlayMp3 = function() { 290 var a = document.createElement('audio'); 291 return !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, '')); 292 } 293 294 HAPUtils.canPlayWav = function() { 295 var a = document.createElement('audio'); 296 return !!(a.canPlayType && a.canPlayType('audio/wav;').replace(/no/, '')); 297 } 298 299 HAPUtils.canPlayAac = function() { 300 var a = document.createElement('audio'); 301 return !!(a.canPlayType && a.canPlayType('audio/aac;').replace(/no/, '')); 302 } 303 304 HAPUtils.canPlayOgg = function() { 305 var a = document.createElement('audio'); 306 return !!(a.canPlayType && a.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, '')); 307 } 308 309 HAPUtils.canPlayFlac = function() { 310 var a = document.createElement('audio'); 311 return !!(a.canPlayType && a.canPlayType('audio/flac;').replace(/no/, '')); 312 } 313 314 HAPUtils.hasCanvas = function(){ 315 return Boolean(document.createElement("canvas")); 316 }; 317 318 HAPUtils.getElementOffsetTop = function(el) { 319 var boundingClientRect = el.getBoundingClientRect(); 320 var bodyEl = document.body; 321 var docEl = document.documentElement; 322 var scrollTop = window.pageYOffset || docEl.scrollTop || bodyEl.scrollTop; 323 var clientTop = docEl.clientTop || bodyEl.clientTop || 0; 324 return Math.round(boundingClientRect.bottom - 100 + scrollTop - clientTop); 325 } 326 327 HAPUtils.getScrollTop = function(el) { 328 var docEl = document.documentElement; 329 return (window.pageYOffset || docEl.scrollTop) - (docEl.clientTop || 0); 330 } 331 332 HAPUtils.getEvents = function() { 333 334 var events = {}; 335 336 if("ontouchstart" in window){ 337 events.downEvent = "mousedown"; 338 events.moveEvent = "mousemove"; 339 events.upEvent = "mouseup"; 340 }else{ 341 if(window.PointerEvent){ 342 events.downEvent = "pointerdown"; 343 events.moveEvent = "pointermove"; 344 events.upEvent = "pointerup"; 345 }else{ 346 events.downEvent = "mousedown"; 347 events.moveEvent = "mousemove"; 348 events.upEvent = "mouseup"; 349 } 350 } 351 352 return events; 353 } 354 355 HAPUtils.getUrlParameter = function(k) { 356 var p={}; 357 window.location.search.replace(/[?&]+([^=&]+)=([^&]*)/gi,function(s,k,v){p[k]=v}) 358 return k?p[k]:p; 359 }; 360 361 // Pass in the objects to merge as arguments. 362 // For a deep extend, set the first argument to `true`. 363 HAPUtils.extendObj = function() { 364 365 // Variables 366 var extended = {}; 367 var deep = false;
368 var i = 0; 369 var length = arguments.length; 370 371 // Check if a deep merge 372 if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) { 373 deep = arguments[0]; 374 i++; 375 } 376 377 // Merge the object into the extended object 378 var merge = function (obj) { 379 for ( var prop in obj ) { 380 if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) { 381 // If deep merge and property is an object, merge properties 382 if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) { 383 extended[prop] = HAPUtils.extendObj( true, extended[prop], obj[prop] ); 384 } else { 385 extended[prop] = obj[prop]; 386 } 387 } 388 } 389 }; 390 391 // Loop through each object and conduct a merge 392 for ( ; i < length; i++ ) { 393 var obj = arguments[i]; 394 merge(obj); 395 } 396 397 return extended; 398 399 }; 400 401 HAPUtils.drawBars = function(ctx, ctx2, waveOptions, peaks, start, end) { 402 403 var absmax = 1 / waveOptions.barHeight; 404 405 if (waveOptions.normalize) { 406 var max = util.max(peaks); 407 var min = util.min(peaks); 408 absmax = -min > max ? -min : max; 409 } // Bar wave draws the bottom only as a reflection of the top, 410 // so we don't need negative values 411 412 var hasMinVals = [].some.call(peaks, function (val) { 413 return val < 0; 414 }); 415 var height = waveOptions.height * waveOptions.pixelRatio; 416 var offsetY = 0; 417 var halfH = height / 2; 418 419 var peakIndexScale = hasMinVals ? 2 : 1; 420 var length = peaks.length / peakIndexScale; 421 var bar = waveOptions.barWidth * waveOptions.pixelRatio; 422 var gap = waveOptions.barGap === null ? Math.max(waveOptions.pixelRatio, ~~(bar / 2)) : Math.max(waveOptions.pixelRatio, waveOptions.barGap * waveOptions.pixelRatio); 423 var step = bar + gap; 424 var scale = length / waveOptions.width; 425 var first = start; 426 var last = end; 427 var i = first; 428 429 430 431 432 for (i; i < last; i += step) { 433 var peak = peaks[Math.floor(i * scale * peakIndexScale)] || 0; 434 var h = Math.round(peak / absmax * halfH); 435 436 if (h == 0 && waveOptions.barMinHeight) h = waveOptions.barMinHeight; 437 438 if(waveOptions.barRadius){ 439 drawRoundedRect(ctx, i + waveOptions.halfPixel, halfH - h + offsetY, bar + waveOptions.halfPixel, h * 2, waveOptions.barRadius) 440 }else{ 441 ctx.fillRect(i + waveOptions.halfPixel, halfH - h + offsetY, bar + waveOptions.halfPixel, h * 2, waveOptions.barRadius); 442 } 443 444 445 } 446 447 448 i = first; 449 450 for (i; i < last; i += step) { 451 var peak = peaks[Math.floor(i * scale * peakIndexScale)] || 0; 452 var h = Math.round(peak / absmax * halfH); 453 454 if (h == 0 && waveOptions.barMinHeight) h = waveOptions.barMinHeight; 455 456 if(waveOptions.barRadius){ 457 458 drawRoundedRect(ctx2, i + waveOptions.halfPixel, halfH - h + offsetY, bar + waveOptions.halfPixel, h * 2, waveOptions.barRadius) 459 460 }else{ 461 462 ctx2.fillRect(i + waveOptions.halfPixel, halfH - h + offsetY, bar + waveOptions.halfPixel, h * 2, waveOptions.barRadius); 463 } 464 } 465 466 } 467 468 function drawRoundedRect(ctx, x, y, width, height, radius) { 469 if (height === 0) { 470 return; 471 } 472 // peaks are float values from -1 to 1. Use absolute height values in 473 // order to correctly calculate rounded rectangle coordinates 474 if (height < 0) { 475 height *= -1; 476 y -= height; 477 } 478 ctx.beginPath(); 479 ctx.moveTo(x + radius, y); 480 ctx.lineTo(x + width - radius, y); 481 ctx.quadraticCurveTo(x + width, y, x + width, y + radius); 482 ctx.lineTo(x + width, y + height - radius); 483 ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); 484 ctx.lineTo(x + radius, y + height); 485 ctx.quadraticCurveTo(x, y + height, x, y + height - radius); 486 ctx.lineTo(x, y + radius); 487 ctx.quadraticCurveTo(x, y, x + radius, y); 488 ctx.closePath(); 489 ctx.fill(); 490 } 491 492 493 HAPUtils.drawWave = function(ctx, ctx2, waveOptions, peaks, start, end) { 494 495 var absmax = 1 / waveOptions.barHeight; 496 497 if (waveOptions.normalize) { 498 var max = util.max(peaks); 499 var min = util.min(peaks); 500 absmax = -min > max ? -min : max; 501 } 502 503 var hasMinVals = [].some.call(peaks, function (val) { 504 return val < 0; 505 }); 506 var height = waveOptions.height * waveOptions.pixelRatio; 507 var offsetY = 0; 508 var halfH = height / 2; 509 510 if (!hasMinVals) { 511 var reflectedPeaks = []; 512 var len = peaks.length; 513 var i = 0; 514 515 for (i; i < len; i++) { 516 reflectedPeaks[2 * i] = peaks[i];
517 reflectedPeaks[2 * i + 1] = -peaks[i]; 518 } 519 520 peaks = reflectedPeaks; 521 } 522 523 if (start !== undefined) { 524 drawLineToContext(ctx, waveOptions, peaks, absmax, halfH, offsetY, start, end); 525 drawLineToContext(ctx2, waveOptions, peaks, absmax, halfH, offsetY, start, end); 526 } 527 528 ctx.fillRect(0, halfH + offsetY - waveOptions.halfPixel, waveOptions.width, waveOptions.halfPixel, waveOptions.barRadius); 529 530 ctx2.fillRect(0, halfH + offsetY - waveOptions.halfPixel, waveOptions.width, waveOptions.halfPixel, waveOptions.barRadius); 531 532 } 533 534 function drawLineToContext(ctx, waveOptions, peaks, absmax, halfH, offsetY, start, end) { 535 536 var length = peaks.length / 2; 537 var first = Math.round(length * start); 538 539 var last = Math.round(length * 1) + 1; 540 var canvasStart = first; 541 var canvasEnd = last; 542 var scale = waveOptions.width / (canvasEnd - canvasStart - 1); // optimization 543 544 var halfOffset = halfH + offsetY; 545 var absmaxHalf = absmax / halfH; 546 ctx.beginPath(); 547 ctx.moveTo((canvasStart - first) * scale, halfOffset); 548 ctx.lineTo((canvasStart - first) * scale, halfOffset - Math.round((peaks[2 * canvasStart] || 0) / absmaxHalf)); 549 var i, peak, h; 550 551 for (i = canvasStart; i < canvasEnd; i++) { 552 peak = peaks[2 * i] || 0; 553 h = Math.round(peak / absmaxHalf); 554 ctx.lineTo((i - first) * scale + waveOptions.halfPixel, halfOffset - h); 555 } 556 557 var j = canvasEnd - 1; 558 559 for (j; j >= canvasStart; j--) { 560 peak = peaks[2 * j + 1] || 0; 561 h = Math.round(peak / absmaxHalf); 562 ctx.lineTo((j - first) * scale + waveOptions.halfPixel, halfOffset - h); 563 } 564 565 ctx.lineTo((canvasStart - first) * scale, halfOffset - Math.round((peaks[2 * canvasStart + 1] || 0) / absmaxHalf)); 566 ctx.closePath(); 567 ctx.fill(); 568 } 569 570 window.HAPUtils = HAPUtils; 571 572}(window)); 573 574(function (){ 575 var HAPEventDispatcher = function (){ 576 577 var self = this; 578 579 self.events = {}; 580 581 self.addEventListener = function(name, handler) { 582 if (self.events.hasOwnProperty(name)){ 583 self.events[name].push(handler); 584 }else{ 585 self.events[name] = [handler]; 586 } 587 }; 588 589 self.removeEventListener = function(name, handler) { 590 /* This is a bit tricky, because how would you identify functions? 591 This simple solution should work if you pass THE SAME handler. */ 592 if (!self.events.hasOwnProperty(name))return; 593 594 var index = self.events[name].indexOf(handler); 595 if (index != -1)self.events[name].splice(index, 1); 596 }; 597 598 self.fireEvent = function(name, args) { 599 if (!self.events.hasOwnProperty(name))return; 600 601 if (!args || !args.length)args = []; 602 603 var evs = self.events[name], l = evs.length; 604 for (var i = 0; i < l; i++) { 605 evs[i].apply(null, args); 606 } 607 }; 608 609 }; 610 611 window.HAPEventDispatcher = HAPEventDispatcher; 612}(window)); 613 614(function (window){ 615 "use strict" 616 var HAPPlaylistManager = function (data){ 617 618 var self = this, 619 loopState = data.loop, 620 randomPlay = data.random, 621 playlistItems, 622 lastInOrder = false, 623 queNextCounterState, 624 lastCounterState, 625 counter = -1, 626 lastPlayedFromPlaylistClick,//last played on click. 627 lastRandomCounter,//last played random media in random playlist. 628 randomPaused = false,//when random is playing and we interrupt it by click on the playlist. 629 randomArr = [], 630 playlistSelect = false;//prevent geting counter from randomArr on playlist click (get 'normal' counter instead) 631 632 HAPEventDispatcher.call(this); 633 634 //set counter to specific number or add it to the currect counter value 635 this.setCounter = function(value, _add) { 636 if (typeof _add === 'undefined') _add = true; 637 if(_add){ 638 counter += parseInt(value, 10); 639 }else{ 640 counter = parseInt(value, 10); 641 } 642 checkCounter(); 643 } 644 this.getCounter = function() { 645 var i; 646 if(randomPlay){ 647 if(!playlistSelect){ 648 i = randomArr[counter]; 649 }else{ 650 i = counter; 651 } 652 }else{ 653 i = counter; 654 } 655 return i; 656 } 657 this.queNext = function(type, a){ 658 659 if(type == 'advance'){ 660 queNextCounterState = true; 661 lastCounterState = counter; 662 self.advanceHandler(a) 663 counter = lastCounterState; 664 queNextCounterState = false;
665 } 666 else{//pick 667 668 queNextCounterState = true; 669 lastCounterState = counter; 670 self.setCounter(a, false) 671 counter = lastCounterState; 672 queNextCounterState = false; 673 674 } 675 676 } 677 this.advanceHandler = function(a) { 678 playlistSelect = false;//reset 679 if(randomPaused){ 680 handleRandomPaused(a); 681 }else{ 682 self.setCounter(a); 683 } 684 } 685 this.processPlaylistRequest = function(id) { 686 playlistSelect = false;//reset 687 if(randomPlay){ 688 playlistSelect = true; 689 lastPlayedFromPlaylistClick = id;//always remember last played on each click. 690 if(!randomPaused){ 691 lastRandomCounter = counter; 692 randomPaused = true;//needs to stay until random play comes back again! So that the above reference to last random counter doesnt get lost. (if we constantly clicking playlist) 693 } 694 } 695 self.setCounter(id, false); 696 } 697 this.setPlaylistItems = function(val, resetCounter) { 698 if(typeof resetCounter === 'undefined') resetCounter = true; 699 if(resetCounter)counter = -1; 700 playlistItems = val; 701 if(randomPlay) makeRandomList(); 702 } 703 this.reSetCounter = function(num) { 704 if(typeof num === 'undefined'){ 705 counter = -1; 706 }else{//set counter to specific number 707 var n = parseInt(num,10); 708 if(playlistItems){ 709 if(n > playlistItems - 1){ 710 n = playlistItems - 1; 711 }else if(n < 0){ 712 n = 0; 713 } 714 counter = n; 715 }else{ 716 counter = -1; 717 } 718 } 719 } 720 this.setRandom = function(val) { 721 randomPlay = val; 722 if(randomPlay) makeRandomList(); 723 randomChange(); 724 } 725 this.setLooping = function(val) { 726 loopState = val; 727 } 728 this.getPosition = function(val) { 729 return randomArr.indexOf(val); 730 } 731 732 //exiting randomPaused and going back to random mode 733 function handleRandomPaused(a) { 734 //just an exit out of randomPaused (because of a playlist click) and back to random again 735 randomPaused = false;//reset before because of the getCounter() 736 737 if(lastRandomCounter + a > playlistItems - 1){ 738 counter = playlistItems - 1; 739 740 var k = self.getCounter() 741 742 if(queNextCounterState)self.fireEvent('HAPPlaylistManager.QUE_NEXT_READY', [{counter:k}]); 743 else self.fireEvent('HAPPlaylistManager.COUNTER_READY', [{counter:k}]); 744 745 return; 746 } else if( lastRandomCounter + a < 0){ 747 counter = 0; 748 749 var k = self.getCounter() 750 751 if(queNextCounterState)self.fireEvent('HAPPlaylistManager.QUE_NEXT_READY', [{counter:k}]); 752 else self.fireEvent('HAPPlaylistManager.COUNTER_READY', [{counter:k}]); 753 754 return; 755 } 756 self.setCounter(lastRandomCounter + a, false); 757 } 758 function randomChange() {//when random is turned on / off 759 if(randomPlay){ 760 activeIndexFirst(); 761 counter = 0;//we have to do it like this, because with (setCounter(0, false)) media starts to play from the beginning if its already playing. (when random requested) 762 //we need to say this on the every beginning of random to redirect the counter from wherever the currently is to 0, so that it becomes first index in randomArr. (after we have moved active index to beginning of randomArr) 763 764 }else{ 765 //we are not going through setCounter here because its just getting out of random mode, and its not changing counter, it just stays where it is (playing or not) 766 if(randomPaused){ 767 counter = lastPlayedFromPlaylistClick; 768 randomPaused = false;//when random mode stops randomPaused stops also. 769 }else{ 770 counter = randomArr[counter];//when we turn off random we need to set counter to the value of the current counter in randomArr, so if the counter is 1, and thats value 3 in randomArr for example, we want the active counter to stay 3, not 1, and next to go to 4, not 2. 771 } 772 } 773 } 774 function checkCounter() { 775 if(isNaN(counter)){ 776 console.log('HAPPlaylistManager message: No active media, counter = ' + counter); 777 return; 778 } 779 //reset 780 lastInOrder = false; 781 782 if(loopState == 'playlist' || loopState == 'single'){ 783 if(randomPlay){ 784 785 if(counter > playlistItems - 1){//moving fowards 786 counter = randomArr[ playlistItems - 1];//remember counter for comparison 787 makeRandomList(); 788 _firstIndexCheck(); 789 counter = 0; 790 791 }else if(counter < 0){//moving backwards 792 counter = randomArr[0];//remember counter for comparison 793 makeRandomList(); 794 lastIndexCheck(); 795 counter = playlistItems - 1; 796 } 797 798 }else{//random off 799 if(counter > playlistItems - 1){ 800 counter = 0; 801 }else if( counter < 0){ 802 counter = playlistItems - 1; 803 } 804 } 805 806 var k = self.getCounter() 807 808 if(queNextCounterState)self.fireEvent('HAPPlaylistManager.QUE_NEXT_READY', [{counter:k}]); 809 else self.fireEvent('HAPPlaylistManager.COUNTER_READY', [{counter:k}]); 810 811 }else if(loopState == 'off'){//looping off 812 813 if(counter > playlistItems - 1){ 814 counter = playlistItems - 1; 815 lastInOrder = true;//last item 816 }else if(counter < 0){ 817 counter = 0; 818 lastInOrder = true;//last item 819 } 820 821 if(!lastInOrder){ 822 var k = self.getCounter() 823 824 if(queNextCounterState)self.fireEvent('HAPPlaylistManager.QUE_NEXT_READY', [{counter:k}]); 825 else self.fireEvent('HAPPlaylistManager.COUNTER_READY', [{counter:k}]); 826 827 }else{ 828 self.fireEvent('PLAYLIST_END'); 829 } 830 } 831 832 } 833 function makeRandomList() { 834 randomArr = HAPUtils.randomiseArray(playlistItems); 835 } 836 function _firstIndexCheck () { 837 //check that first item in newly generated random array isnt equal to last active item. 838 if(randomArr[0] == counter){//if yes, put it at the last place in array.
839 var i = randomArr.splice(0,1); 840 randomArr.push(i); 841 } 842 } 843 function lastIndexCheck() { 844 if(randomArr[playlistItems - 1] == counter){//if yes, put it at the first place in array. 845 var i = randomArr.splice(playlistItems - 1,1); 846 randomArr.unshift(i); 847 } 848 } 849 function activeIndexFirst() {//when going into random (playing or not) put currently active index on the first place of random array. 850 var i,len = randomArr.length, j; 851 for(i = 0; i < len; i++){ 852 if(randomArr[i] == counter){ 853 if(i == 0){//if its already on the first place no need for action. 854 break; 855 } 856 j = randomArr.splice(i,1); 857 randomArr.unshift(parseInt(j,10)); 858 break; 859 } 860 } 861 } 862 863 }; 864 865 window.HAPPlaylistManager = HAPPlaylistManager; 866 867}(window)); 868 869(function (window){ 870 "use strict" 871 var HAPSCLoader = function (data){ 872 873 var self = this, 874 settings = data.settings, 875 soundCloudToken, 876 soundCloudRefreshToken, 877 soundCloudExpiredTimeInSeconds, 878 action, 879 storage_key = 'hap_sc_at' + settings.instanceName, 880 current_track_id, 881 current_url, 882 playlistProcessData = [], 883 defaultData, 884 nextPageToken = [], 885 resultLimit, 886 xhrRequest 887 888 HAPEventDispatcher.call(this); 889 890 function getToken(){ 891 892 var apk = settings.scak[Math.floor(Math.random() * settings.scak.length)]; 893 894 if(xhrRequest){ 895 xhrRequest.abort(); 896 xhrRequest = null; 897 } 898 899 var url = settings.sourcePath + 'includes/sc/sc2.php'; 900 901 var params = 'action=sc_get_auth&sck='+apk; 902 903 xhrRequest = new XMLHttpRequest(); 904 xhrRequest.onreadystatechange = function() { 905 if (xhrRequest.readyState == 4) { 906 907 var d = JSON.parse(xhrRequest.response); 908 909 soundCloudToken = d.access_token; 910 soundCloudRefreshToken = d.refresh_token; 911 d.soundCloudExpiredTimeInSeconds = d.expires_in + getCurrentTimeInSeconds() - 10; 912 913 localStorage.setItem(storage_key, JSON.stringify(d)); 914 915 if(action == 'url_request')scRequest() 916 else if(action == 'download')download() 917 else if(action == 'get_stream_url')getStreamUrl() 918 919 } 920 } 921 xhrRequest.onerror = function(e) { 922 console.log('Error processSC ' + e); 923 }; 924 xhrRequest.open('POST', url); 925 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 926 xhrRequest.send(params); 927 928 } 929 930 this.get_stream_url = function(id){ 931 932 current_track_id = id 933 934 getStreamUrl() 935 } 936 937 function getStreamUrl(){ 938 939 if(xhrRequest){ 940 xhrRequest.abort(); 941 xhrRequest = null; 942 } 943 944 var url = settings.sourcePath + 'includes/sc/sc2.php'; 945 946 var params = 'action=sc_get_stream_url&track_id='+current_track_id+'&access_token='+soundCloudToken; 947 948 xhrRequest = new XMLHttpRequest(); 949 xhrRequest.onreadystatechange = function() { 950 if (xhrRequest.readyState == 4) { 951 952 var d = JSON.parse(xhrRequest.response); 953 954 if(d.location){ 955 956 self.fireEvent('HAPSCLoader.GET_STREAM_URL', [{location: d.location}]); 957 958 }else{ 959 960 console.log('stream url not valid?', d) 961 } 962 } 963 } 964 xhrRequest.onerror = function(e) { 965 console.log('Error processSC: ' + e); 966 }; 967 xhrRequest.open('POST', url); 968 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 969 xhrRequest.send(params); 970 971 } 972 973 this.resume = function(){ 974 975 if(checkToken()){ 976 getStreamUrl() 977 }else{ 978 action = 'get_stream_url' 979 getToken() 980 } 981 } 982 983 this.get_dl = function(track_id, title){ 984 getDlUrl(track_id, title) 985 } 986 987 function getDlUrl(track_id, title){ 988 989 /*console.log(track_id) 990 991 title+='.mp3' 992 993 var hap_dl_iframe = document.querySelector('<iframe class="hap_dl_iframe"/>') 994 hap_dl_iframe.style.display = 'none' 995 hap_dl_iframe.appendTo('body'); 996 997 hap_dl_iframe.setAttribute('src',settings.sourcePath + "includes/sc/dl.php?path="+track_id+"&name="+title); 998 999 return 1000*/ 1001 1002 if(xhrRequest){ 1003 xhrRequest.abort(); 1004 xhrRequest = null; 1005 } 1006 1007 var url = settings.sourcePath + 'includes/sc/sc2.php' 1008 1009 var params = 'action=sc_get_dl_url&track_id='+track_id+'&title='+title+'&access_token='+soundCloudToken; 1010 1011 xhrRequest = new XMLHttpRequest(); 1012 xhrRequest.onreadystatechange = function() { 1013 if (xhrRequest.readyState == 4) { 1014 1015 console.log(xhrRequest.response) 1016 1017 } 1018 } 1019 xhrRequest.onerror = function(e) { 1020 console.log(jqXHR.responseText); 1021 }; 1022 xhrRequest.open('POST', url); 1023 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 1024 xhrRequest.send(params); 1025 1026 1027 1028 1029 /* var postData = [ 1030 {name: 'action', value: 'sc_get_dl_url'}, 1031 {name: 'track_id', value: track_id}, 1032 {name: 'title', value: title}, 1033 {name: 'access_token', value: soundCloudToken},// 1034 ]; 1035 1036 $.ajax({ 1037 url: settings.sourcePath + 'includes/sc/sc2.php', 1038 data: postData, 1039 }).done(function(response) { 1040 1041 console.log(response) 1042 1043 1044 }).fail(function(jqXHR, textStatus, errorThrown) { 1045 console.log(jqXHR.responseText); 1046 }); */ 1047 1048 } 1049 1050 function checkToken() { 1051 1052 var ls = localStorage.getItem(storage_key); 1053 1054 if(ls){ 1055 var d = JSON.parse(ls); 1056 1057 soundCloudToken = d.access_token; 1058 1059 return getCurrentTimeInSeconds() < d.soundCloudExpiredTimeInSeconds; 1060 1061 }else{ 1062 return false;
1063 } 1064 1065 } 1066 1067 function getCurrentTimeInSeconds() { 1068 return Date.now() * 0.001; 1069 } 1070 1071 function scRequest(){ 1072 1073 if(xhrRequest){ 1074 xhrRequest.abort(); 1075 xhrRequest = null; 1076 } 1077 1078 var url = settings.sourcePath + 'includes/sc/sc2.php'; 1079 1080 var params = 'action=sc_get_request&access_token='+soundCloudToken+'&url='+current_url; 1081 1082 xhrRequest = new XMLHttpRequest(); 1083 xhrRequest.onreadystatechange = function() { 1084 if (xhrRequest.readyState == 4) { 1085 1086 var d = JSON.parse(xhrRequest.response) 1087 1088 if(d.location){ 1089 scRequest2(d.location) 1090 }else{ 1091 console.log('sc request fail?') 1092 self.fireEvent('HAPSCLoader.END_LOAD', [{data: []}]); 1093 } 1094 1095 } 1096 } 1097 xhrRequest.onerror = function(e) { 1098 console.log('Error processSC: ' + e); 1099 }; 1100 xhrRequest.open('POST', url); 1101 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 1102 xhrRequest.send(params); 1103 1104 } 1105 1106 function scRequest2(curl){ 1107 1108 if(xhrRequest){ 1109 xhrRequest.abort(); 1110 xhrRequest = null; 1111 } 1112 1113 var url = settings.sourcePath + 'includes/sc/sc2.php'; 1114 1115 var params = 'action=sc_get_request&access_token='+soundCloudToken+'&url='+curl; 1116 1117 xhrRequest = new XMLHttpRequest(); 1118 xhrRequest.onreadystatechange = function() { 1119 if (xhrRequest.readyState == 4) { 1120 1121 var data = JSON.parse(xhrRequest.response); 1122 1123 playlistProcessData = [] 1124 1125 if(data.kind == "track") { 1126 1127 playlistProcessData.push(getSoundCloudTrack(data)); 1128 1129 }else if(data.kind == "playlist"){ 1130 //no pagination, returns some tracks but not all? 1131 1132 var i, len = data.tracks.length, obj; 1133 for(i=0; i<len; i++) { 1134 obj = getSoundCloudTrack(data.tracks[i]); 1135 1136 if(i < resultLimit)playlistProcessData.push(obj); 1137 else nextPageToken.push(obj); 1138 1139 } 1140 1141 }else if(data.collection){ 1142 //has pagination 1143 /*var i, len = data.collection.length, end; 1144 if(soundCloudResultArr.length + len >= resultLimit){ 1145 len = resultLimit - soundCloudResultArr.length; 1146 end = true; 1147 } 1148 1149 for(i=0; i<len; i++) { 1150 getSoundCloudTrack(data.collection[i]); 1151 }*/ 1152 1153 }else if(data.username) { 1154 //data username goes to data collection, always? 1155 /*var sc_uri = data.uri; 1156 if(/likes/.test(path)) { 1157 sc_uri += '/likes'; 1158 }else if(/favorites/.test(path)) { 1159 sc_uri += '/favorites'; 1160 }else{ 1161 sc_uri += '/tracks'; 1162 } 1163 getSoundCloudPage(false, sc_uri); 1164 return;*/ 1165 1166 //}else if($.isArray(data)) { 1167 }else if (data instanceof Array) { 1168 //username/tracks returns this, always returns 50 tracks?, no pagination 1169 /*var i, len = data.length; 1170 if(soundCloudResultArr.length + len >= resultLimit){ 1171 len = resultLimit - soundCloudResultArr.length; 1172 end = true; 1173 } 1174 for(i=0; i<len; i++) { 1175 getSoundCloudTrack(data[i]); 1176 }*/ 1177 } 1178 1179 //console.log(playlistProcessData) 1180 1181 self.fireEvent('HAPSCLoader.END_LOAD', [{data: playlistProcessData, nextPageToken: nextPageToken}]); 1182 1183 } 1184 } 1185 xhrRequest.onerror = function(e) { 1186 console.log('Error processSC: ' + e); 1187 self.fireEvent('HAPSCLoader.END_LOAD', [{data: []}]); 1188 }; 1189 xhrRequest.open('POST', url); 1190 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 1191 xhrRequest.send(params); 1192 1193 } 1194 1195 this.request = function(data, limit){ 1196 action = 'url_request' 1197 1198 nextPageToken = [] 1199 resultLimit = limit 1200 defaultData = data 1201 1202 var s = 'https://api.soundcloud.com/resolve?url=' + data.path 1203 1204 current_url = s 1205 1206 if(checkToken()){ 1207 scRequest() 1208 } 1209 else{ 1210 getToken() 1211 } 1212 1213 } 1214 1215 function getSoundCloudTrack(track){ 1216 1217 if(track.streamable && track.stream_url){ 1218 1219 var obj = HAPUtils.extendObj(true, {}, defaultData); 1220 1221 obj.type = 'audio'; 1222 obj.origtype = 'soundcloud' 1223 obj.id = track.id; 1224 1225 if(track.duration)obj.duration = track.duration / 1000;//miliseconds 1226 1227 if(track.downloadable && track.download_url){ 1228 obj.download = track.download_url; 1229 } 1230 1231 if(!obj.title && track.title)obj.title = track.title; 1232 if(!obj.description && track.description)obj.description = track.description; 1233 if(!obj.thumb && track.artwork_url){ 1234 obj.thumb = track.artwork_url; 1235 } 1236 if(track.created_at)obj.date = track.created_at; 1237 obj.favoritingsCount = parseInt(track.favoritings_count?track.favoritings_count:0,10); 1238 obj.playbackCount = parseInt(track.playback_count?track.playback_count:0,10); 1239 obj.hotness = obj.favoritingsCount + obj.playbackCount; 1240 if(track.permalink_url){ 1241 //if(!obj.share)obj.share = track.permalink_url; 1242 if(settings.createLinkIconsInPlaylist)if(!obj.link)obj.link = track.permalink_url; 1243 } 1244 1245 obj.sc_data = track; 1246 1247 return obj; 1248 1249 } 1250 } 1251 1252 }; 1253 1254 window.HAPSCLoader = HAPSCLoader; 1255 1256}(window)); 1257 1258(function (window){ 1259 "use strict" 1260 var HAPCirclePlayer = function (data){ 1261 1262 var self = this, 1263 parent = data.parent, 1264 circlePlayer = parent.querySelector('.hap-circle-player'), 1265 loadCanvas = parent.querySelector('.hap-load-canvas'),
1266 progressCanvas = parent.querySelector('.hap-progress-canvas'), 1267 strokeSize = parseInt(circlePlayer.getAttribute('data-stroke-size'),10); 1268 1269 if(loadCanvas){ 1270 var loadColor = loadCanvas.getAttribute('data-color'), 1271 loadCtx = loadCanvas.getContext('2d'), 1272 circleSize = loadCanvas.offsetWidth 1273 } 1274 if(progressCanvas){ 1275 var progressColor = progressCanvas.getAttribute('data-color'), 1276 progressCtx = progressCanvas.getContext('2d'), 1277 circleSize = progressCanvas.offsetWidth 1278 } 1279 1280 var circ = Math.PI * 2, 1281 quart = Math.PI / 2, 1282 circleRadius = circleSize/2 1283 1284 this.drawSeekbar = function(loadPercent,t,d){ 1285 if(loadCanvas)drawLoadbar(loadPercent); 1286 if(progressCanvas)drawProgressbar(t/d); 1287 } 1288 1289 this.clear = function(){ 1290 if(progressCanvas)progressCtx.clearRect(0, 0, circleSize, circleSize); 1291 if(loadCanvas)loadCtx.clearRect(0, 0, circleSize, circleSize); 1292 } 1293 1294 this.setProgress = function(point){ 1295 1296 var rect = circlePlayer.getBoundingClientRect() 1297 1298 var x = point.pageX - rect.left - circleSize/2, 1299 y = point.pageY - rect.top - circleSize/2, 1300 mAngle = Math.atan2(y, x); 1301 1302 if (mAngle > -1 * Math.PI && mAngle < -0.5 * Math.PI) { 1303 mAngle = 2 * Math.PI + mAngle; 1304 } 1305 1306 var v = Math.max(0, Math.min((mAngle + Math.PI / 2) / 2 * Math.PI * 10))/100; 1307 1308 if(progressCanvas){ 1309 progressCtx.clearRect(0, 0, circleSize, circleSize); 1310 drawProgressbar(v); 1311 } 1312 1313 return v; 1314 1315 } 1316 1317 this.trackTooltip = function(e){ 1318 1319 var rect = circlePlayer.getBoundingClientRect() 1320 1321 var x1 = e.pageX - rect.left, 1322 y1 = e.pageY - rect.top, 1323 x = x1 - circleSize/2, 1324 y = y1 - circleSize/2, 1325 mAngle = Math.atan2(y,x); 1326 1327 if (mAngle > -1 * Math.PI && mAngle < -0.5 * Math.PI){ 1328 mAngle = 2 * Math.PI + mAngle; 1329 } 1330 var v = Math.max(0, Math.min((mAngle + Math.PI / 2) / 2 * Math.PI * 10))/100; 1331 1332 return v; 1333 1334 } 1335 1336 function drawProgressbar(percent){ 1337 if(progressCanvas){ 1338 progressCtx.clearRect(0, 0, circleSize, circleSize); 1339 progressCtx.beginPath(); 1340 progressCtx.arc(circleSize/2, circleSize/2,circleRadius-strokeSize/2,-(quart),((circ) * percent) - quart,false); 1341 progressCtx.strokeStyle = progressColor; 1342 progressCtx.lineCap = 'butt'; 1343 progressCtx.lineWidth = strokeSize; 1344 progressCtx.stroke(); 1345 } 1346 } 1347 1348 function drawLoadbar(percent){ 1349 if(loadCanvas){ 1350 loadCtx.clearRect(0, 0, circleSize, circleSize); 1351 loadCtx.beginPath(); 1352 loadCtx.arc(circleSize/2, circleSize/2,circleRadius-strokeSize/2,-(quart),((circ) * percent) - quart,false); 1353 loadCtx.strokeStyle = loadColor; 1354 loadCtx.lineCap = 'butt'; 1355 loadCtx.lineWidth = strokeSize; 1356 loadCtx.stroke(); 1357 } 1358 } 1359 1360 }; 1361 1362 window.HAPCirclePlayer = HAPCirclePlayer; 1363 1364}(window)); 1365 1366(function (window){ 1367 "use strict" 1368 var HAPAdManager = function(settings, parent, cmd, progressBg, progressLevel, mediaTimeAd){ 1369 1370 var self = this, 1371 isIOS = HAPUtils.isIOS(), 1372 adPreOn, 1373 adAudio, 1374 adMidTimeoutID, 1375 adMidOn, 1376 adEndOn, 1377 adCounter = 0, 1378 currMediaData = cmd, 1379 volume = settings.volume 1380 1381 adAudio = new Audio() 1382 adAudio.preload = "auto"; 1383 adAudio.addEventListener("loadedmetadata", adPlay); 1384 1385 HAPEventDispatcher.call(this); 1386 1387 //ad pre 1388 1389 this.initAd = function(type){ 1390 1391 if(type == 'pre'){ 1392 1393 adPreOn = true; 1394 adCounter = 0; 1395 adAudio.src = currMediaData.adPre[adCounter]; 1396 } 1397 1398 else if(type == 'mid'){ 1399 1400 adMidOn = true; 1401 adCounter = 0; 1402 adAudio.src = currMediaData.adMid[adCounter]; 1403 1404 if(isIOS)adAudio.load() 1405 1406 1407 } 1408 else if(type == 'end'){ 1409 1410 adEndOn = true; 1411 adCounter = 0; 1412 adAudio.src = currMediaData.adEnd[adCounter]; 1413 1414 } 1415 1416 adAudio.volume = volume; 1417 1418 var promise = adAudio.play(); 1419 if (promise !== undefined) { 1420 promise.then(function(){ 1421 1422 if(adPreOn){ 1423 self.fireEvent('HAPAdManager.AD_PLAY_ACTION'); 1424 } 1425 1426 }).catch(function(error){ 1427 }); 1428 } 1429 1430 adAudio.addEventListener("ended", adEnded); 1431 1432 } 1433 1434 this.forceAdMidAudio = function(){ 1435 if(adAudio){ 1436 adAudio.src = settings.sourcePath + 'data/m.mp3'; 1437 adAudio.play(); 1438 } 1439 } 1440 1441 function adPlay() { 1442 1443 if(adPreOn){ 1444 1445 self.fireEvent('HAPAdManager.ADPRE_PLAY'); 1446 1447 parent.fireEvent("adPrePlay", [{instance:parent, instanceName:settings.instanceName, media:currMediaData.adPre}]); 1448 1449 adAudio.addEventListener("timeupdate", adTimeUpdate); 1450 adTimeUpdate(); 1451 1452 } 1453 else if(adMidOn){ 1454 1455 adAudio.addEventListener("timeupdate", adTimeUpdate); 1456 adTimeUpdate(); 1457 1458 self.fireEvent('HAPAdManager.ADMID_PLAY'); 1459 1460 parent.fireEvent("adMidPlay", [{instance:parent, instanceName:settings.instanceName, media:currMediaData.adMid}]); 1461 1462 } 1463 else if(adEndOn){ 1464 1465 self.fireEvent('HAPAdManager.ADEND_PLAY'); 1466 1467 adAudio.addEventListener("timeupdate", adTimeUpdate); 1468 adTimeUpdate(); 1469 1470 parent.fireEvent("adEndPlay", [{instance:parent, instanceName:settings.instanceName, media:currMediaData.adMid}]); 1471 1472 } 1473 1474 } 1475 1476 function adEnded() { 1477 1478 if(adPreOn){ 1479 1480 //we can have multiple ads 1481 adCounter++; 1482 if(adCounter < currMediaData.adPre.length){ 1483 1484 adAudio.src = currMediaData.adPre[adCounter]; 1485 var promise = adAudio.play(); 1486 if (promise !== undefined) { 1487 promise.then(function(){ 1488 }).catch(function(error){ 1489 }); 1490 } 1491 1492 }else{ 1493 1494 adAudio.removeEventListener("timeupdate", adTimeUpdate); 1495 adAudio.removeEventListener("ended", adEnded); 1496 1497 if(progressLevel)progressLevel.style.width = 0;//reset do its not seen as full width after ad seekbar disapears 1498 1499 self.fireEvent('HAPAdManager.ADPRE_ENDED'); 1500 1501 adPreOn = false;
1502 1503 } 1504 1505 } 1506 else if(adMidOn){ 1507 1508 //we can have multiple ads 1509 adCounter++; 1510 if(adCounter < currMediaData.adMid.length){ 1511 1512 adAudio.src = currMediaData.adMid[adCounter]; 1513 var promise = adAudio.play(); 1514 if (promise !== undefined) { 1515 promise.then(function(){ 1516 }).catch(function(error){ 1517 }); 1518 } 1519 1520 }else{ 1521 1522 adAudio.removeEventListener("timeupdate", adTimeUpdate); 1523 adAudio.removeEventListener("ended", adEnded); 1524 1525 self.fireEvent('HAPAdManager.ADMID_ENDED'); 1526 1527 adMidOn = false; 1528 1529 parent.fireEvent("adMidEnded", [{instance:parent, instanceName:settings.instanceName, media:currMediaData.adMid}]); 1530 1531 startAdMidTimer(); 1532 1533 } 1534 1535 } 1536 1537 else if(adEndOn){ 1538 1539 //we can have multiple ads 1540 adCounter++; 1541 if(adCounter < currMediaData.adEnd.length){ 1542 1543 adAudio.src = currMediaData.adEnd[adCounter]; 1544 var promise = adAudio.play(); 1545 if (promise !== undefined) { 1546 promise.then(function(){ 1547 }).catch(function(error){ 1548 }); 1549 } 1550 1551 }else{ 1552 1553 adAudio.removeEventListener("timeupdate", adTimeUpdate); 1554 adAudio.removeEventListener("ended", adEnded); 1555 1556 adEndOn = false; 1557 1558 self.fireEvent('HAPAdManager.ADEND_ENDED'); 1559 1560 } 1561 1562 } 1563 } 1564 1565 function startAdMidTimer(){ 1566 1567 if(adMidTimeoutID)clearTimeout(adMidTimeoutID); 1568 var interval = currMediaData.adMidInterval || 10000; 1569 1570 adMidTimeoutID = setTimeout(function(){ 1571 adMidTimeoutID = null; 1572 if(parent.getMediaPlaying()){ 1573 self.initAd('mid') 1574 } 1575 }, parseInt(interval,10) + settings.dataInterval); 1576 } 1577 1578 this.adMidStartHandler = function(){ 1579 startAdMidTimer(); 1580 } 1581 1582 this.adMidPlayHandler = function(){ 1583 1584 //if we paused audio and ad timer fired later while audio paused, we want to resume ad timer now 1585 if(!adMidTimeoutID){ 1586 1587 //console.log('audio resumed, but no ad timeout') 1588 1589 startAdMidTimer(); 1590 1591 } 1592 } 1593 1594 this.clearAdMidTimeout = function(){ 1595 if(adMidTimeoutID){ 1596 clearTimeout(adMidTimeoutID); 1597 adMidTimeoutID = null; 1598 } 1599 } 1600 1601 this.toggleAdAudio = function(){ 1602 1603 if(adAudio.paused) { 1604 var promise = adAudio.play(); 1605 if (promise !== undefined) { 1606 promise.then(function(){ 1607 1608 if(adPreOn){ 1609 self.fireEvent('HAPAdManager.AD_PLAY_ACTION'); 1610 } 1611 1612 }).catch(function(error){ 1613 }); 1614 } 1615 }else{ 1616 adAudio.pause(); 1617 1618 if(adPreOn){ 1619 self.fireEvent('HAPAdManager.AD_PAUSE_ACTION'); 1620 } 1621 } 1622 } 1623 1624 //ad time update 1625 1626 function adTimeUpdate(){ 1627 var t = adAudio.currentTime, d = adAudio.duration; 1628 parent.displayAdTime(d,t) 1629 } 1630 1631 this.isAdOn = function(){ 1632 return (adPreOn || adMidOn || adEndOn); 1633 } 1634 1635 this.isAdPreOn = function(){ 1636 return adPreOn; 1637 } 1638 1639 this.isAdMidOn = function(){ 1640 return adMidOn; 1641 } 1642 1643 this.isAdEndOn = function(){ 1644 return adEndOn; 1645 } 1646 1647 this.setAdData = function(cmd){ 1648 currMediaData = cmd; 1649 adCounter = 0; 1650 } 1651 1652 this.setVolume = function(vol){ 1653 volume = vol; 1654 if(adAudio)adAudio.volume = volume; 1655 } 1656 1657 this.cleanAds = function(){ 1658 1659 if(adAudio){ 1660 1661 adAudio.removeEventListener("timeupdate", adTimeUpdate); 1662 adAudio.removeEventListener("ended", adEnded); 1663 1664 adAudio.pause(); 1665 adAudio.src = ''; 1666 1667 } 1668 1669 adPreOn = false; 1670 1671 if(adMidTimeoutID){ 1672 clearTimeout(adMidTimeoutID); 1673 adMidTimeoutID = null; 1674 } 1675 1676 adMidOn = false; 1677 1678 adEndOn = false; 1679 1680 } 1681 1682 }; 1683 1684 window.HAPAdManager = HAPAdManager; 1685 1686}(window)); 1687 1688(function (window){ 1689 "use strict" 1690 var HAPYoutubeLoader = function (data){ 1691 1692 var self = this, 1693 settings = data, 1694 type, 1695 processData, 1696 finishData = [], 1697 deeplinkCounter, 1698 maxResults = 50, 1699 requestUrl, 1700 nextPageToken, 1701 limit, 1702 order, 1703 orderArr = ['date','rating','relevance','title','videoCount','viewCount'],//only valid for search? 1704 appId = data.youtubeAppId || data.ytk, 1705 xhrRequest; 1706 1707 HAPEventDispatcher.call(this); 1708 1709 this.resumeLoad = function(nextPageToken){ 1710 finishData = []; 1711 1712 if(nextPageToken){ 1713 requestUrl = nextPageToken.substr(0,nextPageToken.lastIndexOf('&pageToken='));//remove last page token 1714 process(nextPageToken); 1715 }else{ 1716 self.fireEvent('HAPYoutubeLoader.END_LOAD', [{data:finishData, nextPageToken:nextPageToken}]); 1717 } 1718 } 1719 this.setData = function(data){ 1720 1721 if(!appId){ 1722 alert('Youtube API key missing! Set API key in settings.'); 1723 return; 1724 } 1725 1726 finishData = []; 1727 processData = data; 1728 deeplinkCounter = 0; 1729 limit = processData.limit || 400; 1730 maxResults = 50; 1731 if(limit < maxResults)maxResults = limit; 1732 order = processData.sort || 'relevance'; 1733 type = processData.type; 1734 nextPageToken = null; 1735 1736 //build snippet fields 1737 var s = ''; 1738 if(settings.playlistItemContent.indexOf('title')>-1)s+='title,'; 1739 if(settings.playlistItemContent.indexOf('description')>-1)s+='description,'; 1740 if(settings.playlistItemContent.indexOf('date')>-1)s+='publishedAt,'; 1741 if(settings.playlistItemContent.indexOf('thumb')>-1)s+='thumbnails,';
1742 if(s.length>0){ 1743 s = s.substr(0,s.length-1)//remove comma 1744 var snippetTitle = ',snippet'; 1745 var snippet = ',snippet('+s+')'; 1746 }else{ 1747 var snippetTitle = ''; 1748 var snippet = ''; 1749 } 1750 1751 if(type == 'youtube_single' || type == 'youtube_single_list'){ 1752 1753 if(type == 'youtube_single_list')processData.path = processData.path.replace(/\s+/g, ''); 1754 1755 //build contentDetails fields 1756 if(settings.playlistItemContent.indexOf('duration')>-1){ 1757 var contentDetailsTitle = ',contentDetails'; 1758 var contentDetails = ',contentDetails(duration)'; 1759 }else{ 1760 var contentDetailsTitle = ''; 1761 var contentDetails = ''; 1762 } 1763 1764 //video, https://developers.google.com/youtube/v3/docs/videos 1765 //requestUrl = 'https://www.googleapis.com/youtube/v3/videos?id='+processData.path+'&key='+appId+'&part=id'+snippetTitle+',status'+contentDetailsTitle+'&fields=items(id,status(privacyStatus)'+snippet+contentDetails+')'; 1766 1767 //without privacy status 1768 requestUrl = 'https://www.googleapis.com/youtube/v3/videos?id='+processData.path+'&key='+appId+'&part=id'+snippetTitle+contentDetailsTitle+'&fields=items(id'+snippet+contentDetails+')'; 1769 1770 }else{ 1771 1772 if(type == 'youtube_playlist'){ 1773 1774 //no duration in contentDetails here 1775 1776 //https://developers.google.com/youtube/v3/docs/playlistItems/list 1777 //requestUrl = 'https://www.googleapis.com/youtube/v3/playlistItems?playlistId='+processData.path+'&maxResults='+maxResults+'&key='+appId+'&part=status'+snippetTitle+',contentDetails&fields=items(status(privacyStatus)'+snippet+',contentDetails(videoId))'; 1778 1779 //without privacy status 1780 requestUrl = 'https://www.googleapis.com/youtube/v3/playlistItems?playlistId='+processData.path+'&maxResults='+maxResults+'&key='+appId+'&part=contentDetails'+snippetTitle+'&fields=items(contentDetails(videoId)'+snippet+'),nextPageToken'; 1781 1782 } 1783 } 1784 1785 process(requestUrl); 1786 1787 } 1788 function process(url) { 1789 1790 if(xhrRequest){ 1791 xhrRequest.abort(); 1792 xhrRequest = null; 1793 } 1794 1795 xhrRequest = new XMLHttpRequest(); 1796 xhrRequest.onreadystatechange = function() { 1797 if (xhrRequest.readyState == 4) { 1798 1799 var response = JSON.parse(xhrRequest.responseText) 1800 1801 if(response.error && response.error.message){ 1802 console.log(response.error.message); 1803 return; 1804 } 1805 1806 var i, len = response.items.length, item; 1807 1808 nextPageToken = response.nextPageToken; 1809 if(nextPageToken)nextPageToken = requestUrl+'&pageToken='+nextPageToken;//we have to save whole nextPageToken if we load from cache and then load more on total scroll 1810 1811 for(i=0; i < len; i++){ 1812 if(finishData.length == limit)break; 1813 1814 item = response.items[i]; 1815 1816 if(type=='youtube_playlist' || type=='youtube_single' || type=='youtube_single_list'){ 1817 1818 if(item.status){ 1819 if(item.status.privacyStatus == 'public')finishData.push(getItemData(item, type)); 1820 }else if(item.snippet){ 1821 if(item.snippet.title != 'Private video')finishData.push(getItemData(item, type)); 1822 } 1823 } 1824 } 1825 1826 if(type=='youtube_single' || type=='youtube_single_list'){ 1827 1828 self.fireEvent('HAPYoutubeLoader.END_LOAD', [{data:finishData, nextPageToken:nextPageToken}]); 1829 1830 }else{ 1831 1832 if(finishData.length < limit){ 1833 1834 if(nextPageToken){ 1835 //adjust nextPageToken - when we request more than youtube can retrive (50) in one go, for example: 70 videos, in first request we will get 50 videos, then next page token will retrieve 50 videos again, but we only need next 20 videos! so we will loose leftover 30 videos from next page token. In this example we need to adjust maxResults to 20. 1836 1837 if(finishData.length + maxResults > limit){ 1838 maxResults = limit - finishData.length; 1839 var t1 = nextPageToken.substr(0,requestUrl.indexOf('&maxResults=')+12), 1840 t2 = nextPageToken.substr(requestUrl.indexOf('&key=')); 1841 nextPageToken = t1+maxResults.toString()+t2; 1842 } 1843 1844 if(type=='youtube_playlist'){ 1845 var url = nextPageToken; 1846 } 1847 1848 process(url); 1849 1850 }else{ 1851 1852 self.fireEvent('HAPYoutubeLoader.END_LOAD', [{data:finishData, nextPageToken:nextPageToken}]); 1853 1854 } 1855 }else{ 1856 1857 self.fireEvent('HAPYoutubeLoader.END_LOAD', [{data:finishData, nextPageToken:nextPageToken}]); 1858 1859 } 1860 } 1861 1862 1863 } 1864 } 1865 xhrRequest.onerror = function(e) { 1866 console.log('Error processYT: ' + e); 1867 1868 }; 1869 xhrRequest.open('GET', url); 1870 xhrRequest.send(); 1871 1872 } 1873 1874 function getItemData(item, type) { 1875 1876 var obj = HAPUtils.extendObj(true, {}, processData); 1877 obj.type = 'youtube'; 1878 1879 if(type=='youtube_single' || type=='youtube_single_list'){ 1880 obj.mp3 = item.id; 1881 }else if(type=='youtube_playlist'){ 1882 obj.mp3 = item.contentDetails.videoId; 1883 } 1884 1885 if(item.snippet){ 1886 //obj.snippet = item.snippet; 1887 if(!obj.title && item.snippet.title)obj.title = item.snippet.title; 1888 if(!obj.description && item.snippet.description)obj.description = item.snippet.description; 1889 if(item.snippet.publishedAt)obj.date = item.snippet.publishedAt; 1890 if(!item.thumb && item.snippet.thumbnails){ 1891 /* 1892 default 120x90 1893 medium 320x180 1894 high 480x360 1895 standard 640x480 1896 maxres 1280x720 1897 */ 1898 if(item.snippet.thumbnails.medium)obj.thumb = item.snippet.thumbnails.medium.url; 1899 else if(item.snippet.thumbnails.high)obj.thumb = item.snippet.thumbnails.high.url; 1900 else if(item.snippet.thumbnails.default)obj.thumb = item.snippet.thumbnails.default.url; 1901 } 1902 } 1903 1904 if(item.contentDetails){ 1905 if(item.contentDetails.duration)obj.duration = ytDur2Sec(item.contentDetails.duration); 1906 } 1907 1908 return obj; 1909 } 1910 1911 function ytDur2Sec(duration) { 1912 1913 var a = duration.match(/\d+/g); 1914 1915 if (duration.indexOf('M') >= 0 && duration.indexOf('H') == -1 && duration.indexOf('S') == -1) { 1916 a = [0, a[0], 0]; 1917 } 1918 1919 if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1) { 1920 a = [a[0], 0, a[1]]; 1921 } 1922 if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1 && duration.indexOf('S') == -1) { 1923 a = [a[0], 0, 0]; 1924 } 1925 1926 duration = 0; 1927 1928 if (a.length == 3) { 1929 duration = duration + parseInt(a[0]) * 3600; 1930 duration = duration + parseInt(a[1]) * 60; 1931 duration = duration + parseInt(a[2]); 1932 } 1933 1934 if (a.length == 2) { 1935 duration = duration + parseInt(a[0]) * 60; 1936 duration = duration + parseInt(a[1]); 1937 } 1938 1939 if (a.length == 1) { 1940 duration = duration + parseInt(a[0]); 1941 } 1942 return duration; 1943 } 1944 1945 this.getNextPageToken = function(){ 1946 return nextPageToken; 1947 } 1948 1949 }; 1950 1951 window.HAPYoutubeLoader = HAPYoutubeLoader; 1952 1953}(window)); 1954 1955 1956(function (window){ 1957 "use strict" 1958 var HAPPlaybackRateSlider = function (data){ 1959 1960 var self = this, 1961 _doc = document, 1962 _window = window, 1963 isMobile = HAPUtils.isMobile(), 1964 wrapper = data.wrapper, 1965 isPressed, 1966 isVertical = data.isVertical, 1967 prop = isVertical ? 'height' : 'width', 1968 tooltip = data.tooltip, 1969 e_holder = data.e_holder, 1970 sliderBg = data.sliderBg, 1971 sliderLevel = data.sliderLevel, 1972 seekbarHolder = data.seekbarHolder, 1973 seekbar = data.seekbar, 1974 rangeSize, 1975 events = HAPUtils.getEvents(), 1976 min = Number(data.settings.playbackRateMin),
1977 max = Number(data.settings.playbackRateMax), 1978 mobileSelect 1979 1980 HAPEventDispatcher.call(this); 1981 1982 if(isMobile && data.settings.useMobileSelect){ 1983 1984 var i, len = max+.1, p, o, select = '<select size="5" class="hap-mobile-playback-rate">' 1985 1986 for (i = min; i <= len; i+=.1){ 1987 p = parseFloat(i.toFixed(1)) 1988 1989 o = '<option value="'+p+'">'+p+'</option>' 1990 1991 select += o 1992 } 1993 1994 select += '</select>' 1995 1996 seekbarHolder.innerHTML = select 1997 1998 mobileSelect = seekbarHolder.querySelector('.hap-mobile-playback-rate') 1999 2000 }else{ 2001 2002 seekbar.addEventListener(events.downEvent,function(e){ 2003 onDragStart(e); 2004 }); 2005 2006 if("ontouchstart" in window){ 2007 seekbar.addEventListener('touchstart',function(e){ 2008 if(e.preventDefault) e.preventDefault(); 2009 2010 onDragStart(e); 2011 }); 2012 } 2013 2014 } 2015 2016 function onDragStart(e) { 2017 if(!isPressed){ 2018 isPressed = true; 2019 _doc.addEventListener(events.moveEvent, onDragMove) 2020 _doc.addEventListener(events.upEvent, onDragRelease); 2021 2022 if("ontouchstart" in window){ 2023 _doc.addEventListener('touchmove', onDragMove) 2024 _doc.addEventListener('touchend', onDragRelease); 2025 } 2026 } 2027 } 2028 2029 function onDragMove(e) { 2030 var point; 2031 if(e.type == 'touchmove'){ 2032 var touches = e.changedTouches; 2033 2034 if(touches.length > 1) { 2035 return false; 2036 } 2037 point = touches[0]; 2038 e.preventDefault(); 2039 } else { 2040 point = e; 2041 e.preventDefault(); 2042 } 2043 moveTo(point); 2044 2045 if(tooltip)mouseMoveHandlerTooltip(point); 2046 2047 } 2048 2049 function onDragRelease(e) { 2050 if(isPressed){ 2051 isPressed = false; 2052 _doc.removeEventListener(events.moveEvent, onDragMove) 2053 _doc.removeEventListener(events.upEvent, onDragRelease); 2054 2055 if("ontouchstart" in window){ 2056 _doc.removeEventListener('touchmove', onDragMove) 2057 _doc.removeEventListener('touchend', onDragRelease); 2058 } 2059 2060 var point; 2061 if(e.type == 'touchend'){ 2062 var touches = e.changedTouches; 2063 2064 if(touches.length > 1) { 2065 return false; 2066 } 2067 point = touches[0]; 2068 e.preventDefault(); 2069 } else { 2070 point = e; 2071 e.preventDefault(); 2072 } 2073 moveTo(point); 2074 2075 if(tooltip)tooltip.style.display = 'none'; 2076 2077 } 2078 2079 } 2080 2081 function moveTo(v) { 2082 2083 var rect = sliderBg.getBoundingClientRect() 2084 2085 var value; 2086 if(isVertical){ 2087 value = Math.max(0, Math.min(1, (v.pageY - rect.top) / rangeSize)); 2088 value = 1 - value;//reverse for up dir 2089 }else{ 2090 value = Math.max(0, Math.min(1, (v.pageX - rect.left) / rangeSize)); 2091 } 2092 2093 self.setValue(value); 2094 } 2095 2096 this.setValue = function(percent){ 2097 2098 if(!HAPUtils.isNumber(rangeSize) || rangeSize == 0){ 2099 e_holder.classList.add('hap-measure') 2100 rangeSize = isVertical ? sliderBg.offsetHeight : sliderBg.offsetWidth; 2101 e_holder.classList.remove('hap-measure') 2102 } 2103 2104 if(prop == 'width')sliderLevel.style.width = percent*rangeSize+'px'; 2105 else sliderLevel.style.height = percent*rangeSize+'px'; 2106 2107 //convert to playback rate 2108 var val = min+(max-min)*percent; 2109 val = Math.round( val * 10) / 10;//one decimal 2110 2111 self.fireEvent("HAPPlaybackRateSlider.RANGE_CHANGE", [{value:val}]); 2112 2113 } 2114 2115 this.setVisual = function(v){ 2116 2117 //convert to percent 2118 var percent = (v - min) / (max-min); 2119 2120 if(!HAPUtils.isNumber(rangeSize) || rangeSize == 0){ 2121 e_holder.classList.add('hap-measure') 2122 rangeSize = isVertical ? sliderBg.offsetHeight : sliderBg.offsetWidth; 2123 e_holder.classList.remove('hap-measure') 2124 } 2125 2126 if(prop == 'width')sliderLevel.style.width = percent*rangeSize+'px'; 2127 else sliderLevel.style.height = percent*rangeSize+'px'; 2128 2129 } 2130 2131 //############################################// 2132 /* tooltip */ 2133 //############################################// 2134 2135 if(!isMobile && tooltip){ 2136 seekbar.addEventListener('mouseover', function mouseOverHandlerSeek(){ 2137 if(isPressed)return; 2138 seekbar.addEventListener(events.moveEvent, mouseMoveHandlerTooltip) 2139 seekbar.addEventListener('mouseout', mouseOutHandler); 2140 2141 _doc.addEventListener('mouseout', mouseOutHandler); 2142 }); 2143 function mouseOutHandler() { 2144 seekbar.removeEventListener(events.moveEvent, mouseMoveHandlerTooltip) 2145 seekbar.removeEventListener('mouseout', mouseOutHandler); 2146 2147 _doc.removeEventListener('mouseout', mouseOutHandler); 2148 tooltip.style.display = 'none'; 2149 } 2150 } 2151 2152 function mouseMoveHandlerTooltip(e){ 2153 2154 var rect = sliderBg.getBoundingClientRect() 2155 2156 var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, 2157 scrollTop = window.pageYOffset || document.documentElement.scrollTop; 2158 2159 if(!isVertical)var s = e.pageX - rect.left - scrollLeft; 2160 else var s = e.pageY - rect.top - scrollTop; 2161 if(s < 0) s = 0; 2162 else if(s > rangeSize) s = rangeSize; 2163 var newPercent = Math.max(0, Math.min(1, s / rangeSize)); 2164 if(!HAPUtils.isNumber(newPercent))return false;
2165 if(isVertical)newPercent = 1 - newPercent;//reverse for up dir 2166 2167 var val = min+(max-min)*newPercent; 2168 val = Math.round( val * 10) / 10; 2169 2170 tooltip.style.display = 'block'; 2171 2172 tooltip.innerHTML = val; 2173 2174 var main = wrapper.getBoundingClientRect(), 2175 element = seekbar.getBoundingClientRect(); 2176 2177 var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, 2178 scrollTop = window.pageYOffset || document.documentElement.scrollTop; 2179 2180 if(isVertical){ 2181 var l = parseInt(element.left - main.left - tooltip.offsetWidth/2 + seekbar.offsetWidth/2), 2182 t = parseInt(e.pageY - scrollTop - main.top - tooltip.offsetHeight - 10); 2183 2184 //restrain 2185 if(t < element.top - main.top - tooltip.offsetHeight - 10)t = element.top - main.top - tooltip.offsetHeight - 10; 2186 else if(t > element.top - main.top + seekbar.offsetHeight - tooltip.offsetHeight) t = element.top - main.top + seekbar.offsetHeight - tooltip.offsetHeight; 2187 2188 }else{ 2189 var l = parseInt(e.pageX - scrollLeft - main.left - tooltip.offsetWidth/2), 2190 t = parseInt(element.top - main.top - tooltip.offsetHeight); 2191 2192 //restrain 2193 if(l < element.left - main.left)l = element.left - main.left; 2194 else if(l > element.left - main.left + seekbar.offsetWidth - tooltip.offsetWidth) l = element.left - main.left + seekbar.offsetWidth - tooltip.offsetWidth; 2195 } 2196 2197 //keep within component 2198 //if(t + main.top < 0)t = parseInt(element.top - main.top + tooltip.offsetHeight + 15);//position below 2199 //if(t < 0) t = 0; 2200 2201 tooltip.style.left = l+'px'; 2202 tooltip.style.top = t+'px'; 2203 2204 } 2205 2206 //init 2207 2208 this.setVisual(data.settings.playbackRate) 2209 2210 } 2211 2212 window.HAPPlaybackRateSlider = HAPPlaybackRateSlider; 2213 2214}(window)); 2215 2216 2217(function (window){ 2218 "use strict" 2219 var HAPRangeSlider = function (data){ 2220 2221 var self = this, 2222 _doc = document, 2223 _window = window, 2224 isPressed, 2225 events = HAPUtils.getEvents(), 2226 range_handle_a = data.range_handle_a, 2227 range_handle_b = data.range_handle_b, 2228 elem 2229 2230 HAPEventDispatcher.call(this); 2231 2232 range_handle_a.addEventListener(events.downEvent,function(e){ 2233 elem = e.currentTarget 2234 elem.style.zIndex = 1;//make last dragged z index higher, so we cannot drag into corner one over another 2235 range_handle_b.style.zIndex = 0; 2236 onDragStart(e); 2237 }); 2238 2239 range_handle_b.addEventListener(events.downEvent,function(e){ 2240 elem = e.currentTarget 2241 elem.style.zIndex = 1; 2242 range_handle_a.style.zIndex = 0; 2243 onDragStart(e); 2244 }); 2245 2246 if("ontouchstart" in window){ 2247 2248 range_handle_a.addEventListener('touchstart',function(e){ 2249 if(e.preventDefault) e.preventDefault(); 2250 2251 elem = e.currentTarget 2252 elem.style.zIndex = 1;//make last dragged z index higher, so we cannot drag into corner one over another 2253 range_handle_b.style.zIndex = 0; 2254 onDragStart(e); 2255 }); 2256 2257 range_handle_b.addEventListener('touchstart',function(e){ 2258 if(e.preventDefault) e.preventDefault(); 2259 2260 elem = e.currentTarget 2261 elem.style.zIndex = 1; 2262 range_handle_a.style.zIndex = 0; 2263 onDragStart(e); 2264 }); 2265 2266 } 2267 2268 function onDragStart(e) { 2269 if(!isPressed){ 2270 2271 isPressed = true; 2272 _doc.addEventListener(events.moveEvent, onDragMove); 2273 _doc.addEventListener(events.upEvent, onDragRelease); 2274 2275 if("ontouchstart" in window){ 2276 _doc.addEventListener('touchmove', onDragMove); 2277 _doc.addEventListener('touchend', onDragRelease); 2278 } 2279 } 2280 } 2281 2282 function onDragMove(e) { 2283 var point; 2284 if(e.type == 'touchmove'){ 2285 var touches = e.changedTouches; 2286 2287 if(touches.length > 1) { 2288 return false; 2289 } 2290 point = touches[0]; 2291 e.preventDefault(); 2292 } else { 2293 point = e; 2294 e.preventDefault(); 2295 } 2296 2297 self.fireEvent("HAPRangeSlider.RANGE_CHANGE", [{point:point, elem: elem, event:point}]); 2298 2299 } 2300 2301 function onDragRelease(e) { 2302 if(isPressed){ 2303 isPressed = false; 2304 _doc.removeEventListener(events.moveEvent, onDragMove) 2305 _doc.removeEventListener(events.upEvent, onDragRelease); 2306 2307 if("ontouchstart" in window){ 2308 _doc.removeEventListener('touchmove', onDragMove); 2309 _doc.removeEventListener('touchend', onDragRelease); 2310 } 2311 2312 var point; 2313 if(e.type == 'touchend'){ 2314 var touches = e.changedTouches; 2315 2316 if(touches.length > 1) { 2317 return false;
2318 } 2319 point = touches[0]; 2320 e.preventDefault(); 2321 } else { 2322 point = e; 2323 e.preventDefault(); 2324 } 2325 2326 self.fireEvent("HAPRangeSlider.RANGE_CHANGE", [{point:point, elem: elem}]); 2327 } 2328 2329 } 2330 2331 this.isDrag = function(){ 2332 return isPressed; 2333 } 2334 2335 } 2336 2337 window.HAPRangeSlider = HAPRangeSlider; 2338 2339}(window)); 2340 2341(function (window){ 2342 "use strict" 2343 var HAPLyrics = function (data){ 2344 2345 var self = this, 2346 2347 settings = data.settings, 2348 lyricsArr = [], 2349 lineElements = [], 2350 enabled = true, 2351 xhr, 2352 autoScroll = settings.lyricsAutoScroll, 2353 scrollContainer = data.scrollContainer, 2354 wrapContainer = data.wrapContainer 2355 2356 this.load = function(url){ 2357 2358 enabled = true; 2359 2360 if(window.location.protocol == 'file:'){ 2361 console.log('Getting lyrics requires server connection.'); 2362 return false; 2363 } 2364 2365 if(xhr){ 2366 xhr.abort(); 2367 xhr = null; 2368 } 2369 2370 xhr = new XMLHttpRequest(); 2371 xhr.onreadystatechange = function() { 2372 2373 if (xhr.readyState == 4) { 2374 if(!enabled)return 2375 2376 if(url.indexOf('.lrc') > -1){ 2377 var type = 'lrc' 2378 }else if(url.indexOf('.vtt') > -1){ 2379 var type = 'vtt' 2380 }else if(url.indexOf('.srt') > -1){ 2381 var type = 'srt' 2382 }else{ 2383 var type = 'lrc'//try to guess 2384 } 2385 2386 lyricsArr = [] 2387 2388 parseLyrics(type, xhr.responseText); 2389 createLyrics() 2390 2391 } 2392 } 2393 xhr.onerror = function(e) { 2394 console.log(e); 2395 }; 2396 xhr.open('GET', url); 2397 xhr.send(); 2398 2399 } 2400 2401 function createLyrics(){ 2402 2403 var n, len = lyricsArr.length, start, end, lineElement 2404 for(n=0; n<len; n++) { 2405 2406 start = lyricsArr[n].start 2407 2408 if(n<len-1)end = lyricsArr[n+1].start 2409 else end = lyricsArr[n].start 2410 2411 lineElement = document.createElement("div"); 2412 lineElement.className = data.itemClass; 2413 data.scrollContainer.appendChild(lineElement); 2414 lineElements.push(lineElement); 2415 2416 lineElement.dataset.start = start; 2417 lineElement.dataset.end = end; 2418 2419 lineElement.innerHTML = lyricsArr[n].text; 2420 2421 2422 if(settings.useSeekOnLyrics){ 2423 lineElement.addEventListener('click', function(e){ 2424 var time = Number(e.currentTarget.getAttribute('data-start')) 2425 var event = new CustomEvent("HAPLyrics.LYRICS_CLICKED", {"detail": time}); 2426 document.dispatchEvent(event); 2427 }); 2428 } 2429 2430 } 2431 2432 var event = new CustomEvent("HAPLyrics.LYRICS_READY", {"detail": lyricsArr}); 2433 document.dispatchEvent(event); 2434 2435 } 2436 2437 this.setAutoScroll = function(v){ 2438 autoScroll = v; 2439 } 2440 2441 this.setData = function(arr){ 2442 lyricsArr = arr; 2443 createLyrics() 2444 } 2445 2446 this.synchronize = function(currentTime) { 2447 2448 // Highlight the current transcript item. 2449 2450 var div_list = scrollContainer.querySelectorAll('.hap-lyrics-item').forEach(div => { 2451 2452 var start = parseFloat(div.getAttribute('data-start')), 2453 end = parseFloat(div.getAttribute('data-end')) 2454 2455 if (currentTime >= start && currentTime <= end) { 2456 2457 // If this item isn't already highlighted, it should be 2458 if (!div.classList.contains('hap-lyrics-item-active')) { 2459 // remove all previous highlights before adding one to current 2460 scrollContainer.querySelectorAll('.hap-lyrics-item').forEach(function(el){ 2461 el.classList.remove('hap-lyrics-item-active'); 2462 }) 2463 div.classList.add('hap-lyrics-item-active'); 2464 scrollContainer.movingHighlight = true; 2465 2466 } 2467 2468 return false; 2469 } 2470 2471 }); 2472 2473 scrollContainer.currentHighlight = scrollContainer.querySelector('.hap-lyrics-item-active'); 2474 if (!scrollContainer.currentHighlight) { 2475 scrollContainer.currentHighlight = null; 2476 } 2477 2478 if(autoScroll){ 2479 2480 if (scrollContainer.currentHighlight) { 2481 2482 var rect = scrollContainer.currentHighlight.getBoundingClientRect() 2483 2484 var newTop = Math.floor(wrapContainer.scrollTop + 2485 rect.top - 2486 (wrapContainer.offsetHeight / 2 + 2487 rect.height / 2)); 2488 2489 if (newTop != Math.floor(wrapContainer.scrollTop)) {
2490 // only scroll once after moving a highlight 2491 if (scrollContainer.movingHighlight) { 2492 //wrapContainer.scrollTop(newTop); 2493 scrollContainer.currentHighlight.scrollIntoView({behavior: 'smooth', block: 'nearest' }); 2494 2495 scrollContainer.movingHighlight = false; 2496 } 2497 } 2498 } 2499 2500 } 2501 } 2502 2503 function parseLyrics(type, data) { 2504 2505 if(type == 'lrc'){ 2506 2507 var lrcs = data.split('\n');//Use Enter to split into an array 2508 var i, len = lrcs.length; 2509 2510 for(i=0;i<len;i++) {//Traversing the lyrics array 2511 2512 lrcs[i] = lrcs[i].replace(/(^\s*)|(\s*$)/g, ""); //Remove spaces before and after 2513 var t = lrcs[i].substring(lrcs[i].indexOf("[") + 1, lrcs[i].indexOf("]"));//Fetch the contents of [] 2514 var s = t.split(":");//Separation: before and after text 2515 2516 if(isNaN(parseInt(s[0]))) {//Not a number 2517 //id tags 2518 2519 }else {//is a value 2520 2521 var arr = lrcs[i].match(/\[(\d+:.+?)\]/g);//Extract time field, there may be multiple 2522 var start = 0; 2523 var k, klen = arr.length; 2524 for(k=0;k<klen;k++){ 2525 start += arr[k].length; //Calculate the lyrics position 2526 } 2527 2528 var content = lrcs[i].substring(start);//Get lyrics content 2529 2530 if(!HAPUtils.isEmpty(content)){ 2531 for(k=0;k<klen;k++){ 2532 var t = arr[k].substring(1, arr[k].length-1);//Fetch the contents of [] 2533 var s = t.split(":");//Separation: before and after text 2534 lyricsArr.push({//object{t: time, c: lyrics} added to ms array 2535 start: (parseFloat(s[0])*60+parseFloat(s[1])).toFixed(3), 2536 text: content 2537 }); 2538 } 2539 } 2540 } 2541 } 2542 2543 }else if(type == 'vtt' || type == 'srt'){ 2544 2545 var srt = data.replace(/\r\n|\r|\n/g, '\n'); 2546 2547 srt = HAPUtils.strip(srt); 2548 2549 var sub = srt.split('\n\n'), s, st, z = 0, j, number, start, end, text; 2550 2551 for(s in sub) { 2552 2553 st = sub[s].split('\n'); 2554 2555 if(st == "WEBVTT")continue; 2556 2557 if(st.length >= 2) { 2558 //number = st[0]; 2559 2560 if(st[0] == "WEBVTT")continue; 2561 2562 if(st.length > 2){ 2563 2564 start = HAPUtils.strip(st[1].split(' --> ')[0]); 2565 end = HAPUtils.strip(st[1].split(' --> ')[1]); 2566 text = st[2]; 2567 2568 if(st.length > 3) { 2569 for(j=3; j<st.length;j++){ 2570 text += '\n'+st[j]; 2571 } 2572 } 2573 2574 }else{ 2575 start = HAPUtils.strip(st[0].split(' --> ')[0]); 2576 end = HAPUtils.strip(st[0].split(' --> ')[1]); 2577 text = st[1]; 2578 } 2579 2580 lyricsArr[z] = {}; 2581 lyricsArr[z].start = HAPUtils.formatTimeWithMiliseconds(start); 2582 lyricsArr[z].end = HAPUtils.formatTimeWithMiliseconds(end); 2583 lyricsArr[z].text = text; 2584 2585 z++; 2586 2587 } 2588 } 2589 2590 } 2591 2592 //console.log(lyricsArr) 2593 2594 } 2595 2596 this.deactivate = function(){ 2597 2598 if(xhr){ 2599 xhr.abort(); 2600 xhr = null; 2601 } 2602 enabled = false; 2603 2604 data.scrollContainer.innerHTML = '' 2605 } 2606 2607 }; 2608 2609 window.HAPLyrics = HAPLyrics; 2610 2611}(window)); 2612 2613(function (window){ 2614 "use strict" 2615 var HAPDialog = function (wrap, data, settings){ 2616 2617 var self = this, 2618 wrapper = wrap, 2619 elements = data, 2620 activeDrag, 2621 events = HAPUtils.getEvents(), 2622 _doc = document, 2623 activeResize 2624 2625 function resizeDialog(element, w, h, save){ 2626 2627 if(element == 'lyrics'){ 2628 var dialog = getResizeItem2('lyrics') 2629 var storage_key = 'hap_lyrics_dialog_'+settings.instanceName 2630 } 2631 else if(element == 'video'){ 2632 var dialog = getResizeItem2('video') 2633 var storage_key = 'hap_video_dialog_'+settings.instanceName 2634 } 2635 2636 //not bigger than screen 2637 var wv = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, 2638 wh = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 2639 2640 if(w > wv) w = wv; 2641 if(h > wh) h = wh; 2642 2643 dialog.style.width = w + 'px'; 2644 dialog.style.height = h + 'px'; 2645 2646 var innerHeight = h - 75;//header + padding bottom height 2647 2648 dialog.querySelector('.hap-dialog-content').style.height = innerHe
2648ight + 'px'; 2649 2650 if(element == 'lyrics'){ 2651 2652 dialog.querySelector('.hap-lyrics-wrap').style.height = innerHeight + 'px'; 2653 2654 }else if(element == 'video'){ 2655 2656 dialog.querySelector('.hap-video-wrap').style.height = innerHeight + 'px'; 2657 dialog.querySelector('.hap-video-wrap').style.width = w + 'px'; 2658 } 2659 2660 //save 2661 if(localStorage && save){ 2662 if(localStorage.getItem(storage_key)){ 2663 var l = JSON.parse(localStorage.getItem(storage_key)) 2664 }else{ 2665 var l = {} 2666 } 2667 2668 var pos = dialog.getBoundingClientRect() 2669 l.pos = pos 2670 2671 localStorage.setItem(storage_key, JSON.stringify(l)); 2672 } 2673 2674 } 2675 2676 function getDragItem(target){ 2677 2678 var i, len = elements.length, found 2679 2680 for (i = 0;i < len; i++) { 2681 if(target == elements[i].itemHandle){ 2682 activeDrag = elements[i] 2683 2684 found = true 2685 break; 2686 } 2687 } 2688 return found; 2689 } 2690 2691 function getResizeItem(target){ 2692 2693 var i, len = elements.length, found 2694 2695 for (i = 0;i < len; i++) { 2696 if(target == elements[i].itemResizeHandle){ 2697 activeResize = elements[i] 2698 found = true 2699 break; 2700 } 2701 } 2702 return found; 2703 } 2704 2705 function getResizeItem2(element){ 2706 2707 var i, len = elements.length, item 2708 2709 for (i = 0;i < len; i++) { 2710 if(element == elements[i].element){ 2711 item = elements[i].itemDialog; 2712 break; 2713 } 2714 } 2715 return item; 2716 } 2717 2718 //drag 2719 2720 function onDragStart(e) { 2721 2722 if (getDragItem(e.target)) { 2723 2724 if(e.type == 'touchstart'){ 2725 2726 var touches = e.changedTouches; 2727 2728 if(touches.length > 1) { 2729 return false; 2730 } 2731 2732 activeDrag.initialX = touches[0].pageX - activeDrag.xOffset; 2733 activeDrag.initialY = touches[0].pageY - activeDrag.yOffset; 2734 2735 e.preventDefault(); 2736 }else{ 2737 e.preventDefault(); 2738 2739 activeDrag.initialX = e.pageX - activeDrag.xOffset; 2740 activeDrag.initialY = e.pageY - activeDrag.yOffset; 2741 2742 } 2743 2744 _doc.addEventListener(events.moveEvent, onDragMove) 2745 _doc.addEventListener(events.upEvent, onDragRelease); 2746 2747 if("ontouchstart" in window){ 2748 _doc.addEventListener('touchmove', onDragMove); 2749 _doc.addEventListener('touchend', onDragRelease); 2750 } 2751 2752 } 2753 2754 } 2755 2756 function onDragMove(e) { 2757 2758 if (activeDrag) { 2759 2760 if(e.type == 'touchmove'){ 2761 var touches = e.changedTouches; 2762 2763 if(touches.length > 1) { 2764 return false; 2765 } 2766 e.preventDefault(); 2767 2768 activeDrag.currentX = touches[0].pageX - activeDrag.initialX; 2769 activeDrag.currentY = touches[0].pageY - activeDrag.initialY; 2770 2771 } else { 2772 e.preventDefault(); 2773 2774 activeDrag.currentX = e.pageX - activeDrag.initialX; 2775 activeDrag.currentY = e.pageY - activeDrag.initialY; 2776 } 2777 2778 activeDrag.xOffset = activeDrag.currentX; 2779 activeDrag.yOffset = activeDrag.currentY; 2780 2781 activeDrag.itemDialog.style.left = activeDrag.currentX + "px"; 2782 activeDrag.itemDialog.style.top = activeDrag.currentY + "px"; 2783 2784 2785 } 2786 2787 } 2788 2789 function onDragRelease(e) { 2790 2791 if(activeDrag){ 2792 2793 _doc.removeEventListener(events.moveEvent, onDragMove) 2794 _doc.removeEventListener(events.upEvent, onDragRelease); 2795 2796 if("ontouchstart" in window){ 2797 _doc.removeEventListener('touchmove', onDragMove); 2798 _doc.removeEventListener('touchend', onDragRelease); 2799 } 2800 2801 activeDrag.initialX = activeDrag.currentX; 2802 activeDrag.initialY = activeDrag.currentY; 2803 2804 if(activeDrag.itemDialog.classList.contains('hap-lyrics-holder')){ 2805 2806 if(localStorage){ 2807 if(localStorage.getItem('hap_lyrics_dialog_'+settings.instanceName)){ 2808 var l = JSON.parse(localStorage.getItem('hap_lyrics_dialog_'+settings.instanceName)) 2809 }else{ 2810 var l = {} 2811 } 2812 2813 l.currentX = activeDrag.currentX; 2814 l.currentY = activeDrag.currentY; 2815 2816 localStorage.setItem('hap_lyrics_dialog_'+settings.instanceName, JSON.stringify(l)); 2817 } 2818 2819 } 2820 else if(activeDrag.itemDialog.classList.contains('hap-video-holder')){ 2821 2822 if(localStorage){ 2823 if(localStorage.getItem('hap_video_dialog_'+settings.instanceName)){ 2824 var l = JSON.parse(localStorage.getItem('hap_video_dialog_'+settings.instanceName)) 2825 }else{ 2826 var l = {} 2827 } 2828 2829 l.currentX = activeDrag.currentX; 2830 l.currentY = activeDrag.currentY; 2831 2832 localStorage.setItem('hap_video_dialog_'+settings.instanceName, JSON.stringify(l)); 2833 } 2834 2835 } 2836 2837 activeDrag = null; 2838 2839 } 2840 2841 } 2842 2843 this.setTranslateInit = function(selector, xPos, yPos) {//restore position 2844 2845 var i, len = elements.length, el 2846 for (i = 0;i < len; i++) { 2847 //only if draggable (is dialog) 2848 if(elements[i].itemDialog.classList.contains('hap-dialog') && elements[i].itemDialog.classList.contains(selector)){ 2849 el = elements[i] 2850 break; 2851 } 2852 } 2853 2854 if(el){ 2855 //start in center like fixed 2856 var player_bound = wrapper.getBoundingClientRect() 2857 2858 el.itemDialog.classList.add('hap-dialog-force-hide') 2859 2860 var x = window.innerWidth / 2; 2861 var y = window.innerHeight / 2; 2862 var rect = el.itemDialog.getBoundingClientRect() 2863 2864 xPos = x - rect.width / 2// - player_bound.left; 2865 yPos = y - rect.height / 2 //- player_bound.top; 2866 2867 if(isNaN(xPos))xPos = 0; 2868 if(isNaN(yPos))yPos = 0; 2869 2870 if(xPos < 0)xPos = 0; 2871 if(yPos < 0)yPos = 0; 2872 2873 el.itemDialog.style.left = xPos + "px"; 2874 el.itemDialog.style.top = yPos + "px"; 2875 2876 el.initialX = xPos; 2877 el.initialY = yPos; 2878 2879 el.currentX = xPos; 2880 el.currentY = yPos; 2881 2882 el.xOffset = xPos; 2883 el.yOffset = yPos; 2884 2885 el.dragInited = true 2886 2887 el.itemDialog.classList.remove('hap-dialog-force-hide') 2888 2889 } 2890 2891 } 2892 2893 //resize 2894 2895 function onDialogResizeStart(e) { 2896 2897 if (getResizeItem(e.target)) { 2898 2899 var point; 2900 if(e.type == 'touchstart'){ 2901 var touches = e.changedTouches; 2902 2903 if(touches.length > 1) { 2904 return false;
2905 } 2906 point = touches[0]; 2907 e.preventDefault(); 2908 }else{ 2909 point = e; 2910 e.preventDefault(); 2911 } 2912 2913 activeResize.startMouseX = point.pageX 2914 activeResize.startMouseY = point.pageY 2915 activeResize.dragStartWidth = activeResize.itemDialog.offsetWidth 2916 activeResize.dragStartHeight = activeResize.itemDialog.offsetHeight 2917 2918 _doc.addEventListener(events.moveEvent, onDialogResizeMove) 2919 _doc.addEventListener(events.upEvent, onDialogResizeRelease); 2920 2921 if("ontouchstart" in window){ 2922 _doc.addEventListener('touchmove', onDialogResizeMove); 2923 _doc.addEventListener('touchend', onDialogResizeRelease); 2924 } 2925 } 2926 2927 } 2928 2929 function onDialogResizeMove(e) { 2930 2931 var point; 2932 if(e.type == 'touchmove'){ 2933 var touches = e.changedTouches; 2934 2935 if(touches.length > 1) { 2936 return false; 2937 } 2938 point = touches[0]; 2939 e.preventDefault(); 2940 } else { 2941 point = e; 2942 e.preventDefault(); 2943 } 2944 2945 var w = parseInt(activeResize.dragStartWidth + (point.pageX - activeResize.startMouseX),10), 2946 h = parseInt(activeResize.dragStartHeight + (point.pageY - activeResize.startMouseY),10) 2947 2948 if(w < activeResize.itemResizeMinW) w = activeResize.itemResizeMinW; 2949 if(h < activeResize.itemResizeMinH) h = activeResize.itemResizeMinH; 2950 2951 resizeDialog(activeResize.element, w, h, true) 2952 2953 } 2954 2955 function onDialogResizeRelease(e) { 2956 if(activeResize){ 2957 activeResize = null; 2958 _doc.removeEventListener(events.moveEvent, onDialogResizeMove) 2959 _doc.removeEventListener(events.upEvent, onDialogResizeRelease); 2960 2961 if("ontouchstart" in window){ 2962 _doc.removeEventListener('touchmove', onDialogResizeMove); 2963 _doc.removeEventListener('touchend', onDialogResizeRelease); 2964 } 2965 } 2966 2967 } 2968 2969 //init 2970 2971 if(settings.clearDialogCacheOnStart || settings.isPopup){ 2972 if(localStorage){ 2973 localStorage.removeItem('hap_lyrics_dialog_'+settings.instanceName) 2974 localStorage.removeItem('hap_video_dialog_'+settings.instanceName) 2975 } 2976 } 2977 2978 2979 2980 var i, len = elements.length, item 2981 for (i = 0;i < len; i++) { 2982 item = elements[i] 2983 item.xOffset = 0 2984 item.yOffset = 0 2985 2986 item.itemHandle.addEventListener(events.downEvent,function(e){ 2987 onDragStart(e); 2988 }); 2989 2990 if("ontouchstart" in window){ 2991 2992 item.itemHandle.addEventListener('touchstart',function(e){ 2993 if(e.preventDefault) e.preventDefault(); 2994 onDragStart(e); 2995 }); 2996 2997 } 2998 2999 if(item.itemResizeHandle){ 3000 item.itemResizeHandle.addEventListener(events.downEvent,function(e){ 3001 onDialogResizeStart(e); 3002 }); 3003 3004 if("ontouchstart" in window){ 3005 3006 item.itemResizeHandle.addEventListener('touchstart',function(e){ 3007 if(e.preventDefault) e.preventDefault(); 3008 onDialogResizeStart(e); 3009 }); 3010 3011 } 3012 } 3013 3014 if(item.element == 'lyrics'){ 3015 3016 //autoscroll checkbox 3017 3018 item.itemDialog.querySelector('.hap-lyrics-autoscroll').addEventListener('change', function(e){ 3019 3020 var lyricsAutoScroll = e.currentTarget.checked; 3021 3022 var event = new CustomEvent("HAPDialog.LYRICS_AUTOSCROLL_CHANGE", {"detail": lyricsAutoScroll}); 3023 document.dispatchEvent(event); 3024 3025 //save 3026 if(localStorage){ 3027 if(localStorage.getItem('hap_lyrics_dialog_'+settings.instanceName)){ 3028 var l = JSON.parse(localStorage.getItem('hap_lyrics_dialog_'+settings.instanceName)) 3029 }else{ 3030 var l = {} 3031 } 3032 l.autoScroll = lyricsAutoScroll 3033 3034 localStorage.setItem('hap_lyrics_dialog_'+settings.instanceName, JSON.stringify(l)); 3035 } 3036 }) 3037 3038 if(localStorage && localStorage.getItem('hap_lyrics_dialog_'+settings.instanceName)){ 3039 3040 var l = JSON.parse(localStorage.getItem('hap_lyrics_dialog_'+settings.instanceName)) 3041 console.log(l) 3042 if(l.pos){ 3043 var w = l.pos.width, h = l.pos.height 3044 resizeDialog('lyrics', w, h) 3045 }else{ 3046 var width = window.getComputedStyle(wrapper.querySelector(".hap-lyrics-holder")).getPropertyValue("width"); 3047 } 3048 3049 if(l.currentX && l.currentY){//restore position 3050 self.setTranslateInit('hap-lyrics-holder', l.currentX, l.currentY) 3051 } 3052 3053 var checked = l.autoScroll ? true : false;
3054 item.itemDialog.querySelector('.hap-lyrics-autoscroll').checked = true; 3055 3056 var event = new CustomEvent("HAPDialog.LYRICS_AUTOSCROLL_CHANGE", {"detail": l.autoScroll}); 3057 document.dispatchEvent(event); 3058 3059 }else{ 3060 if(settings.lyricsAutoScroll){ 3061 item.itemDialog.querySelector('.hap-lyrics-autoscroll').checked = true; 3062 3063 var event = new CustomEvent("HAPDialog.LYRICS_AUTOSCROLL_CHANGE", {"detail": settings.lyricsAutoScroll}); 3064 document.dispatchEvent(event); 3065 } 3066 self.setTranslateInit('hap-lyrics-holder', 0, 0) 3067 } 3068 3069 } 3070 else if(item.element == 'video'){ 3071 3072 if(localStorage && localStorage.getItem('hap_video_dialog_'+settings.instanceName)){ 3073 var l = JSON.parse(localStorage.getItem('hap_video_dialog_'+settings.instanceName)) 3074 3075 if(l.pos){ 3076 var w = l.pos.width, h = l.pos.height 3077 resizeDialog('video', w, h) 3078 } 3079 3080 if(l.currentX && l.currentY){//restore position 3081 self.setTranslateInit('hap-video-holder', l.currentX, l.currentY) 3082 } 3083 3084 }else{ 3085 self.setTranslateInit('hap-video-holder', 0, 0)//restore layout if we open in popup 3086 } 3087 3088 } 3089 3090 } 3091 3092 }; 3093 3094 window.HAPDialog = HAPDialog; 3095 3096}(window)); 3097 3098 3099(function (window){ 3100 "use strict" 3101 var HAPVolumeSlider = function (data){ 3102 3103 var self = this, 3104 isMobile = HAPUtils.isMobile(), 3105 _window = window, 3106 settings = data.settings, 3107 tooltip = data.tooltip, 3108 parent = data.parent, 3109 3110 volumeToggle = data.container.querySelector('.hap-volume-toggle'), 3111 volumeSeekbar = data.container.querySelector('.hap-volume-seekbar'), 3112 volumeBg = data.container.querySelector('.hap-volume-bg'), 3113 volumeLevel = data.container.querySelector('.hap-volume-level'), 3114 3115 _doc = document, 3116 events = HAPUtils.getEvents(), 3117 3118 volume = data.volume, 3119 volumeBarDown, 3120 volumeVertical, 3121 volumeSize 3122 3123 HAPEventDispatcher.call(this); 3124 3125 if(volumeSeekbar){ 3126 volumeVertical = volumeSeekbar.classList.contains('hap-volume-vertical'), 3127 volumeSize = volumeVertical ? volumeBg.clientHeight : volumeBg.clientWidth; 3128 3129 volumeSeekbar.addEventListener(events.downEvent,function(e){ 3130 if(data.parent.isCrossFade()) return false; 3131 onDragStartVolume(e); 3132 }); 3133 3134 if("ontouchstart" in window){ 3135 3136 volumeSeekbar.addEventListener('touchstart',function(e){ 3137 if(e.preventDefault) e.preventDefault(); 3138 if(data.parent.isCrossFade()) return false; 3139 onDragStartVolume(e); 3140 }); 3141 3142 } 3143 } 3144 3145 if(!volumeSeekbar || volumeToggle && volumeToggle.classList.contains('hap-volume-toggable')){ 3146 if(volumeToggle){ 3147 volumeToggle.addEventListener('click', function(){ 3148 self.fireEvent("HAPVolumeSlider.TOGGLE_MUTE"); 3149 }) 3150 } 3151 } 3152 3153 function onDragStartVolume(e) { 3154 if(!volumeBarDown){ 3155 var point; 3156 if(e.type == 'touchstart'){ 3157 var touches = e.changedTouches; 3158 3159 if(touches.length > 1) { 3160 return false; 3161 } 3162 point = touches[0]; 3163 e.preventDefault(); 3164 }else{ 3165 point = e; 3166 e.preventDefault(); 3167 } 3168 volumeBarDown = true; 3169 _doc.addEventListener(events.moveEvent, onDragMoveVolume) 3170 _doc.addEventListener(events.upEvent, onDragReleaseVolume); 3171 3172 if("ontouchstart" in window){ 3173 _doc.addEventListener('touchmove', onDragMoveVolume); 3174 _doc.addEventListener('touchend', onDragReleaseVolume); 3175 } 3176 } 3177 } 3178 3179 function onDragMoveVolume(e) { 3180 var point; 3181 if(e.type == 'touchmove'){ 3182 var touches = e.changedTouches; 3183 3184 if(touches.length > 1) { 3185 return false; 3186 } 3187 point = touches[0]; 3188 e.preventDefault(); 3189 } else { 3190 point = e; 3191 e.preventDefault(); 3192 } 3193 volumeTo(point); 3194 3195 if(tooltip)mouseMoveHandlerVolumeTooltip(point); 3196 3197 } 3198 3199 function onDragReleaseVolume(e) { 3200 if(volumeBarDown){ 3201 volumeBarDown = false; 3202 _doc.removeEventListener(events.moveEvent, onDragMoveVolume) 3203 _doc.removeEventListener(events.upEvent, onDragReleaseVolume); 3204 3205 if("ontouchstart" in window){ 3206 _doc.removeEventListener('touchmove', onDragMoveVolume); 3207 _doc.removeEventListener('touchend', onDragReleaseVolume); 3208 } 3209 3210 var point; 3211 if(e.type == 'touchend'){ 3212 var touches = e.changedTouches; 3213 3214 if(touches.length > 1) { 3215 return false;
3216 } 3217 point = touches[0]; 3218 e.preventDefault(); 3219 } else { 3220 point = e; 3221 e.preventDefault(); 3222 } 3223 volumeTo(point); 3224 3225 if(tooltip)tooltip.style.display = 'none'; 3226 3227 } 3228 3229 } 3230 3231 function volumeTo(v) { 3232 var rect = volumeBg.getBoundingClientRect() 3233 3234 var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, 3235 scrollTop = window.pageYOffset || document.documentElement.scrollTop; 3236 3237 volumeSize = volumeVertical ? rect.height : rect.width; 3238 3239 if(volumeVertical){ 3240 volume = Math.max(0, Math.min(1, (v.pageY - rect.top - scrollTop) / volumeSize)); 3241 volume = 1 - volume;//reverse for up dir 3242 }else{ 3243 volume = Math.max(0, Math.min(1, (v.pageX - rect.left - scrollLeft) / volumeSize)); 3244 } 3245 self.setValue(volume); 3246 } 3247 3248 this.setValue = function(volume){ 3249 3250 self.setVisual(volume) 3251 3252 self.fireEvent("HAPVolumeSlider.VOLUME_CHANGE", [{volume:volume}]); 3253 3254 } 3255 3256 this.setVisual = function(v){ 3257 3258 volume = v; 3259 3260 if(volumeBg){ 3261 3262 var rect = volumeBg.getBoundingClientRect() 3263 3264 volumeSize = volumeVertical ? rect.height : rect.width; 3265 3266 var prop = volumeVertical ? 'height' : 'width'; 3267 3268 if(prop == 'width')volumeLevel.style.width = volume * volumeSize+'px'; 3269 else volumeLevel.style.height = volume * volumeSize+'px'; 3270 3271 } 3272 3273 if(volumeToggle){ 3274 3275 volumeToggle.querySelectorAll('.hap-btn').forEach(function(el){ 3276 el.style.display = 'none'; 3277 }) 3278 3279 volumeToggle.querySelectorAll('.hap-sticky-btn').forEach(function(el){ 3280 el.style.display = 'none'; 3281 }) 3282 3283 if(volume == 0){ 3284 volumeToggle.querySelector('.hap-btn-volume-off').style.display = 'block'; 3285 }else if(volume > 0 && volume < 0.5){ 3286 volumeToggle.querySelector('.hap-btn-volume-down').style.display = 'block'; 3287 }else{ 3288 volumeToggle.querySelector('.hap-btn-volume-up').style.display = 'block'; 3289 } 3290 3291 } 3292 3293 } 3294 3295 //############################################// 3296 /* volume tooltip */ 3297 //############################################// 3298 3299 if(tooltip && !isMobile && volumeSeekbar){ 3300 volumeSeekbar.addEventListener('mouseover', function mouseOverHandlerSeek(){ 3301 if(volumeBarDown)return; 3302 3303 volumeSeekbar.addEventListener(events.moveEvent, mouseMoveHandlerVolumeTooltip) 3304 volumeSeekbar.addEventListener('mouseout', mouseOutHandlerVolume); 3305 3306 _doc.addEventListener('mouseout', mouseOutHandlerVolume); 3307 }); 3308 } 3309 3310 function mouseOutHandlerVolume() { 3311 volumeSeekbar.removeEventListener(events.moveEvent, mouseMoveHandlerVolumeTooltip) 3312 volumeSeekbar.removeEventListener('mouseout', mouseOutHandlerVolume); 3313 3314 _doc.removeEventListener('mouseout', mouseOutHandlerVolume); 3315 3316 tooltip.style.display = 'none'; 3317 } 3318 3319 function mouseMoveHandlerVolumeTooltip(e){ 3320 3321 let volumeBg_rect = volumeBg.getBoundingClientRect(); 3322 3323 var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, 3324 scrollTop = window.pageYOffset || document.documentElement.scrollTop; 3325 3326 if(!volumeVertical)var s = e.pageX - volumeBg_rect.left - scrollLeft; 3327 else var s = e.pageY - volumeBg_rect.top - scrollTop; 3328 if(s<0) s=0; 3329 else if(s>volumeSize) s=volumeSize; 3330 3331 var newPercent = Math.max(0, Math.min(1, s / volumeSize)); 3332 if(!HAPUtils.isNumber(newPercent))return false; 3333 if(volumeVertical)newPercent = 1 - newPercent;//reverse for up dir 3334 var value = parseInt(newPercent * 100, 10); 3335 3336 tooltip.innerHTML = value + ' %'; 3337 3338 tooltip.style.display = 'block'; 3339 3340 var main = data.container.getBoundingClientRect(), 3341 element = volumeSeekbar.getBoundingClientRect(); 3342 3343 if(volumeVertical){ 3344 var l = parseInt(element.left + element.width/2 - main.left- tooltip.offsetWidth/2), 3345 t = parseInt(e.pageY - scrollTop - main.top - tooltip.offsetHeight - 20); 3346 3347 //restrain 3348 if(t < element.top - main.top - tooltip.offsetHeight - 10)t = element.top - main.top - tooltip.offsetHeight - 10; 3349 else if(t > element.top - main.top + volumeSeekbar.offsetHeight - tooltip.offsetHeight) t = element.top - main.top + volumeSeekbar.offsetHeight - tooltip.offsetHeight; 3350 3351 }else{ 3352 3353 var l = parseInt(e.pageX - scrollLeft - main.left - tooltip.offsetWidth/2), 3354 t = parseInt(element.top - main.top - tooltip.offsetHeight) - 15; 3355 3356 //restrain 3357 if(l < element.left - main.left)l = element.left - main.left; 3358 else if(l > element.left - main.left + volumeSeekbar.offsetWidth - tooltip.offsetWidth) l = element.left - main.left + volumeSeekbar.offsetWidth - tooltip.offsetWidth; 3359 3360 } 3361 3362 if(l < 0 || t < 0){//if we have a seekbar that shows on hover it will hide when we hold and press outside seekbar. 3363 //tooltip.style.display = 'none'; 3364 //return; 3365 } 3366 3367 if(t + main.top < 0)t = parseInt(element.top - main.top + tooltip.offsetHeight + 20);//position below 3368 //if(t < 0) t = 0; 3369 3370 tooltip.style.top = t+'px' 3371 tooltip.style.left = l+'px' 3372 3373 } 3374 3375 3376 //init 3377 setTimeout(function(){ 3378 self.setVisual(volume); 3379 },200) 3380 3381 }; 3382 3383 window.HAPVolumeSlider = HAPVolumeSlider; 3384 3385}(window)); 3386 3387 3388(function() { 3389 3390 var hap = function(delem, settings) { 3391 3392 "use strict" 3393 3394 var self = this; 3395 3396 HAPEventDispatcher.call(this); 3397 3398 //############################################// 3399 /* settings */ 3400 //############################################// 3401 3402 var defaults = { 3403 //scripts
3404 gtag_js: "//www.googletagmanager.com/gtag/js?id=", 3405 sharemanager_js: "js/sharemanager.js", 3406 perfectScrollbar_js: 'js/perfect-scrollbar.min.js', 3407 imaLoader_js: 'js/imaloader.js', 3408 sortable_js: 'js/sortable.min.js', 3409 ima_js: '//imasdk.googleapis.com/js/sdkloader/ima3.js', 3410 md5_js: "https://cdnjs.cloudflare.com/ajax/libs/blueimp-md5/2.10.0/js/md5.min.js", 3411 mediaId:null, 3412 mediaTitle:null, 3413 resumeTime:null,//we use this to set audio start time, we cant use start alone in querystring because query playlist does not exist (unless we have other required query string parameters for playlist, then we can use start) 3414 sourcePath:"", 3415 instanceName: "", 3416 queryInstance: "", 3417 playlistItemContent:"", 3418 playlistTitleOrder:"title,artist", 3419 statisticsContent:"plays,likes,downloads", 3420 dataInterval: 250, 3421 volume:0.5, 3422 activeItem:0, 3423 numberTitleSeparator:". ", 3424 artistTitleSeparator:" - ", 3425 embedSrc: 'Embed url goes here', 3426 useNumbersInPlaylist:false, 3427 preload:"auto", 3428 autoPlay:false, 3429 loopState:"playlist", 3430 playbackRate:1, 3431 addResizeEvent:true, 3432 sortableTracksSet:false, 3433 togglePlaybackOnPlaylistItem:false, 3434 pauseAudioDuringAds:true, 3435 randomPlay:false, 3436 usePlaylist:true, 3437 waveOptions: { 3438 barHeight: 1, 3439 halfPixel: 0.5 / 1, 3440 barMinHeight: null, 3441 normalize: false, 3442 partialRender: false, 3443 pixelRatio:1, 3444 barWidth: 1, 3445 barRadius: 0, 3446 barGap: 5, 3447 }, 3448 demoPeakArr: [ 3449 3450 '0.05,-0.11,0.27,-0.57,0.19,-0.12,0.14,-0.12,0.13,-0.07,0.11,-0.11,0.12,-0.14,0.31,-0.16,0.29,-0.09,0.15,-0.24,0.18,-0.45,0.3,-0.16,0.24,-0.1,0.1,-0.2,0.16,-0.13,0.12,-0.13,0.34,-0.13,0.44,-0.22,0.54,-0.32,0.48,-0.24,0.57,-0.51,0.54,-0.42,0.22,-0.44,0.31,-0.37,0.58,-0.57,0.58,-0.69,0.75,-0.41,0.41,-0.22,0.66,-0.68,0.64,-0.36,0.42,-0.41,0.34,-0.56,0.37,-0.38,0.33,-0.49,0.38,-0.37,0.41,-0.4,0.55,-0.58,0.4,-0.33,0.35,-0.43,0.16,-0.26,0.26,-0.33,0.38,-0.3,0.23,-0.56,0.52,-0.39,0.41,-0.89,0.49,-0.36,0.43,-0.42,0.35,-0.36,0.48,-0.28,0.34,-0.35,0.78,-0.18,0.63,-0.43,0.13,-0.34,0.18,-0.44,0.35,-0.14,0.22,-0.36,0.26,-0.13,0.28,-0.31,0.31,-0.32,0.29,-0.33,0.26,-0.27,0.36,-0.21,0.16,-0.28,0.55,-0.34,0.38,-0.42,0.53,-0.71,0.56,-0.65,0.81,-0.55,0.55,-0.46,0.67,-0.71,0.96,-0.89,0.88,-0.54,0.65,-0.51,0.55,-0.47,0.79,-0.34,0.66,-0.45,0.57,-0.73,0.66,-0.71,0.59,-0.77,0.64,-0.32,0.65,-0.22,0.5,-0.7,0.62,-0.67,0.52,-0.57,0.8,-0.5,0.69,-0.67,0.79,-0.63,0.63,-0.8,0.78,-0.59,0.73,-0.6,0.65,-0.72,0.8,-0.65,0.84,-0.74,0.64,-0.56,0.75,-0.81,0.42,-0.19,0.25,-0.15,0.1,-0.04,0.07,-0.11,0.08,-0.06', 3451 3452 '0.09,-0.09,0.16,-0.12,0.14,-0.28,0.18,-0.31,0.26,-0.29,0.34,-0.3,0.32,-0.2,0.44,-0.22,0.34,-0.28,0.22,-0.19,0.18,-0.29,0.26,-0.21,0.3,-0.14,0.23,-0.17,0.2,-0.36,0.26,-0.19,0.28,-0.2,0.16,-0.19,0.33,-0.15,0.27,-0.21,0.3,-0.35,0.23,-0.3,0.55,-0.35,0.49,-0.32,0.61,-0.35,0.28,-0.2,0.27,-0.26,0.41,-0.38,0.39,-0.3,0.29,-0.26,0.37,-0.44,0.22,-0.22,0.52,-0.25,0.24,-0.31,0.35,-0.26,0.53,-0.32,0.33,-0.32,0.36,-0.25,0.42,-0.14,0.46,-0.29,0.28,-0.2,0.22,-0.28,0.25,-0.29,0.3,-0.34,0.41,-0.36,0.3,-0.48,0.64,-0.49,0.21,-0.29,0.36,-0.47,0.33,-0.39,0.36,-0.63,0.17,-0.47,0.43,-0.58,0.41,-0.58,0.54,-0.31,0.47,-0.55,0.5,-0.45,0.78,-0.44,0.13,-0.51,0.46,-0.58,0.48,-0.19,0.51,-0.18,0.39,-0.03,0.28,-0.16,0.17,-0.3,0.24,-0.22,0.27,-0.28,0.35,-0.39,0.63,-0.3,0.55,-0.46,0.84,-0.51,0.62,-0.86,0.59,-0.59,0.59,-0.61,0.7,-0.42,0.64,-0.43,0.6,-0.44,0.58,-0.62,0.58,-0.5,0.58,-0.55,0.62,-0.54,0.57,-0.36,0.54,-0.71,0.49,-0.39,0.43,-0.47,0.7,-0.66,0.78,-0.37,0.57,-0.57,0.31,-0.58,0.41,-0.72,0.53,-0.66,0.57,-0.49,0.51,-0.67,0.45,-0.6,0.41,-0.7,0.81,-0.56,0.66,-0.55,0.46,-0.75,0.52,-0.54,0.37,-0.33', 3453 3454 '0.32,-0.57,0.34,-0.39,0.36,-0.17,0.35,-0.37,0.42,-0.28,0.71,-0.31,0.42,-0.31,0.51,-0.28,0.33,-0.39,0.52,-0.69,0.35,-0.56,0.79,-0.94,0.55,-0.55,0.58,-0.41,0.35,-0.5,0.19,-0.48,0.3,-0.54,0.14,-0.2,0.11,-0.1,0.35,-0.45,0.28,-0.32,0.4,-0.28,0.3,-0.45,0.22,-0.22,0.29,-0.44,0.28,-0.5,0.5,-0.43,0.29,-0.5,0.51,-0.22,0.29,-0.38,0.32,-0.54,0.2,-0.32,0.97,-0.52,0.41,-0.42,0.44,-0.48,0.75,-0.39,0.31,-0.12,0.13,-0.12,0.27,-0.56,0.41,-0.72,0.35,-0.17,0.28,-0.78,0.24,-0.74,0.23,-0.56,0.43,-0.69,0.53,-0.27,0.2,-0.44,0.37,-0.22,0.37,-0.21,0.26,-0.32,0.39,-0.23,0.19,-0.43,0.41,-0.25,0.59,-0.47,0.36,-0.52,0.33,-0.18,0.16,-0.17,0.1,-0.58,0.51,-0.46,0.47,-0.4,0.38,-0.52,0.33,-0.44,0.48,-0.34,0.23,-0.51,0.42,-0.73,0.41,-0.32,0.61,-0.18,0.43,-0.37,0.38,-0.31,0.46,-0.2,0.36,-0.53,0.38,-0.76,0.26,-0.51,0.33,-0.69,0.55,-0.34,0.17,-0.
345411,0.71,-0.32,0.37,-0.24,0.48,-0.56,0.29,-0.55,0.26,-0.67,0.41,-0.41,0.39,-0.32,0.39,-0.23,0.35,-0.51,0.55,-0.39,0.47,-0.4,0.35,-0.35,0.4,-0.74,0.35,-0.23,0.2,-0.59,0.52,-0.16,0.44,-0.37,0.2,-0.57,0.18,-0.12,0.04,-0.1,0.03,-0.02,0.01,-0.01,0,0,0,0' 3455 ], 3456 playlistScrollType: 'browser', 3457 useVideoControls: false, 3458 usePlaylistScroll:false, 3459 useKeyboardNavigationForPlayback:false, 3460 variationToggleSpeed: 300, 3461 keyboardControls: [], 3462 togglePlaybackOnMultipleInstances:true, 3463 useTitleScroll:false, 3464 clearDialogCacheOnStart:true, 3465 useSeekOnLyrics:true, 3466 lyricsAutoOpen:false, 3467 videoAutoOpen:false, 3468 titleScrollSpeed: 1, 3469 titleScrollSeparator: " *** ", 3470 continousKey:"hap-continous-key", 3471 openPlayerInMainWindowAfterPopupClose:true, 3472 lyricsAutoScroll:true, 3473 useMediaSession:true, 3474 crossFadeTime: 5, 3475 s3ThumbExtension: 'jpg', 3476 s3UrlExpireTime: '+15 seconds', 3477 s3Region: 'us-east-1', 3478 cf_expire: 300, 3479 createDownloadIconsInPlaylist: false, 3480 createLinkIconsInPlaylist: false, 3481 limitDescriptionReadMoreText:"Read more", 3482 limitDescriptionReadLessText:"Read less", 3483 useShare:true, 3484 percentToCountAsPlay: 25, 3485 scrollToPlayer:0, 3486 linkIconTitle:"Purchase", 3487 downloadIconTitle:"Download", 3488 tooltipStatPlays: "Plays", 3489 tooltipStatLikes: "Likes", 3490 tooltipStatDownloads: "Downloads", 3491 artworkSize: [100,200,250,340,460,600], 3492 soundCloudThumbQuality: "t300x300.jpg", 3493 playlistSelectorPlaceholderThumb:'media/playlist-placeholder.jpg', 3494 playlistContentClass: 'hap-playlist-default', 3495 playbackRateMin: 0.5, 3496 playbackRateMax: 2, 3497 playbackRateArr:[0.5,1,1.2,1.5,2], 3498 playlistItemClickSelectorArr: ['hap-playlist-thumb', 'hap-thumbimg', 'hap-playlist-title-wrap', 'hap-playlist-title', 'hap-playlist-artist'], 3499 sortOrder: "", 3500 modifierKey: "", 3501 getId3Image: true, 3502 useContinousPlayback:false, 3503 playlistItemMultilineWidth:600, 3504 searchDescriptionInPlaylist:true, 3505 hideYoutubeAfterStart:false, 3506 defaultSongArtist: "DATA NOT AVAILABLE", 3507 defaultSongTitle: "DATA NOT AVAILABLE", 3508 cors: 'https://cors-anywhere.herokuapp.com', 3509 seekTime:10, 3510 //pagination 3511 paginationPreviousBtnTitle:"Previous", 3512 paginationPreviousBtnText:"Prev", 3513 paginationNextBtnTitle:"Next", 3514 paginationNextBtnText:"Next", 3515 3516 useTitleAnimationInSticky:true, 3517 3518 downloadIcon: "<svg aria-hidden='true' focusable='false' role='img' viewBox='0 0 512 512'><path d='M216 0h80c13.3 0 24 10.7 24 24v168h87.7c17.8 0 26.7 21.5 14.1 34.1L269.7 378.3c-7.5 7.5-19.8 7.5-27.3 0L90.1 226.1c-12.6-12.6-3.7-34.1 14.1-34.1H192V24c0-13.3 10.7-24 24-24zm296 376v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h146.7l49 49c20.1 20.1 52.5 20.1 72.6 0l49-49H488c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z'></path></svg>", 3519 3520 linkIcon: "<svg aria-hidden='true' focusable='false' role='img' viewBox='0 0 576 512'><path d='M504.717 320H211.572l6.545 32h268.418c15.401 0 26.816 14.301 23.403 29.319l-5.517 24.276C523.112 414.668 536 433.828 536 456c0 31.202-25.519 56.444-56.824 55.994-29.823-.429-54.35-24.631-55.155-54.447-.44-16.287 6.085-31.049 16.803-41.548H231.176C241.553 426.165 248 440.326 248 456c0 31.813-26.528 57.431-58.67 55.938-28.54-1.325-51.751-24.385-53.251-52.917-1.158-22.034 10.436-41.455 28.051-51.586L93.883 64H24C10.745 64 0 53.255 0 40V24C0 10.745 10.745 0 24 0h102.529c11.401 0 21.228 8.021 23.513 19.19L159.208 64H551.99c15.401 0 26.816 14.301 23.403 29.319l-47.273 208C525.637 312.246 515.923 320 504.717 320zM408 168h-48v-40c0-8.837-7.163-16-16-16h-16c-8.837 0-16 7.163-16 16v40h-48c-8.837 0-16 7.163-16 16v16c0 8.837 7.163 16 16 16h48v40c0 8.837 7.163 16 16 16h16c8.837 0 16-7.163 16-16v-40h48c8.837 0 16-7.163 16-16v-16c0-8.837-7.163-16-16-16z'></path></svg>", 3521 3522 statDownloadIcon: "<svg aria-hidden='true' focusable='false' role='img' viewBox='0 0 512 512'><path d='M504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zM212 140v116h-70.9c-10.7 0-16.1 13-8.5 20.5l114.9 114.3c4.7 4.7 12.2 4.7 16.9 0l114.9-114.3c7.6-7.6 2.2-20.5-8.5-20.5H300V140c0-6.6-5.4-12-12-12h-64c-6.6 0-12 5.4-12 12z'></path></svg>", 3523 3524 statLikeIcon: "<svg aria-hidden='true' focusable='false' role='img' viewBox='0 0 512 512'>
3524<path d='M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z'></path></svg>", 3525 3526 statPlayIcon: "<svg aria-hidden='true' focusable='false' role='img' viewBox='0 0 512 512'><path d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm115.7 272l-176 101c-15.8 8.8-35.7-2.5-35.7-21V152c0-18.4 19.8-29.8 35.7-21l176 107c16.4 9.2 16.4 32.9 0 42z'></path></svg>", 3527 3528 iconClose: "<svg aria-hidden='true' focusable='false' role='img' viewBox='0 0 320 512'><path d='M317.7 402.3c3.125 3.125 3.125 8.188 0 11.31c-3.127 3.127-8.186 3.127-11.31 0L160 267.3l-146.3 146.3c-3.127 3.127-8.186 3.127-11.31 0c-3.125-3.125-3.125-8.188 0-11.31L148.7 256L2.344 109.7c-3.125-3.125-3.125-8.188 0-11.31s8.188-3.125 11.31 0L160 244.7l146.3-146.3c3.125-3.125 8.188-3.125 11.31 0s3.125 8.188 0 11.31L171.3 256L317.7 402.3z'/></svg>" 3529 3530 } 3531 3532 var settings = HAPUtils.extendObj(true, {}, defaults, settings); 3533 3534 3535 3536 //############################################// 3537 /* url params */ 3538 //############################################// 3539 3540 //check url params, overwrite settings 3541 //check playlist from url params 3542 3543 var urlParams = HAPUtils.getUrlParameter(), 3544 queryPlaylistArr = [], 3545 queryPlaylist = []; 3546 3547 var supportedPlaylistKeyArr = ['type','noapi','video','audio-preview','path','path','version','sid','lyrics','limit','thumb','thumb-small','thumb-default','thumb-alt','title','description','artist','album','download','duration','date','id3','start','end','link','target','rel','load-more','active-accordion'] 3548 3549 if(urlParams['hap-query-instance']){ 3550 if(decodeURIComponent(urlParams['hap-query-instance']) == settings.instanceName)checkUrlParams();//on if share url is for this instance 3551 }else{ 3552 checkUrlParams();//we have single player or down want to check instance name 3553 } 3554 3555 function checkUrlParams(){ 3556 3557 Object.keys(urlParams).forEach(function(key) { 3558 if(key.indexOf('hap-')==0){//url params start with 'hap-' 3559 var k = key.substr(4),//remove hap- 3560 camelCased = k.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); }); 3561 var value = decodeURIComponent(urlParams[key]).replace(/\+/g, ' ');//+ to space 3562 if(value){ 3563 if(settings.hasOwnProperty(camelCased)){//update settings 3564 if(value === "true")value = true; 3565 else if(value === "false")value = false; 3566 settings[camelCased] = value;//only accept if property already exist 3567 }else{//check for playlist 3568 value = value.split(",").map(function(item){ 3569 return item.trim(); 3570 }); 3571 //check if we have valid key! 3572 //if(supportedPlaylistKeyArr.indexOf(k) > -1){ 3573 queryPlaylistArr.push({key:camelCased, value: value}) 3574 // } 3575 } 3576 } 3577 } 3578 }); 3579 3580 //playlist from url params 3581 if(queryPlaylistArr.length){ 3582 3583 var i, j, len = queryPlaylistArr.length, len2 = queryPlaylistArr[0].value.length, item, obj, value; 3584 for(j = 0;j<len2;j++){ 3585 obj = {}; 3586 for(i = 0;i<len;i++){ 3587 item = queryPlaylistArr[i]; 3588 value = item.value[j]; 3589 if(value === "true")value = true; 3590 else if(value === "false")value = false; 3591 obj[item.key] = value; 3592 if(item.key === 'type')obj['origtype'] = value;//for stats 3593 } 3594 queryPlaylist.push(obj); 3595 } 3596 } 3597 3598 } 3599 3600 urlParams = null; 3601 3602 3603 //############################################// 3604 /* elements */ 3605 //############################################// 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 var wrapper = delem; 3616 wrapper.style.display = 'block'; 3617 3618 var playerOuter = wrapper.querySelector('.hap-player-outer'); 3619 if(playerOuter && settings.hidePlayerUntilMusicStart)playerOuter.classList.add('hap-music-player-force-hidden'); 3620 3621 3622 var class_list = ''; 3623 if(wrapper.getAttribute('class') != undefined){ 3624 class_list = wrapper.getAttribute('class').split(/(\s+)/); 3625 } 3626 3627 if(settings.customClass){ 3628 if(settings.customClass.indexOf('|')>-1){ 3629 var cc = settings.customClass.split(','), i, len = cc.length, clas; 3630 for(i=0;i<len;i++){ 3631 clas = cc[i].split('|'); 3632 wrapper.querySelector(clas[0]).classList.add(clas[1]); 3633 } 3634 }else{ 3635 wrapper.classList.add(settings.customClass); 3636 } 3637 } 3638 3639 3640 if(settings.markup) wrapper.insertAdjacentHTML("beforeend",settings.markup); 3641 3642 3643 3644 3645 3646 3647 3648 3649 var playlistList = settings.playlistList ? document.querySelector(settings.playlistList) : null, 3650 playlistHolder = wrapper.querySelector('.hap-playlist-holder'), 3651 playlistInner = wrapper.querySelector('.hap-playlist-inner'), 3652 playlistInnerWrap = wrapper.querySelector('.hap-playlist-inner-wrap'), 3653 playlistContent = wrapper.querySelector('.hap-playlist-content'), 3654 playlistFilterMsg = wrapper.querySelector('.hap-playlist-filter-msg'), 3655 sortAlpha = wrapper.querySelector('.hap-sort-alpha'), 3656 popupToggle = wrapper.querySelector('.hap-popup-toggle'), 3657 progressBg = wrapper.querySelector('.hap-progress-bg'), 3658 loadLevel = wrapper.querySelector('.hap-load-level'), 3659 progressLevel = wrapper.querySelector('.hap-progress-level'), 3660 3661 seekbarWave = wrapper.querySelector('.hap-seekbar-wave'), 3662 seekbarWaveProgress = wrapper.querySelector('.hap-seekbar-wave-progress'), 3663 3664 volumeToggle = wrapper.querySelector('.hap-volume-toggle'), 3665 volumeSeekbar = wrapper.querySelector('.hap-volume-seekbar'), 3666 volumeBg = wrapper.querySelector('.hap-volume-bg'), 3667 volumeLevel = wrapper.querySelector('.hap-volume-level'), 3668 3669 lyricsHolder = wrapper.querySelector('.hap-lyrics-holder'), 3670 lyricsToggle = wrapper.querySelector('.hap-lyrics-toggle'), 3671 3672 videoHolder = wrapper.querySelector('.hap-video-holder'), 3673 videoWrap = wrapper.querySelector('.hap-video-wrap'), 3674 videoToggle = wrapper.querySelector('.hap-video-toggle'), 3675 3676 playerHolder = wrapper.querySelector('.hap-player-holder'), 3677 playerThumb = wrapper.querySelector('.hap-player-thumb'), 3678 shareHolder = wrapper.querySelector('.hap-share-holder'), 3679 playbackRateHolder = wrapper.querySelector('.hap-playback-rate-holder'), 3680 playbackRateToggle = wrapper.querySelector('.hap-playback-rate-toggle'), 3681 playbackRateToggleNum = wrapper.querySelector('.hap-playback-rate-toggle-num'), 3682 playerTitle = wrapper.querySelector('.hap-player-title'), 3683 playerArtist = wrapper.querySelector('.hap-player-artist'), 3684 3685 playlistTitle = wrapper.querySelector('.hap-playlist-main-title'), 3686 playlistDescription = wrapper.querySelector('.hap-playlist-main-description'), 3687 3688 mediaTimeCurrent = wrapper.querySelector('.hap-media-time-current'), 3689 mediaTimeTotal = wrapper.querySelector('.hap-media-time-total'), 3690 mediaTimeAd = wrapper.querySelector('.hap-media-time-ad'), 3691 adSkipBtn = wrapper.querySelector('.hap-ad-skip'), 3692 playbackToggle = wrapper.querySelector('.hap-playback-toggle'), 3693 loopToggle = wrapper.querySelector('.hap-loop-toggle'), 3694 randomToggle = wrapper.querySelector('.hap-random-toggle'), 3695 rangeToggle = wrapper.querySelector('.hap-range-toggle'), 3696 rangeHolder = wrapper.querySelector('.hap-range-holder'), 3697 shareToggle = wrapper.querySelector('.hap-share-toggle'), 3698 preloader = wrapper.querySelector('.hap-preloader'), 3699 3700 embedToggle = wrapper.querySelector('.hap-embed-toggle'), 3701 embedHolder = wrapper.querySelector('.hap-embed-holder'), 3702 3703 pwdHolder = wrapper.querySelector('.hap-pwd-holder'), 3704 pwdField = wrapper.querySelector('.hap-pwd-field'), 3705 pwdErrorMsg = wrapper.querySelector('.hap-pwd-error') ? wrapper.querySelector('.hap-pwd-error').innerHTML : '', 3706 3707 playbackToggleIndicator = wrapper.querySelector('.hap-playback-toggle-indicator'), 3708 3709 //fixed 3710 externalPlaybackBtn = wrapper.querySelector('.hap-playback-toggle-ex'), 3711 externalPlayerToggleBtn = wrapper.querySelector('.hap-player-toggle-ex'), 3712 3713 waveformLoader = wrapper.querySelector('.hap-waveform-loader'), 3714
3715 //restrict download 3716 redirectLoginHolderDownload = wrapper.querySelector('.hap-redirect-login-holder-download'), 3717 redirectLoginHolderWatch = wrapper.querySelector('.hap-redirect-login-holder-watch'), 3718 redirectLoginHolder, 3719 3720 globalDownloadBtn 3721 3722 3723 3724 3725 //############################################// 3726 /* vars */ 3727 //############################################// 3728 3729 var isMobile = HAPUtils.isMobile(), 3730 isIOS = HAPUtils.isIOS(), 3731 hasLocalStorage = HAPUtils.hasLocalStorage(), 3732 3733 autoPlay = settings.autoPlay, 3734 initialAutoPlay = autoPlay, 3735 playlistItemContent = settings.playlistItemContent.replace(/\s+/g, '').split(','), 3736 playlistTitleOrder = settings.playlistTitleOrder.replace(/\s+/g, '').split(','), 3737 statisticsContent = settings.statisticsContent ? settings.statisticsContent.replace(/\s+/g, '').split(',') : '', 3738 useContinousPlayback = settings.useContinousPlayback && hasLocalStorage, 3739 continousPlaybackTrackAllSongs = useContinousPlayback && settings.continousPlaybackTrackAllSongs, 3740 useMediaSession = settings.useMediaSession && 'mediaSession' in navigator && window.location.protocol != 'file:', 3741 useGa = settings.useGa && settings.gaTrackingId, 3742 sortOrder = settings.sortOrder 3743 3744 if(settings.playlistContent)playlistContent = document.querySelector(settings.playlistContent)//custom playlist element 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 var componentInited, 3755 playlistTransitionOn, 3756 _body = document.body, 3757 _window = window, 3758 _doc = document, 3759 windowResizeTimeoutID, 3760 windowResizeTimeout = 150, 3761 hasDownloadSupport = HAPUtils.hasDownloadSupport(), 3762 isAndroid = HAPUtils.isAndroid(), 3763 mp3Support = HAPUtils.canPlayMp3(), 3764 wavSupport = HAPUtils.canPlayWav(), 3765 aacSupport = HAPUtils.canPlayAac(), 3766 flacSupport = HAPUtils.canPlayFlac(), 3767 isChrome = HAPUtils.isChrome(), 3768 isSafari = HAPUtils.isSafari(), 3769 proxy = settings.sourcePath + 'includes/ba-simple-proxy.php', 3770 bsf_match = 'ebsfm:', 3771 loopStateArr = ['playlist','single','off'], 3772 loopStateCounter = loopStateArr.indexOf(settings.loopState), 3773 nonProcessMedia = ['audio', 'hls', 's3_audio'], 3774 allowedCrossFadeMedia = ['audio', 's3_audio'], 3775 singleMediaSourcesArr = ['audio', 'youtube_single', 'hls'], 3776 mediaPrefixUrl, 3777 3778 //pagnation 3779 paginationInited, 3780 lastActivePaginationBtn, 3781 paginationWrap,//pagination buttons go here 3782 paginationTotalPages, 3783 paginationCurrentPage, 3784 paginationArr = [],//save playlist items per page 3785 3786 3787 playlistScroll, 3788 3789 burl_request, 3790 bUrl, 3791 bUrlIntervalID, 3792 useBlob = settings.useBlob && window.location.protocol != "file:", 3793 3794 //audio 3795 id3Counter, 3796 id3Start, 3797 audio, 3798 //audio = audio, 3799 activeAudio, 3800 audioReady, 3801 audioInited, 3802 startEventDone,//lot of delay on ios 3803 3804 //crossfade 3805 audio2, 3806 audioUp2Js2, 3807 crossFadeOn, 3808 fadeOutAudioComplete, 3809 isCancelCrossFade, 3810 comingFromCrossFade, 3811 nextDataCheck, 3812 3813 //add more on total scroll 3814 addMoreOnTotalScroll, 3815 addMoreLimit, 3816 addMoreNumResults, 3817 addMoreOffset, 3818 addMoreSortOrder, 3819 addMoreSortDirection,//asc, desc 3820 3821 waveformCrossfadeTime = 300, 3822 3823 //video 3824 videoSync, 3825 videoOpened, 3826 syncComingFromVideo,//video sync audio (if video has controls) 3827 3828 //playback position 3829 lastPositionDataPath, 3830 3831 //load more 3832 nextPageToken, 3833 loadMoreProcess, 3834 loadMoreType, 3835 loadMoreOnTotalScroll, 3836 useId3, 3837 useID3Cors, 3838 allResults = 999999999, 3839 3840 //soundcloud 3841 soundCloudInited, 3842 resultLimit, 3843 soundCloudResultArr = [], 3844 3845 //hls 3846 hls, 3847 hlsSupport, 3848 hlsInited, 3849 3850 //ads 3851 _HAPAdManager, 3852 iosAdMidFixStart, 3853 showAds = true, 3854 viewSongWithoutAdsUserRoles, 3855 currentUserRoles, 3856 3857 //user roles 3858 downloadVideoUserRoles, 3859 allowedViewVideoUserRole, 3860 allowedDownloadVideoUserRole = true, 3861 mediaForcePause, 3862 3863 redirectLoginOpened, 3864 3865 //ima 3866 _IMALoader, 3867 imaLoaded, 3868 imaStarted, 3869 isIma, 3870 isImaOn, 3871 3872 adContent, 3873 3874 //dialog 3875 _dialog, 3876 3877 _lyrics, 3878 lyricsReady, 3879 lyricsOpened, 3880 3881 s3UrlReady, 3882 scUrlReady, 3883 3884 // 3885 _scLoader, 3886 3887 pwdAction, 3888 pwdDownloadData, 3889 3890 //share 3891 _HAPShareManager, 3892 3893 //youtube 3894 youtubeIframe, 3895 _HAPYoutubeLoader, 3896 youtubeHolder, 3897 youtubePlayer, 3898 youtubeInited, 3899 youtubeReady, 3900 youtubeStarted, 3901 youtubeEndFix,//end event fires multiple with end seconds? 3902 youtubeBlocker, 3903 youtubePlayed,//add autoplay after this 3904 3905 playlistScrollInit, 3906 playlistClick,//scroll to active playlist item 3907 3908 //global playlist otions 3909 playerThumbInited, 3910 globalThumb, 3911 globalDownload, 3912 globalStartTime, 3913 globalStartTimeMediaId, 3914 globalEndTime, 3915 globalAdPre, 3916 globalAdMid, 3917 globalAdMidInterval, 3918 globalAdEnd, 3919 globalPwd, 3920 globalVast, 3921 globalLockTime, 3922 globalLockVideoUserRoles, 3923 3924 soundCloud_id, 3925 3926 //addTrack helpers 3927 endInsert,//insert at playlist end 3928 insertPosition, 3929 addTrackProcess, 3930 addTrackPlayit, 3931 3932 playlistProcessCounter = -1, 3933 playlistDataReady, 3934 playlistDataArr = [], 3935 lastPlaylistDataArr = [],//for load more 3936 playlistProcessData = [], 3937 playlistProcessDataUrl = [], 3938 playlistData, 3939 playlistLength=0, 3940 activeMediaId = null,//active item from media id 3941 playlistInitLoad, 3942 lastPlaylist, 3943 playlistId, 3944 playerId, 3945 activePlaylistItem, 3946 mediaStarted, 3947 mediaType, 3948 mediaTitle, 3949 mediaPath, 3950 nextMediaData, 3951 mediaCounter, 3952 mediaPlaying = false, 3953 isEnqueue, 3954 countryData, 3955 currMediaData, 3956 dataInterval = settings.dataInterval, 3957 dataIntervalID, 3958 seekBarDown, 3959 seekBarSize, 3960 events = HAPUtils.getEvents(), 3961 comingFromPwd, 3962 3963 xhrRequest, 3964 xhrRequest_pag, 3965 3966 _HAPPlaybackRateSlider, 3967 _HAPRangeSlider, 3968 _volumeSlider, 3969 lastVolume = 0.5, 3970 3971 //scripts 3972 hls_js = "https://cdn.jsdelivr.net/npm/hls.js@latest", 3973 youtube_js = "https://www.youtube.com/iframe_api", 3974 3975 //variation 3976 activeVariation, 3977 hasVariation, 3978 3979 //ws 3980 waveformLoading, 3981 waveformLoadingInterval, 3982 waveformDataAws, 3983 waveformDataAws2, 3984 3985 peakWriteRequired, 3986 xhrRequest_remoteDownload, 3987 xhrRequest_loadPeaks, 3988 xhrRequest_writePeaks, 3989 3990 //accordion 3991 lastOpenedAccordion, 3992 accordionLoading, 3993 accordionMode, 3994 accordionHolder,//playlistContent for accordion 3995 accordionInited, 3996 accordionActiveId,//active accordion item 3997 accordioPlaylistId,//currently playing accordion playlist 3998 playlistDataAccordion = [],//save playlist data for each accordion item 3999 accordionUseId3,//use id3 tags in accordion 4000 4001 //fixed 4002 _HAPStickyPlayer, 4003 seekingFixed, 4004 4005 //inline seekbar 4006 inlineSeekbar, 4007 4008 //wave seekbar 4009 seekbarWaveCanvasBg, 4010 seekbarWaveCanvasProgress, 4011 seekbarWaveCtx, 4012 seekbarWaveCtx2, 4013 peakData, 4014 4015 waveOptions = settings.waveOptions 4016 4017 if(settings.waveBgColor != undefined)waveOptions.waveColor = settings.waveBgColor; 4018 if(settings.waveProgressColor != undefined)waveOptions.progressColor = settings.waveProgressColor; 4019 if(settings.waveBarWidth != undefined)waveOptions.barWidth = Number(settings.waveBarWidth); 4020 if(settings.waveBarRadius != undefined)waveOptions.barRadius = Number(settings.waveBarRadius); 4021 if(settings.waveBarGap != undefined)waveOptions.barGap = Number(settings.waveBarGap); 4022 4023 4024 //only click, not mouseenter, leave 4025 const onHandler = (element, type, selector, handler) => { 4026 element.addEventListener(type, (event) => { 4027 if (event.target.closest(selector)) { 4028 handler(event); 4029 } 4030 }); 4031 }; 4032 4033 4034 4035 4036 //############################################// 4037 /* setup */ 4038 //############################################// 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 audio = document.createElement("audio") 4058 audio.setAttribute('preload',settings.preload) 4059 activeAudio = audio; 4060 4061 4062 4063
4064 if(playerThumb)playerThumb.setAttribute('role', 'img') 4065 4066 4067 if(playlistContent && settings.playlistContentClass){ 4068 playlistContent.classList.add(settings.playlistContentClass) 4069 } 4070 4071 4072 4073 4074 if(wrapper.classList.contains('hap-wrapper-popup'))settings.isPopup = true; 4075 else settings.isPopup = false; 4076 4077 4078 //if(class_list.indexOf('hap-fixed') > -1 || class_list.indexOf('hap-fixed2') > -1)settings.useStickyPlayer = false; 4079 4080 if(typeof HAPStickyPlayer !== 'function'){ 4081 settings.useStickyPlayer = false; 4082 //console.log('missing sticky.js script tag, sticky player cannot be used!') 4083 } 4084 4085 4086 if(settings.useStickyPlayer && playbackToggleIndicator)playlistContent.prepend(playbackToggleIndicator)//so its available in fixed player 4087 4088 4089 4090 4091 if(seekbarWave)settings.useWaveSeekbar = true 4092 4093 4094 if(settings.viewSongWithoutAdsForLoggedInUser && settings.isUserLoggedIn){ 4095 showAds = false; 4096 }else{ 4097 showAds = true; 4098 } 4099 4100 if(settings.currentUserRoles)currentUserRoles = settings.currentUserRoles.split(','); 4101 4102 if(settings.downloadVideoUserRoles)downloadVideoUserRoles = settings.downloadVideoUserRoles.split(','); 4103 4104 if(currentUserRoles && downloadVideoUserRoles){ 4105 allowedDownloadVideoUserRole = HAPUtils.arrayContainsAnotherArray(downloadVideoUserRoles, currentUserRoles); 4106 } 4107 4108 4109 if(settings.viewSongWithoutAdsUserRoles)viewSongWithoutAdsUserRoles = settings.viewSongWithoutAdsUserRoles.replace(/\s+/g, '').split(',') 4110 4111 if(currentUserRoles && viewSongWithoutAdsUserRoles){ 4112 showAds = !HAPUtils.arrayContainsAnotherArray(viewSongWithoutAdsUserRoles, currentUserRoles); 4113 } 4114 //console.log('showAds',showAds) 4115 4116 4117 4118 //hide embed functionality if already embeded 4119 if(location.href.indexOf('apmap/includes/embed.php?') > -1 && settings.hideEmbedFunctionWhenEmbeded){ 4120 if(embedToggle)embedToggle.remove() 4121 if(embedHolder)embedHolder.remove() 4122 settings.isEmbed = true; 4123 } 4124 4125 4126 4127 4128 4129 //ads 4130 if(settings.adContent && !settings.isPopup){ 4131 //todo - if ad content in popup doesnt work, in destroyinstance2 remove it from copied html 4132 4133 adContent = document.createElement('div'); 4134 adContent.classList.add('hap-ad-content-wrap') 4135 adContent.innerHTML = settings.adContent; 4136 4137 if(settings.adContentPositionCustom){ 4138 var cp = wrapper.querySelector(settings.adContentPositionCustom) 4139 if(cp)cp.append(adContent); 4140 } 4141 else{ 4142 4143 if(settings.adContentPosition == 'top'){ 4144 wrapper.prepend(adContent) 4145 } 4146 else if(settings.adContentPosition == 'bottom'){ 4147 wrapper.append(adContent); 4148 } 4149 4150 } 4151 } 4152 4153 4154 4155 4156 4157 4158 if(settings.isEmbed && settings.useSingleAudioEmbed){ 4159 wrapper.querySelector('hap-playlist-content').remove(); 4160 settings.usePlaylistScroll = false; 4161 } 4162 4163 4164 4165 4166 if(settings.useInlineSeekbar){ 4167 inlineSeekbar = HAPUtils.htmlToElement('<div class="hap-inline-seekbar-bg">'+ 4168 '<div class="hap-inline-seekbar-progress"></div>'+ 4169 '</div>') 4170 } 4171 4172 4173 4174 4175 //soundcloud 4176 if(settings.sck || settings.soundCloudAppId){ 4177 var k = settings.sck || settings.soundCloudAppId 4178 settings.scak = k.split(",").map(function(item) { 4179 return item.trim(); 4180 }); 4181 } 4182 4183 4184 //fixed 4185 if(settings.useStickyPlayer){ 4186 4187 window['hap_fixed_active_player'] = settings.instanceName 4188 4189 if(!window.hap_fixedPlayer && !settings.hap_fixedPlayer){ 4190 _HAPStickyPlayer = new HAPStickyPlayer({parent: self, settings: settings, wrapper: wrapper}); 4191 window.hap_fixedPlayer = _HAPStickyPlayer 4192 settings.hap_fixedPlayer = _HAPStickyPlayer 4193 }else if(window.hap_fixedPlayer){ 4194 _HAPStickyPlayer = window.hap_fixedPlayer 4195 }else if(settings.hap_fixedPlayer){//for popup 4196 _HAPStickyPlayer = settings.hap_fixedPlayer 4197 } 4198 4199 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.SET_PROGRESS_START', function(data){ 4200 if(data.inst == settings.instanceName){//only for the player currently active 4201 seekBarDown = true; 4202 seekingFixed = true; 4203 } 4204 }) 4205 4206 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.SET_PROGRESS', function(data){ 4207 if(data.inst == settings.instanceName){//only for the player currently active 4208 setProgress(data.point, data.update, true) 4209 if(data.update){ 4210 seekBarDown = false; 4211 seekingFixed = false; 4212 } 4213 } 4214 }) 4215 4216 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.VOLUME_CHANGE', function(data){ 4217 if(data.inst == settings.instanceName){ 4218 settings.volume = data.volume; 4219 self.setVolume(data.volume) 4220 4221 //if(_volumeSlider)_volumeSlider.setVisual(data.volume) 4222 } 4223 }) 4224 4225 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.TOGGLE_MUTE', function(data){ 4226 if(data.inst == settings.instanceName){ 4227 self.toggleMute(); 4228 } 4229 }) 4230 4231 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.TOGGLE_RANDOM', function(data){ 4232 if(data.inst == settings.instanceName){ 4233 self.toggleRandom(); 4234 } 4235 }) 4236 4237 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.TOGGLE_LOOP', function(data){ 4238 if(data.inst == settings.instanceName){ 4239 4240 loopStateCounter++; 4241 if(loopStateCounter > loopStateArr.length - 1)loopStateCounter = 0; 4242 settings.loopState = loopStateArr[loopStateCounter]; 4243 4244 self.setLoop(settings.loopState); 4245 } 4246 }) 4247 4248 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.PREVIOUS_MEDIA', function(data){ 4249 if(data.inst == settings.instanceName){ 4250 self.previousMedia() 4251 } 4252 }) 4253 4254 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.SKIP_BACKWARD', function(data){ 4255 if(data.inst == settings.instanceName){ 4256 self.seekBackward(settings.seekTime); 4257 } 4258 }) 4259 4260 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.SKIP_FORWARD', function(data){ 4261 if(data.inst == settings.instanceName){ 4262 self.seekForward(settings.seekTime); 4263 } 4264 }) 4265 4266 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.SET_PLAYBACK_RATE', function(data){ 4267 if(data.inst == settings.instanceName){ 4268 if(_HAPPlaybackRateSlider)_HAPPlaybackRateSlider.setValue(data.value); 4269 else self.setPlaybackRate(data.value); 4270 } 4271 }) 4272 4273 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.NEXT_MEDIA', function(data){ 4274 if(data.inst == settings.instanceName){ 4275 self.nextMedia() 4276 } 4277 }) 4278 4279 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.TOGGLE_PLAYBACK', function(data){ 4280 if(data.inst == settings.instanceName){ 4281 self.togglePlayback() 4282 } 4283 }) 4284 4285 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.LYRICS_TOGGLE', function(data){ 4286 if(data.inst == settings.instanceName){ 4287 self.toggleLyrics() 4288 } 4289 }) 4290 4291 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.SHARE_TOGGLE', function(data){ 4292 if(data.inst == settings.instanceName){ 4293 if(_HAPShareManager)_HAPShareManager.share(data.type.toLowerCase(), currMediaData, self.getCurrentMediaUrl()); 4294 } 4295 }) 4296 4297 _HAPStickyPlayer.addEventListener('HAPStickyPlayer.TOGGLE_DOWNLOAD', function(data){ 4298 if(data.inst == settings.instanceName){ 4299 handleDownloadFromSticky() 4300 } 4301 }) 4302 4303 } 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 if(playlistItemContent.indexOf('description') == -1)settings.searchDescriptionInPlaylist = false;
4314 4315 4316 if(typeof window.ap_mediaArr === 'undefined')window.ap_mediaArr = []; 4317 window.ap_mediaArr.push({inst: self, id: settings.instanceName});//save instance so we can pause playback in one instance if other is started 4318 4319 if(isMobile){ 4320 autoPlay = false; 4321 } 4322 if(settings.autoPlayAfterFirst){ 4323 autoPlay = false; 4324 initialAutoPlay = true; 4325 } 4326 4327 4328 4329 4330 4331 4332 4333 //volume 4334 if(settings.volume < 0)settings.volume = 0; 4335 else if(settings.volume > 1)settings.volume = 1; 4336 if(settings.volume != 0)lastVolume = settings.volume; 4337 4338 4339 4340 4341 4342 //loop 4343 if(loopStateCounter == -1)settings.loopState = 'off'; 4344 loopStateCounter = loopStateArr.indexOf(settings.loopState); 4345 4346 if(loopToggle)loopToggle.querySelector('.hap-btn-loop-'+settings.loopState).style.display = 'block'; 4347 //shuffle 4348 if(_HAPStickyPlayer)_HAPStickyPlayer.setLoop(settings.loopState) 4349 4350 if(randomToggle){ 4351 if(settings.randomPlay)randomToggle.querySelector('.hap-btn-random-on').style.display = 'block'; 4352 else randomToggle.querySelector('.hap-btn-random-off').style.display = 'block'; 4353 } 4354 if(_HAPStickyPlayer)_HAPStickyPlayer.setRandom(settings.randomPlay) 4355 4356 4357 4358 4359 if(isIOS)settings.useCrossFade = false; 4360 else if(settings.loopState == 'single')settings.useCrossFade = false; 4361 if(settings.stopOnSongEnd)settings.useCrossFade = false; 4362 4363 if(settings.useCrossFade){ 4364 audio.c_active = true; 4365 4366 audio2 = document.createElement("audio") 4367 audio2.setAttribute('preload','auto') 4368 audioUp2Js2 = audio2 4369 } 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 //load playlist from select 4380 /*if(settings.playlistSelector){ 4381 document.querySelector(settings.playlistSelector).addEventListener('change',function(){ 4382 self.loadPlaylist(document.querySelector(this).value); 4383 }); 4384 }*/ 4385 4386 //breakpoints 4387 if(settings.breakPointArr){ 4388 if(typeof settings.breakPointArr === 'string'){ 4389 settings.breakPointArr = settings.breakPointArr.split(","); 4390 HAPUtils.sortNumericArray(settings.breakPointArr);//sort from low to high 4391 } 4392 } 4393 4394 4395 //hidden playlist from dom 4396 if(!playlistContent){ 4397 //playlistContent = document.querySelector('<div style="display:none;"></div>'); 4398 settings.usePlaylist = false; 4399 settings.usePlaylistScroll = false; 4400 settings.useNumbersInPlaylist = false; 4401 } 4402 4403 4404 4405 //set icon visibility on start 4406 if(sortAlpha)sortAlpha.querySelector('.hap-btn-sort-alpha-down').style.display = 'block'; 4407 4408 4409 4410 this.toggleBigPlay = function(on){ 4411 if(on){ 4412 playbackToggle.querySelector('.hap-btn-play').style.display = 'none'; 4413 playbackToggle.querySelector('.hap-btn-pause').style.display = 'block'; 4414 }else{ 4415 playbackToggle.querySelector('.hap-btn-play').style.display = 'block'; 4416 playbackToggle.querySelector('.hap-btn-pause').style.display = 'none'; 4417 } 4418 } 4419 4420 4421 4422 4423 if(playbackToggle)self.toggleBigPlay() 4424 4425 4426 if(settings.sortableTracks && !settings.sortableTracksSet)setSortableTracks(); 4427 4428 4429 4430 4431 4432 4433 4434 if(settings.scrollToPlayer && !settings.isPopup){ 4435 delete settings.scrollToPlayer; 4436 var rect = wrapper.getBoundingClientRect() 4437 var top = rect.top; 4438 document.querySelector('html,body').scrollTo({ 4439 top: top, 4440 behavior: 'smooth' 4441 }); 4442 4443 } 4444 4445 4446 //############################################// 4447 /* load more */ 4448 //############################################// 4449 4450 var loadMoreBtn = wrapper.querySelector('.hap-load-more-btn') 4451 4452 if(loadMoreBtn){ 4453 loadMoreBtn.addEventListener('click',function(){ 4454 4455 if(!componentInited) return false; 4456 if(loadMoreProcess) return false; 4457 if(loadMoreOnTotalScroll)self.loadMore(); 4458 else if(addMoreOnTotalScroll){ 4459 addMore(); 4460 } 4461 if(loadMoreBtn)loadMoreBtn.style.opacity = 0; 4462 }); 4463 } 4464 4465 4466 //############################################// 4467 /* dialog */ 4468 //############################################// 4469 4470 var elements = [] 4471 4472 if(lyricsHolder){ 4473 elements.push({ 4474 element:'lyrics', 4475 itemHandle:lyricsHolder.querySelector('.hap-dialog-header-drag'), 4476 itemResizeHandle:lyricsHolder.querySelector('.hap-dialog-resizable'), 4477 itemResizeMinW: parseInt(lyricsHolder.style.minWidth,10), 4478 itemResizeMinH: parseInt(lyricsHolder.style.minHeight,10), 4479 itemDialog:lyricsHolder 4480 }) 4481 } 4482 4483 if(videoHolder){ 4484 elements.push({ 4485 element:'video', 4486 itemHandle:videoHolder.querySelector('.hap-dialog-header-drag'), 4487 itemResizeHandle:videoHolder.querySelector('.hap-dialog-resizable'), 4488 itemResizeMinW: parseInt(videoHolder.style.minWidth,10), 4489 itemResizeMinH: parseInt(videoHolder.style.minHeight,10), 4490 itemDialog:videoHolder 4491 }) 4492 } 4493 4494 if(elements.length){ 4495 4496 document.addEventListener("HAPDialog.LYRICS_AUTOSCROLL_CHANGE", function(e) { 4497 settings.lyricsAutoScroll = e.detail; 4498 if(_lyrics)_lyrics.setAutoScroll(settings.lyricsAutoScroll) 4499 }) 4500 4501 _dialog = new HAPDialog(wrapper, elements, settings) 4502 4503 } 4504 4505 //############################################// 4506 /* lyrics */ 4507 //############################################// 4508 4509 this.toggleLyrics = function(){ 4510 4511 if(lyricsOpened){ 4512 4513 lyricsHolder.addEventListener('transitionend', function cb(e){ 4514 e.currentTarget.removeEventListener(e.type, cb); 4515 4516 lyricsHolder.style.display = 'none'; 4517 4518 }) 4519 lyricsHolder.classList.remove('hap-lyrics-holder-shown') 4520 4521 lyricsOpened = false;
4522 4523 }else{ 4524 4525 lyricsHolder.style.display = 'block' 4526 4527 setTimeout(function(){ 4528 lyricsHolder.classList.add('hap-lyrics-holder-shown') 4529 },50) 4530 4531 lyricsOpened = true; 4532 4533 } 4534 4535 } 4536 4537 4538 4539 //############################################// 4540 /* video */ 4541 //############################################// 4542 4543 this.toggleVideo = function(){ 4544 4545 if(videoOpened){ 4546 4547 if(videoSync){ 4548 videoSync.pause() 4549 } 4550 4551 videoHolder.style.display = 'none'; 4552 videoOpened = false; 4553 4554 }else{ 4555 4556 videoHolder.style.display = 'block'; 4557 videoOpened = true; 4558 4559 if(videoSync){ 4560 if(mediaPlaying){ 4561 var promise = videoSync.play(); 4562 if (promise !== undefined) { 4563 promise.then(function(){ 4564 var t = self.getCurrentTime() 4565 if(t)videoSync.currentTime = t 4566 }).catch(function(error){ 4567 }); 4568 } 4569 } 4570 } 4571 4572 } 4573 4574 } 4575 4576 4577 4578 4579 4580 //############################################// 4581 /* filter tracks */ 4582 //############################################// 4583 4584 var searchSelector = settings.searchSelector ? document.querySelector(settings.searchSelector) : wrapper.querySelector('.hap-search-filter'); 4585 var isSearchActive//note: not made with accordion 4586 4587 if(searchSelector){ 4588 4589 searchSelector.addEventListener('keyup',function(e){ 4590 if(playlistLength == 0)return false; 4591 4592 var value = e.target.value.toLowerCase(), i, j = 0, title, pi, searchHolder, search_len; 4593 4594 if(accordionMode){ 4595 if(settings.allowOnlyOneOpenedAccordion){ 4596 4597 //same as without accordion 4598 4599 if(value){ 4600 4601 for(i = 0; i< playlistLength; i++){ 4602 4603 pi = lastOpenedAccordion.querySelectorAll('.hap-playlist-item')[i]; 4604 4605 title = ''; 4606 4607 if(pi.querySelector('.hap-playlist-title'))title += pi.querySelector('.hap-playlist-title').innerHTML.toLowerCase(); 4608 if(pi.querySelector('.hap-playlist-artist'))title += pi.querySelector('.hap-playlist-artist').innerHTML.toLowerCase(); 4609 4610 if(settings.searchDescriptionInPlaylist && pi.querySelector('.hap-playlist-description')){ 4611 title += pi.querySelector('.hap-playlist-description').innerHTML.toLowerCase(); 4612 } 4613 4614 if(title.indexOf(value) >- 1){ 4615 pi.classList.remove('hap-filter-hidden', 'hap-hidden') 4616 }else{ 4617 pi.classList.add('hap-filter-hidden', 'hap-hidden'); 4618 j++; 4619 } 4620 4621 } 4622 4623 isSearchActive = true; 4624 4625 }else{ 4626 4627 lastOpenedAccordion.querySelectorAll('.hap-playlist-item').forEach(el => { 4628 el.classList.remove('hap-filter-hidden', 'hap-hidden') 4629 }) 4630 4631 isSearchActive = false; 4632 4633 } 4634 4635 if(playlistFilterMsg){ 4636 if(j == playlistLength){ 4637 if(playlistFilterMsg)playlistFilterMsg.style.display = 'block'; 4638 } 4639 else{ 4640 if(playlistFilterMsg)playlistFilterMsg.style.display = 'none'; 4641 } 4642 } 4643 4644 }else{ 4645 4646 //search all opened accordions 4647 4648 searchHolder = playlistHolder.querySelector('.hap-accordion-item-opened'); 4649 4650 if(value){ 4651 4652 searchHolder.querySelectorAll('.hap-accordion-item-content').forEach(function(el){ 4653 //so they collapse while searching 4654 if(value == '')el.classList.remove('hap-accordion-item-content-search') 4655 else el.classList.add('hap-accordion-item-content-search') 4656 }) 4657 4658 search_len = searchHolder.querySelectorAll('.hap-playlist-item').length; 4659 4660 for(i = 0; i< search_len; i++){ 4661 4662 pi = searchHolder.querySelectorAll('.hap-playlist-item')[i]; 4663 4664 title = ''; 4665 4666 if(pi.querySelector('.hap-playlist-title'))title += pi.querySelector('.hap-playlist-title').innerHTML.toLowerCase(); 4667 if(pi.querySelector('.hap-playlist-artist'))title += pi.querySelector('.hap-playlist-artist').innerHTML.toLowerCase(); 4668 4669 if(settings.searchDescriptionInPlaylist && pi.querySelector('.hap-playlist-description')){ 4670 title += pi.querySelector('.hap-playlist-description').innerHTML.toLowerCase(); 4671 } 4672 4673 if(title.indexOf(value) >- 1){ 4674 pi.classList.remove('hap-filter-hidden', 'hap-hidden') 4675 }else{ 4676 pi.classList.add('hap-filter-hidden', 'hap-hidden'); 4677 j++; 4678 } 4679 4680 } 4681 4682 isSearchActive = true; 4683 4684 }else{ 4685 4686 searchHolder.querySelectorAll('.hap-playlist-item').forEach(el => { 4687 el.classList.remove('hap-filter-hidden', 'hap-hidden') 4688 }) 4689 4690 isSearchActive = false;
4691 4692 } 4693 4694 } 4695 4696 }else{ 4697 4698 if(value){ 4699 4700 if(settings.usePlaylistScroll){//if we scroll to bottom, then search, results would the shown on the top, so we have to reset scroll 4701 if(settings.playlistScrollType == 'perfect-scrollbar'){ 4702 if(settings.playlistScrollOrientation == 'horizontal'){ 4703 playlistInner.scrollLeft = 0; 4704 }else{ 4705 playlistInner.scrollTop = 0; 4706 } 4707 } 4708 } 4709 4710 4711 for(i = 0; i< playlistLength; i++){ 4712 4713 pi = playlistContent.querySelectorAll('.hap-playlist-item')[i]; 4714 4715 title = ''; 4716 4717 if(pi.querySelector('.hap-playlist-title'))title += pi.querySelector('.hap-playlist-title').innerHTML.toLowerCase(); 4718 if(pi.querySelector('.hap-playlist-artist'))title += pi.querySelector('.hap-playlist-artist').innerHTML.toLowerCase(); 4719 4720 if(settings.searchDescriptionInPlaylist && pi.querySelector('.hap-playlist-description')){ 4721 title += pi.querySelector('.hap-playlist-description').innerHTML.toLowerCase(); 4722 } 4723 4724 if(title.indexOf(value) >- 1){ 4725 pi.classList.remove('hap-filter-hidden', 'hap-hidden') 4726 }else{ 4727 pi.classList.add('hap-filter-hidden', 'hap-hidden'); 4728 j++; 4729 } 4730 4731 } 4732 4733 isSearchActive = true; 4734 4735 }else{ 4736 4737 playlistContent.querySelectorAll('.hap-playlist-item').forEach(el => { 4738 el.classList.remove('hap-filter-hidden', 'hap-hidden') 4739 }) 4740 4741 isSearchActive = false; 4742 4743 } 4744 4745 if(j == playlistLength){ 4746 if(playlistFilterMsg)playlistFilterMsg.style.display = 'block'; 4747 if(loadMoreBtn)loadMoreBtn.classList.add('hap-force-hidden') 4748 }else{ 4749 if(playlistFilterMsg)playlistFilterMsg.style.display = 'none'; 4750 if(loadMoreBtn)loadMoreBtn.classList.remove('hap-force-hidden') 4751 } 4752 4753 } 4754 4755 }); 4756 4757 } 4758 4759 4760 //############################################// 4761 /* share */ 4762 //############################################// 4763 4764 if(settings.useShare){ 4765 4766 if(typeof HAPShareManager === 'undefined'){ 4767 var script = document.createElement('script'); 4768 script.type = 'text/javascript'; 4769 script.src = HAPUtils.qualifyURL(settings.sourcePath+settings.sharemanager_js); 4770 script.onload = script.onreadystatechange = function() { 4771 if(!this.readyState || this.readyState == 'complete'){ 4772 _HAPShareManager = new HAPShareManager(settings); 4773 } 4774 }; 4775 script.onerror = function(){ 4776 alert("Error loading " + this.src); 4777 } 4778 var tag = document.getElementsByTagName('script')[0]; 4779 tag.parentNode.insertBefore(script, tag); 4780 }else{ 4781 _HAPShareManager = new HAPShareManager(settings); 4782 } 4783 4784 } 4785 4786 4787 4788 //############################################// 4789 /* playlist selector */ 4790 //############################################// 4791 4792 var playlistSelectorArr = [], 4793 playlistSelectorContainer, 4794 playlistSelectorInner, 4795 playlistSelectorActiveItem, 4796 playlistSelectorSearch, 4797 playlistSelectorLen = 0, 4798 playlistSelectorFilterMsg, 4799 playlistSelectorOpened 4800 4801 if(!wrapper.querySelector('.hap-playlist-selector-container'))settings.usePlaylistSelector = false; 4802 4803 if(settings.usePlaylistSelector){ 4804 4805 playlistSelectorContainer = wrapper.querySelector('.hap-playlist-selector-container') 4806 playlistSelectorInner = playlistSelectorContainer.querySelector('.hap-playlist-selector-inner') 4807 4808 playlistSelectorFilterMsg = playlistSelectorContainer.querySelector('.hap-playlist-selector-filter-msg') 4809 4810 playlistSelectorContainer.querySelectorAll('.hap-playlist-selector-item').forEach(function(el){ 4811 4812 var title = el.getAttribute('data-title') || '', 4813 desc = el.getAttribute('data-description') || '', 4814 thumb = el.getAttribute('data-thumb') || settings.playlistSelectorPlaceholderThumb 4815 4816 var s = '<div class="hap-playlist-selector-thumb">'+ 4817 '<img src="'+thumb+'"/>'+ 4818 '<div class="hap-playlist-selector-thumb-style"></div>'+ 4819 '</div>'+ 4820 '<div class="hap-playlist-selector-info">'+ 4821 '<div class="hap-playlist-selector-title">'+title+'</div>'+ 4822 '<div class="hap-playlist-selector-desc">'+desc+'</div>'+ 4823 '</div>' 4824 4825 el.innerHTML = s; 4826 4827 playlistSelectorArr.push(el) 4828 4829 //disable active playlist if exist 4830 if(el.getAttribute('data-playlist-id') == settings.activePlaylist){ 4831 el.classList.add('hap-playlist-selector-item-active') 4832 playlistSelectorActiveItem = el; 4833 } 4834 4835 playlistSelectorLen++; 4836 }) 4837 4838 //click 4839 playlistSelectorInner.addEventListener('click', function(e){ 4840 4841 if(playlistTransitionOn)return false;
4842 4843 if(e.target.closest('.hap-playlist-selector-item')){ 4844 4845 var parent = e.target.closest('.hap-playlist-selector-item') 4846 4847 if(parent.classList.contains('hap-playlist-selector-item-active'))return false; 4848 4849 if(playlistSelectorActiveItem)playlistSelectorActiveItem.classList.remove('hap-playlist-selector-item-active') 4850 4851 playlistSelectorActiveItem = parent; 4852 playlistSelectorActiveItem.classList.add('hap-playlist-selector-item-active') 4853 4854 var ap = playlistSelectorActiveItem.getAttribute('data-playlist-id') 4855 4856 setPlaylist(ap); 4857 4858 //close playlist selector 4859 4860 setTimeout(function(){ 4861 closePlaylistSelector(); 4862 },200) 4863 4864 } 4865 4866 }) 4867 4868 4869 4870 4871 //search 4872 playlistSelectorSearch = playlistSelectorContainer.querySelector('.hap-playlist-selector-search') 4873 playlistSelectorSearch.addEventListener('keyup',function(e){ 4874 4875 var value = e.target.value.toLowerCase(), i, j = 0, title, pi, search_len; 4876 4877 if(value){ 4878 4879 4880 for(i = 0; i < playlistSelectorLen; i++){ 4881 4882 pi = playlistSelectorContainer.querySelectorAll('.hap-playlist-selector-item')[i]; 4883 4884 title = ''; 4885 4886 if(pi.querySelector('.hap-playlist-selector-title'))title += pi.querySelector('.hap-playlist-selector-title').innerHTML.toLowerCase(); 4887 if(pi.querySelector('.hap-playlist-selector-desc'))title += pi.querySelector('.hap-playlist-selector-desc').innerHTML.toLowerCase(); 4888 4889 if(title.indexOf(value) >- 1){ 4890 pi.classList.remove('hap-filter-hidden') 4891 }else{ 4892 pi.classList.add('hap-filter-hidden'); 4893 j++; 4894 } 4895 4896 } 4897 4898 }else{ 4899 4900 playlistSelectorContainer.querySelectorAll('.hap-playlist-selector-item').forEach(function(el){ 4901 el.classList.remove('hap-filter-hidden') 4902 }) 4903 4904 } 4905 4906 if(j == playlistSelectorLen){ 4907 if(playlistSelectorFilterMsg)playlistSelectorFilterMsg.style.display = 'block'; 4908 }else{ 4909 if(playlistSelectorFilterMsg)playlistSelectorFilterMsg.style.display = 'none'; 4910 } 4911 4912 }) 4913 4914 } 4915 4916 function closePlaylistSelector(){ 4917 4918 playlistSelectorContainer.addEventListener('transitionend', function cb(e){ 4919 e.currentTarget.removeEventListener(e.type, cb); 4920 4921 playlistSelectorContainer.style.display = 'none' 4922 4923 //hide thumbs 4924 var z=0; 4925 for(z=0;z<playlistSelectorLen;z++){ 4926 playlistSelectorArr[z].classList.remove('hap-playlist-selector-item-shown','hap-filter-hidden'); 4927 } 4928 4929 playlistSelectorOpened = false; 4930 4931 }) 4932 playlistSelectorContainer.style.opacity = 0; 4933 4934 //clear filter 4935 playlistSelectorFilterMsg.style.display = 'none'; 4936 playlistSelectorSearch.value = ''; 4937 4938 _body.classList.remove('hap-body-overflow') 4939 4940 } 4941 4942 4943 4944 4945 //############################################// 4946 /* playlist manager */ 4947 //############################################// 4948 4949 var _HAPPlaylistManager = new HAPPlaylistManager({loop:settings.loopState, random:settings.randomPlay}); 4950 4951 _HAPPlaylistManager.addEventListener('HAPPlaylistManager.QUE_NEXT_READY', function(e){ 4952 var data = playlistDataArr[e.counter].data 4953 4954 //check if we can crossfade 4955 if(data.type.indexOf('youtube') > -1 || data.type.indexOf('hls') > -1 || data.adPre || data.adEnd || data.start || data.end || data.vast){ 4956 console.log('crossfade only works with media type audio, podcast, soudncloud, cannot work when audio has pre / end advert set, cannot work when audio start / end positions are used, cannot work with variations!') 4957 nextMediaData = null; 4958 } 4959 else{ 4960 nextMediaData = data; 4961 } 4962 4963 }) 4964 4965 _HAPPlaylistManager.addEventListener('HAPPlaylistManager.COUNTER_READY', function(e){ 4966 if(mediaType){ 4967 cleanMedia(); 4968 } 4969 4970 mediaCounter = e.counter; 4971 currMediaData = playlistDataArr[mediaCounter].data; 4972 4973 self.fireEvent("soundRequest", [{instance:self, instanceName:settings.instanceName, media: currMediaData}]); 4974 4975 if(!currMediaData.type){ 4976 currMediaData = getTrackData(currMediaData); 4977 playlistDataArr[mediaCounter].data = currMediaData; 4978 } 4979 4980 mediaType = currMediaData.type; 4981 4982 if(mediaType == 'youtube_single')mediaType = 'youtube'; 4983 4984 4985 4986 allowedViewVideoUserRole = true; 4987 4988 if(settings.isUserLoggedIn){ 4989 if(typeof currMediaData.lockTime != undefined){ 4990 if(currentUserRoles && currMediaData.lockVideoUserRoles){ 4991 allowedViewVideoUserRole = HAPUtils.arrayContainsAnotherArray(currMediaData.lockVideoUserRoles, currentUserRoles); 4992 } 4993 } 4994 }else{ 4995 allowedViewVideoUserRole = false;
4996 } 4997 4998 4999 if(isEnqueue){ 5000 isEnqueue = false; 5001 return; 5002 } 5003 5004 //check if we can crossfade (maybe last song in playlist and loop is off) 5005 nextMediaData = null; 5006 nextDataCheck = false; 5007 if(settings.useCrossFade){ 5008 setTimeout(function(){ 5009 isCancelCrossFade = false;//wait till ramp ends 5010 },1000) 5011 } 5012 5013 5014 5015 setTitleAndThumb(); 5016 if(useMediaSession)updateMetadata(); 5017 5018 5019 5020 if(seekbarWave){ 5021 5022 if(waveformDataAws){//saved waveform from s3 5023 currMediaData.peaks = waveformDataAws; 5024 waveformDataAws = null; 5025 waveformLoading = false; 5026 } 5027 5028 if(currMediaData.peaks){ 5029 5030 drawWaveSeekbar() 5031 if(waveformLoader)waveformLoader.classList.add('hap-waveform-loader-hidden') 5032 5033 setTimeout(function(){//delay for crossfade 5034 seekbarWave.classList.add('hap-seekbar-wave-visible') 5035 },waveformCrossfadeTime) 5036 5037 }else{ 5038 5039 if(currMediaData.type != 's3_audio'){ 5040 waveformLoading = true; 5041 checkPeakExist(currMediaData.peakName || currMediaData.title); 5042 } 5043 5044 //clearSeekbar() 5045 5046 } 5047 5048 }else if(settings.useStickyPlayer){ 5049 if(currMediaData.type != 's3_audio'){ 5050 waveformLoading = true; 5051 checkPeakExist(currMediaData.peakName || currMediaData.title); 5052 } 5053 } 5054 5055 5056 5057 5058 //check last position 5059 if(continousPlaybackTrackAllSongs){ 5060 if(settings.lastPositionArr){ 5061 var i, len = settings.lastPositionArr.length, item; 5062 for(i = 0;i<len; i++){ 5063 item = settings.lastPositionArr[i]; 5064 if((item.title && currMediaData.title == item.title) && currMediaData.artist == item.artist){ 5065 currMediaData.start = item.start; 5066 break; 5067 } 5068 } 5069 } 5070 } 5071 5072 if(settings.usePlaylist){ 5073 5074 disableActivePlaylistItem(mediaCounter); 5075 5076 hasVariation = false; 5077 if(activePlaylistItem.querySelector('.hap-audio-variation')){ 5078 hasVariation = true; 5079 } 5080 5081 } 5082 5083 5084 5085 if(settings.useInlineSeekbar){ 5086 activePlaylistItem.querySelector('.hap-playlist-thumb').append(inlineSeekbar) 5087 } 5088 5089 5090 5091 5092 //check password 5093 if(!settings.useCrossFade){ 5094 if(currMediaData.pwd){ 5095 pwdHolderToggle() 5096 return false; 5097 } 5098 } 5099 5100 5101 doPostPwdActions()//we have to execute this after we confim pwd as well 5102 5103 5104 }) 5105 5106 _HAPPlaylistManager.addEventListener('PLAYLIST_END', function(){ 5107 self.fireEvent("playlistEnd", [{instance:self, instanceName:settings.instanceName}]); 5108 }); 5109 5110 function doPostPwdActions(){ 5111 5112 if(currMediaData.lyrics && lyricsHolder){ 5113 5114 if(!_lyrics){ 5115 5116 lyricsReady = false; 5117 5118 if(settings.lyricsWrap && settings.lyricsContainer){ 5119 var wrapContainer = document.querySelector(settings.lyricsWrap) 5120 var scrollContainer = document.querySelector(settings.lyricsContainer) 5121 }else{ 5122 var wrapContainer = lyricsHolder.querySelector('.hap-lyrics-wrap') 5123 var scrollContainer = lyricsHolder.querySelector('.hap-lyrics-container') 5124 } 5125 5126 var lyrics_settings = { 5127 wrapContainer: wrapContainer, 5128 scrollContainer: scrollContainer, 5129 settings: settings, 5130 itemClass: "hap-lyrics-item", 5131 activeClass: "hap-lyrics-item-active", 5132 } 5133 5134 _lyrics = new HAPLyrics(lyrics_settings) 5135 5136 document.addEventListener("HAPLyrics.LYRICS_CLICKED", function(e) { 5137 if(_HAPAdManager && _HAPAdManager.isAdOn() && settings.pauseAudioDuringAds) return false; 5138 if(isIma && isImaOn) return false; 5139 5140 self.seek(e.detail) 5141 self.playMedia() 5142 }); 5143 5144 document.addEventListener("HAPLyrics.LYRICS_READY", function(e) { 5145 //console.log('LYRICS_READY') 5146 if(e.detail)currMediaData.lyricsContent = e.detail;//save 5147 5148 lyricsReady = true; 5149 5150 if(settings.lyricsAutoOpen){ 5151 if(!lyricsOpened)self.toggleLyrics() 5152 } 5153 5154 }); 5155 5156 } 5157 5158 //check if lyrics exist 5159 5160 if(currMediaData.lyricsContent){ 5161 _lyrics.setData(currMediaData.lyricsContent) 5162 }else{ 5163 _lyrics.load(currMediaData.lyrics) 5164 } 5165 5166 if(lyricsToggle)lyricsToggle.style.display = 'block' 5167 5168 }else{ 5169 if(lyricsToggle)lyricsToggle.style.display = 'none' 5170 } 5171 5172 5173 if(currMediaData.video && videoWrap){ 5174 5175 var vfs = ' nofullscreen'; 5176 if(settings.useVideoFullscreen)vfs = ''; 5177 5178 var pip = ' disablepictureinpicture'; 5179 if(settings.useVideoPictureInPicture)pip = ''; 5180 5181 var dl = ' nodownload'; 5182 if(settings.useVideoDownload)dl = ''; 5183 5184 var controls = '';
5185 if(settings.useVideoControls)controls = ' controls'; 5186 5187 var code = '<video class="hap-video" preload="'+settings.preload+'" muted playsinline'+pip+' controlsList="noremoteplayback'+dl+vfs+controls+'">'; 5188 5189 code += '<source src="'+currMediaData.video+'" />'; 5190 code += '</video>'; 5191 5192 if(!settings.useVideoControls){ 5193 code += '<div class="hap-video-blocker"></div>'; 5194 } 5195 5196 videoWrap.innerHTML = code 5197 5198 videoSync = videoWrap.querySelector('.hap-video') 5199 5200 videoSync.addEventListener("canplay", function(){ 5201 if(settings.playbackRate){ 5202 try{ 5203 videoSync.playbackRate = Number(settings.playbackRate); 5204 }catch(er){} 5205 } 5206 }) 5207 5208 if(settings.useVideoControls){ 5209 //sync audio 5210 videoSync.addEventListener("play", function(){ 5211 syncComingFromVideo = true; 5212 self.playMedia() 5213 }) 5214 videoSync.addEventListener("pause", function(){ 5215 syncComingFromVideo = true; 5216 self.pauseMedia() 5217 }) 5218 videoSync.addEventListener("seeked", function(){ 5219 syncComingFromVideo = true; 5220 var ct = videoSync.currentTime; 5221 self.seek(ct) 5222 }) 5223 } 5224 5225 if(settings.videoAutoOpen){ 5226 if(!videoOpened)self.toggleVideo() 5227 } 5228 5229 videoToggle.style.display = 'block' 5230 5231 }else{ 5232 if(videoToggle)videoToggle.style.display = 'none' 5233 } 5234 5235 5236 5237 //############################################// 5238 /* ads */ 5239 //############################################// 5240 5241 if(currMediaData.adPre || currMediaData.adMid || currMediaData.adEnd){ 5242 if(!_HAPAdManager){ 5243 5244 if(typeof HAPAdManager === 'undefined'){ 5245 console.log('link to admanager.js file missing in head tag!'); 5246 } 5247 5248 _HAPAdManager = new HAPAdManager(settings, self, currMediaData, progressBg, progressLevel, mediaTimeAd); 5249 5250 _HAPAdManager.addEventListener('HAPAdManager.IOS_ADMID_FIX_START', function(data){ 5251 5252 }) 5253 _HAPAdManager.addEventListener('HAPAdManager.AD_PLAY_ACTION', function(data){ 5254 if(playbackToggle)self.toggleBigPlay(true) 5255 }) 5256 _HAPAdManager.addEventListener('HAPAdManager.AD_PAUSE_ACTION', function(data){ 5257 if(playbackToggle)self.toggleBigPlay() 5258 }) 5259 _HAPAdManager.addEventListener('HAPAdManager.ADPRE_PLAY', function(data){ 5260 5261 self.showAdInterface() 5262 5263 }) 5264 _HAPAdManager.addEventListener('HAPAdManager.ADPRE_ENDED', function(data){ 5265 5266 self.hideAdInterface() 5267 5268 findAudioSrc(); 5269 5270 }) 5271 _HAPAdManager.addEventListener('HAPAdManager.ADMID_PLAY', function(data){ 5272 5273 if(settings.pauseAudioDuringAds)self.pauseMedia(); 5274 5275 self.showAdInterface() 5276 5277 }) 5278 _HAPAdManager.addEventListener('HAPAdManager.ADMID_ENDED', function(data){ 5279 5280 self.hideAdInterface() 5281 5282 if(settings.pauseAudioDuringAds)self.playMedia(); 5283 5284 }) 5285 _HAPAdManager.addEventListener('HAPAdManager.ADEND_PLAY', function(data){ 5286 5287 self.showAdInterface() 5288 5289 }) 5290 _HAPAdManager.addEventListener('HAPAdManager.ADEND_ENDED', function(data){ 5291 5292 self.hideAdInterface() 5293 5294 if(!settings.stopOnSongEnd){ 5295 audioEndedAction(true); 5296 } 5297 5298 }); 5299 5300 }else{ 5301 _HAPAdManager.setAdData(currMediaData); 5302 } 5303 } 5304 5305 if(currMediaData.vast){ 5306 5307 isIma = true; 5308 5309 if(!imaLoaded){ 5310 loadIma() 5311 }else{ 5312 if(autoPlay){ 5313 initVast() 5314 } 5315 } 5316 5317 } 5318 5319 5320 5321 if(currMediaData.adPre){ 5322 5323 _HAPAdManager.initAd('pre'); 5324 5325 autoPlay = true; 5326 settings.autoPlay = true; 5327 5328 //############################################// 5329 /* ads */ 5330 //############################################// 5331 5332 }else{ 5333 5334 if(crossFadeOn){ 5335 5336 if(mediaType == 's3_audio'){ 5337 mediaType = 'audio';//this was set in get aws url 5338 } 5339 5340 }else{ 5341 5342 //check lock time 5343 if(currMediaData.lockTime == '0' && !allowedViewVideoUserRole){ 5344 toggleRedirectLoginScreen('watch'); 5345 }else{ 5346 findAudioSrc(); 5347 } 5348 } 5349 5350 } 5351 5352 } 5353 5354 function findAudioSrc(){ 5355 5356 if(mediaType == 'youtube'){ 5357 initYoutube(); 5358 5359 //if we use youtube we have to start video manually 5360 if(settings.hidePlayerUntilMusicStart)unhidePlayer(); 5361 5362 }else if(mediaType == 's3_audio'){ 5363 5364 getAwsUrl(currMediaData) 5365 5366 }else if(currMediaData.origtype && currMediaData.origtype == 'soundcloud'){ 5367 5368 if(currMediaData.sc_url){ 5369 5370 mediaPath = currMediaData.sc_url; 5371 delete currMediaData.sc_url 5372 5373 initAudio(); 5374 }else{ 5375 5376 _scLoader.get_stream_url(currMediaData.sc_data.id) 5377 } 5378 5379 }else{ 5380 mediaPath = getAudioUrl(currMediaData) 5381 5382 initAudio(); 5383 5384 } 5385 5386 } 5387 5388 //############################################// 5389 /* ima */ 5390 //############################################// 5391 5392 if(settings.useImaSkipButton){ 5393 5394 if(!adSkipBtn){ 5395 adSkipBtn = HAPUtils.htmlToElement('<div class="hap-ad-skip"></div>') 5396 HAPUtils.insertAfter(adSkipBtn, mediaTimeAd) 5397 } 5398 5399 adSkipBtn.addEventListener('click', function(){ 5400 if(_IMALoader)_IMALoader.skip() 5401 }) 5402 } 5403 5404 function loadIma(){ 5405 5406 var imaReady, 5407 imaLoaderReady 5408 5409 var script = document.createElement('script'); 5410 script.type = 'text/javascript'; 5411 script.src = settings.ima_js; 5412 script.onload = script.onreadystatechange = function() { 5413 if(!this.readyState || this.readyState == 'complete'){ 5414 imaReady = true; 5415 } 5416 }; 5417 script.onerror = function(){
5418 console.log("Error loading " + this.src); 5419 } 5420 var tag = document.getElementsByTagName('script')[0]; 5421 tag.parentNode.insertBefore(script, tag); 5422 5423 5424 if(typeof HAPIMALoader === 'undefined'){ 5425 var script = document.createElement('script'); 5426 script.type = 'text/javascript'; 5427 script.src = HAPUtils.qualifyURL(settings.sourcePath+settings.imaLoader_js); 5428 script.onload = script.onreadystatechange = function() { 5429 if(!this.readyState || this.readyState == 'complete'){ 5430 imaLoaderReady = true; 5431 } 5432 }; 5433 script.onerror = function(){ 5434 console.log("Error loading " + this.src); 5435 } 5436 var tag = document.getElementsByTagName('script')[0]; 5437 tag.parentNode.insertBefore(script, tag); 5438 5439 }else{ 5440 imaLoaderReady = true; 5441 } 5442 5443 var interval = setInterval(function(){ 5444 if(imaReady && imaLoaderReady){ 5445 clearInterval(interval); 5446 imaLoaded = true; 5447 initIma() 5448 } 5449 },100); 5450 5451 } 5452 5453 function initIma(){ 5454 5455 var imaHolder = HAPUtils.htmlToElement('<div class="hap-ima-holder"></div>') 5456 wrapper.append(imaHolder) 5457 5458 _IMALoader = new HAPIMALoader(settings, self, audio, imaHolder); 5459 5460 if(comingFromPwd){ 5461 comingFromPwd = false; 5462 if(!imaStarted)initVast() 5463 } 5464 5465 } 5466 5467 function initVast(){ 5468 5469 imaStarted = true; 5470 5471 var url = currMediaData.vast 5472 5473 if(url.substr(-11) == 'correlator='){ 5474 var randNum = Math.floor(Math.random() * (9999999 - 1 + 1)).toString(); 5475 url += randNum; 5476 } 5477 5478 _IMALoader.load(url, settings.volume) 5479 5480 } 5481 5482 this.cancelIma = function(){ 5483 //on ima error 5484 5485 isIma = false; 5486 imaStarted = false; 5487 isImaOn = false; 5488 self.hideAdInterface() 5489 5490 } 5491 5492 this.setImaEnded = function(isEnd){//ads done 5493 5494 isIma = false; 5495 imaStarted = false; 5496 isImaOn = false; 5497 5498 if(isEnd){ 5499 if(!settings.stopOnSongEnd){ 5500 audioEndedAction(); 5501 } 5502 }else{ 5503 self.hideAdInterface(); 5504 self.playMedia(); 5505 } 5506 5507 } 5508 5509 5510 //############################################// 5511 /* aws */ 5512 //############################################// 5513 5514 function getAwsUrl(data){ 5515 console.log('getAwsUrl') 5516 5517 if(data.key.indexOf(bsf_match) != -1)data.key = HAPUtils.b64DecodeUnicode(data.key.substr(6)); 5518 5519 if(settings.useCloudfront)var url = settings.sourcePath + 'includes/aws/aws2.php'; 5520 else var url = settings.sourcePath + 'includes/aws/aws.php'; 5521 5522 var params = 'object_key='+data.key+'&bucket='+data.bucket+'&action=get_url'+'®ion='+settings.s3Region+'&expire='+settings.s3UrlExpireTime+'&cf_expire='+settings.cf_expire+'&cred='+settings.s3+'&upload_dir='+settings.upload_dir; 5523 5524 if(xhrRequest){ 5525 xhrRequest.abort(); 5526 xhrRequest = null; 5527 } 5528 5529 xhrRequest = new XMLHttpRequest(); 5530 xhrRequest.onreadystatechange = function() { 5531 if (xhrRequest.readyState == 4) { 5532 5533 var result = JSON.parse(xhrRequest.responseText) 5534 5535 waveformDataAws2 = result; 5536 5537 if(crossFadeOn){ 5538 s3UrlReady = result; 5539 5540 if(settings.useWaveSeekbar){ 5541 5542 if(!nextMediaData.peaks){//waveform for next media 5543 5544 waveformLoading = true; 5545 5546 getPeakData(result) 5547 5548 } 5549 } 5550 5551 }else{ 5552 5553 mediaType = 'audio'; 5554 mediaPath = currMediaData.path = result 5555 5556 if(seekbarWave){ 5557 5558 if(currMediaData.peaks){//waveform for current media 5559 5560 drawWaveSeekbar() 5561 if(waveformLoader)waveformLoader.classList.add('hap-waveform-loader-hidden') 5562 5563 setTimeout(function(){//delay for crossfade 5564 seekbarWave.classList.add('hap-seekbar-wave-visible') 5565 },waveformCrossfadeTime) 5566 5567 }else{ 5568 5569 checkPeakExist(currMediaData.peakName || currMediaData.title); 5570 5571 } 5572 5573 } 5574 5575 initAudio() 5576 } 5577 5578 } 5579 } 5580 xhrRequest.onerror = function(e) { 5581 console.log('Error getAwsUrl: ' + e); 5582 self.fireEvent('getAws_error:', [{instance:self, instanceName:settings.instanceName, media:currMediaData, error:errorThrown}]); 5583 if(settings.autoAdvanceToNextSongOnError)self.nextMedia() 5584 }; 5585 xhrRequest.open('POST', url); 5586 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 5587 xhrRequest.send(params); 5588 5589 } 5590 5591 function resumeAwsUrl(data){ 5592 5593 if(data.key.indexOf(bsf_match) != -1)data.key = HAPUtils.b64DecodeUnicode(data.key.substr(6)); 5594 5595 if(settings.useCloudfront)var url = settings.sourcePath + 'includes/aws/aws2.php'; 5596 else var url = settings.sourcePath + 'includes/aws/aws.php'; 5597 5598 var params = 'object_key='+data.key+'&bucket='+data.bucket+'&action=get_url'+'®ion='+settings.s3Region+'&expire='+settings.s3UrlExpireTime+'&cf_expire='+settings.cf_expire+'&cred='+settings.s3+'&upload_dir='+settings.upload_dir; 5599 5600 if(xhrRequest){ 5601 xhrRequest.abort(); 5602 xhrRequest = null; 5603 } 5604 5605 xhrRequest = new XMLHttpRequest(); 5606 xhrRequest.onreadystatechange = function() { 5607 if (xhrRequest.readyState == 4) { 5608 5609 activeAudio.src = xhrRequest.responseText; 5610 5611 var promise = activeAudio.play(); 5612 if (promise !== undefined) { 5613 promise.then(function(){ 5614 }).catch(function(error){ 5615 }); 5616 } 5617 } 5618 } 5619 xhrRequest.onerror = function(e) { 5620 console.log('Error resumeAwsUrl: ' + e); 5621 self.fireEvent('getAws_error:', [{instance:self, instanceName:settings.instanceName, media:currMediaData, error:errorThrown}]); 5622 if(settings.autoAdvanceToNextSongOnError)self.nextMedia() 5623 }; 5624 xhrRequest.open('POST', url); 5625 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 5626 xhrRequest.send(params); 5627 5628 } 5629 5630 function getAwsThumb(data){ 5631 5632 var url = settings.sourcePath + 'includes/aws/aws.php' 5633 5634 var params = 'object_key='+data.thumb_key+'&bucket='+data.bucket+'&action=get_url_thumb'+'®ion='+settings.s3Region+'&expire='+settings.s3UrlExpireTime+'&cred='+settings.s3; 5635 5636 var xhr = new XMLHttpRequest(); 5637 xhr.onreadystatechange = function() { 5638 if (xhr.readyState == 4) { 5639 5640 currMediaData.thumb = this.responseText; 5641 5642 setThumb(xhr.responseText) 5643 } 5644 } 5645 xhr.onerror = function(e) { 5646 console.log('Error getAwsThumb: ' + e); 5647 checkProcessCounter(); 5648 }; 5649 xhr.open('POST', url); 5650 xhr.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 5651 xhr.send(params); 5652 5653 } 5654 5655 // bucket 5656 5657 function processS3Bucket(data){ 5658 5659 if(window.location.protocol == 'file:'){ 5660 console.log('Reading folders requires server connection.'); 5661 return false;
5662 } 5663 5664 var url = settings.sourcePath + 'includes/aws/aws.php' 5665 5666 var params = 'bucket='+data.bucket+'&action=list_bucket'+'®ion='+settings.s3Region+'&cred='+settings.s3; 5667 5668 if(xhrRequest){ 5669 xhrRequest.abort(); 5670 xhrRequest = null; 5671 } 5672 5673 xhrRequest = new XMLHttpRequest(); 5674 xhrRequest.onreadystatechange = function() { 5675 if (xhrRequest.readyState == 4) { 5676 5677 var media = JSON.parse(xhrRequest.responseText) 5678 5679 var i, len = media.length, entry, obj; 5680 5681 if(data.sort){ 5682 if(data.sort == 'filename-asc')HAPUtils.keysrt4(media, 'filename'); 5683 else if(data.sort == 'filename-desc')HAPUtils.keysrt4(media, 'filename', true); 5684 } 5685 5686 for(i=0; i < len; i++){ 5687 5688 entry = media[i]; 5689 5690 if(/mp3|wav|aac|ogg|flac/.test(entry)){ 5691 5692 obj = HAPUtils.extendObj(true, {}, data); 5693 obj.type = 's3_audio'; 5694 obj.key = entry; 5695 obj.title = entry.substr(0, entry.lastIndexOf('.')); 5696 5697 obj.thumb_key = obj.title + '.' + settings.s3ThumbExtension; 5698 5699 playlistProcessData.push(obj); 5700 } 5701 5702 } 5703 5704 checkProcessCounter(); 5705 } 5706 } 5707 xhrRequest.onerror = function(e) { 5708 console.log('Error processS3Bucket: ' + e); 5709 checkProcessCounter(); 5710 }; 5711 xhrRequest.open('POST', url); 5712 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 5713 xhrRequest.send(params); 5714 5715 } 5716 5717 /*****************/ 5718 5719 var audioCtx; 5720 var peakLength = 100; 5721 var peakCounter = 0 5722 5723 if(settings.useWaveSeekbar || settings.useStickyPlayer){ 5724 audioCtx = new AudioContext(); 5725 } 5726 5727 function getPeakData(audioData) { 5728 5729 return fetch(audioData) 5730 .then((response) => { 5731 if (!response.ok) { 5732 if(waveformLoader)waveformLoader.classList.add('hap-waveform-loader-hidden') 5733 if(settings.demoPeakArr)fakePeak() 5734 } 5735 return response.arrayBuffer(); 5736 }) 5737 .then((buffer) => audioCtx.decodeAudioData(buffer)) 5738 .then((decodedData) => { 5739 5740 var data = extractPeaks(decodedData), 5741 val = data.toString(); 5742 5743 if(peakWriteRequired){ 5744 writePeaks(val, currMediaData.peakName || currMediaData.title); 5745 peakWriteRequired = false; 5746 } 5747 5748 5749 5750 if(crossFadeOn && s3UrlReady){ 5751 //s3 5752 5753 waveformDataAws = val; 5754 5755 }else{ 5756 5757 currMediaData.peaks = val; 5758 5759 waveformLoading = false; 5760 5761 if(seekbarWave){ 5762 5763 drawWaveSeekbar() 5764 if(waveformLoader)waveformLoader.classList.add('hap-waveform-loader-hidden') 5765 5766 setTimeout(function(){//delay for crossfade 5767 seekbarWave.classList.add('hap-seekbar-wave-visible') 5768 },waveformCrossfadeTime) 5769 5770 }else if(settings.useStickyPlayer){ 5771 5772 if(settings.useStickyPlayer && window['hap_fixed_active_player'] == settings.instanceName){ 5773 _HAPStickyPlayer.setPeakData(currMediaData.peaks) 5774 } 5775 5776 } 5777 5778 } 5779 5780 }).catch((error) => { 5781 console.log(error) 5782 if(waveformLoader)waveformLoader.classList.add('hap-waveform-loader-hidden') 5783 if(settings.demoPeakArr)fakePeak() 5784 }); 5785 5786 }; 5787 5788 function extractPeaks( buffer ) { 5789 const channels = buffer.numberOfChannels, 5790 sampleSize = buffer.length / peakLength, 5791 sampleStep = ~~( sampleSize / 10) || 1 5792 5793 const peak_data = [] 5794 var c 5795 5796 for (c = 0; c < channels; c++) { 5797 const stepPeaks = [] 5798 const chan = buffer.getChannelData(c) 5799 5800 for (var i = 0; i < peakLength; i++) { 5801 var start = ~~(i * sampleSize) 5802 var end = ~~(start + sampleSize) 5803 var min = chan[0] 5804 var max = chan[0] 5805 5806 for (var j = start; j < end; j += sampleStep) { 5807 var value = chan[j] 5808 if (value > max) 5809 max = value 5810 if (value < min) 5811 min = value 5812 } 5813 stepPeaks[2 * i] = max 5814 stepPeaks[2 * i + 1] = min 5815 5816 if (c == 0 || max > peak_data[2 * i]) 5817 peak_data[2 * i] = Math.abs( max.toFixed(2) ) 5818 5819 if (c == 0 || min < peak_data[2 * i + 1]) 5820 peak_data[2 * i + 1] = Math.abs( min.toFixed(2) ) 5821 } 5822 } 5823 return peak_data 5824 } 5825 5826 function fakePeak(){ 5827 //load demo peak if current fails 5828 5829 var r = settings.demoPeakArr[Math.floor(Math.random()*settings.demoPeakArr.length)]; 5830 currMediaData.peaks = r 5831 5832 waveformLoading = false;
5833 5834 if(seekbarWave)drawWaveSeekbar() 5835 if(waveformLoader)waveformLoader.classList.add('hap-waveform-loader-hidden') 5836 5837 if(seekbarWave){ 5838 setTimeout(function(){//delay for crossfade 5839 seekbarWave.classList.add('hap-seekbar-wave-visible') 5840 },waveformCrossfadeTime) 5841 } 5842 5843 if(settings.useStickyPlayer && window['hap_fixed_active_player'] == settings.instanceName){ 5844 _HAPStickyPlayer.setPeakData(currMediaData.peaks) 5845 } 5846 5847 } 5848 5849 function checkPeakExist(id){ 5850 5851 if(window.location.protocol == 'file:'){ 5852 console.log('Using peaks requires server connection!'); 5853 return 5854 } 5855 5856 if(xhrRequest_loadPeaks){ 5857 xhrRequest_loadPeaks.abort(); 5858 xhrRequest_loadPeaks = null; 5859 } 5860 5861 var url = settings.sourcePath + 'peaks/_peaks.php' 5862 5863 var params = 'action=hap_read_peaks' 5864 +'&id='+encodeURIComponent(id) 5865 5866 if(currMediaData.peakdir)params += '&path='+currMediaData.peakdir 5867 5868 xhrRequest_loadPeaks = new XMLHttpRequest(); 5869 xhrRequest_loadPeaks.onreadystatechange = function() { 5870 if (this.readyState == 4) { 5871 5872 if(this.response.length > 2){ 5873 //console.log('peak exist') 5874 //no need for json parse because we needs peak in string format 5875 var peaks = this.response.substring(1, this.response.length-1);//array to string 5876 5877 currMediaData.peaks = peaks; 5878 5879 waveformLoading = false; 5880 5881 if(seekbarWave){ 5882 5883 drawWaveSeekbar() 5884 5885 if(waveformLoader)waveformLoader.classList.add('hap-waveform-loader-hidden') 5886 5887 setTimeout(function(){//delay for crossfade 5888 seekbarWave.classList.add('hap-seekbar-wave-visible') 5889 },waveformCrossfadeTime) 5890 5891 }else if(settings.useStickyPlayer){ 5892 5893 if(window['hap_fixed_active_player'] == settings.instanceName){ 5894 _HAPStickyPlayer.setPeakData(currMediaData.peaks) 5895 } 5896 5897 } 5898 5899 }else{ 5900 //console.log('peak NOT exist', currMediaData.remote) 5901 5902 peakWriteRequired = true; 5903 5904 if(currMediaData.remote){ 5905 5906 if(currMediaData.origtype && currMediaData.origtype == 'soundcloud'){ 5907 5908 if(!currMediaData.sc_url){ 5909 5910 var interval = setInterval(function(){ 5911 if(mediaPath){ 5912 if(interval) clearInterval(interval); 5913 remoteDownload(); 5914 } 5915 }, 100); 5916 5917 }else{ 5918 remoteDownload(); 5919 } 5920 5921 }else{ 5922 remoteDownload(); 5923 } 5924 5925 }else{ 5926 5927 if(currMediaData.type == 's3_audio'){ 5928 if(waveformDataAws2)getPeakData(waveformDataAws2) 5929 }else{ 5930 getPeakData(mediaPath) 5931 } 5932 5933 } 5934 5935 } 5936 5937 5938 } 5939 } 5940 xhrRequest_loadPeaks.onerror = function(e) { 5941 console.log(jqXHR, textStatus, errorThrown); 5942 }; 5943 xhrRequest_loadPeaks.open('POST', url); 5944 xhrRequest_loadPeaks.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 5945 xhrRequest_loadPeaks.send(params); 5946 5947 } 5948 5949 function writePeaks(peaks, title){ 5950 5951 var params = 'action=hap_write_peaks' 5952 +'&peaks='+peaks 5953 +'&id='+encodeURIComponent(title) 5954 5955 if(currMediaData.peakdir)params += '&path='+currMediaData.peakdir 5956 5957 if(xhrRequest_writePeaks){ 5958 xhrRequest_writePeaks.abort(); 5959 xhrRequest_writePeaks = null; 5960 } 5961 5962 var url = settings.sourcePath + 'peaks/_peaks.php'; 5963 5964 xhrRequest_writePeaks = new XMLHttpRequest(); 5965 xhrRequest_writePeaks.onreadystatechange = function() { 5966 5967 } 5968 xhrRequest_writePeaks.onerror = function(e) { 5969 console.log(jqXHR, textStatus, errorThrown); 5970 }; 5971 xhrRequest_writePeaks.open('POST', url); 5972 xhrRequest_writePeaks.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 5973 xhrRequest_writePeaks.send(params); 5974 5975 } 5976 5977 function remoteDownload(){ 5978 console.log('remoteDownload') 5979 5980 if(xhrRequest_remoteDownload){ 5981 xhrRequest_remoteDownload.abort(); 5982 xhrRequest_remoteDownload = null; 5983 } 5984 5985 var url = settings.sourcePath + 'peaks/_remote_dl.php'; 5986 5987 var da = {id: mediaPath, title: currMediaData.title }//sc need, id can contain multiple & 5988 if(currMediaData.peakdir)da.path = currMediaData.peakdir; 5989 5990 xhrRequest_remoteDownload = new XMLHttpRequest(); 5991 xhrRequest_remoteDownload.onreadystatechange = function() { 5992 if (this.readyState == 4) { 5993 5994 if(this.response != ''){ 5995 var response = JSON.parse(this.response); 5996 getPeakData(response) 5997 } 5998 5999 } 6000 } 6001 xhrRequest_remoteDownload.onerror = function(e) { 6002 console.log(jqXHR, textStatus, errorThrown); 6003 6004 if(waveformLoader)waveformLoader.classList.add('hap-waveform-loader-hidden') 6005 if(settings.demoPeakArr)fakePeak() 6006 6007 }; 6008 xhrRequest_remoteDownload.open('POST', url); 6009 xhrRequest_remoteDownload.setRequestHeader("Content-Type", "application/json"); 6010 xhrRequest_remoteDownload.send(JSON.stringify(da)); 6011 6012 } 6013 6014 6015 //############################################// 6016 /* youtube player */ 6017 //############################################// 6018 6019 function initYoutube() { 6020 6021 mediaPath = currMediaData.mp3 || currMediaData.path; 6022 if(mediaPath.indexOf(bsf_match) != -1)mediaPath = HAPUtils.b64DecodeUnicode(mediaPath.substr(6)); 6023 6024 if(!youtubeInited){ 6025 6026 if(!playerThumb){ 6027 alert('Using Youtube requires player to have thumbnail image in player where Youtube player will be placed. Please use demo which has thumbnail in player! hap-player-thumb element'); 6028 return; 6029 } 6030 6031 youtubeHolder = HAPUtils.htmlToElement('<div class="hap-youtube-holder"></div>'); 6032 playerThumb.append(youtubeHolder) 6033 6034 var yt_frameId = 'ytplayer' + Math.floor(Math.random()*0xFFFFFF), 6035 prefix = ('https:' == window.location.protocol ? 'https:' : 'http:'), 6036 yt_embed = '//www.youtube.com/embed/', 6037 enablejsapi = '?enablejsapi=1', 6038 controls = '&controls=0', 6039 wmode = '&wmode=transparent', 6040 showinfo = '&showinfo=0', 6041 modestbranding = '&modestbranding=1', 6042 rel = '&rel=0', 6043 autoplay = '&autoplay=1', 6044 playsinline = '&playsinline=1', 6045 iv_load_policy = '&iv_load_policy=3', 6046 cc_load_policy = '&cc_load_policy=0', 6047 domain = window.location.href.split("/"), 6048 orig = domain[0] + "//" + domain[2], 6049 origin = '&origin=' + orig; 6050 6051 var iframeSrc = prefix + yt_embed + mediaPath + enablejsapi + controls + rel + showinfo + playsinline + modestbranding + wmode + iv_load_policy + cc_load_policy; 6052 6053 if(/^http/.test(orig))iframeSrc += origin; 6054 6055 if(settings.resumeTime){
6056 iframeSrc += '&start='+settings.resumeTime; 6057 delete settings.resumeTime; 6058 }else if(currMediaData.start)iframeSrc += '&start='+currMediaData.start; 6059 if(currMediaData.end)iframeSrc += '&end='+currMediaData.end; 6060 6061 youtubeIframe = HAPUtils.htmlToElement('<iframe id="'+yt_frameId+'" src="'+iframeSrc+'" frameborder="0" width="100%" height="100%" webkitAllowFullScreen mozallowfullscreen allowFullScreen allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"></iframe>'); 6062 6063 youtubeIframe.classList.add('hap-media'); 6064 6065 youtubeHolder.style.display = 'block'; 6066 youtubeHolder.prepend(youtubeIframe); 6067 6068 if(!window.YT){ 6069 var tag = document.createElement('script'); 6070 tag.src = youtube_js; 6071 var firstScriptTag = document.getElementsByTagName('script')[0]; 6072 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 6073 } 6074 6075 var interval = setInterval(function(){ 6076 if(window.YT && window.YT.Player){ 6077 if(interval) clearInterval(interval); 6078 6079 youtubePlayer = new YT.Player(yt_frameId, { 6080 events: { 6081 'onReady': onYtPlayerReady, 6082 'onStateChange': onYtPlayerStateChange, 6083 'onError': onYtPlayerError 6084 } 6085 }); 6086 } 6087 }, 100); 6088 6089 youtubeInited = true; 6090 6091 }else{ 6092 6093 if(youtubeReady){ 6094 6095 var st = 0; 6096 if(settings.resumeTime)st = resumeTime; 6097 else if(currMediaData.start)st = currMediaData.start; 6098 6099 if(autoPlay){ 6100 youtubePlayer.loadVideoById({'videoId':mediaPath, 'startSeconds':st, 'endSeconds':currMediaData.end, 'suggestedQuality':currMediaData.quality}); 6101 }else{ 6102 youtubePlayer.cueVideoById({'videoId':mediaPath, 'startSeconds':st, 'endSeconds':currMediaData.end, 'suggestedQuality':currMediaData.quality}); 6103 } 6104 6105 } 6106 } 6107 6108 youtubeHolder.style.display = 'block'; 6109 } 6110 6111 window.onYouTubeIframeAPIReady = function() {} 6112 6113 function onYtPlayerReady(event) { 6114 youtubeReady = true; 6115 6116 if(settings.forceYoutubeChromeless)youtubeIframe.classList.add('hap-yt-clean'); 6117 6118 if(youtubePlayed && autoPlay){ 6119 youtubePlayer.playVideo(); 6120 } 6121 } 6122 6123 function onYtPlayerStateChange(event) { 6124 if(!youtubeHolder.style.display == 'none')return; 6125 6126 if(event.data == -1){//unstarted 6127 } 6128 else if(event.data == 0){//ended 6129 6130 if(useRange && rangeOn && !rangeSet && !_HAPRangeSlider.isDrag()){ 6131 rangeSet = true; 6132 youtubePlayer.seekTo(range_a_time); 6133 youtubePlayer.playVideo(); 6134 return; 6135 } 6136 6137 if(youtubeEndFix)return; 6138 youtubeEndFix = true; 6139 mediaEndHandler(); 6140 } 6141 else if(event.data == 1){//playing 6142 6143 if(!youtubeStarted){ 6144 youtubeEndFix = false; 6145 6146 youtubePlayer.setPlaybackRate(Number(settings.playbackRate)); 6147 6148 if(!youtubeBlocker){ 6149 youtubeBlocker = HAPUtils.htmlToElement('<div class="hap-iframe-blocker"></div>') 6150 youtubeBlocker.style.display = 'block' 6151 youtubeHolder.append(youtubeBlocker); 6152 } 6153 6154 youtubeStarted = true; 6155 autoPlay = true; 6156 settings.autoPlay = true; 6157 youtubePlayed = true; 6158 6159 if(settings.hideYoutubeAfterStart)youtubeHolder.style.opacity = 0; 6160 6161 if(useRange){ 6162 rangeMinTime.innerHTML = '00:00'; 6163 rangeMaxTime.innerHTML = HAPUtils.formatTime(youtubePlayer.getDuration()); 6164 } 6165 6166 } 6167 6168 if(useRange && rangeOn){ 6169 setTimeout(function(){ 6170 clearTimeout(this); 6171 rangeSet = false; 6172 },1000); 6173 } 6174 6175 if(dataIntervalID) clearInterval(dataIntervalID); 6176 dataIntervalID = setInterval(trackProgress, dataInterval); 6177 6178 playHandler(); 6179 6180 } 6181 else if(event.data == 2){//paused 6182 pauseHandler(); 6183 } 6184 else if(event.data == 3){//buffering 6185 6186 } 6187 else if(event.data == 5){//cued 6188 6189 } 6190 } 6191 6192 function onYtPlayerError(e) { 6193 var error = 'Youtube erorr'; 6194 switch(e.data){ 6195 case 2: 6196 error = "Error code = "+e.data+": The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks." 6197 break; 6198 case 100: 6199 error = "Error code = "+e.data+": Video not found, removed, or marked as private" 6200 break; 6201 case 101:
6202 error = "Error code = "+e.data+": Embedding disabled for this video" 6203 break; 6204 case 150: 6205 error = "Error code = "+e.data+": Video not found, removed, or marked as private [same as error 100]" 6206 break; 6207 } 6208 6209 self.fireEvent('soundError', [{instance:self, instanceName:settings.instanceName, media:currMediaData, error:e}]); 6210 6211 if(settings.autoAdvanceToNextSongOnError)self.nextMedia() 6212 6213 } 6214 6215 //############################################// 6216 /* google analytics */ 6217 //############################################// 6218 6219 if(useGa){ 6220 6221 var script = document.createElement('script'); 6222 script.type = 'text/javascript'; 6223 script.async = true; 6224 script.src = settings.gtag_js + settings.gaTrackingId; 6225 script.onload = script.onreadystatechange = function() { 6226 6227 window.dataLayer = window.dataLayer || []; 6228 function gtag(){dataLayer.push(arguments);} 6229 gtag('js', new Date()); 6230 gtag('config', settings.gaTrackingId); 6231 6232 }; 6233 script.onerror = function(er){ 6234 console.log(er) 6235 } 6236 var tag = document.getElementsByTagName('script')[0]; 6237 tag.parentNode.insertBefore(script, tag); 6238 6239 } 6240 6241 //download 6242 onHandler(wrapper, 'click', '.hap-download', (e) => downloadHandler(e)); 6243 6244 function downloadHandler(e){ 6245 e.preventDefault() 6246 6247 if(!componentInited) return false; 6248 6249 var target = e.target, 6250 item = target.closest('.hap-playlist-item'), 6251 id = Number(item.getAttribute('data-id')) 6252 6253 var i, len = playlistDataArr.length, data 6254 for(i = 0;i < len; i++){ 6255 if(id == playlistDataArr[i].id){ 6256 data = playlistDataArr[i].data 6257 break; 6258 } 6259 } 6260 6261 var title = self.getTitle(data, true) 6262 6263 pwdDownloadData = {} 6264 pwdDownloadData.orig_data = data 6265 pwdDownloadData.type = 'hap-download' 6266 pwdDownloadData.title = title; 6267 6268 if(data && data.download){ 6269 //check password 6270 if(data.pwd){ 6271 pwdAction = 'download' 6272 6273 pwdHolderToggle() 6274 }else{ 6275 doDownloadAction() 6276 } 6277 } 6278 6279 return false; 6280 6281 }; 6282 function handleDownloadFromSticky(){ 6283 6284 var data = currMediaData 6285 6286 var title = self.getTitle(data, true) 6287 6288 pwdDownloadData = {} 6289 pwdDownloadData.orig_data = data 6290 pwdDownloadData.type = 'hap-download' 6291 pwdDownloadData.title = title; 6292 6293 if(data && data.download){ 6294 //check password 6295 if(data.pwd){ 6296 pwdAction = 'download' 6297 6298 pwdHolderToggle() 6299 }else{ 6300 doDownloadAction() 6301 } 6302 } 6303 6304 return false; 6305 6306 } 6307 6308 function doDownloadAction(){ 6309 6310 if(window.location.protocol == 'file:'){ 6311 console.log('Download to work requires server connection!'); 6312 } 6313 6314 if((settings.restrictDownloadForLoggedInUser && !settings.isUserLoggedIn) || !allowedDownloadVideoUserRole){ 6315 toggleRedirectLoginScreen('download'); 6316 return; 6317 } 6318 6319 downloadFile(pwdDownloadData.orig_data.download) 6320 6321 if(pwdDownloadData.type == 'hap-download'){ 6322 6323 if(useGa && typeof gtag !== "undefined"){ 6324 6325 gtag('event', 'download', { 6326 'send_to': settings.gaTrackingId, 6327 'event_category': "Modern audio player: " + settings.instanceName, 6328 eventLabel: 'title: ' + pwdDownloadData.title, 6329 'non_interaction': true 6330 }); 6331 } 6332 6333 } 6334 else if(pwdDownloadData.type == 'hap-download-count'){ 6335 6336 getStats('hap_download_count', pwdDownloadData.id); 6337 6338 } 6339 6340 pwdAction = null; 6341 pwdDownloadData = null; 6342 6343 } 6344 6345 function downloadFile(url) { 6346 const a = document.createElement('a') 6347 a.href = url 6348 a.download = url.split('/').pop() 6349 document.body.appendChild(a) 6350 a.click() 6351 document.body.removeChild(a) 6352 } 6353 6354 //############################################// 6355 /* continous playback */ 6356 //############################################// 6357 6358 var eventName = isIOS ? "pagehide" : "beforeunload", 6359 addListener = window.attachEvent || window.addEventListener; 6360 6361 if(useContinousPlayback){ 6362 6363 addListener(eventName, function (event) { 6364 if(window.event)window.event.cancelBubble = true; 6365 saveSongState() 6366 }); 6367 6368 /*if(isIOS){ 6369 document.addEventListener("unload", function(e){ 6370 saveSongState() 6371 }); 6372 }*/ 6373 6374 }else{ 6375 localStorage.removeItem(settings.continousKey); 6376 } 6377 6378 function saveSongState(){ 6379 6380 if(!componentInited) return false;
6381 if(!mediaType) return false; 6382 6383 var d = { 6384 activePlaylist: settings.activePlaylist, 6385 volume: settings.volume, 6386 activeItem: _HAPPlaylistManager.getCounter(), 6387 resumeTime: self.getCurrentTime(), 6388 autoPlay : mediaPlaying 6389 }; 6390 //remember last song time for each song 6391 if(continousPlaybackTrackAllSongs){ 6392 var i, arr = [], item; 6393 for(i = 0;i<playlistLength; i++){ 6394 item = playlistDataArr[i].data; 6395 if(item.start)arr.push({title: item.title, artist: item.artist, start: item.start}); 6396 } 6397 d.lastPositionArr = arr; 6398 d.lastPositionDataPath = lastPositionDataPath; 6399 } 6400 localStorage.setItem(settings.continousKey, JSON.stringify(d)); 6401 6402 } 6403 6404 //############################################// 6405 /* media session */ 6406 //############################################// 6407 6408 if(useMediaSession){ 6409 6410 navigator.mediaSession.setActionHandler('play', function() { 6411 self.playMedia(); 6412 }); 6413 6414 navigator.mediaSession.setActionHandler('pause', function() { 6415 self.pauseMedia(); 6416 }); 6417 6418 navigator.mediaSession.setActionHandler('previoustrack', function() { 6419 self.previousMedia(); 6420 }); 6421 6422 navigator.mediaSession.setActionHandler('nexttrack', function() { 6423 self.nextMedia(); 6424 }); 6425 6426 navigator.mediaSession.setActionHandler('seekbackward', function() { 6427 self.seekBackward(); 6428 }); 6429 6430 navigator.mediaSession.setActionHandler('seekforward', function() { 6431 self.seekForward(); 6432 }); 6433 6434 } 6435 6436 function updateMetadata(){ 6437 6438 navigator.mediaSession.metadata = new MediaMetadata({ 6439 title: currMediaData.title, 6440 artist: currMediaData.artist || '', 6441 album: currMediaData.album || '', 6442 artwork: [{src:currMediaData.thumb || ''}] 6443 }); 6444 6445 } 6446 6447 //############################################// 6448 /* tooltip */ 6449 //############################################// 6450 6451 var tooltip = wrapper.querySelector('.hap-tooltip'); 6452 6453 if(!isMobile){ 6454 6455 if(tooltip && window.getComputedStyle(wrapper).position == 'static'){ 6456 console.log("player css position is static, therefore tooltip might not work correctly. Please set wrapper css position to other than static if you use tooltip in player."); 6457 } 6458 6459 /*wrapper.querySelectorAll('[data-tooltip]').forEach(el => { 6460 6461 el.addEventListener("mouseenter", function(e){ 6462 6463 if(!tooltip)return false; 6464 6465 var item = e.currentTarget 6466 6467 tooltip.style.display = 'block'; 6468 6469 tooltip.innerHTML = item.getAttribute('data-tooltip'); 6470 6471 var main = wrapper.getBoundingClientRect(), 6472 element = item.getBoundingClientRect(); 6473 6474 var t = parseInt(element.top - main.top - tooltip.offsetHeight), 6475 l = parseInt(element.left - main.left - tooltip.offsetWidth / 2 + item.offsetWidth / 2); 6476 6477 //keep within window 6478 6479 var wv = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 6480 6481 if(l + main.left < 0)l = parseInt(element.left - main.left + 15); 6482 else if(l + main.left + tooltip.offsetWidth > wv){ 6483 l = parseInt(element.left + element.width - main.left - tooltip.offsetWidth); 6484 } 6485 6486 if(t + main.top < 0)t = parseInt(element.top - main.top + tooltip.offsetHeight + 15);//position below 6487 //else if(t < 0) t = 0; 6488 6489 tooltip.style.left = l+'px'; 6490 tooltip.style.top = t+'px'; 6491 6492 }) 6493 6494 el.addEventListener("mouseleave", function(e){ 6495 if(!tooltip)return false; 6496 tooltip.style.display = 'none'; 6497 }); 6498 6499 })*/ 6500 6501 } 6502 6503 function showTooltip(item){ 6504 6505 var main = wrapper.getBoundingClientRect(), 6506 element = item.getBoundingClientRect(); 6507 6508 tooltip.innerHTML = item.getAttribute('data-tooltip'); 6509 6510 tooltip.style.display = 'block'; 6511 6512 var t = parseInt(element.top - main.top - tooltip.offsetHeight), 6513 l = parseInt(element.left - main.left - tooltip.offsetWidth/2 + item.offsetWidth/2); 6514 6515 //keep within component 6516 6517 //if(l + tooltip.offsetWidth > wrapper.offsetWidth)l = wrapper.offsetWidth - tooltip.offsetWidth; 6518 //else if(l < 0) l = 0; 6519 6520 //if(t + main.top < 0)t = parseInt(element.top - main.top + tooltip.offsetHeight + 15);//position below 6521 //else if(t < 0) t = 0; 6522 6523 tooltip.style.left = l+'px'; 6524 tooltip.style.top = t+'px'; 6525 6526 } 6527 6528 6529 //############################################// 6530 /* circle player */ 6531 //############################################// 6532 6533 var circleSeekbar = wrapper.querySelector('.hap-circle-player'), 6534 _HAPCirclePlayer; 6535 6536 if(circleSeekbar && HAPUtils.hasCanvas()){ 6537 if(typeof HAPCirclePlayer === 'undefined'){ 6538 console.log('Link to circleplayer.js file missing in head tag!'); 6539 }else{ 6540 _HAPCirclePlayer = new HAPCirclePlayer({settings:settings, parent:wrapper}); 6541 } 6542 6543 } 6544 6545 6546 //############################################// 6547 /* seekbar */ 6548 //############################################// 6549 6550 if(circleSeekbar){ 6551 var seekbar = wrapper.querySelector('.hap-progress-canvas'); 6552 }else{ 6553 var seekbar = wrapper.querySelector('.hap-seekbar'); 6554 } 6555 6556 if(seekbar){ 6557 seekbar.addEventListener(events.downEvent,function(e){ 6558 if(!componentInited) return; 6559 6560 if(class_list.indexOf('hap-fixed') > -1 || class_list.indexOf('hap-fixed2') > -1)if(!settings.playerOpened)return false;
6561 6562 if(settings.disableSeekbarInRange && rangeOn)return false; 6563 if(settings.disableSeekbar) return false; 6564 if(settings.disableSongSkip) return false; 6565 if(_HAPAdManager && _HAPAdManager.isAdOn()) return false; 6566 if(isIma && isImaOn) return false; 6567 if(!mediaType) return false; 6568 if(crossFadeOn)cancelCrossFadeSeek(); 6569 6570 onDragStartSeek(e); 6571 6572 }); 6573 6574 if("ontouchstart" in window){ 6575 6576 seekbar.addEventListener('touchstart',function(e){ 6577 if(!componentInited) return; 6578 6579 if(e.preventDefault) e.preventDefault(); 6580 6581 if(class_list.indexOf('hap-fixed') > -1 || class_list.indexOf('hap-fixed2') > -1)if(!settings.playerOpened)return false; 6582 6583 if(settings.disableSeekbarInRange && rangeOn)return false; 6584 if(settings.disableSeekbar) return false; 6585 if(settings.disableSongSkip) return false; 6586 if(_HAPAdManager && _HAPAdManager.isAdOn()) return false; 6587 if(isIma && isImaOn) return false; 6588 if(!mediaType) return false; 6589 if(crossFadeOn)cancelCrossFadeSeek(); 6590 6591 onDragStartSeek(e); 6592 6593 }); 6594 6595 } 6596 } 6597 6598 // Start dragging 6599 function onDragStartSeek(e) { 6600 6601 if(!seekBarDown){ 6602 6603 seekBarDown = true; 6604 _doc.addEventListener(events.moveEvent, onDragMoveSeek) 6605 _doc.addEventListener(events.upEvent, onDragReleaseSeek); 6606 6607 if("ontouchstart" in window){ 6608 _doc.addEventListener('touchmove', onDragMoveSeek) 6609 _doc.addEventListener('touchend', onDragReleaseSeek); 6610 } 6611 } 6612 } 6613 6614 function onDragMoveSeek(e) { 6615 6616 var point; 6617 if(e.type == 'touchmove'){ 6618 var touches = e.changedTouches; 6619 6620 if(touches.length > 1) { 6621 return false; 6622 } 6623 point = touches[0]; 6624 e.preventDefault(); 6625 } else { 6626 point = e; 6627 e.preventDefault(); 6628 } 6629 setProgress(point); 6630 6631 if(tooltip)mouseMoveHandlerSeekTooltip(point); 6632 6633 } 6634 6635 function onDragReleaseSeek(e) { 6636 6637 if(seekBarDown){ 6638 seekBarDown = false; 6639 _doc.removeEventListener(events.moveEvent, onDragMoveSeek) 6640 _doc.removeEventListener(events.upEvent, onDragReleaseSeek); 6641 6642 if("ontouchstart" in window){ 6643 _doc.removeEventListener('touchmove', onDragMoveSeek) 6644 _doc.removeEventListener('touchend', onDragReleaseSeek); 6645 } 6646 6647 var point; 6648 if(e.type == 'touchend'){ 6649 var touches = e.changedTouches; 6650 6651 // If touches more then one, so stop sliding and allow browser do default action 6652 if(touches.length > 1) { 6653 return false; 6654 } 6655 point = touches[0]; 6656 e.preventDefault(); 6657 } else { 6658 point = e; 6659 e.preventDefault(); 6660 } 6661 setProgress(point, true); 6662 6663 if(tooltip)tooltip.style.display = 'none'; 6664 6665 } 6666 6667 } 6668 6669 function setProgress(point, update, final) { 6670 6671 if(circleSeekbar){ 6672 var v = _HAPCirclePlayer.setProgress(point); 6673 }else{ 6674 if(final){ 6675 var v = point; 6676 }else{ 6677 6678 if(settings.useWaveSeekbar){ 6679 var rect = seekbarWave.getBoundingClientRect(); 6680 var seekPercent = point.pageX - rect.left; 6681 }else{ 6682 var rect = progressBg.getBoundingClientRect(); 6683 var seekPercent = point.pageX - rect.left; 6684 } 6685 6686 if(seekPercent < 0) seekPercent = 0; 6687 else if(seekPercent > seekBarSize) seekPercent = seekBarSize; 6688 var v = Math.max(0, Math.min(1, seekPercent / seekBarSize)); 6689 } 6690 } 6691 6692 if(update){ 6693 6694 var t,d; 6695 6696 if(mediaType == 'youtube'){ 6697 6698 if(youtubePlayer && youtubeReady)youtubePlayer.seekTo(v * youtubePlayer.getDuration()); 6699 6700 }else{ 6701 6702 if(activeAudio && !isNaN(activeAudio.duration)){ 6703 6704 d = activeAudio.duration; 6705 t = v * d; 6706 if(t > d - 2)t = d - 2;//prevent seeking to end 6707 6708 try{ 6709 activeAudio.currentTime = t; 6710 }catch(er){console.log(er)} 6711 6712 } 6713 } 6714 6715 if(progressLevel)if(!mediaStarted)progressLevel.style.width = v * seekBarSize + 'px'; 6716 6717 if(seekingFixed){ 6718 _HAPStickyPlayer.setProgressData(v, null) 6719 } 6720 6721 }else{ 6722 6723 if(progressLevel)progressLevel.style.width = (v * seekBarSize) + 'px';//redraw seekbar while user seeking, we dont want to update seek position until seeking ends for performance 6724 6725 if(seekingFixed){//we are seeking fixed 6726 6727 //lastActiveTrackInstance.progressLevel.style.width = (v*100)+'%'; 6728 6729 }else{//we are seeking song list 6730 6731 if(settings.useStickyPlayer && window['hap_fixed_active_player'] == settings.instanceName){ 6732 if(mediaStarted){ 6733 _HAPStickyPlayer.setProgressData(v, true) 6734 } 6735 } 6736 6737 } 6738 } 6739 6740 } 6741 6742 if(settings.useWaveSeekbar){ 6743 6744 var w = seekbar.offsetWidth, h = seekbar.offsetHeight 6745 6746 //bg 6747 var canvas = document.createElement('canvas'); 6748 seekbarWaveCanvasBg = canvas; 6749 canvas.width = w; 6750 canvas.height = h; 6751 canvas.classList.add("hap-canvas-seekbar-bg"); 6752 seekbarWaveCtx = canvas.getContext('2d'); 6753 seekbarWaveCtx.fillStyle = settings.waveBgColor;
6754 seekbarWave.prepend(canvas) 6755 6756 //progress 6757 var canvas2 = document.createElement('canvas'); 6758 seekbarWaveCanvasProgress = canvas2 6759 canvas2.width = w; 6760 canvas2.height = h; 6761 canvas2.classList.add("hap-canvas-seekbar-progress"); 6762 seekbarWaveCtx2 = canvas2.getContext('2d'); 6763 seekbarWaveCtx2.fillStyle = settings.waveProgressColor; 6764 seekbarWaveProgress.prepend(canvas2) 6765 6766 } 6767 6768 function clearSeekbar(){ 6769 6770 if(seekbarWaveCtx){ 6771 seekbarWaveCtx.clearRect(0, 0, seekbarWaveCanvasBg.width, seekbarWaveCanvasBg.height); 6772 seekbarWaveCtx.beginPath(); 6773 } 6774 6775 if(seekbarWaveCtx2){ 6776 seekbarWaveCtx2.clearRect(0, 0, seekbarWaveCanvasProgress.width, seekbarWaveCanvasProgress.height); 6777 seekbarWaveCtx2.beginPath(); 6778 } 6779 6780 if(waveformLoader)waveformLoader.classList.remove('hap-waveform-loader-hidden') 6781 6782 if(settings.useStickyPlayer){ 6783 _HAPStickyPlayer.clearSeekbar() 6784 } 6785 6786 } 6787 6788 function drawWaveSeekbar(){ 6789 6790 var w = seekbar.offsetWidth, h = seekbar.offsetHeight 6791 6792 seekbarWaveCanvasBg.width = w 6793 seekbarWaveCanvasProgress.width = w 6794 6795 seekbarWaveCanvasBg.height = h 6796 seekbarWaveCanvasProgress.height = h 6797 6798 waveOptions.width = w; 6799 waveOptions.height = h; 6800 6801 seekbarWaveCtx.fillStyle = settings.waveBgColor; 6802 seekbarWaveCtx2.fillStyle = settings.waveProgressColor; 6803 6804 peakData = currMediaData.peaks; 6805 6806 if(waveOptions.barWidth > 0){ 6807 HAPUtils.drawBars(seekbarWaveCtx, seekbarWaveCtx2, waveOptions, peakData.split(','), 0, w) 6808 }else{ 6809 HAPUtils.drawWave(seekbarWaveCtx, seekbarWaveCtx2, waveOptions, peakData.split(','), 0, w) 6810 } 6811 } 6812 6813 6814 6815 6816 6817 6818 //############################################// 6819 /* seekbar tooltip */ 6820 //############################################// 6821 6822 if(seekbar && tooltip){ 6823 6824 if(!isMobile){ 6825 6826 seekbar.addEventListener('mouseover', function mouseOverHandlerSeek(){ 6827 if(seekBarDown)return; 6828 if(_HAPAdManager && _HAPAdManager.isAdOn()) return false; 6829 if(isIma && isImaOn) return false; 6830 6831 if(class_list.indexOf('hap-fixed') > -1 || class_list.indexOf('hap-fixed2') > -1)if(!settings.playerOpened)return false; 6832 6833 seekbar.addEventListener(events.moveEvent, mouseMoveHandlerSeekTooltip) 6834 seekbar.addEventListener('mouseout', mouseOutHandlerSeek); 6835 6836 _doc.addEventListener('mouseout', mouseOutHandlerSeek); 6837 }); 6838 6839 } 6840 6841 } 6842 6843 function mouseOutHandlerSeek() { 6844 seekbar.removeEventListener(events.moveEvent, mouseMoveHandlerSeekTooltip) 6845 seekbar.removeEventListener('mouseout', mouseOutHandlerSeek); 6846 6847 _doc.removeEventListener('mouseout', mouseOutHandlerSeek); 6848 tooltip.style.display = 'none'; 6849 } 6850 6851 function mouseMoveHandlerSeekTooltip(e){ 6852 6853 tooltip.style.display = 'block'; 6854 6855 var main = wrapper.getBoundingClientRect(), 6856 element = seekbar.getBoundingClientRect(); 6857 6858 if(circleSeekbar){ 6859 6860 var newPercent = _HAPCirclePlayer.trackTooltip(e); 6861 6862 var t = parseInt(element.top - main.top - tooltip.offsetHeight - 20), 6863 l = parseInt(element.left - main.left - tooltip.offsetWidth / 2 + seekbar.offsetWidth / 2); 6864 6865 //keep within component 6866 if(l + tooltip.offsetWidth > main.width)l = wrapper.offsetWidth - tooltip.offsetWidth; 6867 else if(l < 0) l = 0; 6868 6869 if(t + main.top < 0)t = parseInt(element.top - main.top + tooltip.offsetHeight + 20);//position below 6870 //if(t < 0) t = 0; 6871 6872 tooltip.style.left = l+'px' 6873 tooltip.style.top = t+'px' 6874 6875 }else{ 6876 6877 if(settings.useWaveSeekbar){ 6878 var offsets = seekbarWave.getBoundingClientRect(); 6879 }else{ 6880 var offsets = progressBg.getBoundingClientRect(); 6881 } 6882 6883 var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; 6884 6885 var s = e.pageX - offsets.left - scrollLeft; 6886 6887 if(!HAPUtils.isNumber(s))return false; 6888 if(s < 0) s = 0; 6889 else if(s > seekBarSize) s = seekBarSize; 6890 var newPercent = Math.max(0, Math.min(1, s / seekBarSize)); 6891 6892 var l = parseInt(e.pageX - scrollLeft - main.left - (tooltip.offsetWidth / 2),10), 6893 t = parseInt(element.top - main.top - tooltip.offsetHeight,10) - 10; 6894 6895 //restrain 6896 if(l < element.left - main.left)l = element.left - main.left; 6897 else if(l > element.left - main.left + seekbar.clientWidth - tooltip.offsetWidth) l = element.left - main.left + seekbar.clientWidth - tooltip.offsetWidth; 6898 6899 if(t + main.top < 0)t = parseInt(element.top - main.top + tooltip.offsetHeight + 15);//position below 6900 //if(t < 0) t = 0; 6901 6902 tooltip.style.left = l+'px' 6903 tooltip.style.top = t+'px' 6904 6905 } 6906 6907 if(!HAPUtils.isNumber(newPercent))return false;
6908 6909 if(mediaType == 'youtube'){ 6910 6911 if(youtubePlayer && youtubeReady)var d = youtubePlayer.getDuration(), t = newPercent * d; 6912 6913 }else{ 6914 6915 if(activeAudio){ 6916 var d = activeAudio.duration, t = newPercent * d; 6917 } 6918 } 6919 6920 if(!HAPUtils.isNumber(t) || !HAPUtils.isNumber(d)){ 6921 tooltip.style.display = 'none'; 6922 return; 6923 } 6924 6925 tooltip.innerHTML = HAPUtils.formatTime(t)+' / '+HAPUtils.formatTime(d); 6926 6927 } 6928 6929 //############################################// 6930 /* volume */ 6931 //############################################// 6932 6933 if(wrapper.querySelector('.hap-volume-seekbar') || wrapper.querySelector('.hap-volume-toggle')){ 6934 6935 _volumeSlider = new HAPVolumeSlider({volume:settings.volume, container:wrapper, tooltip: tooltip, parent: self}) 6936 6937 _volumeSlider.addEventListener('HAPVolumeSlider.VOLUME_CHANGE', function(data){ 6938 settings.volume = data.volume; 6939 self.setVolume(settings.volume) 6940 }) 6941 6942 _volumeSlider.addEventListener('HAPVolumeSlider.TOGGLE_MUTE', function(e){ 6943 self.toggleMute() 6944 }) 6945 } 6946 6947 6948 6949 6950 6951 6952 //############################################// 6953 /* range (a-b loop) */ 6954 //############################################// 6955 6956 var range_handle_a = wrapper.querySelector('.hap-range-handle-a'), 6957 range_handle_b = wrapper.querySelector('.hap-range-handle-b'), 6958 range_handle_a_width, 6959 range_handle_b_width, 6960 range_a_time, 6961 range_b_time, 6962 range_a_pos, 6963 range_b_pos, 6964 rangeOn, 6965 useRange, 6966 rangeSet, 6967 rangeBg = wrapper.querySelector('.hap-range-bg'), 6968 rangeSize, 6969 rangeLevel = wrapper.querySelector('.hap-range-level'), 6970 rangeMinTime = wrapper.querySelector('.hap-range-min-time'), 6971 rangeMaxTime = wrapper.querySelector('.hap-range-max-time') 6972 6973 if(range_handle_a && range_handle_b){ 6974 range_handle_a_width = parseInt(range_handle_a.getAttribute('data-width'),10) 6975 range_handle_b_width = parseInt(range_handle_b.getAttribute('data-width'),10) 6976 } 6977 6978 self.toggleRange = function(){//open / close range 6979 if(!mediaType)return; 6980 6981 if(rangeOn){ 6982 6983 rangeHolder.addEventListener('transitionend', function cb(e){ 6984 e.currentTarget.removeEventListener(e.type, cb); 6985 rangeHolder.classList.remove('hap-holder-animate') 6986 6987 self.resetRange() 6988 }) 6989 6990 rangeHolder.classList.remove('hap-holder-shown') 6991 6992 rangeSet = true; 6993 6994 }else{ 6995 6996 rangeHolder.classList.add('hap-holder-animate') 6997 6998 setTimeout(function(){ 6999 rangeHolder.classList.add('hap-holder-shown') 7000 },50) 7001 7002 rangeSize = rangeBg.offsetWidth; 7003 7004 range_a_pos = range_handle_a.offsetLeft; 7005 range_b_pos = range_handle_b.offsetLeft; 7006 7007 range_a_time = getRangeTime(range_a_pos); 7008 range_b_time = getRangeTime(range_b_pos); 7009 7010 rangeSet = false; 7011 7012 } 7013 rangeOn = !rangeOn; 7014 7015 } 7016 7017 this.getRangeOn = function(){ 7018 return rangeOn; 7019 } 7020 7021 function getRangeTime(x){//get media time by seek percent 7022 7023 var v = Math.max(0, Math.min(1, x / rangeSize)), c, d; 7024 7025 if(mediaType == 'youtube'){ 7026 d = youtubePlayer.getDuration(); 7027 }else{ 7028 d = activeAudio.duration; 7029 } 7030 c = v * d; 7031 return c; 7032 } 7033 7034 //range api 7035 7036 self.resetRange = function(){//reset range to default position 7037 rangeOn = false; 7038 rangeSet = true; 7039 range_handle_a.style.left = 0; 7040 range_handle_b.style.left = rangeSize + 'px'; 7041 rangeMinTime.innerHTML = '00:00'; 7042 rangeMaxTime.innerHTML = '00:00'; 7043 7044 range_a_pos = range_handle_a.offsetLeft; 7045 range_b_pos = range_handle_b.offsetLeft; 7046 7047 rangeLevel.style.left = 0 + 'px' 7048 rangeLevel.style.right = 0 + 'px' 7049 } 7050 7051 self.setRange = function(a,b){//set range 7052 7053 var d = self.getDuration(); 7054 7055 if(typeof d === 'undefined')return false; 7056 7057 if(a < 0)a = 0; 7058 if(b > d)b = d; 7059 7060 range_a_time = a; 7061 range_b_time = b; 7062 7063 rangeSet = false; 7064 7065 range_handle_a.style.left = (range_a_time / d) * rangeSize + 'px'; 7066 range_handle_b.style.left = (range_b_time / d) * rangeSize + 'px'; 7067 7068 rangeMinTime.innerHTML = HAPUtils.formatTime(a); 7069 rangeMaxTime.innerHTML = HAPUtils.formatTime(b); 7070 7071 var l = parseInt(range_handle_a.style.left,10), 7072 r = parseInt(range_handle_b.style.left,10) 7073 7074 rangeLevel.style.left = l + 'px'; 7075 rangeLevel.style.right = rangeSize - r + 'px'; 7076 7077 if(!rangeOn)self.toggleRange(); 7078 7079 } 7080 7081 self.resizeRange = function(){ 7082 7083 var d = self.getDuration(); 7084 7085 if(typeof d === 'undefined')return false;
7086 if(typeof range_a_time === 'undefined')return false; 7087 if(typeof range_b_time === 'undefined')return false; 7088 7089 rangeSize = rangeBg.offsetWidth; 7090 7091 range_handle_a.style.left = (range_a_time / d) * rangeSize + 'px'; 7092 range_handle_b.style.left = (range_b_time / d) * rangeSize + 'px'; 7093 7094 rangeMinTime.innerHTML = HAPUtils.formatTime(range_a_time); 7095 rangeMaxTime.innerHTML = HAPUtils.formatTime(range_b_time); 7096 7097 var l = parseInt(range_handle_a.style.left,10), 7098 r = parseInt(range_handle_b.style.left,10) 7099 7100 rangeLevel.style.left = l + 'px' 7101 rangeLevel.style.right = rangeSize - r + 'px' 7102 7103 } 7104 7105 self.getRange = function(){//get range times 7106 if(typeof range_a_time !== 'undefined' && typeof range_b_time !== 'undefined')return [range_a_time, range_b_time]; 7107 else return null; 7108 } 7109 7110 if(range_handle_a){ 7111 7112 useRange = true; 7113 7114 _HAPRangeSlider = new HAPRangeSlider({ 7115 settings:settings, 7116 range_handle_a:range_handle_a, 7117 range_handle_b:range_handle_b, 7118 }); 7119 7120 _HAPRangeSlider.addEventListener('HAPRangeSlider.RANGE_CHANGE', function(data){ 7121 7122 var rect = rangeBg.getBoundingClientRect() 7123 7124 var pos = data.point.pageX - rect.left, m, elem = data.elem; 7125 if(pos < 0)pos = 0; 7126 else if(pos > rangeSize)pos = rangeSize; 7127 7128 if(elem.classList.contains('hap-range-handle-a')){ 7129 7130 if(pos > parseInt(range_handle_b.style.left,10) - 3)pos = parseInt(range_handle_b.style.left,10) - 3; 7131 range_a_pos = pos; 7132 range_a_time = getRangeTime(range_a_pos); 7133 7134 rangeMinTime.innerHTML = HAPUtils.formatTime(range_a_time); 7135 7136 }else{ 7137 7138 if(pos < parseInt(range_handle_a.style.left,10) + 4)pos = parseInt(range_handle_a.style.left,10) + 4; 7139 range_b_pos = pos; 7140 range_b_time = getRangeTime(range_b_pos); 7141 7142 rangeMaxTime.innerHTML = HAPUtils.formatTime(range_b_time); 7143 7144 } 7145 7146 rangeLevel.style.left = range_a_pos + 'px' 7147 rangeLevel.style.right = rangeSize - range_b_pos + 'px' 7148 7149 elem.style.left = pos + 'px'; 7150 7151 }); 7152 7153 } 7154 7155 7156 //############################################// 7157 /* playback rate */ 7158 //############################################// 7159 7160 var playbackRateSeekbar = wrapper.querySelector('.hap-playback-rate-seekbar') 7161 7162 if(wrapper.querySelector('.hap-playback-rate-min'))wrapper.querySelector('.hap-playback-rate-min').innerHTML = settings.playbackRateMin 7163 if(wrapper.querySelector('.hap-playback-rate-max'))wrapper.querySelector('.hap-playback-rate-max').innerHTML = settings.playbackRateMax 7164 7165 if(playbackRateSeekbar){ 7166 7167 _HAPPlaybackRateSlider = new HAPPlaybackRateSlider({ 7168 settings:settings, 7169 wrapper: wrapper, 7170 e_holder: playbackRateHolder, 7171 seekbarHolder: wrapper.querySelector('.hap-playback-rate-wrap'), 7172 seekbar:playbackRateSeekbar, 7173 sliderBg:wrapper.querySelector('.hap-playback-rate-bg'), 7174 sliderLevel:wrapper.querySelector('.hap-playback-rate-level'), 7175 isVertical:playbackRateSeekbar.classList.contains('hap-vertical'), 7176 tooltip: tooltip, 7177 }); 7178 7179 _HAPPlaybackRateSlider.addEventListener('HAPPlaybackRateSlider.RANGE_CHANGE', function(data){ 7180 self.setPlaybackRate(data.value); 7181 }); 7182 7183 } 7184 7185 7186 //############################################// 7187 /* context menu */ 7188 //############################################// 7189 7190 if(settings.disableRightClickOverPlayer){ 7191 7192 wrapper.addEventListener("contextmenu", function(){ 7193 return false; 7194 }); 7195 7196 } 7197 7198 //############################################// 7199 /* controls */ 7200 //############################################// 7201 7202 if(settings.useKeyboardNavigationForPlayback && settings.keyboardControls.length){ 7203 7204 if(settings.useGlobalKeyboardControls){ 7205 7206 _doc.addEventListener('keydown',function(e) { 7207 return handleKeyboard(e) 7208 }); 7209 7210 }else{ 7211 7212 wrapper.addEventListener('mouseenter', function(){ 7213 _doc.addEventListener('keydown', handleKeyboard); 7214 }) 7215 wrapper.addEventListener('mouseleave', function(){ 7216 _doc.removeEventListener('keydown', handleKeyboard); 7217 }) 7218 } 7219 7220 } 7221 7222 function handleKeyboard(e){ 7223 7224 if(!componentInited)return false; 7225 //if(playlistSelectorOpened)return false; 7226 7227 var _keycode = e.keyCode, target = e.target; 7228 7229 if(target.classList.contains('hap-search-filter')) return true; 7230 if(target.classList.contains('hap-input-field')) return true; 7231 7232 if(settings.modifierKey){ 7233 7234 var i, len = settings.keyboardControls.length, obj 7235 for(i = 0; i < len; i++){ 7236 obj = settings.keyboardControls[i] 7237 7238 if(e[settings.modifierKey] && _keycode == obj.keycode){ 7239 7240 if (typeof self[obj.action] === "function") { 7241 self[obj.action](); 7242 } 7243 else{ 7244 return true; 7245 } 7246 7247 break; 7248 7249 } 7250 } 7251 7252 }else{ 7253 7254 var i, len = settings.keyboardControls.length, obj 7255 for(i = 0; i < len; i++){ 7256 obj = settings.keyboardControls[i] 7257 7258 if(_keycode == obj.keycode){ 7259 7260 if (typeof self[obj.action] === "function") { 7261 self[obj.action](); 7262 } 7263 else{ 7264 return true; 7265 } 7266 7267 break; 7268 } 7269 } 7270 7271 } 7272 7273 return false;
7274 7275 } 7276 7277 function handleKeyboard2(e){ 7278 7279 if(!componentInited) return false; 7280 7281 var _keycode = e.keyCode, target = e.target; 7282 7283 if(target.classList.contains('hap-search-filter')) return true; 7284 if(target.classList.contains('hap-input-field')) return true; 7285 7286 if(settings.modifierKey){ 7287 7288 var i, len = settings.keyboardControls.length, obj 7289 for(i = 0; i < len; i++){ 7290 obj = settings.keyboardControls[i] 7291 7292 if(e[settings.modifierKey] && _keycode == obj.keycode){ 7293 7294 if(obj.action == 'seekBackward') {//left arrow 7295 self.seekBackward(settings.seekTime); 7296 } 7297 else if(obj.action == 'seekForward') {//right arrow 7298 self.seekForward(settings.seekTime); 7299 } 7300 else if(obj.action == 'togglePlayback') {//space 7301 7302 self.togglePlayback(); 7303 7304 }else if (obj.action == 'volumeUp'){//up arrow 7305 7306 settings.volume += .1; 7307 if(settings.volume > 1) settings.volume = 1; 7308 self.setVolume(settings.volume) 7309 7310 }else if (obj.action == 'volumeDown'){//down arrow 7311 7312 settings.volume -= .1; 7313 if(settings.volume < 0) settings.volume = 0; 7314 self.setVolume(settings.volume) 7315 7316 } 7317 else if(obj.action == 'toggleMute') {//m 7318 self.toggleMute(); 7319 } 7320 else if(obj.action == 'nextMedia') {//page up 7321 self.nextMedia(); 7322 } 7323 else if(obj.action == 'previousMedia') {//page down 7324 self.previousMedia(); 7325 } 7326 else if(obj.action == 'rewind') {//r 7327 self.seek(0); 7328 } 7329 7330 break; 7331 } 7332 } 7333 7334 }else{ 7335 7336 var i, len = settings.keyboardControls.length, obj 7337 for(i = 0; i < len; i++){ 7338 obj = settings.keyboardControls[i] 7339 if(_keycode == obj.keycode){ 7340 7341 if(obj.action == 'seekBackward') {//left arrow 7342 self.seekBackward(settings.seekTime); 7343 } 7344 else if(obj.action == 'seekForward') {//right arrow 7345 self.seekForward(settings.seekTime); 7346 } 7347 else if(obj.action == 'togglePlayback') {//space 7348 7349 self.togglePlayback(); 7350 7351 }else if (obj.action == 'volumeUp'){//up arrow 7352 7353 settings.volume += .1; 7354 if(settings.volume > 1) settings.volume = 1; 7355 self.setVolume(settings.volume) 7356 7357 }else if (obj.action == 'volumeDown'){//down arrow 7358 7359 settings.volume -= .1; 7360 if(settings.volume < 0) settings.volume = 0; 7361 self.setVolume(settings.volume) 7362 7363 } 7364 else if(obj.action == 'toggleMute') {//m 7365 self.toggleMute(); 7366 } 7367 else if(obj.action == 'nextMedia') {//page up 7368 self.nextMedia(); 7369 } 7370 else if(obj.action == 'previousMedia') {//page down 7371 self.previousMedia(); 7372 } 7373 else if(obj.action == 'rewind') {//r 7374 self.seek(0); 7375 } 7376 else{ 7377 return true; 7378 } 7379 7380 break; 7381 } 7382 } 7383 7384 } 7385 7386 e.preventDefault() 7387 7388 } 7389 7390 var buttons = [ 7391 wrapper.querySelector('.hap-next-toggle'), 7392 wrapper.querySelector('.hap-prev-toggle'), 7393 wrapper.querySelector('.hap-skip-forward'), 7394 wrapper.querySelector('.hap-skip-backward'), 7395 wrapper.querySelector('.hap-playlist-toggle'), 7396 wrapper.querySelector('.hap-playlist-close'), 7397 shareToggle, 7398 embedToggle, 7399 wrapper.querySelector('.hap-embed-close'), 7400 wrapper.querySelector('.hap-share-close'), 7401 wrapper.querySelector('.hap-share-copy'), 7402 wrapper.querySelector('.hap-playback-rate-close'), 7403 wrapper.querySelector('.hap-range-close'), 7404 wrapper.querySelector('.hap-lyrics-close'), 7405 wrapper.querySelector('.hap-video-close'), 7406 wrapper.querySelector('.hap-pwd-close'), 7407 wrapper.querySelector('.hap-pwd-confirm'), 7408 wrapper.querySelector('.hap-playlist-selector-toggle'), 7409 wrapper.querySelector('.hap-playlist-selector-close'), 7410 playbackRateToggle, 7411 playbackRateToggleNum, 7412 rangeToggle, 7413 popupToggle, 7414 sortAlpha, 7415 playbackToggle, 7416 loopToggle, 7417 randomToggle, 7418 lyricsToggle, 7419 videoToggle 7420 ]; 7421 7422 var shareList = wrapper.querySelectorAll('.hap-share-item'), 7423 shares = [...shareList]; 7424 7425 var buttonArr = buttons.concat(shares); 7426 7427 var redirectLogin = wrapper.querySelectorAll('.hap-redirect-login-cancel'), 7428 red_log = [...redirectLogin]; 7429 7430 if(red_log.length){ 7431 var t = 0; 7432 for(t; t < red_log.length; t++){ 7433 buttonArr.push(red_log[t]) 7434 } 7435 } 7436 7437 var btn,len = buttonArr.length,i; 7438 for(i=0;i<len;i++){ 7439 btn = buttonArr[i] 7440 if(btn){
7441 btn.style.cursor = 'pointer'; 7442 btn.addEventListener('click', clickControls); 7443 if(!isMobile){ 7444 btn.addEventListener('mouseenter', overControls) 7445 btn.addEventListener('mouseleave', outControls); 7446 } 7447 } 7448 7449 } 7450 7451 function overControls(e){ 7452 if(!tooltip)return; 7453 7454 if(e.target.getAttribute('data-tooltip'))showTooltip(e.target) 7455 else if(e.target.classList.contains('hap-random-toggle')){ 7456 showTooltip(randomToggle.querySelector('.hap-btn[style*="display: block"]')); 7457 } 7458 else if(e.target.classList.contains('hap-loop-toggle')){ 7459 showTooltip(loopToggle.querySelector('.hap-btn[style*="display: block"]')); 7460 } 7461 else if(e.target.classList.contains('hap-sort-alpha')){ 7462 showTooltip(sortAlpha.querySelector('.hap-btn[style*="display: block"]')); 7463 } 7464 7465 } 7466 function outControls(e){ 7467 if(!tooltip)return; 7468 tooltip.style.display = 'none'; 7469 } 7470 7471 //############################################// 7472 /* variation */ 7473 //############################################// 7474 7475 onHandler(wrapper, 'click', '.hap-audio-variation', (e) => handleVariationClick(e)) 7476 7477 function handleVariationClick(e){ 7478 7479 cleanMedia() 7480 7481 activeVariation = e.target.closest('.hap-audio-variation') 7482 7483 activeVariation.classList.add('hap-active-variation') 7484 7485 var url = activeVariation.getAttribute('data-path') 7486 7487 currMediaData = {type:'audio', path: url}; 7488 mediaType = 'audio'; 7489 mediaPath = url; 7490 7491 initAudio(); 7492 7493 } 7494 7495 7496 7497 if(playlistContent){ 7498 playlistContent.addEventListener('click', function(e){ 7499 7500 settings.playlistItemClickSelectorArr.forEach(function(entry) { 7501 if(e.target.classList.contains(entry)){ 7502 clickPlaylistItem(e.target.closest('.hap-playlist-item')); 7503 } 7504 }); 7505 }) 7506 } 7507 7508 function clickPlaylistItem(target){ 7509 7510 if(!componentInited)return false; 7511 if(settings.disableSongSkip) return false; 7512 if(_HAPAdManager && _HAPAdManager.isAdOn()) return false; 7513 if(isIma && isImaOn) return false; 7514 7515 if(crossFadeOn)cancelCrossFadeAdvance(); 7516 7517 if(isIOS && currMediaData && (currMediaData.adMid || currMediaData.adEnd) && !iosAdMidFixStart && _HAPAdManager){ 7518 iosAdMidFixStart = true; 7519 _HAPAdManager.forceAdMidAudio();//ads 7520 } 7521 7522 if(target.classList.contains('hap-playlist-item-disabled')){ 7523 7524 if(hasVariation){ 7525 7526 //if variations play and we click playlist item 7527 7528 }else{ 7529 7530 if(settings.togglePlaybackOnPlaylistItem){ 7531 if(mediaStarted){ 7532 self.togglePlayback() 7533 return false; 7534 } 7535 } 7536 else{//dont reload whole audio process 7537 7538 //check password 7539 if(currMediaData.pwd){ 7540 pwdHolderToggle() 7541 return false; 7542 } 7543 7544 self.seek(0) 7545 if(!mediaPlaying)self.playMedia() 7546 return false; 7547 } 7548 } 7549 } 7550 7551 playlistClick = true; 7552 autoPlay = true; 7553 settings.autoPlay = true; 7554 7555 //if(typeof mediaCounter != undefined)beforeSongAdvanceAction(); 7556 7557 //############################################// 7558 /* accordion */ 7559 //############################################// 7560 7561 if(accordionMode){ 7562 //check if we are still in same accordion folder. If not, switch data to new playlist 7563 var aid = target.closest('.hap-accordion-item').getAttribute('data-id'); 7564 if(aid != accordioPlaylistId){ 7565 7566 accordioPlaylistId = aid; 7567 7568 playlistDataArr = playlistDataAccordion[accordioPlaylistId].data; 7569 7570 playlistLength = playlistDataArr.length; 7571 var i; 7572 for(i = 0;i < playlistLength; i++){ 7573 playlistDataArr[i].id = i; 7574 } 7575 7576 _HAPPlaylistManager.setPlaylistItems(playlistLength);//we treat each accordion as new playlist 7577 7578 } 7579 7580 } 7581 7582 //############################################// 7583 /* accordion */ 7584 //############################################// 7585 7586 var id = target.getAttribute('data-id'); 7587 _HAPPlaylistManager.processPlaylistRequest(id); 7588 7589 7590 7591 //preset mods 7592 if(class_list.indexOf('hap-art-narrow-light') > -1){ 7593 self.togglePlaylist(); 7594 } 7595 7596 self.fireEvent('clickPlaylistItem', [{instance:self, instanceName:settings.instanceName}]); 7597 } 7598 7599 function pwdHolderToggle(hide){ 7600 7601 if(!pwdHolder){ 7602 console.log('this skin does not contain password screen!') 7603 return false; 7604 } 7605 7606 if(hide){ 7607 7608 pwdHolder.addEventListener('transitionend', function cb(e){ 7609 e.currentTarget.removeEventListener(e.type, cb); 7610 pwdHolder.classList.remove('hap-holder-animate') 7611 }) 7612 7613 pwdHolder.classList.remove('hap-holder-shown') 7614 7615 pwdField.value = ''; 7616 7617 }else{ 7618 7619 pwdHolder.classList.add('hap-holder-animate') 7620 7621 setTimeout(function(){ 7622 pwdHolder.classList.add('hap-holder-shown') 7623 },50) 7624 7625 } 7626 7627 } 7628 7629 function overPlaylistItem(e){ 7630 7631 e.preventDefault(); 7632 if(!componentInited) return false;
7633 7634 e.currentTarget.closest('.hap-playlist-item').classList.add('hap-playlist-item-selected'); 7635 7636 self.fireEvent('overPlaylistItem', [{instance:self, instanceName:settings.instanceName}]); 7637 } 7638 7639 function outPlaylistItem(e){ 7640 e.preventDefault(); 7641 if(!componentInited) return false; 7642 7643 var item = e.currentTarget.closest('.hap-playlist-item'); 7644 7645 if(!item.classList.contains('hap-playlist-item-disabled'))item.classList.remove('hap-playlist-item-selected'); 7646 7647 self.fireEvent('outPlaylistItem', [{instance:self, instanceName:settings.instanceName}]); 7648 } 7649 7650 function clickControls(e){ 7651 if(!componentInited) return false; 7652 7653 var currentTarget = e.currentTarget; 7654 7655 if(currentTarget.classList.contains('hap-playlist-toggle') || currentTarget.classList.contains('hap-playlist-close')){ 7656 7657 self.togglePlaylist(); 7658 7659 }else if(currentTarget.classList.contains('hap-skip-backward')){ 7660 7661 self.seekBackward(settings.seekTime); 7662 7663 }else if(currentTarget.classList.contains('hap-skip-forward')){ 7664 7665 self.seekForward(settings.seekTime); 7666 7667 }else if(currentTarget.classList.contains('hap-prev-toggle')){ 7668 7669 if(isIOS && currMediaData && (currMediaData.adMid || currMediaData.adEnd) && !iosAdMidFixStart && _HAPAdManager){ 7670 iosAdMidFixStart = true; 7671 _HAPAdManager.forceAdMidAudio();//ads 7672 } 7673 7674 if(_HAPAdManager && _HAPAdManager.isAdOn()) return false; 7675 if(isIma && isImaOn) return false; 7676 7677 self.previousMedia(); 7678 7679 }else if(currentTarget.classList.contains('hap-playback-toggle')){ 7680 7681 self.togglePlayback(); 7682 7683 }else if(currentTarget.classList.contains('hap-next-toggle')){ 7684 7685 if(isIOS && currMediaData && (currMediaData.adMid || currMediaData.adEnd) && !iosAdMidFixStart && _HAPAdManager){ 7686 iosAdMidFixStart = true; 7687 _HAPAdManager.forceAdMidAudio();//ads 7688 } 7689 7690 if(_HAPAdManager && _HAPAdManager.isAdOn()) return false; 7691 if(isIma && isImaOn) return false; 7692 7693 self.nextMedia(); 7694 7695 }else if(currentTarget.classList.contains('hap-lyrics-toggle') || currentTarget.classList.contains('hap-lyrics-close')){ 7696 7697 self.toggleLyrics(); 7698 7699 }else if(currentTarget.classList.contains('hap-video-toggle') || currentTarget.classList.contains('hap-video-close')){ 7700 7701 self.toggleVideo(); 7702 7703 }else if(currentTarget.classList.contains('hap-loop-toggle')){ 7704 7705 if(loopToggle){ 7706 loopToggle.querySelectorAll('.hap-btn').forEach(function(el){ 7707 el.style.display = 'none'; 7708 }) 7709 } 7710 7711 loopStateCounter++; 7712 if(loopStateCounter > loopStateArr.length - 1)loopStateCounter = 0; 7713 settings.loopState = loopStateArr[loopStateCounter]; 7714 7715 if(loopToggle)loopToggle.querySelector('.hap-btn-loop-'+settings.loopState).style.display = 'block'; 7716 7717 _HAPPlaylistManager.setLooping(settings.loopState); 7718 7719 if(tooltip)showTooltip(loopToggle.querySelector('.hap-btn[style*="display: block"]')); 7720 7721 }else if(currentTarget.classList.contains('hap-random-toggle')){ 7722 7723 self.toggleRandom() 7724 7725 if(tooltip)showTooltip(randomToggle.querySelector('.hap-btn[style*="display: block"]')); 7726 7727 }else if(currentTarget.classList.contains('hap-sort-alpha')){ 7728 7729 if(HAPUtils.isEmpty(sortOrder))sortOrder = 'title-asc'; 7730 else if(sortOrder == 'title-asc')sortOrder = 'title-desc'; 7731 else if(sortOrder == 'title-desc')sortOrder = 'title-asc'; 7732 self.sort(sortOrder); 7733 7734 if(tooltip)showTooltip(sortAlpha.querySelector('.hap-btn[style*="display: block"]')); 7735 7736 }else if(currentTarget.classList.contains('hap-popup-toggle')){ 7737 7738 if(settings.isPopup) return false; 7739 hapOpenPopup(settings, self); 7740 7741 }else if(currentTarget.classList.contains('hap-playback-rate-toggle') || currentTarget.classList.contains('hap-playback-rate-close')){ 7742 7743 if(currentTarget.classList.contains('hap-playback-rate-toggle')){ 7744 checkOpenedWindows('playback_rate') 7745 } 7746 7747 if(playbackRateHolder.classList.contains('hap-holder-shown')){ 7748 7749 playbackRateHolder.addEventListener('transitionend', function cb(e){ 7750 e.currentTarget.removeEventListener(e.type, cb); 7751 playbackRateHolder.classList.remove('hap-holder-animate') 7752 }) 7753 7754 playbackRateHolder.classList.remove('hap-holder-shown') 7755 7756 }else{ 7757 7758 playbackRateHolder.classList.add('hap-holder-animate') 7759 7760 setTimeout(function(){ 7761 playbackRateHolder.classList.add('hap-holder-shown') 7762 },50) 7763 7764 } 7765 7766 }else if(currentTarget.classList.contains('hap-playback-rate-toggle-num')){ 7767 7768 var elem = e.currentTarget.querySelector('.hap-playback-rate-toggle-inner') 7769 7770 var current = elem.innerHTML.toUpperCase() 7771 current = Number(current.substr(0, current.indexOf('X'))) 7772 7773 var value = settings.playbackRateArr.indexOf(current) 7774 7775 //cycle rates 7776 value++; 7777 if(value > settings.playbackRateArr.length - 1){ 7778 value = settings.playbackRateArr[0]; 7779 }else{ 7780 value = settings.playbackRateArr[value]; 7781 } 7782 7783 elem.innerHTML = value + 'X';//update 7784 7785 self.setPlaybackRate(value) 7786 7787 }else if(currentTarget.classList.contains('hap-range-toggle') || currentTarget.classList.contains('hap-range-close')){ 7788 7789 if(currentTarget.classList.contains('hap-range-toggle')){ 7790 checkOpenedWindows('range') 7791 } 7792 7793 self.toggleRange(); 7794 7795 }else if(currentTarget.classList.contains('hap-share-toggle') || currentTarget.classList.contains('hap-share-close')){ 7796 7797 if(currentTarget.classList.contains('hap-share-toggle')){ 7798 checkOpenedWindows('share') 7799 } 7800 7801 if(shareHolder.classList.contains('hap-holder-shown')){ 7802 7803 shareHolder.addEventListener('transitionend', function cb(e){ 7804 e.currentTarget.removeEventListener(e.type, cb); 7805 shareHolder.classList.remove('hap-holder-animate') 7806 7807 if(shareHolder.querySelector('.hap-embed-field-wrap')){ 7808 shareHolder.querySelector('.hap-embed-field-wrap').classList.remove('hap-embed-field-wrap-selected') 7809 } 7810 7811 }) 7812 7813 shareHolder.classList.remove('hap-holder-shown') 7814 }else{ 7815 7816 //link 7817 if(shareHolder.querySelector('.hap-share-link')){ 7818 var url = self.getCurrentMediaUrl(); 7819 shareHolder.querySelector('.hap-share-link').innerHTML = url; 7820 } 7821 7822 shareHolder.classList.add('hap-holder-animate') 7823 7824 setTimeout(function(){ 7825 shareHolder.classList.add('hap-holder-shown') 7826 },50) 7827 7828 } 7829 7830 }else if(currentTarget.classList.contains('hap-share-copy')){ 7831 7832 var btn = e.target, 7833 field = btn.closest('.hap-embed-box').querySelector('.hap-embed-field-wrap') 7834 field.classList.add('hap-embed-field-wrap-selected') 7835 7836 var data = field.textContent.trim() 7837 7838 var dummy = document.createElement("input"); 7839 dummy.setAttribute("id", "hap-copy-url"); 7840 document.body.appendChild(dummy); 7841 document.getElementById("hap-copy-url").value = data; 7842 dummy.select(); 7843 try{ 7844 document.execCommand("copy"); 7845 }catch(er){} 7846 document.body.removeChild(dummy); 7847 7848 }else if(currentTarget.classList.contains('hap-embed-toggle') || currentTarget.classList.contains('hap-embed-close')){ 7849 7850 if(currentTarget.classList.contains('hap-embed-toggle')){ 7851 checkOpenedWindows('embed') 7852 } 7853 7854 if(embedHolder.classList.contains('hap-holder-shown')){ 7855 7856 embedHolder.addEventListener('transitionend', function cb(e){ 7857 e.currentTarget.removeEventListener(e.type, cb); 7858 embedHolder.classList.remove('hap-holder-animate') 7859 }) 7860 7861 embedHolder.classList.remove('hap-holder-shown') 7862 7863 }else{ 7864 7865 setEmbedData(); 7866 7867 embedHolder.classList.add('hap-holder-animate') 7868 7869 setTimeout(function(){ 7870 embedHolder.classList.add('hap-holder-shown') 7871 },50) 7872 7873 } 7874 7875 }else if(currentTarget.classList.contains('hap-pwd-close')){ 7876 7877 pwdHolderToggle(true) 7878 7879 }else if(currentTarget.classList.contains('hap-pwd-confirm')){ 7880 7881 var pwd = pwdField.value; 7882 7883 if(HAPUtils.isEmpty(pwd)){ 7884 alert(pwdErrorMsg); 7885 }else{ 7886 7887 if(typeof md5 === 'undefined'){ 7888 7889 var script = document.createElement('script'); 7890 script.type = 'text/javascript'; 7891 if(!HAPUtils.relativePath(settings.md5_js))var src = HAPUtils.qualifyURL(settings.sourcePath+settings.md5_js); 7892 else var src = settings.md5_js; 7893 script.src = src; 7894 script.onload = script.onreadystatechange = function() { 7895 if(!this.readyState || this.readyState == 'complete'){ 7896 7897 if(pwdAction == 'download'){ 7898 7899 if(md5(pwd) != pwdDownloadData.orig_data.pwd){ 7900 alert(pwdErrorMsg); 7901 }else{ 7902 delete pwdDownloadData.orig_data.pwd; 7903 7904 pwdHolderToggle(true) 7905 7906 doDownloadAction() 7907 7908 } 7909 7910 }else{ 7911 7912 if(md5(pwd) != currMediaData.pwd){ 7913 alert(pwdErrorMsg); 7914 }else{ 7915 delete currMediaData.pwd; 7916 7917 pwdHolderToggle(true) 7918 7919 comingFromPwd = true; 7920 doPostPwdActions() 7921 7922 } 7923 7924 } 7925 7926 } 7927 }; 7928 script.onerror = function(){
7929 console.log("Error loading " + this.src); 7930 } 7931 var tag = document.getElementsByTagName('script')[0]; 7932 tag.parentNode.insertBefore(script, tag); 7933 7934 }else{ 7935 7936 if(pwdAction == 'download'){ 7937 7938 if(md5(pwd) != pwdDownloadData.orig_data.pwd){ 7939 alert(pwdErrorMsg); 7940 }else{ 7941 delete pwdDownloadData.orig_data.pwd; 7942 7943 pwdHolderToggle(true) 7944 7945 doDownloadAction() 7946 7947 } 7948 7949 }else{ 7950 7951 if(md5(pwd) != currMediaData.pwd){ 7952 alert(pwdErrorMsg); 7953 }else{ 7954 delete currMediaData.pwd; 7955 7956 pwdHolderToggle(true) 7957 7958 comingFromPwd = true; 7959 doPostPwdActions() 7960 7961 } 7962 7963 } 7964 7965 } 7966 } 7967 7968 }else if(currentTarget.classList.contains('hap-share-item')){ 7969 7970 if(!mediaType)return false; 7971 7972 if(_HAPShareManager)_HAPShareManager.share(currentTarget.getAttribute('data-type').toLowerCase(), currMediaData, self.getCurrentMediaUrl()); 7973 7974 } 7975 else if(currentTarget.classList.contains('hap-redirect-login-cancel')){ 7976 toggleRedirectLoginScreen(); 7977 } 7978 else if(currentTarget.classList.contains('hap-playlist-selector-toggle')){ 7979 7980 if(!playlistSelectorOpened){ 7981 7982 _body.classList.add('hap-body-overflow') 7983 7984 playlistSelectorContainer.style.display = 'block' 7985 setTimeout(function(){ 7986 playlistSelectorContainer.style.opacity = 1; 7987 },50) 7988 7989 var p=0, z; 7990 for(z=0;z<playlistSelectorLen;z++){ 7991 setTimeout(function(){ 7992 clearTimeout(this); 7993 playlistSelectorArr[p].classList.add('hap-playlist-selector-item-shown'); 7994 p++; 7995 },50 + ( z * 150 )); 7996 } 7997 7998 playlistSelectorOpened = true; 7999 8000 } 8001 8002 } 8003 else if(currentTarget.classList.contains('hap-playlist-selector-close')){ 8004 8005 if(playlistSelectorOpened){ 8006 closePlaylistSelector(); 8007 } 8008 8009 } 8010 } 8011 8012 function checkOpenedWindows(open_type){ 8013 8014 if(open_type != 'range')if(rangeOn)self.toggleRange() 8015 8016 if(open_type != 'playback_rate')if(playbackRateHolder)playbackRateHolder.classList.remove('hap-holder-animate', 'hap-holder-shown') 8017 8018 if(open_type != 'share')if(shareHolder){ 8019 shareHolder.classList.remove('hap-holder-animate', 'hap-holder-shown') 8020 if(shareHolder.querySelector('.hap-embed-field-wrap'))shareHolder.querySelector('.hap-embed-field-wrap').classList.remove('hap-embed-field-wrap-selected') 8021 } 8022 8023 if(open_type != 'pwd'){ 8024 if(pwdHolder){ 8025 pwdHolder.classList.remove('hap-holder-animate', 'hap-holder-shown') 8026 pwdField.value = '' 8027 } 8028 } 8029 8030 if(open_type != 'embed')if(embedHolder)embedHolder.classList.remove('hap-holder-animate', 'hap-holder-shown') 8031 8032 } 8033 8034 function enableActivePlaylistItem(){ 8035 8036 if(activePlaylistItem){ 8037 self.fireEvent('playlistItemEnabled', [{instance:self, instanceName:settings.instanceName, item:activePlaylistItem}]); 8038 8039 if(settings.togglePlaybackOnPlaylistItem){ 8040 activePlaylistItem.querySelector('.hap-playlist-thumb-style')?.classList.remove('hap-playlist-thumb-style-pause') 8041 } 8042 8043 //variation 8044 if(activePlaylistItem.querySelector('.hap-audio-variations')){ 8045 activePlaylistItem.querySelector('.hap-audio-variations').style.height = 0; 8046 } 8047 8048 activePlaylistItem.classList.remove('hap-playlist-item-selected', 'hap-playlist-item-disabled'); 8049 activePlaylistItem = null; 8050 } 8051 } 8052 8053 function disableActivePlaylistItem(id){ 8054 8055 if(activePlaylistItem){//enable active playlist item 8056 enableActivePlaylistItem(); 8057 8058 if(settings.useStickyPlayer && settings.clonePlaylistInFixedPlayer && window['hap_fixed_active_player'] == settings.instanceName){ 8059 _HAPStickyPlayer.enableActivePlaylistItem(); 8060 } 8061 } 8062 8063 activePlaylistItem = playlistContent.querySelectorAll('.hap-playlist-item')[id]; 8064 8065 if(activePlaylistItem){ 8066 8067 if(playbackToggleIndicator){ 8068 playbackToggleIndicator.style.display = 'block' 8069 playbackToggleIndicator.querySelector('.hap-btn-play').style.display = 'block' 8070 playbackToggleIndicator.querySelector('.hap-btn-pause').style.display = 'none' 8071 activePlaylistItem.querySelector('.hap-playlist-title-wrap').prepend(playbackToggleIndicator) 8072 } 8073 8074 activePlaylistItem.classList.add('hap-playlist-item-selected', 'hap-playlist-item-disabled'); 8075 8076 if(settings.useStickyPlayer && settings.clonePlaylistInFixedPlayer && window['hap_fixed_active_player'] == settings.instanceName){ 8077 _HAPStickyPlayer.disableActivePlaylistItem(id); 8078 } 8079 8080 //variation 8081 if(activePlaylistItem.querySelector('.hap-audio-variations')){ 8082 8083 var vp = activePlaylistItem.querySelector('.hap-audio-variations'); 8084 8085 vp.style.display = 'block'; 8086 8087 slidetoggle(vp); 8088 8089 //activePlaylistItem.querySelector('.hap-audio-variations').classList.add('hap-audio-variation-opened') 8090 //activePlaylistItem.querySelector('.hap-audio-variations').slideToggle(settings.variationToggleSpeed); 8091 } 8092 8093 if(settings.usePlaylistScroll && playlistLength > 0){//scroll to active item 8094 8095 if(!playlistClick){//not on playlist item click 8096 8097 setTimeout(function(){ 8098 8099 var rect = activePlaylistItem.getBoundingClientRect(); 8100 8101 if(settings.playlistScrollOrientation == 'horizontal'){ 8102 8103 var leftPos = activePlaylistItem.offsetLeft; 8104 8105 playlistInner.scrollTo({ left: leftPos, top: 0, behavior: 'smooth' }); 8106 8107 }else{ 8108 8109 var topPos = activePlaylistItem.offsetTop; 8110 8111 //https://jsfiddle.net/mrjLbf2n/1/ 8112 8113 //playlistInner.scrollTop = topPos 8114 8115 playlistInner.scrollTo({ left: 0, top: topPos, behavior: 'smooth' }); 8116 8117 //activePlaylistItem.scrollIntoView({behavior: 'smooth', block: 'nearest' }) 8118 8119 } 8120 },1000); 8121 8122 } 8123 playlistClick = false;
8124 8125 } 8126 8127 self.fireEvent('playlistItemDisabled', [{instance:self, instanceName:settings.instanceName, item:activePlaylistItem}]); 8128 } 8129 } 8130 8131 function slidetoggle(el) { 8132 8133 const ch = el.clientHeight, 8134 sh = el.scrollHeight, 8135 isCollapsed = !ch, 8136 noHeightSet = !el.style.height; 8137 8138 el.style.height = (isCollapsed || noHeightSet ? sh : 0) + "px"; 8139 if (noHeightSet) return slidetoggle.call(this, el); 8140 8141 } 8142 8143 8144 //############################################// 8145 /* login */ 8146 //############################################// 8147 8148 function toggleRedirectLoginScreen(type){ 8149 if(!redirectLoginHolderDownload && !redirectLoginHolderWatch){ 8150 console.log('this skin does not contain login screen!') 8151 return false; 8152 } 8153 8154 //note: we use different screen for watch / download login but we cant have both opened at the same time since media is paused during this screen 8155 8156 if(redirectLoginOpened){ 8157 8158 redirectLoginHolder.addEventListener('transitionend', function cb(e){ 8159 e.currentTarget.removeEventListener(e.type, cb); 8160 redirectLoginHolder.style.display = 'none'; 8161 }) 8162 8163 redirectLoginHolder.classList.remove('hap-redirect-login-holder-visible') 8164 8165 redirectLoginOpened = false; 8166 8167 /*if(mediaForcePause){//if it was playing 8168 self.playMedia(); 8169 mediaForcePause = false; 8170 }*/ 8171 8172 }else{ 8173 8174 self.fireEvent("beforeLoginScreen", [{instance:self, instanceName: settings.instanceName, media:currMediaData}]); 8175 8176 if(mediaPlaying){ 8177 self.pauseMedia(); 8178 mediaForcePause = true; 8179 } 8180 8181 redirectLoginHolder = (type == 'download') ? redirectLoginHolderDownload : redirectLoginHolderWatch; 8182 8183 redirectLoginHolder.style.display = 'block'; 8184 setTimeout(function(){ 8185 redirectLoginHolder.classList.add('hap-redirect-login-holder-visible') 8186 },50) 8187 8188 redirectLoginOpened = true; 8189 8190 } 8191 8192 } 8193 8194 //############################################// 8195 /* embed */ 8196 //############################################// 8197 8198 function setEmbedData(){ 8199 8200 embedHolder.querySelectorAll('.hap-embed-field-wrap').forEach(function(el){ 8201 el.classList.remove('hap-embed-field-wrap-selected') 8202 }) 8203 8204 if(settings.wpEmbedUrl){ 8205 //wp 8206 8207 var e_url = settings.wpEmbedUrl + 'includes/embed.php?', 8208 pid_exist 8209 8210 if(settings.playerId != null && settings.playerId != -1){ 8211 e_url += 'player_id='+settings.playerId 8212 pid_exist = true; 8213 }else{ 8214 //use default preset 8215 } 8216 8217 8218 8219 if(pid_exist)e_url += '&' 8220 8221 if(playlistId != null){ 8222 8223 e_url += 'playlist_id='+playlistId+'&active_item='+mediaCounter 8224 8225 if(settings.useSingleAudioEmbed){ 8226 e_url += '&single_audio=1&media_id='+currMediaData.mediaId; 8227 } 8228 8229 }else{ 8230 //copy html 8231 var h = playlistList.querySelector('.hap-playlist-anon').innerHTML.replace(/\n/g,''), 8232 v = encodeURIComponent(h) 8233 8234 e_url += 'plhtml='+v 8235 8236 } 8237 8238 }else{ 8239 8240 //manual embed 8241 var e_url = ''; 8242 if(settings.embedSrc)e_url = settings.embedSrc 8243 8244 } 8245 8246 var es = '<iframe width="100%" height="100%" src="'+e_url+'" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>' 8247 8248 //embed 8249 wrapper.querySelector('.hap-audio-embed').textContent = es; 8250 8251 //link 8252 var url = self.getCurrentMediaUrl(); 8253 embedHolder.querySelector('.hap-audio-link').innerHTML = url; 8254 8255 } 8256 8257 /*function getEmbedCode(){ 8258 8259 var skip_keys = ['playlistId','mediaPath','safeTitle','safeArtist'] 8260 8261 var s = '' 8262 8263 Object.keys(currMediaData).forEach(function(key,index) { 8264 // key: the name of the object key 8265 // index: the ordinal position of the key within the object 8266 8267 if(typeof currMediaData[key] === 'string'){ 8268 8269 if(skip_keys.indexOf(key) > 0) return 8270 8271 key = key.split(/(?=[A-Z])/).join('_').toLowerCase();//camelCase to _ 8272 8273 s += '&' + key + '=' + currMediaData[key] 8274 } 8275 }); 8276 8277 return s; 8278 8279 }*/ 8280 8281 if(embedHolder)onHandler(embedHolder, 'click', '.hap-embed-copy', (e) => embedHandler(e)); 8282 8283 function embedHandler(e){ 8284 8285 embedHolder.querySelectorAll('.hap-embed-field-wrap').forEach(function(el){ 8286 el.classList.remove('hap-embed-field-wrap-selected') 8287 }) 8288 8289 var field = e.target.closest('.hap-embed-box').querySelector('.hap-embed-field-wrap') 8290 field.classList.add('hap-embed-field-wrap-selected') 8291 var data = field.textContent 8292 8293 var dummy = document.createElement("input"); 8294 dummy.setAttribute("id", "hap-copy-url"); 8295 document.body.appendChild(dummy); 8296 document.getElementById("hap-copy-url").value = data.trim(); 8297 dummy.select(); 8298 try{ 8299 document.execCommand("copy"); 8300 }catch(er){} 8301 document.body.removeChild(dummy); 8302 8303 } 8304 8305 //############################################// 8306 /* playlist process */ 8307 //############################################// 8308 8309 function setPlaylist(id){ 8310 8311 playlistTransitionOn = true; 8312 if(preloader)preloader.style.display = 'block'; 8313 8314 if(lastPlaylist)destroyPlaylist(); 8315 8316 if(playlistList){ 8317 var playlist = playlistList.querySelector(id); 8318 }else{ 8319 var playlist = document.querySelector(id); 8320 } 8321 if(playlist.length == 0){ 8322 console.log('Failed playlist selection! Playlist - ' + id + ' does not exist. Check activePlaylist option in settings!'); 8323 settings.activePlaylist = null; 8324 playlistTransitionOn = false;
8325 preloader.style.display = 'none'; 8326 return false; 8327 } 8328 8329 8330 8331 //for load more and stats 8332 if(playlist.getAttribute('data-playlist-id') != undefined){ 8333 playlistId = playlist.getAttribute('data-playlist-id'); 8334 }else{ 8335 playlistId = null; 8336 } 8337 8338 settings.activePlaylist = id; 8339 8340 self.fireEvent('playlistStartLoad', [{instance:self, instanceName:settings.instanceName}]); 8341 8342 //global playlist options 8343 if(playlist.querySelector('.hap-playlist-options')){ 8344 8345 playlistData = playlist.querySelector('.hap-playlist-options')//.cloneNode(true) 8346 //wrapper.prepend(playlistData); 8347 8348 //playlist tile, desc 8349 if(playlistTitle){ 8350 if(playlistData.getAttribute('data-playlist-title') != undefined){ 8351 playlistTitle.innerHTML = playlistData.getAttribute('data-playlist-title') 8352 playlistTitle.style.display = 'block' 8353 }else{ 8354 playlistTitle.innerHTML = '' 8355 playlistTitle.style.display = 'none' 8356 } 8357 } 8358 8359 if(playlistDescription){ 8360 if(playlistData.querySelector('.hap-global-playlist-description')){ 8361 playlistDescription.innerHTML = playlistData.querySelector('.hap-global-playlist-description').innerHTML 8362 playlistDescription.style.display = 'block' 8363 }else{ 8364 playlistDescription.innerHTML = '' 8365 playlistDescription.style.display = 'none' 8366 } 8367 } 8368 8369 8370 addMoreLimit = parseInt(playlistData.getAttribute('data-add-more-limit'),10); 8371 addMoreNumResults = parseInt(playlistData.getAttribute('data-add-more-num-results'),10); 8372 addMoreOffset = parseInt(playlistData.getAttribute('data-add-more-offset'),10); 8373 addMoreSortOrder = playlistData.getAttribute("data-add-more-sort-order"); 8374 addMoreSortDirection = playlistData.getAttribute("data-add-more-sort-direction"); 8375 8376 8377 if(playlistData.getAttribute('data-thumb-global') != undefined){ 8378 globalThumb = playlistData.getAttribute('data-thumb-global'); 8379 } 8380 if(playlistData.getAttribute('data-download-global') != undefined){ 8381 globalDownload = playlistData.getAttribute('data-download-global'); 8382 } 8383 if(playlistData.getAttribute('data-start') != undefined){ 8384 globalStartTime = Number(playlistData.getAttribute('data-start')); 8385 8386 globalStartTimeMediaId = null; 8387 if(playlistData.getAttribute('data-start-media-id') != undefined)globalStartTimeMediaId = playlistData.getAttribute('data-start-media-id'); 8388 } 8389 if(playlistData.getAttribute('data-end') != undefined && !HAPUtils.isEmpty(playlistData.getAttribute('data-end'))){ 8390 globalEndTime = Number(playlistData.getAttribute('data-end')); 8391 } 8392 8393 if(playlistData.getAttribute('data-pwd') != undefined){ 8394 globalPwd = playlistData.getAttribute('data-pwd'); 8395 } 8396 8397 if(playlistData.getAttribute('data-add-more-on-total-scroll') != undefined){ 8398 addMoreOnTotalScroll = true; 8399 } 8400 if(playlistData.getAttribute('data-media-prefix-url') != undefined){ 8401 mediaPrefixUrl = playlistData.getAttribute('data-media-prefix-url'); 8402 } 8403 if(playlistData.getAttribute('data-active-media-id') != undefined){ 8404 activeMediaId = playlistData.getAttribute('data-active-media-id'); 8405 } 8406 8407 if(playlistData.getAttribute('data-lock-time') != undefined){ 8408 globalLockTime = Number(playlistData.getAttribute('data-lock-time')); 8409 } 8410 if(playlistData.getAttribute('data-lock-video-user-roles') != undefined && !HAPUtils.isEmpty(playlistData.getAttribute('data-lock-video-user-roles'))){ 8411 globalLockVideoUserRoles = playlistData.getAttribute('data-lock-video-user-roles').split(','); 8412 } 8413 8414 //ads 8415 if(showAds){ 8416 8417 if(playlistData.getAttribute('data-vast') != undefined){//ima 8418 globalVast = playlistData.getAttribute('data-vast') 8419 } 8420 else{ 8421 8422 if(playlistData.getAttribute('data-ad-pre') != undefined){ 8423 globalAdPre = playlistData.getAttribute('data-ad-pre').split(",").map(function(item){ 8424 return item.trim(); 8425 }); 8426 if(playlistData.getAttribute('data-shuffle-ads') != undefined && globalAdPre.length>1)HAPUtils.shuffleArray(globalAdPre); 8427 } 8428 if(playlistData.getAttribute('data-ad-mid') != undefined){ 8429 globalAdMid = playlistData.getAttribute('data-ad-mid').split(",").map(function(item){ 8430 return item.trim(); 8431 }); 8432 if(playlistData.getAttribute('data-shuffle-ads') != undefined && globalAdMid.length>1)HAPUtils.shuffleArray(globalAdMid); 8433 if(playlistData.getAttribute('data-ad-mid-interval') != undefined){ 8434 globalAdMidInterval = playlistData.getAttribute('data-ad-mid-interval'); 8435 } 8436 } 8437 if(playlistData.getAttribute('data-ad-end') != undefined){ 8438 globalAdEnd = playlistData.getAttribute('data-ad-end').split(",").map(function(item){ 8439 return item.trim(); 8440 }); 8441 if(playlistData.getAttribute('data-shuffle-ads') != undefined && globalAdEnd.length>1)HAPUtils.shuffleArray(globalAdEnd); 8442 } 8443 } 8444 8445 } 8446 8447 } 8448 8449 var item, type; 8450 8451 var div_list = playlist.querySelectorAll('.hap-playlist-item').forEach(div => { 8452 8453 item = div; 8454 type = item.getAttribute('data-type'); 8455 8456 if(RegExp(/^audio|hls$/).test(type) && item.classList.contains('hap-playlist-item-ready')) {//copy directly to playlist 8457 playlistProcessDataUrl.push(item.cloneNode(true)); 8458 }else{ 8459 playlistProcessDataUrl.push(getTrackData(item)); 8460 } 8461 8462 if(item.getAttribute('data-path') != undefined)lastPositionDataPath = item.getAttribute('data-path') 8463 8464 }); 8465 8466 playlistLength = playlistProcessDataUrl.length; 8467 checkProcessCounter(); 8468 8469 } 8470 8471 //############################################// 8472 /* xml */ 8473 //############################################// 8474 8475 function processXml(data){ 8476 //first load xml file, then process its content 8477 8478 if(xhrRequest){ 8479 xhrRequest.abort(); 8480 xhrRequest = null; 8481 } 8482 8483 xhrRequest = new XMLHttpRequest(); 8484 xhrRequest.onreadystatechange = function() { 8485 if (xhrRequest.readyState == 4) { 8486 8487 var dom = HAPUtils.parseXML(xhrRequest.responseText); 8488 8489 var arr = dom.getElementsByClassName("hap-playlist-item"), obj 8490 8491 var i, len = arr.length
8492 for(i = 0;i < len; i++){ 8493 8494 obj = getTrackData(arr[i]); 8495 8496 if(data.origtype)obj.origtype = data.origtype; 8497 if(data.mediaId != undefined)obj.mediaId = data.mediaId;//for stats 8498 8499 playlistProcessDataUrl.push(obj); 8500 8501 } 8502 8503 playlistLength = playlistProcessDataUrl.length; 8504 checkProcessCounter(); 8505 8506 } 8507 } 8508 xhrRequest.onerror = function(e) { 8509 console.log('Error processXML: ' + e); 8510 checkProcessCounter(); 8511 }; 8512 xhrRequest.open('GET', data.path); 8513 xhrRequest.setRequestHeader("Content-Type", "text/xml"); 8514 xhrRequest.send(); 8515 8516 } 8517 8518 //############################################// 8519 /* m3u */ 8520 //############################################// 8521 8522 function processM3u(data) { 8523 8524 if(window.location.protocol == 'file:'){ 8525 console.log('Reading m3u files requires server connection.'); 8526 return false; 8527 } 8528 8529 //note, no mixed playlists! 8530 //only audio file type 8531 8532 if(xhrRequest){ 8533 xhrRequest.abort(); 8534 xhrRequest = null; 8535 } 8536 8537 xhrRequest = new XMLHttpRequest(); 8538 xhrRequest.onreadystatechange = function() { 8539 if (xhrRequest.readyState == 4) { 8540 8541 var result = xhrRequest.responseText 8542 8543 var obj, channel; 8544 8545 result 8546 .replace('#EXTM3U', '') 8547 .split('#EXTINF:') 8548 .slice(1) 8549 .map(function(str, index) { 8550 8551 obj = HAPUtils.extendObj(true, {}, data); 8552 8553 obj.type = 'audio'; 8554 8555 channel = str.split('\n').slice(0,-1); 8556 8557 //audio url 8558 obj.mp3 = channel[1].trim(); 8559 8560 //title, artist 8561 var t = channel[0].split(',') 8562 if(t.length > 1){ 8563 var d = t[0]; 8564 if(HAPUtils.isNumber(d) && d != -1)obj.duration = d; 8565 var title = t[1]; 8566 }else{ 8567 var title = t[0]; 8568 } 8569 8570 if(title.indexOf('-')>-1){ 8571 var s = title.split('-') 8572 obj.title = s[1].trim(); 8573 8574 if(s[0].match(/^\d+(\s*)+\./)) {//contains numbers in front of artist 8575 var a = s[0].substr(s[0].indexOf('.')+1); 8576 obj.artist = a[1].trim(); 8577 }else{ 8578 obj.artist = s[0].trim(); 8579 } 8580 }else{ 8581 obj.title = title.trim(); 8582 } 8583 8584 playlistProcessData.push(obj); 8585 8586 }); 8587 8588 checkProcessCounter(); 8589 8590 } 8591 } 8592 xhrRequest.onerror = function(e) { 8593 console.log('Error processM3u: ' + e); 8594 checkProcessCounter(); 8595 }; 8596 xhrRequest.open('GET', data.path); 8597 xhrRequest.setRequestHeader("Content-Type", "text/xml"); 8598 xhrRequest.send(); 8599 8600 } 8601 8602 //############################################// 8603 /* json */ 8604 //############################################// 8605 8606 function processJson(data){ 8607 //first load json file, then process its content 8608 8609 if(xhrRequest){ 8610 xhrRequest.abort(); 8611 xhrRequest = null; 8612 } 8613 8614 xhrRequest = new XMLHttpRequest(); 8615 xhrRequest.onreadystatechange = function() { 8616 if (xhrRequest.readyState == 4) { 8617 8618 var track = JSON.parse(xhrRequest.responseText) 8619 8620 playlistProcessCounter = -1; 8621 playlistProcessData = []; 8622 playlistProcessDataUrl = []; 8623 8624 lastPlaylist = playlistContent; 8625 8626 if(Array.isArray(track))playlistProcessDataUrl = track; 8627 else playlistProcessDataUrl.push(track); 8628 8629 if(data.origtype && data.mediaId != undefined){ 8630 var i, len = playlistProcessDataUrl.length; 8631 for(i = 0;i<len;i++){ 8632 playlistProcessDataUrl[i].origtype = data.origtype; 8633 if(!playlistProcessDataUrl[i].mediaId !== 'undefined')playlistProcessDataUrl[i].mediaId = data.mediaId;//for stats 8634 } 8635 } 8636 8637 playlistLength = playlistProcessDataUrl.length; 8638 8639 checkProcessCounter(); 8640 8641 } 8642 } 8643 xhrRequest.onerror = function(e) { 8644 console.log('Error processJSON: ' + e); 8645 checkProcessCounter(); 8646 }; 8647 xhrRequest.open('GET', data.path); 8648 xhrRequest.setRequestHeader("Content-Type", "application/json"); 8649 xhrRequest.send(); 8650 8651 } 8652 8653 //############################################// 8654 /* */ 8655 //############################################// 8656 8657 function checkProcessCounter() { 8658 playlistProcessCounter++; 8659 8660 if(playlistProcessCounter > playlistLength - 1){ 8661 buildPlaylist(); 8662 }else{ 8663 var data = playlistProcessDataUrl[playlistProcessCounter], type = data.type; 8664 8665 if(type){ 8666 8667 if(type == 'soundcloud') { 8668
8669 loadMoreType = 'soundcloud'; 8670 8671 if(data.limit){ 8672 resultLimit = data.limit; 8673 if(data.loadMore)loadMoreOnTotalScroll = true;//from addtrack 8674 }else{ 8675 resultLimit = allResults; 8676 loadMoreOnTotalScroll = false; 8677 } 8678 8679 nextPageToken = []; 8680 8681 if(!_scLoader){ 8682 8683 _scLoader = new HAPSCLoader({settings: settings}) 8684 8685 _scLoader.addEventListener('HAPSCLoader.END_LOAD', function(data){ 8686 8687 var i, len = data.data.length, obj; 8688 for(i=0;i<len;i++){ 8689 obj = data.data[i]; 8690 playlistProcessData.push(obj); 8691 } 8692 8693 nextPageToken = data.nextPageToken; 8694 8695 if(loadMoreProcess){ 8696 buildPlaylist(); 8697 }else{ 8698 checkProcessCounter(); 8699 } 8700 8701 }); 8702 8703 _scLoader.addEventListener('HAPSCLoader.GET_STREAM_URL', function( data){ 8704 8705 if(crossFadeOn){ 8706 scUrlReady = data.location; 8707 }else{ 8708 mediaPath = currMediaData.sc_url = data.location; 8709 initAudio() 8710 } 8711 8712 }); 8713 8714 } 8715 8716 _scLoader.request(data, resultLimit); 8717 8718 }else if(type == 'podcast') { 8719 8720 loadMoreType = 'podcast'; 8721 8722 processPodcast(data); 8723 8724 }else if(type == 'itunes_podcast_music') { 8725 8726 processiTunes(data); 8727 8728 }else if(type == 'folder') { 8729 8730 loadMoreType = 'folder'; 8731 8732 processFolder(data); 8733 8734 }else if(type == 'folder_accordion') { 8735 8736 accordionMode = true; 8737 8738 processFolderAccordion(data); 8739 8740 }else if(type == 'json_accordion') { 8741 8742 accordionMode = true; 8743 8744 processJsonAccordion(data); 8745 8746 }else if(type == 'gdrive_folder'){ 8747 8748 processGdriveFolder(data); 8749 8750 }else if(type == 'onedrive_folder') { 8751 8752 processOnedriveFolder(data); 8753 8754 }else if(type == 'hls') { 8755 8756 playlistProcessData.push(data); 8757 checkProcessCounter(); 8758 8759 }else if(type == 'audio'){ 8760 8761 playlistProcessData.push(data); 8762 checkProcessCounter(); 8763 8764 }else if(type == 's3_audio'){ 8765 8766 playlistProcessData.push(data); 8767 checkProcessCounter(); 8768 8769 }else if(type == 's3_bucket_audio'){ 8770 8771 processS3Bucket(data); 8772 8773 }else if(type == 'youtube_single' || type == 'youtube_playlist') { 8774 8775 if(data.noApi){ 8776 8777 playlistProcessData.push(data); 8778 checkProcessCounter(); 8779 8780 }else{ 8781 8782 loadMoreType = 'youtube'; 8783 8784 if(data.loadMore)loadMoreOnTotalScroll = true;//from addtrack 8785 8786 if(!_HAPYoutubeLoader)createLoader('youtube'); 8787 _HAPYoutubeLoader.setData(data); 8788 8789 } 8790 8791 }else if(type == 'xml'){ 8792 8793 processXml(data); 8794 8795 }else if(type == 'json'){ 8796 8797 processJson(data); 8798 8799 }else if(type == 'm3u'){ 8800 8801 processM3u(data); 8802 8803 } 8804 8805 }else{//copy directly to playlist 8806 8807 playlistProcessData.push(data); 8808 8809 checkProcessCounter(); 8810 } 8811 } 8812 } 8813 8814 //############################################// 8815 /* get track data */ 8816 //############################################// 8817 8818 function getTrackData(track){ 8819 8820 var obj = {}; 8821 8822 obj.type = obj.origtype = track.getAttribute('data-type'); 8823 obj.origclasses = track.getAttribute('class');//copy classes 8824 8825 if(nonProcessMedia.indexOf(obj.type) != -1){ 8826 obj.pi_item = track; 8827 } 8828 8829 //if(!track.is(':empty'))obj.content = track.innerHTML = );//copy any content to generated playlist item 8830 8831 if(track.querySelector('.hap-custom-content')){ 8832 obj.content = track.querySelector('.hap-custom-content').innerHTML; 8833 } 8834 8835 if(track.getAttribute('data-noapi') != undefined){ 8836 obj.noApi = true; 8837 } 8838 8839 if(globalPwd){ 8840 obj.pwd = globalPwd; 8841 }else if(track.getAttribute('data-pwd') != undefined){//password 8842 obj.pwd = track.getAttribute('data-pwd'); 8843 } 8844 8845 if(track.getAttribute('data-video') != undefined){ 8846 obj.video = track.getAttribute('data-video'); 8847 if(obj.video.indexOf(bsf_match) != -1)obj.video = HAPUtils.b64DecodeUnicode(obj.video.substr(6)); 8848 } 8849 8850 if(track.getAttribute('data-media-id') != undefined){//stats 8851 obj.mediaId = parseInt(track.getAttribute('data-media-id'),10); 8852 } 8853 8854 if(track.getAttribute('data-audio-preview') != undefined){ 8855 obj.audioPreview = track.getAttribute('data-audio-preview'); 8856 if(obj.audioPreview.indexOf(bsf_match) != -1)obj.audioPreview = HAPUtils.b64DecodeUnicode(obj.audioPreview.substr(6)); 8857 } 8858 8859 //peaks 8860 8861 if(track.getAttribute('data-peaks') != undefined)obj.peaks = track.getAttribute('data-peaks'); 8862 8863 if(track.getAttribute('data-peak-dir') != undefined){ 8864 obj.peakdir = track.getAttribute('data-peak-dir'); 8865 } 8866 if(track.getAttribute('data-peak-name') != undefined){ 8867 obj.peakName = track.getAttribute('data-peak-name'); 8868 } 8869 if(track.getAttribute('data-remote') != undefined){ 8870 obj.remote = true; 8871 } 8872 8873 if(track.getAttribute('data-bucket') != undefined){ 8874 obj.bucket = track.getAttribute('data-bucket'); 8875 if(obj.bucket.indexOf(bsf_match) != -1)obj.bucket = HAPUtils.b64DecodeUnicode(obj.bucket.substr(6)); 8876 } 8877 if(track.getAttribute('data-key') != undefined){ 8878 obj.key = track.getAttribute('data-key'); 8879 if(obj.key.indexOf(bsf_match) != -1)obj.key = HAPUtils.b64DecodeUnicode(obj.key.substr(6)); 8880 } 8881 8882 if(track.getAttribute('data-content-url') != undefined){ 8883 obj.contentUrl = track.getAttribute('data-content-url'); 8884 } 8885 8886 if(track.getAttribute('data-path') != undefined){ 8887 8888 var path = track.getAttribute('data-path'); 8889 if(path.indexOf(bsf_match) != -1)path = HAPUtils.b64DecodeUnicode(path.substr(6)); 8890 8891 obj.path = path; 8892 8893 } 8894 else if(track.getAttribute('data-mp3') != undefined)obj.path = track.getAttribute('data-mp3'); 8895 else if(track.getAttribute('data-wav') != undefined)obj.path = track.getAttribute('data-wav'); 8896 else if(track.getAttribute('data-aac') != undefined)obj.path = track.getAttribute('data-aac'); 8897 else if(track.getAttribute('data-flac') != undefined)obj.path = track.getAttribute('data-flac'); 8898 8899 8900 8901 if(track.getAttribute('data-lyrics') != undefined){ 8902 obj.lyrics = track.getAttribute('data-lyrics'); 8903 if(obj.lyrics.indexOf(bsf_match) != -1)obj.lyrics = HAPUtils.b64DecodeUnicode(obj.lyrics.substr(6)); 8904 } 8905 8906 if(track.getAttribute('data-limit') != undefined){ 8907 obj.limit = Math.abs(parseInt(track.getAttribute('data-limit'),10)); 8908 } 8909 8910 if(globalThumb){ 8911 obj.thumb = globalThumb; 8912 }else if(track.getAttribute('data-thumb') != undefined){ 8913 obj.thumb = track.getAttribute('data-thumb'); 8914 } 8915 if(track.getAttribute('data-thumb-small') != undefined){ 8916 obj.thumbSmall = track.getAttribute('data-thumb-small'); 8917 } 8918 if(track.getAttribute('data-thumb-default') != undefined){ 8919 obj.thumbDefault = track.getAttribute('data-thumb-default'); 8920 } 8921 if(track.getAttribute('data-thumb-alt') != undefined){ 8922 obj.thumbAlt = track.getAttribute('data-thumb-alt'); 8923 } 8924 if(track.getAttribute('data-title') != undefined){ 8925 obj.title = track.getAttribute('data-title'); 8926 } 8927 if(track.getAttribute('data-description') != undefined){ 8928 obj.description = track.getAttribute('data-description'); 8929 } 8930 else if(track.querySelector('.hap-playlist-description')){ 8931 var elem = track.querySelector('.hap-playlist-description') 8932 obj.descriptionHtml = elem.innerHTML 8933 } 8934 if(track.getAttribute('data-artist') != undefined){ 8935 obj.artist = track.getAttribute('data-artist'); 8936 } 8937 if(track.getAttribute('data-album') != undefined){ 8938 obj.album = track.getAttribute('data-album'); 8939 } 8940 8941 if(globalDownload){ 8942 obj.download = globalDownload; 8943 }else if(track.getAttribute('data-download') != undefined){ 8944 obj.download = track.getAttribute('data-download'); 8945 } 8946 8947 8948 if(track.getAttribute('data-duration') != undefined){ 8949 obj.duration = track.getAttribute('data-duration'); 8950 } 8951 if(track.getAttribute('data-date') != undefined){ 8952 obj.date = track.getAttribute('data-date'); 8953 } 8954 if(track.getAttribute('data-id3') != undefined){ 8955 obj.id3 = true; 8956 } 8957 if(globalStartTime){ 8958 if(globalStartTimeMediaId){ 8959 if(obj.mediaId != undefined && obj.mediaId == globalStartTimeMediaId){ 8960 obj.start = globalStartTime; 8961 globalStartTimeMediaId = null; 8962 globalStartTime = null; 8963 } 8964 }else{ 8965 obj.start = globalStartTime; 8966 } 8967 }else if(track.getAttribute('data-start') != undefined){ 8968 obj.start = Math.abs(track.getAttribute('data-start')); 8969 } 8970 if(globalEndTime){ 8971 obj.end = globalEndTime; 8972 }else if(track.getAttribute('data-end') != undefined){ 8973 obj.end = Math.abs(track.getAttribute('data-end')); 8974 } 8975 if(track.getAttribute('data-link') != undefined){ 8976 obj.link = track.getAttribute('data-link'); 8977 obj.target = '_blank'; 8978 if(track.getAttribute('data-target') != undefined){ 8979 obj.target = track.getAttribute('data-target'); 8980 } 8981 if(track.getAttribute('data-rel') != undefined){ 8982 obj.rel = track.getAttribute('data-rel'); 8983 } 8984 } 8985 8986 if(globalLockTime != undefined){ 8987 obj.lockTime = globalLockTime; 8988 }else if(track.getAttribute('data-lock-time') != undefined){ 8989 obj.lockTime = Number(track.getAttribute('data-lock-time')); 8990 } 8991 if(globalLockVideoUserRoles){ 8992 obj.lockVideoUserRoles = globalLockVideoUserRoles; 8993 } 8994 8995 if(track.getAttribute('data-playlist-icons') != undefined){ 8996 obj.playlistIcons = JSON.parse(track.dataset.playlistIcons); 8997 } 8998 8999 if(track.getAttribute('data-sort') != undefined){ 9000 obj.sort = track.getAttribute('data-sort'); 9001 } 9002 if(track.getAttribute('data-active-accordion') != undefined){ 9003 obj.activeAccordion = track.getAttribute('data-active-accordion'); 9004 } 9005 9006 if(track.getAttribute('data-load-more') != undefined){ 9007 loadMoreOnTotalScroll = true; 9008 } 9009 9010 //ads (individual overwrites global) 9011 if(showAds){ 9012 9013 if(track.getAttribute('data-vast') != undefined){//ima 9014 obj.vast = track.getAttribute('data-vast') 9015 }else if(globalVast){ 9016 obj.vast = globalVast 9017 } 9018 9019 if(!obj.vast){//there can be either vast or normal ads, not both 9020 9021 if(track.getAttribute('data-ad-pre') != undefined){ 9022 obj.adPre = track.getAttribute('data-ad-pre').split(",").map(function(item){ 9023 return item.trim(); 9024 }); 9025 if(track.getAttribute('data-shuffle-ads') != undefined && obj.adPre.length>1)HAPUtils.shuffleArray(obj.adPre); 9026 }else if(globalAdPre){ 9027 obj.adPre = globalAdPre; 9028 } 9029 9030 if(track.getAttribute('data-ad-mid') != undefined){ 9031 obj.adMid = track.getAttribute('data-ad-mid').split(",").map(function(item){ 9032 return item.trim(); 9033 }); 9034 if(track.getAttribute('data-shuffle-ads') != undefined && obj.adMid.length>1)HAPUtils.shuffleArray(obj.adMid); 9035 if(track.getAttribute('data-ad-mid-interval') != undefined){ 9036 obj.adMidInterval = track.getAttribute('data-ad-mid-interval'); 9037 } 9038 }else if(globalAdMid){ 9039 obj.adMid = globalAdMid; 9040 if(globalAdMidInterval)obj.adMidInterval = globalAdMidInterval; 9041 } 9042 9043 if(track.getAttribute('data-ad-end') != undefined){ 9044 obj.adEnd = track.getAttribute('data-ad-end').split(",").map(function(item){ 9045 return item.trim(); 9046 }); 9047 if(track.getAttribute('data-shuffle-ads') != undefined && obj.adEnd.length>1)HAPUtils.shuffleArray(obj.adEnd); 9048 }else if(globalAdEnd){ 9049 obj.adEnd = globalAdEnd; 9050 } 9051 9052 } 9053 9054 } 9055 9056 9057 9058 9059 9060 9061 return obj; 9062 } 9063 9064 //############################################// 9065 /* youtube */ 9066 //############################################// 9067 9068 function createLoader(type){ 9069 9070 if(type == 'youtube'){ 9071 9072 _HAPYoutubeLoader = new HAPYoutubeLoader(settings); 9073 _HAPYoutubeLoader.addEventListener('HAPYoutubeLoader.END_LOAD', function(data){ 9074 9075 var i, len = data.data.length, obj; 9076 for(i=0;i<len;i++){ 9077 obj = data.data[i]; 9078 playlistProcessData.push(obj); 9079 } 9080 9081 nextPageToken = data.nextPageToken; 9082 9083 if(loadMoreProcess){ 9084 buildPlaylist(); 9085 }else{ 9086 checkProcessCounter(); 9087 } 9088 9089 }); 9090 9091 } 9092 } 9093 9094 //############################################// 9095 /* folder */ 9096 //############################################// 9097
9098 function processFolder(data){ 9099 9100 if(window.location.protocol == 'file:'){ 9101 console.log('Reading folders requires server connection.'); 9102 return false; 9103 } 9104 9105 if(data.limit){ 9106 resultLimit = data.limit; 9107 if(data.loadMore)loadMoreOnTotalScroll = true;//from addtrack 9108 }else{ 9109 resultLimit = allResults; 9110 } 9111 9112 var path = data.path.replace(/\/\//g, "/"), url = settings.sourcePath + 'includes/folder_parser.php', limit = resultLimit, load_more_limit = resultLimit; 9113 9114 nextPageToken = []; 9115 9116 if(data.id3){ 9117 id3Start = id3Counter = playlistProcessData.length-1; 9118 useId3 = true; 9119 }else{ 9120 useId3 = false; 9121 } 9122 9123 if(xhrRequest){ 9124 xhrRequest.abort(); 9125 xhrRequest = null; 9126 } 9127 9128 var params = 'dir='+path 9129 if(data.contentUrl)params += '&content_url='+data.contentUrl 9130 9131 xhrRequest = new XMLHttpRequest(); 9132 xhrRequest.onreadystatechange = function() { 9133 if (xhrRequest.readyState == 4) { 9134 9135 try{ 9136 var media = JSON.parse(xhrRequest.responseText) 9137 }catch(er){ 9138 alert(xhrRequest.responseText); 9139 return; 9140 } 9141 9142 var i, len = media.length, entry, obj, full_path; 9143 9144 if(data.sort){ 9145 if(data.sort == 'filename-asc')HAPUtils.keysrt(media, 'filename'); 9146 else if(data.sort == 'filename-desc')HAPUtils.keysrt(media, 'filename', true); 9147 else if(data.sort == 'date-asc')HAPUtils.keysrt(media, 'filemtime'); 9148 else if(data.sort == 'date-desc')HAPUtils.keysrt(media, 'filemtime', true); 9149 } 9150 9151 for(i=0; i < len; i++){ 9152 9153 entry = media[i]; 9154 9155 obj = HAPUtils.extendObj(true, {}, data); 9156 obj.type = 'audio'; 9157 full_path = entry.fullpath; 9158 obj.path = full_path; 9159 9160 if(settings.createDownloadIconsInPlaylist)if(!obj.download)obj.download = full_path; 9161 if(settings.createLinkIconsInPlaylist)if(!obj.link)obj.link = full_path; 9162 9163 if(!obj.title)obj.title = entry.filename; 9164 9165 if(i < load_more_limit){ 9166 playlistProcessData.push(obj); 9167 id3Counter++; 9168 }else{ 9169 nextPageToken.push(obj); 9170 } 9171 9172 } 9173 9174 if(nextPageToken.length == 0){ 9175 loadMoreOnTotalScroll = false; 9176 nextPageToken = null; 9177 } 9178 9179 if(data.id3){ 9180 if(typeof jsmediatags === 'undefined'){ 9181 console.log('Link to jsmediatags.js missing in head tag!') 9182 } 9183 getId3(); 9184 }else{ 9185 checkProcessCounter(); 9186 } 9187 9188 } 9189 } 9190 xhrRequest.onerror = function(e) { 9191 console.log('Error processFolder: ' + e); 9192 checkProcessCounter(); 9193 }; 9194 xhrRequest.open('POST', url); 9195 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 9196 xhrRequest.send(params); 9197 9198 } 9199 9200 //############################################// 9201 /* accordion */ 9202 //############################################// 9203 9204 function processFolderAccordion(data){ 9205 9206 if(window.location.protocol == 'file:'){ 9207 console.log('Reading folders requires server connection.'); 9208 return false; 9209 } 9210 9211 var path = data.path.replace(/\/\//g, "/"), url = settings.sourcePath + 'includes/folder_accordion.php' 9212 9213 if(xhrRequest){ 9214 xhrRequest.abort(); 9215 xhrRequest = null; 9216 } 9217 9218 var params = 'dir='+path 9219 if(data.contentUrl)params += '&content_url='+data.contentUrl 9220 9221 xhrRequest = new XMLHttpRequest(); 9222 xhrRequest.onreadystatechange = function() { 9223 if (xhrRequest.readyState == 4) { 9224 9225 try{ 9226 var media = JSON.parse(xhrRequest.responseText) 9227 }catch(er){ 9228 alert(xhrRequest.responseText); 9229 return; 9230 } 9231 9232 var i, len = media.length, len2, j, parent, entry, children, obj, full_path; 9233 9234 for(i=0; i < len; i++){ 9235 9236 children = media[i].children; 9237 9238 if(data.sort){ 9239 if(data.sort == 'filename-asc')HAPUtils.keysrt(children, 'filename'); 9240 else if(data.sort == 'filename-desc')HAPUtils.keysrt(children, 'filename', true); 9241 else if(data.sort == 'date-asc')HAPUtils.keysrt(children, 'filemtime'); 9242 else if(data.sort == 'date-desc')HAPUtils.keysrt(children, 'filemtime', true); 9243 } 9244 9245 playlistDataAccordion.push({media:children}) 9246 9247 len2 = children.length; 9248 9249 for(j=0; j < len2; j++){ 9250 9251 entry = children[j]; 9252 9253 obj = {type: 'audio'}; 9254 if(data.mediaId != undefined)obj.mediaId = data.mediaId; 9255 9256 full_path = entry.fullpath; 9257 9258 obj[entry.extension] = full_path; 9259 9260 if(settings.createDownloadIconsInPlaylist)if(!obj.download)obj.download = full_path; 9261 if(settings.createLinkIconsInPlaylist)if(!obj.link)obj.link = full_path; 9262 9263 if(!obj.title)obj.title = entry.filename; 9264 9265 children[j] = obj; 9266 9267 } 9268 9269 } 9270 9271 buildAccordion(media, data);//create accordion parents 9272 9273 //set accordion item active on start 9274 if(!accordionActiveId)accordionActiveId = 0; 9275 accordioPlaylistId = accordionActiveId; 9276 9277 var ah = playlistContent.querySelector('.hap-accordion-item[data-id="'+accordionActiveId+'"]') 9278 ah.classList.add('hap-accordion-item-inited', 'hap-accordion-item-opened') 9279 9280 accordionHolder = ah.querySelector('.hap-accordion-item-content'); 9281 9282 playlistContent = accordionHolder; 9283 9284 playlistProcessData = media[accordionActiveId].children; 9285 9286 if(data.id3){ 9287 accordionUseId3 = true; 9288 if(typeof jsmediatags === 'undefined'){ 9289 console.log('Link to jsmediatags.js missing in head tag!') 9290 } 9291 id3Start = -1; 9292 id3Counter = playlistProcessData.length-1; 9293 getId3_all(); 9294 }else{ 9295 buildPlaylist(); 9296 } 9297 9298 } 9299 } 9300 xhrRequest.onerror = function(e) { 9301 console.log('Error processFolderAccordion: ' + e); 9302 checkProcessCounter(); 9303 }; 9304 xhrRequest.open('POST', url); 9305 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 9306 xhrRequest.send(params); 9307 9308 } 9309 9310 function processJsonAccordion(data){ 9311 9312 if(window.location.protocol == 'file:'){ 9313 console.log('Reading json requires server connection.'); 9314 return false;
9315 } 9316 9317 if(xhrRequest){ 9318 xhrRequest.abort(); 9319 xhrRequest = null; 9320 } 9321 9322 var path = data.path.replace(/\/\//g, "/") 9323 9324 var params = 'dir='+path 9325 if(data.contentUrl)params += '&content_url='+data.contentUrl 9326 9327 xhrRequest = new XMLHttpRequest(); 9328 xhrRequest.onreadystatechange = function() { 9329 if (xhrRequest.readyState == 4) { 9330 9331 var media = JSON.parse(xhrRequest.responseText) 9332 9333 var i, len = media.length, len2, j, parent, entry, children, obj, full_path; 9334 9335 for(i=0; i < len; i++){ 9336 9337 children = media[i].children; 9338 9339 //sort each folder individually 9340 if(data.sort){ 9341 if(data.sort == 'filename-asc')HAPUtils.keysrt(children, 'filename'); 9342 else if(data.sort == 'filename-desc')HAPUtils.keysrt(children, 'filename', true); 9343 else if(data.sort == 'date-asc')HAPUtils.keysrt(children, 'filemtime'); 9344 else if(data.sort == 'date-desc')HAPUtils.keysrt(children, 'filemtime', true); 9345 } 9346 9347 playlistDataAccordion.push({media:children}) 9348 9349 len2 = children.length; 9350 9351 for(j=0; j < len2; j++){ 9352 9353 entry = children[j]; 9354 9355 obj = {type: 'audio'}; 9356 if(data.mediaId != undefined)obj.mediaId = data.mediaId; 9357 9358 if(mediaPrefixUrl)full_path = mediaPrefixUrl + '/' + media[i].parent + '/' + entry; 9359 else full_path = entry.full_path; 9360 obj.mp3 = full_path; 9361 9362 if(settings.createDownloadIconsInPlaylist)if(!obj.download)obj.download = full_path; 9363 if(settings.createLinkIconsInPlaylist)if(!obj.link)obj.link = full_path; 9364 9365 children[j] = obj; 9366 9367 } 9368 9369 } 9370 9371 buildAccordion(media, data);//create accordion parents 9372 9373 //set accordion item active on start 9374 if(!accordionActiveId)accordionActiveId = 0; 9375 accordioPlaylistId = accordionActiveId; 9376 9377 var ah = playlistContent.querySelector('.hap-accordion-item[data-id="'+accordionActiveId+'"]') 9378 ah.classList.add('hap-accordion-item-inited', 'hap-accordion-item-opened') 9379 9380 accordionHolder = ah.querySelector('.hap-accordion-item-content'); 9381 9382 playlistContent = accordionHolder; 9383 9384 playlistProcessData = media[accordionActiveId].children; 9385 9386 if(data.id3){ 9387 accordionUseId3 = true; 9388 if(typeof jsmediatags === 'undefined'){ 9389 console.log('Link to jsmediatags.js missing in head tag!') 9390 } 9391 id3Start = -1; 9392 id3Counter = playlistProcessData.length-1; 9393 getId3_all(); 9394 }else{ 9395 buildPlaylist(); 9396 } 9397 9398 } 9399 } 9400 9401 xhrRequest.onerror = function(e) { 9402 console.log('Error processJSONAcc: ' + e); 9403 checkProcessCounter(); 9404 }; 9405 xhrRequest.open('POST', data.path); 9406 xhrRequest.setRequestHeader("Content-Type", "application/json"); 9407 xhrRequest.send(params); 9408 9409 } 9410 9411 //############################################// 9412 /* google drive folder */ 9413 //############################################// 9414 9415 function processGdriveFolder(data){ 9416 9417 if(window.location.protocol == 'file:'){ 9418 console.log('Reading files from folders locally is not possible! This requires server connection.'); 9419 return false; 9420 } 9421 9422 var key = settings.gDriveAppId || settings.gdk 9423 9424 if(HAPUtils.isEmpty(key)){ 9425 console.log('Google Drive api key has not been set in settings!'); 9426 return false; 9427 } 9428 9429 var url = "https://www.googleapis.com/drive/v3/files?q='" + data.path + "'+in+parents&pageSize=1000&key=" + key; 9430 9431 if(data.id3 && settings.cors){ 9432 id3Start = id3Counter = playlistProcessData.length-1; 9433 useId3 = true; 9434 useID3Cors = true; 9435 }else{ 9436 useId3 = false;
9437 useID3Cors = false; 9438 } 9439 9440 if(xhrRequest){ 9441 xhrRequest.abort(); 9442 xhrRequest = null; 9443 } 9444 9445 xhrRequest = new XMLHttpRequest(); 9446 xhrRequest.onreadystatechange = function() { 9447 if (xhrRequest.readyState == 4) { 9448 9449 var media = JSON.parse(xhrRequest.responseText) 9450 9451 var i, len = media.files.length, entry, obj, imgArr = [], mediaArr = []; 9452 9453 for(i=0; i < len; i++){ 9454 9455 entry = media.files[i]; 9456 9457 //split audio and images (assume there is equal number of audio and image files named the same in folder!) 9458 if(/audio/.test(entry.mimeType)){ 9459 mediaArr.push(entry); 9460 }else if(/image/.test(entry.mimeType)){ 9461 imgArr.push(entry); 9462 } 9463 } 9464 9465 if(data.sort){ 9466 if(data.sort == 'filename-asc'){ 9467 HAPUtils.keysrt(mediaArr, 'name'); 9468 if(imgArr.length)HAPUtils.keysrt(imgArr, 'name'); 9469 } 9470 else if(data.sort == 'filename-desc'){ 9471 HAPUtils.keysrt(mediaArr, 'name', true); 9472 if(imgArr.length)HAPUtils.keysrt(imgArr, 'name', true); 9473 } 9474 } 9475 9476 len = mediaArr.length; 9477 9478 for(i=0; i < len; i++){ 9479 9480 entry = mediaArr[i]; 9481 9482 obj = HAPUtils.extendObj(true, {}, data); 9483 obj.type = 'audio'; 9484 9485 obj.path = 'https://drive.google.com/uc?export=view&id='+entry.id 9486 9487 if(settings.createDownloadIconsInPlaylist){ 9488 if(!obj.download)obj.download = obj.path 9489 } 9490 9491 //if(!obj.share)obj.share = 'https://drive.google.com/open?id=' + entry.id; 9492 if(settings.createLinkIconsInPlaylist)if(!obj.link)obj.link = 'https://drive.google.com/open?id=' + entry.id; 9493 9494 if(!obj.thumb && imgArr[i])obj.thumb = 'https://drive.google.com/uc?export=view&id=' + imgArr[i].id; 9495 9496 if(!obj.title)obj.title = entry.name.substr(0, entry.name.lastIndexOf('.')); 9497 9498 playlistProcessData.push(obj); 9499 id3Counter++; 9500 9501 } 9502 9503 if(data.id3){ 9504 if(typeof jsmediatags === 'undefined'){ 9505 console.log('Link to jsmediatags.js missing in head tag!') 9506 checkProcessCounter(); 9507 }else{ 9508 getId3(); 9509 } 9510 }else{ 9511 checkProcessCounter(); 9512 } 9513 9514 } 9515 } 9516 xhrRequest.onerror = function(e) { 9517 console.log('Error processGDriveFolder: ' + e); 9518 checkProcessCounter(); 9519 }; 9520 xhrRequest.open('GET', url); 9521 xhrRequest.setRequestHeader("Content-Type", "application/json"); 9522 xhrRequest.send(); 9523 9524 } 9525 9526 function resumeFolderLoad(){ 9527 if(!nextPageToken)return false; 9528 9529 playlistTransitionOn = true; 9530 if(preloader)preloader.style.display = 'block'; 9531 playlistProcessData = nextPageToken.splice(0,resultLimit); 9532 if(nextPageToken.length == 0)nextPageToken = null; 9533 9534 //check id3 9535 if(useId3){ 9536 id3Start = -1; 9537 id3Counter = playlistProcessData.length-1; 9538 getId3(); 9539 }else{ 9540 buildPlaylist(); 9541 } 9542 9543 } 9544 9545 //############################################// 9546 /* id3 tags */ 9547 //############################################// 9548 9549 function getId3(){ 9550 /*https://github.com/aadsm/jsmediatags*/ 9551 9552 var item = playlistProcessData[id3Counter], 9553 url = item.path || item.mp3 || item.wav || item.aac; 9554 9555 if(useID3Cors)url = settings.cors + url 9556 9557 jsmediatags.read(url, { 9558 onSuccess: function(tag) { 9559 var tags = tag.tags, image = tags.picture; 9560 9561 if(tags.artist) item.artist = tags.artist; 9562 if(tags.title) item.title = tags.title; 9563 if(tags.album) item.album = tags.album; 9564 if(settings.getId3Image && image){ 9565 var base64String = "", i, len = image.data.length; 9566 for(i = 0; i < len; i++)base64String += String.fromCharCode(image.data[i]); 9567 item.thumb = "data:" + image.format + ";base64," + window.btoa(base64String); 9568 item.thumbIsBase64 = true; 9569 } 9570 if(tags.TLEN){//https://community.mp3tag.de/t/calculate-mp3-length/10145 9571 item.duration = tags.TLEN.data / 1000; 9572 } 9573 9574 id3Counter--; 9575 if(id3Counter > id3Start){ 9576 getId3(); 9577 }else{ 9578 if(loadMoreProcess){ 9579 buildPlaylist();//from resume folder load 9580 }else{ 9581 checkProcessCounter(); 9582 } 9583 9584 } 9585 9586 }, 9587 onError: function(error) { 9588 console.log("ID3 error: ", error.type, error.info); 9589 id3Counter--; 9590 if(id3Counter > id3Start){ 9591 getId3(); 9592 }else{ 9593 checkProcessCounter(); 9594 } 9595 } 9596 }); 9597 } 9598 9599 //############################################// 9600 /* onedrive folder */ 9601 //############################################// 9602 9603 function processOnedriveFolder(data){ 9604 9605 if(window.location.protocol == 'file:'){ 9606 console.log('Reading files from folders locally is not possible! This requires server connection.'); 9607 return false;
9608 } 9609 9610 var p = data.path 9611 if(p.indexOf('?') > -1)p = p.substr(0,p.indexOf('?')) 9612 var id = btoa(p); 9613 var url = 'https://api.onedrive.com/v1.0/shares/u!'+id+'/root?expand=children' 9614 9615 if(data.id3 && settings.cors){ 9616 id3Start = id3Counter = playlistProcessData.length-1; 9617 useId3 = true; 9618 useID3Cors = true; 9619 }else{ 9620 useId3 = false; 9621 useID3Cors = false; 9622 } 9623 9624 if(xhrRequest){ 9625 xhrRequest.abort(); 9626 xhrRequest = null; 9627 } 9628 9629 xhrRequest = new XMLHttpRequest(); 9630 xhrRequest.onreadystatechange = function() { 9631 if (xhrRequest.readyState == 4) { 9632 9633 var d = JSON.parse(xhrRequest.responseText) 9634 9635 var i, len = d.children.length, entry, obj, imgArr = [], mediaArr = []; 9636 9637 for(i=0; i < len; i++){ 9638 9639 entry = d.children[i]; 9640 9641 if(entry.file){ 9642 9643 if(/audio/.test(entry.file.mimeType)){ 9644 mediaArr.push(entry); 9645 }else if(/image/.test(entry.file.mimeType)){ 9646 imgArr.push(entry); 9647 } 9648 9649 if(data.sort == 'date-asc' || data.sort == 'date-desc'){ 9650 var date = new Date(entry.fileSystemInfo.lastModifiedDateTime); 9651 entry.fileSystemInfo.lastModifiedDateTime = date.getTime(); 9652 } 9653 else if(data.sort == 'created-date-asc' || data.sort == 'created-date-desc'){ 9654 var date = new Date(entry.fileSystemInfo.createdDateTime); 9655 entry.fileSystemInfo.createdDateTime = date.getTime(); 9656 } 9657 9658 } 9659 } 9660 9661 if(data.sort){ 9662 if(data.sort == 'filename-asc'){ 9663 HAPUtils.keysrt(mediaArr, 'name'); 9664 if(imgArr.length)HAPUtils.keysrt(imgArr, 'name'); 9665 } 9666 else if(data.sort == 'filename-desc'){ 9667 HAPUtils.keysrt(mediaArr, 'name', true); 9668 if(imgArr.length)HAPUtils.keysrt(imgArr, 'name', true); 9669 } 9670 else if(data.sort == 'date-asc'){ 9671 HAPUtils.keysrt2(mediaArr, 'fileSystemInfo', 'lastModifiedDateTime'); 9672 if(imgArr.length)HAPUtils.keysrt2(imgArr, 'fileSystemInfo', 'lastModifiedDateTime'); 9673 } 9674 else if(data.sort == 'date-desc'){ 9675 HAPUtils.keysrt2(mediaArr, 'fileSystemInfo', 'lastModifiedDateTime', true); 9676 if(imgArr.length)HAPUtils.keysrt2(imgArr, 'fileSystemInfo', 'lastModifiedDateTime', true); 9677 } 9678 else if(data.sort == 'created-date-asc'){ 9679 HAPUtils.keysrt2(mediaArr, 'fileSystemInfo', 'createdDateTime'); 9680 if(imgArr.length)HAPUtils.keysrt2(imgArr, 'fileSystemInfo', 'createdDateTime'); 9681 } 9682 else if(data.sort == 'created-date-desc'){ 9683 HAPUtils.keysrt2(mediaArr, 'fileSystemInfo', 'createdDateTime', true); 9684 if(imgArr.length)HAPUtils.keysrt2(imgArr, 'fileSystemInfo', 'createdDateTime', true); 9685 } 9686 } 9687 9688 len = mediaArr.length; 9689 9690 for(i=0; i < len; i++){ 9691 9692 entry = mediaArr[i]; 9693 9694 obj = HAPUtils.extendObj(true, {}, data); 9695 obj.type = 'audio'; 9696 9697 //meta 9698 if(entry.audio){ 9699 if(entry.audio.title)obj.title = entry.audio.title; 9700 if(entry.audio.artist)obj.artist = entry.audio.artist; 9701 if(entry.audio.duration)obj.duration = entry.audio.duration / 1000; 9702 if(entry.audio.genre)obj.genre = entry.audio.genre; 9703 if(entry.audio.album)obj.album = entry.audio.album; 9704 if(entry.audio.bitrate)obj.bitrate = entry.audio.bitrate; 9705 } 9706 9707 if(!obj.title)obj.title = entry.name.substr(0, entry.name.lastIndexOf('.')); 9708 9709 obj.path = entry['@content.downloadUrl'] 9710 9711 if(settings.createDownloadIconsInPlaylist){ 9712 if(!obj.download)obj.download = obj.path 9713 } 9714 9715 if(settings.createLinkIconsInPlaylist)if(!obj.link)obj.link = entry.webUrl; 9716 9717 if(!obj.thumb && imgArr[i])obj.thumb = imgArr[i]['@content.downloadUrl'] 9718 9719 playlistProcessData.push(obj); 9720 id3Counter++; 9721 9722 } 9723 9724 if(data.id3){ 9725 if(typeof jsmediatags === 'undefined'){ 9726 console.log('Link to jsmediatags.js missing in head tag!') 9727 checkProcessCounter(); 9728 }else{ 9729 getId3(); 9730 } 9731 }else{ 9732 checkProcessCounter(); 9733 } 9734 9735 } 9736 } 9737 xhrRequest.onerror = function(e) { 9738 console.log('Error processOnedriveFolder: ' + e); 9739 checkProcessCounter(); 9740 }; 9741 xhrRequest.open('GET', url); 9742 xhrRequest.setRequestHeader("Content-Type", "application/json"); 9743 xhrRequest.send(); 9744 9745 } 9746 9747 //############################################// 9748 /* accordion */ 9749 //############################################// 9750 9751 function getId3_all(){ 9752 9753 var item = playlistProcessData[id3Counter], 9754 url = item.path || item.mp3 || item.wav || item.aac; 9755 9756 jsmediatags.read(url, { 9757 onSuccess: function(tag) { 9758 var tags = tag.tags, image = tags.picture; 9759
9760 if(tags.artist) item.artist = tags.artist; 9761 if(tags.title) item.title = tags.title; 9762 if(tags.album) item.album = tags.album; 9763 if(settings.getId3Image && image){ 9764 var base64String = "", i, len = image.data.length; 9765 for(i = 0; i < len; i++)base64String += String.fromCharCode(image.data[i]); 9766 item.thumb = "data:" + image.format + ";base64," + window.btoa(base64String); 9767 item.thumbIsBase64 = true; 9768 } 9769 if(tags.TLEN){ 9770 item.duration = tags.TLEN.data / 1000; 9771 } 9772 9773 id3Counter--; 9774 if(id3Counter > id3Start){ 9775 getId3_all(); 9776 }else{ 9777 buildPlaylist(); 9778 } 9779 9780 }, 9781 onError: function(error) { 9782 console.log("ID3 error: ", error.type, error.info); 9783 id3Counter--; 9784 if(id3Counter > id3Start){ 9785 getId3_all(); 9786 }else{ 9787 buildPlaylist(); 9788 } 9789 } 9790 }); 9791 } 9792 9793 9794 //############################################// 9795 /* podcast */ 9796 //############################################// 9797 9798 function processPodcast(data){ 9799 9800 if(window.location.protocol == 'file:'){ 9801 console.log('Using Podcast requires server connection!'); 9802 return; 9803 } 9804 9805 if(data.limit){ 9806 resultLimit = data.limit; 9807 if(data.loadMore)loadMoreOnTotalScroll = true;//from addtrack 9808 }else{ 9809 resultLimit = allResults; 9810 } 9811 9812 var url = proxy + '?url='+ encodeURIComponent(data.path), limit = resultLimit, load_more_limit = resultLimit; 9813 9814 nextPageToken = []; 9815 9816 if(xhrRequest){ 9817 xhrRequest.abort(); 9818 xhrRequest = null; 9819 } 9820 9821 xhrRequest = new XMLHttpRequest(); 9822 xhrRequest.onreadystatechange = function() { 9823 if (xhrRequest.readyState == 4) { 9824 var media = xhrRequest.responseText 9825 9826 var rss = media.substr(media.indexOf('<?xml')); 9827 9828 rss = rss.substring(0,rss.indexOf('/rss>')+5); 9829 9830 rss = rss.replace(/(\\t|\\n|\\r)/gm, " "); 9831 9832 rss = rss.replace(/\\/g, ''); 9833 9834 var dom = HAPUtils.parseXML(rss), item, obj, default_artwork; 9835 9836 if(dom.getElementsByTagName('image') && dom.getElementsByTagName('image').length && dom.getElementsByTagName('image')[0].getAttribute('href')){ 9837 default_artwork = dom.getElementsByTagName('image')[0].getAttribute('href'); 9838 9839 }else if(dom.getElementsByTagName('itunes\:image') && dom.getElementsByTagName('itunes\:image').length && dom.getElementsByTagName('itunes\:image')[0].getAttribute('href')){ 9840 default_artwork = dom.getElementsByTagName('itunes\:image')[0].getAttribute('href'); 9841 } 9842 9843 if(default_artwork && default_artwork.lastIndexOf('&size=Large'))default_artwork = default_artwork.replace("=Large", "=Small"); 9844 9845 var arr = dom.getElementsByTagName("item"), zlen = 0; 9846 9847 var i, len = arr.length 9848 for(i = 0;i < len; i++){ 9849 item = arr[i] 9850 9851 //if(zlen >= limit) return false; 9852 9853 obj = HAPUtils.extendObj(true, {}, data); 9854 9855 obj.type = 'audio'; 9856 9857 obj.mp3 = item.getElementsByTagName('enclosure')[0].getAttribute('url'); 9858 9859 if(!obj.title){ 9860 var tt; 9861 if(item.getElementsByTagName('title').length)tt = item.getElementsByTagName('title')[0].innerHTML; 9862 else if(item.getElementsByTagName('itunes\:title').length) tt = item.getElementsByTagName('itunes\:title')[0].innerHTML; 9863 9864 if(tt){ 9865 if(tt.indexOf('[CDATA[') > -1){ 9866 tt = tt.replace("<![CDATA[", "").replace("]]>", ""); 9867 } 9868 obj.title = tt; 9869 } 9870 9871 } 9872 9873 if(!obj.artist){ 9874 var tt; 9875 if(item.getElementsByTagName('author').length)tt = item.getElementsByTagName('author')[0].innerHTML; 9876 else if(item.getElementsByTagName('itunes\:author').length) tt = item.getElementsByTagName('itunes\:author')[0].innerHTML; 9877 9878 if(tt){ 9879 if(tt.indexOf('[CDATA[') > -1){ 9880 tt = tt.replace("<![CDATA[", "").replace("]]>", ""); 9881 } 9882 obj.artist = tt; 9883 } 9884 9885 } 9886 9887 if(item.getElementsByTagName('pubDate'))obj.date = item.getElementsByTagName('pubDate')[0].innerHTML; 9888 9889 if(!obj.description && item.getElementsByTagName('description')){ 9890 var desc = item.getElementsByTagName('description')[0].innerHTML; 9891 var div = document.createElement("div"); 9892 div.innerHTML = desc; 9893 obj.description = div.textContent || div.innerText || ""; 9894 } 9895 if(!obj.duration){ 9896 var duration 9897 if(item.getElementsByTagName('itunes\:duration').length)duration = item.getElementsByTagName('itunes\:duration')[0].innerHTML; 9898 else if(item.getElementsByTagName('duration').length)duration = item.getElementsByTagName('duration')[0].innerHTML; 9899 9900 if(duration){ 9901 obj.duration = HAPUtils.hmsToSecondsOnly(duration) 9902 } 9903 } 9904 if(!obj.thumb){ 9905 if(item.getElementsByTagName('image').length && item.getElementsByTagName('image')[0].getAttribute('href')){ 9906 obj.thumb = item.getElementsByTagName('image')[0].getAttribute('href'); 9907 } 9908 else if(item.getElementsByTagName('itunes\:image').length && item.getElementsByTagName('itunes\:image')[0].getAttribute('href')){ 9909 obj.thumb = item.getElementsByTagName('itunes\:image')[0].getAttribute('href'); 9910 } 9911 else if(default_artwork){ 9912 obj.thumb = default_artwork; 9913 } 9914 } 9915 9916 if(obj.thumb && obj.thumb.lastIndexOf('&size=Large'))obj.thumb = obj.thumb.replace("=Large", "=Small"); 9917 9918 if(settings.createDownloadIconsInPlaylist)if(!obj.download)obj.download = obj.mp3; 9919 9920 if(!obj.link)if(settings.createLinkIconsInPlaylist){ 9921 if(item.getElementsByTagName('link').length){ 9922 var link = item.getElementsByTagName('link')[0]; 9923 obj.link = link?.firstChild?.wholeText?.trim(); 9924 } 9925 } 9926 9927 if(zlen < load_more_limit)playlistProcessData.push(obj); 9928 else nextPageToken.push(obj); 9929 9930 zlen++; 9931 9932 } 9933 9934 checkProcessCounter(); 9935 } 9936 } 9937 xhrRequest.onerror = function(e) { 9938 console.log('Error processPodcast: ' + e); 9939 checkProcessCounter(); 9940 }; 9941 xhrRequest.open('GET', url); 9942 xhrRequest.setRequestHeader("Content-Type", "text/xml"); 9943 xhrRequest.send(); 9944 9945 } 9946 9947 //############################################// 9948 /* itunes */ 9949 //############################################// 9950 9951 function processiTunes(data){ 9952 9953 if(window.location.protocol == 'file:'){ 9954 console.log('Using Podcast requires server connection!'); 9955 return; 9956 } 9957 9958 var match = data.path.match(/id(\d+)/); 9959 if (match) var podID = match[1]; 9960 //else var podID = url.match(/\d+/); 9961 9962 if(!podID){ 9963 console.log('No Podcast ID found!'); 9964 checkProcessCounter(); 9965 return; 9966 } 9967 9968 if(xhrRequest){ 9969 xhrRequest.abort(); 9970 xhrRequest = null; 9971 } 9972 9973 var url = 'https://itunes.apple.com/lookup'
9974 var params = 'id='+parseInt(podID)+'&entity=podcast'; 9975 9976 xhrRequest = new XMLHttpRequest(); 9977 xhrRequest.onreadystatechange = function() { 9978 if (xhrRequest.readyState == 4) { 9979 9980 var result = JSON.parse(xhrRequest.responseText) 9981 9982 //console.log(result) 9983 9984 data.path = result.results[0]['feedUrl']; 9985 processPodcast(data); 9986 9987 } 9988 } 9989 xhrRequest.onerror = function(e) { 9990 console.log('Error processItunes: ' + e); 9991 checkProcessCounter(); 9992 }; 9993 xhrRequest.open('POST', url); 9994 xhrRequest.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 9995 xhrRequest.send(params); 9996 9997 } 9998 9999 /////////////// 10000 10001 function resumePodcast(){ 10002 if(!nextPageToken)return false; 10003 10004 playlistTransitionOn = true; 10005 if(preloader)preloader.style.display = 'block'; 10006 playlistProcessData = []; 10007 playlistProcessData = nextPageToken.splice(0,resultLimit); 10008 if(nextPageToken.length == 0)nextPageToken = null; 10009 buildPlaylist(); 10010 } 10011 10012 function resumeSoundCloud(){ 10013 if(!nextPageToken)return false; 10014 10015 playlistTransitionOn = true; 10016 if(preloader)preloader.style.display = 'block'; 10017 playlistProcessData = []; 10018 playlistProcessData = nextPageToken.splice(0,resultLimit); 10019 if(nextPageToken.length == 0)nextPageToken = null; 10020 buildPlaylist(); 10021 10022 /*playlistTransitionOn = true; 10023 preloader.style.display = 'block'; 10024 playlistProcessCounter = 0; 10025 playlistProcessDataUrl = []; 10026 playlistLength = 1; 10027 10028 if(!window.SC){ 10029 initSoundCloud(); 10030 var interval = setInterval(function(){ 10031 if(soundCloudInited){ 10032 if(interval) clearInterval(interval); 10033 getSoundCloudPage(false, nextPageToken); 10034 } 10035 }, 100); 10036 }else{ 10037 getSoundCloudPage(false, nextPageToken); 10038 }*/ 10039 } 10040 10041 10042 10043 //############################################// 10044 /* build playlist */ 10045 //############################################// 10046 10047 function buildPlaylist() { 10048 10049 var counter, i, j = !addTrackProcess ? playlistDataArr.length : insertPosition, len = playlistProcessData.length, type, div, str, item_content, item_content_wrap, data, thumbsrc, thumbImg, playlistThumb, title, artist, img, alt, desc, descHtml, date, duration, counter_add = 0, currentInsert, playlist_data = [], icon_content; 10050 10051 lastPlaylistDataArr = []; 10052 10053 for (i=0; i < len; i++){ 10054 10055 counter = i+j; 10056 if(addTrackProcess)counter_add++; 10057 10058 if(playlistDataReady){ 10059 data = playlistProcessData[i].data; 10060 }else{ 10061 data = playlistProcessData[i]; 10062 } 10063 type = data.type; 10064 10065 if(settings.usePlaylist){ 10066 10067 if(data.type){ 10068 10069 icon_content = null; 10070 img = null; 10071 desc = null; 10072 descHtml = null; 10073 duration = null; 10074 date = null; 10075 10076 //thumb 10077 if(playlistItemContent.indexOf('thumb') != -1){ 10078 var thumb = data.thumbSmall || data.thumb || data.thumbDefault; 10079 10080 if(thumb){ 10081 10082 if(data.origtype == 'soundcloud'){ 10083 if(settings.soundCloudThumbQualityInPlaylist)thumb = thumb.replace('large.jpg', settings.soundCloudThumbQualityInPlaylist); 10084 } 10085 10086 if(mediaPrefixUrl && !data.thumbIsBase64 && !HAPUtils.relativePath(thumb))thumb = mediaPrefixUrl + thumb; 10087 10088 if(data.thumbAlt)alt = data.thumbAlt; 10089 else if(data.title)alt = data.title.replace(/"/g, "'"); 10090 else alt = 'image'; 10091 10092 img = '<img class="hap-thumbimg" src="'+thumb+'" alt="'+alt+'"/>'; 10093 10094 } 10095 } 10096 10097 //duration 10098 if(playlistItemContent.indexOf('duration') != -1 && data.duration){ 10099 if(isNaN(data.duration)){ 10100 if(data.duration.lastIndexOf(':')==-1)duration = HAPUtils.formatTime(data.duration); 10101 else duration = data.duration; 10102 }else{ 10103 duration = HAPUtils.formatTime(data.duration); 10104 } 10105 } 10106 10107 //date 10108 if(playlistItemContent.indexOf('date') != -1 && data.date){ 10109 date = new Date(data.date).toDateString().slice(4,10); 10110 } 10111 10112 if(nonProcessMedia.indexOf(data.origtype) != -1){ 10113 div = data.pi_item.cloneNode(true) 10114 }else{ 10115 if(!data.origclasses)data.origclasses = 'hap-playlist-item';//copy classes if exist 10116 div = HAPUtils.htmlToElement('<div class="'+data.origclasses+'"></div>'); 10117 delete data.origclasses; 10118 } 10119 10120 item_content_wrap = HAPUtils.htmlToElement('<div class="hap-playlist-item-wrap"></div>') 10121 div.prepend(item_content_wrap) 10122 10123 item_content = HAPUtils.htmlToElement('<div class="hap-playlist-item-content"></div>') 10124 item_content_wrap.prepend(item_content) 10125 10126 //thumb 10127 if(playlistItemContent.indexOf('thumb') != -1 && img){ 10128 var pt = '<div class="hap-playlist-thumb">'+img; 10129 10130 if(settings.togglePlaybackOnPlaylistItem)pt += '<div class="hap-playlist-thumb-style"></div>'; 10131 10132 pt += '</div>' 10133 10134 pt = HAPUtils.htmlToElement(pt) 10135 10136 item_content.append(pt) 10137 10138 if(!isMobile){ 10139 10140 pt.addEventListener('mouseenter', function (e) { 10141 overPlaylistItem(e) 10142 }, false); 10143 10144 pt.addEventListener('mouseleave', function (e) { 10145 outPlaylistItem(e) 10146 }, false); 10147 } 10148 10149 } 10150 10151 //title, description 10152 if(playlistItemContent.indexOf('title') != -1 || (playlistItemContent.indexOf('description') != -1 && data.description)){ 10153 10154 var info = HAPUtils.htmlToElement('<div class="hap-playlist-info">') 10155 item_content.append(info) 10156 10157 if(playlistItemContent.indexOf('title') != -1 && data.title){ 10158 10159 var par = '<div class="hap-playlist-title-wrap">'; 10160 10161 if(settings.useNumbersInPlaylist)par += '<div class="hap-playlist-title-num"></div>'; 10162 10163 if(data.artist && data.title){//both title and artist exist 10164 10165 if(playlistTitleOrder[0] == 'title'){ 10166 10167 par += '<div class="hap-playlist-title">'+data.title+'</div>'+settings.artistTitleSeparator+'<div class="hap-playlist-artist">'+data.artist+'</div>'; 10168 }else{ 10169 par += '<div class="hap-playlist-artist">'+data.artist+'</div>'+settings.artistTitleSeparator+'<div class="hap-playlist-title">'+data.title+'</div>'; 10170 } 10171 } 10172 else if(data.title){//only title 10173 par += '<div class="hap-playlist-title">'+data.title+'</div>'; 10174 } 10175 else if(data.artist){//only artist 10176 par += '<div class="hap-playlist-artist">'+data.artist+'</div>'; 10177 } 10178 10179 par += '</div>';//hap-playlist-title-wrap 10180 10181 par = HAPUtils.htmlToElement(par) 10182 10183 info.append(par) 10184 10185 if(!isMobile){ 10186 10187 par.addEventListener('mouseenter', function (e) { 10188 overPlaylistItem(e) 10189 }, false); 10190 10191 par.addEventListener('mouseleave', function (e) { 10192 outPlaylistItem(e) 10193 }, false); 10194 } 10195 10196 } 10197 10198 //description 10199 if(playlistItemContent.indexOf('description') != -1 && data.description){ 10200 10201 desc = data.description; 10202 10203 if(settings.limitDescriptionText && settings.limitDescriptionText != 0 && desc.length > parseInt(settings.limitDescriptionText,10)){ 10204 10205 if(settings.createReadMoreInDescription){ 10206 10207 var d1 = desc.substr(0,parseInt(settings.limitDescriptionText,10)), 10208 d2 = desc.substr(parseInt(settings.limitDescriptionText,10)) 10209 10210 desc = d1 + '<span class="hap-playlist-description-read-more-text hap-playlist-description-read-more-text-hidden">'+d2+'</span><span class="hap-playlist-description-read-more-dots">...</span> <span class="hap-playlist-description-read-more-btn" title="'+settings.limitDescriptionReadMoreText+'">'+settings.limitDescriptionReadMoreText+'</span>'; 10211 10212 }else{ 10213 10214 desc = desc.substr(0,parseInt(settings.limitDescriptionText,10)) + '...' 10215 10216 } 10217 10218 } 10219 //if(nonProcessMedia.indexOf(data.origtype) == -1){ 10220 info.append(HAPUtils.htmlToElement('<div class="hap-playlist-description">'+desc+'</div>')) 10221 10222 } 10223 } 10224 10225 //duration, date 10226 if(playlistItemContent.indexOf('duration') != -1 && data.duration || playlistItemContent.indexOf('date') != -1 && data.date){ 10227 10228 var info2 = HAPUtils.htmlToElement('<div class="hap-playlist-info2"></div>') 10229 item_content.append(info2) 10230 10231 if(playlistItemContent.indexOf('duration') != -1 && duration){ 10232 var dur1 = HAPUtils.htmlToElement('<div class="hap-playlist-duration">'+duration+'</div>') 10233 info2.append(dur1) 10234 } 10235 10236 if(playlistItemContent.indexOf('date') != -1 && date){ 10237 var date1 = HAPUtils.htmlToElement('<div class="hap-playlist-date">'+date+'</div>') 10238 info2.append(date1) 10239 } 10240 } 10241 10242 div.setAttribute('data-type', type); 10243 10244 //we need media-id, title, and artist for stats and api! 10245 if(data.mediaId != undefined){ 10246 div.setAttribute('data-media-id', data.mediaId); 10247 } 10248 if(data.title){ 10249 var st = data.title.replace(/['"\|\&]/g,''), 10250 tt = self.getTitle(data, true); 10251 10252 div.setAttribute('data-title', data.title) 10253 div.setAttribute('data-safe-title', st)//note: we have added this so we can have stats on grouped media with same media id! 10254 10255 data.safeTitle = st; 10256 } 10257 if(data.artist){ 10258 var sa = data.artist.replace(/['"\|\&]/g,''); 10259 div.setAttribute('data-artist', data.artist); 10260 div.setAttribute('data-safe-artist', sa) 10261 10262 data.safeArtist = sa; 10263 } 10264 if(data.description){ 10265 //div.append(HAPUtils.htmlToElement('<div class="hap-playlist-description-full">'+data.description+'</div>')) 10266 } 10267 10268 /*if(data.peaks != undefined){ 10269 div.setAttribute('data-peaks', data.peaks); 10270 }*/ 10271 10272 10273 if(settings.useStatistics && statisticsContent.length){ 10274 10275 var icon_content = HAPUtils.htmlToElement('<div class="hap-playlist-icons"></div>') 10276 item_content.after(icon_content) 10277 //icon_content = document.querySelector('<div class="hap-playlist-icons"></div>').insertAfter(item_content); 10278 10279 //statistics icons 10280 var stats = HAPUtils.htmlToElement('<div class="hap-stats"></div>');
10281 icon_content.prepend(stats); 10282 10283 if(statisticsContent.indexOf('plays') != -1){ 10284 var p = HAPUtils.htmlToElement('<div class="hap-stat-icon hap-play-count" title="'+settings.tooltipStatPlays+'">'+settings.statPlayIcon+'<span>0</span></div>'); 10285 stats.append(p); 10286 } 10287 10288 if(statisticsContent.indexOf('likes') != -1){ 10289 var p = HAPUtils.htmlToElement('<div class="hap-stat-icon hap-like-count" title="'+settings.tooltipStatLikes+'">'+settings.statLikeIcon+'<span>0</span></div>'); 10290 stats.append(p); 10291 } 10292 10293 if(statisticsContent.indexOf('downloads') != -1){ 10294 if(hasDownloadSupport && data.download != undefined){ 10295 10296 var p = HAPUtils.htmlToElement('<a href="#" class="hap-stat-icon hap-download-count" aria-label="'+settings.tooltipStatDownloads+'" title="'+settings.tooltipStatDownloads+'">'+settings.statDownloadIcon+'<span>0</span></a>'); 10297 10298 }else{ 10299 //if download not set on item still show download icon count? 10300 var p = HAPUtils.htmlToElement('<div class="hap-stat-icon hap-download-count hap-no-download" title="'+settings.tooltipStatDownloads+'">'+settings.statDownloadIcon+'<span>0</span></div>'); 10301 } 10302 stats.append(p); 10303 10304 }else{ 10305 10306 //download icon 10307 /*if(hasDownloadSupport && data.download){ 10308 10309 icon_content = document.querySelector('<div class="hap-playlist-icons"></div>').appendTo(div); 10310 10311 icon_content.prepend(getDownloadIcon(data)); 10312 }*/ 10313 10314 } 10315 10316 }else{ 10317 10318 //download icon 10319 if(hasDownloadSupport && data.download){ 10320 10321 var icon_content = HAPUtils.htmlToElement('<div class="hap-playlist-icons"></div>') 10322 item_content.after(icon_content) 10323 10324 icon_content.insertAdjacentHTML('afterbegin', getDownloadIcon(data)); 10325 } 10326 10327 } 10328 10329 10330 if(data.playlistIcons){ 10331 10332 if(!icon_content){ 10333 var icon_content = HAPUtils.htmlToElement('<div class="hap-playlist-icons"></div>') 10334 item_content.after(icon_content) 10335 } 10336 10337 var j, pi_len = data.playlistIcons.length, pi_obj, cl 10338 for(j = 0; j < pi_len; j++){ 10339 pi_obj = data.playlistIcons[j] 10340 10341 if(pi_obj.icon){ 10342 10343 if(pi_obj.class)cl = ' '+pi_obj.class 10344 else cl = '' 10345 10346 var ci = '<a class="hap-playlist-icon'+cl+'"' 10347 if(pi_obj.url)ci += ' href="'+pi_obj.url+'"' 10348 if(pi_obj.target)ci += ' target="'+pi_obj.target+'"' 10349 if(pi_obj.title)ci += ' title="'+pi_obj.title+'"' 10350 if(pi_obj.rel)ci += ' rel="'+pi_obj.rel+'"' 10351 ci += '>'+pi_obj.icon+'</a>'; 10352 10353 } 10354 10355 icon_content.insertAdjacentHTML("beforeend",ci); 10356 } 10357 } 10358 10359 10360 10361 10362 //link icon 10363 if(data.link){ 10364 10365 if(!icon_content){ 10366 var icon_content = HAPUtils.htmlToElement('<div class="hap-playlist-icons"></div>') 10367 item_content.after(icon_content) 10368 } 10369 10370 icon_content.insertAdjacentHTML("beforeend",getLinkIcon(data)); 10371 } 10372 10373 10374 //variations, create icons if added dynamically 10375 if(div.querySelector(".hap-audio-variations")){ 10376 10377 var variations = div.querySelector(".hap-audio-variations"); 10378 if(variations.querySelectorAll('.hap-audio-variation')){ 10379 10380 variations.querySelectorAll('.hap-audio-variation').forEach(div => { 10381 10382 var item = div 10383 10384 if(item.getAttribute('data-download') || item.getAttribute('data-link')){ 10385 var vstr = '<div class="hap-playlist-icons">' 10386 10387 if(item.getAttribute('data-download')){ 10388 vstr += getDownloadIcon({download: item.getAttribute('data-download')}) 10389 } 10390 if(item.getAttribute('data-link')){ 10391 vstr += getLinkIcon({link: item.getAttribute('data-link'), target: item.getAttribute('data-target'), rel: item.getAttribute('data-rel')}) 10392 } 10393 10394 vstr += '</div>' 10395 10396 item.insertAdjacentHTML("beforeend",vstr) 10397 10398 } 10399 10400 }); 10401 10402 } 10403 } 10404 10405 10406 10407 10408 10409 10410 10411 if(!addTrackProcess){ 10412 playlistContent.append(div) 10413 }else{ 10414 if(!currentInsert){ 10415 if(endInsert){ 10416 playlistContent.append(div); 10417 }else{ 10418 var de = playlistContent.querySelectorAll('.hap-playlist-item')[insertPosition] 10419 de.before(div); 10420 } 10421 }else{ 10422 currentInsert.after(div); 10423 } 10424 currentInsert = div; 10425 } 10426 10427 } 10428 else{//copy directly to playlist 10429 10430 div = data; 10431 10432 if(!addTrackProcess){ 10433 playlistContent.append(div); 10434 }else{ 10435 if(!currentInsert){ 10436 if(endInsert){ 10437 playlistContent.append(div); 10438 }else{ 10439 var de = playlistContent.querySelectorAll('.hap-playlist-item')[insertPosition] 10440 de.before(div); 10441 } 10442 }else{ 10443 currentInsert.after(div); 10444 } 10445 currentInsert = div; 10446 } 10447 10448 } 10449 10450 10451 } 10452 else{//no playlist 10453 10454 if(settings.useStatistics){ 10455 10456 if(data.mediaId != undefined){ 10457 if(data.title){ 10458 var st = data.title.replace(/['"\|\&]/g,''); 10459 data.safeTitle = st; 10460 } 10461 if(data.artist){ 10462 var sa = data.artist.replace(/['"\|\&]/g,''); 10463 data.safeArtist = sa; 10464 } 10465 } 10466 } 10467 10468 } 10469 10470 if(playlistId != undefined)data.playlistId = playlistId; 10471 10472 if(accordionMode)playlist_data.push({id: i, type: type, data: data}); 10473 else playlistDataArr.splice(counter, 0, {id: counter, type: type, data: data}); 10474 10475 lastPlaylistDataArr.push({id: counter, type: type, data: data}); 10476 10477 } 10478 10479 if(accordionMode){ 10480 10481 settings.usePlaylistScroll = false;
10482 10483 if(!settings.allowOnlyOneOpenedAccordion)playlistFilterMsg.classList.add('hap-force-hidden')//we cant use nothing found msg with multi opened accordions 10484 10485 if(playlistInner)playlistInner.classList.add('hap-accordion') 10486 10487 //############################################// 10488 /* accordion */ 10489 //############################################// 10490 10491 playlistDataAccordion[accordionActiveId].data = playlist_data;//save all accordion data (when we click other acordion item, we change data) 10492 10493 //only first time accordion is created, next time we switch playlist only when song is clicked in other accordion 10494 10495 if(!accordionInited){ 10496 playlistDataArr = playlist_data;//current accordion playlist data 10497 10498 updatePlaylist(true); 10499 if(settings.useStatistics)updateStats(); 10500 10501 _HAPPlaylistManager.setPlaylistItems(playlistLength);//we treat each accordion as new playlist 10502 10503 }else{ 10504 updatePlaylist(false); 10505 if(settings.useStatistics)updateStats(); 10506 } 10507 10508 endInit(); 10509 10510 //open accordion item 10511 var content = accordionHolder; 10512 setTimeout(function(){ 10513 content.style.height = content.scrollHeight + "px"; 10514 },200) 10515 10516 10517 10518 10519 accordionLoading = false;//set accordion item loaded 10520 10521 accordionInited = true; 10522 10523 //############################################// 10524 /* accordion */ 10525 //############################################// 10526 10527 }else{ 10528 10529 if(playlistInner)playlistInner.classList.remove('hap-accordion') 10530 10531 lastPlaylist = playlistContent; 10532 10533 //console.log('playlistDataArr = ', playlistDataArr); 10534 10535 updatePlaylist(true); 10536 if(settings.useStatistics)updateStats(); 10537 10538 10539 10540 10541 if(!addTrackProcess){ 10542 _HAPPlaylistManager.setPlaylistItems(playlistLength); 10543 }else{ 10544 var current_counter = _HAPPlaylistManager.getCounter(); 10545 _HAPPlaylistManager.setPlaylistItems(playlistLength, false); 10546 10547 if(insertPosition <= current_counter){ 10548 if(!endInsert)_HAPPlaylistManager.reSetCounter(current_counter+counter_add); 10549 } 10550 10551 if(addTrackPlayit)_HAPPlaylistManager.setCounter(insertPosition, false); 10552 10553 isEnqueue = false; 10554 } 10555 10556 endInit(); 10557 10558 } 10559 10560 } 10561 10562 function getDownloadIcon(data){ 10563 10564 var d = '<a class="hap-playlist-icon hap-download" href="'+data.download+'" download title="'+settings.downloadIconTitle+'" aria-label="'+settings.downloadIconTitle+'">'+settings.downloadIcon+'</a>'; 10565 10566 return d; 10567 } 10568 function getLinkIcon(data){ 10569 10570 var target = data.target || '_blank', 10571 rel = data.rel || 'nofollow'; 10572 10573 var d = '<a class="hap-playlist-icon hap-link" href="'+data.link+'" target="'+target+'" title="'+settings.linkIconTitle+'" aria-label="'+settings.linkIconTitle+'" rel="'+rel+'">'+settings.linkIcon+'</a>'; 10574 10575 return d; 10576 } 10577 10578 //############################################// 10579 /* accordion */ 10580 //############################################// 10581 10582 function checkAccordion(holder){//check accordion item when its clicked first time 10583 10584 if(preloader)preloader.style.display = 'block'; 10585 10586 accordionActiveId = holder.getAttribute('data-id'); 10587 accordionHolder = holder.classList.add('hap-accordion-item-inited'); 10588 accordionHolder = holder.querySelector('.hap-accordion-item-content'); 10589 10590 playlistContent = accordionHolder;//current accordion playlist 10591 playlistProcessData = playlistDataAccordion[accordionActiveId].media; 10592 10593 if(accordionUseId3){//load id3 tags 10594 id3Start = -1; 10595 id3Counter = playlistProcessData.length-1; 10596 getId3_all(); 10597 }else{//we dont use id3 tags 10598 buildPlaylist(); 10599 } 10600 } 10601 10602 function buildAccordion(arr, data){//make accordion parents 10603 10604 var i, len = arr.length, str = '', title; 10605 10606 for(i=0; i < len; i++){ 10607 title = arr[i].parent.replace(/"/g, "'"); 10608 10609 if(data.activeAccordion !== 'undefined'){//active folder on start 10610 if(data.activeAccordion == title)accordionActiveId = i; 10611 } 10612 10613 str += '<div class="hap-accordion-item" data-id="'+i+'" title="'+title+'"><span class="hap-accordion-item-title">'+title+'</span>'+ 10614 '<div class="hap-accordion-item-content">'; 10615 if(arr[i].description)str += '<span class="hap-accordion-item-description">'+arr[i].description+'</span>'; 10616 str += '</div>'+ 10617 '</div>'; 10618 } 10619 10620 playlistContent.innerHTML = str; 10621 10622 } 10623 10624 //############################################// 10625 /* accordion */ 10626 //############################################// 10627 10628 function updatePlaylist(update_playlist_data){ 10629 if(update_playlist_data)playlistLength = playlistDataArr.length; 10630 10631 if(settings.usePlaylist){ 10632 10633 var i = 0, item, num, stat_arr = [], title_node; 10634 10635 var div_list = playlistContent.querySelectorAll('.hap-playlist-item').forEach(div => { 10636 10637 item = div 10638 item.setAttribute('data-id', i); 10639 10640 title_node = item.querySelector('.hap-playlist-title'); 10641 10642 if(title_node){ 10643 10644 if(settings.useNumbersInPlaylist){//append counter 10645 num = HAPUtils.formatNumber(i) + settings.numberTitleSeparator; 10646 if(item.querySelector('.hap-playlist-title-num')){//if already exist 10647 item.querySelector('.hap-playlist-title-num').innerHTML = num; 10648 }else{ 10649 10650 var tn = HAPUtils.htmlToElement('<div class="hap-playlist-title-num">
10650'+num+'</div>') 10651 title_node.before(tn) 10652 10653 //title_node.before(document.querySelector('<div class="hap-playlist-title-num">'+num+'</div>')); 10654 } 10655 } 10656 10657 } 10658 10659 if(update_playlist_data)playlistDataArr[i].id = i; 10660 10661 i++; 10662 }); 10663 10664 } 10665 10666 } 10667 10668 function updateStats(){ 10669 10670 var i, item, stat_arr = [], mid; 10671 10672 for(i = 0;i < playlistLength; i++){ 10673 item = playlistDataArr[i].data; 10674 item.id = i; 10675 10676 if(!item.hapStatsSet){ 10677 mid = item.mediaId != undefined ? item.mediaId : null; 10678 stat_arr.push({media_id: mid, title: item.safeTitle || item.title || '', artist: item.safeArtist || item.artist || ''}); 10679 item.hapStatsSet = true; 10680 } 10681 } 10682 10683 if(stat_arr.length)getStats('hap_all_count', null, stat_arr); 10684 10685 } 10686 10687 function checkPlaylistScroll(elem){ 10688 10689 if(settings.playlistScrollType == 'perfect-scrollbar'){ 10690 10691 if(typeof PerfectScrollbar !== 'function'){ 10692 10693 var script = document.createElement('script'); 10694 script.type = 'text/javascript'; 10695 script.src = HAPUtils.qualifyURL(settings.sourcePath+settings.perfectScrollbar_js); 10696 script.onload = script.onreadystatechange = function() { 10697 if(!this.readyState || this.readyState == 'complete'){ 10698 checkPlaylistScroll(elem); 10699 } 10700 }; 10701 script.onerror = function(){ 10702 alert("Error loading " + this.src); 10703 } 10704 var tag = document.getElementsByTagName('script')[0]; 10705 tag.parentNode.insertBefore(script, tag); 10706 10707 }else{ 10708 10709 playlistScroll = new PerfectScrollbar(elem, { 10710 wheelSpeed: 2, 10711 wheelPropagation: true, 10712 minScrollbarLength: 30 10713 }); 10714 10715 var event = settings.playlistScrollOrientation == 'horizontal' ? 'ps-x-reach-end' : 'ps-y-reach-end' 10716 10717 elem.addEventListener(event, () => { 10718 10719 if(loadMoreOnTotalScroll){ 10720 if(nextPageToken && loadMoreType){ 10721 if(!playlistTransitionOn){ 10722 10723 playlistTransitionOn = true; 10724 if(preloader)preloader.style.display = 'block'; 10725 loadMoreProcess = true; 10726 playlistProcessData = []; 10727 if(loadMoreBtn)loadMoreBtn.style.opacity = 0; 10728 10729 if(loadMoreType == 'soundcloud'){ 10730 resumeSoundCloud(); 10731 }else if(loadMoreType == 'podcast'){ 10732 resumePodcast(); 10733 }else if(loadMoreType == 'folder'){ 10734 resumeFolderLoad(); 10735 }else if(loadMoreType == 'youtube'){ 10736 if(!_HAPYoutubeLoader)createLoader('youtube'); 10737 _HAPYoutubeLoader.resumeLoad(nextPageToken); 10738 } 10739 } 10740 } 10741 }else if(addMoreOnTotalScroll){ 10742 if(!loadMoreProcess){ 10743 addMore(); 10744 } 10745 } 10746 10747 }); 10748 10749 10750 } 10751 10752 }else if(settings.playlistScrollType == 'browser'){ 10753 10754 var cl = settings.playlistScrollOrientation == 'horizontal' ? 'hap-playlist-overflow-x' : 'hap-playlist-overflow-y' 10755 10756 playlistInner.classList.add(cl) 10757 10758 } 10759 10760 } 10761 10762 function endInit(){ 10763 10764 if(preloader)preloader.style.display = 'none'; 10765 playlistTransitionOn = false; 10766 if(settings.autoResumeAfterAdd != undefined)return; 10767 10768 if(!componentInited){ 10769 componentInited = true; 10770 10771 if(settings.placeHolderThumb){ 10772 setThumb(settings.placeHolderThumb) 10773 } 10774 10775 10776 10777 //playlist global data 10778 10779 if(playlistData){ 10780 10781 if(playlistData.getAttribute('data-use-pagination') != undefined){//has to be here because savePagination needs build playlist items 10782 paginationTotalPages = Math.ceil(addMoreNumResults / addMoreLimit); 10783 10784 if (addMoreNumResults > addMoreLimit){ 10785 paginationCurrentPage = 0; 10786 createPagination(paginationCurrentPage); 10787 10788 var i,obj; 10789 for(i = 0;i<paginationTotalPages;i++){ 10790 obj = i == 0 ? {page:0} : {page:null}//first page is already available 10791 paginationArr.push(obj); 10792 } 10793 savePagination(paginationCurrentPage); 10794 10795 } 10796 } 10797 } 10798 10799 10800 //read more playlist desc 10801 if(settings.createReadMoreInDescription){ 10802 onHandler(playlistContent, 'click', '.hap-playlist-description-read-more-btn', (e) => handleReadMore(e)) 10803 } 10804 10805 10806 if(settings.useStickyPlayer && settings.clonePlaylistInFixedPlayer){ 10807 var cp = playlistContent.cloneNode(true) 10808 _HAPStickyPlayer.clonePlaylist(cp) 10809 checkPlaylistScroll(_HAPStickyPlayer.getPlaylist()); 10810 } 10811 10812 if(settings.usePlaylistScroll && !playlistScrollInit){//was calling total scroll event (and calling add more) so we put it here 10813 if(playlistInner)checkPlaylistScroll(playlistInner); 10814 playlistScrollInit = true; 10815 } 10816 10817 10818 10819 10820 10821 setTimeout(function(){ 10822 if(!settings.hidePlayerUntilMusicStart){ 10823 10824 checkPresetMods(); 10825 10826 if(settings.addResizeEvent)doneResizing(); 10827 10828 if(playerOuter){ 10829 setTimeout(function(){ 10830 playerOuter.style.opacity = 1; 10831 },50); 10832 } 10833 10834 } 10835 10836 self.fireEvent('setupDone', [{instance:self, instanceName:settings.instanceName}]); 10837 10838 },100); 10839 10840 10841 10842 10843 10844 if(accordionMode){ 10845 10846 lastOpenedAccordion = wrapper.querySelectorAll('.hap-accordion-item')[accordionActiveId]; 10847 10848 wrapper.querySelectorAll('.hap-accordion-item-title').forEach(function(el){ 10849 10850 el.addEventListener('click', function(e){ 10851 10852 var parent = e.currentTarget.closest('.hap-accordion-item'); 10853 10854 if(parent.classList.contains('hap-accordion-item-opened')){ 10855 parent.classList.remove('hap-accordion-item-opened'); 10856 var content = parent.querySelector('.hap-accordion-item-content') 10857 content.style.height = "0"; 10858 }else{ 10859 //close other opened if new is clicked 10860 if(settings.allowOnlyOneOpenedAccordion){ 10861 if(lastOpenedAccordion && lastOpenedAccordion != parent){ 10862 10863 lastOpenedAccordion.classList.remove('hap-accordion-item-opened'); 10864 var content = lastOpenedAccordion.querySelector('.hap-accordion-item-content') 10865 content.style.height = "0"; 10866 10867 //show hidden tracks from search 10868 var div_list = document.querySelectorAll('.hap-playlist-item').forEach(div => { 10869 div.style.display = 'block'; 10870 }) 10871 10872 } 10873 } 10874 10875 //reset search 10876 if(searchSelector)searchSelector.value = ''; 10877 if(playlistFilterMsg)playlistFilterMsg.style.display = 'none'; 10878 10879 10880 if(parent.classList.contains('hap-accordion-item-inited')){ 10881 var content = parent.querySelector('.hap-accordion-item-content') 10882 content.style.height = content.scrollHeight + "px"; 10883 }else{ 10884 if(accordionLoading)return false;
10885 accordionLoading = true; 10886 checkAccordion(parent); 10887 } 10888 10889 lastOpenedAccordion = parent 10890 lastOpenedAccordion.classList.add('hap-accordion-item-opened'); 10891 10892 } 10893 10894 10895 }); 10896 10897 }); 10898 10899 } 10900 10901 } 10902 10903 if(settings.usePlaylist && playlistLength > 0){ 10904 10905 if(settings.usePlaylistScroll && settings.playlistScrollType == 'perfect-scrollbar'){ 10906 if(playlistScroll)playlistScroll.update() 10907 } 10908 10909 10910 10911 //fade thumbs 10912 var fadeArr = []; 10913 10914 var div_list = playlistContent.querySelectorAll('.hap-thumbimg:not(.hap-visible)').forEach(div => { 10915 fadeArr.push(div); 10916 }); 10917 10918 var p=0, len = fadeArr.length, z; 10919 for(z=0;z<len;z++){ 10920 setTimeout(function(){ 10921 clearTimeout(this); 10922 fadeArr[p].classList.add('hap-visible'); 10923 p++; 10924 },50 + ( z * 50 )); 10925 } 10926 10927 if(!accordionMode && !HAPUtils.isEmpty(sortOrder))self.sort(sortOrder);//sort on start 10928 10929 } 10930 10931 if(!playlistInitLoad){//only after destroy playlist, not after add media 10932 playlistInitLoad = true; 10933 10934 if(!addTrackProcess && !loadMoreProcess && playlistLength > 0){ 10935 10936 if(settings.mediaId != undefined && !HAPUtils.isEmpty(settings.mediaId)){ 10937 10938 if(settings.mediaTitle){//used when we share song url from processed media 10939 var pi = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+settings.mediaId+'"][data-safe-title="'+settings.mediaTitle+'"]');//if we have title 10940 10941 if(!pi){//if fails 10942 var pi = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+settings.mediaId+'"]'); 10943 } 10944 10945 delete settings.mediaTitle; 10946 }else{ 10947 var pi = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+settings.mediaId+'"]'); 10948 } 10949 10950 var index = getElementIndex(playlistContent, pi, '.hap-playlist-item'); 10951 10952 if(index == undefined || index == -1){ 10953 alert('No media with ID to load! LoadMedia failed.'); 10954 return false; 10955 } 10956 10957 delete settings.mediaId; 10958 _HAPPlaylistManager.processPlaylistRequest(index); 10959 10960 }else{ 10961 10962 if(activeMediaId != null){ 10963 var pi = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+activeMediaId+'"]'); 10964 if(pi){ 10965 var ai = pi.getAttribute('data-id'); 10966 activeMediaId = null; 10967 }else{ 10968 var ai = 0 10969 } 10970 }else{ 10971 var ai = settings.activeItem; 10972 } 10973 if(ai > playlistLength-1)ai = playlistLength-1; 10974 if(ai>-1)_HAPPlaylistManager.setCounter(ai, false); 10975 10976 } 10977 10978 } 10979 /*else if(playlistDataReady){//load song into connected player on start 10980 var ai = settings.activeItem; 10981 if(ai > playlistLength-1)ai = playlistLength-1; 10982 if(ai>-1)_HAPPlaylistManager.setCounter(ai, false); 10983 }*/ 10984 } 10985 10986 addTrackProcess = false; 10987 loadMoreProcess = false; 10988 10989 if(loadMoreBtn){ 10990 if(loadMoreOnTotalScroll){ 10991 if(nextPageToken){ 10992 loadMoreBtn.style.opacity = 1; 10993 }else{ 10994 loadMoreBtn.remove(); 10995 loadMoreBtn = null; 10996 loadMoreOnTotalScroll = false; 10997 } 10998 }else if(addMoreOnTotalScroll){ 10999 if(addMoreNumResults > 0){ 11000 if(addMoreNumResults > addMoreOffset){ 11001 loadMoreBtn.style.opacity = 1; 11002 }else{ 11003 loadMoreBtn.remove(); 11004 loadMoreBtn = null; 11005 addMoreOnTotalScroll = false; 11006 } 11007 }else{ 11008 loadMoreBtn.remove(); 11009 loadMoreBtn = null; 11010 } 11011 }else{ 11012 loadMoreBtn.remove(); 11013 loadMoreBtn = null; 11014 } 11015 } 11016 11017 self.fireEvent('playlistEndLoad', [{instance:self, instanceName:settings.instanceName, loadMoreOnTotalScroll:loadMoreOnTotalScroll, addMoreOnTotalScroll:addMoreOnTotalScroll, playlistLength: playlistLength}]); 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 } 11029 11030 function handleReadMore(e){ 11031 11032 var btn = e.target, 11033 parent = btn.closest('.hap-playlist-description'), 11034 moreText = parent.querySelector('.hap-playlist-description-read-more-text'), 11035 dots = parent.querySelector('.hap-playlist-description-read-more-dots') 11036 11037 if(dots.style.display == 'none'){ 11038 //all text shown, hide it 11039 btn.innerHTML = settings.limitDescriptionReadMoreText; 11040 btn.setAttribute('title', settings.limitDescriptionReadMoreText) 11041 dots.style.display = 'inline' 11042 11043 moreText.classList.add('hap-playlist-description-read-more-text-hidden') 11044 11045 }else{ 11046 btn.innerHTML = settings.limitDescriptionReadLessText; 11047 btn.setAttribute('title', settings.limitDescriptionReadLessText) 11048 dots.style.display = 'none' 11049 11050 moreText.classList.remove('hap-playlist-description-read-more-text-hidden') 11051 11052 } 11053 } 11054 11055 //############################################// 11056 /* hls */ 11057 //############################################// 11058 11059 var recoverMediaErrorDate, 11060 swapAudioCodecDate 11061 11062 function initHls(){ 11063 11064 if(settings.hlsConfig){ 11065 hls = new Hls(settings.hlsConfig); 11066 }else{ 11067 hls = new Hls(); 11068 } 11069 11070 hlsSupport = Hls.isSupported(); 11071 hlsInited = true; 11072
11073 hls.on(Hls.Events.MEDIA_ATTACHED, function () { 11074 //console.log("video and hls.js are now bound together !"); 11075 hls.loadSource(mediaPath); 11076 }); 11077 11078 hls.on(Hls.Events.ERROR, function (event, data) { 11079 if(data.fatal){ 11080 switch(data.type) { 11081 case Hls.ErrorTypes.NETWORK_ERROR: 11082 // try to recover network error 11083 console.log("fatal network error encountered, try to recover"); 11084 hls.startLoad(); 11085 break; 11086 case Hls.ErrorTypes.MEDIA_ERROR: 11087 console.log("fatal media error encountered, try to recover"); 11088 //hls.recoverMediaError(); 11089 11090 var now = performance.now(); 11091 if (!recoverMediaErrorDate || now - recoverMediaErrorDate > 3000) { 11092 recoverMediaErrorDate = performance.now(); 11093 hls.recoverMediaError(); 11094 } else if (!swapAudioCodecDate || (now - swapAudioCodecDate) > 3000) { 11095 swapAudioCodecDate = performance.now(); 11096 hls.swapAudioCodec(); 11097 hls.recoverMediaError(); 11098 } 11099 11100 break; 11101 default: 11102 // cannot recover 11103 hls.destroy(); 11104 break; 11105 } 11106 } 11107 }); 11108 11109 } 11110 11111 //############################################// 11112 /* audio player */ 11113 //############################################// 11114 11115 function getAudioUrl(data){ 11116 11117 var url 11118 11119 if(mediaType == 'hls'){ 11120 11121 url = data.path; 11122 11123 } 11124 else{ 11125 11126 if(settings.useAudioPreview && data.audioPreview){ 11127 url = data.audioPreview; 11128 }else{ 11129 11130 if(mp3Support && data.mp3){ 11131 url = data.mp3; 11132 } 11133 else if(aacSupport && data.aac){ 11134 url = data.aac; 11135 } 11136 else if(wavSupport && data.wav){ 11137 url = data.wav; 11138 } 11139 else if(flacSupport && data.flac){ 11140 url = data.flac; 11141 } 11142 else if(data.path){ 11143 url = data.path; 11144 } 11145 } 11146 11147 } 11148 11149 if(!url){ 11150 console.log('No required audio format supplied! Please add mp3 audio format to play!'); 11151 return; 11152 } 11153 11154 if(url.indexOf(bsf_match) != -1)url = HAPUtils.b64DecodeUnicode(url.substr(6)); 11155 11156 if(mediaType == 'audio' && mediaPrefixUrl && !HAPUtils.relativePath(url))url = mediaPrefixUrl + url; 11157 11158 if(isSafari && settings.applySafariAudioRestartFix)url += "?rand=" + (Math.random() * 99999999) 11159 11160 return url; 11161 11162 } 11163 11164 function initAudio(){ 11165 11166 if(mediaType == 'hls'){ 11167 11168 if(!hlsInited){ 11169 11170 if(typeof Hls === 'undefined'){ 11171 11172 var script = document.createElement('script'); 11173 script.type = 'text/javascript'; 11174 script.src = hls_js; 11175 script.onload = script.onreadystatechange = function() { 11176 if(!this.readyState || this.readyState == 'complete'){ 11177 initHls(); 11178 initAudio(); 11179 } 11180 }; 11181 script.onerror = function(){ 11182 alert("Error loading " + this.src); 11183 } 11184 var tag = document.getElementsByTagName('script')[0]; 11185 tag.parentNode.insertBefore(script, tag); 11186 11187 }else{ 11188 initHls(); 11189 initAudio(); 11190 } 11191 return; 11192 } 11193 11194 } 11195 11196 audioReady = false; 11197 11198 if(!audioInited){ 11199 audioInited = true; 11200 11201 audio.addEventListener("ended", function(){ 11202 if(activeAudio != audio)return; 11203 11204 if(!crossFadeOn){ 11205 handleAudioEnded() 11206 } 11207 11208 }) 11209 audio.addEventListener("loadedmetadata", function(){ 11210 if(activeAudio != audio)return; 11211 11212 handleAudioLoadedmetadata() 11213 11214 }) 11215 audio.addEventListener("canplay", function(){ 11216 if(activeAudio != audio)return; 11217 11218 handleAudioCanplay() 11219 }) 11220 audio.addEventListener("canplaythrough", function(){ 11221 if(activeAudio != audio)return; 11222 11223 }) 11224 audio.addEventListener("play", function(){ 11225 if(activeAudio != audio)return; 11226 11227 handleAudioPlay() 11228 }) 11229 audio.addEventListener("pause", function(){ 11230 if(activeAudio != audio)return; 11231 11232 handleAudioPause() 11233 }) 11234 audio.addEventListener("seeked", function(){ 11235 if(activeAudio != audio)return; 11236 11237 handleAudioSeeked() 11238 }) 11239 audio.addEventListener("error", function(e){ 11240 if(activeAudio != audio)return; 11241 11242 handleAudioError(e) 11243 11244 }); 11245 11246 11247 if(settings.useCrossFade){ 11248 11249 audio2.addEventListener("ended", function(){ 11250 if(activeAudio != audioUp2Js2)return; 11251 11252 if(!crossFadeOn){ 11253 handleAudioEnded() 11254 } 11255 11256 }) 11257 audio2.addEventListener("loadedmetadata", function(){ 11258 if(activeAudio != audioUp2Js2)return; 11259 11260 handleAudioLoadedmetadata() 11261 11262 }) 11263 audio2.addEventListener("canplay", function(){ 11264 if(activeAudio != audioUp2Js2)return; 11265 11266 handleAudioCanplay() 11267 }) 11268 audio2.addEventListener("canplaythrough", function(){ 11269 if(activeAudio != audioUp2Js2)return; 11270 11271 }) 11272 audio2.addEventListener("play", function(){ 11273 if(activeAudio != audioUp2Js2)return; 11274 11275 handleAudioPlay() 11276 }) 11277 audio2.addEventListener("pause", function(){ 11278 if(activeAudio != audioUp2Js2)return; 11279 11280 handleAudioPause() 11281 }) 11282 audio2.addEventListener("seeked", function(){ 11283 if(activeAudio != audioUp2Js2)return; 11284 11285 handleAudioSeeked() 11286 }) 11287 audio2.addEventListener("error", function(e){ 11288 if(activeAudio != audioUp2Js2)return; 11289 11290 handleAudioError(e) 11291 11292 }); 11293 11294 } 11295 11296 } 11297 11298 11299 if(mediaType == 'hls'){ 11300 11301 if(window.location.protocol == 'file:'){ 11302 console.log('Playing HLS requires server connection!'); 11303 return false;
11304 } 11305 11306 if(hlsSupport){ 11307 hls.attachMedia(activeAudio); 11308 }else if(activeAudio.canPlayType('application/vnd.apple.mpegurl')){//ios backup 11309 11310 if(useBlob){ 11311 11312 if(bUrlIntervalID){ 11313 clearInterval(bUrlIntervalID); 11314 bUrlIntervalID = null; 11315 } 11316 self.getBUrl(mediaPath); 11317 bUrlIntervalID = setInterval(function(){ 11318 if(bUrl){ 11319 clearInterval(bUrlIntervalID); 11320 bUrlIntervalID = null; 11321 11322 activeAudio.src = bUrl; 11323 11324 } 11325 },100); 11326 11327 }else{ 11328 activeAudio.src = mediaPath; 11329 } 11330 11331 }else if(currMediaData.mp3){ 11332 11333 if(useBlob){ 11334 11335 if(bUrlIntervalID){ 11336 clearInterval(bUrlIntervalID); 11337 bUrlIntervalID = null; 11338 } 11339 self.getBUrl(currMediaData.mp3); 11340 bUrlIntervalID = setInterval(function(){ 11341 if(bUrl){ 11342 clearInterval(bUrlIntervalID); 11343 bUrlIntervalID = null; 11344 11345 activeAudio.src = bUrl; 11346 11347 } 11348 },100); 11349 11350 }else{ 11351 activeAudio.src = currMediaData.mp3; 11352 } 11353 11354 }else{ 11355 console.log("This browser or device does not support HLS extension. Please use mp3 audio for playback!"); 11356 return; 11357 } 11358 11359 if(autoPlay){ 11360 var promise = activeAudio.play(); 11361 if (promise !== undefined) { 11362 promise.then(function(){ 11363 }).catch(function(error){ 11364 }); 11365 } 11366 } 11367 11368 }else{ 11369 11370 if(useBlob && (currMediaData.origtype == 'audio')){ 11371 11372 if(bUrlIntervalID){ 11373 clearInterval(bUrlIntervalID); 11374 bUrlIntervalID = null; 11375 } 11376 self.getBUrl(mediaPath); 11377 bUrlIntervalID = setInterval(function(){ 11378 if(bUrl){ 11379 clearInterval(bUrlIntervalID); 11380 bUrlIntervalID = null; 11381 11382 activeAudio.src = bUrl; 11383 11384 } 11385 },100); 11386 11387 }else{ 11388 activeAudio.src = mediaPath; 11389 } 11390 11391 if(autoPlay){ 11392 var promise = activeAudio.play(); 11393 if (promise !== undefined) { 11394 promise.then(function(){ 11395 }).catch(function(error){ 11396 }); 11397 } 11398 } 11399 11400 } 11401 11402 activeAudio.volume = settings.volume; 11403 11404 autoPlay = true; 11405 settings.autoPlay = true; 11406 11407 //10.3.2020 - added this here because there is a lot of delay on ios 11408 11409 if(dataIntervalID) clearInterval(dataIntervalID); 11410 dataIntervalID = setInterval(trackProgress, dataInterval); 11411 11412 } 11413 11414 //############################################// 11415 /* media events */ 11416 //############################################// 11417 11418 function handleAudioEnded(){ 11419 if(useRange && rangeOn && !rangeSet && !_HAPRangeSlider.isDrag()){ 11420 rangeSet = true; 11421 activeAudio.currentTime = range_a_time; 11422 11423 var promise = activeAudio.play(); 11424 if (promise !== undefined) { 11425 promise.then(function(){ 11426 }).catch(function(error){ 11427 }); 11428 } 11429 11430 return; 11431 } 11432 mediaEndHandler(); 11433 } 11434 11435 function handleAudioLoadedmetadata(){ 11436 setTimeout(function(){ 11437 if(!audioReady){ 11438 handleAudioCanplay() 11439 } 11440 },1000); 11441 } 11442 11443 function handleAudioCanplay(){ 11444 if(!audioReady){ 11445 11446 audioReady = true; 11447 11448 try{ 11449 activeAudio.playbackRate = Number(settings.playbackRate); 11450 }catch(er){} 11451 11452 //set visible duration 11453 var d = activeAudio.duration; 11454 11455 if(HAPUtils.isNumber(d)){ 11456 if(mediaTimeTotal)mediaTimeTotal.innerHTML = HAPUtils.formatTime(d); 11457 11458 if(useRange){ 11459 rangeMinTime.innerHTML = '00:00'; 11460 rangeMaxTime.innerHTML = HAPUtils.formatTime(d); 11461 } 11462 11463 } 11464 11465 if(settings.resumeTime){//from continous playback 11466 activeAudio.currentTime = settings.resumeTime; 11467 delete settings.resumeTime; 11468 } 11469 else if(currMediaData.start){ 11470 activeAudio.currentTime = currMediaData.start; 11471 } 11472 11473 } 11474 else{ 11475 if(settings.resumeTime){ 11476 activeAudio.currentTime = settings.resumeTime; 11477 delete settings.resumeTime; 11478 } 11479 } 11480 } 11481 11482 function handleAudioPlay(){ 11483 playHandler(); 11484 } 11485 11486 function handleAudioPause(){ 11487 pauseHandler(); 11488 } 11489 11490 function handleAudioSeeked(){ 11491 if(useRange && rangeOn){ 11492 setTimeout(function(){ 11493 clearTimeout(this); 11494 rangeSet = false; 11495 },500); 11496 } 11497 if(videoSync){ 11498 if(!syncComingFromVideo)videoSync.currentTime = activeAudio.currentTime 11499 syncComingFromVideo = false; 11500 } 11501 } 11502 11503 function handleAudioError(e){ 11504 console.log(activeAudio.error); 11505 11506 if(currMediaData.origtype && currMediaData.origtype == 'soundcloud'){ 11507 11508 if(activeAudio.currentTime)settings.resumeTime = activeAudio.currentTime 11509 11510 _scLoader.resume() 11511 11512 }else if((currMediaData.origtype == 's3_bucket_audio' || currMediaData.origtype == 's3_audio') && activeAudio.error && activeAudio.error.message && activeAudio.error.message.indexOf('PIPELINE_ERROR_READ') > -1){ 11513 11514 if(activeAudio.currentTime)settings.resumeTime = activeAudio.currentTime 11515 11516 resumeAwsUrl(currMediaData) 11517 11518 }else{ 11519 11520 self.fireEvent('soundError', [{instance:self, instanceName:settings.instanceName, media:currMediaData, error:e}]); 11521 if(settings.autoAdvanceToNextSongOnError)self.nextMedia() 11522 } 11523 11524 /*switch (e.target.error.code) { 11525 case e.target.error.MEDIA_ERR_ABORTED: 11526 console.log('You aborted the video playback.'); 11527 break; 11528 case e.target.error.MEDIA_ERR_NETWORK: 11529 console.log('A network error caused the audio download to fail.'); 11530 break; 11531 case e.target.error.MEDIA_ERR_DECODE: 11532 console.log('The audio playback was aborted due to a corruption problem or because the video used features your browser did not support.'); 11533 break; 11534 case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
11535 console.log('The video audio not be loaded, either because the server or network failed or because the format is not supported.'); 11536 break; 11537 default: 11538 console.log('An unknown error occurred.'); 11539 break; 11540 }*/ 11541 } 11542 11543 function cancelCrossFadeSeek(){//cancel when seeking (seek, seek forward / backward) 11544 11545 isCancelCrossFade = true; 11546 crossFadeOn = false; 11547 11548 if(audio.c_active){ 11549 if(audioUp2Js2){ 11550 audioUp2Js2.pause(); 11551 audioUp2Js2.src = ''; 11552 } 11553 } 11554 else { 11555 if(audio){ 11556 audio.pause(); 11557 audio.src = ''; 11558 } 11559 11560 audioUp2Js2.c_active = false; 11561 audio.c_active = true; 11562 activeAudio = audio; 11563 } 11564 11565 nextMediaData = null;//we have to kill crossfade otherwise it hard to manage all 11566 11567 setTimeout(function(){ 11568 isCancelCrossFade = false;//wait till ramp ends 11569 },1000) 11570 11571 } 11572 11573 function cancelCrossFadeAdvance(){//cancel when advancing (next, previous, click playlist item) 11574 11575 isCancelCrossFade = true; 11576 crossFadeOn = false; 11577 11578 if(audio){ 11579 audio.pause(); 11580 audio.src = ''; 11581 } 11582 11583 if(audioUp2Js2){ 11584 audioUp2Js2.pause(); 11585 audioUp2Js2.src = ''; 11586 } 11587 11588 audio.c_active = true; 11589 audioUp2Js2.c_active = false; 11590 11591 activeAudio = audio; 11592 11593 nextMediaData = null; 11594 11595 } 11596 11597 function initCrossFade(next_url, t, d){ 11598 11599 var active_a = audio.c_active ? audio : audioUp2Js2, 11600 next_active_a = !audio.c_active ? audio : audioUp2Js2; 11601 11602 var fade_time = d - t;//if user seeks into fade time 11603 11604 fadeOutAudio(active_a, 0, fade_time) 11605 fadeInAudio(next_active_a, next_url, settings.volume, fade_time) 11606 11607 } 11608 11609 function fadeInAudio(audiox, url, targetVolume, fade_time) { 11610 11611 if(!targetVolume) { 11612 targetVolume = 1; 11613 } 11614 11615 var rampTime = fade_time * 1000 11616 11617 // How often adjust audio volume (ms) 11618 var tick = 50; 11619 11620 var volumeIncrease = targetVolume / (rampTime / tick); 11621 11622 function ramp() { 11623 if(isCancelCrossFade)return 11624 11625 var vol = Math.min(targetVolume, audiox.volume + volumeIncrease); 11626 11627 audiox.volume = vol; 11628 11629 // Have we reached target volume level yet? 11630 if(audiox.volume < targetVolume) { 11631 // Keep up going until 11 11632 setTimeout(ramp, tick); 11633 }else{ 11634 11635 var interval = setInterval(function(){ 11636 if(fadeOutAudioComplete){//after clean media 11637 clearInterval(interval); 11638 11639 comingFromCrossFade = true; 11640 mediaEndHandler(); 11641 11642 if(audio.c_active){ 11643 audio.c_active = false; 11644 audioUp2Js2.c_active = true; 11645 11646 activeAudio = audioUp2Js2 11647 }else{ 11648 audio.c_active = true; 11649 audioUp2Js2.c_active = false; 11650 11651 activeAudio = audio 11652 } 11653 11654 crossFadeOn = false; 11655 11656 } 11657 }, 100); 11658 11659 } 11660 } 11661 11662 function startRampUp() { 11663 // For now, we capture only the first playing event 11664 // as we assume the user calls fadeIn() 11665 // every time when wants to resume playback 11666 audiox.removeEventListener("playing", startRampUp); 11667 11668 ramp(); 11669 11670 } 11671 11672 // Start with zero audio level 11673 audiox.volume = 0; 11674 11675 // Start volume ramp up when the audio actually stars to play (not when begins to buffer, etc.) 11676 audiox.addEventListener("playing", startRampUp); 11677 11678 audiox.src = url 11679 11680 if(isIOS)audiox.load() 11681 11682 var promise = audiox.play(); 11683 if (promise !== undefined) { 11684 promise.then(function(){ 11685 }).catch(function(error){ 11686 console.log(error) 11687 }); 11688 } 11689 }; 11690 11691 function fadeOutAudio(audiox, targetVolume, fade_time) { 11692 11693 fadeOutAudioComplete = false; 11694 11695 var originalVolume = audiox.volume; 11696 11697 if(!targetVolume) { 11698 targetVolume = 0; 11699 } 11700 11701 var rampTime = fade_time * 1000 11702 11703 // How often adjust audio volume (ms) 11704 var tick = 50; 11705 11706 var volumeStep = (audiox.volume - targetVolume) / (rampTime / tick); 11707 11708 if(!volumeStep) { 11709 // Volume already at 0 11710 return; 11711 } 11712 11713 function ramp() { 11714 if(isCancelCrossFade)return 11715 11716 var vol = Math.max(0, audiox.volume - volumeStep); 11717 11718 audiox.volume = vol; 11719 11720 // Have we reached target volume level yet? 11721 if(audiox.volume > targetVolume) { 11722 // Keep up going until 11 11723 setTimeout(ramp, tick); 11724 } else { 11725 audiox.pause(); 11726 11727 fadeOutAudioComplete = true; 11728 11729 // Reset audio volume so audio can be played again 11730 audiox.volume = originalVolume; 11731 } 11732 } 11733 11734 ramp(); 11735 }; 11736 11737 //############################################// 11738 /* */ 11739 //############################################// 11740 11741 function trackProgress(){ 11742 11743 if(seekBarDown)return;//for performance 11744 if(_HAPAdManager && _HAPAdManager.isAdOn()){ 11745 if(settings.pauseAudioDuringAds){ 11746 return; 11747 }else{ 11748 if(_HAPAdManager.isAdPreOn() || _HAPAdManager.isAdEndOn()) return; 11749 } 11750 } 11751 if(_HAPAdManager && _HAPAdManager.isAdOn()) return; 11752 if(isIma && isImaOn)return; 11753 11754 11755 var loadPercent; 11756 11757 if(mediaType == 'youtube'){ 11758 11759 if(youtubePlayer){ 11760 var t = youtubePlayer.getCurrentTime(), d = youtubePlayer.getDuration(); 11761 loadPercent = youtubePlayer.getVideoLoadedFraction(); 11762 } 11763 11764 }else{ 11765 11766 if(activeAudio){ 11767 11768 var t = activeAudio.currentTime, d = activeAudio.duration; 11769 11770 if(HAPUtils.isNumber(t) && HAPUtils.isNumber(d)){ 11771 11772 if(typeof activeAudio.buffered !== 'undefined' && activeAudio.buffered.length != 0) { 11773 try{ 11774 var bufferedEnd = activeAudio.buffered.end(activeAudio.buffered.length - 1); 11775 }catch(error){} 11776 if(!isNaN(bufferedEnd)){ 11777 var loadPercent = bufferedEnd / d; 11778 } 11779 } 11780 } 11781 11782 if(settings.useCrossFade && !isCancelCrossFade && !seekBarDown && settings.volume != 0 && !rangeOn && !activeVariation){ 11783 11784 if(!crossFadeOn && (t + Number(settings.crossFadeTime) > d)){ 11785 11786 if(!nextDataCheck){ 11787 nextMediaData = null; 11788 nextDataCheck = true; 11789 11790 //que here, not on song start, because if search active or next song gets removed before it comes time to play it 11791 11792 if(settings.usePlaylist && isSearchActive){ 11793 11794 var current = playlistContent.querySelector('.hap-playlist-item-selected'), 11795 next = current.nextAll('.hap-playlist-item:not(.hap-filter-hidden)').filter(':first') 11796 if(next){ 11797 var c = next.getAttribute('data-id') 11798 _HAPPlaylistManager.queNext('pick', c); 11799 }
11800 else{//no more in search, try to advance normally 11801 _HAPPlaylistManager.queNext('advance', 1); 11802 } 11803 11804 }else{ 11805 _HAPPlaylistManager.queNext('advance', 1); 11806 } 11807 11808 } 11809 11810 if(nextMediaData){ 11811 11812 //start crossfade 11813 crossFadeOn = true; 11814 11815 if(nextMediaData.type == 's3_audio'){ 11816 11817 s3UrlReady = false; 11818 getAwsUrl(nextMediaData) 11819 11820 var interval = setInterval(function(){ 11821 if(s3UrlReady){ 11822 if(interval) clearInterval(interval); 11823 initCrossFade(s3UrlReady, t, d); 11824 } 11825 }, 100); 11826 11827 11828 }else if(nextMediaData.origtype && nextMediaData.origtype == 'soundcloud'){ 11829 11830 scUrlReady = false; 11831 _scLoader.get_stream_url(currMediaData.sc_data.id) 11832 11833 var interval = setInterval(function(){ 11834 if(scUrlReady){ 11835 if(interval) clearInterval(interval); 11836 initCrossFade(scUrlReady, t, d); 11837 } 11838 }, 100); 11839 11840 }else{ 11841 var next_url = getAudioUrl(nextMediaData) 11842 11843 initCrossFade(next_url, t, d); 11844 11845 } 11846 11847 } 11848 } 11849 } 11850 } 11851 11852 } 11853 11854 if(HAPUtils.isNumber(t) && HAPUtils.isNumber(d)){ 11855 11856 11857 11858 if(!startEventDone){ 11859 if(t > 0 && mediaPlaying){ 11860 startEventDone = true; 11861 self.fireEvent("soundPlay", [{instance:self, instanceName:settings.instanceName, media:currMediaData}]); 11862 } 11863 } 11864 11865 if(settings.useWaveSeekbar){ 11866 11867 if(peakData)seekbarWaveProgress.style.width = (t / d)*100 + '%'; 11868 11869 }else{ 11870 11871 if(circleSeekbar){ 11872 _HAPCirclePlayer.drawSeekbar(loadPercent,t,d); 11873 }else{ 11874 if(progressLevel)progressLevel.style.width = ((t / d) * seekBarSize) + 'px'; 11875 if(loadLevel)if(loadPercent)loadLevel.style.width = (loadPercent * seekBarSize) + 'px'; 11876 } 11877 11878 } 11879 11880 if(settings.useInlineSeekbar){ 11881 var is = inlineSeekbar.querySelector('.hap-inline-seekbar-progress') 11882 is.style.width = (t / d) * parseInt(inlineSeekbar.offsetWidth,10) + 'px' 11883 } 11884 11885 var current_time = HAPUtils.formatTime(t), 11886 total_time = HAPUtils.formatTime(d) 11887 11888 if(mediaTimeCurrent)mediaTimeCurrent.innerHTML = current_time; 11889 if(mediaTimeTotal)mediaTimeTotal.innerHTML = total_time; 11890 11891 if(currMediaData.end || (currMediaData.lockTime && !allowedViewVideoUserRole)){ 11892 var et = currMediaData.end || currMediaData.lockTime; 11893 11894 if(t >= et){ 11895 if(currMediaData.lockTime){ 11896 if(dataIntervalID) clearInterval(dataIntervalID); 11897 dataIntervalID = null; 11898 toggleRedirectLoginScreen('watch'); 11899 }else{ 11900 mediaEndHandler(); 11901 } 11902 return; 11903 } 11904 } 11905 11906 11907 //fixed 11908 if(settings.useStickyPlayer && window['hap_fixed_active_player'] == settings.instanceName){ 11909 if(mediaStarted && mediaPlaying)_HAPStickyPlayer.setProgressData(t / d, null, current_time, total_time, d) 11910 } 11911 11912 11913 if(useRange && rangeOn && !rangeSet && !_HAPRangeSlider.isDrag()){ 11914 if(parseInt(t,10) < parseInt(range_a_time,10) || t > range_b_time){ 11915 rangeSet = true; 11916 self.seek(range_a_time); 11917 return; 11918 } 11919 } 11920 11921 //lyrics 11922 if(currMediaData.lyrics && _lyrics && lyricsReady && lyricsOpened && mediaPlaying){ 11923 _lyrics.synchronize(t) 11924 } 11925 11926 } 11927 } 11928 11929 function playHandler(){ 11930 11931 if(!mediaStarted){ 11932 mediaStarted = true; 11933 11934 if(!circleSeekbar){ 11935 if(settings.useWaveSeekbar){ 11936 if(seekbarWave)seekBarSize = seekbarWave.offsetWidth; 11937 }else{ 11938 if(progressBg)seekBarSize = progressBg.offsetWidth; 11939 } 11940 } 11941 11942 self.fireEvent("soundStart", [{instance:self, instanceName:settings.instanceName, media:currMediaData}]); 11943 11944 //############################################// 11945 /* ads */ 11946 //############################################// 11947 if(currMediaData.adMid){ 11948 _HAPAdManager.adMidStartHandler(); 11949 } 11950 //############################################// 11951 /* ads */ 11952 //############################################// 11953 11954 11955 if(settings.useGlobalDownloadButton && currMediaData.download){ 11956 11957 if(!globalDownloadBtn){ 11958 globalDownloadBtn = HAPUtils.htmlToElement('<a class="hap-contr-btn hap-global-download-btn" href="'+currMediaData.download+'" download data-tooltip="'+settings.downloadIconTitle+'" aria-label="'+settings.downloadIconTitle+'">'+settings.downloadIcon+'</a>') 11959 11960 if(!isMobile){ 11961 globalDownloadBtn.addEventListener('mouseenter', overControls); 11962 globalDownloadBtn.addEventListener('mouseleave', outControls); 11963 } 11964 }else{ 11965 globalDownloadBtn.setAttribute('href', currMediaData.download) 11966 } 11967 11968 globalDownloadBtn.style.display = 'block'; 11969 setTimeout(function(){ 11970 globalDownloadBtn.classList.add('hap-btn-show') 11971 },20) 11972 11973 if(settings.globalDownloadBtnSelector){ 11974 if(wrapper.querySelector(settings.globalDownloadBtnSelector)){ 11975 wrapper.querySelector(settings.globalDownloadBtnSelector).prepend(globalDownloadBtn) 11976 } 11977 } 11978 else if(class_list.indexOf('hap-brona') > -1){ 11979 wrapper.querySelector('.hap-controls-right').prepend(globalDownloadBtn) 11980 } 11981 else if(class_list.indexOf('hap-epic') > -1){
11982 wrapper.querySelector('.hap-player-controls-right').prepend(globalDownloadBtn) 11983 } 11984 else if(class_list.indexOf('hap-art-wide') > -1){ 11985 wrapper.querySelector('.hap-player-controls-right').prepend(globalDownloadBtn) 11986 } 11987 else if(class_list.indexOf('hap-art-narrow') > -1){ 11988 wrapper.querySelector('.hap-top-bar-controls-right').prepend(globalDownloadBtn) 11989 } 11990 else if(class_list.indexOf('hap-metalic') > -1){ 11991 wrapper.querySelector('.hap-bottom-bar-controls').prepend(globalDownloadBtn) 11992 } 11993 else if(class_list.indexOf('hap-modern') > -1){ 11994 wrapper.querySelector('.hap-bottom-bar-controls').prepend(globalDownloadBtn) 11995 } 11996 else if(class_list.indexOf('hap-wave') > -1){ 11997 wrapper.querySelector('.hap-player-controls-right').prepend(globalDownloadBtn) 11998 } 11999 else if(class_list.indexOf('hap-fixed') > -1){ 12000 wrapper.querySelector('.hap-playlist-bar-controls-right').prepend(globalDownloadBtn) 12001 } 12002 else if(class_list.indexOf('hap-fixed2') > -1){ 12003 wrapper.querySelector('.hap-playlist-bar-controls-right').prepend(globalDownloadBtn) 12004 } 12005 12006 } 12007 12008 } 12009 12010 if(settings.useStickyPlayer){//needs to be here, becuase if we have 2 players in page and we just press play between them, sticky player has to change active song data 12011 12012 window['hap_fixed_active_player'] = settings.instanceName 12013 12014 if(waveformLoading){ 12015 //wait for waveform to load so we can give to sticky player 12016 12017 if(waveformLoadingInterval)clearInterval(waveformLoadingInterval) 12018 12019 waveformLoadingInterval = setInterval(function(){ 12020 if(!waveformLoading && currMediaData.peaks){ 12021 12022 clearInterval(waveformLoadingInterval); 12023 waveformLoadingInterval = null; 12024 12025 _HAPStickyPlayer.setData({ 12026 inst: settings.instanceName, 12027 media: currMediaData, 12028 volume: settings.volume, 12029 playlistData: playlistDataArr 12030 }) 12031 } 12032 }, 100); 12033 12034 }else{ 12035 12036 _HAPStickyPlayer.setData({ 12037 inst: settings.instanceName, 12038 media: currMediaData, 12039 volume: settings.volume, 12040 playlistData: playlistDataArr 12041 }) 12042 12043 } 12044 12045 } 12046 12047 12048 //############################################// 12049 /* ads */ 12050 //############################################// 12051 if(currMediaData.adMid){ 12052 _HAPAdManager.adMidPlayHandler(); 12053 } 12054 //############################################// 12055 /* ads */ 12056 //############################################// 12057 12058 12059 if(settings.useStickyPlayer && window['hap_fixed_active_player'] == settings.instanceName){ 12060 _HAPStickyPlayer.setPauseBtn() 12061 } 12062 12063 if(settings.togglePlaybackOnPlaylistItem && activePlaylistItem)activePlaylistItem.querySelector('.hap-playlist-thumb-style')?.classList.add('hap-playlist-thumb-style-pause') 12064 12065 if(settings.togglePlaybackOnMultipleInstances){ 12066 if(ap_mediaArr.length > 1){ 12067 var i, len = ap_mediaArr.length; 12068 for(i=0;i<len;i++){ 12069 if(self != ap_mediaArr[i].inst){ 12070 ap_mediaArr[i].inst.pauseMedia(); 12071 } 12072 } 12073 } 12074 } 12075 12076 if(videoSync){ 12077 if(!syncComingFromVideo){ 12078 var promise = videoSync.play(); 12079 if (promise !== undefined) { 12080 promise.then(function(){ 12081 }).catch(function(error){ 12082 }); 12083 } 12084 } 12085 syncComingFromVideo = false; 12086 } 12087 12088 if(startEventDone){//first time this is done in trackprogress after time is > 0 12089 self.fireEvent("soundPlay", [{instance:self, instanceName:settings.instanceName, media:currMediaData}]); 12090 } 12091 12092 if(playbackToggle)self.toggleBigPlay(true) 12093 12094 //preset mods 12095 if(class_list.indexOf('hap-fixed')>-1 || class_list.indexOf('hap-fixed2')>-1)setExternalIconData(true); 12096 12097 if(playbackToggleIndicator){ 12098 playbackToggleIndicator.querySelector('.hap-btn-play').style.display = 'none' 12099 playbackToggleIndicator.querySelector('.hap-btn-pause').style.display = 'block' 12100 } 12101 12102 mediaPlaying = true; 12103 12104 if(settings.autoPlayAfterFirst){ 12105 autoPlay = true; 12106 settings.autoPlay = true; 12107 } 12108 12109 if(settings.hidePlayerUntilMusicStart)unhidePlayer(); 12110 12111 if(useGa && typeof gtag !== "undefined"){ 12112 12113 gtag('event', 'play', { 12114 'send_to': settings.gaTrackingId, 12115 'event_category': "Modern audio player: " + settings.instanceName, 12116 eventLabel: 'title: ' + self.getTitle(currMediaData, true) + ' | time: ' + Math.round(self.getCurrentTime()), 12117 'non_interaction': true 12118 }); 12119 } 12120 12121 } 12122 12123 function pauseHandler(){ 12124 12125 if(crossFadeOn)return; 12126 12127 if(playbackToggle)self.toggleBigPlay() 12128 12129 //preset mods 12130 if(class_list.indexOf('hap-fixed')>-1 || class_list.indexOf('hap-fixed2')>-1)setExternalIconData(); 12131 12132 if(playbackToggleIndicator){ 12133 playbackToggleIndicator.querySelector('.hap-btn-play').style.display = 'block' 12134 playbackToggleIndicator.querySelector('.hap-btn-pause').style.display = 'none' 12135 } 12136 12137 if(videoSync){ 12138 if(!syncComingFromVideo)videoSync.pause() 12139 syncComingFromVideo = false;
12140 } 12141 12142 if(settings.useStickyPlayer && window['hap_fixed_active_player'] == settings.instanceName){ 12143 _HAPStickyPlayer.setPlayBtn() 12144 } 12145 12146 if(settings.togglePlaybackOnPlaylistItem && activePlaylistItem)activePlaylistItem.querySelector('.hap-playlist-thumb-style')?.classList.remove('hap-playlist-thumb-style-pause') 12147 12148 mediaPlaying = false; 12149 self.fireEvent("soundPause", [{instance:self, instanceName:settings.instanceName, media:currMediaData}]); 12150 12151 if(useGa && typeof gtag !== "undefined"){ 12152 12153 gtag('event', 'pause', { 12154 'send_to': settings.gaTrackingId, 12155 'event_category': "Modern audio player: " + settings.instanceName, 12156 eventLabel: 'title: ' + self.getTitle(currMediaData, true) + ' | time: ' + Math.round(self.getCurrentTime()), 12157 'non_interaction': true 12158 }); 12159 } 12160 12161 } 12162 12163 function mediaEndHandler(){ 12164 12165 //variations 12166 if(hasVariation && settings.playVariationInSequence){ 12167 12168 if(activeVariation){ 12169 12170 var next = getNextSibling(activeVariation); 12171 12172 if(next){ 12173 next.click() 12174 return; 12175 } 12176 12177 }else{ 12178 //play first variation 12179 var ti = activePlaylistItem.querySelectorAll('.hap-audio-variation')[0] 12180 tu.querySelector('.hap-audio-variation').click() 12181 return; 12182 } 12183 } 12184 12185 12186 12187 if(_HAPAdManager)_HAPAdManager.clearAdMidTimeout(); 12188 12189 self.fireEvent('soundEnd', [{instance:self, instanceName:settings.instanceName, media:currMediaData}]); 12190 12191 if(settings.useStatistics)getStats('hap_finish_count', mediaCounter); 12192 12193 if(useGa && typeof gtag !== "undefined"){ 12194 12195 gtag('event', 'end', { 12196 'send_to': settings.gaTrackingId, 12197 'event_category': "Modern audio player: " + settings.instanceName, 12198 eventLabel: 'title: ' + self.getTitle(currMediaData, true), 12199 'non_interaction': true 12200 }); 12201 } 12202 12203 12204 if(currMediaData.adEnd){ 12205 12206 //############################################// 12207 /* ads */ 12208 //############################################// 12209 12210 _HAPAdManager.initAd('end'); 12211 12212 //############################################// 12213 /* ads */ 12214 //############################################// 12215 12216 }else if(isIma){ 12217 12218 _IMALoader.contentComplete() 12219 12220 }else{ 12221 if(!settings.stopOnSongEnd){ 12222 audioEndedAction(); 12223 } 12224 } 12225 12226 } 12227 12228 function audioEndedAction(reset_src){ 12229 12230 var st = currMediaData.start || 0; 12231 12232 if(settings.loopState == 'single'){ 12233 12234 if(!reset_src)beforeSongAdvanceAction();//only is main media plays, not ad 12235 12236 if(mediaType == 'youtube'){ 12237 if(youtubePlayer){ 12238 youtubePlayer.seekTo(st); 12239 youtubePlayer.playVideo(); 12240 } 12241 }else{ 12242 if(reset_src){//if coming from end ad 12243 12244 if(useBlob && (currMediaData.origtype == 'audio')){ 12245 12246 if(bUrlIntervalID){ 12247 clearInterval(bUrlIntervalID); 12248 bUrlIntervalID = null; 12249 } 12250 self.getBUrl(mediaPath); 12251 bUrlIntervalID = setInterval(function(){ 12252 if(bUrl){ 12253 clearInterval(bUrlIntervalID); 12254 bUrlIntervalID = null; 12255 12256 activeAudio.src = bUrl; 12257 12258 } 12259 },100); 12260 12261 }else{ 12262 activeAudio.src = mediaPath; 12263 } 12264 12265 } 12266 12267 activeAudio.currentTime = st; 12268 12269 var promise = activeAudio.play(); 12270 if (promise !== undefined) { 12271 promise.then(function(){ 12272 }).catch(function(error){ 12273 }); 12274 } 12275 } 12276 12277 }else if(settings.loopState == 'off' || settings.loopState == 'playlist'){ 12278 self.nextMedia(); 12279 } 12280 12281 } 12282 12283 function cleanMedia(){ 12284 12285 waveformDataAws2 = null; 12286 12287 if(xhrRequest_remoteDownload){ 12288 xhrRequest_remoteDownload.abort(); 12289 xhrRequest_remoteDownload = null; 12290 } 12291 12292 if(xhrRequest_writePeaks){ 12293 xhrRequest_writePeaks.abort(); 12294 xhrRequest_writePeaks = null; 12295 } 12296 12297 if(xhrRequest_loadPeaks){ 12298 xhrRequest_loadPeaks.abort(); 12299 xhrRequest_loadPeaks = null; 12300 } 12301 12302 if(!crossFadeOn){ 12303 if(dataIntervalID) clearInterval(dataIntervalID); 12304 12305 if(playbackToggle)self.toggleBigPlay() 12306 } 12307 12308 //############################################// 12309 /* ads */ 12310 //############################################// 12311 12312 if(progressLevel)progressLevel.classList.remove('hap-ad-progress-level'); 12313 if(mediaTimeAd)mediaTimeAd.style.display = 'none'; 12314 if(adSkipBtn)adSkipBtn.style.display = 'none' 12315 12316 if(_HAPAdManager){ 12317 _HAPAdManager.cleanAds(); 12318 } 12319 12320 //ima 12321 isIma = false;
12322 isImaOn = false; 12323 imaStarted = false; 12324 12325 //############################################// 12326 /* ads */ 12327 //############################################// 12328 12329 if(mediaType == 'hls'){ 12330 if(hlsSupport)hls.detachMedia(); 12331 } 12332 else if(mediaType == 'youtube'){ 12333 if(youtubePlayer){ 12334 youtubeEndFix = true; 12335 youtubeHolder.style.display = 'none'; 12336 if(youtubeReady)youtubePlayer.stopVideo(); 12337 youtubeStarted = false; 12338 } 12339 } 12340 12341 if(!settings.useCrossFade){ 12342 12343 if(audio){ 12344 audio.pause(); 12345 audio.src = ''; 12346 audio.removeAttribute('src') 12347 } 12348 12349 //if(audio)audio.removeEventListener('ended canplay canplaythrough loadedmetadata pause play error seeked'); 12350 }else{ 12351 12352 if(audio.c_active){ 12353 if(audio){ 12354 audio.pause(); 12355 audio.src = ''; 12356 audio.removeAttribute('src') 12357 } 12358 //if(audio)audio.removeEventListener('ended canplay canplaythrough loadedmetadata pause play error seeked'); 12359 }else{ 12360 if(audioUp2Js2){ 12361 audioUp2Js2.pause(); 12362 audioUp2Js2.src = ''; 12363 audioUp2Js2.removeAttribute('src') 12364 } 12365 //if(audio2)audio2.removeEventListener('ended canplay canplaythrough loadedmetadata pause play error seeked'); 12366 } 12367 12368 } 12369 12370 if(redirectLoginHolder){ 12371 redirectLoginHolder.style.display = 'none'; 12372 redirectLoginHolder.classList.remove('hap-redirect-login-holder-visible') 12373 } 12374 redirectLoginOpened = false; 12375 12376 12377 if(globalDownloadBtn){ 12378 globalDownloadBtn.style.display = 'none'; 12379 globalDownloadBtn.classList.remove('hap-btn-show') 12380 } 12381 12382 12383 if(mediaTimeCurrent)mediaTimeCurrent.innerHTML = '00:00'; 12384 if(mediaTimeTotal)mediaTimeTotal.innerHTML = '00:00'; 12385 if(playerTitle)playerTitle.innerHTML = ''; 12386 if(playerArtist)playerArtist.innerHTML = ''; 12387 if(progressLevel)progressLevel.style.width = 0; 12388 if(loadLevel)loadLevel.style.width = 0; 12389 12390 peakData = null; 12391 if(seekbarWaveProgress)seekbarWaveProgress.style.width = 0; 12392 12393 mediaType = null; 12394 mediaPlaying = false; 12395 mediaStarted = false; 12396 addTrackPlayit = false; 12397 //isEnqueue = false; 12398 if(!initialAutoPlay) autoPlay = false;//note: will not work with ad pre, ad pre will auto trigger autoplay true 12399 12400 if(useRange)self.resetRange(); 12401 12402 startEventDone = false; 12403 12404 if(inlineSeekbar){ 12405 inlineSeekbar.querySelector('.hap-inline-seekbar-progress').style.width = 0; 12406 } 12407 12408 //lyrics 12409 if(lyricsHolder){ 12410 //lyricsHolder.style.display = 'none';//dont close container on going to next media 12411 lyricsHolder.querySelector('.hap-lyrics-container').innerHTML = '' 12412 } 12413 12414 if(_lyrics)_lyrics.deactivate() 12415 lyricsReady = false; 12416 12417 if(videoSync){ 12418 videoSync.pause(); 12419 videoSync.src = ''; 12420 videoSync = null; 12421 videoWrap.innerHTML = '' 12422 } 12423 12424 if(waveformLoadingInterval){ 12425 clearInterval(waveformLoadingInterval); 12426 waveformLoadingInterval = null; 12427 } 12428 waveformLoading = false; 12429 12430 if(activeVariation){ 12431 activeVariation.classList.remove('hap-active-variation') 12432 activeVariation = null; 12433 } 12434 12435 //pwd 12436 if(pwdField)pwdField.value = ''; 12437 if(pwdHolder)pwdHolder.classList.remove('hap-holder-animate', 'hap-holder-shown') 12438 12439 12440 //waveform 12441 if(waveformLoader)waveformLoader.classList.remove('hap-waveform-loader-hidden') 12442 if(seekbarWave)seekbarWave.classList.remove('hap-seekbar-wave-visible') 12443 12444 } 12445 12446 function destroyMedia(){ 12447 if(!componentInited || !mediaType) return; 12448 if(activePlaylistItem)enableActivePlaylistItem(); 12449 cleanMedia(); 12450 _HAPPlaylistManager.reSetCounter(); 12451 } 12452 12453 function setSortableTracks(){ 12454 12455 if(typeof Sortable === "function"){ 12456 12457 Sortable.create(playlistContent, { 12458 animation: 150, 12459 draggable: ".hap-playlist-item", 12460 ghostClass: 'hap-sortable-ghost', 12461 onEnd: function (evt) { 12462 12463 var current_counter = _HAPPlaylistManager.getCounter(); 12464 12465 if(current_counter != -1){ 12466 12467 var new_counter = getElementIndex(playlistContent, activePlaylistItem, '.hap-playlist-item') 12468 12469 //reposition data 12470 var i, arr = [], items = playlistContent.querySelectorAll('.hap-playlist-item').forEach(function(el){ 12471 arr.push(parseInt(el.getAttribute('data-id'),10)); 12472 }); 12473 12474 playlistDataArr = HAPUtils.sortArray(playlistDataArr, arr); 12475 12476 _HAPPlaylistManager.reSetCounter(new_counter); 12477 12478 } 12479 12480 updatePlaylist(); 12481 12482 } 12483 12484 }); 12485 12486 settings.sortableTracksSet = true; 12487 12488 }else{ 12489 12490 var script = document.createElement('script'); 12491 script.type = 'text/javascript'; 12492 script.src = HAPUtils.qualifyURL(settings.sourcePath+settings.sortable_js); 12493 script.onload = script.onreadystatechange = function() { 12494 if(!this.readyState || this.readyState == 'complete'){ 12495 setSortableTracks() 12496 } 12497 }; 12498 script.onerror = function(){
12499 alert("Error loading " + this.src); 12500 } 12501 var tag = document.getElementsByTagName('script')[0]; 12502 tag.parentNode.insertBefore(script, tag); 12503 12504 } 12505 12506 } 12507 12508 function getElementIndex(parent, element, cl) { 12509 return Array.from(parent.querySelectorAll(cl)).indexOf(element); 12510 } 12511 12512 function destroyPlaylist(){ 12513 12514 if(xhrRequest){ 12515 xhrRequest.abort(); 12516 xhrRequest = null; 12517 } 12518 12519 if(xhrRequest_pag){ 12520 xhrRequest_pag.abort(); 12521 xhrRequest_pag = null; 12522 } 12523 12524 if(burl_request){ 12525 burl_request.abort(); 12526 burl_request = null; 12527 } 12528 12529 12530 if(mediaType){ 12531 cleanMedia(); 12532 if(activePlaylistItem)enableActivePlaylistItem(); 12533 } 12534 12535 if(settings.sortableTracks && settings.sortableTracksSet){ 12536 Sortable.destroy();//because of popup 12537 settings.sortableTracksSet = false; 12538 } 12539 12540 if(playlistData){ 12541 playlistData.remove() 12542 playlistData = null; 12543 } 12544 12545 playlistContent.innerHTML = ""; 12546 12547 lastPlaylist = null; 12548 addTrackProcess = false; 12549 playlistInitLoad = false; 12550 playlistLength = 0; 12551 playlistProcessCounter = -1; 12552 playlistDataArr = []; 12553 playlistProcessData = []; 12554 playlistProcessDataUrl = []; 12555 _HAPPlaylistManager.reSetCounter(); 12556 12557 playlistData = null; 12558 globalThumb = null; 12559 globalDownload = null; 12560 globalStartTime = null; 12561 globalStartTimeMediaId = null; 12562 globalEndTime = null; 12563 globalAdPre = null; 12564 globalAdMid = null; 12565 globalAdMidInterval = null; 12566 globalAdEnd = null; 12567 globalVast = null; 12568 globalPwd = null; 12569 globalLockVideoUserRoles = null; 12570 globalLockTime = null; 12571 12572 addMoreOnTotalScroll = false; 12573 mediaPrefixUrl = null; 12574 12575 12576 loadMoreProcess = false; 12577 nextPageToken = null; 12578 loadMoreType = null; 12579 loadMoreOnTotalScroll = false; 12580 12581 addMoreLimit = null; 12582 addMoreNumResults = null; 12583 addMoreOffset = null; 12584 addMoreSortOrder = null; 12585 addMoreSortDirection = null; 12586 12587 12588 //reset sort because tracks are loaded with no sort. TODO: Do we keep last sort on new playlist load? 12589 sortOrder = ""; 12590 if(sortAlpha){ 12591 sortAlpha.querySelector('.hap-btn-sort-alpha-up').style.display = 'none'; 12592 sortAlpha.querySelector('.hap-btn-sort-alpha-down').style.display = 'block'; 12593 } 12594 12595 //search 12596 if(searchSelector)searchSelector.value = ''; 12597 if(playlistFilterMsg)playlistFilterMsg.style.display = 'none'; 12598 12599 //pagination 12600 lastActivePaginationBtn = null; 12601 paginationWrap = null; 12602 paginationArr = []; 12603 12604 if(playerThumb){ 12605 playerThumb.style.backgroundImage = 'none' 12606 playerThumb.style.opacity = 0; 12607 } 12608 12609 self.fireEvent('destroyPlaylist', [{instance:self, instanceName:settings.instanceName}]); 12610 12611 } 12612 12613 function beforeSongAdvanceAction(){ 12614 //before we move to next song 12615 if(useContinousPlayback && continousPlaybackTrackAllSongs)playlistDataArr[mediaCounter].data.start = self.getCurrentTime(); 12616 12617 if(settings.useStatistics){ 12618 12619 getStats('hap_play_count', mediaCounter); 12620 12621 var t = self.getCurrentTime() 12622 if(t > 3 && t < 60){ 12623 getStats('hap_skipped_first_minute', mediaCounter); 12624 } 12625 12626 } 12627 12628 } 12629 12630 if(settings.useStatistics){ 12631 12632 addListener(eventName, function (event) { 12633 if(window.event)window.event.cancelBubble = true; 12634 savetimePlayed() 12635 }); 12636 12637 } 12638 12639 function savetimePlayed(e){ 12640 if(mediaCounter){ 12641 12642 getStats('hap_play_count', mediaCounter); 12643 12644 var t = self.getCurrentTime() 12645 if(t > 3 && t < 60){ 12646 getStats('hap_skipped_first_minute', mediaCounter); 12647 } 12648 12649 } 12650 }; 12651 12652 //############################################// 12653 /* resize */ 12654 //############################################// 12655 12656 if(settings.addResizeEvent){ 12657 _window.addEventListener('resize',function() { 12658 if(!componentInited) return false; 12659 if(windowResizeTimeoutID) clearTimeout(windowResizeTimeoutID); 12660 windowResizeTimeoutID = setTimeout(doneResizing, windowResizeTimeout); 12661 }); 12662 } 12663 12664 function doneResizing(){ 12665 if(!componentInited) return false; 12666 if(!settings.addResizeEvent) return false; 12667 12668 if(tooltip)tooltip.style.display = 'none'; 12669 12670 //player resize 12671 var w = parseInt(wrapper.clientWidth,10); 12672 12673 12674 12675 //playlist items 12676 if(playlistContent){ 12677 if(w < settings.playlistItemMultilineWidth){ 12678 playlistContent.classList.add('hap-playlist-item-multiline'); 12679 }else{ 12680 playlistContent.classList.remove('hap-playlist-item-multiline'); 12681 } 12682 } 12683 12684 12685 //player 12686 if(settings.breakPointArr){ 12687 var i, len = settings.breakPointArr.length, ev; 12688 for(i=0;i<len;i++){ 12689 ev = settings.breakPointArr[i]; 12690 if(w < ev){ 12691 wrapper.classList.add('hap-breakpoint-'+ev.toString()); 12692 }else{ 12693 wrapper.classList.remove('hap-breakpoint-'+ev.toString()); 12694 } 12695 } 12696 } 12697 12698 12699 12700 if(settings.useWaveSeekbar && peakData){ 12701 12702 var w = parseInt(seekbar.clientWidth,10); 12703 12704 seekbarWaveCanvasBg.width = w 12705 seekbarWaveCanvasProgress.width = w 12706 12707 waveOptions.width = w; 12708 12709 //clearSeekbar() 12710 12711 seekbarWaveCtx.fillStyle = settings.waveBgColor; 12712 seekbarWaveCtx2.fillStyle = settings.waveProgressColor; 12713 12714 if(waveOptions.barWidth > 0){ 12715 HAPUtils.drawBars(seekbarWaveCtx, seekbarWaveCtx2, waveOptions, peakData.split(','), 0, w) 12716 }else{ 12717 HAPUtils.drawWave(seekbarWaveCtx, seekbarWaveCtx2, waveOptions, peakData.split(','), 0, w) 12718 } 12719 12720 } 12721 12722 if(!circleSeekbar){ 12723 if(settings.useWaveSeekbar){ 12724 if(seekbarWave)seekBarSize = seekbarWave.offsetWidth 12725 }else{ 12726 if(progressBg)seekBarSize = progressBg.offsetWidth 12727 } 12728 } 12729 12730 if(useRange && rangeOn)self.resizeRange() 12731 12732 12733 12734 12735 //if(useStickyPlayer && _HAPStickyPlayer)_HAPStickyPlayer.setprog 12736 12737 12738 12739 } 12740 12741 //############################################// 12742 /* presets */ 12743 //############################################// 12744 12745 //preset mods 12746 function checkPresetMods(){ 12747 12748 if(class_list.indexOf('hap-fixed') > -1){ 12749 12750 if(externalPlayerToggleBtn){ 12751 12752 externalPlayerToggleBtn.addEventListener('click', function(){ 12753 12754 if(settings.playerOpened){ 12755 12756 wrapper.addEventListener('transitionend', function cb(e){ 12757 e.currentTarget.removeEventListener(e.type, cb); 12758 12759 if(externalPlaybackBtn)externalPlaybackBtn.style.display = 'block'; 12760 12761 wrapper.classList.remove('hap-is-playlist-opened') 12762 12763 }) 12764 wrapper.style.bottom = -wrapper.offsetHeight+'px'; 12765 12766 externalPlayerToggleBtn.querySelector('.hap-btn-player-toggle').classList.add('hap-btn-player-toggle-rotate') 12767 12768 settings.playlistOpened = false;
12769 }else{ 12770 12771 wrapper.style.bottom = -playlistHolder.offsetHeight+'px'; 12772 12773 externalPlayerToggleBtn.querySelector('.hap-btn-player-toggle').classList.remove('hap-btn-player-toggle-rotate') 12774 12775 12776 if(externalPlaybackBtn)externalPlaybackBtn.style.display = 'none'; 12777 } 12778 settings.playerOpened = !settings.playerOpened; 12779 }); 12780 12781 } 12782 12783 if(externalPlaybackBtn){ 12784 12785 externalPlaybackBtn.addEventListener('click',function(e){ 12786 self.togglePlayback(); 12787 }); 12788 12789 externalPlaybackBtn.querySelector('.hap-btn-play').style.display = 'block'; 12790 externalPlaybackBtn.querySelector('.hap-btn-pause').style.display = 'none'; 12791 12792 } 12793 12794 if(!settings.isPopup){//do not repeat in popup 12795 12796 if(!settings.playerOpened){ 12797 settings.playlistOpened = false; 12798 wrapper.style.bottom = -wrapper.offsetHeight+'px'; 12799 12800 if(externalPlayerToggleBtn)externalPlayerToggleBtn.querySelector('.hap-btn-player-toggle').classList.add('hap-btn-player-toggle-rotate') 12801 12802 12803 if(externalPlaybackBtn)externalPlaybackBtn.style.display = 'block'; 12804 }else{ 12805 if(settings.playlistOpened){ 12806 wrapper.style.bottom = 0; 12807 }else{ 12808 wrapper.style.bottom = -playlistHolder.offsetHeight+'px'; 12809 } 12810 12811 if(externalPlayerToggleBtn)externalPlayerToggleBtn.querySelector('.hap-btn-player-toggle').classList.remove('hap-btn-player-toggle-rotate') 12812 12813 } 12814 12815 } 12816 12817 } 12818 else if(class_list.indexOf('hap-fixed2') > -1){ 12819 12820 if(externalPlayerToggleBtn){ 12821 12822 externalPlayerToggleBtn.addEventListener('click', function(){ 12823 12824 if(!settings.playerOpened){ 12825 12826 playerHolder.addEventListener('transitionend', function cb(e){ 12827 e.currentTarget.removeEventListener(e.type, cb); 12828 }) 12829 playerHolder.style.bottom = 0+'px'; 12830 12831 externalPlayerToggleBtn.querySelector('.hap-btn-player-toggle').classList.remove('hap-btn-player-toggle-rotate') 12832 12833 settings.playerOpened = false; 12834 12835 }else{ 12836 12837 playerHolder.style.bottom = -playerHolder.offsetHeight+'px'; 12838 12839 externalPlayerToggleBtn.querySelector('.hap-btn-player-toggle').classList.add('hap-btn-player-toggle-rotate') 12840 12841 if(externalPlaybackBtn)externalPlaybackBtn.style.display = 'block'; 12842 } 12843 settings.playerOpened = !settings.playerOpened; 12844 }); 12845 12846 } 12847 12848 if(externalPlaybackBtn){ 12849 12850 externalPlaybackBtn.addEventListener('click',function(e){ 12851 self.togglePlayback(); 12852 }); 12853 12854 externalPlaybackBtn.querySelector('.hap-btn-play').style.display = 'block'; 12855 externalPlaybackBtn.querySelector('.hap-btn-pause').style.display = 'none'; 12856 12857 } 12858 12859 if(!settings.isPopup){//do not repeat in popup 12860 12861 if(!settings.playerOpened)settings.playlistOpened = false; 12862 12863 if(settings.playerOpened){ 12864 playerHolder.style.bottom = 0+'px'; 12865 12866 if(externalPlayerToggleBtn)externalPlayerToggleBtn.querySelector('.hap-btn-player-toggle').classList.remove('hap-btn-player-toggle-rotate') 12867 12868 }else{ 12869 playerHolder.style.bottom = -playerHolder.offsetHeight+'px'; 12870 12871 if(externalPlayerToggleBtn)externalPlayerToggleBtn.querySelector('.hap-btn-player-toggle').classList.add('hap-btn-player-toggle-rotate') 12872 12873 } 12874 12875 if(settings.playlistOpened){ 12876 playlistHolder.style.bottom = playerHolder.offsetHeight+'px'; 12877 }else{ 12878 playlistHolder.style.bottom = -playlistHolder.offsetHeight+'px'; 12879 wrapper.querySelector('.hap-ex-controls')?.classList.add('hap-ex-controls-shown') 12880 } 12881 } 12882 12883 } 12884 else if(class_list.indexOf('hap-art-wide') > -1 || class_list.indexOf('hap-brona') > -1){ 12885 12886 if(!settings.playlistOpened){ 12887 12888 var ph = parseInt(playlistHolder.clientHeight,10) 12889 playlistHolder.style.height = ph+'px' 12890 12891 playlistHolder.classList.add('hap-playlist-closed-v') 12892 12893 } 12894 } 12895 else if(class_list.indexOf('hap-art-narrow') > -1){ 12896 12897 if(settings.playlistOpened){ 12898 playlistHolder.classList.add('hap-playlist-holder-opened') 12899 playerHolder.classList.add('hap-player-holder-closed') 12900 } 12901 } 12902 12903 if(settings.playlistOpened){ 12904 wrapper.classList.add('hap-is-playlist-opened') 12905 }else{ 12906 wrapper.classList.remove('hap-is-playlist-opened') 12907 } 12908 12909 } 12910 12911 function setExternalIconData(playing){ 12912 externalPlaybackBtn.querySelectorAll('.hap-btn').forEach(function(el){ 12913 el.style.display = 'none'; 12914 }) 12915 if(playing) externalPlaybackBtn.querySelector('.hap-btn-pause').style.display = 'block'; 12916 else externalPlaybackBtn.querySelector('.hap-btn-play').style.display = 'block'; 12917 } 12918 12919 12920 //############################################// 12921 /* misc */ 12922 //############################################// 12923 12924 this.getTitle = function(data, clean){//get title from data 12925 var title; 12926 12927 if(data.artist && !HAPUtils.isEmpty(data.artist) && data.title && !HAPUtils.isEmpty(data.title)){ 12928 if(clean)title = data.artist + ' - ' + data.title; 12929 else title = data.artist + settings.artistTitleSeparator + data.title; 12930 } 12931 else if(data.title && !HAPUtils.isEmpty(data.title)){ 12932 title = data.title; 12933 } 12934 else if(data.artist && !HAPUtils.isEmpty(data.artist)){ 12935 title = data.artist; 12936 } 12937 12938 return title; 12939 } 12940 12941 function setTitleAndThumb(){ 12942 12943 //title, artist 12944 if(currMediaData.title || currMediaData.artist){ 12945 var full_title = self.getTitle(currMediaData) 12946 12947 audio.setAttribute('title', self.getTitle(currMediaData, true)) 12948 12949 }else{ 12950 audio.setAttribute('title', '') 12951 } 12952 12953 if(playerTitle && currMediaData.title)playerTitle.innerHTML = currMediaData.title; 12954 if(playerArtist && currMediaData.artist)playerArtist.innerHTML = currMediaData.artist; 12955 if(wrapper.querySelector('.hap-player-desc') && currMediaData.description)wrapper.querySelector('.hap-player-desc').innerHTML = currMediaData.description; 12956 12957 if(playerThumbInited && globalThumb)return; 12958 12959 //thumb 12960 if(playerThumb){ 12961 12962 if(!currMediaData.thumb && (currMediaData.origtype == 's3_bucket_audio' || currMediaData.origtype == 's3_audio') && settings.getThumbFromBucket){ 12963 12964 if(!currMediaData.thumb_key){ 12965 var key = currMediaData.key.substr(0, currMediaData.key.lastIndexOf('.')); 12966 currMediaData.thumb_key = key + '.' + settings.s3ThumbExtension; 12967 } 12968 12969 getAwsThumb(currMediaData) 12970 return; 12971 } 12972 12973 var next_thumb = currMediaData.thumb || currMediaData.thumbDefault; 12974 if(next_thumb)setThumb(next_thumb) 12975 else if(mediaType == 'youtube'){ 12976 playerThumb.style.opacity = 1; 12977 } 12978 } 12979 12980 } 12981 12982 function setThumb(next_thumb){ 12983 12984 if(mediaPrefixUrl && !currMediaData.thumbIsBase64 && !HAPUtils.relativePath(next_thumb))next_thumb = mediaPrefixUrl + next_thumb; 12985 12986 if(currMediaData && currMediaData.origtype == 'soundcloud'){ 12987 if(settings.soundCloudThumbQuality)next_thumb = next_thumb.replace('large.jpg', settings.soundCloudThumbQuality); 12988 } 12989 12990 //if(next_thumb.indexOf("'") > -1)next_thumb = next_thumb.replace(/'/g, "%27");//if has single quote? 12991 12992 if(currMediaData && currMediaData.origtype != 's3_bucket_audio' && currMediaData.origtype != 's3_audio' && next_thumb.indexOf(' ') > -1)next_thumb = encodeURI(next_thumb);//spaces in url 12993 12994 if(playerThumb.style.backgroundImage.indexOf(next_thumb) > -1)return;//dont reload same thumb 12995 12996 if(currMediaData && currMediaData.title)playerThumb.setAttribute('aria-label', currMediaData.title); 12997 else playerThumb.setAttribute('aria-label',''); 12998 12999 if(playerThumbInited){ 13000 playerThumb.style.opacity = 0; 13001 setTimeout(function(){ 13002 playerThumb.style.backgroundImage = 'url("'+next_thumb+'")' 13003 playerThumb.style.opacity = 1; 13004 },300); 13005 }else{ 13006 playerThumb.style.backgroundImage = 'url("'+next_thumb+'")' 13007 playerThumb.style.opacity = 1; 13008 } 13009 playerThumbInited = true; 13010 13011 13012 //preset mods 13013 if(class_list.indexOf('hap-metalic') > -1 || class_list.indexOf('hap-poster') > -1){ 13014 var pi = wrapper.querySelector('.hap-player-image') 13015 if(pi)pi.style.backgroundImage = 'url('+next_thumb+')'; 13016 } 13017 13018 13019 } 13020 13021 13022 //############################################// 13023 /* statistics */ 13024 //############################################// 13025 13026 function handleLikeClick(e){ 13027 13028 if(!componentInited) return false;
13029 if(!mediaType) return false; 13030 13031 var p = e.target.closest('.hap-playlist-item'); 13032 getStats('hap_like_count', p.getAttribute('data-id')); 13033 13034 } 13035 13036 if(settings.useStatistics){ 13037 13038 if(settings.ipInfo){ 13039 countryData = settings.ipInfo 13040 } 13041 13042 /*fetch('https://extreme-ip-lookup.com/json/') 13043 .then( res => res.json()) 13044 .then(response => { 13045 countryData = response; 13046 console.log("Country: ", response); 13047 }) 13048 .catch((data, status) => { 13049 console.log('country request failed'); 13050 })*/ 13051 13052 13053 13054 onHandler(wrapper, 'click', '.hap-like-count', (e) => handleLikeClick(e)); 13055 13056 onHandler(wrapper, 'click', '.hap-download-count:not(.hap-no-download)', (e) => handleDownloadClick(e)); 13057 13058 function handleDownloadClick(e){ 13059 e.preventDefault() 13060 13061 if(!componentInited) return false; 13062 13063 13064 var target = e.target, 13065 id = Number(target.closest('.hap-playlist-item').getAttribute('data-id')) 13066 13067 var i, len = playlistDataArr.length, data 13068 for(i = 0;i < len; i++){ 13069 if(id == playlistDataArr[i].id){ 13070 data = playlistDataArr[i].data 13071 break; 13072 } 13073 } 13074 13075 var title = getTitleForStats(data); 13076 13077 pwdDownloadData = {} 13078 pwdDownloadData.orig_data = data 13079 pwdDownloadData.type = 'hap-download-count' 13080 pwdDownloadData.id = id 13081 pwdDownloadData.title = title 13082 13083 if(data && data.download){ 13084 //check password 13085 if(data.pwd){ 13086 pwdAction = 'download' 13087 13088 pwdHolderToggle() 13089 }else{ 13090 doDownloadAction() 13091 } 13092 } 13093 13094 return false; 13095 13096 } 13097 13098 } 13099 13100 function getTitleForStats(data){ 13101 13102 var title, artist 13103 13104 title = data.safeTitle || data.title || '' 13105 artist = data.safeArtist || data.artist || '' 13106 13107 return {title: title, artist: artist} 13108 13109 } 13110 13111 function getStats(action, id, arr){ 13112 13113 if(window.location.protocol == 'file:'){ 13114 return; 13115 } 13116 13117 var plid = settings.playerId != -1 ? settings.playerId : null; 13118 13119 if(action == 'hap_all_count'){ 13120 13121 var params = 'action='+action+'&data='+JSON.stringify(arr); 13122 13123 } 13124 else if(action == 'hap_play_count'){ 13125 13126 if(!playlistDataArr[id])return; 13127 13128 var data = playlistDataArr[id].data; 13129 13130 //if(data.mediaId == undefined)return; 13131 if(playlistId == undefined){//if we get stats from connected player 13132 if(data.playlistId != undefined)playlistId = data.playlistId; 13133 //else return; 13134 } 13135 13136 var songData = getTitleForStats(data) 13137 13138 var album = data.album || '', 13139 thumb = data.thumb || data.thumbDefault || '', 13140 c_data = countryData ? JSON.stringify(countryData) : '' 13141 13142 var params = 'action='+action 13143 +'&percentToCountAsPlay='+settings.percentToCountAsPlay 13144 +'&playlist_id='+playlistId 13145 +'&player_id='+settings.playerId 13146 +'&media_id='+data.mediaId 13147 +'&audio_url='+mediaPath 13148 +'&title='+songData.title 13149 +'&artist='+songData.artist 13150 +'&album='+ album 13151 +'&thumb='+ thumb 13152 +'¤tTime='+activeAudio.currentTime 13153 +'&duration='+activeAudio.duration 13154 +'&countryData='+c_data 13155 13156 } 13157 else if(action == 'hap_download_count' || action == 'hap_like_count' || action == 'hap_finish_count'){ 13158 13159 var data = playlistDataArr[id].data; 13160 13161 //if(data.mediaId == undefined)return; 13162 if(playlistId == undefined){//if we get stats from connected player 13163 if(data.playlistId != undefined)playlistId = data.playlistId; 13164 //else return; 13165 } 13166 13167 var songData = getTitleForStats(data) 13168 13169 var album = data.album || '', 13170 thumb = data.thumb || data.thumbDefault || '' 13171 13172 var params = 'action='+action 13173 +'&playlist_id='+playlistId 13174 +'&player_id='+settings.playerId 13175 +'&media_id='+data.mediaId 13176 +'&audio_url='+mediaPath 13177 +'&title='+songData.title 13178 +'&artist='+songData.artist 13179 +'&album='+ album 13180 +'&thumb='+ thumb 13181 13182 } 13183 else if(action == 'hap_skipped_first_minute'){ 13184 13185 var data = playlistDataArr[id].data; 13186 13187 var songData = getTitleForStats(data) 13188 13189 var album = data.album || '', 13190 thumb = data.thumb || data.thumbDefault || '' 13191 13192 var params = 'action='+action 13193 +'&playlist_id='+playlistId 13194 +'&player_id='+settings.playerId 13195 +'&media_id='+data.mediaId 13196 +'&audio_url='+mediaPath 13197 +'&title='+songData.title 13198 +'&artist='+songData.artist 13199 +'&album='+ album 13200 +'&thumb='+ thumb 13201 13202 } 13203 else if(action == 'hap_time_played'){ 13204 13205 if(!playlistDataArr[id])return; 13206 13207 var data = playlistDataArr[id].data; 13208 13209 if(playlistId == undefined){ 13210 if(data.playlistId != undefined)playlistId = data.playlistId; 13211 } 13212 13213 var songData = getTitleForStats(data) 13214 13215 var album = data.album || '', 13216 thumb = data.thumb || data.thumbDefault || '' 13217 13218 var params = 'action='+action 13219 +'&playlist_id='+playlistId 13220 +'&player_id='+settings.playerId 13221 +'&media_id='+data.mediaId 13222 +'&audio_url='+mediaPath 13223 +'&title='+songData.title 13224 +'&artist='+songData.artist 13225 +'&album='+ album 13226 +'&thumb='+ thumb 13227 13228 } 13229 13230 13231 var url = settings.ajax_url; 13232 13233 13234 13235 var xhrRequest_stat = new XMLHttpRequest(); 13236 xhrRequest_stat.onreadystatechange = function() { 13237 if (xhrRequest_stat.readyState == 4) { 13238 13239 var response = JSON.parse(this.responseText); 13240 13241 if(response){ 13242 13243 if(settings.usePlaylist && response && response != '-1'){ 13244 13245 if(action == 'hap_like_count' && response.c_like){ 13246 13247 var p = playlistContent.querySelector('.hap-playlist-item[data-id="'+id+'"]'); 13248 13249 p.querySelector('.hap-like-count span').innerHTML = HAPUtils.nFormatter(parseInt(response.c_like,10), 1); 13250 } 13251 else if(action == 'hap_download_count' && response.c_download){ 13252 13253 var p = playlistContent.querySelector('.hap-playlist-item[data-id="'+id+'"]'); 13254 13255 p.querySelector('.hap-download-count span').innerHTML = HAPUtils.nFormatter(parseInt(response.c_download,10), 1); 13256 } 13257 else if(action == 'hap_play_count' && response.c_play){ 13258 13259 var p = playlistContent.querySelector('.hap-playlist-item[data-id="'+id+'"]'); 13260 13261 p.querySelector('.hap-play-count span').innerHTML = HAPUtils.nFormatter(parseInt(response.c_play,10), 1); 13262 } 13263 else if(action == 'hap_all_count'){ 13264 13265 var i, len = response.length, obj, item; 13266 for(i=0;i<len;i++){ 13267 obj = response[i]; 13268 13269 if(obj.title && obj.artist && obj.media_id){ 13270 13271 item = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+obj.media_id+'"][data-safe-title="'+obj.title+'"][data-safe-artist="'+obj.artist+'"]'); 13272 13273 }else if(obj.title && obj.artist){ 13274 13275 item = playlistContent.querySelector('.hap-playlist-item[data-safe-title="'+obj.title+'"][data-safe-artist="'+obj.artist+'"]'); 13276 13277 }else if(obj.title){ 13278 13279 item = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+obj.media_id+'"][data-safe-title="'+obj.title+'"]'); 13280 13281 }else if(obj.artist){ 13282 13283 item = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+obj.media_id+'"][data-safe-artist="'+obj.artist+'"]'); 13284 } 13285 13286 if(item.querySelector('.hap-like-count'))item.querySelector('.hap-like-count span').innerHTML = HAPUtils.nFormatter(parseInt(obj.c_like,10), 1); 13287 13288 if(item.querySelector('.hap-download-count'))item.querySelector('.hap-download-count span').innerHTML = HAPUtils.nFormatter(parseInt(obj.c_download,10), 1); 13289 13290 if(item.querySelector('.hap-play-count'))item.querySelector('.hap-play-count span').innerHTML = HAPUtils.nFormatter(parseInt(obj.c_play,10), 1); 13291 } 13292 } 13293 13294 } 13295 13296 } 13297 13298 } 13299 } 13300 xhrRequest_stat.onerror = function(e) { 13301 console.log('Error getStats: ' + e); 13302 }; 13303 xhrRequest_stat.open('POST', url); 13304 xhrRequest_stat.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 13305 xhrRequest_stat.send(params); 13306 13307 } 13308 13309 //############################################// 13310 /* ads */ 13311 //############################################// 13312 13313 this.showAdInterface = function(){ 13314 13315 if(progressLevel)progressLevel.classList.add('hap-ad-progress-level'); 13316 if(mediaTimeCurrent)mediaTimeCurrent.style.display = 'none'; 13317 if(mediaTimeTotal)mediaTimeTotal.style.display = 'none'; 13318 if(mediaTimeAd)mediaTimeAd.style.display = 'block'; 13319 13320 } 13321 13322 this.hideAdInterface = function(){ 13323 13324 if(progressLevel)progressLevel.classList.remove('hap-ad-progress-level'); 13325 if(mediaTimeCurrent)mediaTimeCurrent.style.display = 'block'; 13326 if(mediaTimeTotal)mediaTimeTotal.style.display = 'block'; 13327 if(mediaTimeAd)mediaTimeAd.style.display = 'none'; 13328 13329 } 13330 13331 this.hideImaAdInterface = function(){ 13332 13333 if(progressLevel)progressLevel.classList.remove('hap-ad-progress-level'); 13334 if(mediaTimeCurrent)mediaTimeCurrent.style.display = 'block'; 13335 if(mediaTimeTotal)mediaTimeTotal.style.display = 'block'; 13336 13337 if(mediaTimeAd)mediaTimeAd.style.display = 'none'; 13338 if(adSkipBtn)adSkipBtn.style.display = 'none'; 13339 13340 isImaOn = false;
13341 13342 } 13343 13344 this.showImaAdInterface = function(){ 13345 13346 if(progressLevel)progressLevel.classList.add('hap-ad-progress-level'); 13347 if(mediaTimeCurrent)mediaTimeCurrent.style.display = 'none'; 13348 if(mediaTimeTotal)mediaTimeTotal.style.display = 'none'; 13349 if(mediaTimeAd)mediaTimeAd.style.display = 'block'; 13350 13351 isImaOn = true; 13352 13353 } 13354 13355 this.displayAdTime = function(d, t, skip_allowed){ 13356 13357 if(HAPUtils.isNumber(t) && HAPUtils.isNumber(d)){ 13358 13359 if(progressLevel)progressLevel.style.width = (t / d) * seekBarSize + 'px'; 13360 13361 var adt = parseInt(d-t,10); 13362 if(mediaTimeAd)mediaTimeAd.querySelector('span').innerHTML = HAPUtils.formatTime(adt); 13363 } 13364 13365 if(settings.useImaSkipButto && adSkipBtn){ 13366 if(skip_allowed){ 13367 adSkipBtn.style.display = 'block' 13368 }else{ 13369 adSkipBtn.style.display = 'none' 13370 } 13371 } 13372 13373 } 13374 13375 13376 //############################################// 13377 /* api */ 13378 //############################################// 13379 13380 function log(s){ 13381 var h = document.createElement("H1"); 13382 var t = document.createTextNode(s); 13383 h.style.color = '#ffffff'; 13384 h.appendChild(t); 13385 document.body.appendChild(h); 13386 } 13387 13388 this.playMedia = function() { 13389 if(!componentInited) return false; 13390 if(!mediaType) return false; 13391 if(mediaPlaying) return false; 13392 13393 if(mediaType == 'youtube'){ 13394 if(youtubePlayer && youtubeReady)youtubePlayer.playVideo(); 13395 }else{ 13396 if(activeAudio){ 13397 var promise = activeAudio.play(); 13398 if (promise !== undefined) { 13399 promise.then(function(){ 13400 }).catch(function(error){ 13401 }); 13402 } 13403 } 13404 } 13405 } 13406 this.pauseMedia = function() { 13407 if(!componentInited) return false; 13408 if(!mediaType) return false; 13409 if(!mediaPlaying) return false; 13410 13411 if(mediaType == 'youtube'){ 13412 if(youtubePlayer && youtubeReady)youtubePlayer.pauseVideo(); 13413 }else{ 13414 if(activeAudio)activeAudio.pause(); 13415 } 13416 } 13417 this.togglePlayback = function(){ 13418 13419 if(!componentInited) return false; 13420 if(!mediaType) return false; 13421 if(_HAPAdManager)_HAPAdManager.clearAdMidTimeout(); 13422 if(crossFadeOn)cancelCrossFadeSeek(); 13423 13424 //check password 13425 if(currMediaData.pwd){ 13426 pwdHolderToggle() 13427 return false; 13428 } 13429 13430 if(!mediaStarted){ 13431 if(currMediaData.lockTime == '0' && !allowedViewVideoUserRole){ 13432 toggleRedirectLoginScreen('watch'); 13433 return 13434 } 13435 } 13436 13437 13438 if(dataIntervalID == null){//from login 13439 dataIntervalID = setInterval(trackProgress, dataInterval); 13440 } 13441 13442 13443 if(_HAPAdManager && _HAPAdManager.isAdOn()){ 13444 13445 if(isIOS && currMediaData && (currMediaData.adMid || currMediaData.adEnd) && !iosAdMidFixStart && _HAPAdManager){ 13446 iosAdMidFixStart = true; 13447 _HAPAdManager.forceAdMidAudio();//ads 13448 } 13449 13450 //############################################// 13451 /* ads */ 13452 //############################################// 13453 13454 if(_HAPAdManager.isAdPreOn()){ 13455 _HAPAdManager.toggleAdAudio(); 13456 } 13457 else if(_HAPAdManager.isAdMidOn() && settings.pauseAudioDuringAds){ 13458 _HAPAdManager.toggleAdAudio(); 13459 } 13460 13461 //############################################// 13462 /* ads */ 13463 //############################################// 13464 13465 }else if(isIma){ 13466 13467 if(!imaStarted){ 13468 initVast() 13469 }else if(isImaOn){ 13470 _IMALoader.togglePlayPause() 13471 }else{ 13472 if(mediaPlaying)self.pauseMedia() 13473 else self.playMedia() 13474 } 13475 13476 }else{ 13477 13478 if(mediaType == 'youtube'){ 13479 if(youtubePlayer && youtubeReady){ 13480 var player_state = youtubePlayer.getPlayerState(); 13481 13482 if(player_state == 1){//playing 13483 youtubePlayer.pauseVideo(); 13484 }else if(player_state == 2){//paused 13485 youtubePlayer.playVideo(); 13486 }else if(player_state == -1 || player_state == 5 || player_state == 0){//unstarted, cued, ended 13487 youtubePlayer.playVideo(); 13488 } 13489 } 13490 }else{ 13491 13492 if(activeAudio){ 13493 13494 if(activeAudio.paused) { 13495 13496 if(isSafari && settings.applySafariAudioRestartFix){ 13497 var url = mediaPath.substr(0,mediaPath.indexOf('?') ) 13498 url += "?rand=" + (Math.random() * 99999999) 13499 activeAudio.url = mediaPath; 13500 activeAudio.load() 13501 } 13502 13503 var promise = activeAudio.play(); 13504 if (promise !== undefined) { 13505 promise.then(function(){ 13506 }).catch(function(error){ 13507 }); 13508 } 13509 }else{ 13510 activeAudio.pause(); 13511 } 13512
13513 if(_HAPAdManager && !settings.pauseAudioDuringAds && _HAPAdManager.isAdMidOn()){ 13514 //_HAPAdManager.toggleAdAudio();//potential useful if one wants to enable ad pause while main audio plays? 13515 } 13516 } 13517 } 13518 13519 } 13520 } 13521 this.nextMedia = function() { 13522 if(!componentInited) return false; 13523 13524 if(_HAPAdManager && _HAPAdManager.isAdOn()) return false; 13525 if(isIma && isImaOn) return false; 13526 13527 if(settings.disableSongSkip) return false; 13528 if(playlistLength == 0) return; 13529 if(crossFadeOn && !comingFromCrossFade)cancelCrossFadeAdvance(); 13530 comingFromCrossFade = false; 13531 13532 if(typeof mediaCounter != undefined)beforeSongAdvanceAction(); 13533 13534 if(settings.usePlaylist && isSearchActive){ 13535 13536 var current = playlistContent.querySelector('.hap-playlist-item-selected:not(.hap-filter-hidden)'), 13537 next 13538 13539 if(current){ 13540 next = getNextSibling(current); 13541 }else{ 13542 //if no active item from search 13543 next = playlistContent.querySelector('.hap-playlist-item:not(.hap-filter-hidden)'); 13544 } 13545 13546 if(next){ 13547 var c = next.getAttribute('data-id') 13548 _HAPPlaylistManager.setCounter(c, false); 13549 } 13550 else{//no more in search, try to advance normally 13551 //_HAPPlaylistManager.advanceHandler(1, true); 13552 } 13553 13554 }else{ 13555 _HAPPlaylistManager.advanceHandler(1, true); 13556 } 13557 } 13558 function getNextSibling (elem, selector) { 13559 //https://gomakethings.com/finding-the-next-and-previous-sibling-elements-that-match-a-selector-with-vanilla-js/ 13560 13561 // Get the next sibling element 13562 var sibling = elem.nextElementSibling; 13563 13564 // If there's no selector, return the first sibling 13565 //if (!selector) return sibling; 13566 13567 // If the sibling matches our selector, use it 13568 // If not, jump to the next sibling and continue the loop 13569 while (sibling) { 13570 if (sibling.classList.contains('hap-playlist-item') && !sibling.classList.contains('hap-filter-hidden')) { 13571 return sibling; 13572 } 13573 sibling = sibling.nextElementSibling 13574 } 13575 13576 }; 13577 function getPreviousSibling (elem, selector) { 13578 13579 // Get the next sibling element 13580 var sibling = elem.previousElementSibling; 13581 13582 // If there's no selector, return the first sibling 13583 //if (!selector) return sibling; 13584 13585 // If the sibling matches our selector, use it 13586 // If not, jump to the next sibling and continue the loop 13587 while (sibling) { 13588 if (sibling.classList.contains('hap-playlist-item') && !sibling.classList.contains('hap-filter-hidden')) { 13589 return sibling; 13590 } 13591 sibling = sibling.nextElementSibling 13592 } 13593 13594 }; 13595 this.previousMedia = function() { 13596 if(!componentInited) return false; 13597 13598 if(_HAPAdManager && _HAPAdManager.isAdOn()) return false; 13599 if(isIma && isImaOn) return false; 13600 13601 if(settings.disableSongSkip) return false; 13602 if(playlistLength == 0) return; 13603 if(crossFadeOn && !comingFromCrossFade)cancelCrossFadeAdvance(); 13604 comingFromCrossFade = false; 13605 13606 if(typeof mediaCounter != undefined)beforeSongAdvanceAction(); 13607 13608 if(settings.usePlaylist && isSearchActive){ 13609 13610 var current = playlistContent.querySelector('.hap-playlist-item-selected:not(.hap-filter-hidden)'), 13611 next 13612 13613 if(current)next = getPreviousSibling(current); 13614 else{ 13615 //if no active item from search 13616 next = playlistContent.querySelector('.hap-playlist-item:not(.hap-filter-hidden)'); 13617 } 13618 13619 if(next){ 13620 var c = next.getAttribute('data-id') 13621 _HAPPlaylistManager.setCounter(c, false); 13622 } 13623 else{//no more in search, try to advance normally 13624 //_HAPPlaylistManager.advanceHandler(-1, true); 13625 } 13626 13627 }else{ 13628 _HAPPlaylistManager.advanceHandler(-1, true); 13629 } 13630 13631 } 13632 this.loadMedia = function(format, value, title, artist) { 13633 if(!componentInited) return false; 13634 if(playlistTransitionOn) return false; 13635 if(playlistLength == 0) return; 13636 console.log(format, value, title, artist) 13637 var index = -1; 13638 13639 if(format == 'title'){ 13640 13641 var i, found; 13642 for(i = 0;i < playlistLength; i++){ 13643 if(value == playlistDataArr[i].data.title){ 13644 index = i; 13645 found = true; 13646 break; 13647 } 13648 } 13649 13650 if(!found){ 13651 alert('No media with title "'+value+'" to load! LoadMedia failed.'); 13652 return false; 13653 } 13654 13655 }else if(format == 'title-artist'){ 13656 13657 var pi = playlistContent.querySelector('.hap-playlist-item[data-title="'+title+'"][data-artist="'+artist+'"]'); 13658 13659 if(!pi){ 13660 alert('No media with title "'+title+'" and artist "'+artist+'" to load! Loa
13660dMedia failed.'); 13661 return false; 13662 } 13663 13664 index = pi.getAttribute('data-id'); 13665 13666 }else if(format == 'counter'){ 13667 13668 if(value<0){ 13669 alert('Invalid track number. Track number "' + value + '" doesnt exist. LoadMedia failed.'); 13670 return false; 13671 } 13672 else if(value > playlistLength-1){ 13673 alert('Invalid track number. Track number "' + value + '" doesnt exist. LoadMedia failed.'); 13674 return false; 13675 } 13676 else{ 13677 index = value; 13678 } 13679 13680 }else if(format == 'id'){//data-media-id 13681 13682 var pi = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+value+'"]'); 13683 13684 if(!pi){ 13685 alert('No media with media ID '+value+' to load! LoadMedia failed.'); 13686 return false; 13687 } 13688 13689 index = pi.getAttribute('data-id'); 13690 13691 }else if(format == 'id-title'){//data-media-id and title, artist (we use this if playlist is grouped source and all items can have same media-id) 13692 13693 if(title && artist){ 13694 var pi = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+value+'"][title="'+title+'"][data-artist="'+artist+'"]'); 13695 }else if(title){ 13696 var pi = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+value+'"][title="'+title+'"]'); 13697 }else if(artist){ 13698 var pi = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+value+'"][data-artist="'+artist+'"]'); 13699 } 13700 13701 if(!pi){ 13702 alert('No media with media ID '+value+' to load! LoadMedia failed.'); 13703 return false; 13704 } 13705 13706 index = pi.getAttribute('data-id'); 13707 13708 }else{ 13709 console.log('loadMedia function requires format parameter!'); 13710 return false; 13711 } 13712 13713 if(typeof mediaCounter != undefined)beforeSongAdvanceAction(); 13714 13715 autoPlay = true; 13716 settings.autoPlay = true; 13717 13718 _HAPPlaylistManager.processPlaylistRequest(index); 13719 } 13720 13721 //############################################// 13722 /* load more, add more */ 13723 //############################################// 13724 13725 this.loadMore = function(){ 13726 13727 if(!componentInited) return false; 13728 if(!loadMoreType) return false; 13729 if(!nextPageToken) return false; 13730 if(playlistTransitionOn)return false; 13731 13732 playlistTransitionOn = true; 13733 if(preloader)preloader.style.display = 'block'; 13734 loadMoreProcess = true; 13735 playlistProcessData = []; 13736 13737 if(loadMoreType == 'soundcloud'){ 13738 resumeSoundCloud(); 13739 }else if(loadMoreType == 'podcast'){ 13740 resumePodcast(); 13741 }else if(loadMoreType == 'folder'){ 13742 resumeFolderLoad(); 13743 }else if(loadMoreType == 'youtube'){ 13744 if(!_HAPYoutubeLoader)createLoader('youtube'); 13745 _HAPYoutubeLoader.resumeLoad(nextPageToken); 13746 } 13747 } 13748 this.setLoadMore = function(value){ 13749 loadMoreOnTotalScroll = value; 13750 } 13751 this.endLoadMore = function(){ 13752 playlistTransitionOn = false; 13753 preloader.style.display = 'none'; 13754 loadMoreProcess = false; 13755 } 13756 function addMore(){//load more from database 13757 13758 if(preloader)preloader.style.display = 'block'; 13759 loadMoreProcess = true; 13760 if(loadMoreBtn)loadMoreBtn.style.opacity = 0; 13761 13762 var params = 'action=hap_add_more' 13763 +'&playlist_id='+playlistId 13764 +'&addMoreOffset='+addMoreOffset 13765 +'&addMoreLimit='+addMoreLimit 13766 +'&addMoreSortOrder='+addMoreSortOrder 13767 +'&addMoreSortDirection='+addMoreSortDirection 13768 +'&encryptMediaPaths='+settings.encryptMediaPaths 13769 13770 if(xhrRequest_pag){ 13771 xhrRequest_pag.abort(); 13772 xhrRequest_pag = null; 13773 } 13774 13775 var url = settings.ajax_url 13776 13777 xhrRequest_pag = new XMLHttpRequest(); 13778 xhrRequest_pag.onreadystatechange = function() { 13779 if (xhrRequest_pag.readyState == 4) { 13780 13781 var response = JSON.parse(xhrRequest_pag.responseText); 13782 13783 if(playlistData && playlistData.getAttribute('data-add-more-offset') != undefined){ 13784 addMoreOffset = parseInt(playlistData.getAttribute('data-add-more-offset'),10) + addMoreLimit; 13785 playlistData.setAttribute('data-add-more-offset', addMoreOffset); 13786 } 13787 self.addTrack(response); 13788 13789 } 13790 } 13791 xhrRequest_pag.onerror = function(e) { 13792 console.log(jqXHR, textStatus, errorThrown); 13793 self.endLoadMore(); 13794 }; 13795 xhrRequest_pag.open('POST', url); 13796 xhrRequest_pag.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 13797 xhrRequest_pag.send(params); 13798 13799 } 13800 this.addMore = function(){ 13801 if(!componentInited) return false;
13802 if(playlistTransitionOn)return false; 13803 if(addMoreOnTotalScroll){ 13804 if(!loadMoreProcess){ 13805 addMore(); 13806 } 13807 } 13808 } 13809 this.setAddMore = function(value){ 13810 addMoreOnTotalScroll = value; 13811 } 13812 13813 //############################################// 13814 /* pagination */ 13815 //############################################// 13816 13817 function paginate(){ 13818 13819 if(preloader)preloader.style.display = 'block'; 13820 loadMoreProcess = true; 13821 13822 var params = 'action=hap_paginate' 13823 +'&playlist_id='+playlistId 13824 +'&addMoreOffset='+addMoreOffset 13825 +'&addMoreLimit='+addMoreLimit 13826 +'&addMoreSortOrder='+addMoreSortOrder 13827 +'&addMoreSortDirection='+addMoreSortDirection 13828 +'&encryptMediaPaths='+settings.encryptMediaPaths 13829 13830 if(xhrRequest_pag){ 13831 xhrRequest_pag.abort(); 13832 xhrRequest_pag = null; 13833 } 13834 13835 var url = settings.ajax_url 13836 13837 xhrRequest_pag = new XMLHttpRequest(); 13838 xhrRequest_pag.onreadystatechange = function() { 13839 if (xhrRequest_pag.readyState == 4) { 13840 13841 var response = JSON.parse(xhrRequest_pag.responseText); 13842 13843 //hide visible playlist items (do this now so layout doesnt change until we wait for new playlist items) 13844 playlistContent.querySelectorAll('.hap-playlist-item:not(.hap-pagination-hidden)').forEach(function(el){ 13845 el.classList.add('hap-pagination-hidden') 13846 el.querySelector('.hap-thumbimg').classList.remove('hap-visible') 13847 }) 13848 13849 self.addTrack(response); 13850 13851 createPagination(paginationCurrentPage); 13852 13853 savePagination(); 13854 13855 } 13856 } 13857 xhrRequest_pag.onerror = function(e) { 13858 console.log(jqXHR, textStatus, errorThrown); 13859 self.endLoadMore(); 13860 }; 13861 xhrRequest_pag.open('POST', url); 13862 xhrRequest_pag.setRequestHeader("Content-Type", 'application/x-www-form-urlencoded'); 13863 xhrRequest_pag.send(params); 13864 13865 } 13866 13867 function savePagination(){ 13868 paginationArr[paginationCurrentPage].page = paginationCurrentPage; 13869 13870 var arr = []; 13871 playlistContent.querySelectorAll('.hap-playlist-item:not(.hap-pagination-hidden)').forEach(function(el){ 13872 arr.push(el) 13873 }) 13874 paginationArr[paginationCurrentPage].media_id = arr; 13875 13876 } 13877 13878 function createPagination(page){ 13879 13880 page += 1; 13881 13882 var id, c, str = '<div class="hap-pagination-container">'; 13883 13884 if (page > 1){ 13885 str += '<div class="hap-pagination-page hap-pagination-prev" data-page-id="prev" title="'+settings.paginationPreviousBtnTitle+'">'+settings.paginationPreviousBtnText+'</div>'; 13886 } 13887 13888 if (page > 3){ 13889 str += '<div class="hap-pagination-page hap-pagination-start" data-page-id="0">1</div>'+ 13890 '<div class="hap-pagination-dots">...</div>'; 13891 } 13892 13893 if (page-2 > 0){ 13894 id = page-2; 13895 c = id-1; 13896 str += '<div class="hap-pagination-page" data-page-id="'+c+'">'+id+'</div>'; 13897 } 13898 if (page-1 > 0){ 13899 id = page-1; 13900 c = id-1; 13901 str += '<div class="hap-pagination-page" data-page-id="'+c+'">'+id+'</div>'; 13902 } 13903 13904 id = page; 13905 c = id-1; 13906 str += '<div class="hap-pagination-page hap-pagination-currentpage" data-page-id="'+c+'">'+id+'</div>' 13907 13908 if (page+1 < paginationTotalPages+1){ 13909 id = page+1; 13910 c = id-1; 13911 str += '<div class="hap-pagination-page" data-page-id="'+c+'">'+id+'</div>'; 13912 } 13913 13914 if (page+2 < paginationTotalPages+1){ 13915 id = page+2; 13916 c = id-1; 13917 str += '<div class="hap-pagination-page" data-page-id="'+c+'">'+id+'</div>'; 13918 } 13919 13920 if (page < paginationTotalPages-2){ 13921 id = paginationTotalPages; 13922 c = id-1; 13923 str += '<div class="hap-pagination-dots">...</div>'+ 13924 '<div class="hap-pagination-page hap-pagination-end" data-page-id="'+c+'">'+id+'</div>'; 13925 } 13926 13927 if (page < paginationTotalPages){ 13928 str += '<div class="hap-pagination-page hap-pagination-next" data-page-id="next" title="'+settings.paginationNextBtnTitle+'">'+settings.paginationNextBtnText+'</div>'; 13929 } 13930 13931 str += '</div>'; 13932 13933 if(paginationWrap)paginationWrap.innerHTML = str; 13934 else{ 13935 wrapper.insertAdjacentHTML("beforeend",'<div class="hap-pagination-wrap">'+str+'</div>'); 13936 } 13937 13938 if(!paginationInited){ 13939 paginationInited = true; 13940 13941 paginationWrap = wrapper.querySelector('.hap-pagination-wrap') 13942 13943 onHandler(paginationWrap, 'click', '.hap-pagination-page:not(.hap-pagination-currentpage)', (e) => handlePaginationClick(e)); 13944 13945 lastActivePaginationBtn = paginationWrap.querySelector('.hap-pagination-currentpage') 13946 13947 } 13948 13949 } 13950 13951 function handlePaginationClick(e){ 13952 13953 if(!componentInited)return false;
13954 if(playlistTransitionOn)return false; 13955 if(loadMoreProcess)return false; 13956 13957 loadMoreProcess = true; 13958 13959 var btn = e.target; 13960 13961 if(lastActivePaginationBtn)lastActivePaginationBtn.classList.remove('hap-pagination-currentpage'); 13962 lastActivePaginationBtn = btn.classList.add('hap-pagination-currentpage'); 13963 13964 //get new page 13965 var page = btn.getAttribute('data-page-id') 13966 if(page == 'prev')paginationCurrentPage -= 1; 13967 else if(page == 'next')paginationCurrentPage += 1; 13968 else paginationCurrentPage = parseInt(page,10); 13969 13970 if(paginationArr[paginationCurrentPage].page == null){//sql 13971 13972 addMoreOffset = paginationCurrentPage * addMoreLimit; 13973 paginate(); 13974 13975 }else{//already have data 13976 //console.log('already have data') 13977 13978 //hide visible playlist items 13979 playlistContent.querySelectorAll('.hap-playlist-item:not(.hap-pagination-hidden)').forEach(function(el){ 13980 el.classList.add('hap-pagination-hidden') 13981 el.querySelector('.hap-thumbimg').classList.remove('hap-visible'); 13982 }) 13983 13984 //show current page 13985 var ids = paginationArr[paginationCurrentPage].media_id; 13986 13987 ids.forEach(element => { 13988 element.classList.remove('hap-pagination-hidden') 13989 element.querySelector('.hap-thumbimg').classList.remove('hap-visible'); 13990 13991 setTimeout(function(){ 13992 element.querySelector('.hap-thumbimg').classList.add('hap-visible'); 13993 },20); 13994 13995 }); 13996 13997 createPagination(paginationCurrentPage); 13998 loadMoreProcess = false; 13999 14000 } 14001 } 14002 14003 //############################################// 14004 /* */ 14005 //############################################// 14006 14007 this.processPlaylistRequest = function(index){ 14008 if(typeof mediaCounter != undefined)beforeSongAdvanceAction(); 14009 autoPlay = true; 14010 settings.autoPlay = true; 14011 _HAPPlaylistManager.processPlaylistRequest(index); 14012 } 14013 14014 this.loadPlaylist = function(value, active_item) { 14015 if(!componentInited || playlistTransitionOn) return false; 14016 14017 if(typeof(value) === 'string'){ 14018 if(typeof active_item != undefined)settings.mediaId = active_item; 14019 if(settings.activePlaylist == value)return false;//playlist already loaded! 14020 setPlaylist(value); 14021 }else{ 14022 alert('Invalid value loadPlaylist!'); 14023 return false; 14024 } 14025 } 14026 this.addTrack = function(track, playit, position, ready) { 14027 if(!componentInited || playlistTransitionOn) return false; 14028 14029 if(typeof track === 'undefined'){ 14030 alert('addTrack method requires track parameter. AddTrack failed.'); 14031 return false; 14032 } 14033 14034 addTrackPlayit = false; 14035 if(typeof playit !== 'undefined'){ 14036 addTrackPlayit = playit; 14037 if(playit == false)isEnqueue = true; 14038 } 14039 14040 if(ready){//pass ready playlistData to build playlist in connected player without processing 14041 playlistDataReady = true; 14042 playlistInitLoad = false; 14043 }else{ 14044 playlistDataReady = false; 14045 } 14046 14047 if(playlistFilterMsg)playlistFilterMsg.style.display = 'none'; 14048 14049 insertPosition = position; 14050 endInsert = false; 14051 addTrackProcess = true; 14052 14053 if(lastPlaylist){ 14054 14055 if(typeof insertPosition !== 'undefined'){ 14056 if(insertPosition < 0){ 14057 insertPosition = 0; 14058 } 14059 else if(insertPosition >= playlistLength || insertPosition == 'end'){ 14060 insertPosition = playlistLength; 14061 endInsert = true; 14062 } 14063 }else{ 14064 endInsert = true; 14065 insertPosition = playlistLength; 14066 } 14067 }else{//first time create playlist from addTrack method 14068 insertPosition = 0; 14069 endInsert = true; 14070 } 14071 14072 playlistTransitionOn = true; 14073 if(preloader)preloader.style.display = 'block'; 14074 14075 playlistProcessCounter = -1; 14076 playlistProcessData = []; 14077 playlistProcessDataUrl = []; 14078 14079 if(Array.isArray(track))playlistProcessDataUrl = track; 14080 else playlistProcessDataUrl.push(track); 14081 14082 playlistLength = playlistProcessDataUrl.length; 14083 14084 lastPlaylist = playlistContent; 14085 14086 if(playlistDataReady){ 14087 playlistProcessData = playlistProcessDataUrl; 14088 buildPlaylist(); 14089 }else{ 14090 checkProcessCounter(); 14091 } 14092 14093 } 14094 14095 this.inputAudio = function(data){ 14096 if(!componentInited) return false; 14097 if(playlistTransitionOn) return false; 14098 14099 if(typeof data === 'undefined'){ 14100 alert('inputAudio method requires data parameter. inputAudio failed.'); 14101 return false; 14102 } 14103 14104 //enable active item, if exist, but dont dispose current playlist 14105 if(activePlaylistItem)enableActivePlaylistItem(); 14106 if(playlistLength > 0)_HAPPlaylistManager.reSetCounter(); 14107 14108 currMediaData = data; 14109 mediaType = data.type; 14110 mediaPath = getAudioUrl(data); 14111 14112 if(nonProcessMedia.indexOf(mediaType) == -1){ 14113 alert('inputAudio method supports tracks that dont require processing: ' + nonProcessMedia); 14114 return false;
14115 } 14116 14117 setTitleAndThumb(); 14118 if(useMediaSession)updateMetadata(); 14119 14120 autoPlay = true; 14121 settings.autoPlay = true; 14122 14123 initAudio(); 14124 } 14125 14126 this.removeTrack = function(format, value) { 14127 if(!componentInited || playlistTransitionOn) return false; 14128 if(playlistLength == 0) return; 14129 14130 var track, found, title; 14131 14132 if(format == 'title'){ 14133 14134 var i; 14135 for(i = 0;i < playlistLength; i++){ 14136 if(value == playlistDataArr[i].data.title){ 14137 track = playlistContent.querySelectorAll('.hap-playlist-item')[i]; 14138 console.log(track,value) 14139 found = true; 14140 break; 14141 } 14142 } 14143 14144 if(!found){ 14145 alert('Track with title "' + value + '" doesnt exist. RemoveTrack failed.'); 14146 return false; 14147 } 14148 14149 }else if(format == 'counter'){ 14150 14151 value = parseInt(value,10); 14152 14153 if(value < 0 || value > playlistLength-1){ 14154 alert('Track number "' + value + '" doesnt exist. RemoveTrack failed.'); 14155 return false; 14156 } 14157 14158 track = playlistContent.querySelectorAll('.hap-playlist-item')[value]; 14159 14160 }else if(format == 'id'){//data-media-id 14161 14162 track = playlistContent.querySelector('.hap-playlist-item[data-media-id="'+value+'"]'); 14163 14164 if(!track){ 14165 alert('Track with media id "' + value + '" doesnt exist. RemoveTrack failed.'); 14166 return false; 14167 } 14168 14169 }else{ 14170 alert('removeTrack method failed.'); 14171 return false; 14172 } 14173 14174 14175 //remove track 14176 track.remove(); 14177 playlistDataArr.splice(parseInt(track.getAttribute('data-id'),10),1); 14178 14179 14180 updatePlaylist(true); 14181 14182 if(playlistLength > 0){ 14183 14184 var current_counter = _HAPPlaylistManager.getCounter(); 14185 if(value == current_counter){//remove number equal to current counter 14186 cleanMedia(); 14187 _HAPPlaylistManager.setPlaylistItems(playlistLength);//counter resets to -1 14188 }else{ 14189 _HAPPlaylistManager.setPlaylistItems(playlistLength, false); 14190 if(value < current_counter){//remove number less than current counter 14191 _HAPPlaylistManager.reSetCounter(_HAPPlaylistManager.getCounter()-1);//if we removed media before current playing media, descrease counter! 14192 }else{//remove number larger than current counter, current counter doesnt change 14193 } 14194 } 14195 14196 }else{//we removed last track in playlist 14197 destroyPlaylist(); 14198 } 14199 14200 } 14201 14202 this.sort = function(order) { 14203 if(!componentInited) return false; 14204 if(playlistLength < 3) return false; 14205 14206 if(typeof order === 'undefined'){ 14207 console.log('Sort method requires order parameter. Sort method failed.'); 14208 return false; 14209 } 14210 14211 if(sortOrder == v) return false; 14212 14213 var item_list = playlistContent.querySelectorAll('.hap-playlist-item'), 14214 items = [...item_list], 14215 len = items.length, v = order.toLowerCase(); 14216 14217 if(v == 'title-asc'){ 14218 14219 HAPUtils.keysrt2(playlistDataArr, 'data', 'title'); 14220 14221 var i, arr = []; 14222 for(i = 0;i < playlistLength; i++){ 14223 arr.push(playlistDataArr[i].id); 14224 } 14225 14226 if(sortAlpha)sortAlpha.querySelector('.hap-btn-sort-alpha-up').style.display = 'none'; 14227 if(sortAlpha)sortAlpha.querySelector('.hap-btn-sort-alpha-down').style.display = 'block'; 14228 14229 } 14230 else if(v == 'title-desc'){ 14231 14232 HAPUtils.keysrt2(playlistDataArr, 'data', 'title', true); 14233 14234 var i, arr = []; 14235 for(i = 0;i < playlistLength; i++){ 14236 arr.push(playlistDataArr[i].id); 14237 } 14238 14239 if(sortAlpha)sortAlpha.querySelector('.hap-btn-sort-alpha-up').style.display = 'block'; 14240 if(sortAlpha)sortAlpha.querySelector('.hap-btn-sort-alpha-down').style.display = 'none'; 14241 14242 } 14243 else if(v == 'random'){ 14244 14245 var arr = HAPUtils.randomiseArray(playlistLength); 14246 14247 playlistDataArr = HAPUtils.sortArray(playlistDataArr, arr); 14248 14249 } 14250 else{ 14251 console.log('Unknown sort order. Sort method failed.'); 14252 return; 14253 } 14254 14255 sortOrder = v; 14256 14257 var current_counter = mediaCounter, orderedItems; 14258 14259 //reposition data 14260 14261 let modifiedArr = arr.map(function(v){ 14262 return items[v]; 14263 }); 14264 14265 modifiedArr.forEach(function(item) { 14266 playlistContent.append(item) 14267 }); 14268 14269 //update counter 14270 if(current_counter!=-1){ 14271 14272 //find new position of active item 14273 14274 var el = playlistContent.querySelector(".hap-playlist-item[data-id='" + current_counter + "']") 14275 var new_counter = [...playlistContent.childNodes].indexOf(el); 14276 14277 _HAPPlaylistManager.reSetCounter(new_counter); 14278 14279 } 14280 14281 updatePlaylist(true); 14282 14283 } 14284 14285 this.destroyInstance = function(){ 14286 destroyPlaylist(); 14287 cleanMedia(); 14288 if(settings.usePlaylistScroll){ 14289 14290 if(settings.playlistScrollType == 'perfect-scrollbar'){ 14291 if(playlistScroll){ 14292 playlistScroll.destroy(); 14293 playlistScroll = null; 14294 } 14295 } 14296 14297 playlistScrollInit = false;
14298 } 14299 14300 if(adContent){ 14301 adContent.remove(); 14302 adContent = null; 14303 } 14304 14305 14306 } 14307 this.destroyInstance2 = function(){ 14308 cleanMedia(); 14309 14310 playlistContent.innerHTML = ""; 14311 14312 if(settings.usePlaylistScroll){ 14313 14314 if(settings.playlistScrollType == 'perfect-scrollbar'){ 14315 if(playlistScroll){ 14316 playlistScroll.destroy(); 14317 playlistScroll = null; 14318 } 14319 } 14320 14321 playlistScrollInit = false; 14322 } 14323 if(settings.sortableTracks && settings.sortableTracksSet){ 14324 if(Sortable)Sortable.destroy();//because of popup 14325 settings.sortableTracksSet = false; 14326 } 14327 14328 /*if(adContent){ 14329 adContent.remove(); 14330 adContent = null; 14331 }*/ 14332 } 14333 this.destroyMedia = function() { 14334 if(!componentInited) return false; 14335 destroyMedia(); 14336 } 14337 this.destroyPlaylist = function() { 14338 if(!componentInited) return false; 14339 destroyPlaylist(); 14340 } 14341 this.isCrossFade = function(){ 14342 return crossFadeOn; 14343 } 14344 this.setPlaybackRate = function(v){ 14345 if(!componentInited) return false; 14346 if(!mediaType) return false; 14347 14348 settings.playbackRate = v; 14349 if(_HAPPlaybackRateSlider)_HAPPlaybackRateSlider.setVisual(v); 14350 14351 if(mediaType == 'youtube'){ 14352 youtubePlayer.setPlaybackRate(Number(v)); 14353 }else{ 14354 if(activeAudio){ 14355 try{ 14356 activeAudio.playbackRate = Number(v); 14357 }catch(er){} 14358 } 14359 } 14360 if(videoSync){ 14361 try{ 14362 videoSync.playbackRate = Number(v); 14363 }catch(er){} 14364 } 14365 14366 } 14367 this.toggleRandom = function(v) { 14368 if(!componentInited) return false; 14369 if(typeof _HAPPlaylistManager === 'undefined') return false; 14370 if(typeof v !== 'undefined')settings.randomPlay=v; 14371 else settings.randomPlay=!settings.randomPlay; 14372 _HAPPlaylistManager.setRandom(settings.randomPlay); 14373 14374 if(randomToggle){ 14375 randomToggle.querySelectorAll('.hap-btn').forEach(function(el){ 14376 el.style.display = 'none'; 14377 }) 14378 14379 if(settings.randomPlay)randomToggle.querySelector('.hap-btn-random-on').style.display = 'block'; 14380 else randomToggle.querySelector('.hap-btn-random-off').style.display = 'block'; 14381 } 14382 14383 if(_HAPStickyPlayer)_HAPStickyPlayer.setRandom(settings.randomPlay) 14384 14385 } 14386 this.setLoop = function(v) { 14387 if(!componentInited) return false; 14388 if(typeof _HAPPlaylistManager === 'undefined') return false; 14389 14390 settings.loopState = v; 14391 14392 if(loopToggle){ 14393 loopToggle.querySelectorAll('.hap-btn').forEach(function(el){ 14394 el.style.display = 'none'; 14395 }) 14396 14397 loopStateCounter = loopStateArr.indexOf(settings.loopState); 14398 loopToggle.querySelector('.hap-btn-loop-'+settings.loopState).style.display = 'block'; 14399 14400 } 14401 14402 _HAPPlaylistManager.setLooping(settings.loopState); 14403 14404 if(_HAPStickyPlayer)_HAPStickyPlayer.setLoop(settings.loopState) 14405 } 14406 this.getVolume = function() { 14407 return settings.volume; 14408 } 14409 this.setVolume = function(val) { 14410 if(!componentInited) return false; 14411 14412 if(val<0) val=0; 14413 else if(val>1) val=1; 14414 14415 settings.volume = val; 14416 14417 if(_HAPAdManager)_HAPAdManager.setVolume(settings.volume) 14418 14419 if(isIma && isImaOn)_IMALoader.setVolume(settings.volume) 14420 14421 if(mediaType == 'youtube'){ 14422 if(youtubePlayer && youtubeReady){ 14423 youtubePlayer.setVolume(settings.volume * 100); 14424 } 14425 }else{ 14426 if(activeAudio){ 14427 activeAudio.volume = settings.volume; 14428 if(settings.volume == 0)activeAudio.muted = true; 14429 else activeAudio.muted = false; 14430 } 14431 } 14432 14433 if(_volumeSlider)_volumeSlider.setVisual(settings.volume); 14434 14435 if(settings.useStickyPlayer && window['hap_fixed_active_player'] == settings.instanceName){ 14436 _HAPStickyPlayer.setVisual(settings.volume) 14437 } 14438 } 14439 this.toggleMute = function(){ 14440 if(!componentInited) return false; 14441 14442 if(settings.volume > 0){ 14443 lastVolume = settings.volume;//remember last volume 14444 settings.volume = 0; 14445 }else{ 14446 settings.volume = lastVolume;//restore last volume 14447 } 14448 14449 self.setVolume(settings.volume) 14450 14451 } 14452 this.setAutoPlay = function(value){ 14453 autoPlay = value; 14454 settings.autoPlay = true; 14455 } 14456 this.seek = function(v){ 14457 if(!componentInited) return false; 14458 if(!mediaType) return false; 14459 14460 if(settings.disableSeekbarInRange && rangeOn)return false; 14461 if(settings.disableSeekbar) return false; 14462 if(settings.disableSongSkip) return false; 14463 14464 if(mediaType == 'youtube'){ 14465 if(youtubePlayer && youtubeReady)youtubePlayer.seekTo(v); 14466 }else if(mediaType == 'audio'){ 14467 if(activeAudio){
14468 try{ 14469 activeAudio.currentTime = v; 14470 }catch(er){console.log(er)} 14471 } 14472 } 14473 } 14474 this.seekBackward = function(val){ 14475 if(!componentInited) return false; 14476 if(!mediaType) return false; 14477 if(crossFadeOn)cancelCrossFadeSeek(); 14478 14479 var st = val || settings.seekTime 14480 st = parseInt(st,10) 14481 14482 if(mediaType == 'youtube'){ 14483 if(youtubePlayer && youtubeReady){ 14484 var pos = Math.max(youtubePlayer.getCurrentTime() - st, 0); 14485 youtubePlayer.seekTo(pos); 14486 } 14487 }else{ 14488 if(activeAudio){ 14489 try{ 14490 activeAudio.currentTime = Math.max(activeAudio.currentTime - st, 0); 14491 }catch(er){console.log(er)} 14492 } 14493 } 14494 } 14495 this.seekForward = function(val){ 14496 if(!componentInited) return false; 14497 if(!mediaType) return false; 14498 if(crossFadeOn)cancelCrossFadeSeek(); 14499 14500 if(settings.disableSeekbarInRange && rangeOn)return false; 14501 if(settings.disableSeekbar) return false; 14502 if(settings.disableSongSkip) return false; 14503 14504 var st = val || settings.seekTime 14505 st = parseInt(st,10) 14506 14507 if(mediaType == 'youtube'){ 14508 if(youtubePlayer && youtubeReady){ 14509 var pos = Math.min(youtubePlayer.getCurrentTime() + st, youtubePlayer.getDuration()); 14510 youtubePlayer.seekTo(pos); 14511 } 14512 }else{ 14513 if(activeAudio){ 14514 try{ 14515 activeAudio.currentTime = Math.min(activeAudio.currentTime + st, activeAudio.duration); 14516 }catch(er){console.log(er)} 14517 } 14518 } 14519 } 14520 this.getCurrentMediaUrl = function(){ 14521 if(!componentInited) return false; 14522 if(!mediaType) return ''; 14523 14524 var current_url = window.location.href, separator;//check if url contains other parameters 14525 14526 //clear existing parameters from url 14527 if(current_url.indexOf('hap-') > -1){ 14528 var params = current_url.substring(current_url.indexOf('?')); 14529 params = params.split('&'); 14530 var i, len = params.length; 14531 for(i = len - 1; i > -1; i--){ 14532 if(params[i].indexOf('hap-') > -1){ 14533 params.splice(i, 1); 14534 } 14535 } 14536 14537 var base_url = current_url.substring(0, current_url.indexOf('?')+1);//get with ? 14538 if(params.length){//append rest params which are not ours 14539 var i, len = params.length, p; 14540 for(i = 0; i < len; i++){ 14541 p = params[i]; 14542 if(p.charAt(0) == '?'){ 14543 base_url += p.substring(1);//remove ? 14544 }else{ 14545 if(i > 0){ 14546 base_url += '&'+p; 14547 }else{ 14548 base_url += p;//after ? 14549 } 14550 } 14551 } 14552 } 14553 14554 current_url = base_url; 14555 } 14556 14557 if(current_url.indexOf('?') == -1){ 14558 separator = '?' 14559 }else{ 14560 if(current_url.charAt(current_url.length-1) == '?' || current_url.charAt(current_url.length-1) == '&')separator = ''; 14561 else separator = '&'; 14562 } 14563 14564 14565 var instance = 'hap-query-instance='+encodeURIComponent(settings.instanceName); //differentaite multiple instances 14566 var scroll = '&hap-scroll-to-player=1'; //scroll to player on start 14567 14568 //share url to specific media 14569 if(currMediaData.mediaId != undefined)var activeItem = '&hap-media-id='+currMediaData.mediaId; 14570 else var activeItem = '&hap-active-item='+mediaCounter; 14571 var start = mediaStarted ? '&hap-resume-time='+Math.floor(self.getCurrentTime()) : ''; 14572 14573 var autoplay = '&hap-auto-play=' + (settings.autoPlay ? '1' : '0'); 14574 14575 var share_url = separator + instance + scroll + activeItem + start + autoplay; 14576 14577 if(currMediaData.mediaId != undefined && singleMediaSourcesArr.indexOf(currMediaData.origtype) == -1 && currMediaData.safeTitle){//add title if we have same media-id 14578 var title = '&hap-media-title=' + encodeURIComponent(currMediaData.safeTitle); 14579 share_url += title; 14580 } 14581 14582 return current_url + share_url; 14583 14584 } 14585 this.getBUrl = function(url){ 14586 14587 bUrl = null; 14588 14589 if(burl_request){ 14590 burl_request.abort(); 14591 burl_request = null; 14592 } 14593 14594 burl_request = new XMLHttpRequest(); 14595 burl_request.onreadystatechange = function() { 14596 if (burl_request.readyState == 4) { 14597 14598 var reader = new FileReader(); 14599 reader.readAsArrayBuffer(burl_request.response); 14600 reader.onload = function(e){ 14601 14602 var contents = e.target.result; 14603 var uint8Array = new Uint8Array(contents); 14604 var arrayBuffer = uint8Array.buffer; 14605 if(isIOS || isSafari){ 14606 var blob = new Blob([arrayBuffer], {type: "audio/mpeg" }); 14607 }else{ 14608 var blob = new Blob([arrayBuffer]); 14609 } 14610 14611 bUrl = URL.createObjectURL(blob); 14612 14613 } 14614 } 14615 }; 14616 burl_request.responseType = 'blob'; 14617 burl_request.open('GET', url, true); 14618 burl_request.send(); 14619 14620 } 14621 this.getCurrentTime = function(){ 14622 if(mediaType == 'youtube'){ 14623 if(youtubePlayer && youtubeReady)return youtubePlayer.getCurrentTime(); 14624 else return 0; 14625 }else{ 14626 if(activeAudio)return activeAudio.currentTime; 14627 else return 0; 14628 } 14629 } 14630 this.getDuration = function(){ 14631 if(!componentInited) return false;
14632 if(!mediaType) return false; 14633 14634 if(mediaType == 'youtube'){ 14635 if(youtubePlayer && youtubeReady)return youtubePlayer.getDuration(); 14636 }else{ 14637 if(activeAudio)return activeAudio.duration; 14638 } 14639 } 14640 this.setSortable = function(){ 14641 if(!componentInited) return false; 14642 if(settings.sortableTracks && !settings.sortableTracksSet)setSortableTracks(); 14643 } 14644 14645 this.initPlaylistScroll = function(){ 14646 if(!componentInited) return false; 14647 if(settings.usePlaylistScroll){ 14648 14649 if(settings.playlistScrollType == 'perfect-scrollbar' && !playlistScrollInit){ 14650 if(playlistInner)checkPlaylistScroll(playlistInner); 14651 playlistScrollInit = true; 14652 } 14653 14654 } 14655 } 14656 this.destroyPlaylistScroll = function(){ 14657 if(!componentInited) return false; 14658 if(settings.usePlaylistScroll){ 14659 14660 if(settings.playlistScrollType == 'perfect-scrollbar'){ 14661 if(playlistScroll){ 14662 playlistScroll.destroy(); 14663 playlistScroll = null; 14664 } 14665 } 14666 14667 playlistScrollInit = false; 14668 } 14669 } 14670 this.getSetupDone = function(){ 14671 return componentInited; 14672 } 14673 this.getMediaPlaying = function(){ 14674 if(!componentInited) return false; 14675 return mediaPlaying; 14676 } 14677 this.getPlaylistLoading = function(){ 14678 return playlistTransitionOn; 14679 } 14680 this.getCounter = function(){ 14681 if(componentInited) return typeof _HAPPlaylistManager !== 'undefined' ? _HAPPlaylistManager.getCounter() : -1; 14682 else return null; 14683 } 14684 this.getPlaylistContent = function(){ 14685 return playlistContent; 14686 } 14687 this.getPlaylistData = function(){ 14688 return playlistDataArr; 14689 } 14690 this.getLastPlaylistData = function(){ 14691 if(!componentInited) return false; 14692 return lastPlaylistDataArr; 14693 } 14694 this.getPlaylistLength = function(){ 14695 if(!componentInited) return false; 14696 return HAPUtils.isNumber(playlistLength) ? playlistLength : 0; 14697 } 14698 this.getPlaylistList = function(){ 14699 return playlistList; 14700 } 14701 this.getSettings = function(){ 14702 return settings; 14703 } 14704 this.getCurrMediaData = function(){ 14705 if(!componentInited) return false; 14706 return currMediaData; 14707 } 14708 this.getWrapper = function(){ 14709 return wrapper; 14710 } 14711 this.getPlaylistItems = function(){ 14712 if(!componentInited) return false; 14713 var arr = []; 14714 playlistContent.querySelectorAll('.hap-playlist-item').forEach(function(el){ 14715 arr.push(el); 14716 }); 14717 return arr; 14718 } 14719 this.openPopup = function(){ 14720 if(!componentInited) return false; 14721 if(settings.isPopup) return false; 14722 hapOpenPopup(settings, self); 14723 } 14724 this.togglePlaylist = function(){ 14725 14726 //preset mods 14727 14728 if(class_list.indexOf('hap-art-narrow-light') > -1 || class_list.indexOf('hap-art-narrow-dark') > -1){ 14729 14730 if(!settings.playlistOpened){ 14731 playerHolder.classList.add('hap-player-holder-closed') 14732 playlistHolder.classList.add('hap-playlist-holder-opened') 14733 }else{ 14734 playerHolder.classList.remove('hap-player-holder-closed') 14735 playlistHolder.classList.remove('hap-playlist-holder-opened') 14736 } 14737 14738 }else if(class_list.indexOf('hap-art-wide-light') > -1 || class_list.indexOf('hap-art-wide-dark') > -1 || class_list.indexOf('hap-brona-light') > -1 || class_list.indexOf('hap-brona-dark') > -1){ 14739 14740 if(!settings.playlistOpened){ 14741 14742 playlistHolder.addEventListener('transitionend', function cb(e){ 14743 e.currentTarget.removeEventListener(e.type, cb); 14744 14745 playlistHolder.style.height = 'auto' 14746 }) 14747 14748 playlistHolder.classList.remove('hap-playlist-closed-v') 14749 14750 }else{ 14751 14752 var ph = parseInt(playlistHolder.clientHeight,10) 14753 playlistHolder.style.height = ph+'px' 14754 14755 setTimeout(function(){ 14756 playlistHolder.classList.add('hap-playlist-closed-v') 14757 },100) 14758 14759 } 14760 14761 }else if(class_list.indexOf('hap-fixed') > -1){ 14762 14763 if(settings.playlistOpened){ 14764 wrapper.style.bottom = -playlistHolder.offsetHeight+'px'; 14765 }else{ 14766 wrapper.style.bottom = -1+'px'; 14767 } 14768 14769 }else if(class_list.indexOf('hap-fixed2') > -1){ 14770 14771 if(settings.playlistOpened){ 14772 playlistHolder.style.bottom = -playlistHolder.offsetHeight+'px'; 14773 14774 wrapper.querySelector('.hap-ex-controls')?.classList.add('hap-ex-controls-shown') 14775 14776 }else{ 14777 playlistHolder.style.bottom = playerHolder.offsetHeight+'px'; 14778 14779 wrapper.querySelector('.hap-ex-controls')?.classList.remove('hap-ex-controls-shown') 14780 14781 } 14782 14783 } 14784 14785 settings.playlistOpened = !settings.playlistOpened; 14786 14787 if(settings.playlistOpened){ 14788 wrapper.classList.add('hap-is-playlist-opened') 14789 }else{ 14790 wrapper.classList.remove('hap-is-playlist-opened') 14791 } 14792 14793 } 14794 14795 function unhidePlayer(){ 14796 14797 if(settings.hidePlayerUntilMusicStart){ 14798 settings.hidePlayerUntilMusicStart = false;
14799 if(playerOuter)playerOuter.classList.remove('hap-music-player-force-hidden'); 14800 doneResizing(); 14801 checkPresetMods(); 14802 14803 if(playerOuter){ 14804 setTimeout(function(){ 14805 playerOuter.style.opacity = 1; 14806 },50); 14807 } 14808 14809 } 14810 } 14811 14812 14813 14814 14815 14816 14817 14818 14819 14820 14821 //############################################// 14822 /* remember playback position */ 14823 //############################################// 14824 14825 if(hasLocalStorage){ 14826 if(settings.continousKey){ 14827 if(!useContinousPlayback){ 14828 localStorage.removeItem(settings.continousKey); 14829 }else{ 14830 if(localStorage.getItem(settings.continousKey)){ 14831 14832 var d = JSON.parse(localStorage.getItem(settings.continousKey)); 14833 14834 settings.activePlaylist = d.activePlaylist, 14835 settings.resumeTime = d.resumeTime; 14836 settings.volume = d.volume; 14837 settings.activeItem = d.activeItem; 14838 settings.autoPlay = d.autoPlay; 14839 autoPlay = d.autoPlay; 14840 settings.lastPositionArr = d.lastPositionArr; 14841 14842 localStorage.removeItem(settings.continousKey); 14843 } 14844 } 14845 } 14846 } 14847 14848 14849 14850 //############################################// 14851 /* load playlist */ 14852 //############################################// 14853 14854 setTimeout(function(){ 14855 14856 if(settings.isPopup && settings.copyCurrentPlaylistToPopup){//open in popup and copy playlist from parent 14857 14858 /*playlistDataArr = settings.playlistDataArr;//get playlist data from settings 14859 playlistLength = playlistDataArr.length; 14860 _HAPPlaylistManager.setPlaylistItems(playlistLength, false); 14861 14862 if(settings.useStatistics){ 14863 if(!settings.usePlaylist){ 14864 var i; 14865 for(i = 0;i < playlistLength; i++){ 14866 playlistDataArr[i].data.hapStatsSet = false; 14867 } 14868 } 14869 updateStats(); 14870 } 14871 14872 lastPlaylist = playlistContent; 14873 14874 endInit();*/ 14875 14876 }else{ 14877 14878 if(queryPlaylist.length){//proces playlist from query params 14879 14880 playlistTransitionOn = true; 14881 preloader.style.display = 'block'; 14882 14883 self.fireEvent('playlistStartLoad', [{instance:self, instanceName:settings.instanceName}]); 14884 14885 playlistProcessDataUrl = queryPlaylist; 14886 playlistLength = playlistProcessDataUrl.length; 14887 checkProcessCounter(); 14888 14889 }else if(settings.activePlaylist && !HAPUtils.isEmpty(settings.activePlaylist)){ 14890 14891 setPlaylist(settings.activePlaylist);//process playlist 14892 14893 }else{ 14894 endInit(); 14895 } 14896 14897 } 14898 14899 },50); 14900 14901 14902 this.initPlaylist = function(){//from popup closed 14903 14904 if(queryPlaylist.length){//proces playlist from query params 14905 14906 playlistTransitionOn = true; 14907 preloader.style.display = 'block'; 14908 14909 self.fireEvent('playlistStartLoad', [{instance:self, instanceName:settings.instanceName}]); 14910 14911 playlistProcessDataUrl = queryPlaylist; 14912 playlistLength = playlistProcessDataUrl.length; 14913 checkProcessCounter(); 14914 14915 }else if(settings.activePlaylist && !HAPUtils.isEmpty(settings.activePlaylist)){ 14916 14917 setPlaylist(settings.activePlaylist);//process playlist 14918 14919 }else{ 14920 endInit(); 14921 } 14922 14923 } 14924 14925 return this; 14926 14927 } 14928 14929 window.hap = hap; 14930 14931})(); 14932 14933 14934 14935 14936 14937 14938 14939 14940//############################################// 14941/* popup */ 14942//############################################// 14943 14944var hap_popup_window, hap_player_instance, hap_player_auto_instance, hasLocalStorage = HAPUtils.hasLocalStorage(); 14945 14946function hapOpenPopup(settings, inst){ 14947 14948 if(window.location.protocol == 'file:'){ 14949 alert('Using popup requires server connection.'); 14950 return false; 14951 } 14952 14953 if(hasLocalStorage && localStorage.getItem('hap_popup')){ 14954 return; 14955 } 14956 14957 hap_player_instance = inst; 14958 14959 if(hap_player_instance){ 14960 var wrapper = hap_player_instance.getWrapper(); 14961 }else if(hap_player_auto_instance){ 14962 var wrapper = hap_player_auto_instance.wrapper; 14963 } 14964 14965 var popupUrl = settings.popupUrl || settings.sourcePath + 'popup.html'+"?rand=" + (Math.random() * 99999999), 14966 pw = settings.popupWidth ? settings.popupWidth : wrapper.offsetWidth, 14967 ph = settings.popupHeight ? settings.popupHeight : wrapper.offsetHeight, 14968 left = (window.screen.width - parseInt(pw,10)) / 2, 14969 top = (window.screen.height - parseInt(ph,10)) / 2; 14970 14971 if(!hap_popup_window || hap_popup_window.closed){ 14972 hap_popup_window = window.open(popupUrl,'audio_player','menubar=no,toolbar=no,location=no,scrollbars=1,resizable,width='+pw+',height='+ph+',left='+left+',top='+top+''); 14973 14974 if(!hap_popup_window) { 14975 alert("Player can not be opened in a popup window because your browser is blocking Pop-Ups. You need to allow Pop-Ups in browser for this site to use the Player."); 14976 return false;
14977 } 14978 14979 } 14980} 14981 14982function hapPopupClosed(id, active_item){ 14983 if(document.getElementById(id)){ 14984 var wrapper = document.getElementById(id) 14985 wrapper.style.display = 'block'; 14986 setTimeout(function(){ 14987 wrapper.querySelector('.hap-player-outer').style.opacity = 1; 14988 },100) 14989 if(hap_player_instance){ 14990 14991 hap_player_instance.getSettings().activeItem = active_item; 14992 14993 hap_player_instance.initPlaylist() 14994 14995 hap_player_instance.initPlaylistScroll(); 14996 hap_player_instance.setSortable() 14997 }else{ 14998 //on auto open popup 14999 if(hap_player_auto_instance.settings)new hap(wrapper, hap_player_auto_instance.settings); 15000 else wrapper.style.display = 'none'; 15001 } 15002 } 15003} 15004 15005function hapNotifyParent(){//called from popup window when popup window has opened! 15006 15007 if(hap_popup_window && hap_popup_window.initPopup != undefined){ 15008 15009 /* 15010 NOTES: 15011 new+copies whole playlist list and loads active playlist again in player 15012 15013 old-This copies current playlist from playlist content to popup window (if load more, add more was used etc..) 15014 actions: 15015 add more - works 15016 load more (needs token from before, currently not implemented) 15017 15018 - accordion in popup has to reload 15019 */ 15020 15021 if(hap_player_instance){ 15022 15023 var settings = hap_player_instance.getSettings(); 15024 15025 settings.volume = hap_player_instance.getVolume(); 15026 settings.activePlaylist = settings.activePlaylist; 15027 settings.activeItem = hap_player_instance.getCounter(); 15028 settings.resumeTime = hap_player_instance.getCurrentTime(); 15029 15030 hap_player_instance.destroyInstance2(); 15031 15032 var wrapper = hap_player_instance.getWrapper(); 15033 15034 }else if(hap_player_auto_instance){ 15035 15036 var settings = hap_player_auto_instance.settings; 15037 settings.copyCurrentPlaylistToPopup = false; 15038 var wrapper = hap_player_auto_instance.wrapper; 15039 15040 } 15041 15042 var wrapper_id = wrapper.getAttribute('id'), 15043 css = document.getElementById('hap-inline-css') ? document.getElementById('hap-inline-css').outerHTML : null, 15044 playlist_list = document.getElementById('hap-playlist-list') ? document.getElementById('hap-playlist-list').outerHTML : null; 15045 wrapper2 = wrapper.outerHTML; 15046 wrapper.style.display = 'none'; 15047 wrapper.querySelector('.hap-player-outer').style.opacity = 0; 15048 15049 try { 15050 window[settings.instanceName] = hap_popup_window.initPopup(wrapper2, wrapper_id, settings, css, playlist_list); 15051 }catch(e){ 15052 alert('initPopup error: ' + e.message); 15053 return false; 15054 } 15055 15056 } 15057} 15058 15059
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.