Эх сурвалжийг харах

Fixed height on many webapp windows

Toby Chui 2 жил өмнө
parent
commit
9438ae6edc
4 өөрчлөгдсөн 898 нэмэгдсэн , 898 устгасан
  1. 104 104
      module.util.go
  2. 749 749
      web/Music/embedded.html
  3. 23 23
      web/Music/init.agi
  4. 22 22
      web/Video/init.agi

+ 104 - 104
module.util.go

@@ -1,104 +1,104 @@
-package main
-
-import (
-	module "imuslab.com/arozos/mod/modules"
-)
-
-/*
-	MODULE UTIL HANDLER
-	This is a util module for doing basic registry works and < 20 line server side handling.
-
-	DO NOT USE THIS TO WRITE A NEW MODULE
-
-
-	>> Updates v1.112
-	This util functions will be deprecated before v1.120.
-	Please migrate all of the modules out as WebApps using agi interface
-*/
-
-//Register the utilities here
-
-func util_init() {
-	/*
-		ArOZ Video Player - The basic video player
-	*/
-	//Open Documents Viewer
-	moduleHandler.RegisterModule(module.ModuleInfo{
-		Name:         "Video Player",
-		Desc:         "Basic Video Player",
-		Group:        "Utilities",
-		IconPath:     "SystemAO/utilities/img/mediaPlayer.png",
-		Version:      "1.0",
-		SupportFW:    false,
-		SupportEmb:   true,
-		LaunchEmb:    "SystemAO/utilities/mediaPlayer.html",
-		InitEmbSize:  []int{720, 480},
-		SupportedExt: []string{".mp4", ".webm", ".ogv"},
-	})
-
-	/*
-		ArOZ Audio Player - Basic Audio File Player
-	*/
-	moduleHandler.RegisterModule(module.ModuleInfo{
-		Name:         "Audio Player",
-		Desc:         "Basic Audio Player",
-		Group:        "Utilities",
-		IconPath:     "SystemAO/utilities/img/audio.png",
-		Version:      "1.0",
-		SupportFW:    false,
-		SupportEmb:   true,
-		LaunchEmb:    "SystemAO/utilities/audio.html",
-		InitEmbSize:  []int{533, 144},
-		SupportedExt: []string{".mp3", ".wav", ".ogg", ".flac"},
-	})
-
-	/*
-		STL File Viewer - Plotted from ArOZ Online Beta
-	*/
-	moduleHandler.RegisterModule(module.ModuleInfo{
-		Name:         "STL Viewer",
-		Desc:         "3D Model Viewer for STL Files",
-		Group:        "Utilities",
-		IconPath:     "SystemAO/utilities/img/stlViewer.png",
-		Version:      "1.0",
-		SupportFW:    false,
-		SupportEmb:   true,
-		LaunchEmb:    "SystemAO/utilities/stlViewer.html",
-		InitEmbSize:  []int{720, 480},
-		SupportedExt: []string{".stl"},
-	})
-
-	/*
-		Gcode File Viewer - Plotted from ArOZ Online Beta
-	*/
-	moduleHandler.RegisterModule(module.ModuleInfo{
-		Name:         "Gcode Viewer",
-		Desc:         "Gcode Toolpath Viewer",
-		Group:        "Utilities",
-		IconPath:     "SystemAO/utilities/img/gcodeViewer.png",
-		Version:      "1.0",
-		SupportFW:    false,
-		SupportEmb:   true,
-		LaunchEmb:    "SystemAO/utilities/gcodeViewer.html",
-		InitEmbSize:  []int{720, 480},
-		SupportedExt: []string{".gcode", ".gco"},
-	})
-
-	/*
-		Gcode File Viewer - Plotted from ArOZ Online Beta
-	*/
-	moduleHandler.RegisterModule(module.ModuleInfo{
-		Name:         "Image Paste",
-		Desc:         "Paste image from clipboard to cloud storage",
-		Group:        "Utilities",
-		IconPath:     "SystemAO/utilities/img/ImagePaste.png",
-		Version:      "1.0",
-		StartDir:     "SystemAO/utilities/imgPaste.html",
-		SupportFW:    true,
-		SupportEmb:   false,
-		LaunchFWDir:  "SystemAO/utilities/imgPaste.html",
-		InitFWSize:   []int{720, 480},
-		SupportedExt: []string{".png", ".jpg", ".jpeg", ".webp"},
-	})
-
-}
+package main
+
+import (
+	module "imuslab.com/arozos/mod/modules"
+)
+
+/*
+	MODULE UTIL HANDLER
+	This is a util module for doing basic registry works and < 20 line server side handling.
+
+	DO NOT USE THIS TO WRITE A NEW MODULE
+
+
+	>> Updates v1.112
+	This util functions will be deprecated before v1.120.
+	Please migrate all of the modules out as WebApps using agi interface
+*/
+
+//Register the utilities here
+
+func util_init() {
+	/*
+		ArOZ Video Player - The basic video player
+	*/
+	//Open Documents Viewer
+	moduleHandler.RegisterModule(module.ModuleInfo{
+		Name:         "Video Player",
+		Desc:         "Basic Video Player",
+		Group:        "Utilities",
+		IconPath:     "SystemAO/utilities/img/mediaPlayer.png",
+		Version:      "1.0",
+		SupportFW:    false,
+		SupportEmb:   true,
+		LaunchEmb:    "SystemAO/utilities/mediaPlayer.html",
+		InitEmbSize:  []int{720, 500},
+		SupportedExt: []string{".mp4", ".webm", ".ogv"},
+	})
+
+	/*
+		ArOZ Audio Player - Basic Audio File Player
+	*/
+	moduleHandler.RegisterModule(module.ModuleInfo{
+		Name:         "Audio Player",
+		Desc:         "Basic Audio Player",
+		Group:        "Utilities",
+		IconPath:     "SystemAO/utilities/img/audio.png",
+		Version:      "1.0",
+		SupportFW:    false,
+		SupportEmb:   true,
+		LaunchEmb:    "SystemAO/utilities/audio.html",
+		InitEmbSize:  []int{533, 164},
+		SupportedExt: []string{".mp3", ".wav", ".ogg", ".flac"},
+	})
+
+	/*
+		STL File Viewer - Plotted from ArOZ Online Beta
+	*/
+	moduleHandler.RegisterModule(module.ModuleInfo{
+		Name:         "STL Viewer",
+		Desc:         "3D Model Viewer for STL Files",
+		Group:        "Utilities",
+		IconPath:     "SystemAO/utilities/img/stlViewer.png",
+		Version:      "1.0",
+		SupportFW:    false,
+		SupportEmb:   true,
+		LaunchEmb:    "SystemAO/utilities/stlViewer.html",
+		InitEmbSize:  []int{720, 500},
+		SupportedExt: []string{".stl"},
+	})
+
+	/*
+		Gcode File Viewer - Plotted from ArOZ Online Beta
+	*/
+	moduleHandler.RegisterModule(module.ModuleInfo{
+		Name:         "Gcode Viewer",
+		Desc:         "Gcode Toolpath Viewer",
+		Group:        "Utilities",
+		IconPath:     "SystemAO/utilities/img/gcodeViewer.png",
+		Version:      "1.0",
+		SupportFW:    false,
+		SupportEmb:   true,
+		LaunchEmb:    "SystemAO/utilities/gcodeViewer.html",
+		InitEmbSize:  []int{720, 500},
+		SupportedExt: []string{".gcode", ".gco"},
+	})
+
+	/*
+		Gcode File Viewer - Plotted from ArOZ Online Beta
+	*/
+	moduleHandler.RegisterModule(module.ModuleInfo{
+		Name:         "Image Paste",
+		Desc:         "Paste image from clipboard to cloud storage",
+		Group:        "Utilities",
+		IconPath:     "SystemAO/utilities/img/ImagePaste.png",
+		Version:      "1.0",
+		StartDir:     "SystemAO/utilities/imgPaste.html",
+		SupportFW:    true,
+		SupportEmb:   false,
+		LaunchFWDir:  "SystemAO/utilities/imgPaste.html",
+		InitFWSize:   []int{720, 500},
+		SupportedExt: []string{".png", ".jpg", ".jpeg", ".webp"},
+	})
+
+}

