Procházet zdrojové kódy

Added experimental airmusic local indexDB caching function

Toby Chui před 2 roky
rodič
revize
a7d8f6fcf4
4 změnil soubory, kde provedl 2755 přidání a 2649 odebrání
  1. binární
      web/Music/img/favicon.png
  2. binární
      web/Music/img/favicon.psd
  3. 2730 2624
      web/Music/index.html
  4. 25 25
      web/Music/manifest.json

binární
web/Music/img/favicon.png


binární
web/Music/img/favicon.psd


+ 2730 - 2624
web/Music/index.html

@@ -1,2625 +1,2731 @@
-<!DOCTYPE html>
-<html>
-<head>
-	<meta charset="UTF-8">
-	<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"/>
-	<meta name="theme-color" content="#4b75ff">
-	<link rel="stylesheet" href="../script/semantic/semantic.min.css">
-	<link rel="stylesheet" href="./main.css">
-	<script src="../script/jquery.min.js"></script>
-	<script src="../script/ao_module.js"></script>
-	<script src="../script/semantic/semantic.min.js"></script>
-	
-	<!-- Handle native playback on Chrome Andoird-->
-	<script src="native.js"></script>
-
-	<link rel="manifest" crossorigin="use-credentials" href="manifest.json">
-	<title>AirMusic</title>
-</head>
-<body>
-<div id="mainMenu" class="ui basic fluid AMmenu menu bottomBlue" style="z-index:80;position:fixed;position:top:0px;left:0px;width:100%;">
-    <button class="ui item icon noBorder AMmenu button" onClick="toggleLeftMenu();"><i class="content icon"></i></button>
-	<div class="item noBorder AMmenu" style="padding-right:0px;padding-top:12px;"><i id="AMmenuIcon" class="music icon large whiteFont"></i></div>
-	<div class="item noBorder AMmenu" style="padding-left:3px;padding-top:3px;padding-bottom:5px;min-width:50%;">
-		<div class="ui header whiteFont">
-			<div id="interfaceTitle" style="display:inline; font-weight: lighter;">Music</div>
-			<div id="interfaceDetails" class="sub header" style="font-size:80%; line-height:1em; color: white;">[0 songs]</div>
-		</div>
-	</div>
-	<button class="ui right item icon AMmenu noBorder button" onClick="enterSearchMode();"><i class="search icon"></i></button>
-	<!-- <button class="ui right item icon AMmenu noBorder button"><i class="ellipsis vertical icon"></i></button> -->
-</div>
-<div id="searchModeMenu" class="ui basic fluid AMmenu menu bottomBlue" style="z-index:85;position:fixed;top:0px;left:0px;width:100%;height:51px;display:none;margin-top: 0px;">
-    <button class="ui item icon noBorder AMmenu button" onClick="exitSearchMode();"><i class="arrow left icon"></i></button>
-	<div class="ui input" style="flex-grow: 1;">
-		<input id="searchInputBar" onkeypress="//handleSearchInputEnter(event);" type="text" style="background-color:rgb(48, 48, 48);border:0px !important;border-bottom:2px solid rgb(60, 60, 60) !important;margin-bottom:3px;color:white;" placeholder="Search Music">
-	</div>
-	<button class="ui right item icon AMmenu noBorder button" onClick="searchSong();"><i class="search icon"></i></button>
-</div>
-<!-- The main list that display the current information-->
-<div id="mainList">
-
-</div>
-
-<!-- Advance functions config menu-->
-<div id="showmoreUIcover" style="position:fixed;left:0px;top:0px;width:100%;height:100%;background:rgba(30,30,30,0.7);z-index:95;display:none;" onClick="hideShowMoreMenu();"></div>
-<div id="showMoreUI" class="showMoreMenus" style="display:none;">
-    <div class="ui large header whiteFont songTitle">N/A</div>
-    <div class="showMoreMenuItem" onClick="playFromShowMoreMenu();">Play</div>
-    <div class="showMoreMenuItem" onclick='addToPlaylistFromMoreMenu();'>Add to Playlist</div>
-    <div class="showMoreMenuItem playlistonly" onclick="removeFromPlylistFromMoreMenu();">Remove from current Playlist</div>
-    <div class="showMoreMenuItem" onClick="searchYoutubeViaShowMore();">Search on Youtube</div>
-    <div class="showMoreMenuItem">Edit Tag</div>
-    <div class="showMoreMenuItem">Share</div>
-    <div class="showMoreMenuItem" onClick="startRelatedSearch();">Related Search</div>
-    <div class="showMoreMenuItem" onClick="showFileInfo();">File Information</div>
-    
-    <div class="topRightCorner songID" align="center" style="margin-top:10px !important;padding-top:3px !important;">-1</div>
-</div>
-<div id="showFileInfo" class="showMoreMenus" style="display:none;">
-    <div class="ui large header">
-		<span class="filename whiteFont">Title</span>
-		<div class="sub header rawname whiteFont" style="word-break: break-all !important; font-size:80%;">Storage Name</div>
-	</div>
-	<div class="ui list whiteFont">
-		<div class="item whiteFont">Storage Location:   <span class="filepath" style="word-break:break-all;">N/A</span></div>
-		<div class="item whiteFont">File Size:   <span class="filesize">N/A</span></div>
-		<div class="item whiteFont">Last Modification Date:   <span class="filedate">N/A</span></div>
-	</div>
-</div>
-
-<!-- Side bar -->
-<div id="sideBarCover" style="position:fixed;left:0px;top:0px;width:100%;height:100%;background:rgba(30,30,30,0.7);z-index:50;display:none;" onClick="toggleLeftMenu();"></div>
-<div id="leftSideBar" class="leftsb" style="max-width:60%;height:100%;z-index:90;display:none;">
-	<div class="leftsbObject sidebarBanner">
-		<img class="ui tiny middle aligned image" src="img/main_icon.png" style="max-width: 50px;"><h5 class="whiteFont" style="display:inline;padding-left:8px;">AirMusic</h5>
-	</div>
-	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadSongList();setStorage('viewingTab','music');">
-		<div class="ui header">
-			<i class="music tiny icon whiteFont"></i>
-			<div class="content whiteFont">
-				Music
-			</div>
-		</div>
-	</div>
-	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadFolderView();setStorage('viewingTab','folder');">
-		<div class="ui header">
-			<i class="folder tiny icon whiteFont"></i>
-			<div class="content whiteFont">
-				Folder
-			</div>
-		</div>
-	</div>
-	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadPlaylistView(); setStorage('viewingTab','playlist');">
-		<div class="ui header">
-			<i class="align justify tiny icon whiteFont"></i>
-			<div class="content whiteFont">
-				Playlists
-			</div>
-		</div>
-	</div>
-	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadNetworkView(); setStorage('viewingTab','network');">
-		<div class="ui header">
-			<i class="world tiny icon whiteFont"></i>
-			<div class="content whiteFont">
-				Network
-			</div>
-		</div>
-	</div>
-	<!-- 
-	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="">
-		<div class="ui header">
-			<i class="upload icon whiteFont"></i>
-			<div class="content whiteFont">
-				Upload
-			</div>
-		</div>
-	</div>
-	-->
-	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;border-top: 2px solid #4a4a4a;">
-		<div class="ui header">
-			<i class="setting tiny icon whiteFont"></i>
-			<div class="content whiteFont">
-				Settings
-			</div>
-		</div>
-	</div>
-</div>
-
-<!-- Mini player controller put on the bottom side of the list interface-->
-<div id="miniPlayer" class="hidden">
-    <div style="padding-left:20px;padding-top:5px;" >
-        <div class="ui header selectable" style="margin:0px !important;width:300px;cursor:pointer;" onClick="showMainPlayerInterface();">
-            <img id="smallPlayerThumb" class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
-            <div class="content whiteFont" style="padding-top:5px;line-height:1em;">
-                <div id="miniPlayerDisplayName" style="text-overflow: ellipsis;overflow: hidden;max-width:200px; white-space: nowrap;">N/A</div>
-                <div id="miniPlayerInformation" class="sub header" style="color: #c7c7c7;size:95%;">No information</div>
-            </div>
-        </div> 
-    </div>
-    <div id="miniPlayerIDtab" class="miniPlayer minitab">
-        0/0
-    </div>
-    <div class="miniPlayerControls">
-        <button class="miniPlayer selectable" style="font-size:90%; font-weight: lighter;" onClick="previousSong();"><i class="step backward icon whiteFont"></i></button>
-        <button class="miniPlayer selectable" style="font-size:120%; font-weight: lighter;" onClick="togglePlayMode();"><i class="play icon whiteFont PlayButton"></i></button>
-        <button class="miniPlayer selectable" style="font-size:90%; font-weight: lighter;" onClick="nextSong();"><i class="step forward icon whiteFont "></i></button>
-    </div>
-</div>
-<!-- Main interface for player and audio controller-->
-<div id="playerInterface" style="display:none;">
-    <div id="infoBar" class="whiteFont" style="padding:20px;" align="center">
-        <!-- Top Information Bar-->
-       
-        <div class="whiteFont songTitleWrapper" style="margin:0px;display:inline-block;">
-            <div id="mainPlayerSongTitle" class="whiteFont" style="font-weight: bold;font-size:120%;">Song Title</div>
-            <small id="mainPlayerSongDesc">This is some small text for display</small>
-        </div>
-         <div style="position:absolute;left:20px;top:30px;cursor:pointer;" onClick="hideMainPlayerInterface();">
-            <i class="large chevron left icon"></i>
-        </div>
-        <div style="position:absolute;right:20px;top:30px;cursor:pointer;" onClick='$("#dropdownSonglist").slideDown();'>
-            <i class="large content icon"></i>
-        </div>
-    </div>
-    <div style="padding-left:20px; padding-right:20px;padding-bottom:5px; position: relative;" align="center">
-        <!-- Function Menu Bar-->
-        <div class="ui grid">
-            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onclick="showPlaylistInterface();"><i class="large plus icon whiteFont"></i></button></div>
-            <div class="two wide column"><button class="topPanelButtons" id="downloadBtn" style="cursor: pointer;" onClick="downloadPlayingSong();"><i class="large download icon whiteFont"></i></button></div>
-            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onClick="openInFileExplorer();"><i class="large folder open icon whiteFont"></i></button></div>
-            <div class="two wide column desktopOnly" style="margin-top: -4px;"><button class="topPanelButtons" style="cursor: pointer; opacity: 0.6;" onClick="mute(this);" ><i class="icons"><i class="big red dont icon"></i><i style="margin-left: -3px;" class="large volume off icon whiteFont"></i></i></button></div>
-            <div class="two wide column desktopOnly"><button class="topPanelButtons" id="voldownBtn" style="cursor: pointer;" onClick="addAudioVolume(-0.05);"><i class="large volume down icon whiteFont"></i></button></div>
-            <div class="two wide column desktopOnly"><button class="topPanelButtons" id="volupBtn" style="cursor: pointer;" onClick="addAudioVolume(0.05);"><i class="large volume up icon whiteFont"></i></button></div>
-            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onClick="showTimerInterface();"><i class="large clock icon whiteFont"></i></button></div>
-            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onClick="showSettingInterface();"><i class="large setting icon whiteFont"></i></button></div>
-        </div>
-        <div id="volumeGUI" align="center">
-            <i class="volume off large icon whiteFont" style="position:absolute;left:2em;top:1em;"></i>
-            <div class="ui tiny progress" style=" margin-top: calc(2em - 5px); margin-bottom: 0; background-color: rgba(255,255,255,0.2);" align="left">
-                <div id="volBar" class="bar" style="min-width: 0px; width: 40%; height: 10px; background-color: #4b75ff;"></div>
-            </div>
-           <i class="volume up large icon whiteFont" style="position:absolute;right:2em;top:1em;"></i>
-        </div>
-    </div>
-	<!-- Download progress bar-->
-	<div id="downloadProgressBar" class="ui attached fluid tiny progress" style="background-color:rgba(20, 20, 20, 0.9);display:none;">
-		<div class="bar" style="min-width: 0px; width: 0%;background-color:rgb(75, 117, 255) !important;"></div>
-	</div>
-
-    <div id="albumnArt" align="center">
-        <img id="albumnArtImage" style="max-width: 80%; pointer-events: none; user-select: none;" src="img/default.png"> 
-    </div>
-    <div id="mainPlayerControlInterface">
-        <!-- main control interface-->
-        <div style="width:100%;" align="center">
-            <div id="progressTime">
-                0:00
-            </div>
-            <div id="mainPlayerMiniTab" class="mainPlayer minitab">
-                0/0
-            </div>
-            <div id="remainTime">
-                -0:00
-            </div>
-        </div>
-        
-        <div style="position:absolute;width:100%;left:0px;bottom:0px;">
-            <div style="padding-left:10px;padding-right:10px;">
-                <div class="ui small primary progress" style="background-color: rgba(255,255,255,0.4);">
-                    <div id="audioProgressBar" class="bar" style="min-width: 0px; width: 100%; background: #4b75ff;"></div>
-                </div>
-            </div>
-            <div class="mainControlButtons">
-                <button class="panelButtons" style="font-size:90%;padding:15px;" onClick="previousSong();"><i class="step backward icon whiteFont"></i></button>
-                <button class="panelButtons" style="font-size:130%;" onClick="togglePlayMode();"><i class="play icon whiteFont PlayButton"></i></button>
-                <button class="panelButtons" style="font-size:90%;padding:15px;" onClick="nextSong();"><i class="step forward icon whiteFont "></i></button>
-            </div>
-            <div id="randomModeButton" style="position: absolute; left:30px;bottom:20px;" onClick="toggleRandomMode(this);">
-                <i class="large random icon disabled"></i>
-            </div>
-            <div id="repeatModeButton" style="position: absolute; right:30px;bottom:20px;" onClick="toggleRepeatMode(this);">
-                <i class="large retweet icon disabled"></i>
-                <p class="whiteFont singleLoop" style="position:absolute;right:0px;bottom:0px;margin-bottom:-13px;margin-right:-2px;display:none;">1</p>
-            </div>
-        </div>
-    </div>
-    <audio id="mainAudioPlayer" style="display:none;" src=""></audio>
-   
-	<div id="dropdownSonglist" class="dropdownMusicList" style="display:none;">
-			<div class="dropdownMusicListMiniMenu">
-				<i class="icons" style="margin-right:8px;">
-					<i class="content icon"></i>
-				<i class="corner music icon" style='color:#333333'></i>
-				</i>
-				Now Playing
-				<div style="position:absolute;top:3px;right:5px;">
-					[ <span id="dropdownListSongCount">N/A</span> songs / <span id="dropdownListIDCount">N/A</span> MB ] <button onClick='$("#dropdownSonglist").slideUp();' style="cursor:pointer;"><i class="caret up icon whiteFont"></i></button>
-				</div>
-			</div>
-			<div id="currentPlayingMainList" style="overflow-x:hidden;">
-				
-			</div>
-			<div class="dropdownMusicListBottom" align="center" onClick='$("#dropdownSonglist").slideUp();'><i class="caret up icon"></i></div>
-	</div>
-    
-</div>
-
-<!-- Quick Menus and other tool windows-->
-
- <!-- Timer control interface-->
- <div id="timerInterface" class="quickMenu">
-	<h4 class="whiteFont">Countdown Timer</h4>
-	<br>
-	<div id="timerSettingInterface" style="width:100%;" align="center">
-		<div>
-			<div class="ui statistic">
-				<div class="label whiteFont">hours</div>
-				<div id="timerHour" class="value whiteFont">0</div>
-			</div>
-			 <div class="ui statistic">
-				<div class="label whiteFont">minutes</div>
-				<div id="timerMinute" class="value whiteFont">0</div>
-			</div>
-		</div>
-		<div>
-			<div class="ui icon mini buttons">
-				<button class="ui secondary button" onClick="addTimer('h',1);"><i class="add icon"></i></button>
-				<button class="ui secondary button" onClick="addTimer('h','r');"><i class="refresh icon"></i></button>
-				<button class="ui secondary button" onClick="addTimer('h',-1);"><i class="minus icon"></i></button>
-			 </div>
-			 <div class="ui icon mini buttons">
-				<button class="ui secondary button" onClick="addTimer('m',10);"><i class="add icon"></i></button>
-				<button class="ui secondary button" onClick="addTimer('m','r');"><i class="refresh icon"></i></button>
-				<button class="ui secondary button" onClick="addTimer('m',-1);"><i class="minus icon"></i></button>
-			 </div>
-		</div>
-	</div>
-	<div id="timerCountingInterface" style="width:100%; display:none;" align="center">
-		<div class="ui statistic">
-			<div id="remainingUI" class="value whiteFont">0:00:00</div>
-			<div class="label whiteFont">Remaining</div>
-		</div>
-	</div>
-	<div class="ui divider"></div>
-	<div>
-		<div class="ui grid">
-			<div class="eight wide column">
-				Times up action
-			</div>
-			<div class="eight wide column">
-				<select id="stopMode" class="ui selection mini fluid dropdown">
-					<option>Fade Out & Stop</option>
-					<option>Stop Playing</option>
-				</select>
-			</div>
-		</div>
-	</div>
-	<div style="width:100%;position:absolute;left:0px;bottom:20px;" align="right">
-		<div class="ui grid" >
-			<div class="eight wide column" style="padding-right: 0px;" align="center"><button class="greenBtn fluid" onClick='hideAllquickMenu();'>Close</button></div>
-			<div class="eight wide column"  style="padding-left: 0px;" align="center"><button class="greenBtn fluid" onClick="toggleCountDown(this);">Start</button></div>
-		</div> 
-	</div>
-</div>
-
-<!-- File properties interface-->
-<div id="filepropInterface" class="quickMenu">
-	<div class="ui header">
-		<span class="filename whiteFont">Title</span>
-		<div class="sub header rawname whiteFont"  style="word-break:break-all;">Storage Name</div>
-	</div>
-	<div class="ui list whiteFont">
-		<div class="item whiteFont">Storage Location:   <span class="filepath"  style="word-break:break-all;">N/A</span></div>
-		<div class="item whiteFont">File Size:   <span class="filesize">N/A</span></div>
-		<div class="item whiteFont">Last Modification Date:   <span class="filedate">N/A</span></div>
-	</div>
-</div>
-<!-- Setting interface-->
-<div id="settingInterface" class="quickMenu">
-	<div style="">
-		<div class="ui relaxed list" style="padding:0px !important;">
-			<div id="settingMenuTitle" class="item whiteFont" style="">N/A</div>
-			<div class="item selectable whiteFont" onclick="showPlaylistInterface(); $('#settingInterface').fadeOut('fast');"><i class="add icon" style="margin-right:5px;"></i> Add to playlist</div>
-			<div class="item selectable whiteFont" onClick="openInFileExplorer(); hideAllquickMenu();"><i class="folder open icon" style="margin-right:5px;"></i> Open in File Explorer</div>
-			<div class="item selectable whiteFont" onClick="searchOnYoutube(); hideAllquickMenu();"><i class="youtube play icon" style="margin-right:5px;"></i>Search on Youtube</div>
-			<div class="item selectable whiteFont" onClick="showFileInformation();"><i class="file icon" style="margin-right:5px;"></i> File Information</div>
-			<div class="ui divider"></div>
-			<div id="closeWebAppButton" class="item selectable whiteFont"  onClick="ao_module_close();"><i class="remove icon" style="margin-right:5px;"></i> Exit Application</div>
-		</div>
-	</div>
-</div>
-
-
-<!-- Playlist interface-->
-<div id="playlistInterface" class="quickMenu">
-	<div class="ui header">
-		<span class="whiteFont">Add to Playlist</span>
-	</div>
-	<div class="playlist item selectable whiteFont" onclick="addToNewPlaylist();">
-		<i class="add icon whiteFont"></i> New Playlist
-	</div>
-	<!-- playlist list-->
-	<div id="existsingPlaylist" style="overflow-y: scroll; height: 50%; border: 1px solid white;">
-		<div class="playlist item selectable whiteFont">
-			<i class="list icon whiteFont"></i> Test Playlist
-		</div>
-	</div>
-	<br>
-	<div style="width:100%;position:absolute;left:0px;bottom:0px; margin-bottom: 10px;" align="center">
-	<button class="greenBtn" onClick='hideAllquickMenu();'>Close</button>
-	</div>
-	<div class="ui snackbar" id="succSnackBar">
-		<div class="content">
-			Action Completed
-		</div>
-	</div>
-</div>
-
-<!-- Utils Interfaces, usually hidden-->
-<div id="fadeReturnScreen" class="fadeScreen whiteFont" onClick="hideAllquickMenu();"></div>
-
-<script>
-	var leftMenuShown = false;
-	var currentPath = "";
-	var currentMode = "music";
-	var rootPaths = [];
-	var totalMusicCount = 0;
-	var currentPlaying = false;
-	var audioElement = $("#mainAudioPlayer");
-	var audioElementObject = document.getElementById("mainAudioPlayer"); //Directly expose the audio object
-	var playingFileDetail = []; //[id, filepath]
-	var displayList = []; //This is the list where the current UI is displaying.
-	var playingList = []; //This is the list where the player last clicked on an item to play
-	var pagingEnabled = false; //Enable this when there are too many songs in list
-	var pagingEnableForPlayingList = false; 
-	var pagingCutoffCount = 100; //No. of songs to start paging
-	var currentPage = 0;
-	var currentPlayingPage = 0;
-	var randomMode = false;
-	var repeatMode = 0; //Repeat mode 0 -> No repeat, 1 -> Repeat all 2 -> Repeat one
-	var updateSystemVolume = true;
-	var timerMode = false;
-	var timerRemaining = 0;
-	var playlistAddPendingFile = ""; //The filepath of the file that is pending to be added to playlist
-	var timerEndMode = "fade"; //Fade or End, Provide volume fadeout or end immediately while times up
-	var ua =  navigator.userAgent.toLowerCase();
-	var isAndroid = ua.indexOf("android") > -1; //&& ua.indexOf("mobile");
-	var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
-
-	//Embed native mediaSession for any device that supports it 
-	initNativeMediaPlayer();
-
-	//Update implementatio nof user agent detection
-	if (typeof InstallTrigger !== 'undefined'){
-		ua = "firefox";
-	}
-
-	if (!!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime)){
-		ua = "chrome";
-	}
-
-	var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
-	if (isSafari == true){
-		ua = "safari";
-	}
-
-
-	$(document).ready(function(){
-		$("#leftSideBar").animate({left: $("#leftSideBar").width() * -1}, 300);
-		//Update 7-8-2019, default loading tab is handled over to the returnToPreviousState() function.
-		//loadSongList(); 
-		//Initiate the module's volume to the system's
-		syncSystemVol();
-		initAudioListeners();
-        resizeQuickAdjust(); //Adjust all the DOM items position according to window size
-        restoreAllSettings(); //Restore all user prefered settings from storage
-        hideMainPlayerInterface();//Hide the main interface
-        setTimeout(function(){
-            $("#playerInterface").show(); //Only show this interface after it has been out of the working area.
-        },500);
-        
-        //Hide the exit application button if it is not in Virtual Desktop Mode
-        if (!ao_module_virtualDesktop){
-            $("#closeWebAppButton").hide();
-        }
-		returnToPreviousState(); //Try to return to previous state using the window hash value
-	});
-
-	function returnToPreviousState(){
-		var hash = window.location.hash;
-		if (hash != ""){
-			//There are state to restore. Restore using the given hash value
-			hash = decodeURIComponent(hash.substring(1));
-			var previousState = JSON.parse(hash);
-			console.log(previousState);
-			var currentPath = previousState.path;
-			var playingFileDetail = previousState.pfp;
-			var initPauseState = previousState.pause;
-			if (currentPath != ""){
-				//Create a dummy folder and trick the system to load to the previous states
-				var a = '<div></div>';
-				a = $(a).attr("filepath",currentPath);
-				openFolder(a[0],{playIDAfterOpen: playingFileDetail[0],startPaused: initPauseState});
-			}else{
-				//currentpath is empty, aka Music Mode
-				loadSongList();
-			}
-
-			
-		}else{
-			//No state to restore. Restore Viewing Tab instead.
-			var vt = loadStorage("viewingTab");
-			if (vt != ""){
-				if (vt == "music"){
-					loadSongList();
-					
-				}else if(vt == "folder"){
-					loadFolderView();
-					
-				}else if(vt == "playlist"){
-					loadPlaylistView();
-					
-				}else if(vt == "network"){
-					loadNetworkView();
-					
-				}
-			}else{
-				//Default action
-				loadSongList();
-			}
-		}
-	}
-
-	function loadNetworkView(){
-		currentMode = "network";
-		togglePagingMode(false);
-	}
-
-	function togglePagingMode(enabled=false){
-		if (pagingEnabled != enabled){
-			currentPage = 0;
-		}
-		pagingEnabled = enabled;
-	}
-	
-	function initAudioListeners(){
-		//Initiate audio progress bar and link it to the progress bar on the main player interface
-		audioElement[0].addEventListener("timeupdate", function() {
-            var currentTime = audioElement[0].currentTime;
-            var duration = audioElement[0].duration;
-            $('#audioProgressBar').css('width',((currentTime +.25)/duration)*100 + '%');
-            updatePlaybackDisplayTime(currentTime,duration);
-        });
-        audioElement[0].onended = function() {
-            nextSongHandler(); 
-        }; 
-        
-        //Handle clicks on progress bar to skip through the playback
-        $("#audioProgressBar").parent().on("click",function(e){
-           var duration = audioElement[0].duration;
-           var jumpTo = (e.offsetX / $(this).width()) * duration;
-           if (!audioElement[0].paused){
-                audioElement[0].pause();
-                audioElement[0].currentTime = jumpTo;
-	            audioElement[0].play();
-           }else{
-               audioElement[0].currentTime = jumpTo;
-           }
-          
-	      
-        });
-	}
-	
-	function restoreAllSettings(){
-	    //Repeat mode setting
-	    var strRmode = loadStorage("repeatMode");
-	    if (strRmode != ""){
-	        repeatMode = parseInt(strRmode);
-	        setRepeatMode(repeatMode,$("#repeatModeButton")[0]);
-	    }
-	    //Random Mode setting
-	    var random = loadStorage("randomMode");
-	    if (random != ""){
-	        if (random == "true"){
-	            //random Mode is true when loaded from configuration. Toggle once to match the setting
-	            toggleRandomMode($("#randomModeButton")[0]);
-	        }
-	    }
-	    //Timer mode setting
-	    var TEM = loadStorage("timerEndMode");
-	    if (TEM != ""){
-	        if (TEM == "fade"){
-	            $("#stopMode").val("Fade Out & Stop");
-    	    }else{
-    	        $("#stopMode").val("Stop Playing");
-    	    }
-	    }
-	  
-	}
-	
-	//Setting menu function
-	function searchOnYoutube(filename = ""){
-		if (filename == ""){
-			var filename = $("#mainPlayerSongTitle").text().trim();
-		}
-	    
-	    var url = "https://www.youtube.com/results?search_query=" + filename ;
-	    window.open(url);
-	}
-	
-	//Searching related functions
-	var preSearchItemBuffer = "";
-	var searchModeEnabled = false;
-	var previousPagingEnabled = false;
-	function enterSearchMode(){
-		if (searchModeEnabled){
-			//Search mode already enabled
-			return;
-		}
-		previousPagingEnabled = pagingEnabled;
-		togglePagingMode(false);
-		$("#searchModeMenu").show();
-		$("#mainMenu").hide();
-		let previousDisplayList = Array.from(displayList);
-		preSearchItemBuffer = [$("#mainList").html(),$("#interfaceTitle").text(),$("#AMmenuIcon").attr("class"), $("#interfaceDetails").html(), previousDisplayList];
-		searchModeEnabled = true;
-	}
-
-	function exitSearchMode(){
-		$("#searchModeMenu").hide();
-		$("#mainMenu").show();
-		$("#searchInputBar").val("");
-		if (preSearchItemBuffer != ""){
-			//If previous record exists, recover the previous view from storage
-			$("#mainList").html(preSearchItemBuffer[0]);
-			$("#interfaceTitle").text(preSearchItemBuffer[1]);
-			$("#AMmenuIcon").attr("class",preSearchItemBuffer[2]);
-			$("#interfaceDetails").html(preSearchItemBuffer[3]);
-			displayList = preSearchItemBuffer[4];
-			preSearchItemBuffer = "";
-		}
-
-		if (previousPagingEnabled){
-			togglePagingMode(true);
-		}
-		searchModeEnabled = false;
-	}
-
-	document.getElementById("searchInputBar").addEventListener("keypress", function(event){
-		console.log(event, event.keyCode);
-		if(event.keyCode == 13){
-			//Enter pressed. start searching
-			searchSong();
-		}
-	});
-
-	/*
-	function handleSearchInputEnter(e){
-		if(e.keyCode == 13){
-			//Enter pressed. start searching
-			searchSong();
-		}
-	}
-	*/
-
-	function searchSong(){
-		var keyword = $("#searchInputBar").val();
-		if (keyword.includes("?") || keyword.includes("&")){
-			alert("Search keyword cannot contains & or ? symbol.");
-			return;
-		}
-
-		if (keyword == ""){
-			//Empty keyword. Return nothing
-			return;
-		}
-		//Clear the mainList, replace with a dummy loading screen
-		$("#mainList").html('<div class="mainList item whiteFont">\
-			<div class="ui header" style="margin:0px !important;padding-bottom:15px;padding-top:5px;">\
-			<i class="loading spinner icon whiteFont" style="overflow:hidden;margin-top:5px;"></i>\
-				<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">\
-					Searching...\
-				</div>\
-			</div>\
-			<div class="topRightCorner" align="center">\
-				-1\
-			</div>\
-			</div>');
-
-		ao_module_agirun("Music/functions/listSong.js", {
-			listSong: "search:" + keyword
-		}, function(data){
-			currentPath = "";
-			var template = '<div class="mainList file item" filepath={filepath} id={id} rawname={rawname}>\
-			<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">\
-				<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>\
-				<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">\
-					{songtitle}\
-					<div class="sub header fileinfo" style="color: #c7c7c7;">{ext} / {size}</div>\
-				</div>\
-			</div>\
-			<div class="topRightCorner" align="center">\
-				{id}\
-			</div>\
-			<div class="mainList rightFunctionBar" align="center" onClick="showMore(this);">\
-				<i class="ellipsis vertical icon" style="top: 2em;"></i>\
-			</div>\
-		</div>';
-
-		if ($("#searchModeMenu").is(":hidden")){
-			//The user exited search mode before the search results come back
-			//Dispose the search result
-			return;
-		}
-		
-		if (data.length == 0){
-			//No search results.
-			$("#mainList").html("");
-			$("#mainList").append('<div class="mainList item whiteFont">\
-			<div class="ui header" style="margin:0px !important;padding-bottom:15px;padding-top:5px;">\
-			<i class="remove icon whiteFont" style="overflow:hidden;margin-top:5px;"></i>\
-				<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">\
-					No result for keyword: ' + keyword + '.\
-				</div>\
-			</div>\
-			<div class="topRightCorner" align="center">\
-				-1\
-			</div>\
-			</div>');
-			return;
-		}
-		
-
-        $("#interfaceTitle").text("Search");
-        $("#AMmenuIcon").attr("class","search icon large whiteFont")
-		//Initialize the song list
-		displayList = data;
-		if (playingList == []){
-			playingList = Array.from(displayList);
-			pagingEnableForPlayingList = pagingEnabled;
-			currentPlayingPage = currentPage;
-		}
-		$("#mainList").html("");
-		for ( var i =0; i < data.length; i++){
-			var songInfo = data[i];
-			var path = songInfo[0];
-			var displayname = ao_module_codec.decodeUmFilename(songInfo[1]);
-			var ext = songInfo[2];
-			var size = songInfo[3];
-			var box = template;
-			box = replaceAll("{filepath}",ao_module_utils.objectToAttr(path),box);
-			box = replaceAll("{id}",i + 1,box); //User count from 1
-			box = replaceAll("{rawname}",ao_module_utils.objectToAttr(songInfo[1]),box);
-			box = replaceAll("{songtitle}",displayname,box);
-			box = replaceAll("{ext}",ext,box);
-			box = replaceAll("{size}",size,box);
-			$("#mainList").append(box);
-		}
-		totalMusicCount = data.length;
-		$("#mainList").append("<br><br><br><br><br><br><br>");
-		$("#interfaceDetails").text("[" + i + " songs]");
-		highLightPlayingMusic();
-		loadThumbnailToMusicList(".mainList.file.item");
-	});
-
-	}
-	
-	function enterRemotePlayID(object){
-	    var id = $(object).text().trim();
-	    $("#remotePlayID").val($("#remotePlayID").val() + id);
-	}
-	
-	function ridOpr(opr){
-	    if (opr == 'backspace'){
-	        var currentText = $("#remotePlayID").val();
-	        var newText = currentText.substring(0,currentText.length - 1);
-	        $("#remotePlayID").val(newText);
-	    }else if (opr == 'reset'){
-	        $("#remotePlayID").val("");
-	    }
-	}
-	
-	function openInFileExplorer(){
-	    var dirname = playingFileDetail[1].split("/");
-	    var fname = dirname.pop(); //Pop away the filename
-	    dirname = dirname.join("/") + "/";
-	    var path = dirname;
-	    if (dirname.substring(0,1) != "/"){
-	        //This is not absolute path. Start the path from airMusic
-	        path = "AirMusic/" + dirname;
-	    }
-	    
-		path = path.replace("media?file=","");
-		if (path.substring(0,1) == "/"){
-			path = path.substring(1)
-		}
-	    ao_module_openPath(path, fname);
-	}
-	
-	
-	//quickmenu Functions
-	function hideAllquickMenu(){
-	    $(".quickMenu").fadeOut('fast');
-	    $("#fadeReturnScreen").fadeOut('fast');
-	}
-
-	
-
-	
-	//Setting related function
-	function showSettingInterface(){
-	    $("#settingInterface").fadeIn('fast');
-	    $("#fadeReturnScreen").fadeIn('fast');
-	    //Update contents in the setting menu
-	    $("#settingMenuTitle").text($("#mainPlayerSongTitle").text());
-	}
-	
-	
-	//Timer related functions
-	function showTimerInterface(){
-	    $("#timerInterface").fadeIn('fast');
-	    $("#fadeReturnScreen").fadeIn('fast');
-	}
-
-	function initPlaylistInterfaceList(){
-		$("#existsingPlaylist").html("");
-		//Get the playlist list from server side
-		ao_module_agirun("Music/functions/playlist.js", {
-			opr: "root"
-		}, function(data){
-			data.forEach(playlist => {
-				$("#existsingPlaylist").append(`<div class="playlist item selectable whiteFont" name="${playlist.name}" onclick="addSongToSelectedPlaylist(this);">
-					<i class="list icon whiteFont"></i> ${playlist.name} [${playlist.count} files]
-				</div>`);
-			})
-		});
-	}
-
-	function showPlaylistInterface(){
-		initPlaylistInterfaceList();
-		$("#playlistInterface").fadeIn('fast');
-	    $("#fadeReturnScreen").fadeIn('fast');
-	}
-
-	function addToThisPlaylist(){
-
-	}
-	
-	$("#stopMode").change(function () {
-        var end = this.value;
-        if (end.includes("Fade Out & Stop")){
-            //Start fading out the volume
-            timerEndMode = "fade";
-            setStorage("timerEndMode","fade");
-        }else{
-            //End immediately
-            timerEndMode = "end";
-            setStorage("timerEndMode","end");
-        }
-    });
-    
-    var fadeOutStepping = 0.1; //The steps size for fading out during timer countdown
-    var defaultVolumeBeforeFadeout = 0;
-    function toggleCountDown(button){
-        if (!timerMode){
-            //Start count down
-            timerMode = true;
-            $(button).text("Stop");
-            timerRemaining = ((parseInt($("#timerHour").text()) * 60) + parseInt($("#timerMinute").text())) * 60; //in seconds
-            if (timerRemaining <= 0){
-				//Start with 0
-				timerMode = false;
-				$(button).text("Start");
-				return;
-			}
-			//Update the value on the remaining counter
-            $("#remainingUI").text(parseTimer(timerRemaining));
-            $("#timerSettingInterface").slideUp('fast');
-            $("#timerCountingInterface").slideDown('fast');
-            $("#stopMode").attr("disabled","");
-            defaultVolumeBeforeFadeout = audioElement[0].volume;
-            fadeOutStepping = (audioElement[0].volume) / timerRemaining;
-            progressCounter();
-        }else{
-            //Stop count down
-            timerMode = false;
-            $(button).text("Start");
-            timerRemaining = 0;
-            $("#timerSettingInterface").slideDown('fast');
-            $("#timerCountingInterface").slideUp('fast');
-            $("#stopMode").removeAttr("disabled");
-        }
-    }
-    
-    function progressCounter(){
-        //Update the timer
-        timerRemaining = timerRemaining - 1;
-        $("#remainingUI").text(parseTimer(timerRemaining));
-        if (timerRemaining > 0){
-            //Continues
-            if (timerEndMode == "fade"){
-                var newvol = audioElement[0].volume - fadeOutStepping;
-                audioElement[0].volume = Math.max(0,newvol);
-            }
-            setTimeout(progressCounter,1000);
-        }else{
-            //Times up
-            handleTimerEnd();
-        }
-        
-    }
-    
-    function handleTimerEnd(){
-        //Stop the playback
-        originalVol = audioElement[0].volume;
-	    fadeAudio();
-	    setPlaying(false);
-	    audioElement[0].pause();
-	    setTimeout(function(){
-	        audioElement[0].volume = defaultVolumeBeforeFadeout;
-	    },500);
-	    
-    }
-    
-    function parseTimer(remainingTime){
-        //remainingTime in seconds, prase to HH:mm:ss
-        var hours = Math.floor(remainingTime / 3600);
-        var remainingTime = remainingTime % 3600;
-        var minutes = Math.floor(remainingTime / 60);
-        var seconds = remainingTime % 60;
-        if (minutes < 10){
-            minutes = "0" + minutes;
-        }
-        if (seconds < 10){
-            seconds = "0" + seconds;
-        }
-        var formatted = hours + ":" + minutes + ":" + seconds;
-        return formatted;
-    }
-    
-    function addTimer(unit,value){
-        if (unit == "h"){
-            if (value == "r"){
-                $("#timerHour").text("0");
-            }else{
-                $("#timerHour").text($("#timerHour").text() - -1 * value); 
-            }
-           
-        }else if (unit == "m"){
-            if (value == "r"){
-                $("#timerMinute").text("0");
-            }else{
-               $("#timerMinute").text($("#timerMinute").text() - -1 * value); 
-            }
-        }
-        if (parseInt($("#timerHour").text()) < 0){
-            $("#timerHour").text("0");
-        }
-        if (parseInt($("#timerMinute").text()) < 0){
-            if (parseInt($("#timerHour").text()) > 0){
-                //subtract 1 from the hour
-                 $("#timerHour").text($("#timerHour").text() - 1); 
-                 $("#timerMinute").text(parseInt($("#timerMinute").text()) + 60);
-            }else{
-                //There is no hours to subtract
-                $("#timerMinute").text("0");
-            }
-            
-        }
-        if (parseInt($("#timerMinute").text()) > 59){
-            $("#timerMinute").text(parseInt($("#timerMinute").text()) - 60);
-            $("#timerHour").text($("#timerHour").text() - -1); 
-        }
-    }
-    
-	//Download function
-	function downloadPlayingSong(){
-	    var url = audioElement.attr("src");
-	    var ext = url.split(".").pop();
-	    var filename = $("#mainPlayerSongTitle").text().trim();
-		generateDownloadElement(url,filename);
-		/*
-		if (url.includes("/media")){
-			blobDownloadElement(url,filename);
-		}else{
-			generateDownloadElement(url,filename);
-		}
-		*/
-	}
-	
-	var downloadInProgress = false;
-	function blobDownloadElement(filepath,filename){
-		if (downloadInProgress){
-			alert("Please wait until another download finished.");
-			return;
-		}
-		downloadInProgress = true;
-		$("#downloadBtn").find("i").addClass("disabled");
-		$("#downloadProgressBar").find(".bar").css("width","0%");
-		$("#downloadProgressBar").show();
-		var xhr = new XMLHttpRequest();
-		xhr.onreadystatechange = function(){
-			if (this.readyState == 4 && this.status == 200){
-				//handler(this.response);
-				//console.log(this.response, typeof this.response);
-				var url = window.URL || window.webkitURL;
-				//Open the downloaded data in new window for testing
-				//window.open(url.createObjectURL(this.response));
-				generateDownloadElement(url.createObjectURL(this.response),filename);
-				$("#downloadBtn").find("i").removeClass("disabled");
-				$("#downloadProgressBar").hide();
-				downloadInProgress = false;
-			}
-			
-		}
-		xhr.onprogress = function (event) {
-			console.log("[AirMusic] Download Progress: " + event.loaded + " / " + event.total + "Bytes");
-			$("#downloadProgressBar").find(".bar").css("width",(event.loaded / event.total) * 100 + "%");
-		};
-		xhr.open('GET', filepath);
-		xhr.responseType = 'blob';
-		xhr.send();      
-	}
-
-	function generateDownloadElement(filepath, filename){
-		var link = document.createElement('a');
-
-		//Clean the filepath
-		filepath = filepath.split("//").join("/");
-		//Convert the filepath to download path
-        link.href = filepath.replace("/media?file=", "/media/download/?file=");
-
-		//Generate the download element
-        link.setAttribute('download', filename);
-        document.getElementsByTagName("body")[0].appendChild(link);
-        // Firefox
-        if (document.createEvent) {
-            var event = document.createEvent("MouseEvents");
-            event.initEvent("click", true, true);
-            link.dispatchEvent(event);
-        }
-        // IE
-        else if (link.click) {
-            link.click();
-        }
-        link.parentNode.removeChild(link);
-	}
-	
-	//Volume control related features
-	var previousAudioVolume = 0;
-	function mute(button){
-	    if (audioElement[0].volume != 0){
-	        //Set to mute
-	        previousAudioVolume = audioElement[0].volume;
-	        audioElement[0].volume = 0;
-			$(button).css("opacity", "1");
-			$("#voldownBtn").addClass("disabled");
-			$("#volupBtn").addClass("disabled");
-	    }else{
-	        //Restore from mute
-	        audioElement[0].volume = previousAudioVolume;
-			$(button).css("opacity", "0.6");
-			$("#voldownBtn").removeClass("disabled");
-			$("#volupBtn").removeClass("disabled");
-	    }
-	    $("#volBar").css("width",audioElement[0].volume * 100 + "%");
-	}
-	var volbarTimeoutEvt;
-	function addAudioVolume(value){
-	    $("#volumeGUI").slideDown('fast');
-	    if (volbarTimeoutEvt !== undefined){
-	        clearTimeout(volbarTimeoutEvt);
-	    }
-	    volbarTimeoutEvt = setTimeout(function(){
-	        $("#volumeGUI").slideUp('fast');
-	    },3000);
-	    $("#volumeGUI")
-	    if (audioElement[0].volume + value >= 1){
-	        audioElement[0].volume = 1;
-	    }else if (audioElement[0].volume + value <= 0){
-	        audioElement[0].volume = 0;
-	    }else{
-	        audioElement[0].volume += value; 
-		}
-	    
-	    $("#volBar").css("width",Math.min(100,audioElement[0].volume * 100) + "%");
-	}
-	
-	function updatePlaybackDisplayTime(currentTime,duration){
-	    let progress = Math.round(currentTime);
-	    let remainTime = Math.round(duration - currentTime);
-	    $("#progressTime").text(secondsToHms(progress));
-	    if (!isNaN(remainTime)){
-	        $("#remainTime").text("-" + secondsToHms(remainTime));
-	    }
-
-	}
-	
-	function nextSongHandler(){
-	    console.log("Next song");
-	    if (repeatMode == 1){
-			//Next song in the playlist
-	        if (randomMode){
-	            var randomTrackID = Math.floor(Math.random() * (playingList.length - 1));
-	            //console.log(randomTrackID, playingList[randomTrackID]);
-	            nextSong(randomTrackID,true);
-	        }else{
-				var playingSongIndex = playingFileDetail[0];
-				var nextSongIndex = playingSongIndex;
-				if (nextSongIndex >= playingList.length){
-					nextSongIndex = 0;
-				}
-				//console.log(playingSongIndex, nextSongIndex);
-	            nextSong(nextSongIndex,true);
-	        }
-	    }else if (repeatMode == 2){
-			//Loop this song only
-	       audioElement[0].pause();
-	       audioElement[0].currentTime = 0;
-	       audioElement[0].play();
-	    }else if (repeatMode == 0){
-			//Pause after finish this song
-	       setPlaying(false);
-	       audioElement[0].pause();
-	       audioElement[0].currentTime = 0;
-	    }
-	}
-	
-	function mainPlayerShown(){
-	    if ($("#playerInterface").offset().left == 0){
-	        return true;
-	    }
-	    return false;
-	}
-	
-	function toggleRandomMode(button){
-	    var btn = $(button).find("i");
-	    if (randomMode){
-	        //Set the random mode to false
-	        btn.removeClass("enabled").addClass("disabled");
-	        randomMode = false;
-	    }else{
-	        btn.removeClass("disabled").addClass("enabled");
-	        randomMode = true;
-	    }
-	    setStorage("randomMode",randomMode);
-	}
-	
-	function toggleRepeatMode(button){
-	    if (repeatMode == 0){
-	       setRepeatMode(1,button);
-	       setStorage("repeatMode",1);
-	    }else if (repeatMode == 1){
-	       setRepeatMode(2,button);
-	       setStorage("repeatMode",2);
-	    }else if (repeatMode == 2){
-	       setRepeatMode(0,button);
-	       setStorage("repeatMode",0);
-	    }
-	}
-	
-	function setRepeatMode(modeCode,button){
-	    if (modeCode == 1){
-	        //Set repeat mode to "Repeat all"
-	        $(button).find(".singleLoop").hide();
-	        $(button).find("i").removeClass("disabled").addClass("enabled");
-	        repeatMode = 1;
-	    }else if (modeCode == 2){
-	        //Set repeat mode to "Repeat one"
-	        $(button).find(".singleLoop").show();
-	        $(button).find("i").removeClass("disabled").addClass("enabled");
-	        repeatMode = 2;
-	    }else if (modeCode == 0){
-	        //Set repeat mode to "None"
-	        $(button).find(".singleLoop").hide();
-	        $(button).find("i").removeClass("enabled").addClass("disabled");
-	        repeatMode = 0;
-	    }
-	}
-	
-	
-	function hideMainPlayerInterface(){
-	    $("#playerInterface").animate({left: window.innerWidth},300);
-	    $("body").css("overflow-y","auto");
-	}
-	
-	function showMainPlayerInterface(){
-	    $("#playerInterface").animate({left:0},300);
-	    $("body").css("overflow-y","hidden");
-	}
-	
-	function syncSystemVol(){
-        //Initiate the module's volume to the system's
-        var globalvol = localStorage.getItem("global_volume");
-        //console.log("Global Volume" + globalvol.toString());
-        if (!globalvol){
-            globalvol = 0.1;
-		}
-		
-		//Check if it is mobile. If yes, always 100% and leave volume to system
-		if (isMobile()){
-			globalvol = 1;
-			//$(".desktopOnly").addClass("disabled");
-		}
-
-		audioElement[0].volume = parseFloat(globalvol);
-        $("#volBar").css("width",audioElement[0].volume * 100 + "%");
-	}
-	
-	function replaceAll(target, replace, original){
-	  return original.split(target).join(replace);  
-	};
-	
-	function playSong(object, startPaused = false){
-	    if ($(object).parent().hasClass("playingTrack")){
-	        //This is already the song that is currently playing. Show the main player interface instead.
-	        showMainPlayerInterface();
-	        resizeQuickAdjust();
-	        return;
-	    }
-
-	    //$(".playingTrack").removeClass("playingTrack");
-		//$(object).parent().addClass("playingTrack");
-		var filepath = ao_module_utils.attrToObject($(object).parent().attr('filepath'));
-	    var rawname = ao_module_utils.attrToObject($(object).parent().attr('rawname'));
-	    var displayName = ao_module_codec.decodeUmFilename(rawname);
-	    var info = $(object).parent().find(".fileinfo").text();
-		var id = $(object).parent().attr('id');
-		if (id === undefined){
-			//This might be a file from dropdown list. use listid instead
-			id = $(object).parent().attr('listid');
-		}
-		
-
-	    updateMiniPlayerUI(displayName,info,id);
-
-		//Check if page mode is enabled. If yes, do auto tab switch
-		if (pagingEnabled){
-			var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
-			switchToPage(targetPageNumber);
-		}
-
-		//Seperate out the filepath without media server path
-		var fileVpath = filepath.split("=")[1];
-	    updateMainPlayerUI(displayName,info,id, fileVpath);
-	    loadAndPlayAudioFile(filepath, !startPaused);
-	    if (!currentPlaying && !startPaused){
-	        setPlaying(true);
-	    }
-		playingFileDetail = [parseInt(id),filepath];
-
-		//If the user play this file, assume the next file to be added to playlist is this file
-		playlistAddPendingFile = filepath;
-	    //Have a backup of the current list just incase the user open another directory while a list is playing
-		//Only backup when it is not call from dropdown list
-		if (!$(object).parent().hasClass("dropdownList")){
-			playingList = Array.from(displayList);
-			pagingEnableForPlayingList = pagingEnabled;
-			currentPlayingPage = currentPage;
-		}
-	    parsePlayingSongList();
-	    if ($("#miniPlayer").hasClass("hidden")){
-	        //This is the first song that has played after the UI init
-	        $("#miniPlayer").css("display","none").removeClass("hidden").slideDown();
-	    }
-	    showMainPlayerInterface();
-	    
-	    //Just in case the albumn image changed, albumn art css is also updated.
-	    resizeQuickAdjust();
-
-		updateStateReferingURL();
-		highLightPlayingMusic();
-	}
-
-	function loadThumbnailToMusicList(selector = ".mainList.file.item"){
-		$(selector).each(function(){
-			let filepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
-			let thisFileItemID = $(this).attr("id");
-			let rawname = JSON.parse(decodeURIComponent($(this).attr("rawname")));
-			
-			let realVpath = filepath.split("=");
-			realVpath.shift();
-			realVpath = realVpath.join("=");
-			//console.log(thisFileItemID, realVpath, rawname);
-			//Load the thumbnail for this item in list
-			fetch("../system/file_system/loadThumbnail?vpath=" + encodeURIComponent(realVpath))
-			.then((response) => response.json())
-			.then((data) => {
-				if (data.error !== undefined || data.trim() == ""){
-					return;
-				}
-				$("#" + thisFileItemID).find("img").attr("src","data:image/jpg;base64," + data);
-				$(".dropdownList.file.item").each(function(){
-					var thisFilepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
-					if ($(this).attr("listid") == thisFileItemID && thisFilepath == filepath){
-						$(this).find("img").attr("src","data:image/jpg;base64," + data);
-					}
-				});
-			});
-			/*
-			ao_module_agirun("Music/functions/getThumbnail.js", {
-				file: realVpath,
-			}, function(data){
-				if (data.error !== undefined){
-
-				}else{
-					$("#" + thisFileItemID).find("img").attr("src","data:image/jpg;base64," + data);
-					$(".dropdownList.file.item").each(function(){
-						var thisFilepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
-						if ($(this).attr("listid") == thisFileItemID && thisFilepath == filepath){
-							$(this).find("img").attr("src","data:image/jpg;base64," + data);
-						}
-					})
-				}
-			});
-			*/
-		})
-	}
-
-	function loadThumbnail(filepath){
-		//Load the thumbnail
-		var realVpath = filepath.split("=");
-		realVpath.shift();
-		realVpath = realVpath.join("=");
-		ao_module_agirun("Music/functions/getThumbnail.js", {
-			file: realVpath,
-		}, function(data){
-			if (data.error !== undefined){
-				console.log(data.error)
-				$("#albumnArtImage").attr("src","img/default.png");
-				$("#smallPlayerThumb").attr("src","img/default.png");
-				if (navigator.mediaSession.metadata){
-					navigator.mediaSession.metadata.artwork = [
-						{ src: "img/default.png",   sizes: '512x512',   type: 'image/png' }
-					]
-				}
-			}else{
-				$("#albumnArtImage").attr("src","data:image/jpg;base64," + data);
-				$("#smallPlayerThumb").attr("src","data:image/jpg;base64," + data);
-				if (isAndroid && navigator.mediaSession.metadata){
-					//Android
-					navigator.mediaSession.metadata.artwork = [
-						{ src: "data:image/jpg;base64," + data,   sizes: '480x480',   type: 'image/jpg' }
-					]
-				}
-			}
-			resizeQuickAdjust();
-		});
-	}
-	
-	function nextSong(id = false,forcePlayEvenStopped = false){
-	    //Check if the current playlist has more than one songs.
-	    var currentPaused =  audioElement[0].paused;
-	    if (playingList.length > 1){
-	        var nextSongIndex = playingFileDetail[0];
-	        if (id != false){
-	            //Allow manual overwrite for this function
-	            nextSongIndex = id;
-	            var nextSong = playingList[nextSongIndex]; 
-	        }else{
-	           if (playingFileDetail[0] >= playingList.length){
-    	            var nextSong = playingList[0]; //Back to the first song in list
-    	            nextSongIndex = 0;
-    	        }else{
-    	             var nextSong = playingList[nextSongIndex]; //Index of the playList + 1 as the index for the files is alrady i+1. (User count from one)
-    	        } 
-	        }
-	        //The songs has to be play via background services instead of relying on DOM 
-	        var filepath = nextSong[0];
-    	    var rawname = nextSong[1];
-    	    var displayName = ao_module_codec.decodeUmFilename(rawname);
-    	    var info = nextSong[2] + " / " + nextSong[3];
-    	    var id = nextSongIndex + 1;
-    	    updateMiniPlayerUI(displayName,info,id);
-
-			//Seperate out the filepath without media server path
-			var fileVpath = filepath.split("=")[1];
-    	    updateMainPlayerUI(displayName,info,id, fileVpath);
-    	    if (forcePlayEvenStopped){
-    	        loadAndPlayAudioFile(filepath,true);
-    	    }else{
-    	       loadAndPlayAudioFile(filepath,!currentPaused); 
-    	    }
-    	    
-    	    if (currentPlaying){
-    	        setPlaying(true);
-    	    }
-    	    playingFileDetail = [id,filepath];
-    	    //Need not to update the playlist because it is the same
-			if (pagingEnabled){
-				var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
-				switchToPage(targetPageNumber, function(){
-					parsePlayingSongList();
-					highLightPlayingMusic();
-				});
-			}else{
-				highLightPlayingMusic();
-			}
-			
-			
-	    }else{
-	        //This is the only song in playlist. Play again from start
-	        audioElement[0].pause();
-	        audioElement[0].currentTime = 0;
-	        if (!currentPaused){
-	             audioElement[0].play();
-	        }
-	       
-	    }
-		updateStateReferingURL();
-	}
-	
-	function previousSong(){
-	    var currentPaused =  audioElement[0].paused;
-	    if (playingList.length > 1){
-	        var nextSongIndex = playingFileDetail[0] - 1;
-	        if (nextSongIndex == 0){
-	            nextSongIndex = playingList.length;
-	            var nextSong = playingList[nextSongIndex - 1]; //Back to the last song in list
-	        }else{
-	             var nextSong = playingList[playingFileDetail[0] - 2]; //Index of the playList - 1 as the index for the files is alrady i+1. (User count from one)
-	        }
-	        //The songs has to be play via background services instead of relying on DOM 
-	        var filepath = nextSong[0];
-    	    var rawname = nextSong[1];
-    	    var displayName = ao_module_codec.decodeUmFilename(rawname);
-    	    var info = nextSong[2] + " / " + nextSong[3];
-    	    var id = nextSongIndex;
-    	    updateMiniPlayerUI(displayName,info,id);
-
-			//Seperate out the filepath without media server path
-			var fileVpath = filepath.split("=")[1];
-    	    updateMainPlayerUI(displayName,info,id, fileVpath);
-    	    loadAndPlayAudioFile(filepath,!currentPaused);
-    	    if (currentPlaying){
-    	        setPlaying(true);
-    	    }
-    	    playingFileDetail = [id,filepath];
-    	    //Need not to update the playlist because it is the same
-    	    if (pagingEnabled){
-				var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
-				switchToPage(targetPageNumber, function(){
-					parsePlayingSongList();
-					highLightPlayingMusic();
-					
-				});
-			}else{
-				highLightPlayingMusic();
-			}
-	    }else{
-	        //This is the only song in playlist. Play again from start
-	        audioElement[0].pause();
-	        audioElement[0].currentTime = 0;
-	        audioElement[0].play();
-	    }
-		updateStateReferingURL();
-	}
-	
-	var originalVol = 0;
-	function togglePlayMode(){
-	    if (currentPlaying){
-	        originalVol = audioElement[0].volume;
-	        fadeAudio();
-	        setPlaying(false);
-	    }else{
-	        gainAudio();
-	        setPlaying(true);
-	    }
-	}
-
-
-	let audioTransitioning = false;
-	function fadeAudio(){
-		audioTransitioning = true;
-		if(audioElement[0].volume > 0){
-			var testval = audioElement[0].volume - 0.1;
-			audioElement[0].volume = Math.max(0,testval);
-			setTimeout(fadeAudio, 50);
-		}else{
-			audioElement[0].pause();
-			setTimeout(function(){
-				audioElement[0].volume = originalVol;
-				updateStateReferingURL();
-				audioTransitioning = false;
-			}, 100);
-		}
-	}
-    
-    
-    var targetVol = 0;
-    function gainAudio(){
-		targetVol = audioElement[0].volume;
-		audioElement[0].volume = 0;
-		setTimeout(function(){
-			audioElement[0].play();
-			recursiveGainAudio();
-		}, 100);
-    }
-    
-    function recursiveGainAudio(){
-		audioTransitioning = true;
-        if(audioElement[0].volume < targetVol){
-            if (audioElement[0].volume + 0.1 < 1){
-				audioElement[0].volume += 0.1
-			}else{
-				//Audio volume larger than 1, make it 1
-				audioElement[0].volume = 1
-			}
-            setTimeout(recursiveGainAudio, 50);
-        }else{
-            setTimeout(function(){
-                audioElement[0].volume = targetVol;
-				updateStateReferingURL();
-				audioTransitioning = false;
-            }, 100);
-        }
-    }
-	
-	//Update all icons on play and pause buttons
-	function setPlaying(playing){
-	    if (playing == true){
-	        $(".PlayButton").attr("class","pause icon whiteFont PlayButton");
-	        currentPlaying = true;
-	    }else{
-	        $(".PlayButton").attr("class","play icon whiteFont PlayButton");
-	        currentPlaying = false;
-	    }
-	}
-
-	function loadAndPlayAudioFile(sourceURL,playAfterLoad = true){
-		var audio = audioElement;
-
-		//These was added to fix the legacy file listing issue
-		var fd = sourceURL.split("=");
-		var rootPath = fd.shift();
-		var filename = fd.join("=");
-		var playbackURL = "../" + rootPath + "=" + encodeURIComponent(filename); //Convert absolute dir to relative
-		//console.log(playbackURL);
-		$("#mainAudioPlayer").attr("src", playbackURL);
-
-        audio[0].pause();
-        audio[0].load();
-        if(playAfterLoad){
-            audio[0].oncanplaythrough = audio[0].play();
-        }else{
-            var currentTime = audioElement[0].currentTime;
-            var duration = audioElement[0].duration;
-            $('#audioProgressBar').css('width','0%');
-            updatePlaybackDisplayTime(currentTime,duration);
-		}
-		
-		loadThumbnail(sourceURL);
-	}
-	
-	function updateMiniPlayerUI(displayName, fileinfo,id){
-	    $("#miniPlayerDisplayName").text(displayName);
-	    $("#miniPlayerInformation").text(fileinfo);
-	    $("#miniPlayerIDtab").text(id + "/" + totalMusicCount);
-	}
-	
-	function updateMainPlayerUI(songname, fileinfo, id, filepath){
-	    $("#mainPlayerSongTitle").text(songname);
-	    $("#mainPlayerSongDesc").text(fileinfo);
-	    $("#mainPlayerMiniTab").text(id + "/" + totalMusicCount);
-		if ('mediaSession' in navigator){
-			var infoRewrite = fileinfo.split(" / ")
-			updateTitle(songname, infoRewrite[1] + " (" + infoRewrite[0] + ")", id + "/" + totalMusicCount, filepath);
-		}
-	}
-
-	
-	/*
-		Playlist related functions
-
-	*/
-
-	function renderPlaylistByName(listname){
-		$("#interfaceTitle").text(listname);
-		ao_module_agirun("Music/functions/playlist.js", {
-			opr: "list",
-			playlistname: listname
-		}, function(data){
-			$("#mainList").html("");
-			if (data.error !== undefined){
-				//This playlist no longer exists. Back to main
-				loadPlaylistView();
-			}else{
-				//Updat ethe global values
-				displayList = data;
-    	        totalMusicCount = data.length;
-				currentPath = listname;
-				//Add the back btn for back to playlist view
-				$("#mainList").append(`<div class="mainList item extrapadding" onClick="loadPlaylistView();">
-					<div class="ui header selectable" style="margin:0px !important;">
-						<i class="angle left icon whiteFont" style="overflow:hidden;"></i>
-						<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
-							../
-						</div>
-					</div>
-				</div>`);
-
-
-				//List the resulting song list 
-				for (var i = 0; i < data.length; i++){
-					var songInfo = data[i];
-					
-					$("#mainList").append(`<div class="mainList file item" filepath=${ao_module_utils.objectToAttr(songInfo[0])} id=${i+1} rawname=${ao_module_utils.objectToAttr(songInfo[1])}>
-						<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">
-							<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
-							<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">
-								${songInfo[1]}
-								<div class="sub header fileinfo" style="color: #c7c7c7;">${songInfo[2]} / ${songInfo[3]}</div>
-							</div>
-						</div>\
-						<div class="topRightCorner" align="center">
-							${i + 1}
-						</div>
-						<div class="mainList rightFunctionBar" type="file" align="center" onclick="showMore(this);">
-							<i class="ellipsis vertical icon" style="margin-top:1.2em;"></i>
-						</div>
-					</div>`);
-
-					//Update the interface Detail
-					$("#interfaceDetails").text("[" + data.length + " files]");
-				};
-
-
-				loadThumbnailToMusicList();
-				//Fix some legacy css isseus
-				$("#mainList").append("<br><br><br><br><br><br><br>");
-			}
-		});
-	}
-	//Open a given playlist
-	function openPlaylist(object){
-		var listname = $(object).attr("listname");
-		renderPlaylistByName(listname);
-	}
-
-	function addToNewPlaylist(){
-		var playlistname = prompt("Enter new playlist name");
-		if (playlistname != null && playlistname != ""){
-			//Add to playlist
-			addSongToPlayList(playlistname);
-		}else{
-			$("#succSnackBar").find(".content").html(`<i class="remove icon"></i> Invalid playlist name`);
-			$("#succSnackBar").slideDown("fast").delay(3000).slideUp("fast");
-			
-		}
-	}
-
-	function addToPlaylistFromMoreMenu(){
-		$(".showMoreMenus").fadeOut('fast');
-		$("#showmoreUIcover").fadeOut('fast');
-		showPlaylistInterface();
-	}
-
-	//Remove the curernt file from the current playlist
-	function removeFromPlylistFromMoreMenu(){
-		if (currentMode == "playlist"){
-			//Remvoe the playlistAddPendingFile
-			//In playlist mode, the currentPath is used to store the plylist name
-			ao_module_agirun("Music/functions/playlist.js", {
-			opr: "remove",
-			playlistname: currentPath,
-			musicpath: playlistAddPendingFile.replace("/media?file=","")
-			}, function(data){
-				if (data.error !== undefined){
-					alert(data.error);
-				}else{
-					//Removed. Reload playlist
-					renderPlaylistByName(currentPath);
-
-					//Hide the MoreMenu
-					hideShowMoreMenu();
-				}
-			});
-		}
-	}
-
-	function addSongToSelectedPlaylist(object){
-		var playlistName = $(object).attr("name").trim();
-		addSongToPlayList(playlistName);
-	}
-
-	function addSongToPlayList(listname){
-		//Get current music file name
-		var currentSongPath = "";
-		if (playlistAddPendingFile !== ""){
-			currentSongPath = playlistAddPendingFile.replace("/media?file=","");
-		}else{
-			$("#succSnackBar").find(".content").html(`<i class="remove icon"></i> No song selected`);
-			$("#succSnackBar").slideDown("fast").delay(3000).slideUp("fast");
-			return;
-		}
-		
-		//Add to playlist
-		ao_module_agirun("Music/functions/playlist.js", {
-			opr: "add",
-			playlistname: listname,
-			musicpath: currentSongPath
-		},function(data){
-			//Show success
-			$("#succSnackBar").find(".content").html(`<i class="checkmark icon"></i> Added to playlist ${listname}`);
-			$("#succSnackBar").slideDown("fast").delay(3000).slideUp("fast");
-
-			//Reload the playlist
-			initPlaylistInterfaceList();
-		});
-	}
-
-	//List the number of playlist stored in this database
-	function loadPlaylistView(){
-		currentMode = "playlist";
-		//Clear the main list
-		$("#mainList").html("");
-		togglePagingMode(false);
-		ao_module_agirun("Music/functions/playlist.js", {
-			opr: "root",
-		},function(data){
-			//Get the list of playlist
-			console.log(data);
-
-			//Render the elements
-			data.forEach(playlist => {
-				$("#mainList").append(`<div class="mainList item" listname="${playlist.name}" tag="playlist" onClick="openPlaylist(this);">
-					<div class="ui header selectable" style="margin:0px !important;" >
-						<img class="ui small image" src="img/list.svg" style="margin-right: 0.2em;"></img>
-						<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
-							${playlist.name}
-							<div class="sub header fileinfo" style="color: #c7c7c7;">[${playlist.count} files]</div>
-						</div>
-					</div>
-					<div class="mainList rightFunctionBar" tag="moreInfo" align="center" onClick="openPlaylist(this);">
-						<i class="chevron right icon" style="margin-top:1.2em;"></i>
-					</div>
-				</div>`);
-			});
-			hideLeftMenu();
-
-			//Update the headers
-			$("#interfaceTitle").text("Playlist");
-			$("#AMmenuIcon").attr("class","list icon large whiteFont");
-			$("#interfaceDetails").text("[" + data.length + " playlist]");
-		});
-		
-	}
-	
-	function loadFolderView(){
-		currentMode = "folder";
-	    currentPath = "";
-	    var tempalte = '<div class="mainList item" filepath={filepath} id={id} tag="folder" onClick="openFolder(this);">\
-        <div class="ui header selectable" style="margin:0px !important;" >\
-            <img class="ui small image" src="img/fo.svg" style="margin-right: 0.2em;"></img>\
-            <div class="content whiteFont" style="padding-top: 2px; line-height:1em;width : 80%; font-weight: lighter;">\
-                {foldername}\
-                <div class="sub header fileinfo" style="color: #c7c7c7;">{fileinfo}</div>\
-            </div>\
-        </div>\
-        <div class="mainList rightFunctionBar" tag="moreInfo" align="center" onClick="moreFolder(this);">\
-            <i class="chevron right icon" style="margin-top:1.2em;"></i>\
-        </div>\
-    </div>';
-        $("#interfaceTitle").text("Storage");
-		togglePagingMode(false);
-		$("#AMmenuIcon").attr("class","folder open icon large whiteFont");
-		ao_module_agirun("Music/functions/listSong.js", {
-			listdir: "root",
-		},function(data){
-	        $("#mainList").html("");
-	        for (var i =0; i < data.length; i++){
-	            var folderName = data[i][0];
-	            var folderPath = data[i][1];
-	            var fileCount = data[i][2];
-	            var folderCount = data[i][3];
-	            var box = tempalte;
-	            box = replaceAll("{filepath}",folderPath,box);
-				box = replaceAll("{id}",i + 1,box);
-				
-				if (folderName == ".cache" || folderName == ".trash"){
-					//Hidden folders
-					continue;
-				}
-	            if (folderPath.includes("/media")){
-	                //This is from external storage devices. List its number as well.
-	                var tmp = folderPath.split("/");
-	                var extStoragePath = "/" + tmp[1] + "/" + tmp[2];
-	                box = replaceAll("{foldername}",folderName + " ( " + extStoragePath + " )",box);
-	            }else{
-	                //This is directory inside normal folders. 
-	                box = replaceAll("{foldername}",folderName,box);
-	            }
-
-				/*
-				var fileinfo = fileinfo = "[No playable files]";
-				console.log(folderCount, fileCount);
-				if (folderCount > 0 && fileCount > 0){
-					fileinfo = "[" + fileCount + " files, " + folderCount  +" folders]"
-				}else if (fileCount > 0){
-					fileinfo = "[" + fileCount + " files]";
-				}else if (fileCount == -1 && folderCount == -1){
-					fileinfo = "";
-				}
-				*/
-				var fileinfo = folderPath;
-				
-	           
-	            box = replaceAll("{fileinfo}",fileinfo,box);
-				rootPaths.push(folderPath);
-	            $("#mainList").append(box);
-	        }
-	        $("#interfaceDetails").text("[" + data.length + " folders]");
-	    });
-	    hideLeftMenu();
-	}
-	
-	function isMobile(){
-		if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
-			return true
-		}
-		return false
-	}
-
-	function setWindowHash(hashValue){
-		hashValue = JSON.stringify(hashValue);
-
-		if (!isAndroid){
-			return;
-		}
-		
-		if(history.pushState) {
-			window.history.pushState(null, null, '#' + hashValue);
-		}else {
-			location.hash =  '#' + hashValue;
-		}
-		if(ao_module_virtualDesktop && !isMobile()){
-		    //Update the iframe src as well
-		    var newsrc =  window.frameElement.getAttribute("src");
-		    if (newsrc.includes("#")){
-		      newsrc = newsrc.split("#")
-		      newsrc.pop();
-		      newsrc = newsrc.join("#");
-		    }
-		    newsrc = newsrc + "#" + hashValue;
-		    $(window.frameElement).attr("src",newsrc);
-		    //console.log(window.frameElement.getAttribute("src"));
-		}
-	}
-
-	function updateStateReferingURL(){
-		var paused = audioElement[0].paused; //Check the current playing state of the player
-		setWindowHash({path: currentPath, pfp:playingFileDetail,pause:paused});
-	}
-	
-	function openFolder(object, playParameters=null){
-		var playIDAfterOpen = -1;
-		var startPaused = false;
-		if (playParameters !== null){
-			playIDAfterOpen = playParameters.playIDAfterOpen;
-			startPaused = playParameters.startPaused;
-		}
-	    var backbtnTemplate = '<div class="mainList item extrapadding" filepath={filepath} id={id} onClick="openFolder(this);">\
-        <div class="ui header selectable" style="margin:0px !important;">\
-            <i class="angle left icon whiteFont" style="overflow:hidden;"></i>\
-            <div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">\
-                ../\
-            </div>\
-        </div>\
-    </div>';
-	    
-	    var folderTemplate = '<div class="mainList item" filepath={filepath} tag="folder" id={id} onClick="openFolder(this);">\
-        <div class="ui header selectable" style="margin:0px !important;">\
-            <img class="ui small image" src="img/fo.svg" style="margin-right: 0.2em;"></img>\
-            <div class="content whiteFont" style="padding-top:2px;line-height:1em; width:80%; font-weight: lighter;">\
-                {foldername}\
-                <div class="sub header fileinfo" style="color: #c7c7c7;">{fileinfo}</div>\
-            </div>\
-        </div>\
-        <div class="mainList rightFunctionBar" type="folder" align="center">\
-            <i class="chevron right icon" style="margin-top:1.2em;"></i>\
-        </div>\
-    </div>';
-    var fileTemplate = `<div class="mainList file item" filepath={filepath} id={id} rawname={rawname}>\
-        <div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">\
-            <img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
-			<!-- <i class="music icon whiteFont" style="overflow:hidden;"></i> -->\
-            <div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">\
-                {songtitle}\
-                <div class="sub header fileinfo" style="color: #c7c7c7;">{ext} / {size}</div>\
-            </div>\
-        </div>\
-        <div class="topRightCorner" align="center">\
-            {id}\
-        </div>\
-        <div class="mainList rightFunctionBar" type="file" align="center">\
-            <i class="ellipsis vertical icon" style="margin-top:1.2em;"></i>\
-        </div>\
-    </div>`;
-
-        var targetPath = decodeURIComponent($(object).attr("filepath"));
-        if (targetPath == "root" || targetPath == "/"){
-            //User request to go back to storage root
-            loadFolderView();
-            return;
-        }
-		currentPath = targetPath.split("/./").join("/");
-		currentPath = currentPath.split("//").join("/");
-	    $("#interfaceTitle").text(ao_module_codec.decodeHexFoldername(targetPath.substring(0,targetPath.length -1).split("/").pop()));
-		var parentDir = currentPath.split("/");
-	    parentDir.pop();parentDir.pop();
-	    parentDir = (parentDir.join("/") + "/");
-	    //console.log(currentPath);
-		var backbtn;
-	    if (rootPaths.includes(currentPath) == false){
-	        //We are currently not at root
-	        backbtn = backbtnTemplate;
-            backbtn = replaceAll("{filepath}",encodeURIComponent(parentDir),backbtn);
-            backbtn = replaceAll("{id}",0,backbtn);
-	    }else{
-	        //Create a back button to go back to root of storage
-	        backbtn = backbtnTemplate;
-            backbtn = replaceAll("{filepath}","root",backbtn);
-            backbtn = replaceAll("{id}",0,backbtn);
-	    }
-	    
-	    //Request the server for a list of folders and file in this directory
-		ao_module_agirun("Music/functions/listSong.js", {
-			listdir: targetPath.split("//").join("/"),
-		},function(data){
-	        $("#mainList").html("");
-	        $("#mainList").append(backbtn);
-            if (Array.isArray(data)){
-                var folders = data[0];
-                var files = data[1];
-                //List all folders
-                for (var i =0; i < folders.length; i++){
-    	            var folderName = folders[i][0];
-    	            var folderPath = folders[i][1];
-    	            var fileCount = folders[i][2];
-    	            var folderCount = folders[i][3];
-					var box = folderTemplate;
-					if (folderName == ".cache" || folderName == ".trash"){
-						//Hidden folders
-						continue;
-					}
-    	            box = replaceAll("{filepath}",encodeURIComponent(folderPath),box);
-    	            box = replaceAll("{id}","folder-" + i + 1,box);
-    	            box = replaceAll("{foldername}",ao_module_codec.decodeHexFoldername(folderName),box);
-    	            var fileinfo = "[" + fileCount + " files]"
-    	            if (folderCount > 0){
-    	                fileinfo = "[" + fileCount + " files, " + folderCount  +" folders]"
-    	            }else if (folderCount == -1){
-						fileinfo = folderPath;
-					}
-    	            box = replaceAll("{fileinfo}",fileinfo,box);
-    	             $("#mainList").append(box);
-    	        }
-            
-
-                //List all files
-                for ( var i =0; i < files.length; i++){
-					var songInfo = files[i];
-    	            var path = songInfo[0];
-					var displayname = ao_module_codec.decodeUmFilename(songInfo[1]);
-    	            var ext = songInfo[2];
-    	            var size = songInfo[3];
-    	            var box = fileTemplate;
-    	            box = replaceAll("{filepath}",ao_module_utils.objectToAttr(path),box);
-    	            box = replaceAll("{id}",i + 1,box); //User count from 1
-    	            box = replaceAll("{rawname}",ao_module_utils.objectToAttr(songInfo[1]),box);
-    	            box = replaceAll("{songtitle}",displayname,box);
-    	            box = replaceAll("{ext}",ext,box);
-    	            box = replaceAll("{size}",size,box);
-    	            $("#mainList").append(box);
-    	        }
-    	        displayList = files;
-    	        totalMusicCount = files.length;
-    	        $("#mainList").append("<br><br><br><br><br><br><br>");
-                
-            }else{
-                //Something went wrong
-                //console.log('[AirMusic] Something went wrong: ' + data);
-				loadFolderView();
-				return;
-            }
-            if (folders.length > 0 && files.length > 0){
-                $("#interfaceDetails").text("[" + files.length + " files, " + folders.length+ " folders]");
-            }else if (folders.length > 0){
-                 $("#interfaceDetails").text("[" + folders.length + " folders]");
-            }else if (files.length > 0){
-                 $("#interfaceDetails").text("[" + files.length + " files]");
-            }else{
-                $("#interfaceDetails").text("[0 files or folders]");
-            }
-            //Hook all the events for the moreinfo on folders
-            hookMoreFolderInfoClickEvent();
-            
-            //Check if the current playing file is located inside this list. 
-            highLightPlayingMusic();
-
-			//Check if auto playback is required. If yes, play it with the given filepath.
-			if (playIDAfterOpen != -1){
-				$(".mainList.item").each(function(){
-					if ($(this).attr("id") == playIDAfterOpen){
-						//This is the file that require to playback after the folder loaded
-						playSong($(this).find(".ts.header.selectable"),startPaused);
-						setTimeout(resizeQuickAdjust,500);
-					}
-				});
-			}
-
-			//Load thumbnail for song in list
-			loadThumbnailToMusicList();
-	    });
-	}
-	
-	function moreInfo(object){
-		if ($(object).parent().attr('tag') == "folder"){
-			//This is a folder. Ask if play as playlist
-			alert("Folder playback work in progress");
-		}else{
-			showMore(object);
-		}
-	    
-	}
-	
-	function hookMoreFolderInfoClickEvent(){
-	    $(".mainList.rightFunctionBar").on("click", function(e){
-	        e.stopPropagation();
-	        moreInfo(this);
-	    });
-	}
-	
-	function highLightPlayingMusic(){
-	    //This function is used for highlighting the current playing music if the music piece is found inside the current list
-	    $(".mainList.item").removeClass("playingTrack");
-	    $(".mainList.item").each(function(){
-			var id = parseInt($(this).attr("id"));
-			try{
-				var filepath = ao_module_utils.attrToObject($(this).attr("filepath"));
-			}catch{
-				//Use back the previous method of filepath storage for compatibility
-				var filepath = $(this).attr("filepath");
-			}
-			
-			//Id is ignored in the 9/9/2019 updates and only check if the path matches.
-			if (filepath == playingFileDetail[1]){
-				$(this).addClass("playingTrack");
-			}
-	        //console.log([id,filepath], playingFileDetail);
-	    });
-
-		//Update dropdownList as well if exists
-		$(".dropdownList.item").removeClass("playingTrack");
-		$(".dropdownList.item").each(function(){
-			try{
-				var filepath = ao_module_utils.attrToObject($(this).attr("filepath"));
-			}catch{
-				//Use back the previous method of filepath storage for compatibility
-				var filepath = $(this).attr("filepath");
-			}
-	        //var filepath = $(this).attr("filepath");
-			if (filepath == playingFileDetail[1]){
-				$(this).addClass("playingTrack");
-			}
-		});
-	}
-	
-	function hideShowMoreMenu(){
-	    $(".showMoreMenus").fadeOut('fast');
-		$("#showmoreUIcover").fadeOut('fast');
-		
-		//Return the playlistAddPendingFile object back to the playing one
-		if (playingFileDetail !== undefined){
-			playlistAddPendingFile = playingFileDetail[1];
-		}else{
-			//No song is being play back
-			playlistAddPendingFile = "";
-		}
-		
-	}
-	
-	function playFromShowMoreMenu(){
-		nextSong(showMoreOprPlayID - 1);
-		$(".showMoreMenus").fadeOut('fast');
-	}
-
-	function showFileInfo(){
-	    $("#showFileInfo").show();
-	    $("#showMoreUI").hide();
-	}
-
-	function startRelatedSearch(){
-		enterSearchMode();
-		$("#searchInputBar").val(showMoreoprDisplayName);
-		$("#searchInputBar").focus();
-		hideShowMoreMenu();
-	}
-
-	function searchYoutubeViaShowMore(){
-		if (showMoreoprDisplayName != "" || showMoreoprDisplayName != undefined){
-			var filename = showMoreoprDisplayName;
-			searchOnYoutube(filename);
-		}
-	}
-	
-	var showMoreOprPlayID,showMoreOprFilepath, showMoreoprDisplayName;
-	function showMore(object){
-	    var filepath = $(object).parent().attr("filepath");
-		filepath = JSON.parse(decodeURIComponent(filepath));
-		//User want more action on this file. assume this is the file to add
-		playlistAddPendingFile = filepath;
-	    var id = $(object).parent().attr('id');
-	    var rawname = $(object).parent().attr("rawname");
-	    var displayName = JSON.parse(decodeURIComponent(ao_module_codec.decodeUmFilename(rawname)));
-	    //Update global variable for quick operations
-	    showMoreOprPlayID = id;
-	    showMoreOprFilepath = filepath;
-	    showMoreoprDisplayName = displayName; 
-	    $("#showMoreUI").find(".songTitle").text(displayName);
-	    $("#showMoreUI").find(".songID").text(id);
-	    $("#showFileInfo").find(".songTitle").text(displayName);
-	    $("#showMoreUI").fadeIn('fast');
-	    $("#showmoreUIcover").fadeIn('fast');
-	    //Update fileinformation as well
-		if (filepath.substring(0, 12) == "/media?file="){
-			filepath = filepath.substring(12);
-		}
-		
-		//Pre-render the file info
-		ao_module_agirun("Music/functions/getFileInfo.js", {
-			filepath: filepath,
-		}, function(data){
-			$("#showFileInfo").find(".filename").text(ao_module_codec.decodeUmFilename(data[0]));
-    		$("#showFileInfo").find(".rawname").text(data[0]);
-    		$("#showFileInfo").find(".filepath").text(data[1]);
-    		$("#showFileInfo").find(".filesize").text(data[2] + " (" + data[3] + " Bytes)");
-    		$("#showFileInfo").find(".filedate").text(data[4]);
-		});
-
-		if (currentMode != "playlist"){
-			$(".playlistonly").hide();
-		}else{
-			$(".playlistonly").show();
-		}
-	}
-
-	function playSongFromDropdownList(object){
-		//Play song from dropdown list. Hence, no need to update dropdownList
-		if ($(object).parent().hasClass("playingTrack")){
-			//This song already playing. Ignore play request.
-			return;
-		}
-
-		if (pagingEnableForPlayingList && $(object).attr("targetPage") != currentPlayingPage){
-			let newPage = parseInt($(object).attr("targetPage"));
-			if (!isNaN(newPage)){
-				currentPlayingPage = newPage;
-			}
-		}
-		playSong(object);
-		//Check if the song is also in main list. If yes, highlight it as well
-		/*
-		$(".mainList.item").each(function(){
-			if ($(this).attr("filepath") == $(object).parent().attr("filepath")){
-				$(".mainList.item.playingTrack").removeClass("playingTrack");
-				$(this).addClass("playingTrack");
-			}
-		});
-		*/
-		$("#dropdownSonglist").delay(500).slideUp();
-		highLightPlayingMusic();
-	}
-
-	//Move the playing song list into the dropdown song list. This list might not be the same as the one in the main list.
-	function parsePlayingSongList(){
-		$("#currentPlayingMainList").html("");
-		var counter = playingList.length;
-		var totalSize = 0.0;
-		var renderRange = [0, playingList.length];
-		var pageKeepRange = [0, playingList.length]
-		if (pagingEnableForPlayingList){
-			//Paging Enabled. Only show 1/2 max + current page song + 1/2 max
-			var startEndRange = getPageStartAndEndByPageNumber(currentPlayingPage, playingList);
-			startEndRange = [startEndRange[0] - pagingCutoffCount /2, startEndRange[1] + pagingCutoffCount / 2]
-			//console.log("DEFAULT START END RANGE", startEndRange)
-			//page keep range is the middle 1/2 number of songs, [1/4 => prev page][1/2][1/4 => next page]
-			pageKeepRange[0] = startEndRange[0] + pagingCutoffCount / 2;
-			pageKeepRange[1] = startEndRange[1] - pagingCutoffCount / 2;
-			
-			if (startEndRange[0] < 0){
-				startEndRange[0] = 0;
-			}
-
-			if (startEndRange[1] > playingList.length){
-				startEndRange[1] = playingList.length;
-			}
-
-			renderRange = startEndRange;
-			
-			
-
-			if (pageKeepRange[0] < 0){
-				pageKeepRange[0] = 0;
-			}
-			if (pageKeepRange[1] > playingList.length){
-				pageKeepRange[1] = playingList.length;
-			}
-			//console.log("KEEP RANGE", pageKeepRange);
-		}
-
-		for (var i = renderRange[0]; i < renderRange[1]; i++){
-			var displayname = ao_module_codec.decodeUmFilename(playingList[i][1]);
-			if (playingList[i][3].includes("MB")){
-				totalSize += parseFloat(playingList[i][3].split(" ")[0]);
-			}else if (playingList[i][3].includes("KB")){
-				totalSize += parseFloat(playingList[i][3].split(" ")[0]) / 1000;
-			}else if (playingList[i][3].includes("GB")){
-				totalSize += parseFloat(playingList[i][3].split(" ")[0]) * 1000;
-			}
-
-			//Get thumbnail from the current list to prevent re-loading form remote
-			let targetThumbnail = $("#" + (i + 1)).find("img").attr("src");
-			let opacityShowing = "";
-			let realVpath = playingList[i][0].split("=");
-			realVpath.shift();
-			realVpath = realVpath.join("=");
-
-			if ($("#" + (i + 1)).length == 0 && displayList.length == playingList.length){
-				//Item not exists
-				targetThumbnail = "img/eq.svg";
-				opacityShowing = "opacity: 0.6;"
-			}else if (pagingEnableForPlayingList){
-				if (i < pageKeepRange[0] || i > pageKeepRange[1]){
-					//Out of paging range. Do hidden display
-					targetThumbnail = "img/eq.svg";
-					opacityShowing = "opacity: 0.6;"
-				}else{
-					targetThumbnail = `../system/file_system/loadThumbnail?bytes=true&vpath=${encodeURIComponent(realVpath)}`;
-				}
-			}else{
-				//Non paging list. Always do all thumbnails.
-				targetThumbnail = `../system/file_system/loadThumbnail?bytes=true&vpath=${encodeURIComponent(realVpath)}`;
-			}
-
-			let targetPage = currentPlayingPage;
-			if (i < pageKeepRange[0]){
-				targetPage -= 1;
-			}
-			if (i > pageKeepRange[1]){
-				targetPage += 1;
-			}
-			
-		
-
-			$("#currentPlayingMainList").append(`<div class="dropdownList file item" style="${opacityShowing}" filepath="${ao_module_utils.objectToAttr(playingList[i][0])}" listid="${i + 1}" rawname="${ao_module_utils.objectToAttr(playingList[i][1])}">
-				<div class="ui header selectable" style="margin:0px !important;" onClick="playSongFromDropdownList(this);" targetPage="${targetPage}">
-					<img class="ui small image" src="${targetThumbnail}" onError="replaceImageToDefault(this);" style="margin-right: 0.2em;"></img>
-					<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
-						<span style="font-weight: lighter;">${displayname}</span>
-						<div class="sub header fileinfo" style="color: #c7c7c7;">${playingList[i][2]} / ${playingList[i][3]}</div>
-					</div>
-				</div>
-				<div class="topRightCorner" align="center">
-					${i + 1}
-				</div>
-			</div>`);
-			$("#dropdownListSongCount").text(counter);
-			$("#dropdownListIDCount").text(parseInt(totalSize) + "");
-		}
-		$(".dropdownList.item").each(function(){
-			if ($(this).attr('filepath') == playingFileDetail[1]){
-				$(this).addClass("playingTrack");
-			}
-		});
-
-	}
-
-	function replaceImageToDefault(target){
-		$(target).attr('src', "img/eq.svg");
-	}
-	
-	function loadSongList(type = "all"){
-		currentPath = "";
-		currentMode = "music";
-    
-        $("#interfaceTitle").text("Music");
-		$("#AMmenuIcon").attr("class","music icon large whiteFont")
-		
-		ao_module_agirun("Music/functions/listSong.js", {
-			listSong: type,
-		},function(data){
-			//Initialize the song list
-			displayList = data;
-			if (type == "all"){
-				//Caching is used in here
-				displayList = data.list;
-				if (data.cached == true){
-					//This is a cached version of the music list. 
-					console.log("Updating cached song list");
-					ao_module_agirun("Music/functions/buildCache.js", {}, function(data){
-						console.log("Cache updated: ", data);
-					});
-				}
-			}
-
-			//Updates 2022-07-12: Check if the list is too long. If yes, use paging
-			let renderRange = [0,displayList.length];
-
-			if (displayList.length > pagingCutoffCount){
-				togglePagingMode(true);
-				renderRange = [0, pagingCutoffCount];
-			}else{
-				togglePagingMode(false);
-			}
-
-			if (playingList == []){
-	            playingList = Array.from(displayList);
-				pagingEnableForPlayingList = pagingEnabled;
-				currentPlayingPage = currentPage;
-	        }
-
-			renderDisplayList(displayList,renderRange[0], renderRange[1] );
-
-	    }, function(){
-			alert("Failed to access listSong API with type: " + type)
-		});
-	    hideLeftMenu();
-	}
-
-	function renderDisplayList(displayList, start, end, callback=undefined){
-		$("#mainList").html("");
-		for ( var i =start; i < end; i++){
-	            var songInfo = displayList[i];
-	            var path = songInfo[0];
-	            var displayname = ao_module_codec.decodeUmFilename(songInfo[1]);
-	            var ext = songInfo[2];
-	            var size = songInfo[3];
-				$("#mainList").append(`<div class="mainList file item" filepath="${ao_module_utils.objectToAttr(path)}" id="${i + 1}" rawname="${ao_module_utils.objectToAttr(songInfo[1])}">
-					<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">
-						<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
-						<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">
-							${displayname}
-							<div class="sub header fileinfo" style="color: #c7c7c7;">${ext} / ${size}</div>
-						</div>
-					</div>
-					<div class="topRightCorner" align="center">
-						${i + 1}
-					</div>
-					<div class="mainList rightFunctionBar" align="center" onClick="showMore(this);">
-						<i class="ellipsis vertical icon" style="margin-top:1.2em;"></i>\
-					</div>
-				</div>`);
-	        }
-
-			if (pagingEnabled){
-				//Append the page switch buttons
-				let numberOfPages = Math.ceil(parseFloat(displayList.length) / parseFloat(pagingCutoffCount));
-				let pageSelector  = ``;
-				for (var i = 0; i < numberOfPages; i++){
-					let disabled = "";
-					if (i == currentPage){
-						disabled = "disabled";
-					}
-					pageSelector = pageSelector + `<button id="pagebtn_${i}" onclick="switchToPage(${i});" class="pagebtn noborderbtn inverted basic ui icon button ${disabled}" style="box-shadow: none !important; -webkit-box-shadow: none !important;">
-										${i + 1}
-									</button>`;
-				}
-				$("#mainList").append(`<div class="mainList item" style="cursor: unset;">
-					<div>${pageSelector}</div>	
-				</div>`);
-			}
-
-
-	        totalMusicCount = displayList.length;
-	        $("#mainList").append("<br><br><br><br><br><br><br>");
-	        $("#interfaceDetails").text("[" + totalMusicCount + " songs]");
-	        highLightPlayingMusic();
-
-			
-			//Load thumbnail for song in list
-			loadThumbnailToMusicList();
-
-			if (callback != undefined){
-				callback();
-			}
-	}
-
-	function switchToPage(pageNumber, callback=undefined){
-		if (!pagingEnabled){
-			return;
-		}
-
-		let thisCallback = callback;
-		if (pageNumber == currentPage){
-			//Already in that page
-			if (thisCallback != undefined){
-				callback();
-			}
-			return;
-		}
-
-		currentPage = pageNumber;
-
-		let startPage = pageNumber * pagingCutoffCount;
-		let endPage = startPage + pagingCutoffCount;
-		if (endPage > displayList.length){
-			endPage = displayList.length;
-		}
-
-		
-		if (thisCallback == undefined){
-			renderDisplayList(displayList, startPage, endPage, function(){
-				window.scrollTo(0, document.body.scrollHeight);
-			});
-		}else{
-			renderDisplayList(displayList, startPage, endPage,thisCallback);
-		}
-		
-	}
-
-	function getPageNumberByPlaybackId(id){
-		let numberOfPages = Math.ceil(parseFloat(displayList.length) / parseFloat(pagingCutoffCount));
-		let targetPageNo = Math.ceil(id / pagingCutoffCount) - 1;
-		return targetPageNo;
-	}
-
-	function getPageStartAndEndByPageNumber(pageNumber, targetList){
-		let startPage = pageNumber * pagingCutoffCount;
-		let endPage = startPage + pagingCutoffCount;
-		if (endPage > targetList.length){
-			endPage = targetList.length;
-		}
-
-		return [startPage, endPage];
-	}
-	
-	
-	function toggleLeftMenu(){
-		if (leftMenuShown){
-			$("#leftSideBar").animate({left: $("#leftSideBar").width() * -1}, 120,function(){
-				$("#leftSideBar").hide();
-			});
-			$("#sideBarCover").fadeOut();
-			leftMenuShown = false;
-		}else{
-			$("#leftSideBar").show();
-			$("#leftSideBar").animate({left:0}, 300);
-			$("#sideBarCover").fadeIn();
-			leftMenuShown = true;
-		}
-		
-	}
-	
-	function hideLeftMenu(){
-	    if (leftMenuShown){
-	        $("#leftSideBar").animate({left: $("#leftSideBar").width() * -1}, 120,function(){
-				$("#leftSideBar").hide();
-			});
-			$("#sideBarCover").fadeOut();
-			leftMenuShown = false;
-	    }
-	}
-	
-	function showFileInformation(){
-		ao_module_agirun("Music/functions/getFileInfo.js", {
-			filepath: playingFileDetail[1],
-		},function(data){
-			//console.log(data);
-			$("#settingInterface").hide();
-			$("#filepropInterface").show();
-			$("#filepropInterface").find(".filename").text(ao_module_codec.decodeUmFilename(data[0]));
-			$("#filepropInterface").find(".rawname").text(data[0]);
-			$("#filepropInterface").find(".filepath").text(data[1]);
-			$("#filepropInterface").find(".filesize").text(data[2] + " (" + data[3] + " Bytes)");
-			$("#filepropInterface").find(".filedate").text(data[4]);
-		});
-	}
-	
-	function resizeQuickAdjust(){
-	  //Resize the position of the leftMenu
-	  if (!leftMenuShown){
-		  $("#leftSideBar").css("left", $("#leftSideBar").width() * -1);
-	  }
-	  if ($("#playerInterface").offset().left != 0){
-	      $("#playerInterface").css("left",window.innerWidth);
-	  }
-
-	  $("#albumnArtImage").css("max-height",window.innerHeight - 255);
-
-	  setTimeout(function(){
-		$("#albumnArt").css({
-			"height": window.innerHeight - 255,
-			"top": (window.innerHeight / 2 -  $("#albumnArtImage").height()/2)
-		});
-	  },50);
-	 
-	
-	  
-	  //var imageTop = (window.innerHeight - 255 - $("#albumnArtImage").height()) / 2;
-	  //$("#albumnArtImage").css("top",imageTop + "px");
-	}
-	
-	function setStorage(configName,configValue){
-		ao_module_storage.setStorage("AirMusic",configName,configValue);
-		/*
-    	$.ajax({
-    	  type: 'GET',
-    	  url: "../system/file_system/preference",
-    	  data: {key: "AirMusic/" + 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: "AirMusic/" + configName},
-    	  success: function(data){
-				if (data.error !== undefined){
-					result = "";
-				}else{
-					result = data;
-				}
-			  },
-    	  error: function(data){result = "";},
-    	  async:false,
-    	  timeout: 3000
-    	});
-		return result;
-		*/
-
-		return ao_module_storage.loadStorage("AirMusic",configName);
-    }
-
-	
-	//Wipe controller for mobile users
-	$("#albumnArt")[0].addEventListener('touchstart', handleTouchStart, false);        
-    $("#albumnArt")[0].addEventListener('touchmove', handleTouchMove, false);
-    
-    var xDown = null;                                                        
-    var yDown = null;
-    
-    function getTouches(evt) {
-      return evt.touches ||             // browser API
-             evt.originalEvent.touches; // jQuery
-    }                                                     
-    
-    function handleTouchStart(evt) {
-        const firstTouch = getTouches(evt)[0];                                      
-        xDown = firstTouch.clientX;                                      
-        yDown = firstTouch.clientY;                                      
-    };                                                
-    
-    function handleTouchMove(evt) {
-        if ( ! xDown || ! yDown ) {
-            return;
-        }
-    
-        var xUp = evt.touches[0].clientX;                                    
-        var yUp = evt.touches[0].clientY;
-    
-        var xDiff = xDown - xUp;
-        var yDiff = yDown - yUp;
-    
-        if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
-            if ( xDiff > 0 ) {
-                /* left swipe */ 
-                //Going to the next song
-                nextSong();
-            } else {
-                /* right swipe */
-                //Going back one song
-                previousSong();
-            }                       
-        } else {
-            if ( yDiff > 0 ) {
-                /* up swipe */ 
-            } else { 
-                /* down swipe */
-            }                                                                 
-        }
-        /* reset values */
-        xDown = null;
-        yDown = null;                                             
-    };
-	
-	//Handle audio progress to time conversion
-	function secondsToHms(d) {
-        d = Number(d);
-        var h = Math.floor(d / 3600);
-        var m = Math.floor(d % 3600 / 60);
-        var s = Math.floor(d % 3600 % 60);
-        
-        if (h > 0 && h < 10){
-            dh = "0" + h + ":";
-        }else if (h == 0){
-            dh = "";
-        }else{
-            dh = h + ":";
-        }
-        
-        if (m > 0 && m < 10){
-            dm = "0" + m + ":";
-        }else if (m == 0){
-            if (h > 0){
-                dm = "00:";
-            }else{
-                dm = "0:";
-            }
-        }else{
-            dm = m + ":";
-        }
-        
-        if (s > 0 && s < 10){
-            ds = "0" + s;
-        }else if (s == 0){
-            if (m > 0 || h > 0){
-                ds = "00";
-            }else{
-                ds = "00";
-            }
-        }else{
-            ds = s;
-        }
-        
-        return dh + dm + ds; 
-    }
-
-	//Handle window resize events
-	$(window).on("resize", function(){
-		resizeQuickAdjust();
-	});
-	
-	function AllQuickMenuHidden(){
-	    var result = true;
-	    $(".quickMenu").each(function(){
-	        if ( $(this).is(':visible') ){
-	            result = false;
-	        }
-	    });
-	    return result;
-	}
-	
-	
-	function AllSubMenuHidden(){
-	    var result = true;
-	    $(".showMoreMenus").each(function(){
-	        if ( $(this).is(':visible') ){
-	            result = false;
-	        }
-	    });
-	    return result;
-	}
-	
-	//Handle back button press on mobile devices
-    function handleBackButton() {
-        if (!AllQuickMenuHidden()){
-            hideAllquickMenu();
-            window.history.pushState({}, '');
-        }else if (mainPlayerShown()){
-            //Close the main Menu
-            hideMainPlayerInterface();
-            window.history.pushState({}, '');
-        }else if (!AllSubMenuHidden()){
-             $(".showMoreMenus").fadeOut('fast');
-             $("#showmoreUIcover").fadeOut('fast');
-             window.history.pushState({}, '');
-        }else{
-            window.history.back();
-        }
-        
-    }
-    window.addEventListener('popstate', handleBackButton);
-    window.history.pushState({}, '');
-</script>
-</body>
+<!DOCTYPE html>
+<html>
+<head>
+	<meta charset="UTF-8">
+	<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"/>
+	<meta name="theme-color" content="#4b75ff">
+	<link rel="stylesheet" href="../script/semantic/semantic.min.css">
+	<link rel="stylesheet" href="./main.css">
+	<script src="../script/jquery.min.js"></script>
+	<script src="../script/ao_module.js"></script>
+	<script src="../script/semantic/semantic.min.js"></script>
+	<link rel="icon" type="image/png" href="img/favicon.png" />
+	<!-- Handle native playback on Chrome Andoird-->
+	<script src="native.js"></script>
+
+	<link rel="manifest" crossorigin="use-credentials" href="manifest.json">
+	<title>AirMusic</title>
+</head>
+<body>
+<div id="mainMenu" class="ui basic fluid AMmenu menu bottomBlue" style="z-index:80;position:fixed;position:top:0px;left:0px;width:100%;">
+    <button class="ui item icon noBorder AMmenu button" onClick="toggleLeftMenu();"><i class="content icon"></i></button>
+	<div class="item noBorder AMmenu" style="padding-right:0px;padding-top:12px;"><i id="AMmenuIcon" class="music icon large whiteFont"></i></div>
+	<div class="item noBorder AMmenu" style="padding-left:3px;padding-top:3px;padding-bottom:5px;min-width:50%;">
+		<div class="ui header whiteFont">
+			<div id="interfaceTitle" style="display:inline; font-weight: lighter;">Music</div>
+			<div id="interfaceDetails" class="sub header" style="font-size:80%; line-height:1em; color: white;">[0 songs]</div>
+		</div>
+	</div>
+	<button class="ui right item icon AMmenu noBorder button" onClick="enterSearchMode();"><i class="search icon"></i></button>
+	<!-- <button class="ui right item icon AMmenu noBorder button"><i class="ellipsis vertical icon"></i></button> -->
+</div>
+<div id="searchModeMenu" class="ui basic fluid AMmenu menu bottomBlue" style="z-index:85;position:fixed;top:0px;left:0px;width:100%;height:51px;display:none;margin-top: 0px;">
+    <button class="ui item icon noBorder AMmenu button" onClick="exitSearchMode();"><i class="arrow left icon"></i></button>
+	<div class="ui input" style="flex-grow: 1;">
+		<input id="searchInputBar" onkeypress="//handleSearchInputEnter(event);" type="text" style="background-color:rgb(48, 48, 48);border:0px !important;border-bottom:2px solid rgb(60, 60, 60) !important;margin-bottom:3px;color:white;" placeholder="Search Music">
+	</div>
+	<button class="ui right item icon AMmenu noBorder button" onClick="searchSong();"><i class="search icon"></i></button>
+</div>
+<!-- The main list that display the current information-->
+<div id="mainList">
+
+</div>
+
+<!-- Advance functions config menu-->
+<div id="showmoreUIcover" style="position:fixed;left:0px;top:0px;width:100%;height:100%;background:rgba(30,30,30,0.7);z-index:95;display:none;" onClick="hideShowMoreMenu();"></div>
+<div id="showMoreUI" class="showMoreMenus" style="display:none;">
+    <div class="ui large header whiteFont songTitle">N/A</div>
+    <div class="showMoreMenuItem" onClick="playFromShowMoreMenu();">Play</div>
+    <div class="showMoreMenuItem" onclick='addToPlaylistFromMoreMenu();'>Add to Playlist</div>
+    <div class="showMoreMenuItem playlistonly" onclick="removeFromPlylistFromMoreMenu();">Remove from current Playlist</div>
+    <div class="showMoreMenuItem" onClick="searchYoutubeViaShowMore();">Search on Youtube</div>
+    <div class="showMoreMenuItem">Edit Tag</div>
+    <div class="showMoreMenuItem">Share</div>
+    <div class="showMoreMenuItem" onClick="startRelatedSearch();">Related Search</div>
+    <div class="showMoreMenuItem" onClick="showFileInfo();">File Information</div>
+    
+    <div class="topRightCorner songID" align="center" style="margin-top:10px !important;padding-top:3px !important;">-1</div>
+</div>
+<div id="showFileInfo" class="showMoreMenus" style="display:none;">
+    <div class="ui large header">
+		<span class="filename whiteFont">Title</span>
+		<div class="sub header rawname whiteFont" style="word-break: break-all !important; font-size:80%;">Storage Name</div>
+	</div>
+	<div class="ui list whiteFont">
+		<div class="item whiteFont">Storage Location:   <span class="filepath" style="word-break:break-all;">N/A</span></div>
+		<div class="item whiteFont">File Size:   <span class="filesize">N/A</span></div>
+		<div class="item whiteFont">Last Modification Date:   <span class="filedate">N/A</span></div>
+	</div>
+</div>
+
+<!-- Side bar -->
+<div id="sideBarCover" style="position:fixed;left:0px;top:0px;width:100%;height:100%;background:rgba(30,30,30,0.7);z-index:50;display:none;" onClick="toggleLeftMenu();"></div>
+<div id="leftSideBar" class="leftsb" style="max-width:60%;height:100%;z-index:90;display:none;">
+	<div class="leftsbObject sidebarBanner">
+		<img class="ui tiny middle aligned image" src="img/main_icon.png" style="max-width: 50px;"><h5 class="whiteFont" style="display:inline;padding-left:8px;">AirMusic</h5>
+	</div>
+	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadSongList();setStorage('viewingTab','music');">
+		<div class="ui header">
+			<i class="music tiny icon whiteFont"></i>
+			<div class="content whiteFont">
+				Music
+			</div>
+		</div>
+	</div>
+	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadFolderView();setStorage('viewingTab','folder');">
+		<div class="ui header">
+			<i class="folder tiny icon whiteFont"></i>
+			<div class="content whiteFont">
+				Folder
+			</div>
+		</div>
+	</div>
+	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadPlaylistView(); setStorage('viewingTab','playlist');">
+		<div class="ui header">
+			<i class="align justify tiny icon whiteFont"></i>
+			<div class="content whiteFont">
+				Playlists
+			</div>
+		</div>
+	</div>
+	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="loadNetworkView(); setStorage('viewingTab','network');">
+		<div class="ui header">
+			<i class="world tiny icon whiteFont"></i>
+			<div class="content whiteFont">
+				Network
+			</div>
+		</div>
+	</div>
+	<!-- 
+	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;" onClick="">
+		<div class="ui header">
+			<i class="upload icon whiteFont"></i>
+			<div class="content whiteFont">
+				Upload
+			</div>
+		</div>
+	</div>
+	-->
+	<div class="leftsbObject sbSelectable sbPaddingIn" style="font-size:80%;border-top: 2px solid #4a4a4a;">
+		<div class="ui header">
+			<i class="setting tiny icon whiteFont"></i>
+			<div class="content whiteFont">
+				Settings
+			</div>
+		</div>
+	</div>
+</div>
+
+<!-- Mini player controller put on the bottom side of the list interface-->
+<div id="miniPlayer" class="hidden">
+    <div style="padding-left:20px;padding-top:5px;" >
+        <div class="ui header selectable" style="margin:0px !important;width:300px;cursor:pointer;" onClick="showMainPlayerInterface();">
+            <img id="smallPlayerThumb" class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
+            <div class="content whiteFont" style="padding-top:5px;line-height:1em;">
+                <div id="miniPlayerDisplayName" style="text-overflow: ellipsis;overflow: hidden;max-width:200px; white-space: nowrap;">N/A</div>
+                <div id="miniPlayerInformation" class="sub header" style="color: #c7c7c7;size:95%;">No information</div>
+            </div>
+        </div> 
+    </div>
+    <div id="miniPlayerIDtab" class="miniPlayer minitab">
+        0/0
+    </div>
+    <div class="miniPlayerControls">
+        <button class="miniPlayer selectable" style="font-size:90%; font-weight: lighter;" onClick="previousSong();"><i class="step backward icon whiteFont"></i></button>
+        <button class="miniPlayer selectable" style="font-size:120%; font-weight: lighter;" onClick="togglePlayMode();"><i class="play icon whiteFont PlayButton"></i></button>
+        <button class="miniPlayer selectable" style="font-size:90%; font-weight: lighter;" onClick="nextSong();"><i class="step forward icon whiteFont "></i></button>
+    </div>
+</div>
+<!-- Main interface for player and audio controller-->
+<div id="playerInterface" style="display:none;">
+    <div id="infoBar" class="whiteFont" style="padding:20px;" align="center">
+        <!-- Top Information Bar-->
+       
+        <div class="whiteFont songTitleWrapper" style="margin:0px;display:inline-block;">
+            <div id="mainPlayerSongTitle" class="whiteFont" style="font-weight: bold;font-size:120%;">Song Title</div>
+            <small id="mainPlayerSongDesc">This is some small text for display</small>
+        </div>
+         <div style="position:absolute;left:20px;top:30px;cursor:pointer;" onClick="hideMainPlayerInterface();">
+            <i class="large chevron left icon"></i>
+        </div>
+        <div style="position:absolute;right:20px;top:30px;cursor:pointer;" onClick='$("#dropdownSonglist").slideDown();'>
+            <i class="large content icon"></i>
+        </div>
+    </div>
+    <div style="padding-left:20px; padding-right:20px;padding-bottom:5px; position: relative;" align="center">
+        <!-- Function Menu Bar-->
+        <div class="ui grid">
+            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onclick="showPlaylistInterface();"><i class="large plus icon whiteFont"></i></button></div>
+            <div class="two wide column"><button class="topPanelButtons" id="downloadBtn" style="cursor: pointer;" onClick="downloadPlayingSong();"><i class="large download icon whiteFont"></i></button></div>
+            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onClick="openInFileExplorer();"><i class="large folder open icon whiteFont"></i></button></div>
+            <div class="two wide column desktopOnly" style="margin-top: -4px;"><button class="topPanelButtons" style="cursor: pointer; opacity: 0.6;" onClick="mute(this);" ><i class="icons"><i class="big red dont icon"></i><i style="margin-left: -3px;" class="large volume off icon whiteFont"></i></i></button></div>
+            <div class="two wide column desktopOnly"><button class="topPanelButtons" id="voldownBtn" style="cursor: pointer;" onClick="addAudioVolume(-0.05);"><i class="large volume down icon whiteFont"></i></button></div>
+            <div class="two wide column desktopOnly"><button class="topPanelButtons" id="volupBtn" style="cursor: pointer;" onClick="addAudioVolume(0.05);"><i class="large volume up icon whiteFont"></i></button></div>
+            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onClick="showTimerInterface();"><i class="large clock icon whiteFont"></i></button></div>
+            <div class="two wide column"><button class="topPanelButtons" style="cursor: pointer;" onClick="showSettingInterface();"><i class="large setting icon whiteFont"></i></button></div>
+        </div>
+        <div id="volumeGUI" align="center">
+            <i class="volume off large icon whiteFont" style="position:absolute;left:2em;top:1em;"></i>
+            <div class="ui tiny progress" style=" margin-top: calc(2em - 5px); margin-bottom: 0; background-color: rgba(255,255,255,0.2);" align="left">
+                <div id="volBar" class="bar" style="min-width: 0px; width: 40%; height: 10px; background-color: #4b75ff;"></div>
+            </div>
+           <i class="volume up large icon whiteFont" style="position:absolute;right:2em;top:1em;"></i>
+        </div>
+    </div>
+	<!-- Download progress bar-->
+	<div id="downloadProgressBar" class="ui attached fluid tiny progress" style="background-color:rgba(20, 20, 20, 0.9);display:none;">
+		<div class="bar" style="min-width: 0px; width: 0%;background-color:rgb(75, 117, 255) !important;"></div>
+	</div>
+
+    <div id="albumnArt" align="center">
+        <img id="albumnArtImage" style="max-width: 80%; pointer-events: none; user-select: none;" src="img/default.png"> 
+    </div>
+    <div id="mainPlayerControlInterface">
+        <!-- main control interface-->
+        <div style="width:100%;" align="center">
+            <div id="progressTime">
+                0:00
+            </div>
+            <div id="mainPlayerMiniTab" class="mainPlayer minitab">
+                0/0
+            </div>
+            <div id="remainTime">
+                -0:00
+            </div>
+        </div>
+        
+        <div style="position:absolute;width:100%;left:0px;bottom:0px;">
+            <div style="padding-left:10px;padding-right:10px;">
+                <div class="ui small primary progress" style="background-color: rgba(255,255,255,0.4);">
+                    <div id="audioProgressBar" class="bar" style="min-width: 0px; width: 100%; background: #4b75ff;"></div>
+                </div>
+            </div>
+            <div class="mainControlButtons">
+                <button class="panelButtons" style="font-size:90%;padding:15px;" onClick="previousSong();"><i class="step backward icon whiteFont"></i></button>
+                <button class="panelButtons" style="font-size:130%;" onClick="togglePlayMode();"><i class="play icon whiteFont PlayButton"></i></button>
+                <button class="panelButtons" style="font-size:90%;padding:15px;" onClick="nextSong();"><i class="step forward icon whiteFont "></i></button>
+            </div>
+            <div id="randomModeButton" style="position: absolute; left:30px;bottom:20px;" onClick="toggleRandomMode(this);">
+                <i class="large random icon disabled"></i>
+            </div>
+            <div id="repeatModeButton" style="position: absolute; right:30px;bottom:20px;" onClick="toggleRepeatMode(this);">
+                <i class="large retweet icon disabled"></i>
+                <p class="whiteFont singleLoop" style="position:absolute;right:0px;bottom:0px;margin-bottom:-13px;margin-right:-2px;display:none;">1</p>
+            </div>
+        </div>
+    </div>
+    <audio id="mainAudioPlayer" style="display:none;" src=""></audio>
+   
+	<div id="dropdownSonglist" class="dropdownMusicList" style="display:none;">
+			<div class="dropdownMusicListMiniMenu">
+				<i class="icons" style="margin-right:8px;">
+					<i class="content icon"></i>
+				<i class="corner music icon" style='color:#333333'></i>
+				</i>
+				Now Playing
+				<div style="position:absolute;top:3px;right:5px;">
+					[ <span id="dropdownListSongCount">N/A</span> songs / <span id="dropdownListIDCount">N/A</span> MB ] <button onClick='$("#dropdownSonglist").slideUp();' style="cursor:pointer;"><i class="caret up icon whiteFont"></i></button>
+				</div>
+			</div>
+			<div id="currentPlayingMainList" style="overflow-x:hidden;">
+				
+			</div>
+			<div class="dropdownMusicListBottom" align="center" onClick='$("#dropdownSonglist").slideUp();'><i class="caret up icon"></i></div>
+	</div>
+    
+</div>
+
+<!-- Quick Menus and other tool windows-->
+
+ <!-- Timer control interface-->
+ <div id="timerInterface" class="quickMenu">
+	<h4 class="whiteFont">Countdown Timer</h4>
+	<br>
+	<div id="timerSettingInterface" style="width:100%;" align="center">
+		<div>
+			<div class="ui statistic">
+				<div class="label whiteFont">hours</div>
+				<div id="timerHour" class="value whiteFont">0</div>
+			</div>
+			 <div class="ui statistic">
+				<div class="label whiteFont">minutes</div>
+				<div id="timerMinute" class="value whiteFont">0</div>
+			</div>
+		</div>
+		<div>
+			<div class="ui icon mini buttons">
+				<button class="ui secondary button" onClick="addTimer('h',1);"><i class="add icon"></i></button>
+				<button class="ui secondary button" onClick="addTimer('h','r');"><i class="refresh icon"></i></button>
+				<button class="ui secondary button" onClick="addTimer('h',-1);"><i class="minus icon"></i></button>
+			 </div>
+			 <div class="ui icon mini buttons">
+				<button class="ui secondary button" onClick="addTimer('m',10);"><i class="add icon"></i></button>
+				<button class="ui secondary button" onClick="addTimer('m','r');"><i class="refresh icon"></i></button>
+				<button class="ui secondary button" onClick="addTimer('m',-1);"><i class="minus icon"></i></button>
+			 </div>
+		</div>
+	</div>
+	<div id="timerCountingInterface" style="width:100%; display:none;" align="center">
+		<div class="ui statistic">
+			<div id="remainingUI" class="value whiteFont">0:00:00</div>
+			<div class="label whiteFont">Remaining</div>
+		</div>
+	</div>
+	<div class="ui divider"></div>
+	<div>
+		<div class="ui grid">
+			<div class="eight wide column">
+				Times up action
+			</div>
+			<div class="eight wide column">
+				<select id="stopMode" class="ui selection mini fluid dropdown">
+					<option>Fade Out & Stop</option>
+					<option>Stop Playing</option>
+				</select>
+			</div>
+		</div>
+	</div>
+	<div style="width:100%;position:absolute;left:0px;bottom:20px;" align="right">
+		<div class="ui grid" >
+			<div class="eight wide column" style="padding-right: 0px;" align="center"><button class="greenBtn fluid" onClick='hideAllquickMenu();'>Close</button></div>
+			<div class="eight wide column"  style="padding-left: 0px;" align="center"><button class="greenBtn fluid" onClick="toggleCountDown(this);">Start</button></div>
+		</div> 
+	</div>
+</div>
+
+<!-- File properties interface-->
+<div id="filepropInterface" class="quickMenu">
+	<div class="ui header">
+		<span class="filename whiteFont">Title</span>
+		<div class="sub header rawname whiteFont"  style="word-break:break-all;">Storage Name</div>
+	</div>
+	<div class="ui list whiteFont">
+		<div class="item whiteFont">Storage Location:   <span class="filepath"  style="word-break:break-all;">N/A</span></div>
+		<div class="item whiteFont">File Size:   <span class="filesize">N/A</span></div>
+		<div class="item whiteFont">Last Modification Date:   <span class="filedate">N/A</span></div>
+	</div>
+</div>
+<!-- Setting interface-->
+<div id="settingInterface" class="quickMenu">
+	<div style="">
+		<div class="ui relaxed list" style="padding:0px !important;">
+			<div id="settingMenuTitle" class="item whiteFont" style="">N/A</div>
+			<div class="item selectable whiteFont" onclick="showPlaylistInterface(); $('#settingInterface').fadeOut('fast');"><i class="add icon" style="margin-right:5px;"></i> Add to playlist</div>
+			<div class="item selectable whiteFont" onClick="openInFileExplorer(); hideAllquickMenu();"><i class="folder open icon" style="margin-right:5px;"></i> Open in File Explorer</div>
+			<div class="item selectable whiteFont" onClick="searchOnYoutube(); hideAllquickMenu();"><i class="youtube play icon" style="margin-right:5px;"></i>Search on Youtube</div>
+			<div class="item selectable whiteFont" onClick="showFileInformation();"><i class="file icon" style="margin-right:5px;"></i> File Information</div>
+			<div class="ui divider"></div>
+			<div id="closeWebAppButton" class="item selectable whiteFont"  onClick="ao_module_close();"><i class="remove icon" style="margin-right:5px;"></i> Exit Application</div>
+		</div>
+	</div>
+</div>
+
+
+<!-- Playlist interface-->
+<div id="playlistInterface" class="quickMenu">
+	<div class="ui header">
+		<span class="whiteFont">Add to Playlist</span>
+	</div>
+	<div class="playlist item selectable whiteFont" onclick="addToNewPlaylist();">
+		<i class="add icon whiteFont"></i> New Playlist
+	</div>
+	<!-- playlist list-->
+	<div id="existsingPlaylist" style="overflow-y: scroll; height: 50%; border: 1px solid white;">
+		<div class="playlist item selectable whiteFont">
+			<i class="list icon whiteFont"></i> Test Playlist
+		</div>
+	</div>
+	<br>
+	<div style="width:100%;position:absolute;left:0px;bottom:0px; margin-bottom: 10px;" align="center">
+	<button class="greenBtn" onClick='hideAllquickMenu();'>Close</button>
+	</div>
+	<div class="ui snackbar" id="succSnackBar">
+		<div class="content">
+			Action Completed
+		</div>
+	</div>
+</div>
+
+<!-- Utils Interfaces, usually hidden-->
+<div id="fadeReturnScreen" class="fadeScreen whiteFont" onClick="hideAllquickMenu();"></div>
+
+<script>
+	var leftMenuShown = false;
+	var currentPath = "";
+	var currentMode = "music";
+	var rootPaths = [];
+	var totalMusicCount = 0;
+	var currentPlaying = false;
+	var audioElement = $("#mainAudioPlayer");
+	var audioElementObject = document.getElementById("mainAudioPlayer"); //Directly expose the audio object
+	var playingFileDetail = []; //[id, filepath]
+	var displayList = []; //This is the list where the current UI is displaying.
+	var playingList = []; //This is the list where the player last clicked on an item to play
+	var pagingEnabled = false; //Enable this when there are too many songs in list
+	var pagingEnableForPlayingList = false; 
+	var pagingCutoffCount = 100; //No. of songs to start paging
+	var currentPage = 0;
+	var currentPlayingPage = 0;
+	var randomMode = false;
+	var repeatMode = 0; //Repeat mode 0 -> No repeat, 1 -> Repeat all 2 -> Repeat one
+	var updateSystemVolume = true;
+	var timerMode = false;
+	var timerRemaining = 0;
+	var playlistAddPendingFile = ""; //The filepath of the file that is pending to be added to playlist
+	var timerEndMode = "fade"; //Fade or End, Provide volume fadeout or end immediately while times up
+	var ua =  navigator.userAgent.toLowerCase();
+	var isAndroid = ua.indexOf("android") > -1; //&& ua.indexOf("mobile");
+	var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
+	var cacheAvailable = 'caches' in self;
+	let cacheDb, cacheStore, cacheDbTx;
+	var dbExists = !(!window.indexedDB);
+
+	//Init database connection if indexedDB Exists
+	if (dbExists){
+		let cacheDbConn = window.indexedDB.open('airmusic', 4);
+		cacheDbConn.onupgradeneeded = function(event) { 
+			cacheDb = event.target.result;
+			cacheDbTx = event.target.transaction;
+			cacheStore = cacheDb.createObjectStore("files",{keyPath:"filename"})
+		};
+		cacheDbConn.onerror = function(event) {
+			console.log("ERROR: " + event.target.errorCode)
+		};
+		cacheDbConn.onsuccess = function(event) {
+			cacheDb = event.target.result
+		}
+	}
+
+	//Embed native mediaSession for any device that supports it 
+	initNativeMediaPlayer();
+
+
+	//Update implementatio nof user agent detection
+	if (typeof InstallTrigger !== 'undefined'){
+		ua = "firefox";
+	}
+
+	if (!!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime)){
+		ua = "chrome";
+	}
+
+	var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
+	if (isSafari == true){
+		ua = "safari";
+	}
+
+
+	$(document).ready(function(){
+		$("#leftSideBar").animate({left: $("#leftSideBar").width() * -1}, 300);
+		//Update 7-8-2019, default loading tab is handled over to the returnToPreviousState() function.
+		//loadSongList(); 
+		//Initiate the module's volume to the system's
+		syncSystemVol();
+		initAudioListeners();
+        resizeQuickAdjust(); //Adjust all the DOM items position according to window size
+        restoreAllSettings(); //Restore all user prefered settings from storage
+        hideMainPlayerInterface();//Hide the main interface
+        setTimeout(function(){
+            $("#playerInterface").show(); //Only show this interface after it has been out of the working area.
+        },500);
+        
+        //Hide the exit application button if it is not in Virtual Desktop Mode
+        if (!ao_module_virtualDesktop){
+            $("#closeWebAppButton").hide();
+        }
+		returnToPreviousState(); //Try to return to previous state using the window hash value
+	});
+
+	function returnToPreviousState(){
+		var hash = window.location.hash;
+		if (hash != ""){
+			//There are state to restore. Restore using the given hash value
+			hash = decodeURIComponent(hash.substring(1));
+			var previousState = JSON.parse(hash);
+			console.log(previousState);
+			var currentPath = previousState.path;
+			var playingFileDetail = previousState.pfp;
+			var initPauseState = previousState.pause;
+			if (currentPath != ""){
+				//Create a dummy folder and trick the system to load to the previous states
+				var a = '<div></div>';
+				a = $(a).attr("filepath",currentPath);
+				openFolder(a[0],{playIDAfterOpen: playingFileDetail[0],startPaused: initPauseState});
+			}else{
+				//currentpath is empty, aka Music Mode
+				loadSongList();
+			}
+
+			
+		}else{
+			//No state to restore. Restore Viewing Tab instead.
+			var vt = loadStorage("viewingTab");
+			if (vt != ""){
+				if (vt == "music"){
+					loadSongList();
+					
+				}else if(vt == "folder"){
+					loadFolderView();
+					
+				}else if(vt == "playlist"){
+					loadPlaylistView();
+					
+				}else if(vt == "network"){
+					loadNetworkView();
+					
+				}
+			}else{
+				//Default action
+				loadSongList();
+			}
+		}
+	}
+
+	function loadNetworkView(){
+		currentMode = "network";
+		togglePagingMode(false);
+	}
+
+	function togglePagingMode(enabled=false){
+		if (pagingEnabled != enabled){
+			currentPage = 0;
+		}
+		pagingEnabled = enabled;
+	}
+	
+	function initAudioListeners(){
+		//Initiate audio progress bar and link it to the progress bar on the main player interface
+		audioElement[0].addEventListener("timeupdate", function() {
+            var currentTime = audioElement[0].currentTime;
+            var duration = audioElement[0].duration;
+            $('#audioProgressBar').css('width',((currentTime +.25)/duration)*100 + '%');
+            updatePlaybackDisplayTime(currentTime,duration);
+        });
+        audioElement[0].onended = function() {
+            nextSongHandler(); 
+        }; 
+        
+        //Handle clicks on progress bar to skip through the playback
+        $("#audioProgressBar").parent().on("click",function(e){
+           var duration = audioElement[0].duration;
+           var jumpTo = (e.offsetX / $(this).width()) * duration;
+           if (!audioElement[0].paused){
+                audioElement[0].pause();
+                audioElement[0].currentTime = jumpTo;
+	            audioElement[0].play();
+           }else{
+               audioElement[0].currentTime = jumpTo;
+           }
+          
+	      
+        });
+	}
+	
+	function restoreAllSettings(){
+	    //Repeat mode setting
+	    var strRmode = loadStorage("repeatMode");
+	    if (strRmode != ""){
+	        repeatMode = parseInt(strRmode);
+	        setRepeatMode(repeatMode,$("#repeatModeButton")[0]);
+	    }
+	    //Random Mode setting
+	    var random = loadStorage("randomMode");
+	    if (random != ""){
+	        if (random == "true"){
+	            //random Mode is true when loaded from configuration. Toggle once to match the setting
+	            toggleRandomMode($("#randomModeButton")[0]);
+	        }
+	    }
+	    //Timer mode setting
+	    var TEM = loadStorage("timerEndMode");
+	    if (TEM != ""){
+	        if (TEM == "fade"){
+	            $("#stopMode").val("Fade Out & Stop");
+    	    }else{
+    	        $("#stopMode").val("Stop Playing");
+    	    }
+	    }
+	  
+	}
+	
+	//Setting menu function
+	function searchOnYoutube(filename = ""){
+		if (filename == ""){
+			var filename = $("#mainPlayerSongTitle").text().trim();
+		}
+	    
+	    var url = "https://www.youtube.com/results?search_query=" + filename ;
+	    window.open(url);
+	}
+	
+	//Searching related functions
+	var preSearchItemBuffer = "";
+	var searchModeEnabled = false;
+	var previousPagingEnabled = false;
+	function enterSearchMode(){
+		if (searchModeEnabled){
+			//Search mode already enabled
+			return;
+		}
+		previousPagingEnabled = pagingEnabled;
+		togglePagingMode(false);
+		$("#searchModeMenu").show();
+		$("#mainMenu").hide();
+		let previousDisplayList = Array.from(displayList);
+		preSearchItemBuffer = [$("#mainList").html(),$("#interfaceTitle").text(),$("#AMmenuIcon").attr("class"), $("#interfaceDetails").html(), previousDisplayList];
+		searchModeEnabled = true;
+	}
+
+	function exitSearchMode(){
+		$("#searchModeMenu").hide();
+		$("#mainMenu").show();
+		$("#searchInputBar").val("");
+		if (preSearchItemBuffer != ""){
+			//If previous record exists, recover the previous view from storage
+			$("#mainList").html(preSearchItemBuffer[0]);
+			$("#interfaceTitle").text(preSearchItemBuffer[1]);
+			$("#AMmenuIcon").attr("class",preSearchItemBuffer[2]);
+			$("#interfaceDetails").html(preSearchItemBuffer[3]);
+			displayList = preSearchItemBuffer[4];
+			preSearchItemBuffer = "";
+		}
+
+		if (previousPagingEnabled){
+			togglePagingMode(true);
+		}
+		searchModeEnabled = false;
+	}
+
+	document.getElementById("searchInputBar").addEventListener("keypress", function(event){
+		console.log(event, event.keyCode);
+		if(event.keyCode == 13){
+			//Enter pressed. start searching
+			searchSong();
+		}
+	});
+
+	/*
+	function handleSearchInputEnter(e){
+		if(e.keyCode == 13){
+			//Enter pressed. start searching
+			searchSong();
+		}
+	}
+	*/
+
+	function searchSong(){
+		var keyword = $("#searchInputBar").val();
+		if (keyword.includes("?") || keyword.includes("&")){
+			alert("Search keyword cannot contains & or ? symbol.");
+			return;
+		}
+
+		if (keyword == ""){
+			//Empty keyword. Return nothing
+			return;
+		}
+		//Clear the mainList, replace with a dummy loading screen
+		$("#mainList").html('<div class="mainList item whiteFont">\
+			<div class="ui header" style="margin:0px !important;padding-bottom:15px;padding-top:5px;">\
+			<i class="loading spinner icon whiteFont" style="overflow:hidden;margin-top:5px;"></i>\
+				<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">\
+					Searching...\
+				</div>\
+			</div>\
+			<div class="topRightCorner" align="center">\
+				-1\
+			</div>\
+			</div>');
+
+		ao_module_agirun("Music/functions/listSong.js", {
+			listSong: "search:" + keyword
+		}, function(data){
+			currentPath = "";
+			var template = '<div class="mainList file item" filepath={filepath} id={id} rawname={rawname}>\
+			<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">\
+				<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>\
+				<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">\
+					{songtitle}\
+					<div class="sub header fileinfo" style="color: #c7c7c7;">{ext} / {size}</div>\
+				</div>\
+			</div>\
+			<div class="topRightCorner" align="center">\
+				{id}\
+			</div>\
+			<div class="mainList rightFunctionBar" align="center" onClick="showMore(this);">\
+				<i class="ellipsis vertical icon" style="top: 2em;"></i>\
+			</div>\
+		</div>';
+
+		if ($("#searchModeMenu").is(":hidden")){
+			//The user exited search mode before the search results come back
+			//Dispose the search result
+			return;
+		}
+		
+		if (data.length == 0){
+			//No search results.
+			$("#mainList").html("");
+			$("#mainList").append('<div class="mainList item whiteFont">\
+			<div class="ui header" style="margin:0px !important;padding-bottom:15px;padding-top:5px;">\
+			<i class="remove icon whiteFont" style="overflow:hidden;margin-top:5px;"></i>\
+				<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">\
+					No result for keyword: ' + keyword + '.\
+				</div>\
+			</div>\
+			<div class="topRightCorner" align="center">\
+				-1\
+			</div>\
+			</div>');
+			return;
+		}
+		
+
+        $("#interfaceTitle").text("Search");
+        $("#AMmenuIcon").attr("class","search icon large whiteFont")
+		//Initialize the song list
+		displayList = data;
+		if (playingList == []){
+			playingList = Array.from(displayList);
+			pagingEnableForPlayingList = pagingEnabled;
+			currentPlayingPage = currentPage;
+		}
+		$("#mainList").html("");
+		for ( var i =0; i < data.length; i++){
+			var songInfo = data[i];
+			var path = songInfo[0];
+			var displayname = ao_module_codec.decodeUmFilename(songInfo[1]);
+			var ext = songInfo[2];
+			var size = songInfo[3];
+			var box = template;
+			box = replaceAll("{filepath}",ao_module_utils.objectToAttr(path),box);
+			box = replaceAll("{id}",i + 1,box); //User count from 1
+			box = replaceAll("{rawname}",ao_module_utils.objectToAttr(songInfo[1]),box);
+			box = replaceAll("{songtitle}",displayname,box);
+			box = replaceAll("{ext}",ext,box);
+			box = replaceAll("{size}",size,box);
+			$("#mainList").append(box);
+		}
+		totalMusicCount = data.length;
+		$("#mainList").append("<br><br><br><br><br><br><br>");
+		$("#interfaceDetails").text("[" + i + " songs]");
+		highLightPlayingMusic();
+		loadThumbnailToMusicList(".mainList.file.item");
+	});
+
+	}
+	
+	function enterRemotePlayID(object){
+	    var id = $(object).text().trim();
+	    $("#remotePlayID").val($("#remotePlayID").val() + id);
+	}
+	
+	function ridOpr(opr){
+	    if (opr == 'backspace'){
+	        var currentText = $("#remotePlayID").val();
+	        var newText = currentText.substring(0,currentText.length - 1);
+	        $("#remotePlayID").val(newText);
+	    }else if (opr == 'reset'){
+	        $("#remotePlayID").val("");
+	    }
+	}
+	
+	function openInFileExplorer(){
+	    var dirname = playingFileDetail[1].split("/");
+	    var fname = dirname.pop(); //Pop away the filename
+	    dirname = dirname.join("/") + "/";
+	    var path = dirname;
+	    if (dirname.substring(0,1) != "/"){
+	        //This is not absolute path. Start the path from airMusic
+	        path = "AirMusic/" + dirname;
+	    }
+	    
+		path = path.replace("media?file=","");
+		if (path.substring(0,1) == "/"){
+			path = path.substring(1)
+		}
+	    ao_module_openPath(path, fname);
+	}
+	
+	
+	//quickmenu Functions
+	function hideAllquickMenu(){
+	    $(".quickMenu").fadeOut('fast');
+	    $("#fadeReturnScreen").fadeOut('fast');
+	}
+
+	
+
+	
+	//Setting related function
+	function showSettingInterface(){
+	    $("#settingInterface").fadeIn('fast');
+	    $("#fadeReturnScreen").fadeIn('fast');
+	    //Update contents in the setting menu
+	    $("#settingMenuTitle").text($("#mainPlayerSongTitle").text());
+	}
+	
+	
+	//Timer related functions
+	function showTimerInterface(){
+	    $("#timerInterface").fadeIn('fast');
+	    $("#fadeReturnScreen").fadeIn('fast');
+	}
+
+	function initPlaylistInterfaceList(){
+		$("#existsingPlaylist").html("");
+		//Get the playlist list from server side
+		ao_module_agirun("Music/functions/playlist.js", {
+			opr: "root"
+		}, function(data){
+			data.forEach(playlist => {
+				$("#existsingPlaylist").append(`<div class="playlist item selectable whiteFont" name="${playlist.name}" onclick="addSongToSelectedPlaylist(this);">
+					<i class="list icon whiteFont"></i> ${playlist.name} [${playlist.count} files]
+				</div>`);
+			})
+		});
+	}
+
+	function showPlaylistInterface(){
+		initPlaylistInterfaceList();
+		$("#playlistInterface").fadeIn('fast');
+	    $("#fadeReturnScreen").fadeIn('fast');
+	}
+
+	function addToThisPlaylist(){
+
+	}
+	
+	$("#stopMode").change(function () {
+        var end = this.value;
+        if (end.includes("Fade Out & Stop")){
+            //Start fading out the volume
+            timerEndMode = "fade";
+            setStorage("timerEndMode","fade");
+        }else{
+            //End immediately
+            timerEndMode = "end";
+            setStorage("timerEndMode","end");
+        }
+    });
+    
+    var fadeOutStepping = 0.1; //The steps size for fading out during timer countdown
+    var defaultVolumeBeforeFadeout = 0;
+    function toggleCountDown(button){
+        if (!timerMode){
+            //Start count down
+            timerMode = true;
+            $(button).text("Stop");
+            timerRemaining = ((parseInt($("#timerHour").text()) * 60) + parseInt($("#timerMinute").text())) * 60; //in seconds
+            if (timerRemaining <= 0){
+				//Start with 0
+				timerMode = false;
+				$(button).text("Start");
+				return;
+			}
+			//Update the value on the remaining counter
+            $("#remainingUI").text(parseTimer(timerRemaining));
+            $("#timerSettingInterface").slideUp('fast');
+            $("#timerCountingInterface").slideDown('fast');
+            $("#stopMode").attr("disabled","");
+            defaultVolumeBeforeFadeout = audioElement[0].volume;
+            fadeOutStepping = (audioElement[0].volume) / timerRemaining;
+            progressCounter();
+        }else{
+            //Stop count down
+            timerMode = false;
+            $(button).text("Start");
+            timerRemaining = 0;
+            $("#timerSettingInterface").slideDown('fast');
+            $("#timerCountingInterface").slideUp('fast');
+            $("#stopMode").removeAttr("disabled");
+        }
+    }
+    
+    function progressCounter(){
+        //Update the timer
+        timerRemaining = timerRemaining - 1;
+        $("#remainingUI").text(parseTimer(timerRemaining));
+        if (timerRemaining > 0){
+            //Continues
+            if (timerEndMode == "fade"){
+                var newvol = audioElement[0].volume - fadeOutStepping;
+                audioElement[0].volume = Math.max(0,newvol);
+            }
+            setTimeout(progressCounter,1000);
+        }else{
+            //Times up
+            handleTimerEnd();
+        }
+        
+    }
+    
+    function handleTimerEnd(){
+        //Stop the playback
+        originalVol = audioElement[0].volume;
+	    fadeAudio();
+	    setPlaying(false);
+	    audioElement[0].pause();
+	    setTimeout(function(){
+	        audioElement[0].volume = defaultVolumeBeforeFadeout;
+	    },500);
+	    
+    }
+    
+    function parseTimer(remainingTime){
+        //remainingTime in seconds, prase to HH:mm:ss
+        var hours = Math.floor(remainingTime / 3600);
+        var remainingTime = remainingTime % 3600;
+        var minutes = Math.floor(remainingTime / 60);
+        var seconds = remainingTime % 60;
+        if (minutes < 10){
+            minutes = "0" + minutes;
+        }
+        if (seconds < 10){
+            seconds = "0" + seconds;
+        }
+        var formatted = hours + ":" + minutes + ":" + seconds;
+        return formatted;
+    }
+    
+    function addTimer(unit,value){
+        if (unit == "h"){
+            if (value == "r"){
+                $("#timerHour").text("0");
+            }else{
+                $("#timerHour").text($("#timerHour").text() - -1 * value); 
+            }
+           
+        }else if (unit == "m"){
+            if (value == "r"){
+                $("#timerMinute").text("0");
+            }else{
+               $("#timerMinute").text($("#timerMinute").text() - -1 * value); 
+            }
+        }
+        if (parseInt($("#timerHour").text()) < 0){
+            $("#timerHour").text("0");
+        }
+        if (parseInt($("#timerMinute").text()) < 0){
+            if (parseInt($("#timerHour").text()) > 0){
+                //subtract 1 from the hour
+                 $("#timerHour").text($("#timerHour").text() - 1); 
+                 $("#timerMinute").text(parseInt($("#timerMinute").text()) + 60);
+            }else{
+                //There is no hours to subtract
+                $("#timerMinute").text("0");
+            }
+            
+        }
+        if (parseInt($("#timerMinute").text()) > 59){
+            $("#timerMinute").text(parseInt($("#timerMinute").text()) - 60);
+            $("#timerHour").text($("#timerHour").text() - -1); 
+        }
+    }
+    
+	//Download function
+	function downloadPlayingSong(){
+	    var url = audioElement.attr("src");
+	    var ext = url.split(".").pop();
+	    var filename = $("#mainPlayerSongTitle").text().trim();
+		generateDownloadElement(url,filename);
+		/*
+		if (url.includes("/media")){
+			blobDownloadElement(url,filename);
+		}else{
+			generateDownloadElement(url,filename);
+		}
+		*/
+	}
+	
+	var downloadInProgress = false;
+	function blobDownloadElement(filepath,filename){
+		if (downloadInProgress){
+			alert("Please wait until another download finished.");
+			return;
+		}
+		downloadInProgress = true;
+		$("#downloadBtn").find("i").addClass("disabled");
+		$("#downloadProgressBar").find(".bar").css("width","0%");
+		$("#downloadProgressBar").show();
+		var xhr = new XMLHttpRequest();
+		xhr.onreadystatechange = function(){
+			if (this.readyState == 4 && this.status == 200){
+				//handler(this.response);
+				//console.log(this.response, typeof this.response);
+				var url = window.URL || window.webkitURL;
+				//Open the downloaded data in new window for testing
+				//window.open(url.createObjectURL(this.response));
+				generateDownloadElement(url.createObjectURL(this.response),filename);
+				$("#downloadBtn").find("i").removeClass("disabled");
+				$("#downloadProgressBar").hide();
+				downloadInProgress = false;
+			}
+			
+		}
+		xhr.onprogress = function (event) {
+			console.log("[AirMusic] Download Progress: " + event.loaded + " / " + event.total + "Bytes");
+			$("#downloadProgressBar").find(".bar").css("width",(event.loaded / event.total) * 100 + "%");
+		};
+		xhr.open('GET', filepath);
+		xhr.responseType = 'blob';
+		xhr.send();      
+	}
+
+	function generateDownloadElement(filepath, filename){
+		var link = document.createElement('a');
+
+		//Clean the filepath
+		filepath = filepath.split("//").join("/");
+		//Convert the filepath to download path
+        link.href = filepath.replace("/media?file=", "/media/download/?file=");
+
+		//Generate the download element
+        link.setAttribute('download', filename);
+        document.getElementsByTagName("body")[0].appendChild(link);
+        // Firefox
+        if (document.createEvent) {
+            var event = document.createEvent("MouseEvents");
+            event.initEvent("click", true, true);
+            link.dispatchEvent(event);
+        }
+        // IE
+        else if (link.click) {
+            link.click();
+        }
+        link.parentNode.removeChild(link);
+	}
+	
+	//Volume control related features
+	var previousAudioVolume = 0;
+	function mute(button){
+	    if (audioElement[0].volume != 0){
+	        //Set to mute
+	        previousAudioVolume = audioElement[0].volume;
+	        audioElement[0].volume = 0;
+			$(button).css("opacity", "1");
+			$("#voldownBtn").addClass("disabled");
+			$("#volupBtn").addClass("disabled");
+	    }else{
+	        //Restore from mute
+	        audioElement[0].volume = previousAudioVolume;
+			$(button).css("opacity", "0.6");
+			$("#voldownBtn").removeClass("disabled");
+			$("#volupBtn").removeClass("disabled");
+	    }
+	    $("#volBar").css("width",audioElement[0].volume * 100 + "%");
+	}
+	var volbarTimeoutEvt;
+	function addAudioVolume(value){
+	    $("#volumeGUI").slideDown('fast');
+	    if (volbarTimeoutEvt !== undefined){
+	        clearTimeout(volbarTimeoutEvt);
+	    }
+	    volbarTimeoutEvt = setTimeout(function(){
+	        $("#volumeGUI").slideUp('fast');
+	    },3000);
+	    $("#volumeGUI")
+	    if (audioElement[0].volume + value >= 1){
+	        audioElement[0].volume = 1;
+	    }else if (audioElement[0].volume + value <= 0){
+	        audioElement[0].volume = 0;
+	    }else{
+	        audioElement[0].volume += value; 
+		}
+	    
+	    $("#volBar").css("width",Math.min(100,audioElement[0].volume * 100) + "%");
+	}
+	
+	function updatePlaybackDisplayTime(currentTime,duration){
+	    let progress = Math.round(currentTime);
+	    let remainTime = Math.round(duration - currentTime);
+	    $("#progressTime").text(secondsToHms(progress));
+	    if (!isNaN(remainTime)){
+	        $("#remainTime").text("-" + secondsToHms(remainTime));
+	    }
+
+	}
+	
+	function nextSongHandler(){
+	    console.log("Next song");
+	    if (repeatMode == 1){
+			//Next song in the playlist
+	        if (randomMode){
+	            var randomTrackID = Math.floor(Math.random() * (playingList.length - 1));
+	            //console.log(randomTrackID, playingList[randomTrackID]);
+	            nextSong(randomTrackID,true);
+	        }else{
+				var playingSongIndex = playingFileDetail[0];
+				var nextSongIndex = playingSongIndex;
+				if (nextSongIndex >= playingList.length){
+					nextSongIndex = 0;
+				}
+				//console.log(playingSongIndex, nextSongIndex);
+	            nextSong(nextSongIndex,true);
+	        }
+	    }else if (repeatMode == 2){
+			//Loop this song only
+	       audioElement[0].pause();
+	       audioElement[0].currentTime = 0;
+	       audioElement[0].play();
+	    }else if (repeatMode == 0){
+			//Pause after finish this song
+	       setPlaying(false);
+	       audioElement[0].pause();
+	       audioElement[0].currentTime = 0;
+	    }
+	}
+	
+	function mainPlayerShown(){
+	    if ($("#playerInterface").offset().left == 0){
+	        return true;
+	    }
+	    return false;
+	}
+	
+	function toggleRandomMode(button){
+	    var btn = $(button).find("i");
+	    if (randomMode){
+	        //Set the random mode to false
+	        btn.removeClass("enabled").addClass("disabled");
+	        randomMode = false;
+	    }else{
+	        btn.removeClass("disabled").addClass("enabled");
+	        randomMode = true;
+	    }
+	    setStorage("randomMode",randomMode);
+	}
+	
+	function toggleRepeatMode(button){
+	    if (repeatMode == 0){
+	       setRepeatMode(1,button);
+	       setStorage("repeatMode",1);
+	    }else if (repeatMode == 1){
+	       setRepeatMode(2,button);
+	       setStorage("repeatMode",2);
+	    }else if (repeatMode == 2){
+	       setRepeatMode(0,button);
+	       setStorage("repeatMode",0);
+	    }
+	}
+	
+	function setRepeatMode(modeCode,button){
+	    if (modeCode == 1){
+	        //Set repeat mode to "Repeat all"
+	        $(button).find(".singleLoop").hide();
+	        $(button).find("i").removeClass("disabled").addClass("enabled");
+	        repeatMode = 1;
+	    }else if (modeCode == 2){
+	        //Set repeat mode to "Repeat one"
+	        $(button).find(".singleLoop").show();
+	        $(button).find("i").removeClass("disabled").addClass("enabled");
+	        repeatMode = 2;
+	    }else if (modeCode == 0){
+	        //Set repeat mode to "None"
+	        $(button).find(".singleLoop").hide();
+	        $(button).find("i").removeClass("enabled").addClass("disabled");
+	        repeatMode = 0;
+	    }
+	}
+	
+	
+	function hideMainPlayerInterface(){
+	    $("#playerInterface").animate({left: window.innerWidth},300);
+	    $("body").css("overflow-y","auto");
+	}
+	
+	function showMainPlayerInterface(){
+	    $("#playerInterface").animate({left:0},300);
+	    $("body").css("overflow-y","hidden");
+	}
+	
+	function syncSystemVol(){
+        //Initiate the module's volume to the system's
+        var globalvol = localStorage.getItem("global_volume");
+        //console.log("Global Volume" + globalvol.toString());
+        if (!globalvol){
+            globalvol = 0.1;
+		}
+		
+		//Check if it is mobile. If yes, always 100% and leave volume to system
+		if (isMobile()){
+			globalvol = 1;
+			//$(".desktopOnly").addClass("disabled");
+		}
+
+		audioElement[0].volume = parseFloat(globalvol);
+        $("#volBar").css("width",audioElement[0].volume * 100 + "%");
+	}
+	
+	function replaceAll(target, replace, original){
+	  return original.split(target).join(replace);  
+	};
+	
+	function playSong(object, startPaused = false){
+	    if ($(object).parent().hasClass("playingTrack")){
+	        //This is already the song that is currently playing. Show the main player interface instead.
+	        showMainPlayerInterface();
+	        resizeQuickAdjust();
+	        return;
+	    }
+
+	    //$(".playingTrack").removeClass("playingTrack");
+		//$(object).parent().addClass("playingTrack");
+		var filepath = ao_module_utils.attrToObject($(object).parent().attr('filepath'));
+	    var rawname = ao_module_utils.attrToObject($(object).parent().attr('rawname'));
+	    var displayName = ao_module_codec.decodeUmFilename(rawname);
+	    var info = $(object).parent().find(".fileinfo").text();
+		var id = $(object).parent().attr('id');
+		if (id === undefined){
+			//This might be a file from dropdown list. use listid instead
+			id = $(object).parent().attr('listid');
+		}
+		
+
+	    updateMiniPlayerUI(displayName,info,id);
+
+		//Check if page mode is enabled. If yes, do auto tab switch
+		if (pagingEnabled){
+			var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
+			switchToPage(targetPageNumber);
+		}
+
+		//Seperate out the filepath without media server path
+		var fileVpath = filepath.split("=")[1];
+	    updateMainPlayerUI(displayName,info,id, fileVpath);
+	    loadAndPlayAudioFile(filepath, !startPaused);
+	    if (!currentPlaying && !startPaused){
+	        setPlaying(true);
+	    }
+		playingFileDetail = [parseInt(id),filepath];
+
+		//If the user play this file, assume the next file to be added to playlist is this file
+		playlistAddPendingFile = filepath;
+	    //Have a backup of the current list just incase the user open another directory while a list is playing
+		//Only backup when it is not call from dropdown list
+		if (!$(object).parent().hasClass("dropdownList")){
+			playingList = Array.from(displayList);
+			pagingEnableForPlayingList = pagingEnabled;
+			currentPlayingPage = currentPage;
+		}
+	    parsePlayingSongList();
+	    if ($("#miniPlayer").hasClass("hidden")){
+	        //This is the first song that has played after the UI init
+	        $("#miniPlayer").css("display","none").removeClass("hidden").slideDown();
+	    }
+	    showMainPlayerInterface();
+	    
+	    //Just in case the albumn image changed, albumn art css is also updated.
+	    resizeQuickAdjust();
+
+		updateStateReferingURL();
+		highLightPlayingMusic();
+	}
+
+	function loadThumbnailToMusicList(selector = ".mainList.file.item"){
+		$(selector).each(function(){
+			let filepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
+			let thisFileItemID = $(this).attr("id");
+			let rawname = JSON.parse(decodeURIComponent($(this).attr("rawname")));
+			
+			let realVpath = filepath.split("=");
+			realVpath.shift();
+			realVpath = realVpath.join("=");
+			//console.log(thisFileItemID, realVpath, rawname);
+			//Load the thumbnail for this item in list
+			fetch("../system/file_system/loadThumbnail?vpath=" + encodeURIComponent(realVpath))
+			.then((response) => response.json())
+			.then((data) => {
+				if (data.error !== undefined || data.trim() == ""){
+					return;
+				}
+				$("#" + thisFileItemID).find("img").attr("src","data:image/jpg;base64," + data);
+				$(".dropdownList.file.item").each(function(){
+					var thisFilepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
+					if ($(this).attr("listid") == thisFileItemID && thisFilepath == filepath){
+						$(this).find("img").attr("src","data:image/jpg;base64," + data);
+					}
+				});
+			});
+			/*
+			ao_module_agirun("Music/functions/getThumbnail.js", {
+				file: realVpath,
+			}, function(data){
+				if (data.error !== undefined){
+
+				}else{
+					$("#" + thisFileItemID).find("img").attr("src","data:image/jpg;base64," + data);
+					$(".dropdownList.file.item").each(function(){
+						var thisFilepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
+						if ($(this).attr("listid") == thisFileItemID && thisFilepath == filepath){
+							$(this).find("img").attr("src","data:image/jpg;base64," + data);
+						}
+					})
+				}
+			});
+			*/
+		})
+	}
+
+	function loadThumbnail(filepath){
+		//Load the thumbnail
+		var realVpath = filepath.split("=");
+		realVpath.shift();
+		realVpath = realVpath.join("=");
+		ao_module_agirun("Music/functions/getThumbnail.js", {
+			file: realVpath,
+		}, function(data){
+			if (data.error !== undefined){
+				console.log(data.error)
+				$("#albumnArtImage").attr("src","img/default.png");
+				$("#smallPlayerThumb").attr("src","img/default.png");
+				if (navigator.mediaSession.metadata){
+					navigator.mediaSession.metadata.artwork = [
+						{ src: "img/default.png",   sizes: '512x512',   type: 'image/png' }
+					]
+				}
+			}else{
+				$("#albumnArtImage").attr("src","data:image/jpg;base64," + data);
+				$("#smallPlayerThumb").attr("src","data:image/jpg;base64," + data);
+				if (isAndroid && navigator.mediaSession.metadata){
+					//Android
+					navigator.mediaSession.metadata.artwork = [
+						{ src: "data:image/jpg;base64," + data,   sizes: '480x480',   type: 'image/jpg' }
+					]
+				}
+			}
+			resizeQuickAdjust();
+		});
+	}
+	
+	function nextSong(id = false,forcePlayEvenStopped = false){
+	    //Check if the current playlist has more than one songs.
+	    var currentPaused =  audioElement[0].paused;
+	    if (playingList.length > 1){
+	        var nextSongIndex = playingFileDetail[0];
+	        if (id != false){
+	            //Allow manual overwrite for this function
+	            nextSongIndex = id;
+	            var nextSong = playingList[nextSongIndex]; 
+	        }else{
+	           if (playingFileDetail[0] >= playingList.length){
+    	            var nextSong = playingList[0]; //Back to the first song in list
+    	            nextSongIndex = 0;
+    	        }else{
+    	             var nextSong = playingList[nextSongIndex]; //Index of the playList + 1 as the index for the files is alrady i+1. (User count from one)
+    	        } 
+	        }
+	        //The songs has to be play via background services instead of relying on DOM 
+	        var filepath = nextSong[0];
+    	    var rawname = nextSong[1];
+    	    var displayName = ao_module_codec.decodeUmFilename(rawname);
+    	    var info = nextSong[2] + " / " + nextSong[3];
+    	    var id = nextSongIndex + 1;
+    	    updateMiniPlayerUI(displayName,info,id);
+
+			//Seperate out the filepath without media server path
+			var fileVpath = filepath.split("=")[1];
+    	    updateMainPlayerUI(displayName,info,id, fileVpath);
+    	    if (forcePlayEvenStopped){
+    	        loadAndPlayAudioFile(filepath,true);
+    	    }else{
+    	       loadAndPlayAudioFile(filepath,!currentPaused); 
+    	    }
+    	    
+    	    if (currentPlaying){
+    	        setPlaying(true);
+    	    }
+    	    playingFileDetail = [id,filepath];
+    	    //Need not to update the playlist because it is the same
+			if (pagingEnabled){
+				var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
+				switchToPage(targetPageNumber, function(){
+					parsePlayingSongList();
+					highLightPlayingMusic();
+				});
+			}else{
+				highLightPlayingMusic();
+			}
+			
+			
+	    }else{
+	        //This is the only song in playlist. Play again from start
+	        audioElement[0].pause();
+	        audioElement[0].currentTime = 0;
+	        if (!currentPaused){
+	             audioElement[0].play();
+	        }
+	       
+	    }
+		updateStateReferingURL();
+	}
+	
+	function previousSong(){
+	    var currentPaused =  audioElement[0].paused;
+	    if (playingList.length > 1){
+	        var nextSongIndex = playingFileDetail[0] - 1;
+	        if (nextSongIndex == 0){
+	            nextSongIndex = playingList.length;
+	            var nextSong = playingList[nextSongIndex - 1]; //Back to the last song in list
+	        }else{
+	             var nextSong = playingList[playingFileDetail[0] - 2]; //Index of the playList - 1 as the index for the files is alrady i+1. (User count from one)
+	        }
+	        //The songs has to be play via background services instead of relying on DOM 
+	        var filepath = nextSong[0];
+    	    var rawname = nextSong[1];
+    	    var displayName = ao_module_codec.decodeUmFilename(rawname);
+    	    var info = nextSong[2] + " / " + nextSong[3];
+    	    var id = nextSongIndex;
+    	    updateMiniPlayerUI(displayName,info,id);
+
+			//Seperate out the filepath without media server path
+			var fileVpath = filepath.split("=")[1];
+    	    updateMainPlayerUI(displayName,info,id, fileVpath);
+    	    loadAndPlayAudioFile(filepath,!currentPaused);
+    	    if (currentPlaying){
+    	        setPlaying(true);
+    	    }
+    	    playingFileDetail = [id,filepath];
+    	    //Need not to update the playlist because it is the same
+    	    if (pagingEnabled){
+				var targetPageNumber = getPageNumberByPlaybackId(parseInt(id));
+				switchToPage(targetPageNumber, function(){
+					parsePlayingSongList();
+					highLightPlayingMusic();
+					
+				});
+			}else{
+				highLightPlayingMusic();
+			}
+	    }else{
+	        //This is the only song in playlist. Play again from start
+	        audioElement[0].pause();
+	        audioElement[0].currentTime = 0;
+	        audioElement[0].play();
+	    }
+		updateStateReferingURL();
+	}
+	
+	var originalVol = 0;
+	function togglePlayMode(){
+	    if (currentPlaying){
+	        originalVol = audioElement[0].volume;
+	        fadeAudio();
+	        setPlaying(false);
+	    }else{
+	        gainAudio();
+	        setPlaying(true);
+	    }
+	}
+
+
+	let audioTransitioning = false;
+	function fadeAudio(){
+		audioTransitioning = true;
+		if(audioElement[0].volume > 0){
+			var testval = audioElement[0].volume - 0.1;
+			audioElement[0].volume = Math.max(0,testval);
+			setTimeout(fadeAudio, 50);
+		}else{
+			audioElement[0].pause();
+			setTimeout(function(){
+				audioElement[0].volume = originalVol;
+				updateStateReferingURL();
+				audioTransitioning = false;
+			}, 100);
+		}
+	}
+    
+    
+    var targetVol = 0;
+    function gainAudio(){
+		targetVol = audioElement[0].volume;
+		audioElement[0].volume = 0;
+		setTimeout(function(){
+			audioElement[0].play();
+			recursiveGainAudio();
+		}, 100);
+    }
+    
+    function recursiveGainAudio(){
+		audioTransitioning = true;
+        if(audioElement[0].volume < targetVol){
+            if (audioElement[0].volume + 0.1 < 1){
+				audioElement[0].volume += 0.1
+			}else{
+				//Audio volume larger than 1, make it 1
+				audioElement[0].volume = 1
+			}
+            setTimeout(recursiveGainAudio, 50);
+        }else{
+            setTimeout(function(){
+                audioElement[0].volume = targetVol;
+				updateStateReferingURL();
+				audioTransitioning = false;
+            }, 100);
+        }
+    }
+	
+	//Update all icons on play and pause buttons
+	function setPlaying(playing){
+	    if (playing == true){
+	        $(".PlayButton").attr("class","pause icon whiteFont PlayButton");
+	        currentPlaying = true;
+	    }else{
+	        $(".PlayButton").attr("class","play icon whiteFont PlayButton");
+	        currentPlaying = false;
+	    }
+	}
+
+	function loadAndPlayAudioFile(sourceURL,playAfterLoad = true){
+		var audio = audioElement;
+
+		//These was added to fix the legacy file listing issue
+		var fd = sourceURL.split("=");
+		var rootPath = fd.shift();
+		var filename = fd.join("=");
+		var playbackURL = "../" + rootPath + "=" + encodeURIComponent(filename); //Convert absolute dir to relative
+		var ext = filename.split(".").pop();
+		if (dbExists){
+			cacheDbTx = cacheDb.transaction("files","readwrite");
+			cacheStore = cacheDbTx.objectStore("files");
+
+			let retrvReq = cacheStore.get(filename);
+			retrvReq.onsuccess = (event) => {
+				let cachefile = retrvReq.result;
+				if (cachefile == undefined || cachefile.content == undefined){
+					//No cache. Play from streaming and cache this
+					$("#mainAudioPlayer").attr("src", playbackURL);
+					startPlaybackAfterAudioLoaded(audio, playAfterLoad);
+
+					if (ext == "mp3"){
+						loadAudioFileURLAsBlob(playbackURL, function(fileBlob){
+							//Store the blob into indexDB
+							let cacheDbTx2 = cacheDb.transaction("files","readwrite");
+							let cacheStore2 = cacheDbTx2.objectStore("files");
+							cacheStore2.put({
+								"filename": filename,
+								"cachetime": parseInt(Date.now() / 1000),
+								"content": fileBlob
+							});
+						});
+					}
+					
+				}else{
+					//Cache exists. Load this instead
+					console.log("Loaded from cache ", filename)
+					let reader = new FileReader();
+					reader.onload = function(e) {
+						let srcUrl = e.target.result;
+						$("#mainAudioPlayer").attr("src", srcUrl);
+						startPlaybackAfterAudioLoaded(audio, playAfterLoad);
+					};
+					reader.readAsDataURL(cachefile.content);
+				}
+			}
+		}else{
+			//IndexedDB not found
+			$("#mainAudioPlayer").attr("src", playbackURL);
+			startPlaybackAfterAudioLoaded(audio, playAfterLoad);
+		}
+
+		loadThumbnail(sourceURL);
+	}
+
+	function startPlaybackAfterAudioLoaded(audio, playAfterLoad=true){
+		audio[0].pause();
+		audio[0].load();
+		if(playAfterLoad){
+			audio[0].oncanplaythrough = audio[0].play();
+		}else{
+			var currentTime = audioElement[0].currentTime;
+			var duration = audioElement[0].duration;
+			$('#audioProgressBar').css('width','0%');
+			updatePlaybackDisplayTime(currentTime,duration);
+		}
+	}
+	
+	function updateMiniPlayerUI(displayName, fileinfo,id){
+	    $("#miniPlayerDisplayName").text(displayName);
+	    $("#miniPlayerInformation").text(fileinfo);
+	    $("#miniPlayerIDtab").text(id + "/" + totalMusicCount);
+	}
+	
+	function updateMainPlayerUI(songname, fileinfo, id, filepath){
+	    $("#mainPlayerSongTitle").text(songname);
+	    $("#mainPlayerSongDesc").text(fileinfo);
+	    $("#mainPlayerMiniTab").text(id + "/" + totalMusicCount);
+		if ('mediaSession' in navigator){
+			var infoRewrite = fileinfo.split(" / ")
+			updateTitle(songname, infoRewrite[1] + " (" + infoRewrite[0] + ")", id + "/" + totalMusicCount, filepath);
+		}
+	}
+
+	
+	/*
+		Playlist related functions
+
+	*/
+
+	function renderPlaylistByName(listname){
+		$("#interfaceTitle").text(listname);
+		ao_module_agirun("Music/functions/playlist.js", {
+			opr: "list",
+			playlistname: listname
+		}, function(data){
+			$("#mainList").html("");
+			if (data.error !== undefined){
+				//This playlist no longer exists. Back to main
+				loadPlaylistView();
+			}else{
+				//Updat ethe global values
+				displayList = data;
+    	        totalMusicCount = data.length;
+				currentPath = listname;
+				//Add the back btn for back to playlist view
+				$("#mainList").append(`<div class="mainList item extrapadding" onClick="loadPlaylistView();">
+					<div class="ui header selectable" style="margin:0px !important;">
+						<i class="angle left icon whiteFont" style="overflow:hidden;"></i>
+						<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
+							../
+						</div>
+					</div>
+				</div>`);
+
+
+				//List the resulting song list 
+				for (var i = 0; i < data.length; i++){
+					var songInfo = data[i];
+					
+					$("#mainList").append(`<div class="mainList file item" filepath=${ao_module_utils.objectToAttr(songInfo[0])} id=${i+1} rawname=${ao_module_utils.objectToAttr(songInfo[1])}>
+						<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">
+							<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
+							<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">
+								${songInfo[1]}
+								<div class="sub header fileinfo" style="color: #c7c7c7;">${songInfo[2]} / ${songInfo[3]}</div>
+							</div>
+						</div>\
+						<div class="topRightCorner" align="center">
+							${i + 1}
+						</div>
+						<div class="mainList rightFunctionBar" type="file" align="center" onclick="showMore(this);">
+							<i class="ellipsis vertical icon" style="margin-top:1.2em;"></i>
+						</div>
+					</div>`);
+
+					//Update the interface Detail
+					$("#interfaceDetails").text("[" + data.length + " files]");
+				};
+
+
+				loadThumbnailToMusicList();
+				//Fix some legacy css isseus
+				$("#mainList").append("<br><br><br><br><br><br><br>");
+			}
+		});
+	}
+	//Open a given playlist
+	function openPlaylist(object){
+		var listname = $(object).attr("listname");
+		renderPlaylistByName(listname);
+	}
+
+	function addToNewPlaylist(){
+		var playlistname = prompt("Enter new playlist name");
+		if (playlistname != null && playlistname != ""){
+			//Add to playlist
+			addSongToPlayList(playlistname);
+		}else{
+			$("#succSnackBar").find(".content").html(`<i class="remove icon"></i> Invalid playlist name`);
+			$("#succSnackBar").slideDown("fast").delay(3000).slideUp("fast");
+			
+		}
+	}
+
+	function addToPlaylistFromMoreMenu(){
+		$(".showMoreMenus").fadeOut('fast');
+		$("#showmoreUIcover").fadeOut('fast');
+		showPlaylistInterface();
+	}
+
+	//Remove the curernt file from the current playlist
+	function removeFromPlylistFromMoreMenu(){
+		if (currentMode == "playlist"){
+			//Remvoe the playlistAddPendingFile
+			//In playlist mode, the currentPath is used to store the plylist name
+			ao_module_agirun("Music/functions/playlist.js", {
+			opr: "remove",
+			playlistname: currentPath,
+			musicpath: playlistAddPendingFile.replace("/media?file=","")
+			}, function(data){
+				if (data.error !== undefined){
+					alert(data.error);
+				}else{
+					//Removed. Reload playlist
+					renderPlaylistByName(currentPath);
+
+					//Hide the MoreMenu
+					hideShowMoreMenu();
+				}
+			});
+		}
+	}
+
+	function addSongToSelectedPlaylist(object){
+		var playlistName = $(object).attr("name").trim();
+		addSongToPlayList(playlistName);
+	}
+
+	function addSongToPlayList(listname){
+		//Get current music file name
+		var currentSongPath = "";
+		if (playlistAddPendingFile !== ""){
+			currentSongPath = playlistAddPendingFile.replace("/media?file=","");
+		}else{
+			$("#succSnackBar").find(".content").html(`<i class="remove icon"></i> No song selected`);
+			$("#succSnackBar").slideDown("fast").delay(3000).slideUp("fast");
+			return;
+		}
+		
+		//Add to playlist
+		ao_module_agirun("Music/functions/playlist.js", {
+			opr: "add",
+			playlistname: listname,
+			musicpath: currentSongPath
+		},function(data){
+			//Show success
+			$("#succSnackBar").find(".content").html(`<i class="checkmark icon"></i> Added to playlist ${listname}`);
+			$("#succSnackBar").slideDown("fast").delay(3000).slideUp("fast");
+
+			//Reload the playlist
+			initPlaylistInterfaceList();
+		});
+	}
+
+	//List the number of playlist stored in this database
+	function loadPlaylistView(){
+		currentMode = "playlist";
+		//Clear the main list
+		$("#mainList").html("");
+		togglePagingMode(false);
+		ao_module_agirun("Music/functions/playlist.js", {
+			opr: "root",
+		},function(data){
+			//Get the list of playlist
+			console.log(data);
+
+			//Render the elements
+			data.forEach(playlist => {
+				$("#mainList").append(`<div class="mainList item" listname="${playlist.name}" tag="playlist" onClick="openPlaylist(this);">
+					<div class="ui header selectable" style="margin:0px !important;" >
+						<img class="ui small image" src="img/list.svg" style="margin-right: 0.2em;"></img>
+						<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
+							${playlist.name}
+							<div class="sub header fileinfo" style="color: #c7c7c7;">[${playlist.count} files]</div>
+						</div>
+					</div>
+					<div class="mainList rightFunctionBar" tag="moreInfo" align="center" onClick="openPlaylist(this);">
+						<i class="chevron right icon" style="margin-top:1.2em;"></i>
+					</div>
+				</div>`);
+			});
+			hideLeftMenu();
+
+			//Update the headers
+			$("#interfaceTitle").text("Playlist");
+			$("#AMmenuIcon").attr("class","list icon large whiteFont");
+			$("#interfaceDetails").text("[" + data.length + " playlist]");
+		});
+		
+	}
+	
+	function loadFolderView(){
+		currentMode = "folder";
+	    currentPath = "";
+	    var tempalte = '<div class="mainList item" filepath={filepath} id={id} tag="folder" onClick="openFolder(this);">\
+        <div class="ui header selectable" style="margin:0px !important;" >\
+            <img class="ui small image" src="img/fo.svg" style="margin-right: 0.2em;"></img>\
+            <div class="content whiteFont" style="padding-top: 2px; line-height:1em;width : 80%; font-weight: lighter;">\
+                {foldername}\
+                <div class="sub header fileinfo" style="color: #c7c7c7;">{fileinfo}</div>\
+            </div>\
+        </div>\
+        <div class="mainList rightFunctionBar" tag="moreInfo" align="center" onClick="moreFolder(this);">\
+            <i class="chevron right icon" style="margin-top:1.2em;"></i>\
+        </div>\
+    </div>';
+        $("#interfaceTitle").text("Storage");
+		togglePagingMode(false);
+		$("#AMmenuIcon").attr("class","folder open icon large whiteFont");
+		ao_module_agirun("Music/functions/listSong.js", {
+			listdir: "root",
+		},function(data){
+	        $("#mainList").html("");
+	        for (var i =0; i < data.length; i++){
+	            var folderName = data[i][0];
+	            var folderPath = data[i][1];
+	            var fileCount = data[i][2];
+	            var folderCount = data[i][3];
+	            var box = tempalte;
+	            box = replaceAll("{filepath}",folderPath,box);
+				box = replaceAll("{id}",i + 1,box);
+				
+				if (folderName == ".cache" || folderName == ".trash"){
+					//Hidden folders
+					continue;
+				}
+	            if (folderPath.includes("/media")){
+	                //This is from external storage devices. List its number as well.
+	                var tmp = folderPath.split("/");
+	                var extStoragePath = "/" + tmp[1] + "/" + tmp[2];
+	                box = replaceAll("{foldername}",folderName + " ( " + extStoragePath + " )",box);
+	            }else{
+	                //This is directory inside normal folders. 
+	                box = replaceAll("{foldername}",folderName,box);
+	            }
+
+				/*
+				var fileinfo = fileinfo = "[No playable files]";
+				console.log(folderCount, fileCount);
+				if (folderCount > 0 && fileCount > 0){
+					fileinfo = "[" + fileCount + " files, " + folderCount  +" folders]"
+				}else if (fileCount > 0){
+					fileinfo = "[" + fileCount + " files]";
+				}else if (fileCount == -1 && folderCount == -1){
+					fileinfo = "";
+				}
+				*/
+				var fileinfo = folderPath;
+				
+	           
+	            box = replaceAll("{fileinfo}",fileinfo,box);
+				rootPaths.push(folderPath);
+	            $("#mainList").append(box);
+	        }
+	        $("#interfaceDetails").text("[" + data.length + " folders]");
+	    });
+	    hideLeftMenu();
+	}
+	
+	function isMobile(){
+		if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
+			return true
+		}
+		return false
+	}
+
+	function setWindowHash(hashValue){
+		hashValue = JSON.stringify(hashValue);
+
+		if (!isAndroid){
+			return;
+		}
+		
+		if(history.pushState) {
+			window.history.pushState(null, null, '#' + hashValue);
+		}else {
+			location.hash =  '#' + hashValue;
+		}
+		if(ao_module_virtualDesktop && !isMobile()){
+		    //Update the iframe src as well
+		    var newsrc =  window.frameElement.getAttribute("src");
+		    if (newsrc.includes("#")){
+		      newsrc = newsrc.split("#")
+		      newsrc.pop();
+		      newsrc = newsrc.join("#");
+		    }
+		    newsrc = newsrc + "#" + hashValue;
+		    $(window.frameElement).attr("src",newsrc);
+		    //console.log(window.frameElement.getAttribute("src"));
+		}
+	}
+
+	function updateStateReferingURL(){
+		var paused = audioElement[0].paused; //Check the current playing state of the player
+		setWindowHash({path: currentPath, pfp:playingFileDetail,pause:paused});
+	}
+	
+	function openFolder(object, playParameters=null){
+		var playIDAfterOpen = -1;
+		var startPaused = false;
+		if (playParameters !== null){
+			playIDAfterOpen = playParameters.playIDAfterOpen;
+			startPaused = playParameters.startPaused;
+		}
+	    var backbtnTemplate = '<div class="mainList item extrapadding" filepath={filepath} id={id} onClick="openFolder(this);">\
+        <div class="ui header selectable" style="margin:0px !important;">\
+            <i class="angle left icon whiteFont" style="overflow:hidden;"></i>\
+            <div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">\
+                ../\
+            </div>\
+        </div>\
+    </div>';
+	    
+	    var folderTemplate = '<div class="mainList item" filepath={filepath} tag="folder" id={id} onClick="openFolder(this);">\
+        <div class="ui header selectable" style="margin:0px !important;">\
+            <img class="ui small image" src="img/fo.svg" style="margin-right: 0.2em;"></img>\
+            <div class="content whiteFont" style="padding-top:2px;line-height:1em; width:80%; font-weight: lighter;">\
+                {foldername}\
+                <div class="sub header fileinfo" style="color: #c7c7c7;">{fileinfo}</div>\
+            </div>\
+        </div>\
+        <div class="mainList rightFunctionBar" type="folder" align="center">\
+            <i class="chevron right icon" style="margin-top:1.2em;"></i>\
+        </div>\
+    </div>';
+    var fileTemplate = `<div class="mainList file item" filepath={filepath} id={id} rawname={rawname}>\
+        <div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">\
+            <img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
+			<!-- <i class="music icon whiteFont" style="overflow:hidden;"></i> -->\
+            <div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">\
+                {songtitle}\
+                <div class="sub header fileinfo" style="color: #c7c7c7;">{ext} / {size}</div>\
+            </div>\
+        </div>\
+        <div class="topRightCorner" align="center">\
+            {id}\
+        </div>\
+        <div class="mainList rightFunctionBar" type="file" align="center">\
+            <i class="ellipsis vertical icon" style="margin-top:1.2em;"></i>\
+        </div>\
+    </div>`;
+
+        var targetPath = decodeURIComponent($(object).attr("filepath"));
+        if (targetPath == "root" || targetPath == "/"){
+            //User request to go back to storage root
+            loadFolderView();
+            return;
+        }
+		currentPath = targetPath.split("/./").join("/");
+		currentPath = currentPath.split("//").join("/");
+	    $("#interfaceTitle").text(ao_module_codec.decodeHexFoldername(targetPath.substring(0,targetPath.length -1).split("/").pop()));
+		var parentDir = currentPath.split("/");
+	    parentDir.pop();parentDir.pop();
+	    parentDir = (parentDir.join("/") + "/");
+	    //console.log(currentPath);
+		var backbtn;
+	    if (rootPaths.includes(currentPath) == false){
+	        //We are currently not at root
+	        backbtn = backbtnTemplate;
+            backbtn = replaceAll("{filepath}",encodeURIComponent(parentDir),backbtn);
+            backbtn = replaceAll("{id}",0,backbtn);
+	    }else{
+	        //Create a back button to go back to root of storage
+	        backbtn = backbtnTemplate;
+            backbtn = replaceAll("{filepath}","root",backbtn);
+            backbtn = replaceAll("{id}",0,backbtn);
+	    }
+	    
+	    //Request the server for a list of folders and file in this directory
+		ao_module_agirun("Music/functions/listSong.js", {
+			listdir: targetPath.split("//").join("/"),
+		},function(data){
+	        $("#mainList").html("");
+	        $("#mainList").append(backbtn);
+            if (Array.isArray(data)){
+                var folders = data[0];
+                var files = data[1];
+                //List all folders
+                for (var i =0; i < folders.length; i++){
+    	            var folderName = folders[i][0];
+    	            var folderPath = folders[i][1];
+    	            var fileCount = folders[i][2];
+    	            var folderCount = folders[i][3];
+					var box = folderTemplate;
+					if (folderName == ".cache" || folderName == ".trash"){
+						//Hidden folders
+						continue;
+					}
+    	            box = replaceAll("{filepath}",encodeURIComponent(folderPath),box);
+    	            box = replaceAll("{id}","folder-" + i + 1,box);
+    	            box = replaceAll("{foldername}",ao_module_codec.decodeHexFoldername(folderName),box);
+    	            var fileinfo = "[" + fileCount + " files]"
+    	            if (folderCount > 0){
+    	                fileinfo = "[" + fileCount + " files, " + folderCount  +" folders]"
+    	            }else if (folderCount == -1){
+						fileinfo = folderPath;
+					}
+    	            box = replaceAll("{fileinfo}",fileinfo,box);
+    	             $("#mainList").append(box);
+    	        }
+            
+
+                //List all files
+                for ( var i =0; i < files.length; i++){
+					var songInfo = files[i];
+    	            var path = songInfo[0];
+					var displayname = ao_module_codec.decodeUmFilename(songInfo[1]);
+    	            var ext = songInfo[2];
+    	            var size = songInfo[3];
+    	            var box = fileTemplate;
+    	            box = replaceAll("{filepath}",ao_module_utils.objectToAttr(path),box);
+    	            box = replaceAll("{id}",i + 1,box); //User count from 1
+    	            box = replaceAll("{rawname}",ao_module_utils.objectToAttr(songInfo[1]),box);
+    	            box = replaceAll("{songtitle}",displayname,box);
+    	            box = replaceAll("{ext}",ext,box);
+    	            box = replaceAll("{size}",size,box);
+    	            $("#mainList").append(box);
+    	        }
+    	        displayList = files;
+    	        totalMusicCount = files.length;
+    	        $("#mainList").append("<br><br><br><br><br><br><br>");
+                
+            }else{
+                //Something went wrong
+                //console.log('[AirMusic] Something went wrong: ' + data);
+				loadFolderView();
+				return;
+            }
+            if (folders.length > 0 && files.length > 0){
+                $("#interfaceDetails").text("[" + files.length + " files, " + folders.length+ " folders]");
+            }else if (folders.length > 0){
+                 $("#interfaceDetails").text("[" + folders.length + " folders]");
+            }else if (files.length > 0){
+                 $("#interfaceDetails").text("[" + files.length + " files]");
+            }else{
+                $("#interfaceDetails").text("[0 files or folders]");
+            }
+            //Hook all the events for the moreinfo on folders
+            hookMoreFolderInfoClickEvent();
+            
+            //Check if the current playing file is located inside this list. 
+            highLightPlayingMusic();
+
+			//Check if auto playback is required. If yes, play it with the given filepath.
+			if (playIDAfterOpen != -1){
+				$(".mainList.item").each(function(){
+					if ($(this).attr("id") == playIDAfterOpen){
+						//This is the file that require to playback after the folder loaded
+						playSong($(this).find(".ts.header.selectable"),startPaused);
+						setTimeout(resizeQuickAdjust,500);
+					}
+				});
+			}
+
+			//Load thumbnail for song in list
+			loadThumbnailToMusicList();
+	    });
+	}
+	
+	function moreInfo(object){
+		if ($(object).parent().attr('tag') == "folder"){
+			//This is a folder. Ask if play as playlist
+			alert("Folder playback work in progress");
+		}else{
+			showMore(object);
+		}
+	    
+	}
+	
+	function hookMoreFolderInfoClickEvent(){
+	    $(".mainList.rightFunctionBar").on("click", function(e){
+	        e.stopPropagation();
+	        moreInfo(this);
+	    });
+	}
+	
+	function highLightPlayingMusic(){
+	    //This function is used for highlighting the current playing music if the music piece is found inside the current list
+	    $(".mainList.item").removeClass("playingTrack");
+	    $(".mainList.item").each(function(){
+			var id = parseInt($(this).attr("id"));
+			try{
+				var filepath = ao_module_utils.attrToObject($(this).attr("filepath"));
+			}catch{
+				//Use back the previous method of filepath storage for compatibility
+				var filepath = $(this).attr("filepath");
+			}
+			
+			//Id is ignored in the 9/9/2019 updates and only check if the path matches.
+			if (filepath == playingFileDetail[1]){
+				$(this).addClass("playingTrack");
+			}
+	        //console.log([id,filepath], playingFileDetail);
+	    });
+
+		//Update dropdownList as well if exists
+		$(".dropdownList.item").removeClass("playingTrack");
+		$(".dropdownList.item").each(function(){
+			try{
+				var filepath = ao_module_utils.attrToObject($(this).attr("filepath"));
+			}catch{
+				//Use back the previous method of filepath storage for compatibility
+				var filepath = $(this).attr("filepath");
+			}
+	        //var filepath = $(this).attr("filepath");
+			if (filepath == playingFileDetail[1]){
+				$(this).addClass("playingTrack");
+			}
+		});
+	}
+	
+	function hideShowMoreMenu(){
+	    $(".showMoreMenus").fadeOut('fast');
+		$("#showmoreUIcover").fadeOut('fast');
+		
+		//Return the playlistAddPendingFile object back to the playing one
+		if (playingFileDetail !== undefined){
+			playlistAddPendingFile = playingFileDetail[1];
+		}else{
+			//No song is being play back
+			playlistAddPendingFile = "";
+		}
+		
+	}
+	
+	function playFromShowMoreMenu(){
+		nextSong(showMoreOprPlayID - 1);
+		$(".showMoreMenus").fadeOut('fast');
+	}
+
+	function showFileInfo(){
+	    $("#showFileInfo").show();
+	    $("#showMoreUI").hide();
+	}
+
+	function startRelatedSearch(){
+		enterSearchMode();
+		$("#searchInputBar").val(showMoreoprDisplayName);
+		$("#searchInputBar").focus();
+		hideShowMoreMenu();
+	}
+
+	function searchYoutubeViaShowMore(){
+		if (showMoreoprDisplayName != "" || showMoreoprDisplayName != undefined){
+			var filename = showMoreoprDisplayName;
+			searchOnYoutube(filename);
+		}
+	}
+	
+	var showMoreOprPlayID,showMoreOprFilepath, showMoreoprDisplayName;
+	function showMore(object){
+	    var filepath = $(object).parent().attr("filepath");
+		filepath = JSON.parse(decodeURIComponent(filepath));
+		//User want more action on this file. assume this is the file to add
+		playlistAddPendingFile = filepath;
+	    var id = $(object).parent().attr('id');
+	    var rawname = $(object).parent().attr("rawname");
+	    var displayName = JSON.parse(decodeURIComponent(ao_module_codec.decodeUmFilename(rawname)));
+	    //Update global variable for quick operations
+	    showMoreOprPlayID = id;
+	    showMoreOprFilepath = filepath;
+	    showMoreoprDisplayName = displayName; 
+	    $("#showMoreUI").find(".songTitle").text(displayName);
+	    $("#showMoreUI").find(".songID").text(id);
+	    $("#showFileInfo").find(".songTitle").text(displayName);
+	    $("#showMoreUI").fadeIn('fast');
+	    $("#showmoreUIcover").fadeIn('fast');
+	    //Update fileinformation as well
+		if (filepath.substring(0, 12) == "/media?file="){
+			filepath = filepath.substring(12);
+		}
+		
+		//Pre-render the file info
+		ao_module_agirun("Music/functions/getFileInfo.js", {
+			filepath: filepath,
+		}, function(data){
+			$("#showFileInfo").find(".filename").text(ao_module_codec.decodeUmFilename(data[0]));
+    		$("#showFileInfo").find(".rawname").text(data[0]);
+    		$("#showFileInfo").find(".filepath").text(data[1]);
+    		$("#showFileInfo").find(".filesize").text(data[2] + " (" + data[3] + " Bytes)");
+    		$("#showFileInfo").find(".filedate").text(data[4]);
+		});
+
+		if (currentMode != "playlist"){
+			$(".playlistonly").hide();
+		}else{
+			$(".playlistonly").show();
+		}
+	}
+
+	function playSongFromDropdownList(object){
+		//Play song from dropdown list. Hence, no need to update dropdownList
+		if ($(object).parent().hasClass("playingTrack")){
+			//This song already playing. Ignore play request.
+			return;
+		}
+
+		if (pagingEnableForPlayingList && $(object).attr("targetPage") != currentPlayingPage){
+			let newPage = parseInt($(object).attr("targetPage"));
+			if (!isNaN(newPage)){
+				currentPlayingPage = newPage;
+			}
+		}
+		playSong(object);
+		//Check if the song is also in main list. If yes, highlight it as well
+		/*
+		$(".mainList.item").each(function(){
+			if ($(this).attr("filepath") == $(object).parent().attr("filepath")){
+				$(".mainList.item.playingTrack").removeClass("playingTrack");
+				$(this).addClass("playingTrack");
+			}
+		});
+		*/
+		$("#dropdownSonglist").delay(500).slideUp();
+		highLightPlayingMusic();
+	}
+
+	//Move the playing song list into the dropdown song list. This list might not be the same as the one in the main list.
+	function parsePlayingSongList(){
+		$("#currentPlayingMainList").html("");
+		var counter = playingList.length;
+		var totalSize = 0.0;
+		var renderRange = [0, playingList.length];
+		var pageKeepRange = [0, playingList.length]
+		if (pagingEnableForPlayingList){
+			//Paging Enabled. Only show 1/2 max + current page song + 1/2 max
+			var startEndRange = getPageStartAndEndByPageNumber(currentPlayingPage, playingList);
+			startEndRange = [startEndRange[0] - pagingCutoffCount /2, startEndRange[1] + pagingCutoffCount / 2]
+			//console.log("DEFAULT START END RANGE", startEndRange)
+			//page keep range is the middle 1/2 number of songs, [1/4 => prev page][1/2][1/4 => next page]
+			pageKeepRange[0] = startEndRange[0] + pagingCutoffCount / 2;
+			pageKeepRange[1] = startEndRange[1] - pagingCutoffCount / 2;
+			
+			if (startEndRange[0] < 0){
+				startEndRange[0] = 0;
+			}
+
+			if (startEndRange[1] > playingList.length){
+				startEndRange[1] = playingList.length;
+			}
+
+			renderRange = startEndRange;
+			
+			
+
+			if (pageKeepRange[0] < 0){
+				pageKeepRange[0] = 0;
+			}
+			if (pageKeepRange[1] > playingList.length){
+				pageKeepRange[1] = playingList.length;
+			}
+			//console.log("KEEP RANGE", pageKeepRange);
+		}
+
+		for (var i = renderRange[0]; i < renderRange[1]; i++){
+			var displayname = ao_module_codec.decodeUmFilename(playingList[i][1]);
+			if (playingList[i][3].includes("MB")){
+				totalSize += parseFloat(playingList[i][3].split(" ")[0]);
+			}else if (playingList[i][3].includes("KB")){
+				totalSize += parseFloat(playingList[i][3].split(" ")[0]) / 1000;
+			}else if (playingList[i][3].includes("GB")){
+				totalSize += parseFloat(playingList[i][3].split(" ")[0]) * 1000;
+			}
+
+			//Get thumbnail from the current list to prevent re-loading form remote
+			let targetThumbnail = $("#" + (i + 1)).find("img").attr("src");
+			let opacityShowing = "";
+			let realVpath = playingList[i][0].split("=");
+			realVpath.shift();
+			realVpath = realVpath.join("=");
+
+			if ($("#" + (i + 1)).length == 0 && displayList.length == playingList.length){
+				//Item not exists
+				targetThumbnail = "img/eq.svg";
+				opacityShowing = "opacity: 0.6;"
+			}else if (pagingEnableForPlayingList){
+				if (i < pageKeepRange[0] || i > pageKeepRange[1]){
+					//Out of paging range. Do hidden display
+					targetThumbnail = "img/eq.svg";
+					opacityShowing = "opacity: 0.6;"
+				}else{
+					targetThumbnail = `../system/file_system/loadThumbnail?bytes=true&vpath=${encodeURIComponent(realVpath)}`;
+				}
+			}else{
+				//Non paging list. Always do all thumbnails.
+				targetThumbnail = `../system/file_system/loadThumbnail?bytes=true&vpath=${encodeURIComponent(realVpath)}`;
+			}
+
+			let targetPage = currentPlayingPage;
+			if (i < pageKeepRange[0]){
+				targetPage -= 1;
+			}
+			if (i > pageKeepRange[1]){
+				targetPage += 1;
+			}
+			
+		
+
+			$("#currentPlayingMainList").append(`<div class="dropdownList file item" style="${opacityShowing}" filepath="${ao_module_utils.objectToAttr(playingList[i][0])}" listid="${i + 1}" rawname="${ao_module_utils.objectToAttr(playingList[i][1])}">
+				<div class="ui header selectable" style="margin:0px !important;" onClick="playSongFromDropdownList(this);" targetPage="${targetPage}">
+					<img class="ui small image" src="${targetThumbnail}" onError="replaceImageToDefault(this);" style="margin-right: 0.2em;"></img>
+					<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%;">
+						<span style="font-weight: lighter;">${displayname}</span>
+						<div class="sub header fileinfo" style="color: #c7c7c7;">${playingList[i][2]} / ${playingList[i][3]}</div>
+					</div>
+				</div>
+				<div class="topRightCorner" align="center">
+					${i + 1}
+				</div>
+			</div>`);
+			$("#dropdownListSongCount").text(counter);
+			$("#dropdownListIDCount").text(parseInt(totalSize) + "");
+		}
+		$(".dropdownList.item").each(function(){
+			if ($(this).attr('filepath') == playingFileDetail[1]){
+				$(this).addClass("playingTrack");
+			}
+		});
+
+	}
+
+	function loadAudioFileURLAsBlob(url, callback){
+		var xhr = new XMLHttpRequest();
+		xhr.open('GET', url);
+		xhr.responseType = 'blob';
+		xhr.onload = function(e){
+			console.log("Buffer completed: ", url);
+			callback(xhr.response);
+		}
+		xhr.send();
+	}
+
+	//Clear all cached audio files
+	function clearAllCache(){
+		let dbtx = cacheDb.transaction("files","readwrite");
+		let fstore = dbtx.objectStore("files");
+		var clearReq = fstore.clear();
+		clearReq.onsuccess = function(e){
+			console.log("All cache file cleared");
+		}
+		
+	}
+
+	function getAllItems(callback) {
+		var trans = cacheDb.transaction("files", IDBTransaction.READ_ONLY);
+		var store = trans.objectStore("files");
+		var items = [];
+		trans.oncomplete = function(evt) {  
+			callback(items);
+		};
+		var cursorRequest = store.openCursor();
+		cursorRequest.onerror = function(error) {
+			console.log(error);
+		};
+		cursorRequest.onsuccess = function(evt) {                    
+			var cursor = evt.target.result;
+			if (cursor) {
+				items.push(cursor.value);
+				cursor.continue();
+			}
+		};
+	}
+
+
+	function replaceImageToDefault(target){
+		$(target).attr('src', "img/eq.svg");
+	}
+	
+	function loadSongList(type = "all"){
+		currentPath = "";
+		currentMode = "music";
+    
+        $("#interfaceTitle").text("Music");
+		$("#AMmenuIcon").attr("class","music icon large whiteFont")
+		
+		ao_module_agirun("Music/functions/listSong.js", {
+			listSong: type,
+		},function(data){
+			//Initialize the song list
+			displayList = data;
+			if (type == "all"){
+				//Caching is used in here
+				displayList = data.list;
+				if (data.cached == true){
+					//This is a cached version of the music list. 
+					console.log("Updating cached song list");
+					ao_module_agirun("Music/functions/buildCache.js", {}, function(data){
+						console.log("Cache updated: ", data);
+					});
+				}
+			}
+
+			//Updates 2022-07-12: Check if the list is too long. If yes, use paging
+			let renderRange = [0,displayList.length];
+
+			if (displayList.length > pagingCutoffCount){
+				togglePagingMode(true);
+				renderRange = [0, pagingCutoffCount];
+			}else{
+				togglePagingMode(false);
+			}
+
+			if (playingList == []){
+	            playingList = Array.from(displayList);
+				pagingEnableForPlayingList = pagingEnabled;
+				currentPlayingPage = currentPage;
+	        }
+
+			renderDisplayList(displayList,renderRange[0], renderRange[1] );
+
+	    }, function(){
+			alert("Failed to access listSong API with type: " + type)
+		});
+	    hideLeftMenu();
+	}
+
+	function renderDisplayList(displayList, start, end, callback=undefined){
+		$("#mainList").html("");
+		for ( var i =start; i < end; i++){
+	            var songInfo = displayList[i];
+	            var path = songInfo[0];
+	            var displayname = ao_module_codec.decodeUmFilename(songInfo[1]);
+	            var ext = songInfo[2];
+	            var size = songInfo[3];
+				$("#mainList").append(`<div class="mainList file item" filepath="${ao_module_utils.objectToAttr(path)}" id="${i + 1}" rawname="${ao_module_utils.objectToAttr(songInfo[1])}">
+					<div class="ui header selectable" style="margin:0px !important;" onClick="playSong(this);">
+						<img class="ui small image" src="img/eq.svg" style="margin-right: 0.2em;"></img>
+						<div class="content whiteFont" style="padding-top:5px;line-height:1em;width : 80%; font-weight: lighter;">
+							${displayname}
+							<div class="sub header fileinfo" style="color: #c7c7c7;">${ext} / ${size}</div>
+						</div>
+					</div>
+					<div class="topRightCorner" align="center">
+						${i + 1}
+					</div>
+					<div class="mainList rightFunctionBar" align="center" onClick="showMore(this);">
+						<i class="ellipsis vertical icon" style="margin-top:1.2em;"></i>\
+					</div>
+				</div>`);
+	        }
+
+			if (pagingEnabled){
+				//Append the page switch buttons
+				let numberOfPages = Math.ceil(parseFloat(displayList.length) / parseFloat(pagingCutoffCount));
+				let pageSelector  = ``;
+				for (var i = 0; i < numberOfPages; i++){
+					let disabled = "";
+					if (i == currentPage){
+						disabled = "disabled";
+					}
+					pageSelector = pageSelector + `<button id="pagebtn_${i}" onclick="switchToPage(${i});" class="pagebtn noborderbtn inverted basic ui icon button ${disabled}" style="box-shadow: none !important; -webkit-box-shadow: none !important;">
+										${i + 1}
+									</button>`;
+				}
+				$("#mainList").append(`<div class="mainList item" style="cursor: unset;">
+					<div>${pageSelector}</div>	
+				</div>`);
+			}
+
+
+	        totalMusicCount = displayList.length;
+	        $("#mainList").append("<br><br><br><br><br><br><br>");
+	        $("#interfaceDetails").text("[" + totalMusicCount + " songs]");
+	        highLightPlayingMusic();
+
+			
+			//Load thumbnail for song in list
+			loadThumbnailToMusicList();
+
+			if (callback != undefined){
+				callback();
+			}
+	}
+
+	function switchToPage(pageNumber, callback=undefined){
+		if (!pagingEnabled){
+			return;
+		}
+
+		let thisCallback = callback;
+		if (pageNumber == currentPage){
+			//Already in that page
+			if (thisCallback != undefined){
+				callback();
+			}
+			return;
+		}
+
+		currentPage = pageNumber;
+
+		let startPage = pageNumber * pagingCutoffCount;
+		let endPage = startPage + pagingCutoffCount;
+		if (endPage > displayList.length){
+			endPage = displayList.length;
+		}
+
+		
+		if (thisCallback == undefined){
+			renderDisplayList(displayList, startPage, endPage, function(){
+				window.scrollTo(0, document.body.scrollHeight);
+			});
+		}else{
+			renderDisplayList(displayList, startPage, endPage,thisCallback);
+		}
+		
+	}
+
+	function getPageNumberByPlaybackId(id){
+		let numberOfPages = Math.ceil(parseFloat(displayList.length) / parseFloat(pagingCutoffCount));
+		let targetPageNo = Math.ceil(id / pagingCutoffCount) - 1;
+		return targetPageNo;
+	}
+
+	function getPageStartAndEndByPageNumber(pageNumber, targetList){
+		let startPage = pageNumber * pagingCutoffCount;
+		let endPage = startPage + pagingCutoffCount;
+		if (endPage > targetList.length){
+			endPage = targetList.length;
+		}
+
+		return [startPage, endPage];
+	}
+	
+	
+	function toggleLeftMenu(){
+		if (leftMenuShown){
+			$("#leftSideBar").animate({left: $("#leftSideBar").width() * -1}, 120,function(){
+				$("#leftSideBar").hide();
+			});
+			$("#sideBarCover").fadeOut();
+			leftMenuShown = false;
+		}else{
+			$("#leftSideBar").show();
+			$("#leftSideBar").animate({left:0}, 300);
+			$("#sideBarCover").fadeIn();
+			leftMenuShown = true;
+		}
+		
+	}
+	
+	function hideLeftMenu(){
+	    if (leftMenuShown){
+	        $("#leftSideBar").animate({left: $("#leftSideBar").width() * -1}, 120,function(){
+				$("#leftSideBar").hide();
+			});
+			$("#sideBarCover").fadeOut();
+			leftMenuShown = false;
+	    }
+	}
+	
+	function showFileInformation(){
+		ao_module_agirun("Music/functions/getFileInfo.js", {
+			filepath: playingFileDetail[1],
+		},function(data){
+			//console.log(data);
+			$("#settingInterface").hide();
+			$("#filepropInterface").show();
+			$("#filepropInterface").find(".filename").text(ao_module_codec.decodeUmFilename(data[0]));
+			$("#filepropInterface").find(".rawname").text(data[0]);
+			$("#filepropInterface").find(".filepath").text(data[1]);
+			$("#filepropInterface").find(".filesize").text(data[2] + " (" + data[3] + " Bytes)");
+			$("#filepropInterface").find(".filedate").text(data[4]);
+		});
+	}
+	
+	function resizeQuickAdjust(){
+	  //Resize the position of the leftMenu
+	  if (!leftMenuShown){
+		  $("#leftSideBar").css("left", $("#leftSideBar").width() * -1);
+	  }
+	  if ($("#playerInterface").offset().left != 0){
+	      $("#playerInterface").css("left",window.innerWidth);
+	  }
+
+	  $("#albumnArtImage").css("max-height",window.innerHeight - 255);
+
+	  setTimeout(function(){
+		$("#albumnArt").css({
+			"height": window.innerHeight - 255,
+			"top": (window.innerHeight / 2 -  $("#albumnArtImage").height()/2)
+		});
+	  },50);
+	 
+	
+	  
+	  //var imageTop = (window.innerHeight - 255 - $("#albumnArtImage").height()) / 2;
+	  //$("#albumnArtImage").css("top",imageTop + "px");
+	}
+	
+	function setStorage(configName,configValue){
+		ao_module_storage.setStorage("AirMusic",configName,configValue);
+		/*
+    	$.ajax({
+    	  type: 'GET',
+    	  url: "../system/file_system/preference",
+    	  data: {key: "AirMusic/" + 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: "AirMusic/" + configName},
+    	  success: function(data){
+				if (data.error !== undefined){
+					result = "";
+				}else{
+					result = data;
+				}
+			  },
+    	  error: function(data){result = "";},
+    	  async:false,
+    	  timeout: 3000
+    	});
+		return result;
+		*/
+
+		return ao_module_storage.loadStorage("AirMusic",configName);
+    }
+
+	
+	//Wipe controller for mobile users
+	$("#albumnArt")[0].addEventListener('touchstart', handleTouchStart, false);        
+    $("#albumnArt")[0].addEventListener('touchmove', handleTouchMove, false);
+    
+    var xDown = null;                                                        
+    var yDown = null;
+    
+    function getTouches(evt) {
+      return evt.touches ||             // browser API
+             evt.originalEvent.touches; // jQuery
+    }                                                     
+    
+    function handleTouchStart(evt) {
+        const firstTouch = getTouches(evt)[0];                                      
+        xDown = firstTouch.clientX;                                      
+        yDown = firstTouch.clientY;                                      
+    };                                                
+    
+    function handleTouchMove(evt) {
+        if ( ! xDown || ! yDown ) {
+            return;
+        }
+    
+        var xUp = evt.touches[0].clientX;                                    
+        var yUp = evt.touches[0].clientY;
+    
+        var xDiff = xDown - xUp;
+        var yDiff = yDown - yUp;
+    
+        if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/
+            if ( xDiff > 0 ) {
+                /* left swipe */ 
+                //Going to the next song
+                nextSong();
+            } else {
+                /* right swipe */
+                //Going back one song
+                previousSong();
+            }                       
+        } else {
+            if ( yDiff > 0 ) {
+                /* up swipe */ 
+            } else { 
+                /* down swipe */
+            }                                                                 
+        }
+        /* reset values */
+        xDown = null;
+        yDown = null;                                             
+    };
+	
+	//Handle audio progress to time conversion
+	function secondsToHms(d) {
+        d = Number(d);
+        var h = Math.floor(d / 3600);
+        var m = Math.floor(d % 3600 / 60);
+        var s = Math.floor(d % 3600 % 60);
+        
+        if (h > 0 && h < 10){
+            dh = "0" + h + ":";
+        }else if (h == 0){
+            dh = "";
+        }else{
+            dh = h + ":";
+        }
+        
+        if (m > 0 && m < 10){
+            dm = "0" + m + ":";
+        }else if (m == 0){
+            if (h > 0){
+                dm = "00:";
+            }else{
+                dm = "0:";
+            }
+        }else{
+            dm = m + ":";
+        }
+        
+        if (s > 0 && s < 10){
+            ds = "0" + s;
+        }else if (s == 0){
+            if (m > 0 || h > 0){
+                ds = "00";
+            }else{
+                ds = "00";
+            }
+        }else{
+            ds = s;
+        }
+        
+        return dh + dm + ds; 
+    }
+
+	//Handle window resize events
+	$(window).on("resize", function(){
+		resizeQuickAdjust();
+	});
+	
+	function AllQuickMenuHidden(){
+	    var result = true;
+	    $(".quickMenu").each(function(){
+	        if ( $(this).is(':visible') ){
+	            result = false;
+	        }
+	    });
+	    return result;
+	}
+	
+	
+	function AllSubMenuHidden(){
+	    var result = true;
+	    $(".showMoreMenus").each(function(){
+	        if ( $(this).is(':visible') ){
+	            result = false;
+	        }
+	    });
+	    return result;
+	}
+	
+	//Handle back button press on mobile devices
+    function handleBackButton() {
+        if (!AllQuickMenuHidden()){
+            hideAllquickMenu();
+            window.history.pushState({}, '');
+        }else if (mainPlayerShown()){
+            //Close the main Menu
+            hideMainPlayerInterface();
+            window.history.pushState({}, '');
+        }else if (!AllSubMenuHidden()){
+             $(".showMoreMenus").fadeOut('fast');
+             $("#showmoreUIcover").fadeOut('fast');
+             window.history.pushState({}, '');
+        }else{
+            window.history.back();
+        }
+        
+    }
+    window.addEventListener('popstate', handleBackButton);
+    window.history.pushState({}, '');
+</script>
+</body>
 </html>

