a simple web player for subsonic tinysub.devins.page
subsonic navidrome javascript
11
fork

Configure Feed

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

refactor: move strings to language file, rename MESSAGES to strings

intergrav 3dd7663e 648d8d43

+23 -17
+1
src/index.html
··· 209 209 </footer> 210 210 211 211 <script src="js/constants.js"></script> 212 + <script src="js/strings/en.js"></script> 212 213 <script src="js/utils.js"></script> 213 214 <script src="js/validation.js"></script> 214 215 <script src="js/selection-manager.js"></script>
+1 -1
src/js/auth.js
··· 67 67 await initializeApp(); 68 68 } catch (error) { 69 69 console.error("[Auth] Login failed:", error); 70 - ui.authError.textContent = `${MESSAGES.CONNECTION_ERROR} ${error.message}`; 70 + ui.authError.textContent = `${STRINGS.CONNECTION_ERROR} ${error.message}`; 71 71 state.api = null; 72 72 } finally { 73 73 handleLogin.isInProgress = false;
-7
src/js/constants.js
··· 56 56 SECTION_TOGGLE: "section-toggle", 57 57 }; 58 58 59 - const MESSAGES = { 60 - NO_TRACK_PLAYING: "no track playing", 61 - NO_ARTISTS: "no artists", 62 - NO_PLAYLISTS: "no playlists", 63 - CONNECTION_ERROR: "connection failed:", 64 - }; 65 - 66 59 const ICONS = { 67 60 PLAY: 68 61 document.getElementById("icon-play")?.src ||
+2 -2
src/js/library.js
··· 143 143 data: () => state.library, 144 144 expandedKey: "artists", 145 145 expandedMap: () => state.expanded.items.artists, 146 - message: MESSAGES.NO_ARTISTS, 146 + message: STRINGS.NO_ARTISTS, 147 147 artType: "artArtist", 148 148 itemMapper: (artist) => ({ 149 149 label: artist.title || artist.name, ··· 164 164 data: () => state.playlists, 165 165 expandedKey: "playlists", 166 166 expandedMap: () => state.expanded.items.playlists, 167 - message: MESSAGES.NO_PLAYLISTS, 167 + message: STRINGS.NO_PLAYLISTS, 168 168 artType: "artArtist", 169 169 itemMapper: (playlist) => ({ 170 170 label: playlist.name,
+5 -5
src/js/player.js
··· 5 5 return; 6 6 } 7 7 8 - ui.trackTitle.textContent = song.title || "Unknown"; 9 - ui.trackArtist.textContent = song.artist || "Unknown Artist"; 8 + ui.trackTitle.textContent = song.title || STRINGS.UNKNOWN_TRACK; 9 + ui.trackArtist.textContent = song.artist || STRINGS.UNKNOWN_ARTIST; 10 10 setCoverArt(song); 11 11 ui.player.src = state.api.getStreamUrl(song.id); 12 12 ui.player.play(); ··· 67 67 // clear player UI and reset to default state 68 68 function clearPlayerUI() { 69 69 ui.player.src = ""; 70 - ui.trackTitle.textContent = MESSAGES.NO_TRACK_PLAYING; 70 + ui.trackTitle.textContent = STRINGS.NO_TRACK_PLAYING; 71 71 ui.trackArtist.textContent = ""; 72 72 clearLyrics(); 73 73 ui.coverArt.src = "static/subsonic.png"; ··· 112 112 if (!song) return; 113 113 withMediaSession((ms) => { 114 114 ms.metadata = new MediaMetadata({ 115 - title: song.title || "Unknown", 116 - artist: song.artist || "Unknown Artist", 115 + title: song.title || STRINGS.UNKNOWN_TRACK, 116 + artist: song.artist || STRINGS.UNKNOWN_ARTIST, 117 117 album: song.album || "", 118 118 artwork: song.coverArt 119 119 ? [
+10
src/js/strings/en.js
··· 1 + const STRINGS = { 2 + NO_TRACK_PLAYING: "no track playing", 3 + NO_ARTISTS: "no artists", 4 + NO_PLAYLISTS: "no playlists", 5 + CONNECTION_ERROR: "connection failed:", 6 + UNKNOWN_TRACK: "unknown", 7 + UNKNOWN_ARTIST: "unknown artist", 8 + SERVER_URL_EMPTY: "server URL cannot be empty", 9 + SERVER_URL_REQUIRED: "server URL is required", 10 + };
+2
src/js/strings/index.js
··· 1 + // TODO: add language support 2 + export { STRINGS } from "./en.js";
+2 -2
src/js/validation.js
··· 14 14 // validate server URL is valid HTTP(S) format 15 15 function validateServerUrl(url) { 16 16 if (!url || typeof url !== "string") { 17 - return buildValidation(false, null, "Server URL is required"); 17 + return buildValidation(false, null, STRINGS.SERVER_URL_REQUIRED); 18 18 } 19 19 20 20 const trimmed = url.trim(); 21 21 if (!trimmed) { 22 - return buildValidation(false, null, "Server URL cannot be empty"); 22 + return buildValidation(false, null, STRINGS.SERVER_URL_EMPTY); 23 23 } 24 24 25 25 try {