summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaindropsSys <raindrops@equestria.dev>2023-11-29 22:27:20 +0100
committerRaindropsSys <raindrops@equestria.dev>2023-11-29 22:27:20 +0100
commit747d8f88d5a635ba68b3f6288fb8d1f3fe48f83d (patch)
tree66101947d417a29099b1be462ec3029a7a092657
parent6f6a92041aae1577a963af9c3a31b46950e15f40 (diff)
downloadmist-747d8f88d5a635ba68b3f6288fb8d1f3fe48f83d.tar.gz
mist-747d8f88d5a635ba68b3f6288fb8d1f3fe48f83d.tar.bz2
mist-747d8f88d5a635ba68b3f6288fb8d1f3fe48f83d.zip
Updated 19 files, added 5 files and deleted app/studio.php (automated)
-rw-r--r--.DS_Storebin20484 -> 20484 bytes
-rw-r--r--api/hasVideo.php11
-rw-r--r--app/.DS_Storebin6148 -> 6148 bytes
-rw-r--r--app/index.php6
-rw-r--r--app/studio.php445
-rw-r--r--app/ui/listing.php27
-rw-r--r--app/ui/lyrics.php134
-rw-r--r--app/ui/navigation.php12
-rw-r--r--app/ui/settings.php11
-rw-r--r--app/ui/stella.php2
-rw-r--r--app/ui/video.php7
-rw-r--r--assets/.DS_Storebin10244 -> 10244 bytes
-rw-r--r--assets/delays.json15
-rw-r--r--assets/icons/now.svg1
-rw-r--r--assets/icons/video.svg1
-rw-r--r--assets/native.css8
-rw-r--r--desktop/main.js39
-rw-r--r--desktop/preload.js3
-rw-r--r--includes/session.php17
-rw-r--r--index.php2
-rw-r--r--oauth/.DS_Storebin6148 -> 6148 bytes
-rw-r--r--oauth/callback/index.php2
-rw-r--r--oauth/init/index.php2
-rw-r--r--profile/index.php2
-rw-r--r--version2
25 files changed, 190 insertions, 559 deletions
diff --git a/.DS_Store b/.DS_Store
index 36baf1f..1a02e99 100644
--- a/.DS_Store
+++ b/.DS_Store
Binary files differ
diff --git a/api/hasVideo.php b/api/hasVideo.php
new file mode 100644
index 0000000..0881c78
--- /dev/null
+++ b/api/hasVideo.php
@@ -0,0 +1,11 @@
+<?php
+
+header("X-Frame-Options: SAMEORIGIN");
+header("Content-Type: application/json");
+require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $songs;
+
+if (!isset($_GET["id"]) || !isset($songs[$_GET["id"]])) {
+ die();
+}
+
+die(file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/content/" . $_GET["id"] . ".webm") ? "true" : "false"); \ No newline at end of file
diff --git a/app/.DS_Store b/app/.DS_Store
index 60beba8..c348c57 100644
--- a/app/.DS_Store
+++ b/app/.DS_Store
Binary files differ
diff --git a/app/index.php b/app/index.php
index 82b4791..8a6aff6 100644
--- a/app/index.php
+++ b/app/index.php
@@ -56,7 +56,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $_PROFI
}
if (window.MistNative) {
- MistNative.version("<?= explode("|", trim(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/version")))[0] ?>", "<?= trim(file_exists("/opt/spotify/build.txt") ? file_get_contents("/opt/spotify/build.txt") : "trunk") ?>");
+ MistNative.version("<?= explode("|", trim(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/version")))[0] ?>", "<?= trim(file_exists($_SERVER['DOCUMENT_ROOT'] . "/build.txt") ? file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/build.txt") : (file_exists("/opt/spotify/build.txt") ? file_get_contents("/opt/spotify/build.txt") : "trunk")) ?>");
MistNative.userInfo(`<?= str_replace("`", "\\`", json_encode($_PROFILE)) ?>`);
}
</script>
@@ -209,6 +209,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $_PROFI
if (name === "lyrics") showLyrics();
if (name === "search") name = "home";
if (name === "stella") name = "settings";
+ if (name === "video") name = "settings";
Array.from(document.getElementById("navigation").contentDocument.getElementsByClassName("navigation-item")).map(i => i.classList.remove("active"));
document.getElementById("navigation").contentDocument.getElementById(name).classList.add("active");
} catch (e) {
@@ -456,6 +457,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $_PROFI
}
playerDocument.getElementById("player-audio").onplay = () => {
+ document.getElementById("lyrics-page").contentWindow.updateVideo();
updateAndroidNotification();
if (window.preloadedGains[window.currentSongID]) {
@@ -497,6 +499,8 @@ require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; global $_PROFI
}
playerDocument.getElementById("player-audio").onpause = () => {
+ document.getElementById("lyrics-page").contentWindow.updateVideo();
+
if (window.preloadedGains[window.currentSongID]) {
try {
window.currentNormalizationSource.disconnect();
diff --git a/app/studio.php b/app/studio.php
deleted file mode 100644
index 4f002f7..0000000
--- a/app/studio.php
+++ /dev/null
@@ -1,445 +0,0 @@
-<?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/listing.php b/app/ui/listing.php
index 29a1bce..fdef674 100644
--- a/app/ui/listing.php
+++ b/app/ui/listing.php
@@ -37,9 +37,9 @@ if (!$presetList) {
}
}
-if (!isset($onlyStella)) $onlyStella = false;
+if (!isset($onlyStella)) $onlyStella = 0;
-if ($onlyStella) {
+if ($onlyStella === 1) {
$hasAlbum = false;
$list = $songs;
@@ -56,6 +56,23 @@ if ($onlyStella) {
$list = array_filter($list, function ($i) {
return file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/content/" . $i . ".stella");
}, ARRAY_FILTER_USE_KEY);
+} elseif ($onlyStella === 2) {
+ $hasAlbum = false;
+ $list = $songs;
+
+ foreach ($albums as $id => $album) {
+ foreach ($album["tracks"] as $track) {
+ $list[$track]["_albumID"] = $id;
+ }
+ }
+
+ uasort($list, function ($a, $b) {
+ return strcmp($a["title"], $b["title"]);
+ });
+
+ $list = array_filter($list, function ($i) {
+ return file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/content/" . $i . ".webm");
+ }, ARRAY_FILTER_USE_KEY);
}
?>
@@ -76,8 +93,10 @@ if ($onlyStella) {
Favorites
<?php elseif ($hasAlbum): ?>
<?= $albums[$_GET["a"]]["title"] ?>
- <?php elseif ($onlyStella): ?>
+ <?php elseif ($onlyStella === 1): ?>
Mist Stella
+ <?php elseif ($onlyStella === 2): ?>
+ Music videos
<?php else: ?>
Songs
<?php endif; ?>
@@ -97,7 +116,7 @@ if ($onlyStella) {
<div id="ui-back-button" onclick="history.back();" style="display: flex; align-items: center; justify-content: center; text-align: center;<?php if (!$hasAlbum): ?>pointer-events: none; opacity: 0;<?php endif; ?>">
<img src="/assets/icons/back.svg" alt="Back" class="icon">
</div>
- <div style="display: flex; align-items: center; justify-content: center; text-align: center;"><b><?php if (!$hasAlbum && !isset($favoritesList) && !$onlyStella): ?>Songs<?php elseif ($onlyStella): ?>Mist Stella<?php endif; ?></b></div>
+ <div style="display: flex; align-items: center; justify-content: center; text-align: center;"><b><?php if (!$hasAlbum && !isset($favoritesList) && $onlyStella === 0): ?>Songs<?php elseif ($onlyStella === 1): ?>Mist Stella<?php elseif ($onlyStella === 2): ?>Music videos<?php endif; ?></b></div>
<?php if (!$hasAlbum): ?>
<div>
<input placeholder="Filter" id="filter" class="form-control" style="width: 256px;height: 32px;border-top: none;" onchange="updateFilter();" onkeyup="updateFilter();">
diff --git a/app/ui/lyrics.php b/app/ui/lyrics.php
index 274ff93..103167c 100644
--- a/app/ui/lyrics.php
+++ b/app/ui/lyrics.php
@@ -46,7 +46,10 @@
<body style="background-color: transparent;">
<script src="/assets/js/common.js"></script>
<div id="lyrics-outer">
- <div id="not-playing" style="position: fixed; inset: 16px; display: flex; align-items: center; justify-content: center; opacity: .5; text-align: center;">
+ <div id="not-playing" style="display: none; position: fixed; inset: 16px; align-items: center; justify-content: center; opacity: .5; text-align: center;">
+ Lyrics and music videos will appear here when you start playing a song. If supported, lyrics will also scroll as the song plays.
+ </div>
+ <div id="not-playing-2" style="display: none; position: fixed; inset: 16px; align-items: center; justify-content: center; opacity: .5; text-align: center;">
Lyrics will appear here when you start playing a song. If supported, they will also scroll as the song plays.
</div>
@@ -58,94 +61,119 @@
Loading lyrics...
</div>
+ <video id="video" style="width: 100%; height: 100%; display: none; position: fixed; inset: 0; background-color: black;"></video>
+
<div id="lyrics-unsynced" style="display: none; position: fixed; inset: 16px; overflow: auto;"></div>
<div id="lyrics-synced" style="text-align: center; display: none; position: fixed; left: 16px; right: 16px; top: 0; bottom: 0; z-index: 5;"></div>
<div id="lyrics-synced-fade" style="display: none; position: fixed; inset: 0; z-index: 10; background-image: linear-gradient(180deg, rgba(255,0,0,0) 25%, rgba(255,255,255,1) 100%);"></div>
</div>
<script>
+
let lastID = null;
let lastTimestamp = null;
window.lyrics = {};
setInterval(async () => {
+ if (!window.delays) window.delays = await (await fetch("/assets/delays.json")).json();
+
if (window.parent.currentSongID !== lastID) {
lastID = window.parent.currentSongID;
if (lastID === null) {
document.getElementById("lyrics-synced").style.display = "none";
+ document.getElementById("video").style.display = "none";
document.getElementById("lyrics-synced-fade").style.display = "none";
document.getElementById("lyrics-unsynced").style.display = "none";
document.getElementById("not-available").style.display = "none";
document.getElementById("loading").style.display = "none";
- document.getElementById("not-playing").style.display = "flex";
+ document.getElementById(localStorage.getItem("data-saving") === "true" ? "not-playing-2" : "not-playing").style.display = "flex";
} else {
document.getElementById("lyrics-synced").style.display = "none";
+ document.getElementById("video").style.display = "none";
document.getElementById("lyrics-synced-fade").style.display = "none";
document.getElementById("lyrics-unsynced").style.display = "none";
document.getElementById("not-available").style.display = "none";
document.getElementById("loading").style.display = "flex";
- document.getElementById("not-playing").style.display = "none";
-
- if (!window.lyrics[lastID]) {
- window.lyricsLoadTimeout = setTimeout(() => {
- location.reload();
- }, 10000);
-
- try {
- window.lyrics[lastID] = await (await fetch("/api/lyrics.php?id=" + lastID)).json()
- } catch (e) {
- window.lyrics[lastID] = {
- synced: false,
- payload: null
+ document.getElementById(localStorage.getItem("data-saving") === "true" ? "not-playing-2" : "not-playing").style.display = "none";
+
+ window.hasVideo = await (await fetch("/api/hasVideo.php?id=" + lastID)).json();
+
+ if (window.hasVideo && !window.parent.document.getElementById("lyrics-page").classList.contains("mobile-show") && localStorage.getItem("data-saving") !== "true") {
+ document.getElementById("lyrics-synced").style.display = "none";
+ document.getElementById("lyrics-synced-fade").style.display = "none";
+ document.getElementById("lyrics-unsynced").style.display = "none";
+ document.getElementById("video").style.display = "block";
+ document.getElementById("not-available").style.display = "none";
+ document.getElementById("loading").style.display = "none";
+ document.getElementById(localStorage.getItem("data-saving") === "true" ? "not-playing-2" : "not-playing").style.display = "none";
+
+ document.getElementById("video").src = "/assets/content/" + lastID + ".webm";
+ } else {
+ if (!window.lyrics[lastID]) {
+ window.lyricsLoadTimeout = setTimeout(() => {
+ location.reload();
+ }, 10000);
+
+ try {
+ window.lyrics[lastID] = await (await fetch("/api/lyrics.php?id=" + lastID)).json();
+ } catch (e) {
+ window.lyrics[lastID] = {
+ synced: false,
+ payload: null
+ }
}
- }
- clearTimeout(window.lyricsLoadTimeout);
+ clearTimeout(window.lyricsLoadTimeout);
- if (window.lyrics[lastID] && window.lyrics[lastID].payload) {
- if (window.lyrics[lastID].synced) {
- document.getElementById("lyrics-synced").style.display = "";
- document.getElementById("lyrics-synced-fade").style.display = "";
- document.getElementById("lyrics-unsynced").style.display = "none";
- document.getElementById("not-available").style.display = "none";
- document.getElementById("loading").style.display = "none";
- document.getElementById("not-playing").style.display = "none";
+ if (window.lyrics[lastID] && window.lyrics[lastID].payload) {
+ if (window.lyrics[lastID].synced) {
+ document.getElementById("video").style.display = "none";
+ document.getElementById("lyrics-synced").style.display = "";
+ document.getElementById("lyrics-synced-fade").style.display = "";
+ document.getElementById("lyrics-unsynced").style.display = "none";
+ document.getElementById("not-available").style.display = "none";
+ document.getElementById("loading").style.display = "none";
+ document.getElementById(localStorage.getItem("data-saving") === "true" ? "not-playing-2" : "not-playing").style.display = "none";
- document.getElementById("lyrics-synced").style.top = "0px";
- document.getElementById("lyrics-synced").innerHTML = "<div style='height: 16px;'></div>" + window.lyrics[lastID].payload.map(i => `
+ document.getElementById("lyrics-synced").style.top = "0px";
+ document.getElementById("lyrics-synced").innerHTML = "<div style='height: 16px;'></div>" + window.lyrics[lastID].payload.map(i => `
<div class="synced-lyrics-item" id="synced-lyrics-${i.startTimeMs}">${i.words}</div>
`).join("") + "<div style='height: 16px;'></div>";
+ } else {
+ document.getElementById("video").style.display = "none";
+ document.getElementById("lyrics-synced").style.display = "none";
+ document.getElementById("lyrics-synced-fade").style.display = "none";
+ document.getElementById("lyrics-unsynced").style.display = "";
+ document.getElementById("not-available").style.display = "none";
+ document.getElementById("loading").style.display = "none";
+ document.getElementById(localStorage.getItem("data-saving") === "true" ? "not-playing-2" : "not-playing").style.display = "none";
+
+ document.getElementById("lyrics-unsynced").scrollTop = false;
+ document.getElementById("lyrics-unsynced").innerText = window.lyrics[lastID].payload.replaceAll("\n\n\n", "\n");
+ }
} else {
+ document.getElementById("video").style.display = "none";
document.getElementById("lyrics-synced").style.display = "none";
document.getElementById("lyrics-synced-fade").style.display = "none";
- document.getElementById("lyrics-unsynced").style.display = "";
- document.getElementById("not-available").style.display = "none";
+ document.getElementById("lyrics-unsynced").style.display = "none";
+ document.getElementById("not-available").style.display = "flex";
document.getElementById("loading").style.display = "none";
- document.getElementById("not-playing").style.display = "none";
-
- document.getElementById("lyrics-unsynced").scrollTop = false;
- document.getElementById("lyrics-unsynced").innerText = window.lyrics[lastID].payload.replaceAll("\n\n\n", "\n");
+ document.getElementById(localStorage.getItem("data-saving") === "true" ? "not-playing-2" : "not-playing").style.display = "none";
}
- } else {
- document.getElementById("lyrics-synced").style.display = "none";
- document.getElementById("lyrics-synced-fade").style.display = "none";
- document.getElementById("lyrics-unsynced").style.display = "none";
- document.getElementById("not-available").style.display = "flex";
- document.getElementById("loading").style.display = "none";
- document.getElementById("not-playing").style.display = "none";
}
}
}
}
if (window.lyrics[lastID] && window.lyrics[lastID].synced) {
+ document.getElementById("video").style.display = "none";
document.getElementById("lyrics-synced").style.display = "";
document.getElementById("lyrics-synced-fade").style.display = "";
document.getElementById("lyrics-unsynced").style.display = "none";
document.getElementById("not-available").style.display = "none";
document.getElementById("loading").style.display = "none";
- document.getElementById("not-playing").style.display = "none";
+ document.getElementById(localStorage.getItem("data-saving") === "true" ? "not-playing-2" : "not-playing").style.display = "none";
for (let item of [...window.lyrics[lastID].payload].reverse()) {
if (parseInt(item.startTimeMs) / 1000 <= window.parent.document.getElementById("player").contentDocument.getElementById("player-audio").currentTime) {
@@ -161,6 +189,30 @@
}
}
}, 100);
+
+ window.updateVideo = () => {
+ if (window.hasVideo && !window.parent.document.getElementById("lyrics-page").classList.contains("mobile-show") && localStorage.getItem("data-saving") !== "true") {
+ document.getElementById("video").currentTime = window.parent.playerDocument.getElementById("player-audio").currentTime + (window.delays[window.parent.currentSongID] ?? 0);
+
+ if (window.parent.playerDocument.getElementById("player-audio").paused) {
+ document.getElementById("video").pause();
+ } else {
+ document.getElementById("video").play();
+ }
+ }
+ }
+
+ document.onvisibilitychange = () => {
+ window.updateVideo();
+ }
+
+ setInterval(() => {
+ if (Math.abs(window.parent.playerDocument.getElementById("player-audio").currentTime - document.getElementById("video").currentTime) > 0.5 + Math.abs((window.delays[window.parent.currentSongID] ?? 0))) {
+ window.updateVideo();
+ }
+ }, 1000);
+
+ document.getElementById(localStorage.getItem("data-saving") === "true" ? "not-playing-2" : "not-playing").style.display = "flex";
</script>
</body>
</html> \ No newline at end of file
diff --git a/app/ui/navigation.php b/app/ui/navigation.php
index 0125418..617bc63 100644
--- a/app/ui/navigation.php
+++ b/app/ui/navigation.php
@@ -39,6 +39,12 @@
<div id="home" class="navigation-item" onclick="window.parent.openUI('home');">
<img class="icon" alt="" src="/assets/icons/home.svg" style="vertical-align: middle; width: 32px;"><span style="vertical-align: middle; margin-left: 5px;" class="navigation-desktop">Home</span>
</div>
+ <div id="lyrics" class="navigation-item" onclick="window.parent.showLyrics();">
+ <img class="icon" alt="" src="/assets/icons/now.svg" style="vertical-align: middle; width: 32px;"><span style="vertical-align: middle; margin-left: 5px;" class="navigation-desktop">Now playing</span>
+ </div>
+ <div id="queue" class="navigation-item" onclick="window.parent.openUI('queue');">
+ <img class="icon" alt="" src="/assets/icons/playlist.svg" style="vertical-align: middle; width: 32px;"><span style="vertical-align: middle; margin-left: 5px;" class="navigation-desktop">Queue</span>
+ </div>
<div id="library" class="navigation-item-mobile navigation-item" onclick="window.parent.openUI('library');">
<img class="icon" alt="" src="/assets/icons/library.svg" style="vertical-align: middle; width: 32px;"><span style="vertical-align: middle; margin-left: 5px;" class="navigation-desktop">Library</span>
</div>
@@ -51,12 +57,6 @@
<div id="favorites" class="navigation-item-desktop navigation-item" onclick="window.parent.openUI('favorites');">
<img class="icon" alt="" src="/assets/icons/favorites.svg" style="vertical-align: middle; width: 32px;"><span style="vertical-align: middle; margin-left: 5px;" class="navigation-desktop">Favorites</span>
</div>
- <div id="lyrics" class="navigation-item" onclick="window.parent.showLyrics();">
- <img class="icon" alt="" src="/assets/icons/lyrics.svg" style="vertical-align: middle; width: 32px;"><span style="vertical-align: middle; margin-left: 5px;" class="navigation-desktop">Lyrics</span>
- </div>
- <div id="queue" class="navigation-item" onclick="window.parent.openUI('queue');">
- <img class="icon" alt="" src="/assets/icons/playlist.svg" style="vertical-align: middle; width: 32px;"><span style="vertical-align: middle; margin-left: 5px;" class="navigation-desktop">Queue</span>
- </div>
<div id="settings" class="navigation-item" onclick="window.parent.openUI('settings');">
<img class="icon" alt="" src="/assets/icons/settings.svg" style="vertical-align: middle; width: 32px;"><span style="vertical-align: middle; margin-left: 5px;" class="navigation-desktop">Settings</span>
</div>
diff --git a/app/ui/settings.php b/app/ui/settings.php
index 4897f06..d4cb6f2 100644
--- a/app/ui/settings.php
+++ b/app/ui/settings.php
@@ -33,7 +33,7 @@
<input onchange="saveDS();" class="form-check-input" type="checkbox" role="switch" id="data-saving">
<label class="form-check-label" for="data-saving">
Enable data saving
- <div class="text-muted small">Data saving disables playing lossless and high-resolution audio. Instead, you will get 256 kbps AAC-encoded audio, which is highly efficient. If you use Bluetooth headphones, the difference should be unnoticeable.</div>
+ <div class="text-muted small">Data saving disables playing lossless and high-resolution audio, as well as music videos. Instead, you will get 256 kbps AAC-encoded audio, which is highly efficient. If you use Bluetooth headphones, the difference should be unnoticeable.</div>
</label>
</div>
<script>
@@ -251,16 +251,11 @@
<hr>
<?php if (str_contains($_SERVER['HTTP_USER_AGENT'], "MistNative/")): ?>
- <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>
+ <a onclick="window.parent.MistNative.about();" href="#">About Mist</a>
<?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="">
- <span style="vertical-align: middle;">Mist version <?= str_replace("|", " ", file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/version")) ?> (build <?= trim(file_exists("/opt/spotify/build.txt") ? file_get_contents("/opt/spotify/build.txt") : "trunk") ?>)<span id="copyright-separator-desktop"> · </span><span id="copyright-separator-mobile"><br></span>© <?= date('Y') ?> Equestria.dev</span>
+ <span style="vertical-align: middle;">Mist version <?= str_replace("|", " ", file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/version")) ?> (build <?= trim(file_exists($_SERVER['DOCUMENT_ROOT'] . "/build.txt") ? file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/build.txt") : (file_exists("/opt/spotify/build.txt") ? file_get_contents("/opt/spotify/build.txt") : "trunk")) ?>)<span id="copyright-separator-desktop"> · </span><span id="copyright-separator-mobile"><br></span>© <?= date('Y') ?> Equestria.dev</span>
</div>
<style>
@media (min-width: 768px) {
diff --git a/app/ui/stella.php b/app/ui/stella.php
index 143a172..c0f1fc6 100644
--- a/app/ui/stella.php
+++ b/app/ui/stella.php
@@ -2,6 +2,6 @@
header("X-Frame-Options: SAMEORIGIN");
unset($_GET["a"]);
-$onlyStella = true;
+$onlyStella = 1;
global $onlyStella;
require_once "./listing.php"; \ No newline at end of file
diff --git a/app/ui/video.php b/app/ui/video.php
new file mode 100644
index 0000000..fa11e6c
--- /dev/null
+++ b/app/ui/video.php
@@ -0,0 +1,7 @@
+<?php
+
+header("X-Frame-Options: SAMEORIGIN");
+unset($_GET["a"]);
+$onlyStella = 2;
+global $onlyStella;
+require_once "./listing.php"; \ No newline at end of file
diff --git a/assets/.DS_Store b/assets/.DS_Store
index b8d5529..8baa47b 100644
--- a/assets/.DS_Store
+++ b/assets/.DS_Store
Binary files differ
diff --git a/assets/delays.json b/assets/delays.json
new file mode 100644
index 0000000..148a018
--- /dev/null
+++ b/assets/delays.json
@@ -0,0 +1,15 @@
+{
+ "3b195ffe-7454-4ca9-9147-993b42faaab9": 0.1,
+ "7c5ac2fe-92e6-46e4-9e32-77e6468ec376": 0.1,
+ "c7ded287-ef9b-4527-b30a-bac3a26452a9": 1,
+ "2abe4059-7f4e-45ae-8877-43d43fff705d": -0.7,
+ "5551298a-abd8-4a48-81f6-c4c1f1499879": -0.1,
+ "28d82a9b-0867-4486-8cc8-19609a3b7c12": 0.1,
+ "2d8dcafd-ec1c-4c0f-a5b0-70da73bf2fd8": 0.1,
+ "b540d733-23a1-47ed-ae82-d187830d204b": 0.1,
+ "c9e459bd-cb02-4a14-92c0-f78509f22267": 1.3,
+ "0143c30b-8bbe-4bde-a149-eff69547b9a5": 1.3,
+ "d0408137-e2e2-4935-923b-a40088d1199b": 0.1,
+ "c9fcbfb5-9e4c-4398-9b46-e1a99bd22ce7": -18,
+ "7c55b870-bb22-497a-aed5-fdf30845c327": -0.2
+} \ No newline at end of file
diff --git a/assets/icons/now.svg b/assets/icons/now.svg
new file mode 100644
index 0000000..f6cd4d3
--- /dev/null
+++ b/assets/icons/now.svg
@@ -0,0 +1 @@
+<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M4.524 6.25a.75.75 0 0 1 .75-.75H18.73a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-.75.75H5.274a.75.75 0 0 1-.75-.75v-3.5Zm1.5.75v2H17.98V7H6.024ZM14.23 11.979a.75.75 0 0 0-.75.75v4.5c0 .414.335.75.75.75h4.5a.75.75 0 0 0 .75-.75v-4.5a.75.75 0 0 0-.75-.75h-4.5Zm.75 4.5v-3h3v3h-3ZM4.524 13.25a.75.75 0 0 1 .75-.75h5.976a.75.75 0 0 1 0 1.5H5.274a.75.75 0 0 1-.75-.75ZM5.274 16a.75.75 0 0 0 0 1.5h5.976a.75.75 0 0 0 0-1.5H5.274Z" fill="#000000"/><path d="M2 5.75A2.75 2.75 0 0 1 4.75 3h14.5A2.75 2.75 0 0 1 22 5.75v12.5A2.75 2.75 0 0 1 19.25 21H4.75A2.75 2.75 0 0 1 2 18.25V5.75ZM4.75 4.5c-.69 0-1.25.56-1.25 1.25v12.5c0 .69.56 1.25 1.25 1.25h14.5c.69 0 1.25-.56 1.25-1.25V5.75c0-.69-.56-1.25-1.25-1.25H4.75Z" fill="#000000"/></svg> \ No newline at end of file
diff --git a/assets/icons/video.svg b/assets/icons/video.svg
new file mode 100644
index 0000000..bc0238f
--- /dev/null
+++ b/assets/icons/video.svg
@@ -0,0 +1 @@
+<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M6.25 4h11.5a3.25 3.25 0 0 1 3.245 3.066L21 7.25v9.5a3.25 3.25 0 0 1-3.066 3.245L17.75 20H6.25a3.25 3.25 0 0 1-3.245-3.066L3 16.75v-9.5a3.25 3.25 0 0 1 3.066-3.245L6.25 4h11.5-11.5Zm11.5 1.5H6.25a1.75 1.75 0 0 0-1.744 1.606L4.5 7.25v9.5a1.75 1.75 0 0 0 1.606 1.744l.144.006h11.5a1.75 1.75 0 0 0 1.744-1.607l.006-.143v-9.5a1.75 1.75 0 0 0-1.607-1.744L17.75 5.5Zm-7.697 4.085a.5.5 0 0 1 .587-.256l.084.033 4.382 2.19a.5.5 0 0 1 .076.848l-.076.047-4.382 2.191a.5.5 0 0 1-.716-.357L10 14.19V9.809a.5.5 0 0 1 .053-.224Z" fill="#000000"/></svg> \ No newline at end of file
diff --git a/assets/native.css b/assets/native.css
index 8552508..48fa535 100644
--- a/assets/native.css
+++ b/assets/native.css
@@ -17,10 +17,6 @@ body.navigation-body {
display: none !important;
}
-#search, .list-group-item {
- background-color: rgba(255, 255, 255, .25) !important;
-}
-
@media (prefers-color-scheme: dark) {
body, #player.bg-white {
background-color: transparent !important;
@@ -36,8 +32,4 @@ body.navigation-body {
#navigation-gradient {
display: none !important;
}
-
- #filter, #search, .list-group-item {
- background-color: rgba(0, 0, 0, .25) !important;
- }
} \ No newline at end of file
diff --git a/desktop/main.js b/desktop/main.js
index 02f153d..617df9e 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -338,40 +338,6 @@ 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/");
});
@@ -380,11 +346,6 @@ 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 4c85000..b699153 100644
--- a/desktop/preload.js
+++ b/desktop/preload.js
@@ -5,6 +5,5 @@ contextBridge.exposeInMainWorld('MistNative', {
version: (v, b) => ipcRenderer.invoke("version", v, b),
about: () => ipcRenderer.invoke('about'),
notification: (song, img) => ipcRenderer.invoke('notification', song, img),
- userInfo: (ui) => ipcRenderer.invoke('userInfo', ui),
- studio: () => ipcRenderer.invoke('studio')
+ userInfo: (ui) => ipcRenderer.invoke('userInfo', ui)
}) \ No newline at end of file
diff --git a/includes/session.php b/includes/session.php
index 3936a20..a87ad72 100644
--- a/includes/session.php
+++ b/includes/session.php
@@ -77,6 +77,23 @@ function displayList($list, $hasAlbum = false) { global $albums; global $favorit
</div>
<?php endif; ?>
<div class="list-actions">
+ <span style="margin-right: 10px;">
+ <?php if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/content/" . $id . ".stella")): ?>
+ <img data-bs-html="true" title="<img src='/assets/icons/stella-full.svg' class='stella-logo-full'>" data-bs-toggle="tooltip" alt="" src="/assets/icons/stella.svg" style="vertical-align: middle; width: 16px; height: 16px; position: relative; top: -10px;">
+ <style>
+ .stella-logo-full {
+ height: 12px;
+ filter: invert(1);
+ }
+ </style>
+ <?php endif; ?><?php if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/assets/content/" . $id . ".webm")): ?>
+ <img title="Music video available" data-bs-toggle="tooltip" alt="" src="/assets/icons/video.svg" style="vertical-align: middle; width: 24px; height: 24px; position: relative; top: -12px;">
+ <?php endif; ?>
+ <script>
+ aTooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
+ [...aTooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
+ </script>
+ </span>
<!--<span onclick="<?= in_array($id, $favorites) ? "un" : "" ?>favoriteSong('<?= $id ?>');" class="player-btn" style="border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; height: 48px; width: 48px;" id="btn-favorite-<?= $id ?>">
<img class="icon" alt="" src="/assets/icons/favorite-<?= in_array($id, $favorites) ? "on" : "off" ?>.svg" style="pointer-events: none; width: 32px; height: 32px;" id="btn-favorite-<?= $id ?>-icon">
</span>-->
diff --git a/index.php b/index.php
index 141bdca..f987d9f 100644
--- a/index.php
+++ b/index.php
@@ -1,5 +1,7 @@
<?php
+// ffmpeg -y -i <source> -vf scale=1280:720,fps=fps=24 -an <id>.webm
+
header("X-Frame-Options: DENY");
require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php";
header("Location: /app/");
diff --git a/oauth/.DS_Store b/oauth/.DS_Store
index 2a12673..e14fa9f 100644
--- a/oauth/.DS_Store
+++ b/oauth/.DS_Store
Binary files differ
diff --git a/oauth/callback/index.php b/oauth/callback/index.php
index bbb3322..bb3f57f 100644
--- a/oauth/callback/index.php
+++ b/oauth/callback/index.php
@@ -19,7 +19,7 @@ curl_setopt($crl, CURLOPT_HTTPHEADER, [
"Content-Type: application/x-www-form-urlencoded",
"Accept: application/json"
]);
-curl_setopt($crl, CURLOPT_POSTFIELDS, "grant_type=authorization_code&redirect_uri=" . urlencode(($_SERVER['SERVER_PORT'] === "8043" ? "https://mist-testing.equestria.horse" : "https://mist.equestria.horse") . "/oauth/callback") . "&code=" . $_GET['code']);
+curl_setopt($crl, CURLOPT_POSTFIELDS, "grant_type=authorization_code&redirect_uri=" . urlencode(($_SERVER['HTTP_HOST'] === "mist-testing.equestria.horse" ? "https://mist-testing.equestria.horse" : "https://mist.equestria.horse") . "/oauth/callback") . "&code=" . $_GET['code']);
$result = curl_exec($crl);
$result = json_decode($result, true);
diff --git a/oauth/init/index.php b/oauth/init/index.php
index f0696b2..4f2be05 100644
--- a/oauth/init/index.php
+++ b/oauth/init/index.php
@@ -4,5 +4,5 @@ header("X-Frame-Options: DENY");
$app = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/app.json"), true);
$server = "account.equestria.dev";
-header("Location: https://$server/hub/api/rest/oauth2/auth?client_id=" . $app["id"] . "&response_type=code&redirect_uri=" . ($_SERVER['SERVER_PORT'] === "8043" ? "https://mist-testing.equestria.horse" : "https://mist.equestria.horse") . "/oauth/callback&scope=Hub&request_credentials=default&access_type=offline");
+header("Location: https://$server/hub/api/rest/oauth2/auth?client_id=" . $app["id"] . "&response_type=code&redirect_uri=" . ($_SERVER['HTTP_HOST'] === "mist-testing.equestria.horse" ? "https://mist-testing.equestria.horse" : "https://mist.equestria.horse") . "/oauth/callback&scope=Hub&request_credentials=default&access_type=offline");
die();
diff --git a/profile/index.php b/profile/index.php
index 2005b5f..f7c6984 100644
--- a/profile/index.php
+++ b/profile/index.php
@@ -366,7 +366,7 @@ function allowed(string $item): bool {
<div class="text-muted">
<img class="icon" src="/icons/logo-transparent.svg" style="vertical-align: middle; filter: grayscale(1) invert(1); width: 32px; height: 32px;" alt="">
- <span style="vertical-align: middle;">Powered by <a class="link-secondary" href="https://source.equestria.dev/equestria.dev/mist" target="_blank">Mist</a> (Version <?= str_replace("|", " ", file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/version")) ?>, Build <?= trim(file_exists("/opt/spotify/build.txt") ? file_get_contents("/opt/spotify/build.txt") : "trunk") ?>)<span id="copyright-separator-desktop"> · </span><span id="copyright-separator-mobile"><br></span>© <?= date('Y') ?> Equestria.dev</span>
+ <span style="vertical-align: middle;">Powered by <a class="link-secondary" href="https://source.equestria.dev/equestria.dev/mist" target="_blank">Mist</a> (Version <?= str_replace("|", " ", file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/version")) ?>, Build <?= trim(file_exists($_SERVER['DOCUMENT_ROOT'] . "/build.txt") ? file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/build.txt") : (file_exists("/opt/spotify/build.txt") ? file_get_contents("/opt/spotify/build.txt") : "trunk")) ?>)<span id="copyright-separator-desktop"> · </span><span id="copyright-separator-mobile"><br></span>© <?= date('Y') ?> Equestria.dev</span>
</div>
</div>
diff --git a/version b/version
index 7b378be..abb1658 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.8.4 \ No newline at end of file
+1.9.0 \ No newline at end of file