+ 25 - 25
web/Music/manifest.json

@@ -1,26 +1,26 @@
-{
-  "name": "AirMusic",
-  "short_name": "AirMusic",
-  "icons": [{
-    "src": "img/pwa/128.png",
-      "sizes": "128x128",
-      "type": "image/png"
-    },{
-      "src": "img/pwa/192.png",
-      "sizes": "192x192",
-      "type": "image/png"
-    }, {
-      "src": "img/pwa/256.png",
-      "sizes": "256x256",
-      "type": "image/png"
-    }, {
-      "src": "img/pwa/512.png",
-      "sizes": "512x512",
-      "type": "image/png"
-    }],
-  "start_url": "index.html",
-  "display": "fullscreen",
-  "scope": "./",
-  "background_color": "#4b75ff",
-  "theme_color": "#4b75ff"
+{
+  "name": "AirMusic",
+  "short_name": "AirMusic",
+  "icons": [{
+    "src": "img/pwa/128.png",
+      "sizes": "128x128",
+      "type": "image/png"
+    },{
+      "src": "img/pwa/192.png",
+      "sizes": "192x192",
+      "type": "image/png"
+    }, {
+      "src": "img/pwa/256.png",
+      "sizes": "256x256",
+      "type": "image/png"
+    }, {
+      "src": "img/pwa/512.png",
+      "sizes": "512x512",
+      "type": "image/png"
+    }],
+  "start_url": "index.html",
+  "display": "standalone",
+  "scope": "./",
+  "background_color": "#4b75ff",
+  "theme_color": "#4b75ff"
 }