music.html 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. <!DOCTYPE html>
  2. <meta name="apple-mobile-web-app-capable" content="yes" />
  3. <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
  4. <html>
  5. <head>
  6. <title>Music Player</title>
  7. <meta charset="UTF-8">
  8. <meta name="theme-color" content="#232324">
  9. <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  10. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css" />
  11. <script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.js"></script>
  12. <style>
  13. body{
  14. padding:0px !important;
  15. overflow: hidden;
  16. height:100%;
  17. background-color: #f2f2f2;
  18. }
  19. .coloredBackground{
  20. background: rgb(253,255,254);
  21. background: linear-gradient(321deg, rgba(253,255,254,1) 29%, rgba(240,250,255,1) 100%);
  22. }
  23. html, body { height: 100%; width: 100%; margin: 0; }
  24. .playerInterface{
  25. background-color:rgba(226, 221, 220,0.95);
  26. height:150px !important;
  27. width:100%;
  28. }
  29. #playerUI{
  30. margin-left:0px !important;
  31. margin-right:0px !important;
  32. width:100% !important;
  33. position: relative;
  34. color: #404147;
  35. background: rgb(255,255,255);
  36. background: linear-gradient(90deg, rgba(255,255,255,1) 13%, rgba(227,228,246,1) 84%);
  37. overflow: hidden;
  38. }
  39. .parkLeft{
  40. position:absolute !important;
  41. top:70px;
  42. left:5px;
  43. margin-left:-30px;
  44. }
  45. .rotateNinetyDegree{
  46. -webkit-transform: rotate(-90deg);
  47. -moz-transform: rotate(-90deg);
  48. -o-transform: rotate(-90deg);
  49. -ms-transform: rotate(-90deg);
  50. transform: rotate(-90deg);
  51. }
  52. .roundbtn{
  53. border-radius: 40px !important;
  54. box-shadow: 2px 2px 2px 2px #bfbfbf;
  55. }
  56. .playBtn{
  57. color: white !important;
  58. transition: opacity 0.1s;
  59. }
  60. #playpauseBtn{
  61. width: 66px;
  62. height: 66px;
  63. }
  64. .playerControlWrapper .sidebuttons{
  65. background-color: white !important;
  66. }
  67. .playerControlWrapper .white.icon.button:hover{
  68. opacity: 0.6;
  69. }
  70. .playerControlWrapper{
  71. text-align: center;
  72. position:absolute;
  73. margin-top: 3rem;
  74. width:100% !important;
  75. }
  76. .rightPaddedOprButtons{
  77. position:absolute;
  78. right:3px;
  79. top:3px;
  80. }
  81. .modeEnabled{
  82. background-color: #186ed2 !important;
  83. color:white !important;
  84. border: 0px solid transparent !important;
  85. }
  86. #volControlOverlay{
  87. background-color: rgba(255,255,255,0.01);
  88. z-index:999;
  89. position:absolute;
  90. width:14px;
  91. height:120px;
  92. top:17px;
  93. left:28px;
  94. }
  95. .songlabel{
  96. padding-right:3px;
  97. position:absolute;
  98. display:inline-box;
  99. left:5px;
  100. top:5px;
  101. color:#77767b;
  102. height:22px;
  103. text-overflow: ellipsis;
  104. overflow: hidden;
  105. width: 100%;
  106. white-space: nowrap;
  107. font-weight: bold;
  108. }
  109. .durationDisplay{
  110. position:absolute;
  111. right:0px;
  112. bottom:0px;
  113. padding-right:5px;
  114. padding-bottom:5px;
  115. margin: 0px !important;
  116. color: #77767b;
  117. }
  118. .bottomBackground{
  119. background: rgb(255,255,255);
  120. background: linear-gradient(90deg, rgba(255,255,255,1) 13%, rgba(227,228,246,1) 84%);
  121. position:relative;
  122. height:58px;
  123. width:100%;
  124. }
  125. .sameDirFileList{
  126. width:100%;
  127. height:calc(100% - 220px) !important;
  128. background-color:rgba(243, 243, 243, 0.95);
  129. overflow-y:auto;
  130. overflow-x:hidden;
  131. }
  132. #nearbyFilelist{
  133. background: white !important;
  134. }
  135. @supports ((-webkit-backdrop-filter: blur(2em)) or (backdrop-filter: blur(2em))) {
  136. .sameDirFileList {
  137. background-color:rgba(240, 240, 240, 0.5);
  138. -webkit-backdrop-filter: blur(2em);
  139. backdrop-filter: blur(2em);
  140. }
  141. }
  142. .listitem{
  143. border-bottom: 1px solid #404040;
  144. padding: 12px;
  145. color:rgb(51, 51, 51);
  146. font-size:120%;
  147. cursor:pointer;
  148. }
  149. .listitem:hover{
  150. background-color:#e3e4f6;
  151. }
  152. .listitem.selected{
  153. background-color:#e3e4f6;
  154. }
  155. .noradius{
  156. border-radius: 0px !important;
  157. }
  158. #playerWrapper{
  159. width: 100%;
  160. height: 100%;
  161. }
  162. @media (min-width:600px) {
  163. #playerWrapper{
  164. border-radius: 0.6em;
  165. overflow: hidden;
  166. margin-top: 2em;
  167. height: calc(100% - 4em);
  168. max-width: 500px;
  169. margin-left: 50%;
  170. transform: translate(-50%, 0%);
  171. -webkit-box-shadow: 10px 10px 5px -4px rgba(28,28,28,0.1);
  172. -moz-box-shadow: 10px 10px 5px -4px rgba(28,28,28,0.1);
  173. box-shadow: 10px 10px 5px -4px rgba(28,28,28,0.1);
  174. }
  175. }
  176. </style>
  177. </head>
  178. <body align="center">
  179. <diV id="playerWrapper" align="left">
  180. <div id="playerUI" class="playerInterface ui container">
  181. <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;">
  182. <div class="parkLeft">
  183. <div class="ui primary small progress rotateNinetyDegree" style="width:120px !important; background-color: white;">
  184. <div id="volControl" class="bar" style="min-width: 0%; width: 60%;background-color:#4576c5;"></div>
  185. </div>
  186. </div>
  187. <div id="volControlOverlay"></div>
  188. <div class="playerControlWrapper" align="center">
  189. <button class="ui white huge icon button sidebuttons roundbtn playlistStepBtn" onClick="lastSong();"><i class="step backward icon"></i></button>
  190. <button id="playpauseBtn" style="background-color:#186ed2;" class="ui white massive icon button roundbtn playBtn" onClick="togglePlay(this);"><i class="pause icon"></i></button>
  191. <button class="ui huge white icon button sidebuttons roundbtn playlistStepBtn" onClick="nextSong();"><i class="step forward icon"></i></button>
  192. </div>
  193. <div class="rightPaddedOprButtons">
  194. <button id="repeatModeBtn" class="ui icon button" style="margin-top:0.6em; margin-right: 0.6em;" onClick="toggleRepeat(this);"><i class="retweet icon"></i></button><br>
  195. </div>
  196. <!-- Adding in some labels for the progress bars and song information-->
  197. <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>
  198. <p class="durationDisplay">0:00 / 0:00</p>
  199. </div>
  200. <div id="progressControl" class="ui attached small progress" style="height: 0.8rem; background: rgba(255,255,255,0.8);">
  201. <div id="playbackProgress" class="bar" style="min-width: 0%; width: 0%;background-color: #4576c5; "></div>
  202. </div>
  203. <div class="bottomBackground" >
  204. <!-- Song Title at the bottom black area-->
  205. <div id="songtitle" class="songlabel">Loading Song Information</div>
  206. <div id="fileSize" style="position:absolute;bottom:5px;left:5px;color:#77767b;"><i class="file outline icon"></i> 0.0 MB</div>
  207. <div style="position:absolute;right:3px;bottom:3px;color:#77767b;"><i class='leaf icon'></i>AirMusic</div>
  208. </div>
  209. <!-- The sections below are for mobile interfaces -->
  210. <div id="nearbyFilelist" class="sameDirFileList">
  211. <div class="listitem" onClick="playThis(this);"><div style="width: 100%; text-align: center;"><i class="ui loading spinner icon"></i></div></div>
  212. </div>
  213. <!-- autoplay -->
  214. <audio id="mainPlayer" style="display:none;" preload="auto" autoplay></audio>
  215. <div style="display:none;">
  216. <div id="meta_dirSongList"></div>
  217. <div id="meta_playingSong"></div>
  218. </div>
  219. </diV>
  220. <script>
  221. var jsmediatags = window.jsmediatags;
  222. function loadInputFiles(){
  223. try{
  224. if (window.location.hash.length == 0){
  225. return null;
  226. }
  227. var inputFileInfo = window.location.hash.substring(1,window.location.hash.length);
  228. inputFileInfo = JSON.parse(decodeURIComponent(inputFileInfo));
  229. if (inputFileInfo.length == 0){
  230. return null;
  231. }
  232. return inputFileInfo
  233. }catch{
  234. return null;
  235. }
  236. }
  237. //Define global variables
  238. var player = $("#mainPlayer")[0];
  239. var mediaExchanging = false;
  240. var listShown = true;
  241. //Override VDI mode from ArozOS desktop
  242. player.volume = getCurrentGlobVol();
  243. $("#nearbyFilelist").addClass("coloredBackground");
  244. //Ignore all other input files.
  245. var playingFileInfo = loadInputFiles();
  246. //Get the song title and meta data from server
  247. var songInfo = [];
  248. var songList = [];
  249. if (playingFileInfo.filepath != undefined){
  250. player.src = "/api/fs/download?preview=true&file=" + playingFileInfo.filepath;
  251. }
  252. if (playingFileInfo.filename != undefined){
  253. document.title = "Playing - " + (playingFileInfo.filename);
  254. }
  255. //Populate the file info
  256. $.get("/api/fs/properties?file=" + playingFileInfo.filepath, function(data){
  257. if (data.error == undefined){
  258. updateDisplayInformation(data.filename, humanFileSize(data.filesize));
  259. updatePlayerThemeAndBackground(data.filepath);
  260. }
  261. });
  262. let parentDir = playingFileInfo.filepath.split("/");
  263. parentDir.pop();
  264. parentDir = parentDir.join("/");
  265. $.get("/api/fs/list?dir=" + parentDir, function(data){
  266. if (data.error == undefined){
  267. //Build songlist from dirlist
  268. let newSongList = [];
  269. data.forEach(function(fileEntry){
  270. let ext = fileEntry.Filename.split(".").pop();
  271. if (ext == "mp3" || ext == "aac" || ext == "ogg"){
  272. newSongList.push([fileEntry.Filename, parentDir + "/" + fileEntry.Filename, "." + ext, humanFileSize(fileEntry.Filesize)]);
  273. }
  274. });
  275. songList = newSongList;
  276. //Create the playlist for all the files in the same directory
  277. createPlayList();
  278. //Initiate the current playSong in the songList
  279. updatePlayingSongSelection();
  280. }
  281. });
  282. function humanFileSize(bytes, si=true, dp=1) {
  283. const thresh = si ? 1000 : 1024;
  284. if (Math.abs(bytes) < thresh) {
  285. return bytes + ' B';
  286. }
  287. const units = si
  288. ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
  289. : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
  290. let u = -1;
  291. const r = 10**dp;
  292. do {
  293. bytes /= thresh;
  294. ++u;
  295. } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
  296. return bytes.toFixed(dp) + ' ' + units[u];
  297. }
  298. //Get the song title from meta data
  299. //var songInfo = JSON.parse($("#meta_playingSong").text().trim());
  300. //var songList = JSON.parse($("#meta_dirSongList").text().trim());
  301. //Define supporting function for trunc.
  302. String.prototype.trunc = String.prototype.trunc ||
  303. function(n){
  304. return (this.length > n) ? this.substr(0, n-1) + '&hellip;' : this;
  305. };
  306. //Setup listen events to global volume
  307. setInterval(function(){
  308. var globvol = getCurrentGlobVol();
  309. updateVolControlDisplay(globvol);
  310. player.volume = globvol;
  311. if (player.paused == true){
  312. //Check if anytime that the button UI is not in sync with the current playing status. Update it if found.
  313. $(".playBtn").html("<i class='play icon'></i>");
  314. }else{
  315. $(".playBtn").html("<i class='pause icon'></i>");
  316. }
  317. },1000);
  318. updateVolControlDisplay(getCurrentGlobVol());
  319. //Add volume bar change event listener
  320. $("#volControlOverlay").on("click",function(e){
  321. var x = e.pageX - $('#volControlOverlay').offset().left;
  322. var y = e.pageY - $('#volControlOverlay').offset().top;
  323. var height = $('#volControlOverlay').height();
  324. var newvol = Math.round(((height - y) / height)*20)/20;
  325. localStorage.setItem("global_volume",newvol);
  326. player.volume = newvol;
  327. updateVolControlDisplay(newvol);
  328. });
  329. //Also add draging bar for mouse operations
  330. player.onended = function(){
  331. if (!repeatMode){
  332. $(".playBtn").html("<i class='play icon'></i>");
  333. }
  334. }
  335. var dragging = false;
  336. $("#volControlOverlay").on("mousedown",function(){
  337. dragging = true;
  338. });
  339. $("#volControlOverlay").on("mousemove",function(e){
  340. if (dragging){
  341. var y = e.pageY - $('#volControlOverlay').offset().top;
  342. var height = $('#volControlOverlay').height();
  343. var newvol = Math.round(((height - y) / height)*100)/100;
  344. //console.log(newvol);
  345. localStorage.setItem("global_volume",newvol);
  346. player.volume = newvol;
  347. updateVolControlDisplay(newvol);
  348. }
  349. });
  350. $("#volControlOverlay").on("mouseup",function(){
  351. if (dragging){
  352. dragging = false;
  353. }
  354. });
  355. $("body").on("mouseup",function(){
  356. if (dragging){
  357. dragging = false;
  358. }
  359. });
  360. //Audio element custom UI listeners
  361. document.getElementById("progressControl").addEventListener("click",function(e){
  362. //Click on the progress control bar, update the audio playing location
  363. var x = e.pageX - $('#progressControl').offset().left;
  364. var w = $("#progressControl").width();
  365. var alength = player.duration;
  366. var targetPos = (x / w * alength);
  367. player.currentTime = targetPos;
  368. });
  369. player.addEventListener("timeupdate", function(){
  370. var currentTime = player.currentTime;
  371. var duration = player.duration;
  372. var progressPercentage = currentTime / duration * 100 + "%";
  373. $("#playbackProgress").css("width",progressPercentage);
  374. if (!mediaExchanging){
  375. updateDurationDisplay(currentTime,duration);
  376. }
  377. });
  378. //Load repeat mode from storage
  379. var repeatMode = false;
  380. repeatMode = loadStorage("repeatModeEmbedded");
  381. if (repeatMode != ""){
  382. repeatMode = (repeatMode == "true");
  383. }
  384. if (repeatMode){
  385. $("#repeatModeBtn").addClass("modeEnabled");
  386. player.loop = true;
  387. }
  388. //End of startup seuqence
  389. function updatePlayingSongSelection(){
  390. $(".listitem.selected").removeClass("selected");
  391. $(".listitem").each(function(){
  392. if ($(this).attr("filename") == songInfo[0]){
  393. $(this).addClass("selected");
  394. }
  395. });
  396. }
  397. function lastSong(){
  398. //Switch to the next song in list
  399. player.pause();
  400. mediaExchanging = true;
  401. $(".durationDisplay").html('<i class="clock icon"></i> Loading Media');
  402. var nextSong = -1; //There is no next song in the current directory
  403. for (var i =0; i < songList.length; i++){
  404. if (songList[i][0] == songInfo[0]){
  405. //Filename are the same
  406. if (i-1 < 0){
  407. //This is the last song in list
  408. nextSong = songList[songList.length - 1]
  409. }else{
  410. //Play previous song
  411. nextSong = songList[i-1]
  412. }
  413. }
  414. }
  415. if (nextSong == -1){
  416. //There is no more similar file with similar extensions or there are no other supported files in the same directory.
  417. player.currentTime = 0;
  418. updateDisplayInformation(songInfo[0],songInfo[3]);
  419. player.play();
  420. setTimeout(function(){
  421. mediaExchanging = false;
  422. },300);
  423. return;
  424. }
  425. loadSongFromSongInfo(nextSong);
  426. player.play();
  427. setTimeout(function(){
  428. mediaExchanging = false;
  429. },300);
  430. updatePlayingSongSelection();
  431. }
  432. function uuidv4() {
  433. return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
  434. (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  435. );
  436. }
  437. function createPlayList(){
  438. $(".sameDirFileList").html("");
  439. for (var i = 0; i < songList.length; i++){
  440. //console.log(box);
  441. let thisFileItemID = "thumb_" + uuidv4();
  442. $(".sameDirFileList").append(`<div class="listitem" filename="${songList[i][0]}" onClick="playThis(this);">
  443. <div class="ui unstackable grid">
  444. <div class="three wide column" align="right">
  445. <img id="${thisFileItemID}" class="ui image noradius" style="height: 2rem;" src="img/eq.svg">
  446. </div>
  447. <div class="thirteen wide column">
  448. ${songList[i][0]} (${songList[i][3]})
  449. </div>
  450. </div>
  451. </div>`);
  452. }
  453. }
  454. function playThis(object){
  455. var songName = $(object).attr("filename");
  456. $(".listitem.selected").removeClass("selected");
  457. $(object).addClass("selected");
  458. for (var i =0; i < songList.length; i++){
  459. if (songList[i][0] == songName){
  460. //This is the song that the user request to play.
  461. player.pause();
  462. mediaExchanging = true;
  463. $(".durationDisplay").html('<i class="clock icon"></i> Loading Media');
  464. loadSongFromSongInfo(songList[i]);
  465. player.play();
  466. setTimeout(function(){
  467. mediaExchanging = false;
  468. },300);
  469. break;
  470. }
  471. }
  472. }
  473. function nextSong(){
  474. //Switch to the next song in list
  475. player.pause();
  476. mediaExchanging = true;
  477. $(".durationDisplay").html('<i class="clock icon"></i> Loading Media');
  478. var nextSong = -1; //There is no next song in the current directory
  479. for (var i =0; i < songList.length; i++){
  480. if (songList[i][0] == songInfo[0]){
  481. //Filename are the same
  482. if (i+1 >= songList.length){
  483. //This is the last song in list
  484. nextSong = songList[0]
  485. }else{
  486. //Play next song
  487. nextSong = songList[i+1]
  488. }
  489. }
  490. }
  491. if (nextSong == -1){
  492. //There is no more similar file with similar extensions or there are no other supported files in the same directory.
  493. player.currentTime = 0;
  494. updateDisplayInformation(songInfo[0], songInfo[3]);
  495. player.play();
  496. setTimeout(function(){
  497. mediaExchanging = false;
  498. },300);
  499. return;
  500. }
  501. loadSongFromSongInfo(nextSong);
  502. player.play();
  503. setTimeout(function(){
  504. mediaExchanging = false;
  505. },300);
  506. updatePlayingSongSelection();
  507. }
  508. function blobToDataURL(blob, callback) {
  509. var a = new FileReader();
  510. a.onload = function(e) {callback(e.target.result);}
  511. a.readAsDataURL(blob);
  512. }
  513. function loadSongFromSongInfo(playSongInfo){
  514. var songName = playSongInfo[0];
  515. var songPath = playSongInfo[1];
  516. var fileSize = playSongInfo[3];
  517. $(player).attr('src',"/api/fs/download?preview=true&file=" + encodeURIComponent(songPath));
  518. document.title = "Playing - " + songName;
  519. songInfo = playSongInfo;
  520. updateDisplayInformation(songInfo[0] ,songInfo[3]);
  521. updatePlayerThemeAndBackground(songPath);
  522. }
  523. //Update the theme color, require something like { r: 231, g: 159, b: 140 }
  524. function updateThemeColor(newRGBColor){
  525. let colorText = `rgb(${newRGBColor.r} ,${newRGBColor.g} ,${newRGBColor.b})`
  526. $("#playbackProgress").css("background-color", colorText);
  527. $("#playpauseBtn").css("background-color", colorText);
  528. $("#volControl").css("background-color", colorText);
  529. $(".modeEnabled")[0].style.setProperty( "background-color", colorText, 'important' );
  530. //$(".sameDirFileList").css("background-color", `rgba(${newRGBColor.r}, ${newRGBColor.g}, ${newRGBColor.b}, 0.1)`);
  531. }
  532. function updateDisplayInformation(songname, filesize){
  533. $("#songtitle").html("<i class='music icon'></i>" + songname)
  534. $("#fileSize").html("<i class='file outline icon'></i> " + filesize);
  535. }
  536. function updateDurationDisplay(pos,dur){
  537. pos = secondsToHMS(pos);
  538. dur = secondsToHMS(dur);
  539. $(".durationDisplay").html(pos.trim() + " / " + dur.trim());
  540. }
  541. function secondsToHMS(sec){
  542. let totalSeconds = sec;
  543. let hours = Math.floor(totalSeconds / 3600);
  544. totalSeconds %= 3600;
  545. let minutes = Math.floor(totalSeconds / 60);
  546. let seconds = totalSeconds % 60;
  547. if (hours > 0){
  548. hours = String(hours).padStart(2, "0");
  549. }else{
  550. hours = 0;
  551. }
  552. seconds = Math.round(seconds);
  553. minutes = String(minutes).padStart(2, "0");
  554. seconds = String(seconds).padStart(2, "0");
  555. if (hours != 0){
  556. return hours + ":" + minutes + ":" + seconds;
  557. }else{
  558. return minutes + ":" + seconds;
  559. }
  560. }
  561. function togglePlay(object){
  562. if (player.paused == true){
  563. player.play();
  564. $(object).html("<i class='pause icon'></i>");
  565. }else{
  566. player.pause();
  567. $(object).html("<i class='play icon'></i>");
  568. }
  569. }
  570. function toggleRepeat(object){
  571. if ($(object).hasClass("modeEnabled")){
  572. $(object).removeClass("modeEnabled");
  573. repeatMode = false;
  574. setStorage("repeatModeEmbedded","false");
  575. player.loop = false;
  576. }else{
  577. $(object).addClass("modeEnabled");
  578. repeatMode = true;
  579. setStorage("repeatModeEmbedded","true");player.loop = true;
  580. }
  581. }
  582. function updateVolControlDisplay(percentage){
  583. var adjWidth = percentage * 100 + "%";
  584. $("#volControl").css("width",adjWidth);
  585. $("#volControl").attr("vol",percentage);
  586. }
  587. function getCurrentGlobVol(){
  588. //console.log(localStorage.getItem("global_volume"));
  589. if (localStorage.getItem("global_volume") === null || localStorage.getItem("global_volume") == ""){
  590. return 0;
  591. }
  592. return parseFloat(localStorage.getItem("global_volume"));
  593. }
  594. function setStorage(configName,configValue){
  595. $.ajax({
  596. type: 'GET',
  597. url: "/api/pref/set",
  598. data: {key: "Music/" + configName, value:configValue},
  599. success: function(data){},
  600. async:true
  601. });
  602. return true;
  603. }
  604. function loadStorage(configName){
  605. var result = "";
  606. $.ajax({
  607. type: 'GET',
  608. url: "/api/pref/get",
  609. data: {key: "Music/" + configName},
  610. success: function(data){
  611. if (data.error !== undefined){
  612. result = "";
  613. }else{
  614. result = data;
  615. }
  616. },
  617. error: function(data){result = "";},
  618. async:false,
  619. timeout: 3000
  620. });
  621. return result;
  622. }
  623. //Update the player background and theme color
  624. function updatePlayerThemeAndBackground(songPath){
  625. return;
  626. }
  627. function getAverageRGB(imgEl) {
  628. var blockSize = 5,
  629. defaultRGB = {r:0,g:0,b:0},
  630. canvas = document.createElement('canvas'),
  631. context = canvas.getContext && canvas.getContext('2d'),
  632. data, width, height,
  633. i = -4,
  634. length,
  635. rgb = {r:0,g:0,b:0},
  636. count = 0;
  637. if (!context) {
  638. return defaultRGB;
  639. }
  640. height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
  641. width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
  642. context.drawImage(imgEl, 0, 0);
  643. try {
  644. data = context.getImageData(0, 0, width, height);
  645. } catch(e) {
  646. /* security error, img on diff domain */
  647. return defaultRGB;
  648. }
  649. length = data.data.length;
  650. while ( (i += blockSize * 4) < length ) {
  651. ++count;
  652. rgb.r += data.data[i];
  653. rgb.g += data.data[i+1];
  654. rgb.b += data.data[i+2];
  655. }
  656. // ~~ used to floor values
  657. rgb.r = ~~(rgb.r/count);
  658. rgb.g = ~~(rgb.g/count);
  659. rgb.b = ~~(rgb.b/count);
  660. return rgb;
  661. }
  662. </script>
  663. </body>
  664. </html>