1<?php 2 3use Ampache\Config\AmpConfig; 4use Ampache\Module\Broadcast\Broadcast_Server; 5use Ampache\Module\Playback\Stream; 6use Ampache\Module\Util\AjaxUriRetrieverInterface; 7use Ampache\Module\Util\Ui; 8 9global $dic; 10$ajaxUriRetriever = $dic->get(AjaxUriRetrieverInterface::class); 11$web_path = AmpConfig::get('web_path'); 12$cookie_string = (make_bool(AmpConfig::get('cookie_secure'))) 13 ? "path: '/', secure: true, samesite: 'Strict'" 14 : "path: '/', samesite: 'Strict'"; 15 16if ($iframed || $is_share) { ?> 17<link rel="stylesheet" href="<?php echo $web_path . Ui::find_template('jplayer.midnight.black-iframed.css', true) ?>" type="text/css" /> 18<?php 19} else { ?> 20<link rel="stylesheet" href="<?php echo $web_path . Ui::find_template('jplayer.midnight.black.css', true) ?>" type="text/css" /> 21<?php 22 } 23 24if (!$iframed) { 25 require_once Ui::find_template('stylesheets.inc.php'); ?> 26<link rel="stylesheet" href="<?php echo $web_path . Ui::find_template('jquery-editdialog.css', true); ?>" type="text/css" media="screen" /> 27<link rel="stylesheet" href="<?php echo $web_path; ?>/lib/modules/jquery-ui-ampache/jquery-ui.min.css" type="text/css" media="screen" /> 28<script src="<?php echo $web_path; ?>/lib/components/jquery/jquery.min.js"></script> 29<script src="<?php echo $web_path; ?>/lib/components/jquery-ui/jquery-ui.min.js"></script> 30<script src="<?php echo $web_path; ?>/lib/components/js-cookie/js-cookie-built.js"></script> 31<script src="<?php echo $web_path; ?>/lib/javascript/base.js"></script> 32<script src="<?php echo $web_path; ?>/lib/javascript/ajax.js"></script> 33<script src="<?php echo $web_path; ?>/lib/javascript/tools.js"></script> 34<script> 35var jsAjaxServer = "<?php echo $ajaxUriRetriever->getAjaxServerUri(); ?>"; 36var jsAjaxUrl = "<?php echo $ajaxUriRetriever->getAjaxUri(); ?>"; 37 38function update_action() 39{ 40 // Stub 41} 42</script> 43<?php 44} ?> 45<link href="<?php echo $web_path; ?>/lib/modules/UberViz/style.css" rel="stylesheet" type="text/css"> 46<?php if (AmpConfig::get('webplayer_aurora')) { ?> 47 <script src="<?php echo $web_path; ?>/lib/modules/aurora.js/aurora.js"></script> 48<?php 49} ?> 50<script src="<?php echo $web_path; ?>/lib/components/happyworm-jplayer/dist/jplayer/jquery.jplayer.min.js"></script> 51<script src="<?php echo $web_path; ?>/lib/components/happyworm-jplayer/dist/add-on/jplayer.playlist.min.js"></script> 52<script src="<?php echo $web_path; ?>/lib/javascript/jplayer.ext.js"></script> 53<script src="<?php echo $web_path; ?>/lib/javascript/jplayer.playlist.ext.js"></script> 54 55<script> 56var jplaylist = new Array(); 57var jtypes = new Array(); 58 59function convertMediaToJPMedia(media) 60{ 61 var jpmedia = {}; 62 jpmedia['title'] = media['title']; 63 jpmedia['artist'] = media['artist']; 64 jpmedia[media['filetype']] = media['url']; 65 jpmedia['poster'] = media['poster']; 66 jpmedia['artist_id'] = media['artist_id']; 67 jpmedia['album_id'] = media['album_id']; 68 jpmedia['media_id'] = media['media_id']; 69 jpmedia['media_type'] = media['media_type']; 70 jpmedia['replaygain_track_gain'] = media['replaygain_track_gain']; 71 jpmedia['replaygain_track_peak'] = media['replaygain_track_peak']; 72 jpmedia['replaygain_album_gain'] = media['replaygain_album_gain']; 73 jpmedia['replaygain_album_peak'] = media['replaygain_album_peak']; 74 jpmedia['r128_track_gain'] = media['r128_track_gain']; 75 jpmedia['r128_album_gain'] = media['r128_album_gain']; 76 77 return jpmedia; 78} 79 80function addMedia(media) 81{ 82 var jpmedia = convertMediaToJPMedia(media); 83 jplaylist.add(jpmedia); 84} 85 86function playNext(media) 87{ 88 var jpmedia = convertMediaToJPMedia(media); 89 jplaylist.addAfter(jpmedia, jplaylist.current); 90} 91</script> 92<script> 93function ExitPlayer() 94{ 95 $("#webplayer").text(''); 96 $("#webplayer").hide(); 97 98<?php 99if (AmpConfig::get('song_page_title')) { 100 echo "window.parent.document.title = '" . addslashes(AmpConfig::get('site_title')) . "';"; 101 } ?> 102 document.onbeforeunload = null; 103} 104 105function TogglePlayerVisibility() 106{ 107 if ($("#webplayer").is(":visible")) { 108 $("#webplayer").slideUp(); 109 } else { 110 $("#webplayer").slideDown(); 111 } 112} 113 114function TogglePlaylistExpand() 115{ 116 if ($(".jp-playlist").css("opacity") !== '1') { 117 $(".jp-playlist").css('top', '-255%'); 118 $(".jp-playlist").css('opacity', '1'); 119 $(".jp-playlist").css('height', '350%'); 120 } else { 121 $(".jp-playlist").css('top', '0px'); 122 $(".jp-playlist").css('opacity', '0.9'); 123 $(".jp-playlist").css('height', '95%'); 124 } 125} 126</script> 127<?php 128if ($iframed) { ?> 129<script> 130function NotifyOfNewSong(title, artist, icon) 131{ 132 if (artist === null) { 133 artist = ''; 134 } 135 if (!("Notification" in window)) { 136 console.error("This browser does not support desktop notification"); 137 } else { 138 if (Notification.permission !== 'denied') { 139 if (Notification.permission === 'granted') { 140 NotifyBrowser(title, artist, icon); 141 } else { 142 Notification.requestPermission(function (permission) { 143 if (!('permission' in Notification)) { 144 Notification.permission = permission; 145 } 146 NotifyBrowser(title, artist, icon); 147 }); 148 } 149 } else { 150 console.error("Desktop notification denied."); 151 } 152 } 153} 154 155function NotifyBrowser(title, artist, icon) 156{ 157 var notyTimeout = <?php echo AmpConfig::get('browser_notify_timeout'); ?>; 158 var notification = new Notification(title, { 159 body: artist, 160 icon: icon, 161 silent: true 162 }); 163 164 if (notyTimeout > 0) { 165 setTimeout(function(){ 166 notification.close() 167 }, notyTimeout * 1000); 168 } 169} 170 171function NotifyOfNewArtist() 172{ 173 refresh_slideshow(); 174} 175 176function SwapSlideshow() 177{ 178 swap_slideshow(); 179} 180 181function initAudioContext() 182{ 183 if (typeof AudioContext !== 'undefined') { 184 audioContext = new AudioContext(); 185 } else if (typeof webkitAudioContext !== 'undefined') { 186 audioContext = new webkitAudioContext(); 187 } else { 188 audioContext = null; 189 } 190} 191 192function isVisualizerEnabled() 193{ 194 return ($('#uberviz').css('visibility') == 'visible'); 195} 196 197var vizInitialized = false; 198var vizPrevHeaderColor = "#000"; 199var vizPrevPlayerColor = "#000"; 200function ShowVisualizer() 201{ 202 if (isVisualizerEnabled()) { 203 $('#uberviz').css('visibility', 'hidden'); 204 $('#equalizerbtn').css('visibility', 'hidden'); 205 $('#equalizer').css('visibility', 'hidden'); 206 $('#header').css('background-color', vizPrevHeaderColor); 207 $('#webplayer').css('background-color', vizPrevPlayerColor); 208 $('.jp-interface').css('background-color', 'rgb(25, 25, 25)'); 209 $('.jp-playlist').css('background-color', 'rgb(20, 20, 20)'); 210 } else { 211 // Resource not yet initialized? Do it. 212 if (!vizInitialized) { 213 if ((typeof AudioContext !== 'undefined') || (typeof webkitAudioContext !== 'undefined')) { 214 UberVizMain.init(); 215 vizInitialized = true; 216 AudioHandler.loadMediaSource($('.jp-jplayer').find('audio').get(0)); 217 } 218 } 219 220 if (vizInitialized) { 221 $('#uberviz').css('visibility', 'visible'); 222 $('#equalizerbtn').css('visibility', 'visible'); 223 vizPrevHeaderColor = $('#header').css('background-color'); 224 $('#header').css('background-color', 'transparent'); 225 vizPrevPlayerColor = $('#webplayer').css('background-color'); 226 $('#webplayer').css('cssText', 'background-color: #000 !important;'); 227 $('#webplayer').show(); 228 $("#webplayer-minimize").show(); 229 $('.jp-interface').css('background-color', '#000'); 230 $('.jp-playlist').css('background-color', '#000'); 231 } else { 232 alert("<?php echo T_("Your browser doesn't support this feature."); ?>"); 233 } 234 } 235} 236 237function ShowVisualizerFullScreen() 238{ 239 if (!isVisualizerEnabled()) { 240 ShowVisualizer(); 241 } 242 243 var element = document.getElementById("viz"); 244 if (element.requestFullScreen) { 245 element.requestFullScreen(); 246 } else if (element.webkitRequestFullScreen) { 247 element.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); 248 } else if (element.mozRequestFullScreen) { 249 element.mozRequestFullScreen(); 250 } else { 251 alert('Full-Screen not supported by your browser'); 252 } 253} 254 255function ShowEqualizer() 256{ 257 if (isVisualizerEnabled()) { 258 if ($('#equalizer').css('visibility') == 'visible') { 259 $('#equalizer').css('visibility', 'hidden'); 260 } else { 261 $('#equalizer').css('visibility', 'visible'); 262 } 263 } 264} 265 266function SavePlaylist() 267{ 268 if (jplaylist['playlist'].length > 0) { 269 var url = "<?php echo $ajaxUriRetriever->getAjaxUri(); ?>?page=playlist&action=append_item&item_type=" + jplaylist['playlist'][0]["media_type"] + "&item_id="; 270 for (var i = 0; i < jplaylist['playlist'].length; i++) { 271 url += "," + jplaylist['playlist'][i]["media_id"]; 272 } 273 handlePlaylistAction(url, 'rb_append_dplaylist_new'); 274 } 275} 276 277function SaveToExistingPlaylist(event) 278{ 279 if (jplaylist['playlist'].length > 0) { 280 var item_ids = ""; 281 for (var i = 0; i < jplaylist['playlist'].length; i++) { 282 item_ids += "," + jplaylist['playlist'][i]["media_id"]; 283 } 284 showPlaylistDialog(event, jplaylist['playlist'][0]["media_type"], item_ids); 285 } 286} 287 288var audioContext = null; 289var mediaSource = null; 290var replaygainEnabled = false; 291var replaygainNode = null; 292initAudioContext(); 293 294function ToggleReplayGain() 295{ 296 if (replaygainNode === null) { 297 var mediaElement = $('.jp-jplayer').find('audio').get(0); 298 if (mediaElement) { 299 if (audioContext !== null) { 300 mediaSource = audioContext.createMediaElementSource(mediaElement); 301 replaygainNode = audioContext.createGain(); 302 replaygainNode.gain.value = 1; 303 mediaSource.connect(replaygainNode); 304 replaygainNode.connect(audioContext.destination); 305 } 306 } 307 } 308 309 if (replaygainNode != null) { 310 replaygainEnabled = !replaygainEnabled; 311 Cookies.set('replaygain', replaygainEnabled, {<?php echo $cookie_string ?>}); 312 ApplyReplayGain(); 313 314 if (replaygainEnabled) { 315 $('#replaygainbtn').css('box-shadow', '0px 1px 0px 0px orange'); 316 } else { 317 $('#replaygainbtn').css('box-shadow', ''); 318 } 319 } 320} 321 322function ApplyReplayGain() 323{ 324 if (replaygainNode != null) { 325 var gainlevel = 1; 326 var replaygain = 0; 327 var peakamplitude = 1; 328 if (replaygainEnabled && currentjpitem != null) { 329 var replaygain_track_gain = currentjpitem.attr("data-replaygain_track_gain"); 330 var r128_track_gain = currentjpitem.attr("data-r128_track_gain"); 331 332 if (r128_track_gain !== 'null') { 333 // R128 PREFERRED 334 replaygain = parseInt(r128_track_gain / 256); // LU/dB away from baseline of -23 LUFS/dB, stored as Q7.8 (2 ^ 8) https://tools.ietf.org/html/rfc7845.html#page-25 335 var referenceLevel = parseInt(-23); // LUFS https://en.wikipedia.org/wiki/EBU_R_128#Specification 336 var targetLevel = parseInt(-18); // LUFS/dB; 337 var masteredVolume = referenceLevel - replaygain; 338 var difference = targetLevel - masteredVolume; 339 340 gainlevel = (Math.pow(10, ((difference /* + Gpre-amp */) / 20))); 341 } else if (replaygain_track_gain !== 'null') { 342 // REPLAYGAIN FALLBACK 343 replaygain = parseFloat(replaygain_track_gain); 344 345 if (replaygain != null) { 346 var track_peak = currentjpitem.attr("data-replaygain_track_peak"); 347 if (track_peak !== 'null') { 348 peakamplitude = parseFloat(track_peak); 349 } 350 gainlevel = Math.min(Math.pow(10, ((replaygain /* + Gpre-amp */) / 20)), (1 / peakamplitude)); 351 } 352 } 353 } 354 355 replaygainNode.gain.value = gainlevel; 356 } 357} 358</script> 359<?php 360} ?> 361<script> 362<?php if (AmpConfig::get('waveform') && !$is_share) { ?> 363var wavclicktimer = null; 364var shouts = {}; 365function WaveformClick(songid, time) 366{ 367 // Double click 368 if (wavclicktimer != null) { 369 clearTimeout(wavclicktimer); 370 wavclicktimer = null; 371 NavigateTo('<?php echo $web_path ?>/shout.php?action=show_add_shout&type=song&id=' + songid + '&offset=' + time); 372 } else { 373 // Single click 374 if (brconn === null) { 375 wavclicktimer = setTimeout(function() { 376 wavclicktimer = null; 377 $("#jquery_jplayer_1").data("jPlayer").play(time); 378 }, 250); 379 } 380 } 381} 382 383function ClickTimeOffset(e) 384{ 385 var parrentOffset = $(".waveform").offset().left; 386 var offset = e.pageX - parrentOffset; 387 var duration = $("#jquery_jplayer_1").data("jPlayer").status.duration; 388 var time = duration * (offset / 400); 389 390 return time; 391} 392 393function ShowWaveform() 394{ 395 $('.waveform').css('visibility', 'visible'); 396} 397 398function HideWaveform() 399{ 400 $('.waveform').css('visibility', 'hidden'); 401} 402<?php 403 } ?> 404 405var brkey = ''; 406var brconn = null; 407 408function startBroadcast(key) 409{ 410 brkey = key; 411 412 listenBroadcast(); 413 brconn.onopen = function(e) { 414 sendBroadcastMessage('AUTH_SID', '<?php echo session_id(); ?>'); 415 sendBroadcastMessage('REGISTER_BROADCAST', brkey); 416 sendBroadcastMessage('SONG', currentjpitem.attr("data-media_id")); 417 }; 418} 419 420function startBroadcastListening(broadcast_id) 421{ 422 listenBroadcast(); 423 424 // Hide few UI information on listening mode 425 $('.jp-previous').css('visibility', 'hidden'); 426 $('.jp-play').css('visibility', 'hidden'); 427 $('.jp-pause').css('visibility', 'hidden'); 428 $('.jp-next').css('visibility', 'hidden'); 429 $('.jp-stop').css('visibility', 'hidden'); 430 $('.jp-toggles').css('visibility', 'hidden'); 431 $('.jp-playlist').css('visibility', 'hidden'); 432 $('#broadcast').css('visibility', 'hidden'); 433 434 $('.jp-seek-bar').css('pointer-events', 'none'); 435 436 brconn.onopen = function(e) { 437 sendBroadcastMessage('AUTH_SID', '<?php echo Stream::get_session(); ?>'); 438 sendBroadcastMessage('REGISTER_LISTENER', broadcast_id); 439 }; 440} 441 442function listenBroadcast() 443{ 444 if (brconn != null) { 445 stopBroadcast(); 446 } 447 448 brconn = new WebSocket('<?php echo Broadcast_Server::get_address(); ?>'); 449 brconn.onmessage = receiveBroadcastMessage; 450} 451 452var brLoadingSong = false; 453var brBufferingSongPos = -1; 454 455function receiveBroadcastMessage(e) 456{ 457 var jp = $("#jquery_jplayer_1").data("jPlayer"); 458 var msgs = e.data.split(';'); 459 460 for (var i = 0; i < msgs.length; ++i) { 461 var msg = msgs[i].split(':'); 462 if (msg.length == 2) { 463 switch (msg[0]) { 464 case 'PLAYER_PLAY': 465 if (msg[1] == '1') { 466 if (jp.status.paused) { 467 jp.play(); 468 } 469 } else { 470 if (!jp.status.paused) { 471 jp.pause(); 472 } 473 } 474 break; 475 case 'SONG': 476 addMedia($.parseJSON(atob(msg[1]))); 477 brLoadingSong = true; 478 // Buffering song position in case it is asked in the next sec. 479 // Otherwise we will move forward on the previous song instead of the new currently loading one 480 setTimeout(function() { 481 if (brBufferingSongPos > -1) { 482 jp.play(brBufferingSongPos); 483 brBufferingSongPos = -1; 484 } 485 brLoadingSong = false; 486 }, 1000); 487 jplaylist.next(); 488 break; 489 case 'SONG_POSITION': 490 if (brLoadingSong) { 491 brBufferingSongPos = parseFloat(msg[1]); 492 } else { 493 jp.play(parseFloat(msg[1])); 494 } 495 break; 496 case 'NB_LISTENERS': 497 $('#broadcast_listeners').html(msg[1]); 498 break; 499 case 'INFO': 500 // Display information notification to user here 501 break; 502 case 'ENDED': 503 jp.stop(); 504 break; 505 default: 506 alert('Unknown message code'); 507 break; 508 } 509 } 510 } 511} 512 513function sendBroadcastMessage(cmd, value) 514{ 515 if (brconn != null && brconn.readyState == 1) { 516 var msg = cmd + ':' + value + ';'; 517 brconn.send(msg); 518 } 519} 520 521function stopBroadcast() 522{ 523 brkey = ''; 524 if (brconn != null && brconn.readyState == 1) { 525 brconn.close(); 526 } 527 brconn = null; 528} 529 530<?php if ($iframed && AmpConfig::get('webplayer_confirmclose') && !$is_share) { ?> 531window.parent.onbeforeunload = function (evt) { 532 if ($("#jquery_jplayer_1") !== undefined && $("#jquery_jplayer_1").data("jPlayer") !== undefined && !$("#jquery_jplayer_1").data("jPlayer").status.paused && 533 (document.activeElement === undefined || (document.activeElement.href.indexOf('/batch.php') < 0 && document.activeElement.href.indexOf('/stream.php') < 0))) { 534 var message = '<?php echo T_('Media is currently playing, are you sure you want to close?') . ' ' . AmpConfig::get('site_title') . '?'; ?>'; 535 if (typeof evt == "undefined") { 536 evt = window.event; 537 } 538 if (evt) { 539 evt.returnValue = message; 540 } 541 return message; 542 } 543 544 return null; 545} 546<?php 547 } ?> 548<?php if ($iframed && AmpConfig::get('webplayer_confirmclose') && !$is_share) { ?> 549window.addEventListener('storage', function (event) { 550 if (event.key == 'ampache-current-webplayer') { 551 // The latest used webplayer is not this player, pause song if playing 552 if (event.newValue != jpuqid) { 553 if (!$("#jquery_jplayer_1").data("jPlayer").status.paused) { 554 $("#jquery_jplayer_1").data("jPlayer").pause(); 555 } 556 } 557 } 558}); 559<?php 560 } ?> 561</script> 562