|
@@ -1,750 +1,750 @@
|
|
|
-<!DOCTYPE html>
|
|
|
-<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
|
-<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
|
|
|
-<html>
|
|
|
-<head>
|
|
|
- <meta charset="UTF-8">
|
|
|
- <meta name="theme-color" content="#232324">
|
|
|
- <link rel="stylesheet" href="../script/semantic/semantic.min.css">
|
|
|
- <link rel="icon" type="image/png" href="./img/small_icon.png">
|
|
|
- <script src="../script/jquery.min.js"></script>
|
|
|
- <script src="../script/semantic/semantic.min.js"></script>
|
|
|
- <script src="../script/ao_module.js"></script>
|
|
|
- <style>
|
|
|
- body{
|
|
|
- padding:0px !important;
|
|
|
- overflow: hidden;
|
|
|
- height:100%;
|
|
|
- background-color: transparent !important;
|
|
|
- }
|
|
|
-
|
|
|
- .coloredBackground{
|
|
|
- background: rgb(253,255,254);
|
|
|
- background: linear-gradient(321deg, rgba(253,255,254,1) 29%, rgba(240,250,255,1) 100%);
|
|
|
- }
|
|
|
-
|
|
|
- html, body { height: 100%; width: 100%; margin: 0; }
|
|
|
- .playerInterface{
|
|
|
- background-color:rgba(226, 221, 220,0.95);
|
|
|
- height:150px !important;
|
|
|
- width:100%;
|
|
|
- }
|
|
|
-
|
|
|
- #playerUI{
|
|
|
- margin-left:0px !important;
|
|
|
- margin-right:0px !important;
|
|
|
- width:100% !important;
|
|
|
- position: relative;
|
|
|
- color: #404147;
|
|
|
- background-color: #f9f9f9 !important;
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
- .parkLeft{
|
|
|
- position:absolute !important;
|
|
|
- top:70px;
|
|
|
- left:5px;
|
|
|
- margin-left:-30px;
|
|
|
- }
|
|
|
- .rotateNinetyDegree{
|
|
|
- -webkit-transform: rotate(-90deg);
|
|
|
- -moz-transform: rotate(-90deg);
|
|
|
- -o-transform: rotate(-90deg);
|
|
|
- -ms-transform: rotate(-90deg);
|
|
|
- transform: rotate(-90deg);
|
|
|
- }
|
|
|
- .roundbtn{
|
|
|
- border-radius: 40px !important;
|
|
|
- box-shadow: 2px 2px 2px 2px #bfbfbf;
|
|
|
- }
|
|
|
- .playBtn{
|
|
|
- color: white !important;
|
|
|
- transition: opacity 0.1s;
|
|
|
- }
|
|
|
-
|
|
|
- #playpauseBtn{
|
|
|
- width: 66px;
|
|
|
- height: 66px;
|
|
|
- }
|
|
|
-
|
|
|
- .playerControlWrapper .sidebuttons{
|
|
|
- background-color: white !important;
|
|
|
- }
|
|
|
- .playerControlWrapper .white.icon.button:hover{
|
|
|
- opacity: 0.6;
|
|
|
- }
|
|
|
- .playerControlWrapper{
|
|
|
- text-align: center;
|
|
|
- position:absolute;
|
|
|
- margin-top: 3rem;
|
|
|
- width:100% !important;
|
|
|
- }
|
|
|
- .rightPaddedOprButtons{
|
|
|
- position:absolute;
|
|
|
- right:3px;
|
|
|
- top:3px;
|
|
|
- }
|
|
|
- .modeEnabled{
|
|
|
- background-color: #186ed2 !important;
|
|
|
- color:white !important;
|
|
|
- border: 0px solid transparent !important;
|
|
|
- }
|
|
|
- #volControlOverlay{
|
|
|
- background-color: rgba(255,255,255,0.01);
|
|
|
- z-index:999;
|
|
|
- position:absolute;
|
|
|
- width:14px;
|
|
|
- height:120px;
|
|
|
- top:17px;
|
|
|
- left:28px;
|
|
|
- }
|
|
|
- .songlabel{
|
|
|
- padding-right:3px;
|
|
|
- position:absolute;
|
|
|
- display:inline-box;
|
|
|
- left:5px;
|
|
|
- top:5px;
|
|
|
- color:#77767b;
|
|
|
- height:22px;
|
|
|
- text-overflow: ellipsis;
|
|
|
- overflow: hidden;
|
|
|
- width: 100%;
|
|
|
- white-space: nowrap;
|
|
|
- font-weight: bold;
|
|
|
- }
|
|
|
- .durationDisplay{
|
|
|
- position:absolute;
|
|
|
- right:0px;
|
|
|
- bottom:0px;
|
|
|
- padding-right:5px;
|
|
|
- padding-bottom:5px;
|
|
|
- margin: 0px !important;
|
|
|
- color: #77767b;
|
|
|
- }
|
|
|
- .bottomBackground{
|
|
|
- background-color: white;
|
|
|
- position:relative;
|
|
|
- height:58px;
|
|
|
- width:100%;
|
|
|
- }
|
|
|
- .sameDirFileList{
|
|
|
- width:100%;
|
|
|
- height:calc(100% - 220px) !important;
|
|
|
- background-color:rgba(243, 243, 243, 0.95);
|
|
|
- overflow-y:auto;
|
|
|
- overflow-x:hidden;
|
|
|
- }
|
|
|
-
|
|
|
- @supports ((-webkit-backdrop-filter: blur(2em)) or (backdrop-filter: blur(2em))) {
|
|
|
- .sameDirFileList {
|
|
|
- background-color:rgba(240, 240, 240, 0.5);
|
|
|
- -webkit-backdrop-filter: blur(2em);
|
|
|
- backdrop-filter: blur(2em);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .listitem{
|
|
|
- border-bottom: 1px solid #404040;
|
|
|
- padding: 12px;
|
|
|
- color:rgb(43, 43, 43);
|
|
|
- font-size:120%;
|
|
|
- cursor:pointer;
|
|
|
- }
|
|
|
- .listitem:hover{
|
|
|
- background-color:#eff1f3;
|
|
|
- }
|
|
|
- .listitem.selected{
|
|
|
- background-color:#eff1f3;
|
|
|
- }
|
|
|
- .noradius{
|
|
|
- border-radius: 0px !important;
|
|
|
- }
|
|
|
- </style>
|
|
|
-</head>
|
|
|
-<body>
|
|
|
- <div id="playerUI" class="playerInterface ui container">
|
|
|
- <img id="Albumnart" class="ui fluid image" src="img/nothumb.png" style="position: absolute; top: -75px; opacity: 0.3; pointer-events: none; user-select: none;">
|
|
|
-
|
|
|
- <div class="parkLeft">
|
|
|
- <div class="ui primary small progress rotateNinetyDegree" style="width:120px !important; background-color: white;">
|
|
|
- <div id="volControl" class="bar" style="min-width: 0%; width: 60%;background-color:#4576c5;"></div>
|
|
|
- </div>
|
|
|
-
|
|
|
- </div>
|
|
|
- <div id="volControlOverlay"></div>
|
|
|
- <div class="playerControlWrapper" align="center">
|
|
|
- <button class="ui white huge icon button sidebuttons roundbtn playlistStepBtn" onClick="lastSong();"><i class="step backward icon"></i></button>
|
|
|
- <button id="playpauseBtn" style="background-color:#186ed2;" class="ui white massive icon button roundbtn playBtn" onClick="togglePlay(this);"><i class="pause icon"></i></button>
|
|
|
- <button class="ui huge white icon button sidebuttons roundbtn playlistStepBtn" onClick="nextSong();"><i class="step forward icon"></i></button>
|
|
|
- </div>
|
|
|
- <div class="rightPaddedOprButtons">
|
|
|
- <button id="repeatModeBtn" class="ui icon button" style="margin-bottom:5px;" onClick="toggleRepeat(this);"><i class="retweet icon"></i></button><br>
|
|
|
- <button id="showListBtn" class="ui icon button" onClick="showRelatedFileList();"><i class="content icon"></i></button>
|
|
|
- <!-- <button class="ui icon button"><i class="exchange icon"></i></button> -->
|
|
|
- </div>
|
|
|
- <!-- Adding in some labels for the progress bars and song information-->
|
|
|
- <p class="rotateNinetyDegree" style="position:absolute;top:65px;left:8px; font-weight: lighter;"><i class="small minus icon"></i> Volume <i class="small plus icon"></i></p>
|
|
|
- <p class="durationDisplay">0:00 / 0:00</p>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div id="progressControl" class="ui attached small progress" style="height: 0.8rem; background: rgba(255,255,255,0.8);">
|
|
|
- <div id="playbackProgress" class="bar" style="min-width: 0%; width: 0%;background-color: #4576c5; "></div>
|
|
|
- </div>
|
|
|
- <div class="bottomBackground" >
|
|
|
- <!-- Song Title at the bottom black area-->
|
|
|
- <div id="songtitle" class="songlabel">Loading Song Information</div>
|
|
|
- <div id="fileSize" style="position:absolute;bottom:5px;left:5px;color:#77767b;"><i class="file outline icon"></i> 0.0 MB</div>
|
|
|
- <div style="position:absolute;right:3px;bottom:3px;color:#77767b;"><i class='leaf icon'></i>AirMusic</div>
|
|
|
- </div>
|
|
|
- <!-- The sections below are for mobile interfaces -->
|
|
|
- <div id="nearbyFilelist" class="sameDirFileList">
|
|
|
- <div class="listitem" onClick="playThis(this);"><div style="width: 100%; text-align: center;"><i class="ui loading spinner icon"></i></div></div>
|
|
|
- </div>
|
|
|
- <!-- autoplay -->
|
|
|
- <audio id="mainPlayer" style="display:none;" preload="auto" autoplay></audio>
|
|
|
-
|
|
|
-
|
|
|
- <div style="display:none;">
|
|
|
- <div id="meta_dirSongList"></div>
|
|
|
- <div id="meta_playingSong"></div>
|
|
|
- </div>
|
|
|
- <script>
|
|
|
- //Define global variables
|
|
|
- var player = $("#mainPlayer")[0];
|
|
|
- var mediaExchanging = false;
|
|
|
- var listShown = true;
|
|
|
- if (ao_module_virtualDesktop){
|
|
|
- listShown = false;
|
|
|
- }else{
|
|
|
- $("#showListBtn").hide();
|
|
|
- }
|
|
|
- player.volume = getCurrentGlobVol();
|
|
|
- //Init ao_module window events
|
|
|
- ao_module_setFixedWindowSize();
|
|
|
-
|
|
|
- //Do things if it is not run under desktop mode
|
|
|
- if (!ao_module_virtualDesktop){
|
|
|
- $("#nearbyFilelist").addClass("coloredBackground");
|
|
|
- }
|
|
|
-
|
|
|
- //Ignore all other input files.
|
|
|
- var playingFileInfo = ao_module_loadInputFiles()[0];
|
|
|
- //Get the song title and meta data from server
|
|
|
- var songInfo = [];
|
|
|
- var songList = [];
|
|
|
-
|
|
|
- if (playingFileInfo.filepath != undefined){
|
|
|
- player.src = "../media?file=" + encodeURIComponent(playingFileInfo.filepath);
|
|
|
- }
|
|
|
-
|
|
|
- if (playingFileInfo.filename != undefined){
|
|
|
- ao_module_setWindowTitle(playingFileInfo.filename);
|
|
|
- }
|
|
|
-
|
|
|
- ao_module_agirun("Music/functions/getMeta.js", {
|
|
|
- file: encodeURIComponent(playingFileInfo.filepath)
|
|
|
- }, function(data){
|
|
|
- songList = data;
|
|
|
- for (var i = 0; i < data.length; i++){
|
|
|
- if (data[i][0] == playingFileInfo.filename){
|
|
|
- songInfo = data[i];
|
|
|
- //Set the audio element src
|
|
|
- //player.src = "../media?file=" + encodeURIComponent(data[i][1]);
|
|
|
-
|
|
|
- //Update window title
|
|
|
- //ao_module_setWindowTitle(data[i][0]);
|
|
|
- updatePlayerThemeAndBackground(data[i][1]);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (data.length == 0){
|
|
|
- //Error occured
|
|
|
- player.src = "../media?file=" + encodeURIComponent(playingFileInfo.filepath);
|
|
|
- }
|
|
|
-
|
|
|
- //Load song title into the display area
|
|
|
- updateDisplayInformation(songInfo[0],songInfo[3]);
|
|
|
-
|
|
|
- //Create the playlist for all the files in the same directory
|
|
|
- createPlayList();
|
|
|
-
|
|
|
- //Initiate the current playSong in the songList
|
|
|
- updatePlayingSongSelection();
|
|
|
- });
|
|
|
- /*
|
|
|
- $.get("../Music/getMeta?file=" + encodeURIComponent(playingFileInfo.filepath),function(data){
|
|
|
- //console.log(data);
|
|
|
- songList = data;
|
|
|
- for (var i = 0; i < data.length; i++){
|
|
|
- if (data[i][0] == playingFileInfo.filename){
|
|
|
- songInfo = data[i];
|
|
|
- //Set the audio element src
|
|
|
- player.src = "../media?file=" + encodeURIComponent(data[i][1]);
|
|
|
- //Update window title
|
|
|
- ao_module_setWindowTitle(data[i][0]);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- //Load song title into the display area
|
|
|
- updateDisplayInformation(songInfo[0],songInfo[3]);
|
|
|
-
|
|
|
- //Create the playlist for all the files in the same directory
|
|
|
- createPlayList();
|
|
|
-
|
|
|
- //Initiate the current playSong in the songList
|
|
|
- updatePlayingSongSelection();
|
|
|
- });
|
|
|
- */
|
|
|
-
|
|
|
- //Get the song title from meta data
|
|
|
- //var songInfo = JSON.parse($("#meta_playingSong").text().trim());
|
|
|
- //var songList = JSON.parse($("#meta_dirSongList").text().trim());
|
|
|
- //ao_module_setWindowTitle(ao_module_codec.decodeUmFilename(songInfo[0]));
|
|
|
-
|
|
|
- //Define supporting function for trunc.
|
|
|
- String.prototype.trunc = String.prototype.trunc ||
|
|
|
- function(n){
|
|
|
- return (this.length > n) ? this.substr(0, n-1) + '…' : this;
|
|
|
- };
|
|
|
- //Setup listen events to global volume
|
|
|
- setInterval(function(){
|
|
|
- var globvol = getCurrentGlobVol();
|
|
|
- updateVolControlDisplay(globvol);
|
|
|
- player.volume = globvol;
|
|
|
- if (player.paused == true){
|
|
|
- //Check if anytime that the button UI is not in sync with the current playing status. Update it if found.
|
|
|
- $(".playBtn").html("<i class='play icon'></i>");
|
|
|
- }else{
|
|
|
- $(".playBtn").html("<i class='pause icon'></i>");
|
|
|
- }
|
|
|
- },1000);
|
|
|
- updateVolControlDisplay(getCurrentGlobVol());
|
|
|
- //Add volume bar change event listener
|
|
|
- $("#volControlOverlay").on("click",function(e){
|
|
|
- var x = e.pageX - $('#volControlOverlay').offset().left;
|
|
|
- var y = e.pageY - $('#volControlOverlay').offset().top;
|
|
|
- var height = $('#volControlOverlay').height();
|
|
|
- var newvol = Math.round(((height - y) / height)*20)/20;
|
|
|
- localStorage.setItem("global_volume",newvol);
|
|
|
- player.volume = newvol;
|
|
|
- updateVolControlDisplay(newvol);
|
|
|
- });
|
|
|
- //Also add draging bar for mouse operations
|
|
|
- player.onended = function(){
|
|
|
- if (!repeatMode){
|
|
|
- $(".playBtn").html("<i class='play icon'></i>");
|
|
|
- }
|
|
|
- }
|
|
|
- var dragging = false;
|
|
|
- $("#volControlOverlay").on("mousedown",function(){
|
|
|
- dragging = true;
|
|
|
- });
|
|
|
- $("#volControlOverlay").on("mousemove",function(e){
|
|
|
- if (dragging){
|
|
|
- var y = e.pageY - $('#volControlOverlay').offset().top;
|
|
|
- var height = $('#volControlOverlay').height();
|
|
|
- var newvol = Math.round(((height - y) / height)*100)/100;
|
|
|
- //console.log(newvol);
|
|
|
- localStorage.setItem("global_volume",newvol);
|
|
|
- player.volume = newvol;
|
|
|
- updateVolControlDisplay(newvol);
|
|
|
- }
|
|
|
- });
|
|
|
- $("#volControlOverlay").on("mouseup",function(){
|
|
|
- if (dragging){
|
|
|
- dragging = false;
|
|
|
- }
|
|
|
- });
|
|
|
- $("body").on("mouseup",function(){
|
|
|
- if (dragging){
|
|
|
- dragging = false;
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- //Audio element custom UI listeners
|
|
|
- document.getElementById("progressControl").addEventListener("click",function(e){
|
|
|
- //Click on the progress control bar, update the audio playing location
|
|
|
- var x = e.pageX - $('#progressControl').offset().left;
|
|
|
- var w = $("#progressControl").width();
|
|
|
- var alength = player.duration;
|
|
|
- var targetPos = (x / w * alength);
|
|
|
- player.currentTime = targetPos;
|
|
|
- });
|
|
|
-
|
|
|
- player.addEventListener("timeupdate", function(){
|
|
|
- var currentTime = player.currentTime;
|
|
|
- var duration = player.duration;
|
|
|
- var progressPercentage = currentTime / duration * 100 + "%";
|
|
|
- $("#playbackProgress").css("width",progressPercentage);
|
|
|
- if (!mediaExchanging){
|
|
|
- updateDurationDisplay(currentTime,duration);
|
|
|
- }
|
|
|
-
|
|
|
- });
|
|
|
-
|
|
|
- //Load repeat mode from storage
|
|
|
- var repeatMode = false;
|
|
|
- repeatMode = loadStorage("repeatModeEmbedded");
|
|
|
- if (repeatMode != ""){
|
|
|
- repeatMode = (repeatMode == "true");
|
|
|
- }
|
|
|
- if (repeatMode){
|
|
|
- $("#repeatModeBtn").addClass("modeEnabled");
|
|
|
- player.loop = true;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- //End of startup seuqence
|
|
|
-
|
|
|
- function updatePlayingSongSelection(){
|
|
|
- $(".listitem.selected").removeClass("selected");
|
|
|
- $(".listitem").each(function(){
|
|
|
- if ($(this).attr("filename") == songInfo[0]){
|
|
|
- $(this).addClass("selected");
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- function showRelatedFileList(){
|
|
|
- if (ao_module_virtualDesktop){
|
|
|
- if (listShown){
|
|
|
- ao_module_setWindowSize(360,240);
|
|
|
- listShown = false;
|
|
|
- }else{
|
|
|
- ao_module_setWindowSize(360,520);
|
|
|
- listShown = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- function lastSong(){
|
|
|
- //Switch to the next song in list
|
|
|
- player.pause();
|
|
|
- mediaExchanging = true;
|
|
|
- $(".durationDisplay").html('<i class="clock icon"></i> Loading Media');
|
|
|
- var nextSong = -1; //There is no next song in the current directory
|
|
|
- for (var i =0; i < songList.length; i++){
|
|
|
- if (songList[i][0] == songInfo[0]){
|
|
|
- //Filename are the same
|
|
|
- if (i-1 < 0){
|
|
|
- //This is the last song in list
|
|
|
- nextSong = songList[songList.length - 1]
|
|
|
- }else{
|
|
|
- //Play previous song
|
|
|
- nextSong = songList[i-1]
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- if (nextSong == -1){
|
|
|
- //There is no more similar file with similar extensions or there are no other supported files in the same directory.
|
|
|
- player.currentTime = 0;
|
|
|
- updateDisplayInformation(ao_module_codec.decodeUmFilename(songInfo[0]),songInfo[3]);
|
|
|
- player.play();
|
|
|
- setTimeout(function(){
|
|
|
- mediaExchanging = false;
|
|
|
- },300);
|
|
|
- return;
|
|
|
- }
|
|
|
- loadSongFromSongInfo(nextSong);
|
|
|
- player.play();
|
|
|
- setTimeout(function(){
|
|
|
- mediaExchanging = false;
|
|
|
- },300);
|
|
|
- updatePlayingSongSelection();
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- function uuidv4() {
|
|
|
- return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
|
|
|
- (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- function createPlayList(){
|
|
|
- $(".sameDirFileList").html("");
|
|
|
- for (var i = 0; i < songList.length; i++){
|
|
|
- //console.log(box);
|
|
|
- let thisFileItemID = "thumb_" + uuidv4();
|
|
|
- $(".sameDirFileList").append(`<div class="listitem" filename="${songList[i][0]}" onClick="playThis(this);">
|
|
|
- <div class="ui unstackable grid">
|
|
|
- <div class="three wide column" align="right">
|
|
|
- <img id="${thisFileItemID}" class="ui image noradius" style="height: 2rem;" src="img/eq.svg">
|
|
|
- </div>
|
|
|
- <div class="thirteen wide column">
|
|
|
- ${ao_module_codec.decodeUmFilename(songList[i][0])} (${songList[i][3]})
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
-
|
|
|
- </div>`);
|
|
|
-
|
|
|
- ao_module_agirun("Music/functions/getThumbnail.js", {
|
|
|
- file: songList[i][1],
|
|
|
- }, function(data){
|
|
|
- if (data.error !== undefined){
|
|
|
-
|
|
|
- }else{
|
|
|
- $("#" + thisFileItemID).attr("src","data:image/jpg;base64," + data);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- function playThis(object){
|
|
|
- var songName = $(object).attr("filename");
|
|
|
- $(".listitem.selected").removeClass("selected");
|
|
|
- $(object).addClass("selected");
|
|
|
- for (var i =0; i < songList.length; i++){
|
|
|
- if (songList[i][0] == songName){
|
|
|
- //This is the song that the user request to play.
|
|
|
- player.pause();
|
|
|
- mediaExchanging = true;
|
|
|
- $(".durationDisplay").html('<i class="clock icon"></i> Loading Media');
|
|
|
- loadSongFromSongInfo(songList[i]);
|
|
|
- player.play();
|
|
|
- setTimeout(function(){
|
|
|
- mediaExchanging = false;
|
|
|
- },300);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function nextSong(){
|
|
|
- //Switch to the next song in list
|
|
|
- player.pause();
|
|
|
- mediaExchanging = true;
|
|
|
- $(".durationDisplay").html('<i class="clock icon"></i> Loading Media');
|
|
|
- var nextSong = -1; //There is no next song in the current directory
|
|
|
- for (var i =0; i < songList.length; i++){
|
|
|
- if (songList[i][0] == songInfo[0]){
|
|
|
- //Filename are the same
|
|
|
- if (i+1 >= songList.length){
|
|
|
- //This is the last song in list
|
|
|
- nextSong = songList[0]
|
|
|
- }else{
|
|
|
- //Play next song
|
|
|
- nextSong = songList[i+1]
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- if (nextSong == -1){
|
|
|
- //There is no more similar file with similar extensions or there are no other supported files in the same directory.
|
|
|
- player.currentTime = 0;
|
|
|
- updateDisplayInformation(ao_module_codec.decodeUmFilename(songInfo[0]), songInfo[3]);
|
|
|
- player.play();
|
|
|
- setTimeout(function(){
|
|
|
- mediaExchanging = false;
|
|
|
- },300);
|
|
|
- return;
|
|
|
- }
|
|
|
- loadSongFromSongInfo(nextSong);
|
|
|
- player.play();
|
|
|
- setTimeout(function(){
|
|
|
- mediaExchanging = false;
|
|
|
- },300);
|
|
|
- updatePlayingSongSelection();
|
|
|
- }
|
|
|
-
|
|
|
- function blobToDataURL(blob, callback) {
|
|
|
- var a = new FileReader();
|
|
|
- a.onload = function(e) {callback(e.target.result);}
|
|
|
- a.readAsDataURL(blob);
|
|
|
- }
|
|
|
-
|
|
|
- function loadSongFromSongInfo(playSongInfo){
|
|
|
- var songName = ao_module_codec.decodeUmFilename(playSongInfo[0]);
|
|
|
- var songPath = playSongInfo[1];
|
|
|
- var fileSize = playSongInfo[3];
|
|
|
- $(player).attr('src',"/media?file=" + encodeURIComponent(songPath));
|
|
|
-
|
|
|
- ao_module_setWindowTitle(songName);
|
|
|
- songInfo = playSongInfo;
|
|
|
- updateDisplayInformation(ao_module_codec.decodeUmFilename(songInfo[0]),songInfo[3]);
|
|
|
- updatePlayerThemeAndBackground(songPath);
|
|
|
- }
|
|
|
-
|
|
|
- //Update the player background and theme color
|
|
|
- function updatePlayerThemeAndBackground(songPath){
|
|
|
- ao_module_agirun("Music/functions/getThumbnail.js", {
|
|
|
- file: songPath,
|
|
|
- }, function(data){
|
|
|
- if (data.error == undefined){
|
|
|
- let imageSrc = "data:image/jpg;base64," + data;
|
|
|
- $("#Albumnart").attr("src",imageSrc);
|
|
|
- //Get theme color and update the player theme color
|
|
|
- let themeColor = getAverageRGB($("#Albumnart")[0]);
|
|
|
- updateThemeColor(themeColor);
|
|
|
- }else{
|
|
|
- //No thumbnail. Restore to default theme color
|
|
|
- updateThemeColor({r:24, g: 110, b: 210});
|
|
|
- $("#Albumnart").attr("src","img/nothumb.png");
|
|
|
- }
|
|
|
- }
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- //Update the theme color, require something like { r: 231, g: 159, b: 140 }
|
|
|
- function updateThemeColor(newRGBColor){
|
|
|
- let colorText = `rgb(${newRGBColor.r} ,${newRGBColor.g} ,${newRGBColor.b})`
|
|
|
- $("#playbackProgress").css("background-color", colorText);
|
|
|
- $("#playpauseBtn").css("background-color", colorText);
|
|
|
- $("#volControl").css("background-color", colorText);
|
|
|
- $(".modeEnabled")[0].style.setProperty( "background-color", colorText, 'important' );
|
|
|
- //$(".sameDirFileList").css("background-color", `rgba(${newRGBColor.r}, ${newRGBColor.g}, ${newRGBColor.b}, 0.1)`);
|
|
|
- }
|
|
|
-
|
|
|
- function updateDisplayInformation(songname, filesize){
|
|
|
- $("#songtitle").html("<i class='music icon'></i>" + songname)
|
|
|
- $("#fileSize").html("<i class='file outline icon'></i> " + filesize);
|
|
|
- }
|
|
|
-
|
|
|
- function updateDurationDisplay(pos,dur){
|
|
|
- pos = secondsToHMS(pos);
|
|
|
- dur = secondsToHMS(dur);
|
|
|
- $(".durationDisplay").html(pos.trim() + " / " + dur.trim());
|
|
|
- }
|
|
|
-
|
|
|
- function secondsToHMS(sec){
|
|
|
- let totalSeconds = sec;
|
|
|
- let hours = Math.floor(totalSeconds / 3600);
|
|
|
- totalSeconds %= 3600;
|
|
|
- let minutes = Math.floor(totalSeconds / 60);
|
|
|
- let seconds = totalSeconds % 60;
|
|
|
-
|
|
|
- if (hours > 0){
|
|
|
- hours = String(hours).padStart(2, "0");
|
|
|
- }else{
|
|
|
- hours = 0;
|
|
|
- }
|
|
|
- seconds = Math.round(seconds);
|
|
|
- minutes = String(minutes).padStart(2, "0");
|
|
|
- seconds = String(seconds).padStart(2, "0");
|
|
|
- if (hours != 0){
|
|
|
- return hours + ":" + minutes + ":" + seconds;
|
|
|
- }else{
|
|
|
- return minutes + ":" + seconds;
|
|
|
- }
|
|
|
- }
|
|
|
- function togglePlay(object){
|
|
|
- if (player.paused == true){
|
|
|
- player.play();
|
|
|
- $(object).html("<i class='pause icon'></i>");
|
|
|
- }else{
|
|
|
- player.pause();
|
|
|
- $(object).html("<i class='play icon'></i>");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function toggleRepeat(object){
|
|
|
- if ($(object).hasClass("modeEnabled")){
|
|
|
- $(object).removeClass("modeEnabled");
|
|
|
- repeatMode = false;
|
|
|
- setStorage("repeatModeEmbedded","false");
|
|
|
- player.loop = false;
|
|
|
- }else{
|
|
|
- $(object).addClass("modeEnabled");
|
|
|
- repeatMode = true;
|
|
|
- setStorage("repeatModeEmbedded","true");player.loop = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function updateVolControlDisplay(percentage){
|
|
|
- var adjWidth = percentage * 100 + "%";
|
|
|
- $("#volControl").css("width",adjWidth);
|
|
|
- $("#volControl").attr("vol",percentage);
|
|
|
- }
|
|
|
-
|
|
|
- function getCurrentGlobVol(){
|
|
|
- //console.log(localStorage.getItem("global_volume"));
|
|
|
- if (localStorage.getItem("global_volume") === null || localStorage.getItem("global_volume") == ""){
|
|
|
- return 0;
|
|
|
- }
|
|
|
- return parseFloat(localStorage.getItem("global_volume"));
|
|
|
- }
|
|
|
-
|
|
|
- function setStorage(configName,configValue){
|
|
|
- $.ajax({
|
|
|
- type: 'GET',
|
|
|
- url: "/system/file_system/preference",
|
|
|
- data: {key: "Music/" + configName,value:configValue},
|
|
|
- success: function(data){},
|
|
|
- async:true
|
|
|
- });
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- function loadStorage(configName){
|
|
|
- var result = "";
|
|
|
- $.ajax({
|
|
|
- type: 'GET',
|
|
|
- url: "/system/file_system/preference",
|
|
|
- data: {key: "Music/" + configName},
|
|
|
- success: function(data){
|
|
|
- if (data.error !== undefined){
|
|
|
- result = "";
|
|
|
- }else{
|
|
|
- result = data;
|
|
|
- }
|
|
|
- },
|
|
|
- error: function(data){result = "";},
|
|
|
- async:false,
|
|
|
- timeout: 3000
|
|
|
- });
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- function getAverageRGB(imgEl) {
|
|
|
- var blockSize = 5,
|
|
|
- defaultRGB = {r:0,g:0,b:0},
|
|
|
- canvas = document.createElement('canvas'),
|
|
|
- context = canvas.getContext && canvas.getContext('2d'),
|
|
|
- data, width, height,
|
|
|
- i = -4,
|
|
|
- length,
|
|
|
- rgb = {r:0,g:0,b:0},
|
|
|
- count = 0;
|
|
|
-
|
|
|
- if (!context) {
|
|
|
- return defaultRGB;
|
|
|
- }
|
|
|
-
|
|
|
- height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
|
|
|
- width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
|
|
|
-
|
|
|
- context.drawImage(imgEl, 0, 0);
|
|
|
-
|
|
|
- try {
|
|
|
- data = context.getImageData(0, 0, width, height);
|
|
|
- } catch(e) {
|
|
|
- /* security error, img on diff domain */
|
|
|
- return defaultRGB;
|
|
|
- }
|
|
|
-
|
|
|
- length = data.data.length;
|
|
|
-
|
|
|
- while ( (i += blockSize * 4) < length ) {
|
|
|
- ++count;
|
|
|
- rgb.r += data.data[i];
|
|
|
- rgb.g += data.data[i+1];
|
|
|
- rgb.b += data.data[i+2];
|
|
|
- }
|
|
|
-
|
|
|
- // ~~ used to floor values
|
|
|
- rgb.r = ~~(rgb.r/count);
|
|
|
- rgb.g = ~~(rgb.g/count);
|
|
|
- rgb.b = ~~(rgb.b/count);
|
|
|
-
|
|
|
- return rgb;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- </script>
|
|
|
-</body>
|
|
|
+<!DOCTYPE html>
|
|
|
+<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
|
+<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
|
|
|
+<html>
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <meta name="theme-color" content="#232324">
|
|
|
+ <link rel="stylesheet" href="../script/semantic/semantic.min.css">
|
|
|
+ <link rel="icon" type="image/png" href="./img/small_icon.png">
|
|
|
+ <script src="../script/jquery.min.js"></script>
|
|
|
+ <script src="../script/semantic/semantic.min.js"></script>
|
|
|
+ <script src="../script/ao_module.js"></script>
|
|
|
+ <style>
|
|
|
+ body{
|
|
|
+ padding:0px !important;
|
|
|
+ overflow: hidden;
|
|
|
+ height:100%;
|
|
|
+ background-color: transparent !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .coloredBackground{
|
|
|
+ background: rgb(253,255,254);
|
|
|
+ background: linear-gradient(321deg, rgba(253,255,254,1) 29%, rgba(240,250,255,1) 100%);
|
|
|
+ }
|
|
|
+
|
|
|
+ html, body { height: 100%; width: 100%; margin: 0; }
|
|
|
+ .playerInterface{
|
|
|
+ background-color:rgba(226, 221, 220,0.95);
|
|
|
+ height:150px !important;
|
|
|
+ width:100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ #playerUI{
|
|
|
+ margin-left:0px !important;
|
|
|
+ margin-right:0px !important;
|
|
|
+ width:100% !important;
|
|
|
+ position: relative;
|
|
|
+ color: #404147;
|
|
|
+ background-color: #f9f9f9 !important;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ .parkLeft{
|
|
|
+ position:absolute !important;
|
|
|
+ top:70px;
|
|
|
+ left:5px;
|
|
|
+ margin-left:-30px;
|
|
|
+ }
|
|
|
+ .rotateNinetyDegree{
|
|
|
+ -webkit-transform: rotate(-90deg);
|
|
|
+ -moz-transform: rotate(-90deg);
|
|
|
+ -o-transform: rotate(-90deg);
|
|
|
+ -ms-transform: rotate(-90deg);
|
|
|
+ transform: rotate(-90deg);
|
|
|
+ }
|
|
|
+ .roundbtn{
|
|
|
+ border-radius: 40px !important;
|
|
|
+ box-shadow: 2px 2px 2px 2px #bfbfbf;
|
|
|
+ }
|
|
|
+ .playBtn{
|
|
|
+ color: white !important;
|
|
|
+ transition: opacity 0.1s;
|
|
|
+ }
|
|
|
+
|
|
|
+ #playpauseBtn{
|
|
|
+ width: 66px;
|
|
|
+ height: 66px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .playerControlWrapper .sidebuttons{
|
|
|
+ background-color: white !important;
|
|
|
+ }
|
|
|
+ .playerControlWrapper .white.icon.button:hover{
|
|
|
+ opacity: 0.6;
|
|
|
+ }
|
|
|
+ .playerControlWrapper{
|
|
|
+ text-align: center;
|
|
|
+ position:absolute;
|
|
|
+ margin-top: 3rem;
|
|
|
+ width:100% !important;
|
|
|
+ }
|
|
|
+ .rightPaddedOprButtons{
|
|
|
+ position:absolute;
|
|
|
+ right:3px;
|
|
|
+ top:3px;
|
|
|
+ }
|
|
|
+ .modeEnabled{
|
|
|
+ background-color: #186ed2 !important;
|
|
|
+ color:white !important;
|
|
|
+ border: 0px solid transparent !important;
|
|
|
+ }
|
|
|
+ #volControlOverlay{
|
|
|
+ background-color: rgba(255,255,255,0.01);
|
|
|
+ z-index:999;
|
|
|
+ position:absolute;
|
|
|
+ width:14px;
|
|
|
+ height:120px;
|
|
|
+ top:17px;
|
|
|
+ left:28px;
|
|
|
+ }
|
|
|
+ .songlabel{
|
|
|
+ padding-right:3px;
|
|
|
+ position:absolute;
|
|
|
+ display:inline-box;
|
|
|
+ left:5px;
|
|
|
+ top:5px;
|
|
|
+ color:#77767b;
|
|
|
+ height:22px;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ overflow: hidden;
|
|
|
+ width: 100%;
|
|
|
+ white-space: nowrap;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ .durationDisplay{
|
|
|
+ position:absolute;
|
|
|
+ right:0px;
|
|
|
+ bottom:0px;
|
|
|
+ padding-right:5px;
|
|
|
+ padding-bottom:5px;
|
|
|
+ margin: 0px !important;
|
|
|
+ color: #77767b;
|
|
|
+ }
|
|
|
+ .bottomBackground{
|
|
|
+ background-color: white;
|
|
|
+ position:relative;
|
|
|
+ height:58px;
|
|
|
+ width:100%;
|
|
|
+ }
|
|
|
+ .sameDirFileList{
|
|
|
+ width:100%;
|
|
|
+ height:calc(100% - 220px) !important;
|
|
|
+ background-color:rgba(243, 243, 243, 0.95);
|
|
|
+ overflow-y:auto;
|
|
|
+ overflow-x:hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ @supports ((-webkit-backdrop-filter: blur(2em)) or (backdrop-filter: blur(2em))) {
|
|
|
+ .sameDirFileList {
|
|
|
+ background-color:rgba(240, 240, 240, 0.5);
|
|
|
+ -webkit-backdrop-filter: blur(2em);
|
|
|
+ backdrop-filter: blur(2em);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .listitem{
|
|
|
+ border-bottom: 1px solid #404040;
|
|
|
+ padding: 12px;
|
|
|
+ color:rgb(43, 43, 43);
|
|
|
+ font-size:120%;
|
|
|
+ cursor:pointer;
|
|
|
+ }
|
|
|
+ .listitem:hover{
|
|
|
+ background-color:#eff1f3;
|
|
|
+ }
|
|
|
+ .listitem.selected{
|
|
|
+ background-color:#eff1f3;
|
|
|
+ }
|
|
|
+ .noradius{
|
|
|
+ border-radius: 0px !important;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+ <div id="playerUI" class="playerInterface ui container">
|
|
|
+ <img id="Albumnart" class="ui fluid image" src="img/nothumb.png" style="position: absolute; top: -75px; opacity: 0.3; pointer-events: none; user-select: none;">
|
|
|
+
|
|
|
+ <div class="parkLeft">
|
|
|
+ <div class="ui primary small progress rotateNinetyDegree" style="width:120px !important; background-color: white;">
|
|
|
+ <div id="volControl" class="bar" style="min-width: 0%; width: 60%;background-color:#4576c5;"></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ <div id="volControlOverlay"></div>
|
|
|
+ <div class="playerControlWrapper" align="center">
|
|
|
+ <button class="ui white huge icon button sidebuttons roundbtn playlistStepBtn" onClick="lastSong();"><i class="step backward icon"></i></button>
|
|
|
+ <button id="playpauseBtn" style="background-color:#186ed2;" class="ui white massive icon button roundbtn playBtn" onClick="togglePlay(this);"><i class="pause icon"></i></button>
|
|
|
+ <button class="ui huge white icon button sidebuttons roundbtn playlistStepBtn" onClick="nextSong();"><i class="step forward icon"></i></button>
|
|
|
+ </div>
|
|
|
+ <div class="rightPaddedOprButtons">
|
|
|
+ <button id="repeatModeBtn" class="ui icon button" style="margin-bottom:5px;" onClick="toggleRepeat(this);"><i class="retweet icon"></i></button><br>
|
|
|
+ <button id="showListBtn" class="ui icon button" onClick="showRelatedFileList();"><i class="content icon"></i></button>
|
|
|
+ <!-- <button class="ui icon button"><i class="exchange icon"></i></button> -->
|
|
|
+ </div>
|
|
|
+ <!-- Adding in some labels for the progress bars and song information-->
|
|
|
+ <p class="rotateNinetyDegree" style="position:absolute;top:65px;left:8px; font-weight: lighter;"><i class="small minus icon"></i> Volume <i class="small plus icon"></i></p>
|
|
|
+ <p class="durationDisplay">0:00 / 0:00</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div id="progressControl" class="ui attached small progress" style="height: 0.8rem; background: rgba(255,255,255,0.8);">
|
|
|
+ <div id="playbackProgress" class="bar" style="min-width: 0%; width: 0%;background-color: #4576c5; "></div>
|
|
|
+ </div>
|
|
|
+ <div class="bottomBackground" >
|
|
|
+ <!-- Song Title at the bottom black area-->
|
|
|
+ <div id="songtitle" class="songlabel">Loading Song Information</div>
|
|
|
+ <div id="fileSize" style="position:absolute;bottom:5px;left:5px;color:#77767b;"><i class="file outline icon"></i> 0.0 MB</div>
|
|
|
+ <div style="position:absolute;right:3px;bottom:3px;color:#77767b;"><i class='leaf icon'></i>AirMusic</div>
|
|
|
+ </div>
|
|
|
+ <!-- The sections below are for mobile interfaces -->
|
|
|
+ <div id="nearbyFilelist" class="sameDirFileList">
|
|
|
+ <div class="listitem" onClick="playThis(this);"><div style="width: 100%; text-align: center;"><i class="ui loading spinner icon"></i></div></div>
|
|
|
+ </div>
|
|
|
+ <!-- autoplay -->
|
|
|
+ <audio id="mainPlayer" style="display:none;" preload="auto" autoplay></audio>
|
|
|
+
|
|
|
+
|
|
|
+ <div style="display:none;">
|
|
|
+ <div id="meta_dirSongList"></div>
|
|
|
+ <div id="meta_playingSong"></div>
|
|
|
+ </div>
|
|
|
+ <script>
|
|
|
+ //Define global variables
|
|
|
+ var player = $("#mainPlayer")[0];
|
|
|
+ var mediaExchanging = false;
|
|
|
+ var listShown = true;
|
|
|
+ if (ao_module_virtualDesktop){
|
|
|
+ listShown = false;
|
|
|
+ }else{
|
|
|
+ $("#showListBtn").hide();
|
|
|
+ }
|
|
|
+ player.volume = getCurrentGlobVol();
|
|
|
+ //Init ao_module window events
|
|
|
+ ao_module_setFixedWindowSize();
|
|
|
+
|
|
|
+ //Do things if it is not run under desktop mode
|
|
|
+ if (!ao_module_virtualDesktop){
|
|
|
+ $("#nearbyFilelist").addClass("coloredBackground");
|
|
|
+ }
|
|
|
+
|
|
|
+ //Ignore all other input files.
|
|
|
+ var playingFileInfo = ao_module_loadInputFiles()[0];
|
|
|
+ //Get the song title and meta data from server
|
|
|
+ var songInfo = [];
|
|
|
+ var songList = [];
|
|
|
+
|
|
|
+ if (playingFileInfo.filepath != undefined){
|
|
|
+ player.src = "../media?file=" + encodeURIComponent(playingFileInfo.filepath);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (playingFileInfo.filename != undefined){
|
|
|
+ ao_module_setWindowTitle(playingFileInfo.filename);
|
|
|
+ }
|
|
|
+
|
|
|
+ ao_module_agirun("Music/functions/getMeta.js", {
|
|
|
+ file: encodeURIComponent(playingFileInfo.filepath)
|
|
|
+ }, function(data){
|
|
|
+ songList = data;
|
|
|
+ for (var i = 0; i < data.length; i++){
|
|
|
+ if (data[i][0] == playingFileInfo.filename){
|
|
|
+ songInfo = data[i];
|
|
|
+ //Set the audio element src
|
|
|
+ //player.src = "../media?file=" + encodeURIComponent(data[i][1]);
|
|
|
+
|
|
|
+ //Update window title
|
|
|
+ //ao_module_setWindowTitle(data[i][0]);
|
|
|
+ updatePlayerThemeAndBackground(data[i][1]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.length == 0){
|
|
|
+ //Error occured
|
|
|
+ player.src = "../media?file=" + encodeURIComponent(playingFileInfo.filepath);
|
|
|
+ }
|
|
|
+
|
|
|
+ //Load song title into the display area
|
|
|
+ updateDisplayInformation(songInfo[0],songInfo[3]);
|
|
|
+
|
|
|
+ //Create the playlist for all the files in the same directory
|
|
|
+ createPlayList();
|
|
|
+
|
|
|
+ //Initiate the current playSong in the songList
|
|
|
+ updatePlayingSongSelection();
|
|
|
+ });
|
|
|
+ /*
|
|
|
+ $.get("../Music/getMeta?file=" + encodeURIComponent(playingFileInfo.filepath),function(data){
|
|
|
+ //console.log(data);
|
|
|
+ songList = data;
|
|
|
+ for (var i = 0; i < data.length; i++){
|
|
|
+ if (data[i][0] == playingFileInfo.filename){
|
|
|
+ songInfo = data[i];
|
|
|
+ //Set the audio element src
|
|
|
+ player.src = "../media?file=" + encodeURIComponent(data[i][1]);
|
|
|
+ //Update window title
|
|
|
+ ao_module_setWindowTitle(data[i][0]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //Load song title into the display area
|
|
|
+ updateDisplayInformation(songInfo[0],songInfo[3]);
|
|
|
+
|
|
|
+ //Create the playlist for all the files in the same directory
|
|
|
+ createPlayList();
|
|
|
+
|
|
|
+ //Initiate the current playSong in the songList
|
|
|
+ updatePlayingSongSelection();
|
|
|
+ });
|
|
|
+ */
|
|
|
+
|
|
|
+ //Get the song title from meta data
|
|
|
+ //var songInfo = JSON.parse($("#meta_playingSong").text().trim());
|
|
|
+ //var songList = JSON.parse($("#meta_dirSongList").text().trim());
|
|
|
+ //ao_module_setWindowTitle(ao_module_codec.decodeUmFilename(songInfo[0]));
|
|
|
+
|
|
|
+ //Define supporting function for trunc.
|
|
|
+ String.prototype.trunc = String.prototype.trunc ||
|
|
|
+ function(n){
|
|
|
+ return (this.length > n) ? this.substr(0, n-1) + '…' : this;
|
|
|
+ };
|
|
|
+ //Setup listen events to global volume
|
|
|
+ setInterval(function(){
|
|
|
+ var globvol = getCurrentGlobVol();
|
|
|
+ updateVolControlDisplay(globvol);
|
|
|
+ player.volume = globvol;
|
|
|
+ if (player.paused == true){
|
|
|
+ //Check if anytime that the button UI is not in sync with the current playing status. Update it if found.
|
|
|
+ $(".playBtn").html("<i class='play icon'></i>");
|
|
|
+ }else{
|
|
|
+ $(".playBtn").html("<i class='pause icon'></i>");
|
|
|
+ }
|
|
|
+ },1000);
|
|
|
+ updateVolControlDisplay(getCurrentGlobVol());
|
|
|
+ //Add volume bar change event listener
|
|
|
+ $("#volControlOverlay").on("click",function(e){
|
|
|
+ var x = e.pageX - $('#volControlOverlay').offset().left;
|
|
|
+ var y = e.pageY - $('#volControlOverlay').offset().top;
|
|
|
+ var height = $('#volControlOverlay').height();
|
|
|
+ var newvol = Math.round(((height - y) / height)*20)/20;
|
|
|
+ localStorage.setItem("global_volume",newvol);
|
|
|
+ player.volume = newvol;
|
|
|
+ updateVolControlDisplay(newvol);
|
|
|
+ });
|
|
|
+ //Also add draging bar for mouse operations
|
|
|
+ player.onended = function(){
|
|
|
+ if (!repeatMode){
|
|
|
+ $(".playBtn").html("<i class='play icon'></i>");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var dragging = false;
|
|
|
+ $("#volControlOverlay").on("mousedown",function(){
|
|
|
+ dragging = true;
|
|
|
+ });
|
|
|
+ $("#volControlOverlay").on("mousemove",function(e){
|
|
|
+ if (dragging){
|
|
|
+ var y = e.pageY - $('#volControlOverlay').offset().top;
|
|
|
+ var height = $('#volControlOverlay').height();
|
|
|
+ var newvol = Math.round(((height - y) / height)*100)/100;
|
|
|
+ //console.log(newvol);
|
|
|
+ localStorage.setItem("global_volume",newvol);
|
|
|
+ player.volume = newvol;
|
|
|
+ updateVolControlDisplay(newvol);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ $("#volControlOverlay").on("mouseup",function(){
|
|
|
+ if (dragging){
|
|
|
+ dragging = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ $("body").on("mouseup",function(){
|
|
|
+ if (dragging){
|
|
|
+ dragging = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ //Audio element custom UI listeners
|
|
|
+ document.getElementById("progressControl").addEventListener("click",function(e){
|
|
|
+ //Click on the progress control bar, update the audio playing location
|
|
|
+ var x = e.pageX - $('#progressControl').offset().left;
|
|
|
+ var w = $("#progressControl").width();
|
|
|
+ var alength = player.duration;
|
|
|
+ var targetPos = (x / w * alength);
|
|
|
+ player.currentTime = targetPos;
|
|
|
+ });
|
|
|
+
|
|
|
+ player.addEventListener("timeupdate", function(){
|
|
|
+ var currentTime = player.currentTime;
|
|
|
+ var duration = player.duration;
|
|
|
+ var progressPercentage = currentTime / duration * 100 + "%";
|
|
|
+ $("#playbackProgress").css("width",progressPercentage);
|
|
|
+ if (!mediaExchanging){
|
|
|
+ updateDurationDisplay(currentTime,duration);
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ //Load repeat mode from storage
|
|
|
+ var repeatMode = false;
|
|
|
+ repeatMode = loadStorage("repeatModeEmbedded");
|
|
|
+ if (repeatMode != ""){
|
|
|
+ repeatMode = (repeatMode == "true");
|
|
|
+ }
|
|
|
+ if (repeatMode){
|
|
|
+ $("#repeatModeBtn").addClass("modeEnabled");
|
|
|
+ player.loop = true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //End of startup seuqence
|
|
|
+
|
|
|
+ function updatePlayingSongSelection(){
|
|
|
+ $(".listitem.selected").removeClass("selected");
|
|
|
+ $(".listitem").each(function(){
|
|
|
+ if ($(this).attr("filename") == songInfo[0]){
|
|
|
+ $(this).addClass("selected");
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function showRelatedFileList(){
|
|
|
+ if (ao_module_virtualDesktop){
|
|
|
+ if (listShown){
|
|
|
+ ao_module_setWindowSize(360,260);
|
|
|
+ listShown = false;
|
|
|
+ }else{
|
|
|
+ ao_module_setWindowSize(360,540);
|
|
|
+ listShown = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function lastSong(){
|
|
|
+ //Switch to the next song in list
|
|
|
+ player.pause();
|
|
|
+ mediaExchanging = true;
|
|
|
+ $(".durationDisplay").html('<i class="clock icon"></i> Loading Media');
|
|
|
+ var nextSong = -1; //There is no next song in the current directory
|
|
|
+ for (var i =0; i < songList.length; i++){
|
|
|
+ if (songList[i][0] == songInfo[0]){
|
|
|
+ //Filename are the same
|
|
|
+ if (i-1 < 0){
|
|
|
+ //This is the last song in list
|
|
|
+ nextSong = songList[songList.length - 1]
|
|
|
+ }else{
|
|
|
+ //Play previous song
|
|
|
+ nextSong = songList[i-1]
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (nextSong == -1){
|
|
|
+ //There is no more similar file with similar extensions or there are no other supported files in the same directory.
|
|
|
+ player.currentTime = 0;
|
|
|
+ updateDisplayInformation(ao_module_codec.decodeUmFilename(songInfo[0]),songInfo[3]);
|
|
|
+ player.play();
|
|
|
+ setTimeout(function(){
|
|
|
+ mediaExchanging = false;
|
|
|
+ },300);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ loadSongFromSongInfo(nextSong);
|
|
|
+ player.play();
|
|
|
+ setTimeout(function(){
|
|
|
+ mediaExchanging = false;
|
|
|
+ },300);
|
|
|
+ updatePlayingSongSelection();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ function uuidv4() {
|
|
|
+ return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
|
|
|
+ (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ function createPlayList(){
|
|
|
+ $(".sameDirFileList").html("");
|
|
|
+ for (var i = 0; i < songList.length; i++){
|
|
|
+ //console.log(box);
|
|
|
+ let thisFileItemID = "thumb_" + uuidv4();
|
|
|
+ $(".sameDirFileList").append(`<div class="listitem" filename="${songList[i][0]}" onClick="playThis(this);">
|
|
|
+ <div class="ui unstackable grid">
|
|
|
+ <div class="three wide column" align="right">
|
|
|
+ <img id="${thisFileItemID}" class="ui image noradius" style="height: 2rem;" src="img/eq.svg">
|
|
|
+ </div>
|
|
|
+ <div class="thirteen wide column">
|
|
|
+ ${ao_module_codec.decodeUmFilename(songList[i][0])} (${songList[i][3]})
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ </div>`);
|
|
|
+
|
|
|
+ ao_module_agirun("Music/functions/getThumbnail.js", {
|
|
|
+ file: songList[i][1],
|
|
|
+ }, function(data){
|
|
|
+ if (data.error !== undefined){
|
|
|
+
|
|
|
+ }else{
|
|
|
+ $("#" + thisFileItemID).attr("src","data:image/jpg;base64," + data);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function playThis(object){
|
|
|
+ var songName = $(object).attr("filename");
|
|
|
+ $(".listitem.selected").removeClass("selected");
|
|
|
+ $(object).addClass("selected");
|
|
|
+ for (var i =0; i < songList.length; i++){
|
|
|
+ if (songList[i][0] == songName){
|
|
|
+ //This is the song that the user request to play.
|
|
|
+ player.pause();
|
|
|
+ mediaExchanging = true;
|
|
|
+ $(".durationDisplay").html('<i class="clock icon"></i> Loading Media');
|
|
|
+ loadSongFromSongInfo(songList[i]);
|
|
|
+ player.play();
|
|
|
+ setTimeout(function(){
|
|
|
+ mediaExchanging = false;
|
|
|
+ },300);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function nextSong(){
|
|
|
+ //Switch to the next song in list
|
|
|
+ player.pause();
|
|
|
+ mediaExchanging = true;
|
|
|
+ $(".durationDisplay").html('<i class="clock icon"></i> Loading Media');
|
|
|
+ var nextSong = -1; //There is no next song in the current directory
|
|
|
+ for (var i =0; i < songList.length; i++){
|
|
|
+ if (songList[i][0] == songInfo[0]){
|
|
|
+ //Filename are the same
|
|
|
+ if (i+1 >= songList.length){
|
|
|
+ //This is the last song in list
|
|
|
+ nextSong = songList[0]
|
|
|
+ }else{
|
|
|
+ //Play next song
|
|
|
+ nextSong = songList[i+1]
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (nextSong == -1){
|
|
|
+ //There is no more similar file with similar extensions or there are no other supported files in the same directory.
|
|
|
+ player.currentTime = 0;
|
|
|
+ updateDisplayInformation(ao_module_codec.decodeUmFilename(songInfo[0]), songInfo[3]);
|
|
|
+ player.play();
|
|
|
+ setTimeout(function(){
|
|
|
+ mediaExchanging = false;
|
|
|
+ },300);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ loadSongFromSongInfo(nextSong);
|
|
|
+ player.play();
|
|
|
+ setTimeout(function(){
|
|
|
+ mediaExchanging = false;
|
|
|
+ },300);
|
|
|
+ updatePlayingSongSelection();
|
|
|
+ }
|
|
|
+
|
|
|
+ function blobToDataURL(blob, callback) {
|
|
|
+ var a = new FileReader();
|
|
|
+ a.onload = function(e) {callback(e.target.result);}
|
|
|
+ a.readAsDataURL(blob);
|
|
|
+ }
|
|
|
+
|
|
|
+ function loadSongFromSongInfo(playSongInfo){
|
|
|
+ var songName = ao_module_codec.decodeUmFilename(playSongInfo[0]);
|
|
|
+ var songPath = playSongInfo[1];
|
|
|
+ var fileSize = playSongInfo[3];
|
|
|
+ $(player).attr('src',"/media?file=" + encodeURIComponent(songPath));
|
|
|
+
|
|
|
+ ao_module_setWindowTitle(songName);
|
|
|
+ songInfo = playSongInfo;
|
|
|
+ updateDisplayInformation(ao_module_codec.decodeUmFilename(songInfo[0]),songInfo[3]);
|
|
|
+ updatePlayerThemeAndBackground(songPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ //Update the player background and theme color
|
|
|
+ function updatePlayerThemeAndBackground(songPath){
|
|
|
+ ao_module_agirun("Music/functions/getThumbnail.js", {
|
|
|
+ file: songPath,
|
|
|
+ }, function(data){
|
|
|
+ if (data.error == undefined){
|
|
|
+ let imageSrc = "data:image/jpg;base64," + data;
|
|
|
+ $("#Albumnart").attr("src",imageSrc);
|
|
|
+ //Get theme color and update the player theme color
|
|
|
+ let themeColor = getAverageRGB($("#Albumnart")[0]);
|
|
|
+ updateThemeColor(themeColor);
|
|
|
+ }else{
|
|
|
+ //No thumbnail. Restore to default theme color
|
|
|
+ updateThemeColor({r:24, g: 110, b: 210});
|
|
|
+ $("#Albumnart").attr("src","img/nothumb.png");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ //Update the theme color, require something like { r: 231, g: 159, b: 140 }
|
|
|
+ function updateThemeColor(newRGBColor){
|
|
|
+ let colorText = `rgb(${newRGBColor.r} ,${newRGBColor.g} ,${newRGBColor.b})`
|
|
|
+ $("#playbackProgress").css("background-color", colorText);
|
|
|
+ $("#playpauseBtn").css("background-color", colorText);
|
|
|
+ $("#volControl").css("background-color", colorText);
|
|
|
+ $(".modeEnabled")[0].style.setProperty( "background-color", colorText, 'important' );
|
|
|
+ //$(".sameDirFileList").css("background-color", `rgba(${newRGBColor.r}, ${newRGBColor.g}, ${newRGBColor.b}, 0.1)`);
|
|
|
+ }
|
|
|
+
|
|
|
+ function updateDisplayInformation(songname, filesize){
|
|
|
+ $("#songtitle").html("<i class='music icon'></i>" + songname)
|
|
|
+ $("#fileSize").html("<i class='file outline icon'></i> " + filesize);
|
|
|
+ }
|
|
|
+
|
|
|
+ function updateDurationDisplay(pos,dur){
|
|
|
+ pos = secondsToHMS(pos);
|
|
|
+ dur = secondsToHMS(dur);
|
|
|
+ $(".durationDisplay").html(pos.trim() + " / " + dur.trim());
|
|
|
+ }
|
|
|
+
|
|
|
+ function secondsToHMS(sec){
|
|
|
+ let totalSeconds = sec;
|
|
|
+ let hours = Math.floor(totalSeconds / 3600);
|
|
|
+ totalSeconds %= 3600;
|
|
|
+ let minutes = Math.floor(totalSeconds / 60);
|
|
|
+ let seconds = totalSeconds % 60;
|
|
|
+
|
|
|
+ if (hours > 0){
|
|
|
+ hours = String(hours).padStart(2, "0");
|
|
|
+ }else{
|
|
|
+ hours = 0;
|
|
|
+ }
|
|
|
+ seconds = Math.round(seconds);
|
|
|
+ minutes = String(minutes).padStart(2, "0");
|
|
|
+ seconds = String(seconds).padStart(2, "0");
|
|
|
+ if (hours != 0){
|
|
|
+ return hours + ":" + minutes + ":" + seconds;
|
|
|
+ }else{
|
|
|
+ return minutes + ":" + seconds;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ function togglePlay(object){
|
|
|
+ if (player.paused == true){
|
|
|
+ player.play();
|
|
|
+ $(object).html("<i class='pause icon'></i>");
|
|
|
+ }else{
|
|
|
+ player.pause();
|
|
|
+ $(object).html("<i class='play icon'></i>");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function toggleRepeat(object){
|
|
|
+ if ($(object).hasClass("modeEnabled")){
|
|
|
+ $(object).removeClass("modeEnabled");
|
|
|
+ repeatMode = false;
|
|
|
+ setStorage("repeatModeEmbedded","false");
|
|
|
+ player.loop = false;
|
|
|
+ }else{
|
|
|
+ $(object).addClass("modeEnabled");
|
|
|
+ repeatMode = true;
|
|
|
+ setStorage("repeatModeEmbedded","true");player.loop = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function updateVolControlDisplay(percentage){
|
|
|
+ var adjWidth = percentage * 100 + "%";
|
|
|
+ $("#volControl").css("width",adjWidth);
|
|
|
+ $("#volControl").attr("vol",percentage);
|
|
|
+ }
|
|
|
+
|
|
|
+ function getCurrentGlobVol(){
|
|
|
+ //console.log(localStorage.getItem("global_volume"));
|
|
|
+ if (localStorage.getItem("global_volume") === null || localStorage.getItem("global_volume") == ""){
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return parseFloat(localStorage.getItem("global_volume"));
|
|
|
+ }
|
|
|
+
|
|
|
+ function setStorage(configName,configValue){
|
|
|
+ $.ajax({
|
|
|
+ type: 'GET',
|
|
|
+ url: "/system/file_system/preference",
|
|
|
+ data: {key: "Music/" + configName,value:configValue},
|
|
|
+ success: function(data){},
|
|
|
+ async:true
|
|
|
+ });
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ function loadStorage(configName){
|
|
|
+ var result = "";
|
|
|
+ $.ajax({
|
|
|
+ type: 'GET',
|
|
|
+ url: "/system/file_system/preference",
|
|
|
+ data: {key: "Music/" + configName},
|
|
|
+ success: function(data){
|
|
|
+ if (data.error !== undefined){
|
|
|
+ result = "";
|
|
|
+ }else{
|
|
|
+ result = data;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error: function(data){result = "";},
|
|
|
+ async:false,
|
|
|
+ timeout: 3000
|
|
|
+ });
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ function getAverageRGB(imgEl) {
|
|
|
+ var blockSize = 5,
|
|
|
+ defaultRGB = {r:0,g:0,b:0},
|
|
|
+ canvas = document.createElement('canvas'),
|
|
|
+ context = canvas.getContext && canvas.getContext('2d'),
|
|
|
+ data, width, height,
|
|
|
+ i = -4,
|
|
|
+ length,
|
|
|
+ rgb = {r:0,g:0,b:0},
|
|
|
+ count = 0;
|
|
|
+
|
|
|
+ if (!context) {
|
|
|
+ return defaultRGB;
|
|
|
+ }
|
|
|
+
|
|
|
+ height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
|
|
|
+ width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
|
|
|
+
|
|
|
+ context.drawImage(imgEl, 0, 0);
|
|
|
+
|
|
|
+ try {
|
|
|
+ data = context.getImageData(0, 0, width, height);
|
|
|
+ } catch(e) {
|
|
|
+ /* security error, img on diff domain */
|
|
|
+ return defaultRGB;
|
|
|
+ }
|
|
|
+
|
|
|
+ length = data.data.length;
|
|
|
+
|
|
|
+ while ( (i += blockSize * 4) < length ) {
|
|
|
+ ++count;
|
|
|
+ rgb.r += data.data[i];
|
|
|
+ rgb.g += data.data[i+1];
|
|
|
+ rgb.b += data.data[i+2];
|
|
|
+ }
|
|
|
+
|
|
|
+ // ~~ used to floor values
|
|
|
+ rgb.r = ~~(rgb.r/count);
|
|
|
+ rgb.g = ~~(rgb.g/count);
|
|
|
+ rgb.b = ~~(rgb.b/count);
|
|
|
+
|
|
|
+ return rgb;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ </script>
|
|
|
+</body>
|
|
|
</html>
|