summaryrefslogtreecommitdiff
path: root/app/ui/lyrics.php
diff options
context:
space:
mode:
Diffstat (limited to 'app/ui/lyrics.php')
-rw-r--r--app/ui/lyrics.php164
1 files changed, 164 insertions, 0 deletions
diff --git a/app/ui/lyrics.php b/app/ui/lyrics.php
new file mode 100644
index 0000000..bd24832
--- /dev/null
+++ b/app/ui/lyrics.php
@@ -0,0 +1,164 @@
+<?php header("X-Frame-Options: SAMEORIGIN"); require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; ?>
+<!doctype html>
+<html lang="en">
+<head>
+ <script>
+ if (typeof window.parent.openModal === "undefined") {
+ location.href = "/app/#/lyrics";
+ }
+ </script>
+ <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>lyrics</title>
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
+ <link href="/assets/dark.css" rel="stylesheet">
+ <link href="/assets/styles.css" rel="stylesheet">
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
+ <script src="/assets/localforage.min.js"></script>
+ <script src="/assets/js/shortcuts.js"></script>
+ <link id="native-css" href="/assets/native.css" rel="stylesheet" disabled>
+ <style>
+ .synced-lyrics-item {
+ opacity: .25;
+ font-size: 4vw;
+ min-font-size: 22px;
+ margin-bottom: 10px;
+ transition: opacity 200ms;
+ }
+
+ .synced-lyrics-item.active {
+ opacity: 1;
+ }
+
+ ::-webkit-scrollbar {
+ display: none;
+ }
+
+ #lyrics-synced {
+ transition-property: top;
+ transition-duration: 500ms;
+ transition-timing-function: cubic-bezier(0.54, 0, 0.23, 0.79);
+ }
+ </style>
+</head>
+<body class="crossplatform" style="background-color: transparent !important;">
+ <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;">
+ Lyrics will appear here when you start playing a song. If supported, they will also scroll as the song plays.
+ </div>
+
+ <div id="not-available" style="display: none; position: fixed; inset: 16px; align-items: center; justify-content: center; opacity: .5; text-align: center;">
+ No lyrics are available for this song. Try again later.
+ </div>
+
+ <div id="loading" style="display: none; position: fixed; inset: 16px; align-items: center; justify-content: center; opacity: .5; text-align: center;">
+ Loading lyrics...
+ </div>
+
+ <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.parent.currentSongID !== lastID) {
+ lastID = window.parent.currentSongID;
+
+ if (lastID === null) {
+ 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 = "none";
+ document.getElementById("loading").style.display = "none";
+ document.getElementById("not-playing").style.display = "flex";
+ } 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 = "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
+ }
+ }
+
+ 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";
+
+ 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("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("not-playing").style.display = "none";
+
+ document.getElementById("lyrics-unsynced").innerText = window.lyrics[lastID].payload.replaceAll("\n\n\n", "\n");
+ }
+ } 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("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";
+
+ for (let item of [...window.lyrics[lastID].payload].reverse()) {
+ if (parseInt(item.startTimeMs) / 1000 <= window.parent.document.getElementById("player").contentDocument.getElementById("player-audio").currentTime) {
+ if (item.startTimeMs !== lastTimestamp) {
+ Array.from(document.getElementsByClassName("synced-lyrics-item")).map(i => i.classList.remove("active"));
+ document.getElementById("lyrics-synced").style.top = "-" + (document.getElementById("synced-lyrics-" + item.startTimeMs).offsetTop - 33) + "px";
+ lastTimestamp = item.startTimeMs;
+ document.getElementById("synced-lyrics-" + item.startTimeMs).classList.add("active");
+ }
+
+ break;
+ }
+ }
+ }
+ }, 100);
+ </script>
+</body>
+</html> \ No newline at end of file