From 3a71e3e8dc8e02a03005374c65051b3630c32a72 Mon Sep 17 00:00:00 2001 From: Indrajith K L Date: Mon, 30 Jun 2025 18:24:18 +0530 Subject: New Features * Implements Terminal --- hg.css | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 70 +++++++++++++++----- player.js | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 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 @@ @@ -78,22 +81,23 @@
🔃
+
⌨️
-
Now Playing
+
NOW PLAYING

-

Retrowave Player

+

RETROWAVE PLAYER

+
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 = `indrajith@retrowave:$ ${text}`; + } 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 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(''); + } })(); -- cgit v1.2.3