aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hg.css210
-rw-r--r--index.html70
-rw-r--r--player.js217
3 files changed, 473 insertions, 24 deletions
diff --git a/hg.css b/hg.css
index 78ebd24..7e12330 100644
--- a/hg.css
+++ b/hg.css
@@ -325,6 +325,10 @@ canvas {
color: #ffff;
right: 0;
margin-right: 5px;
+ padding: 5px;
+ background: rgba(0, 0, 0, 0.5);
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
}
.ERRORS {
@@ -344,3 +348,209 @@ canvas {
border: 2px solid red;
margin-top: 10px;
}
+
+/* Terminal Overlay Styles - ORED Initial Console Emulator Style */
+.terminal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(192, 192, 192, 0.3);
+ backdrop-filter: none;
+ z-index: 10001;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.terminal-window {
+ width: 80%;
+ max-width: 600px;
+ height: 65%;
+ max-height: 450px;
+ min-height: 300px;
+ background: #c0c0c0;
+ border: 4px outset #c0c0c0;
+ border-radius: 0;
+ font-family: 'VCR', 'Monaco', 'Courier New', monospace;
+ box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.6);
+ display: flex;
+ flex-direction: column;
+ position: relative;
+}
+
+.terminal-header {
+ background: #c0c0c0;
+ color: #000000;
+ padding: 1px 0;
+ border-bottom: 2px inset #c0c0c0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 10px;
+ font-weight: bold;
+ font-family: 'VCR', 'Geneva', 'Helvetica', sans-serif;
+ min-height: 16px;
+ position: relative;
+}
+
+.terminal-title {
+ color: #000000;
+ font-size: 10px;
+ font-weight: bold;
+ text-align: center;
+}
+
+.terminal-close {
+ cursor: pointer;
+ color: #000000;
+ font-size: 10px;
+ font-weight: bold;
+ width: 16px;
+ height: 14px;
+ border: 1px outset #c0c0c0;
+ background: #c0c0c0;
+ text-align: center;
+ line-height: 12px;
+ border-radius: 0;
+ position: absolute;
+ right: 2px;
+ top: 1px;
+}
+
+.terminal-close:hover {
+ background: #b0b0b0;
+}
+
+.terminal-close:active {
+ border: 1px inset #c0c0c0;
+ background: #a0a0a0;
+}
+
+.terminal-content {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ padding: 2px;
+ overflow: hidden;
+ background: #c0c0c0;
+}
+
+#terminal-output {
+ flex: 1;
+ overflow-y: auto;
+ margin-bottom: 4px;
+ color: #000000;
+ font-size: 9px;
+ line-height: 1.1;
+ font-family: 'VCR', 'Monaco', 'Courier New', monospace;
+ background: #c0c0c0;
+ border: 2px inset #c0c0c0;
+ padding: 2px 4px;
+ white-space: pre-wrap;
+}
+
+.terminal-line {
+ margin-bottom: 0;
+ word-wrap: break-word;
+ color: #000000;
+ font-size: 9px;
+ line-height: 1.1;
+}
+
+.terminal-input-line {
+ display: flex;
+ align-items: center;
+ color: #000000;
+ font-size: 9px;
+ background: #c0c0c0;
+ border: 2px inset #c0c0c0;
+ padding: 1px 4px;
+ min-height: 14px;
+}
+
+.terminal-prompt {
+ color: #000000;
+ margin-right: 2px;
+ font-weight: normal;
+ font-family: 'VCR', 'Monaco', 'Courier New', monospace;
+ font-size: 9px;
+}
+
+.terminal-input {
+ flex: 1;
+ background: transparent;
+ border: none;
+ color: #000000;
+ font-family: 'VCR', 'Monaco', 'Courier New', monospace;
+ font-size: 9px;
+ outline: none;
+ caret-color: #000000;
+ line-height: 1.1;
+}
+
+.terminal-input::selection {
+ background: #000080;
+ color: #ffffff;
+}
+
+.terminal-btn {
+ float: right;
+ margin-right: 10px;
+ font-size: 16px;
+ color: #565656;
+}
+
+.terminal-btn:hover {
+ color: #000000;
+}
+
+.terminal-overlay.hidden {
+ display: none;
+}
+
+/* Custom scrollbar for terminal output - Classic style */
+#terminal-output::-webkit-scrollbar {
+ width: 16px;
+}
+
+#terminal-output::-webkit-scrollbar-track {
+ background: #c0c0c0;
+ border: 1px inset #c0c0c0;
+}
+
+#terminal-output::-webkit-scrollbar-thumb {
+ background: linear-gradient(to bottom, #e0e0e0 0%, #c0c0c0 50%, #a0a0a0 100%);
+ border: 1px outset #c0c0c0;
+ border-radius: 0;
+}
+
+#terminal-output::-webkit-scrollbar-thumb:hover {
+ background: linear-gradient(to bottom, #d0d0d0 0%, #b0b0b0 50%, #909090 100%);
+}
+
+#terminal-output::-webkit-scrollbar-thumb:active {
+ border: 1px inset #c0c0c0;
+ background: linear-gradient(to bottom, #a0a0a0 0%, #b0b0b0 50%, #d0d0d0 100%);
+}
+
+#terminal-output::-webkit-scrollbar-corner {
+ background: #c0c0c0;
+}
+
+#terminal-output::-webkit-scrollbar-button {
+ width: 16px;
+ height: 16px;
+ background: linear-gradient(to bottom, #e0e0e0 0%, #c0c0c0 50%, #a0a0a0 100%);
+ border: 1px outset #c0c0c0;
+}
+
+#terminal-output::-webkit-scrollbar-button:hover {
+ background: linear-gradient(to bottom, #d0d0d0 0%, #b0b0b0 50%, #909090 100%);
+}
+
+#terminal-output::-webkit-scrollbar-button:active {
+ border: 1px inset #c0c0c0;
+ background: linear-gradient(to bottom, #a0a0a0 0%, #b0b0b0 50%, #d0d0d0 100%);
+}
diff --git a/index.html b/index.html
index 98bc7ef..f49eff4 100644
--- a/index.html
+++ b/index.html
@@ -16,29 +16,32 @@
<div class="modal" id="intro-modal">
<div class="modal-bg modal-exit"></div>
<div class="modal-container">
- <h3 class="text-center">Welcome to Retrowave Player</h3>
- <p class="mt-5">Here are the controls:</p>
+ <h3 class="text-center">WELCOME TO RETROWAVE PLAYER</h3>
+ <p class="mt-5">HERE ARE THE CONTROLS:</p>
<h4 class="mt-5">
- Play/Pause <span class="controls">SPACE or Click or Touch</span>
+ PLAY/PAUSE <span class="controls">SPACE OR CLICK OR TOUCH</span>
</h4>
<h4 class="mt-5">
- Volume Up <span class="controls">w or Swipe Up</span>
+ VOLUME UP <span class="controls">W OR SWIPE UP</span>
</h4>
<h4 class="mt-5">
- Volume Down <span class="controls">s or Swipe Down</span>
+ VOLUME DOWN <span class="controls">S OR SWIPE DOWN</span>
</h4>
<h4 class="mt-5">
- Next Track<span class="controls"> n or Press the Refresh Button</span>
+ NEXT TRACK<span class="controls"> N OR PRESS THE REFRESH BUTTON</span>
</h4>
<h4 class="mt-5">
- Toggle Controls<span class="controls"> h</span>
+ TOGGLE CONTROLS<span class="controls"> H</span>
+ </h4>
+ <h4 class="mt-5">
+ OPEN TERMINAL<span class="controls"> T</span>
</h4>
<p class="mt-5">
- (You can download the music history of your current browser by
- clicking the history link on the player)
+ (YOU CAN DOWNLOAD THE MUSIC HISTORY OF YOUR CURRENT BROWSER BY
+ CLICKING THE HISTORY LINK ON THE PLAYER)
</p>
- <p class="mt-5">All the music is fetched from retrowave.ru</p>
- <div id="warning">⚠️ WARNING: This application contains strobing/flashing lights</div>
+ <p class="mt-5">ALL THE MUSIC IS FETCHED FROM RETROWAVE.RU</p>
+ <div id="warning">⚠️ WARNING: THIS APPLICATION CONTAINS STROBING/FLASHING LIGHTS</div>
<button class="modal-close modal-exit" id="initButton">X</button>
</div>
</div>
@@ -78,22 +81,23 @@
</svg>
</div>
<div class="no-pause buttons refresh toggleable" title="NEXT TRACK">🔃</div>
+ <div class="no-pause buttons terminal-btn toggleable" title="OPEN TERMINAL">⌨️</div>
<div class="title-content">
- <div class="intro">Now Playing</div>
+ <div class="intro">NOW PLAYING</div>
<hr />
- <h3 id="track-name">Retrowave Player</h3>
+ <h3 id="track-name">RETROWAVE PLAYER</h3>
</div>
<div class="gradient-overlay"></div>
<div class="color-overlay"></div>
<div class="footer toggleable">
- <div title="DOWNLOAD YOUR PLAYLIST HISTORY" id="history" class="no-pause footer-items">history</div>
+ <div title="DOWNLOAD YOUR PLAYLIST HISTORY" id="history" class="no-pause footer-items">HISTORY</div>
<div id="source">
<a
title="SOURCE CODE"
class="no-pause footer-items"
href="https://git.indrajith.dev/retrowave-player/"
target="_blank"
- >source code</a
+ >SOURCE CODE</a
>
</div>
<div id="retrowaveru" class="no-pause">
@@ -102,7 +106,7 @@
class="no-pause footer-items"
href="http://retrowave.ru/"
target="_blank"
- >retrowave.ru</a
+ >RETROWAVE.RU</a
>
</div>
<div id="guestbook" class="no-pause">
@@ -111,13 +115,45 @@
class="no-pause footer-items"
href="https://indrajith.atabook.org/"
target="_blank"
- >guestbook</a
+ >GUESTBOOK</a
>
</div>
</div>
<!-- <div id="upload-info" class="no-pause" title="Upload a playlist (downloaded from history)">Upload</div> -->
</div>
</div>
+ <div id="terminal-overlay" class="terminal-overlay hidden">
+ <div class="terminal-window">
+ <div class="terminal-header">
+ <span class="terminal-title">Retrowave Terminal</span>
+ <span class="terminal-close">□</span>
+ </div>
+ <div class="terminal-content">
+ <div id="terminal-output">
+ <div class="terminal-line">Welcome to Retrowave Terminal</div>
+ <div class="terminal-line">Type 'help' for available commands</div>
+ <div class="terminal-line"></div>
+ <div class="terminal-line">Available commands:</div>
+ <div class="terminal-line"> help - Show this help message</div>
+ <div class="terminal-line"> play - Start/resume playback</div>
+ <div class="terminal-line"> pause - Pause playback</div>
+ <div class="terminal-line"> next - Skip to next track</div>
+ <div class="terminal-line"> volume [0-10] - Set volume (0-10)</div>
+ <div class="terminal-line"> status - Show current track info</div>
+ <div class="terminal-line"> history - Download playlist history</div>
+ <div class="terminal-line"> effect - Change visual effect</div>
+ <div class="terminal-line"> fullscreen - Toggle fullscreen mode</div>
+ <div class="terminal-line"> clear - Clear terminal</div>
+ <div class="terminal-line"> exit - Close terminal</div>
+ <div class="terminal-line"></div>
+ </div>
+ <div class="terminal-input-line">
+ <span class="terminal-prompt">indrajith@retrowave:$ </span>
+ <input type="text" id="terminal-input" class="terminal-input" autocomplete="off" spellcheck="false">
+ </div>
+ </div>
+ </div>
+ </div>
<div id="codef-canvas"></div>
<div class="OVR hidden"></div>
<div class="ERRORS hidden"></div>
diff --git a/player.js b/player.js
index e9724ad..3f1bfe7 100644
--- a/player.js
+++ b/player.js
@@ -9,6 +9,11 @@
let refreshBtn = document.querySelector(".refresh");
let ovr = document.querySelector(".OVR");
let fullScreenBtn = document.querySelector(".fullscreen");
+ let terminalBtn = document.querySelector(".terminal-btn");
+ let terminalOverlay = document.getElementById("terminal-overlay");
+ let terminalInput = document.getElementById("terminal-input");
+ let terminalOutput = document.getElementById("terminal-output");
+ let terminalClose = document.querySelector(".terminal-close");
let errorEl = document.querySelector(".ERRORS");
let currentEffectIndex = 0;
const modalEl = document.getElementById("intro-modal");
@@ -113,15 +118,15 @@
});
document.addEventListener("keyup", (event) => {
+ if (!terminalOverlay.classList.contains("hidden")) {
+ return;
+ }
+
const { key } = event;
switch (key) {
case " ":
togglePlay();
break;
- case "a":
- break;
- case "d":
- break;
case "w":
volumeUp();
break;
@@ -143,6 +148,9 @@
case "e":
rotateHydraEffect();
break;
+ case "t":
+ toggleTerminal();
+ break;
}
});
@@ -255,10 +263,11 @@
}
function updateInfo(trackDetails) {
- titleEl.innerText = trackDetails.title;
- document.title = `Now Playing... ${trackDetails.title}`;
+ const trackTitle = trackDetails.title.toString().toUpperCase() || "Unknown Track";
+ titleEl.innerText = trackTitle;
+ document.title = `Now Playing... ${trackTitle}`;
coverArtEl.style.backgroundImage = `url("${retroWaveRu}${trackDetails.artworkUrl}")`;
- ovr.innerHTML = `${trackDetails.title}`;
+ ovr.innerHTML = `> ${trackTitle}`;
}
function getHistory() {
@@ -324,6 +333,27 @@ https://retrowave.ru/${musicData.streamUrl}
fullScreenBtn.addEventListener("click", () => {
toggleFullScreen();
});
+
+ terminalBtn.addEventListener("click", () => {
+ toggleTerminal();
+ });
+
+ terminalClose.addEventListener("click", () => {
+ closeTerminal();
+ });
+
+ terminalInput.addEventListener("keydown", (e) => {
+ if (e.key === "Enter") {
+ executeCommand(terminalInput.value.trim());
+ terminalInput.value = "";
+ }
+ });
+
+ document.addEventListener("keydown", (e) => {
+ if (e.key === "Escape" && !terminalOverlay.classList.contains("hidden")) {
+ closeTerminal();
+ }
+ });
}
async function toggleFullScreen() {
@@ -469,4 +499,177 @@ https://retrowave.ru/${musicData.streamUrl}
);
}
}
+
+ function toggleTerminal() {
+ terminalOverlay.classList.toggle("hidden");
+ if (!terminalOverlay.classList.contains("hidden")) {
+ terminalInput.focus();
+ }
+ }
+
+ function closeTerminal() {
+ terminalOverlay.classList.add("hidden");
+ }
+
+ function addTerminalLine(text, isCommand = false) {
+ const line = document.createElement("div");
+ line.className = "terminal-line";
+ if (isCommand) {
+ line.innerHTML = `<span style="color: #000000; font-weight: normal;">indrajith@retrowave:$ ${text}</span>`;
+ } else {
+ line.textContent = text;
+ }
+ terminalOutput.appendChild(line);
+ terminalOutput.scrollTop = terminalOutput.scrollHeight;
+ }
+
+ function executeCommand(command) {
+ if (!command) return;
+
+ addTerminalLine(command, true);
+
+ const args = command.toLowerCase().split(' ');
+ const cmd = args[0];
+
+ switch (cmd) {
+ case 'help':
+ addTerminalLine('Available commands:');
+ addTerminalLine(' help - Show this help message');
+ addTerminalLine(' play - Start/resume playback');
+ addTerminalLine(' pause - Pause playback');
+ addTerminalLine(' next - Skip to next track');
+ addTerminalLine(' volume [0-10] - Set volume (0-10)');
+ addTerminalLine(' status - Show current track info');
+ addTerminalLine(' history - Download playlist history');
+ addTerminalLine(' effect [list|name] - Change/list visual effects');
+ addTerminalLine(' fullscreen - Toggle fullscreen mode');
+ addTerminalLine(' clear - Clear terminal');
+ addTerminalLine(' exit - Close terminal');
+ break;
+
+ case 'play':
+ if (howlerInstance && !isPlaying) {
+ togglePlay();
+ addTerminalLine('Playback resumed.');
+ } else if (isPlaying) {
+ addTerminalLine('Already playing.');
+ } else {
+ addTerminalLine('No track loaded.');
+ }
+ break;
+
+ case 'pause':
+ if (howlerInstance && isPlaying) {
+ togglePlay();
+ addTerminalLine('Playback paused.');
+ } else {
+ addTerminalLine('Not currently playing.');
+ }
+ break;
+
+ case 'next':
+ if (howlerInstance) {
+ playNextTrack();
+ addTerminalLine('Skipped to next track.');
+ } else {
+ addTerminalLine('No track loaded.');
+ }
+ break;
+
+ case 'volume':
+ if (args[1]) {
+ const vol = parseInt(args[1]);
+ if (vol >= 0 && vol <= 10) {
+ volume = vol / 10;
+ if (howlerInstance) setVolume();
+ addTerminalLine(`Volume set to ${vol}/10`);
+ } else {
+ addTerminalLine('Volume must be between 0 and 10.');
+ }
+ } else {
+ addTerminalLine(`Current volume: ${Math.round(volume * 10)}/10`);
+ }
+ break;
+
+ case 'status':
+ if (currentTracks.length > 0) {
+ const track = currentTracks[0];
+ addTerminalLine(`Now playing: ${track.title}`);
+ addTerminalLine(`Status: ${isPlaying ? 'Playing' : 'Paused'}`);
+ addTerminalLine(`Volume: ${Math.round(volume * 10)}/10`);
+ } else {
+ addTerminalLine('No track loaded.');
+ }
+ break;
+
+ case 'history':
+ downloadHistory();
+ addTerminalLine('Playlist history downloaded.');
+ break;
+
+ case 'effect':
+ if (args[1]) {
+ if (args[1] === 'list') {
+ addTerminalLine('Available effects:');
+ addTerminalLine(' vernoi - Voronoi pattern effect');
+ addTerminalLine(' waveyzz - Wave synthesis effect');
+ addTerminalLine(' oscrotate - Oscillating rotation effect');
+ addTerminalLine('Usage: effect <effect_name> or effect list');
+ } else {
+ const effectName = args[1].toLowerCase();
+ let effectIndex = -1;
+
+ switch (effectName) {
+ case 'vernoi':
+ effectIndex = 0;
+ break;
+ case 'waveyzz':
+ effectIndex = 1;
+ break;
+ case 'oscrotate':
+ effectIndex = 2;
+ break;
+ default:
+ addTerminalLine(`Unknown effect: ${effectName}`);
+ addTerminalLine('Type "effect list" to see available effects.');
+ break;
+ }
+
+ if (effectIndex !== -1) {
+ try {
+ hydraEffects[effectIndex]();
+ currentEffectIndex = effectIndex;
+ addTerminalLine(`Effect changed to: ${effectName}`);
+ } catch (error) {
+ addTerminalLine('Failed to apply effect.');
+ }
+ }
+ }
+ } else {
+ rotateHydraEffect();
+ addTerminalLine('Visualization changed to next effect.');
+ }
+ break;
+
+ case 'fullscreen':
+ toggleFullScreen();
+ addTerminalLine('Toggled fullscreen mode.');
+ break;
+
+ case 'clear':
+ terminalOutput.innerHTML = '';
+ break;
+
+ case 'exit':
+ closeTerminal();
+ break;
+
+ default:
+ addTerminalLine(`Command not found: ${cmd}`);
+ addTerminalLine('Type "help" for available commands.');
+ break;
+ }
+
+ addTerminalLine('');
+ }
})();