Personal Site
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Make record player actually look like a record player

+173 -31
+173 -31
src/components/playing/NowPlaying.astro
··· 1 1 --- 2 2 import { spotifyNowPlaying, SpotifyError } from "./spotify"; 3 3 4 + import mp3Base from "/assets/mp3/base.png"; 5 + import mp3AlbumArtMask from "/assets/mp3/album-art-mask.png"; 6 + import mp3RecordCircle from "/assets/mp3/record-circle.png"; 7 + import mp3HeadCircle from "/assets/mp3/head-circle.png"; 8 + import mp3PlaybackHead from "/assets/mp3/playback-head.png"; 9 + 4 10 const track = await spotifyNowPlaying().catch((err) => { 5 11 if (!(err instanceof SpotifyError)) throw new Error("Unhandled exception"); 12 + if (err.code === "NO_CONTENT") return null; 13 + 6 14 console.error(err.code, err.human, err.details); 7 - 8 - if (err.code === "NO_CONTENT") return null; 9 15 return err; 10 16 }); 11 17 --- 12 18 13 - <section class="playing" id="now-playing"> 14 - { 15 - track ? ( 16 - !(track instanceof SpotifyError) ? ( 17 - <> 18 - Now playing: 19 - <img 20 - src={ 21 - track.album.images.sort( 22 - (a, b) => b.width + b.height - (a.width + a.height), 23 - )[0].url 24 - } 25 - alt="" 26 - /> 27 - {track.name} by {track.artists.map((x) => x.name).join(",")} 28 - </> 29 - ) : ( 30 - <> 31 - Error occurred {track.code} - {track.human} <br /> 32 - <code style="word-wrap: break-word;"> 33 - {JSON.stringify(track.details)} 34 - </code> 35 - <script set:html={`console.log(${JSON.stringify(track.details)})`} /> 36 - </> 37 - ) 38 - ) : ( 39 - <>Nothing is playing :(</> 40 - ) 41 - } 19 + <section 20 + class="playing" 21 + id="now-playing" 22 + style={` 23 + --mp3-base-png: url(${mp3Base.src}); 24 + --mp3-album-art-mask-png: url(${mp3AlbumArtMask.src}); 25 + --mp3-record-circle-png: url(${mp3RecordCircle.src}); 26 + --mp3-head-circle-png: url(${mp3HeadCircle.src}); 27 + --mp3-playback-head-png: url(${mp3PlaybackHead.src}); 28 + `} 29 + > 30 + <div 31 + class="player" 32 + style={`display: ${track instanceof SpotifyError ? "none" : "block"};` + 33 + new Array(5) 34 + .fill(0) 35 + .map( 36 + (_, i) => 37 + `--head-move-${(i + 2) * 10}: ${Math.random() * 20 + 25}deg;`, 38 + ) 39 + .join("")} 40 + > 41 + <div class="spinner"></div> 42 + 43 + <div class="record"> 44 + <img 45 + src={track instanceof SpotifyError || !track 46 + ? "https://undefined/" 47 + : track.album.images[0].url} 48 + alt="" 49 + class="art" 50 + style={`display: ${track instanceof SpotifyError ? "none" : "block"}`} 51 + /> 52 + </div> 53 + 54 + <div class="spinner hidden"> 55 + <div class="head"></div> 56 + </div> 57 + </div> 42 58 </section> 59 + 60 + {track instanceof SpotifyError && <script set:html={`console.error("Failed to load nowPlaying:", ${JSON.stringify(track)})`}></script>} 61 + 62 + <style> 63 + @keyframes spin { 64 + from { 65 + rotate: 0deg; 66 + } 67 + 68 + to { 69 + rotate: 360deg; 70 + } 71 + } 72 + 73 + @keyframes head-move { 74 + from { 75 + rotate: 0deg; 76 + } 77 + 78 + 10% { 79 + rotate: 25deg; 80 + } 81 + 82 + 20% { 83 + rotate: var(--head-move-20); 84 + } 85 + 86 + 30% { 87 + rotate: var(--head-move-30); 88 + } 89 + 90 + 40% { 91 + rotate: var(--head-move-40); 92 + } 93 + 94 + 50% { 95 + rotate: var(--head-move-50); 96 + } 97 + 98 + 60% { 99 + rotate: var(--head-move-60); 100 + } 101 + 102 + 70% { 103 + rotate: 25deg; 104 + } 105 + 106 + 80% { 107 + rotate: 0deg; 108 + } 109 + 110 + to { 111 + rotate: 0deg; 112 + } 113 + } 114 + 115 + .player { 116 + contain: strict; 117 + container: player / size; 118 + width: 100%; 119 + /* design size is 300px by 244px 120 + treat 1cqw = 3px. 121 + */ 122 + aspect-ratio: 300/244; 123 + 124 + image-rendering: pixelated; 125 + background-image: var(--mp3-base-png); 126 + background-size: contain; 127 + 128 + * { 129 + background-size: contain; 130 + } 131 + 132 + position: relative; 133 + 134 + & .record { 135 + position: absolute; 136 + top: calc((20 / 3) * 1cqw); 137 + left: calc((40 / 3) * 1cqw); 138 + 139 + width: calc((200 / 3) * 1cqw); 140 + height: calc((200 / 3) * 1cqw); 141 + background-image: var(--mp3-record-circle-png); 142 + 143 + animation: 30s linear forwards infinite spin; 144 + 145 + & .art { 146 + position: absolute; 147 + top: calc((50 / 3) * 1cqw); 148 + left: calc((50 / 3) * 1cqw); 149 + width: calc((100 / 3) * 1cqw); 150 + height: calc((100 / 3) * 1cqw); 151 + max-width: none; 152 + background-color: #008282; 153 + 154 + mask-image: var(--mp3-album-art-mask-png); 155 + mask-size: calc((100 / 3) * 1cqw) calc((100 / 3) * 1cqw); 156 + } 157 + } 158 + 159 + & .spinner { 160 + position: absolute; 161 + top: calc((30 / 3) * 1cqw); 162 + left: calc((214 / 3) * 1cqw); 163 + 164 + background-image: var(--mp3-head-circle-png); 165 + width: calc((60 / 3) * 1cqw); 166 + height: calc((60 / 3) * 1cqw); 167 + 168 + animation: 30s linear 5s infinite forwards head-move; 169 + 170 + &.hidden { 171 + background: none; 172 + } 173 + 174 + & .head { 175 + position: absolute; 176 + top: calc((-10 / 3) * 1cqw); 177 + left: calc((28 / 3) * 1cqw); 178 + width: calc((30 / 3) * 1cqw); 179 + height: calc((200 / 3) * 1cqw); 180 + background-image: var(--mp3-playback-head-png); 181 + } 182 + } 183 + } 184 + </style> 43 185 44 186 <script> 45 187 import {