+ 749 - 749
web/Music/embedded.html

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

+ 23 - 23
web/Music/init.agi

@@ -1,24 +1,24 @@
-/*
-	Music Module Register Script
-*/
-
-//Setup the module information
-var moduleLaunchInfo = {
-    Name: "Music",
-	Desc: "The best music player in ArOZ Online",
-	Group: "Media",
-	IconPath: "Music/img/module_icon.png",
-	Version: "0.1.0",
-	StartDir: "Music/index.html",
-	SupportFW: true,
-	LaunchFWDir: "Music/index.html",
-	SupportEmb: true,
-	LaunchEmb: "Music/embedded.html",
-	InitFWSize: [475, 700],
-	InitEmbSize: [360, 240],
-	SupportedExt: [".mp3",".flac",".wav",".ogg",".aac",".webm",".mp4"]
-}
-
-
-//Register the module
+/*
+	Music Module Register Script
+*/
+
+//Setup the module information
+var moduleLaunchInfo = {
+    Name: "Music",
+	Desc: "The best music player in ArOZ Online",
+	Group: "Media",
+	IconPath: "Music/img/module_icon.png",
+	Version: "0.1.0",
+	StartDir: "Music/index.html",
+	SupportFW: true,
+	LaunchFWDir: "Music/index.html",
+	SupportEmb: true,
+	LaunchEmb: "Music/embedded.html",
+	InitFWSize: [475, 720],
+	InitEmbSize: [360, 260],
+	SupportedExt: [".mp3",".flac",".wav",".ogg",".aac",".webm",".mp4"]
+}
+
+
+//Register the module
 registerModule(JSON.stringify(moduleLaunchInfo));

+ 22 - 22
web/Video/init.agi

@@ -1,23 +1,23 @@
-/*
-	Video Module Register Script
-*/
-
-//Setup the module information
-var moduleLaunchInfo = {
-    Name: "Video",
-	Desc: "The basic video player for ArOZ Online",
-	Group: "Media",
-	IconPath: "Video/img/module_icon.png",
-	Version: "0.0.6",
-	StartDir: "Video/index.html",
-	SupportFW: true,
-	LaunchFWDir: "Video/index.html",
-	SupportEmb: true,
-	LaunchEmb: "Video/embedded.html",
-	InitFWSize: [585, 820],
-	InitEmbSize: [700, 470],
-	SupportedExt: [".webm",".mp4",".ogg"]
-}
-
-//Register the module
+/*
+	Video Module Register Script
+*/
+
+//Setup the module information
+var moduleLaunchInfo = {
+    Name: "Video",
+	Desc: "The basic video player for ArOZ Online",
+	Group: "Media",
+	IconPath: "Video/img/module_icon.png",
+	Version: "0.0.6",
+	StartDir: "Video/index.html",
+	SupportFW: true,
+	LaunchFWDir: "Video/index.html",
+	SupportEmb: true,
+	LaunchEmb: "Video/embedded.html",
+	InitFWSize: [585, 840],
+	InitEmbSize: [700, 430],
+	SupportedExt: [".webm",".mp4",".ogg"]
+}
+
+//Register the module
 registerModule(JSON.stringify(moduleLaunchInfo));