diff options
| author | Bobby <[email protected]> | 2023-07-11 22:54:23 -0400 |
|---|---|---|
| committer | Bobby <[email protected]> | 2023-07-11 22:54:23 -0400 |
| commit | 1038819ecd3af7056fba5121ff46a2ac748468f9 (patch) | |
| tree | c215066d2915ebd95b80bfd1a226b26faaf7e5c8 | |
| parent | 0dfce68729c7bf768b035157849366fb40638bca (diff) | |
| download | thatcomputerscientist-1038819ecd3af7056fba5121ff46a2ac748468f9.tar.xz thatcomputerscientist-1038819ecd3af7056fba5121ff46a2ac748468f9.zip | |
Music working. Welcome page added
16 files changed, 525 insertions, 4 deletions
diff --git a/solitude/constants/welcome_playlist.py b/solitude/constants/welcome_playlist.py new file mode 100644 index 00000000..628327ce --- /dev/null +++ b/solitude/constants/welcome_playlist.py @@ -0,0 +1,40 @@ +""" + Shifoo's Solitude by Bobby + -------------------------- + Shifoo's Solitude is a Web Dungeon located beyond the Dark Hollows of the Endless Information SuperHighway — a dark yet tranquil place where all questions end, curiosity begins, the mind awakens, and one's journey begins anew in the solitude of a serene mind! + -------------------------- + + File: welcome_playlist.py + Description: Contains Metadata for tracks in the Welcome Page + Date: Jul 11, 2023 + Last Modified: Jul 11, 2023 +""" +BASE_MUSIC_DIR = "/static/@solitude/music/welcome" +BASE_COVER_ART_DIR = "/static/@solitude/music/welcome/cover_art" + +WELCOME_TRACKS = { + "SleepyRain": { + "title": "Sleepy Rain", + "artist": "lorenzobuczek", + "location": f"{BASE_MUSIC_DIR}/sleepy_rain.mp3", + "cover_art": f"{BASE_COVER_ART_DIR}/sleepy_rain.webp", + }, + "RainAndNostalgia": { + "title": "Rain and Nostalgia v60s", + "artist": "lesfm", + "location": f"{BASE_MUSIC_DIR}/rain_and_nostalgia_v60s.mp3", + "cover_art": f"{BASE_COVER_ART_DIR}/default.jpeg", + }, + "WishYouWereHere": { + "title": "Wish You Were Here", + "artist": "Lofi_hour", + "location": f"{BASE_MUSIC_DIR}/wish_you_were_here.mp3", + "cover_art": f"{BASE_COVER_ART_DIR}/wish_you_were_here.webp", + }, + "Dripping": { + "title": "Dripping", + "artist": "Lofi_hour", + "location": f"{BASE_MUSIC_DIR}/dripping.mp3", + "cover_art": f"{BASE_COVER_ART_DIR}/dripping.webp", + }, +} diff --git a/solitude/urls.py b/solitude/urls.py index 68819664..c4458ebe 100644 --- a/solitude/urls.py +++ b/solitude/urls.py @@ -5,5 +5,5 @@ from . import views app_name = 'solitude' urlpatterns = [ - path('', views.home, name='home'), + path('', views.welcome, name='welcome'), ] diff --git a/solitude/views.py b/solitude/views.py index 212c84eb..da2e06ca 100644 --- a/solitude/views.py +++ b/solitude/views.py @@ -1,7 +1,12 @@ from django.shortcuts import render +from .constants.welcome_playlist import WELCOME_TRACKS + +import json # Create your views here. TEMPLATE_BASE_PATH = '@solitude' -def home(request): - return render(request, f'{TEMPLATE_BASE_PATH}/welcome.html') +def welcome(request): + return render(request, f'{TEMPLATE_BASE_PATH}/welcome.html', { + 'playlist_tracks': str(json.dumps(WELCOME_TRACKS)) + }) diff --git a/static/@solitude/css/shared.css b/static/@solitude/css/shared.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/static/@solitude/css/shared.css diff --git a/static/@solitude/css/welcome/audio.css b/static/@solitude/css/welcome/audio.css new file mode 100644 index 00000000..ca5b144c --- /dev/null +++ b/static/@solitude/css/welcome/audio.css @@ -0,0 +1,142 @@ +.audio-bars { + position: relative; + display: flex; + width: auto; + transform: scale3d(2, 2, 1); /* EZ SCALE */ +} +.bar { + background: #fff; + height: 20px; + width: 2px; + margin-right: 2px; +} +.bar:last-child { + margin-right: 0; +} + +@keyframes sound { + 0% { + transform: scale3d(1, 0.1, 1); + } + 100% { + transform: scale3d(1, 1, 1); + } +} +@keyframes sound2 { + 0% { + transform: scale3d(1, 0.1, 1); + } + 100% { + transform: scale3d(1, 0.5, 1); + } +} + +.bar:nth-child(1) { + animation: sound2 0ms -800ms linear infinite alternate; + animation-duration: 200ms; +} +.bar:nth-child(2) { + animation: sound 0ms -800ms linear infinite alternate; + animation-duration: 300ms; +} +.bar:nth-child(3) { + animation: sound 0ms -800ms linear infinite alternate; + animation-duration: 200ms; +} +.bar:nth-child(4) { + animation: sound 0ms -800ms linear infinite alternate; + animation-duration: 250ms; +} +.bar:nth-child(5) { + animation: sound2 0ms -800ms linear infinite alternate; + animation-duration: 150ms; +} + +#welcome-playlist-player { + background: rgba(0, 0, 0, 0.5); + border-radius: 16px 0 0 16px; + box-shadow: 0 4px 30px rgba(255, 255, 255, 0.1); + backdrop-filter: blur(5.5px); + -webkit-backdrop-filter: blur(5.5px); + border: 1px solid rgba(0, 0, 0, 0.3); + padding: 16px; + position: absolute; + bottom: 2rem; + right: 0; + display: flex; + flex-direction: row; + align-items: center; + gap: 1.5rem; + transition: all 0.5s ease; +} + +.controls { + display: flex; + justify-content: center; + align-items: center; + width: 1rem; + height: 1rem; + padding: 0.8rem; + border: 0.2rem solid var(--button-color); + border-radius: 50%; + filter: drop-shadow(0 0 0.5rem rgba(255, 255, 255, 0.8)); +} + +.player { + display: flex; + flex-direction: row; + align-items: center; + gap: 1.5rem; +} + +.play { + height: 0; + width: 0; + margin-left: calc(2 * 0.25 * var(--button-height)); + /*margin-left: 17px;*/ + background: none; + border: none; + border-top: var(--button-height) solid transparent; + border-bottom: var(--button-height) solid transparent; + border-left: calc(var(--button-height) * 2 * 0.86) solid var(--button-color); +} + +.pause { + position: relative; + background: none; + border: none; + height: calc(var(--button-height) * 2); + width: calc(var(--button-height) * 2 * 0.86); +} +.pause:before, +.pause:after { + content: ""; + position: absolute; + top: 0; + height: 100%; + width: 33%; + background: var(--button-color); +} +.pause:before { + left: 0; +} +.pause:after { + right: 0; +} + +.hidden { + display: none; +} + +.title { + color: #7679f5; +} + +.artist { + color: #e2fdff; +} + +.track { + letter-spacing: 0.1rem; +} + diff --git a/static/@solitude/css/welcome/welcome.css b/static/@solitude/css/welcome/welcome.css new file mode 100644 index 00000000..22a1a747 --- /dev/null +++ b/static/@solitude/css/welcome/welcome.css @@ -0,0 +1,98 @@ +/* + Shifoo's Solitude by Bobby + -------------------------- + Shifoo's Solitude is a Web Dungeon located beyond the Dark Hollows of the Endless Information SuperHighway — a dark yet tranquil place where all questions end, curiosity begins, the mind awakens, and one's journey begins anew in the solitude of a serene mind! + -------------------------- + + File: welcome.css + Description: CSS for the welcome page (exclusively) + Date: Jul 11, 2023 + Last Modified: Jul 11, 2023 +*/ +@import url("https://fonts.googleapis.com/css2?family=Handlee&family=Poppins:wght@400&family=Share:wght@700&display=swap"); +@import url(audio.css); +:root { + --button-height: 0.5rem; + --button-color: #edd; + color-schema: dark; + font-family: "Handlee", cursive; +} + +* { + margin: 0; + padding: 0; + color: white; +} + +#cover-video { + position: fixed; + top: 0; + left: 0; + height: 100%; + width: 100%; + object-fit: cover; + z-index: -100; +} + +#cover-wrapper { + position: fixed; + top: 0; + left: 0; + min-width: 100%; + min-height: 100%; + height: 100%; + width: 100%; + background-color: rgba(0, 0, 0, 0.15); + z-index: -99; +} + +#welcome-content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 100vh; +} + +.cwrapper { + text-align: center; +} + +p { + margin: 0; + padding: 0; +} + +.small { + font-size: 0.8rem; + margin: 0.5rem 0; + color: #aaa; +} + +#welcome-button { + font-family: "Poppins", sans-serif; + font-size: 1.5rem; + padding: 0.5rem 1rem; + border-radius: 0.5rem; + transition: all 0.2s ease-in-out; + margin-top: 10rem; +} + +.description { + font-family: "Share", sans-serif; + font-size: 1rem; + margin-top: -4rem; + letter-spacing: 0.1rem; +} + +.text-box { + font-family: "Share", cursive; +} + +.text-box > h1 { + margin: 0; + font-size: 10rem; + color: rgb(255 255 255 / 60%); + padding: .5em; +} + diff --git a/static/@solitude/music/welcome/cover_art/default.jpeg b/static/@solitude/music/welcome/cover_art/default.jpeg Binary files differnew file mode 100644 index 00000000..39937665 --- /dev/null +++ b/static/@solitude/music/welcome/cover_art/default.jpeg diff --git a/static/@solitude/music/welcome/cover_art/dripping.webp b/static/@solitude/music/welcome/cover_art/dripping.webp Binary files differnew file mode 100644 index 00000000..3edb2ce3 --- /dev/null +++ b/static/@solitude/music/welcome/cover_art/dripping.webp diff --git a/static/@solitude/music/welcome/cover_art/sleepy_rain.webp b/static/@solitude/music/welcome/cover_art/sleepy_rain.webp Binary files differnew file mode 100644 index 00000000..a9bd0566 --- /dev/null +++ b/static/@solitude/music/welcome/cover_art/sleepy_rain.webp diff --git a/static/@solitude/music/welcome/cover_art/wish_you_were_here.webp b/static/@solitude/music/welcome/cover_art/wish_you_were_here.webp Binary files differnew file mode 100644 index 00000000..4ed66ea7 --- /dev/null +++ b/static/@solitude/music/welcome/cover_art/wish_you_were_here.webp diff --git a/static/@solitude/music/welcome/dripping.mp3 b/static/@solitude/music/welcome/dripping.mp3 Binary files differnew file mode 100644 index 00000000..b0e2e1c5 --- /dev/null +++ b/static/@solitude/music/welcome/dripping.mp3 diff --git a/static/@solitude/music/welcome/rain_and_nostalgia_v60s.mp3 b/static/@solitude/music/welcome/rain_and_nostalgia_v60s.mp3 Binary files differnew file mode 100644 index 00000000..b5146189 --- /dev/null +++ b/static/@solitude/music/welcome/rain_and_nostalgia_v60s.mp3 diff --git a/static/@solitude/music/welcome/sleepy_rain.mp3 b/static/@solitude/music/welcome/sleepy_rain.mp3 Binary files differnew file mode 100644 index 00000000..5b5e4eb8 --- /dev/null +++ b/static/@solitude/music/welcome/sleepy_rain.mp3 diff --git a/static/@solitude/music/welcome/wish_you_were_here.mp3 b/static/@solitude/music/welcome/wish_you_were_here.mp3 Binary files differnew file mode 100644 index 00000000..9aece37c --- /dev/null +++ b/static/@solitude/music/welcome/wish_you_were_here.mp3 diff --git a/static/@solitude/videos/solitude_welcome.mp4 b/static/@solitude/videos/solitude_welcome.mp4 Binary files differnew file mode 100644 index 00000000..623c5cd9 --- /dev/null +++ b/static/@solitude/videos/solitude_welcome.mp4 diff --git a/templates/@solitude/welcome.html b/templates/@solitude/welcome.html index a3fd191e..9c07dad2 100644 --- a/templates/@solitude/welcome.html +++ b/templates/@solitude/welcome.html @@ -1 +1,237 @@ -<h1>Shifoo's Solitude</h1>
\ No newline at end of file +{% load static %} +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Shifoo's Solitude | Welcome</title> + <meta name="description" content="Welcome to Shifoo's Solitude — A Web Dungeon located beyond the Dark Hollows of the Endless Information SuperHighway — a dark yet tranquil place where all questions end, curiosity begins, the mind awakens, and one's journey begins anew in the solitude of a serene mind!" /> + <link rel="stylesheet"type="text/css" href="{% static '@solitude/css/welcome/welcome.css' %}" /> + </head> + <body> + <video id="cover-video" autoplay muted playsinline loop preload="auto" nocontrols> + <source src="{% static '@solitude/videos/solitude_welcome.mp4' %}#t=0.1" type="video/mp4" /> + </video> + </div><div id="cover-wrapper"> + <div id="welcome-content"> + <div class="cwrapper"> + <div class="text-box"> + <h1>THE SOLITUDE</h1> + </div> + </div> + <p class="description"></p> + <button id="enter">Enter The Solitude!</button> + <div id="welcome-playlist-player"> + <div class="controls"> + <button role="play" id="playButton" class="play"></button> + <button role="pause" id="pauseButton" class="pause hidden"></button> + </div> + <img id="album-art" src="" alt="Album Art" width="100" height="100" /> + <div class="player"> + <div class="audio-bars"> + <div class="bar"></div> + <div class="bar"></div> + <div class="bar"></div> + <div class="bar"></div> + <div class="bar"></div> + </div> + <div class="audio-info"> + <p class="small">Currently Playing</p> + <p class="track"><span id="track-title" class="title">Sleepy Rain</span> by <span id="track-artist" class="artist">lorenzzo</span></p> + <p class="small"><span id="min-elap">00</span>:<span id="sec-elap">00</span> / <span id="min-dur">00</span>:<span id="sec-dur">00</span></p> + <audio id="audio" preload="auto" nocontrols preload="auto"> + <source src="" type="audio/mp3" /> + </audio> + </div> + </div> + </div> + </div> + <script> + Object.defineProperty(Array.prototype, 'shuffle', { + value: function() { + for (let i = this.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this[i], this[j]] = [this[j], this[i]]; + } + return this; + } + }); + + const playlistTracks = JSON.parse("{{ playlist_tracks }}".replace(/"/g, '"')); + const tracks = Object.entries(playlistTracks).map(track => track[1]).shuffle(); + + const controls = document.querySelector('.controls'); + const audio = document.querySelector('#audio'); + const trackTitle = document.querySelector('#track-title'); + const trackArtist = document.querySelector('#track-artist'); + const albumArt = document.querySelector('#album-art'); + const minElap = document.querySelector('#min-elap'); + const secElap = document.querySelector('#sec-elap'); + const minDur = document.querySelector('#min-dur'); + const secDur = document.querySelector('#sec-dur'); + + let currentTrack = 0; + + const loadAudio = new Promise((resolve, reject) => { + audio.addEventListener('canplaythrough', () => { + resolve(audio); + }); + }); + + async function playAudio () { + audio.src = tracks[currentTrack].location; + const duration = audio.duration; + audio.play().catch(e => { + window.addEventListener('click', () => { + controls.click(); + audio.play(); + }, { once: true }); + }); + return audio; + } + + function pauseAudio () { + audio.pause(); + } + + function nextTrack () { + currentTrack = (currentTrack + 1) % tracks.length; + audio.currentTime = 0; + playTrack(); + } + + function playTrack() { + const track = tracks[currentTrack]; + trackTitle.textContent = track.title; + trackArtist.textContent = track.artist; + albumArt.src = track.cover_art; + playAudio().then(audio => { + audio.addEventListener('ended', nextTrack); + }); + } + + function updateIntervals() { + const duration = audio.duration; + const currentTime = audio.currentTime; + const elapsed = Math.floor(currentTime); + const total = Math.floor(duration); + const minutesElapsed = Math.floor(elapsed / 60); + const secondsElapsed = elapsed % 60; + const minutesTotal = Math.floor(total / 60) || 0; + const secondsTotal = total % 60 || 0; + minElap.textContent = minutesElapsed < 10 ? `0${minutesElapsed}` : minutesElapsed; + secElap.textContent = secondsElapsed < 10 ? `0${secondsElapsed}` : secondsElapsed; + minDur.textContent = minutesTotal < 10 ? `0${minutesTotal}` : minutesTotal; + secDur.textContent = secondsTotal < 10 ? `0${secondsTotal}` : secondsTotal; + } + + function togglePlayPause () { + const buttons = Array.from(this.children); + let triggeredButton; + buttons.forEach(button => { + if (!button.classList.contains('hidden')) { + triggeredButton = button; + } + button.classList.toggle('hidden') + }); + signalTrigger(triggeredButton); + }; + + function signalTrigger (button) { + const role = button.getAttribute('role'); + switch (role) { + case 'play': + playAudio(); + break; + case 'pause': + pauseAudio(); + break; + } + } + + audio.currentTime = 0; + controls.addEventListener('click', togglePlayPause); + audio.addEventListener('timeupdate', updateIntervals); + + playTrack(); + + class TextScramble { + constructor(el) { + this.el = el + this.chars = '!<>-_\\/[]{}—=+*^?#________' + this.update = this.update.bind(this) + } + setText(newText) { + const oldText = this.el.innerText + const length = Math.max(oldText.length, newText.length) + const promise = new Promise((resolve) => this.resolve = resolve) + this.queue = [] + for (let i = 0; i < length; i++) { + const from = oldText[i] || '' + const to = newText[i] || '' + const start = Math.floor(Math.random() * 40) + const end = start + Math.floor(Math.random() * 40) + this.queue.push({ from, to, start, end }) + } + cancelAnimationFrame(this.frameRequest) + this.frame = 0 + this.update() + return promise + } + update() { + let output = '' + let complete = 0 + for (let i = 0, n = this.queue.length; i < n; i++) { + let { from, to, start, end, char } = this.queue[i] + if (this.frame >= end) { + complete++ + output += to + } else if (this.frame >= start) { + if (!char || Math.random() < 0.28) { + char = this.randomChar() + this.queue[i].char = char + } + output += `<span class="dud">${char}</span>` + } else { + output += from + } + } + this.el.innerHTML = output + if (complete === this.queue.length) { + this.resolve() + } else { + this.frameRequest = requestAnimationFrame(this.update) + this.frame++ + } + } + randomChar() { + return this.chars[Math.floor(Math.random() * this.chars.length)] + } + } + + const phrases = [ + 'Welcome to Shifoo\'s Solitude', + 'A Web Dungeon located beyond the Dark Hollows of the Endless Information SuperHighway', + 'a dark yet tranquil place where all questions end, curiosity begins, the mind awakens,', + 'and one\'s journey begins anew in the solitude of a serene mind!', + 'The Solitude awaits your arrival...' + ] + + const el = document.querySelector('.description') + const fx = new TextScramble(el) + + let counter = 0 + const next = () => { + fx.setText(phrases[counter]).then(() => { + setTimeout(next, 3200) + }) + counter = (counter + 1) % phrases.length + } + + next() + + </script> + + </body> +</html> |
