diff options
author | RaindropsSys <raindrops@equestria.dev> | 2023-11-26 17:10:11 +0100 |
---|---|---|
committer | RaindropsSys <raindrops@equestria.dev> | 2023-11-26 17:10:11 +0100 |
commit | 417c403ba8e46dd97ffe656fc8761cb8c6380652 (patch) | |
tree | 208c8d5aa23ca4b8ddc35d2b37159ab4ab07b901 | |
parent | e1fe55e82cc4af07a5e4544de1629b9d25c9ce2b (diff) | |
download | mist-417c403ba8e46dd97ffe656fc8761cb8c6380652.tar.gz mist-417c403ba8e46dd97ffe656fc8761cb8c6380652.tar.bz2 mist-417c403ba8e46dd97ffe656fc8761cb8c6380652.zip |
Updated 13 files and added app/studio.php (automated)
-rw-r--r-- | .DS_Store | bin | 20484 -> 20484 bytes | |||
-rw-r--r-- | app/.DS_Store | bin | 6148 -> 6148 bytes | |||
-rw-r--r-- | app/index.php | 68 | ||||
-rw-r--r-- | app/studio.php | 445 | ||||
-rw-r--r-- | app/ui/player.php | 6 | ||||
-rw-r--r-- | app/ui/queue.php | 11 | ||||
-rw-r--r-- | app/ui/settings.php | 7 | ||||
-rw-r--r-- | assets/.DS_Store | bin | 10244 -> 10244 bytes | |||
-rw-r--r-- | assets/js/common.js | 2 | ||||
-rwxr-xr-x | build.sh | 2 | ||||
-rw-r--r-- | desktop/main.js | 48 | ||||
-rw-r--r-- | desktop/preload.js | 1 | ||||
-rw-r--r-- | includes/session.php | 1 | ||||
-rw-r--r-- | version | 2 |
14 files changed, 573 insertions, 20 deletions
Binary files differ diff --git a/app/.DS_Store b/app/.DS_Store Binary files differindex b01224a..60beba8 100644 --- a/app/.DS_Store +++ b/app/.DS_Store diff --git a/app/index.php b/app/index.php index 31ca9aa..82b4791 100644 --- a/app/index.php +++ b/app/index.php @@ -553,7 +553,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $_PROFI } } - function updateDisplay(initial) { + window.updateDisplay = (initial) => { if (initial) { if (playerDocument.getElementById("player-audio").paused) { document.title = "Mist"; @@ -740,6 +740,14 @@ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $_PROFI window.library = await (await fetch("/api/getLibrary.php?_=" + [...crypto.getRandomValues(new Uint8Array(40))].map(m=>('0'+m.toString(16)).slice(-2)).join(''))).json(); } + window.redownloadMedia = async () => { + document.getElementById("loading-text").innerText = "Downloading list of songs..."; + window.songs = await (await fetch("/assets/content/songs.json?_=" + [...crypto.getRandomValues(new Uint8Array(40))].map(m=>('0'+m.toString(16)).slice(-2)).join(''))).json(); + + document.getElementById("loading-text").innerText = "Downloading list of albums..."; + window.albums = await (await fetch("/assets/content/albums.json?_=" + [...crypto.getRandomValues(new Uint8Array(40))].map(m=>('0'+m.toString(16)).slice(-2)).join(''))).json(); + } + (async () => { document.getElementById("loading-text").innerText = "Downloading list of songs..."; window.songs = await (await fetch("/assets/content/songs.json?_=" + [...crypto.getRandomValues(new Uint8Array(40))].map(m=>('0'+m.toString(16)).slice(-2)).join(''))).json(); @@ -943,10 +951,12 @@ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $_PROFI } if (stellaCompatible) { - window.preloaded[id] = await Stella.build("/assets/content/" + id + ".stella"); - window.preloadedGains[id] = await normalizeAudio(window.preloaded[id].stems.vocals.buffer, 0, true); - window.preloadedGainsBoosted1[id] = await normalizeAudio(window.preloaded[id].stems.vocals.buffer, .05, true); - window.preloadedGainsBoosted2[id] = await normalizeAudio(window.preloaded[id].stems.vocals.buffer, .1, true); + if (!window.preloaded[id]) { + window.preloaded[id] = await Stella.build("/assets/content/" + id + ".stella"); + window.preloadedGains[id] = await normalizeAudio(window.preloaded[id].stems.vocals.buffer, 0, true); + window.preloadedGainsBoosted1[id] = await normalizeAudio(window.preloaded[id].stems.vocals.buffer, .05, true); + window.preloadedGainsBoosted2[id] = await normalizeAudio(window.preloaded[id].stems.vocals.buffer, .1, true); + } } else { if (!window.preloaded[id]) { window.buffering = true; @@ -971,9 +981,45 @@ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $_PROFI if (window.currentSongID !== id) return; + try { + window.currentNormalizationSource.disconnect(); + + if (playingStella) { + window.currentNormalizationSource2.disconnect(); + window.currentNormalizationSource3.disconnect(); + } + + window.preloadedGains[window.currentSongID].disconnect(); + } catch (e) { + console.error(e); + } + + if (playingStella) { + for (let player of [ + window.currentNormalizationSource2, + window.currentNormalizationSource3, + window.currentNormalizationSource4, + window.currentNormalizationSource5 + ]) { + try { + player.disconnect(); + window.preloadedGainsBoosted1[window.currentSongID].disconnect(); + } catch (e) { + console.error(e); + } + } + + try { + window.currentNormalizationSource1.disconnect(); + window.preloadedGainsBoosted2[window.currentSongID].disconnect(); + } catch (e) { + console.error(e); + } + } + if (!stellaCompatible) { if (!window.preloadedURLs[id]) { - window.preloadedURLs[id] = localStorage.getItem("data-saving") ? URL.createObjectURL(window.preloadedBlobs[id]) : URL.createObjectURL(window.preloadedBlobs[id]); + window.preloadedURLs[id] = URL.createObjectURL(window.preloadedBlobs[id]); } } else { window.playingStella = true; @@ -1079,10 +1125,12 @@ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $_PROFI } if (stellaCompatible) { - window.preloaded[id] = await Stella.build("/assets/content/" + id + ".stella"); - window.preloadedGains[id] = await normalizeAudio(window.preloaded[id].stems.other.buffer, 0, true); - window.preloadedGainsBoosted1[id] = await normalizeAudio(window.preloaded[id].stems.other.buffer, .05, true); - window.preloadedGainsBoosted2[id] = await normalizeAudio(window.preloaded[id].stems.other.buffer, .1, true); + if (!window.preloaded[id]) { + window.preloaded[id] = await Stella.build("/assets/content/" + id + ".stella"); + window.preloadedGains[id] = await normalizeAudio(window.preloaded[id].stems.other.buffer, 0, true); + window.preloadedGainsBoosted1[id] = await normalizeAudio(window.preloaded[id].stems.other.buffer, .05, true); + window.preloadedGainsBoosted2[id] = await normalizeAudio(window.preloaded[id].stems.other.buffer, .1, true); + } } else { if (!window.preloaded[id]) { if (localStorage.getItem("data-saving") === "true") { diff --git a/app/studio.php b/app/studio.php new file mode 100644 index 0000000..4f002f7 --- /dev/null +++ b/app/studio.php @@ -0,0 +1,445 @@ +<?php header("X-Frame-Options: SAMEORIGIN"); require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; ?> +<!doctype html> +<html lang="en"> +<head> + <script> + if (typeof require === "undefined") { + location.href = "/app/"; + } + </script> + <style> + * { + outline: none; + user-select: none; + -webkit-user-drag: none; + } + + *:hover { + outline: 1px solid #00bbff; + } + + button.active { + outline: 1px solid #00ff04 !important; + } + + *::placeholder { + font-style: italic; + } + </style> + <meta charset="UTF-8"> + <meta name="viewport" + content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> + <meta http-equiv="X-UA-Compatible" content="ie=edge"> + <title>Mist Studio</title> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script> + <script src="/assets/js/pako.js"></script> + <script src="/assets/js/stella.js"></script> +</head> +<body style="background-color: #111111;"> + <div id="app" style="position: fixed; inset: 0; background-color: #111111; display: none;"> + <div id="header" style="position: fixed; top: 5px; left: 5px; right: 5px; height: 48px; background-color: #222222;"></div> + <div id="controls" style="position: fixed; top: 60px; left: 5px; bottom: 5px; width: 256px; background-color: #222222;"> + <div style="background-color: #333; height: 24px;" id="seek"> + <div style="background-color: #444; height: 24px; pointer-events: none;" id="seek-inner"></div> + <span id="seek-cursor" style="pointer-events: none; top: -24px; background-color: red; width: 1px; height: 24px; position: relative; display: none;"></span> + </div> + <script> + document.getElementById("seek").onmouseenter = () => { + document.getElementById("seek-cursor").style.display = "inline-block"; + } + + document.getElementById("seek").onmouseleave = () => { + document.getElementById("seek-cursor").style.display = "none"; + } + + document.getElementById("seek").onmousemove = (e) => { + document.getElementById("seek-cursor").style.left = ((e.offsetX / document.getElementById("seek").clientWidth) * 100) + "%"; + } + + document.getElementById("seek").onclick = (e) => { + let factor = e.offsetX / document.getElementById("seek").clientWidth; + document.getElementById("audio-stream-0").currentTime = document.getElementById("audio-stream-0").duration * factor; + + if (playingStella) { + document.getElementById("audio-stream-1").currentTime = + document.getElementById("audio-stream-2").currentTime = + document.getElementById("audio-stream-3").currentTime = + document.getElementById("audio-stream-4").currentTime = + document.getElementById("audio-stream-5").currentTime = document.getElementById("audio-stream-0").currentTime; + } + } + </script> + <div style="color: white; text-align: center; margin-top: 20px;" id="status">Empty queue</div> + <div id="buttons" style="text-align: center;"> + <button id="btn-prev" style="border: 1px solid #151515; background-color: #333; color: white;"><</button> + <button id="btn-play" onclick="togglePlay();" style="border: 1px solid #151515; background-color: #333; color: white;">Play</button> + <button id="btn-next" style="border: 1px solid #151515; background-color: #333; color: white;">></button> + </div> + <div id="details" style="margin-top: 20px; color: white; font-family: monospace;"> + <div id="time">--:--.--- / ---:--.---</div> + <div id="delay">------ samples</div> + <div id="delay-ms">---- ms</div> + </div> + <div id="clip-indicators" style="display: grid; height: 8px; grid-template-columns: repeat(6, 1fr); pointer-events: none; grid-gap: 2px; position: absolute; bottom: 210px; left: 0; right: 0; margin: 10px; margin-bottom: 5px;"> + <div id="ci-0" style="background-color: #151515;"></div> + <div id="ci-1" style="background-color: #151515;"></div> + <div id="ci-2" style="background-color: #151515;"></div> + <div id="ci-3" style="background-color: #151515;"></div> + <div id="ci-4" style="background-color: #151515;"></div> + <div id="ci-5" style="background-color: #151515;"></div> + </div> + <div id="meters" style="display: grid; grid-template-columns: repeat(6, 1fr); pointer-events: none; grid-gap: 2px; position: absolute; bottom: 0; left: 0; right: 0; margin: 10px;"> + <div id="meter-0" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;"> + <div id="meter-0-inner" style="background-color: #151515; width: 100%; height: 100%;"></div> + </div> + <div id="meter-1" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;"> + <div id="meter-1-inner" style="background-color: #151515; width: 100%; height: 100%;"></div> + </div> + <div id="meter-2" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;"> + <div id="meter-2-inner" style="background-color: #151515; width: 100%; height: 100%;"></div> + </div> + <div id="meter-3" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;"> + <div id="meter-3-inner" style="background-color: #151515; width: 100%; height: 100%;"></div> + </div> + <div id="meter-4" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;"> + <div id="meter-4-inner" style="background-color: #151515; width: 100%; height: 100%;"></div> + </div> + <div id="meter-5" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;"> + <div id="meter-5-inner" style="background-color: #151515; width: 100%; height: 100%;"></div> + </div> + </div> + </div> + <div id="queue" style="position: fixed; top: 60px; left: 269px; right: 5px; height: calc((100vh - 72px) / 2); background-color: #222222; overflow: auto;"></div> + <div id="library" style="display: grid; grid-template-rows: 42px 1fr; position: fixed; top: calc((60px) + (100vh - 58px) / 2); left: 269px; right: 5px; height: calc((100vh - 72px) / 2); background-color: #222222;"> + <input id="query" placeholder="Search..." style="background-color: #252525; border: 1px solid #151515; color: white;" onkeydown="refreshSearch();" onkeyup="refreshSearch();" onchange="refreshSearch();"> + <div id="items" style="overflow: auto;"></div> + </div> + </div> + + <audio id="audio-stream-0"></audio> + <audio id="audio-stream-1"></audio> + <audio id="audio-stream-2"></audio> + <audio id="audio-stream-3"></audio> + <audio id="audio-stream-4"></audio> + <audio id="audio-stream-5"></audio> + + <script> + for (let id of [0, 1, 2, 3, 4, 5]) { + let audioContext = new AudioContext(); + let analyser = audioContext.createAnalyser(); + let source = audioContext.createMediaElementSource(document.getElementById("audio-stream-" + id)); + let javascriptNode = audioContext.createScriptProcessor(2048, 1, 1); + + analyser.fftSize = 1024; + + source.connect(analyser); + analyser.connect(javascriptNode); + javascriptNode.connect(audioContext.destination); + source.connect(audioContext.destination); + + javascriptNode.onaudioprocess = function() { + let array = new Uint8Array(analyser.frequencyBinCount); + analyser.getByteFrequencyData(array); + let values = 0; + + let length = array.length; + for (let i = 0; i < length; i++) { + values += (array[i]); + } + + let average = values / length; + let value = average / (playingStella ? 40 : 60); + + if (value < 0) value = 0; + if (value > 3) { + value = 3; + if (document.getElementById("ci-" + id).style.backgroundColor !== "rgb(21, 21, 21)") document.getElementById("ci-" + id).style.backgroundColor = "#ff7c7c"; + } else { + if (document.getElementById("ci-" + id).style.backgroundColor !== "rgb(21, 21, 21)") document.getElementById("ci-" + id).style.backgroundColor = "#8dff7c"; + } + + document.getElementById("meter-" + id + "-inner").style.height = Math.abs(100 - ((value / 3) * 100)) + "%"; + } + } + + window.queue = []; + window.shouldPlay = false; + + function getTime(time) { + let minutes = Math.floor(time / 60); + let seconds = Math.floor(time) - minutes * 60; + let ms = Math.floor(time * 1000) - minutes * 60000 - seconds * 1000; + + return "00".substring(0, 2 - minutes.toString().length) + minutes + ":" + "00".substring(0, 2 - seconds.toString().length) + seconds + "." + "000".substring(0, 3 - ms.toString().length) + ms + } + + function togglePlay() { + if (!shouldPlay) { + document.getElementById("btn-play").classList.add("active"); + } else { + document.getElementById("btn-play").classList.remove("active"); + } + + shouldPlay = !shouldPlay; + } + + document.getElementById("audio-stream-0").onplay = () => { + if (playingStella) { + document.getElementById("ci-0").style.backgroundColor = "#8dff7c"; + document.getElementById("ci-1").style.backgroundColor = "#8dff7c"; + document.getElementById("ci-2").style.backgroundColor = "#8dff7c"; + document.getElementById("ci-3").style.backgroundColor = "#8dff7c"; + document.getElementById("ci-4").style.backgroundColor = "#8dff7c"; + document.getElementById("ci-5").style.backgroundColor = "#8dff7c"; + } else { + document.getElementById("ci-0").style.backgroundColor = "#8dff7c"; + document.getElementById("ci-1").style.backgroundColor = "#151515"; + document.getElementById("ci-2").style.backgroundColor = "#151515"; + document.getElementById("ci-3").style.backgroundColor = "#151515"; + document.getElementById("ci-4").style.backgroundColor = "#151515"; + document.getElementById("ci-5").style.backgroundColor = "#151515"; + } + + window.uiUpdateInt = setInterval(() => { + document.getElementById("time").innerText = getTime(document.getElementById("audio-stream-0").currentTime) + " / -" + getTime(Math.abs(document.getElementById("audio-stream-0").duration - document.getElementById("audio-stream-0").currentTime)); + + if (playingStella) { + let delay = Math.max( + document.getElementById("audio-stream-1").currentTime - document.getElementById("audio-stream-0").currentTime, + document.getElementById("audio-stream-2").currentTime - document.getElementById("audio-stream-0").currentTime, + document.getElementById("audio-stream-3").currentTime - document.getElementById("audio-stream-0").currentTime, + document.getElementById("audio-stream-4").currentTime - document.getElementById("audio-stream-0").currentTime, + document.getElementById("audio-stream-5").currentTime - document.getElementById("audio-stream-0").currentTime, + ); + + let oldReal; + let real = oldReal = Math.round(delay * 44100); + real = "00000".substring(0, 5 - Math.abs(real).toString().length) + Math.abs(real); + let realMs = "000".substring(0, 3 - Math.abs(Math.round(real / 44.100)).toString().length) + Math.abs(Math.round(real / 44.100)); + + document.getElementById("delay").innerText = (oldReal > 0 ? "+" : (oldReal < 0 ? "-" : "0")) + real + " samples"; + document.getElementById("delay-ms").innerText = (oldReal > 0 ? "+" : (oldReal < 0 ? "-" : "0")) + realMs + " ms"; + } else { + document.getElementById("delay").innerText = "------ samples"; + document.getElementById("delay-ms").innerText = "---- ms"; + } + }); + } + + document.getElementById("audio-stream-0").onpause = () => { + clearInterval(window.uiUpdateInt); + document.getElementById("ci-0").style.backgroundColor = "#151515"; + document.getElementById("ci-1").style.backgroundColor = "#151515"; + document.getElementById("ci-2").style.backgroundColor = "#151515"; + document.getElementById("ci-3").style.backgroundColor = "#151515"; + document.getElementById("ci-4").style.backgroundColor = "#151515"; + document.getElementById("ci-5").style.backgroundColor = "#151515"; + } + + document.getElementById("audio-stream-0").onended = () => { + queue.shift(); + refreshQueue(); + + if (queue.length > 0) { + loadSong(); + } else { + document.getElementById("audio-stream-0").src = ""; + document.getElementById("audio-stream-1").src = ""; + document.getElementById("audio-stream-2").src = ""; + document.getElementById("audio-stream-3").src = ""; + document.getElementById("audio-stream-4").src = ""; + document.getElementById("audio-stream-5").src = ""; + document.getElementById("btn-play").classList.remove("active"); + shouldPlay = false; + document.getElementById("time").innerText = "--:--.--- / ---:--.---"; + } + } + + function loadSong() { + window.playingStella = false; + let id = queue[0]; + + if (window.preloaded[id] instanceof Stella) { + document.getElementById("audio-stream-0").src = window.preloaded[id].urls.hpf; + document.getElementById("audio-stream-1").src = window.preloaded[id].urls.bass; + document.getElementById("audio-stream-2").src = window.preloaded[id].urls.drums; + document.getElementById("audio-stream-3").src = window.preloaded[id].urls.other; + document.getElementById("audio-stream-4").src = window.preloaded[id].urls.piano; + document.getElementById("audio-stream-5").src = window.preloaded[id].urls.vocals; + window.playingStella = true; + } else { + document.getElementById("audio-stream-0").src = window.preloadedURLs[id]; + } + } + + setInterval(() => { + if (shouldPlay && document.getElementById("audio-stream-0").paused) { + document.getElementById("audio-stream-0").play(); + + if (playingStella) { + document.getElementById("audio-stream-1").currentTime = + document.getElementById("audio-stream-2").currentTime = + document.getElementById("audio-stream-3").currentTime = + document.getElementById("audio-stream-4").currentTime = + document.getElementById("audio-stream-5").currentTime = document.getElementById("audio-stream-0").currentTime; + document.getElementById("audio-stream-1").play(); + document.getElementById("audio-stream-2").play(); + document.getElementById("audio-stream-3").play(); + document.getElementById("audio-stream-4").play(); + document.getElementById("audio-stream-5").play(); + } + } else if (!shouldPlay && !document.getElementById("audio-stream-0").paused) { + document.getElementById("audio-stream-0").pause(); + + if (playingStella) { + document.getElementById("audio-stream-1").pause(); + document.getElementById("audio-stream-2").pause(); + document.getElementById("audio-stream-3").pause(); + document.getElementById("audio-stream-4").pause(); + document.getElementById("audio-stream-5").pause(); + } + } + + document.getElementById("seek-inner").style.width = ((document.getElementById("audio-stream-0").currentTime / document.getElementById("audio-stream-0").duration) * 100) + "%"; + + refreshStatus(); + }, 1000); + + window.onload = async () => { + window.songs = await (await fetch("/assets/content/songs.json?_=" + [...crypto.getRandomValues(new Uint8Array(40))].map(m=>('0'+m.toString(16)).slice(-2)).join(''))).json(); + + document.getElementById("items").innerHTML = Object.entries(songs).map(i => ` + <div onclick="enqueue('${i[0]}');" class="item" id="song-${i[0]}" style="display: grid; grid-template-columns: 1fr 1fr 1fr; color: white;"> + <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].title}</div> + <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].artist}</div> + <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].album}</div> + </div> + `).join(""); + document.getElementById("app").style.display = ""; + } + + function refreshQueue() { + document.getElementById("queue").innerHTML = queue.map((i, j) => [i, songs[i], j]).map(i => ` + <div class="queue" id="queue-${i[0]}" onclick="playImmediately(${i[2]});" style="display: grid; grid-template-columns: 1fr 1fr 1fr; color: white;"> + <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].title}</div> + <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].artist}</div> + <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].album}</div> + </div> + `).join(""); + preloadMore(); + } + + function playImmediately(index) { + let item = queue.splice(index, 1); + queue.unshift(item); + document.getElementById("audio-stream-0").pause(); + + if (playingStella) { + document.getElementById("audio-stream-1").pause(); + document.getElementById("audio-stream-2").pause(); + document.getElementById("audio-stream-3").pause(); + document.getElementById("audio-stream-4").pause(); + document.getElementById("audio-stream-5").pause(); + } + refreshQueue(); + loadSong(); + } + + function refreshSearch() { + let query = document.getElementById("query").value.trim().toLowerCase(); + + if (query === "") { + Array.from(document.getElementsByClassName("item")).map(i => i.style.display = "grid"); + } else { + Array.from(document.getElementsByClassName("item")).map(i => { + let id = i.id.substring(5); + let song = songs[id]; + + if (song.title.toLowerCase().includes(query) || song.artist.toLowerCase().includes(query)) { + i.style.display = "grid"; + } else { + i.style.display = "none"; + } + }); + } + } + + function enqueue(id) { + queue.push(id); + refreshQueue(); + refreshStatus(); + } + + function refreshStatus() { + if (window.preloaded[queue[0]]) { + if (document.getElementById("audio-stream-0").paused) { + document.getElementById("status").innerText = "Ready to play"; + } else { + if (playingStella) { + document.getElementById("status").innerText = "Playing 6 streams"; + } else { + document.getElementById("status").innerText = "Playing 1 stream"; + } + } + } else { + if (queue.length > 0) { + document.getElementById("status").innerText = "Waiting for audio"; + } else { + document.getElementById("status").innerText = "Empty queue"; + } + } + } + + window.preloaded = {}; + window.preloadedURLs = {}; + window.preloadedBlobs = {}; + + async function preloadMore() { + for (let i = 0; i < queue.length; i++) { + if (queue[i]) { + let id = queue[i]; + let stellaCompatible = await (await fetch("/api/hasStella.php?id=" + id)).text() === "true"; + + if (stellaCompatible) { + if (!window.preloaded[id]) { + window.preloaded[id] = await Stella.build("/assets/content/" + id + ".stella"); + if (i === 0) loadSong(); + } + } else { + if (!window.preloaded[id]) { + if (localStorage.getItem("data-saving") === "true") { + window.preloaded[id] = await (await fetch("/assets/content/" + id + ".m4a")).arrayBuffer(); + window.preloadedBlobs[id] = new Blob([window.preloaded[id]], { type: "audio/mp4" }); + } else { + window.preloaded[id] = await (await fetch("/assets/content/" + id + ".flac")).arrayBuffer(); + window.preloadedBlobs[id] = new Blob([window.preloaded[id]], { type: "audio/flac" }); + } + } + + if (!window.preloadedURLs[id]) { + window.preloadedURLs[id] = URL.createObjectURL(window.preloadedBlobs[id]); + if (i === 0) loadSong(); + } + } + + refreshStatus(); + } + } + + cleanupPreload(); + } + + function cleanupPreload() { + let keys = Object.keys(window.preloaded).slice(-30); + + for (let key of Object.keys(window.preloaded)) { + if (!keys.includes(key)) { + if (window.preloadedURLs[key]) URL.revokeObjectURL(window.preloadedURLs[key]); + delete window.preloaded[key]; + } + } + } + </script> +</body> +</html>
\ No newline at end of file diff --git a/app/ui/player.php b/app/ui/player.php index 47526f5..3fcdec1 100644 --- a/app/ui/player.php +++ b/app/ui/player.php @@ -168,7 +168,11 @@ window.parent.redoNavigation("home"); } - function openAlbum() { + async function openAlbum() { + if (Object.entries(window.parent.albums).filter(i => i[1].tracks.includes(window.parent.currentSongID))) { + await window.parent.redownloadMedia(); + } + window.parent.location.hash = "#/albums/" + Object.entries(window.parent.albums).filter(i => i[1].tracks.includes(window.parent.currentSongID))[0][0]; window.parent.redoNavigation("albums"); } diff --git a/app/ui/queue.php b/app/ui/queue.php index 81a7079..7d38625 100644 --- a/app/ui/queue.php +++ b/app/ui/queue.php @@ -25,7 +25,10 @@ <script src="/assets/js/common.js"></script> <div class="container"> <br> - <h2 class="desktop-title" style="margin-top: 10px; margin-bottom: 20px; margin-left: 10px;">Queue</h2> + <h2 class="desktop-title" style="margin-top: 10px; margin-bottom: 20px; margin-left: 10px;"> + Queue + <span class="btn btn-primary" style="float: right;" onclick="clearQueue();">Clear queue</span> + </h2> <div class="list-group" style="margin-left: 10px; margin-top: 20px;" id="main-list"></div> <div class="text-muted" style="margin-left: 10px; margin-top: 20px; display: none;" id="empty"> There are no songs playing next. To add songs to the queue, browse your library and select Add to queue. @@ -33,6 +36,11 @@ </div> <script> + function clearQueue() { + window.parent.playlist = window.parent.playlist.slice(0, window.parent.currentPlaylistPosition + 1); + refreshQueue(); + } + function refreshQueue() { let list = window.parent.playlist.slice(window.parent.currentPlaylistPosition + 1); @@ -68,6 +76,7 @@ function removeSong(index) { window.parent.playlist.splice(index, 1); refreshQueue(); + window.parent.updateDisplay(true); } refreshQueue(); diff --git a/app/ui/settings.php b/app/ui/settings.php index 26217f0..4897f06 100644 --- a/app/ui/settings.php +++ b/app/ui/settings.php @@ -251,7 +251,12 @@ <hr> <?php if (str_contains($_SERVER['HTTP_USER_AGENT'], "MistNative/")): ?> - <a onclick="window.parent.MistNative.about();" href="#">About Mist</a> + <a onclick="window.parent.MistNative.about();" href="#">About Mist</a><span id="studio" style="display: none;"> ยท <a onclick="window.parent.MistNative.studio();" href="#">Switch to Mist Studio</a></span> + <script> + if (window.parent.MistNative.studio) { + document.getElementById("studio").style.display = ""; + } + </script> <?php else: ?> <div class="text-muted"> <img class="icon" src="/assets/logo-transparent.svg" style="vertical-align: middle; filter: grayscale(1) invert(1); width: 32px; height: 32px;" alt=""> diff --git a/assets/.DS_Store b/assets/.DS_Store Binary files differindex b5223c8..b8d5529 100644 --- a/assets/.DS_Store +++ b/assets/.DS_Store diff --git a/assets/js/common.js b/assets/js/common.js index 6ccd25c..0762d07 100644 --- a/assets/js/common.js +++ b/assets/js/common.js @@ -18,5 +18,5 @@ document.head.append(style); if (navigator.userAgent.includes("MistNative/darwin")) { if (document.getElementById("native-css")) document.getElementById("native-css").disabled = false; - document.body.classList.remove("crossplatform"); + if (document.body) document.body.classList.remove("crossplatform"); }
\ No newline at end of file @@ -1,6 +1,6 @@ #!/bin/bash cd desktop -#npx electron-packager . Mist --asar --overwrite --platform=darwin --arch=x64 --icon=../assets/logo.icns --out=../build +npx electron-packager . Mist --asar --overwrite --platform=darwin --arch=x64 --icon=../assets/logo.icns --out=../build npx electron-packager . Mist --asar --overwrite --platform=darwin --arch=arm64 --icon=../assets/logo.icns --out=../build #npx electron-packager . Mist --asar --overwrite --platform=linux --arch=x64 --icon=../assets/logo-display.png --out=../build #npx electron-packager . Mist --asar --overwrite --platform=linux --arch=arm64 --icon=../assets/logo-display.png --out=../build diff --git a/desktop/main.js b/desktop/main.js index 1d0b322..02f153d 100644 --- a/desktop/main.js +++ b/desktop/main.js @@ -229,7 +229,6 @@ function getCopyrightYear() { } } -app.setName("Mist"); app.setAsDefaultProtocolClient("mist"); app.setAboutPanelOptions({ applicationName: "Mist", @@ -239,10 +238,12 @@ app.setAboutPanelOptions({ website: "https://mist.equestria.horse/app/" }); -const gotTheLock = app.requestSingleInstanceLock(); +if (app.getName() !== "Electron") { + const gotTheLock = app.requestSingleInstanceLock(); -if (!gotTheLock) { - app.quit(); + if (!gotTheLock) { + app.quit(); + } } let loggedIn = false; @@ -337,6 +338,40 @@ const createWindow = () => { }); } +const studioMode = () => { + if (global.studioWindow) return; + + global.studioWindow = new BrowserWindow({ + width: require('electron').screen.getPrimaryDisplay().workAreaSize.width, + minWidth: 1280, + height: require('electron').screen.getPrimaryDisplay().workAreaSize.height, + minHeight: 720, + autoHideMenuBar: true, + title: "Mist Studio", + backgroundColor: "#111111", + webPreferences: { + nodeIntegration: true, + contextIsolation: false, + scrollBounce: true, + enableWebSQL: false + } + }); + + updateMenu(studioWindow); + + studioWindow.webContents.setUserAgent(studioWindow.webContents.getUserAgent() + " MistNative/" + process.platform); + studioWindow.loadURL("https://mist.equestria.horse/app/studio.php"); + + studioWindow.webContents.setWindowOpenHandler((details) => { + shell.openExternal(details.url); + return { action: "deny" }; + }); + + studioWindow.on('close', () => { + global.studioWindow = null; + }); +} + ipcMain.handle('auth', () => { shell.openExternal("https://mist.equestria.horse/oauth/native/"); }); @@ -345,6 +380,11 @@ ipcMain.handle('about', () => { app.showAboutPanel(); }); +ipcMain.handle('studio', () => { + studioMode(); + mainWindow.close(); +}); + ipcMain.handle('userInfo', (e, userInfo) => { global.userInfo = JSON.parse(userInfo); updateMenu(mainWindow); diff --git a/desktop/preload.js b/desktop/preload.js index 2b37f60..4c85000 100644 --- a/desktop/preload.js +++ b/desktop/preload.js @@ -6,4 +6,5 @@ contextBridge.exposeInMainWorld('MistNative', { about: () => ipcRenderer.invoke('about'), notification: (song, img) => ipcRenderer.invoke('notification', song, img), userInfo: (ui) => ipcRenderer.invoke('userInfo', ui), + studio: () => ipcRenderer.invoke('studio') })
\ No newline at end of file diff --git a/includes/session.php b/includes/session.php index ee6cd85..3936a20 100644 --- a/includes/session.php +++ b/includes/session.php @@ -136,6 +136,7 @@ function displayList($list, $hasAlbum = false) { global $albums; global $favorit window.parent.playSong(id); } else { window.parent.playlist.push(id); + window.parent.updateDisplay(true); } } @@ -1 +1 @@ -1.8.2
\ No newline at end of file +1.8.4
\ No newline at end of file |