From dcf1a57289d61f7204150d45037ccda433ef01be Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Thu, 10 Oct 2024 13:27:47 +0100 Subject: [PATCH 1/4] Feat(setup/library): Automatically Scroll to Bottom on New Message --- .../app/(unprotected)/setup/library/page.tsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/web/app/(unprotected)/setup/library/page.tsx b/apps/web/app/(unprotected)/setup/library/page.tsx index 52e38aaa..5c7ab304 100644 --- a/apps/web/app/(unprotected)/setup/library/page.tsx +++ b/apps/web/app/(unprotected)/setup/library/page.tsx @@ -1,8 +1,7 @@ -"use client" +"use client"; -import getBaseURL from "@/lib/Server/getBaseURL";; - -import React, { useState, useEffect } from "react"; +import getBaseURL from "@/lib/Server/getBaseURL"; +import React, { useState, useEffect, useRef } from "react"; import useWebSocket from "react-use-websocket"; import { ScrollArea, ScrollBar } from "@music/ui/components/scroll-area"; import FileBrowser from "@/components/FileBrowser/FileBrowser"; @@ -10,11 +9,12 @@ import Link from "next/link"; export default function SetupLibrary() { const [messageHistory, setMessageHistory] = useState[]>([]); - + const scrollAreaRef = useRef(null); + const baseUrl = getBaseURL()?.replace(/^https?:\/\//, ''); const socketUrl = `ws://${baseUrl ?? window.location.hostname}/ws`; const { lastMessage } = useWebSocket(socketUrl); - + useEffect(() => { if (lastMessage !== null && typeof lastMessage.data === 'string') { const newMessage = new MessageEvent("message", { data: lastMessage.data }); @@ -24,6 +24,12 @@ export default function SetupLibrary() { } }, [lastMessage]); + useEffect(() => { + if (scrollAreaRef.current) { + scrollAreaRef.current.scrollTop = scrollAreaRef.current.scrollHeight; + } + }, [messageHistory]); + return ( <>
@@ -34,7 +40,7 @@ export default function SetupLibrary() {

Logs

- +
    {messageHistory.map((message) => (

    {message.data}

    @@ -51,4 +57,4 @@ export default function SetupLibrary() {
); -} +} \ No newline at end of file From 3fb7f5ba50c2533021923a972ed45fe2c11b837a Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Thu, 10 Oct 2024 13:28:24 +0100 Subject: [PATCH 2/4] Feat(Playlists): Conditionally Show Playlist Accordion if You Have Playlists --- apps/web/components/Layout/Playlists.tsx | 64 ++++++++++++------------ 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/apps/web/components/Layout/Playlists.tsx b/apps/web/components/Layout/Playlists.tsx index 419f032c..8b62819e 100644 --- a/apps/web/components/Layout/Playlists.tsx +++ b/apps/web/components/Layout/Playlists.tsx @@ -1,4 +1,4 @@ -"use client" +"use client"; import getSession from "@/lib/Authentication/JWT/getSession"; import { getPlaylist, getPlaylists, getUserInfoById } from "@music/sdk"; @@ -8,7 +8,7 @@ import { ListMusic, Plus } from "lucide-react"; import Link from "next/link"; import { useEffect, useState } from "react"; import CreatePlaylistDialog from "../Music/Playlist/CreatePlaylistDialog"; -import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@music/ui/components/accordion" +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@music/ui/components/accordion"; import { useSession } from "../Providers/AuthProvider"; interface Playlist extends OriginalPlaylist { @@ -17,7 +17,7 @@ interface Playlist extends OriginalPlaylist { export default function Playlists() { const [playlists, setPlaylists] = useState(null); - const { session } = useSession() + const { session } = useSession(); useEffect(() => { async function fetchData() { @@ -48,34 +48,36 @@ export default function Playlists() { return (
- - - - - Playlists - - - {playlists?.map(playlist => ( -
- - -

{playlist.name}

-

Playlist • {playlist.users.join(", ")}

- -
- ))} -
-
-
- -
- - - -
+ {playlists && playlists.length > 0 ? ( + + + + + Playlists + + + {playlists.map((playlist) => ( +
+ + +

{playlist.name}

+

Playlist • {playlist.users.join(", ")}

+ +
+ ))} +
+
+
+ ) : ( +
+ + + +
+ )}
); } \ No newline at end of file From 6a90f1252460c6698048aa70ad728718d35a4b4c Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Thu, 10 Oct 2024 13:29:29 +0100 Subject: [PATCH 3/4] Feat(LyricsOverlay): Check first 5 items for Synced Lyrics, if not found, use the first plain lyrics --- apps/web/components/Lyrics/LyricsOverlay.tsx | 36 +++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/apps/web/components/Lyrics/LyricsOverlay.tsx b/apps/web/components/Lyrics/LyricsOverlay.tsx index 54c51970..f782aa81 100644 --- a/apps/web/components/Lyrics/LyricsOverlay.tsx +++ b/apps/web/components/Lyrics/LyricsOverlay.tsx @@ -112,18 +112,36 @@ export default function LyricsOverlay({ children }: QueuePanelProps) { const fetchLyrics = async () => { if (song.id) { + const sanitizedSongName = song.name.replace(/\s*\(.*?\)\s*/g, ''); + const capitalizeFirstLetter = (str: string) => str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); + const capitalizedArtistName = capitalizeFirstLetter(song.artist); + const response = await fetch( - `https://lrclib.net/api/search?q=${encodeURIComponent(`${song.name} ${song.artist}`)}` + `https://lrclib.net/api/search?q=${encodeURIComponent(`${sanitizedSongName} ${capitalizedArtistName}`)}` ); const data: LyricsObjectResponse[] = await response.json(); - setCurrentLyrics(data[0]?.plainLyrics ?? "") - const slowdownFactor = reverb ? 1/0.7 : 1; - if (data[0]?.syncedLyrics) { - setLyrics(parseLyrics(data[0].syncedLyrics, slowdownFactor)); - setIsSyncedLyrics(true); - } else if (data[0]?.plainLyrics) { - setLyrics(parseLyrics(data[0].plainLyrics, slowdownFactor)); - setIsSyncedLyrics(false); + setCurrentLyrics(data[0]?.plainLyrics ?? ""); + + const slowdownFactor = reverb ? 1 / 0.7 : 1; + let foundSyncedLyrics = false; + + for (let i = 0; i < Math.min(data.length, 5); i++) { + if (data[i]?.syncedLyrics) { + setLyrics(parseLyrics(data[i]?.syncedLyrics ?? "", slowdownFactor)); + setIsSyncedLyrics(true); + foundSyncedLyrics = true; + break; + } + } + + if (!foundSyncedLyrics) { + for (let i = 0; i < Math.min(data.length, 5); i++) { + if (data[i]?.plainLyrics) { + setLyrics(parseLyrics(data[i]?.plainLyrics ?? "", slowdownFactor)); + setIsSyncedLyrics(false); + break; + } + } } } }; From c1941531a056a65f89b71cb8a92aab1df8dff862 Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Thu, 10 Oct 2024 13:30:10 +0100 Subject: [PATCH 4/4] Feat(music.rs): Populate Search Data when Finished Indexing --- crates/backend/src/routes/music.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/backend/src/routes/music.rs b/crates/backend/src/routes/music.rs index f704c2bb..2d951de9 100644 --- a/crates/backend/src/routes/music.rs +++ b/crates/backend/src/routes/music.rs @@ -9,9 +9,10 @@ use serde::Deserialize; use tokio::io::{AsyncReadExt, AsyncSeekExt}; use tokio::process::Command; use tokio_util::io::ReaderStream; -use tracing::{info, warn}; +use tracing::{error, info, warn}; use walkdir::WalkDir; +use crate::routes::search::populate_search_data; use crate::structures::structures::Artist; use crate::utils::compare::compare; use crate::utils::config::{get_config, save_config}; @@ -130,7 +131,7 @@ pub async fn process_library(path_to_library: web::Path) -> impl Respond } } - //https://musicbrainz.org/ws/2/release/cbaf43b4-0d8f-4b58-9173-9fe7298e04e9?inc=aliases+artist-credits+labels+discids+recordings+release-groups+media+discids+recordings+artist-credits+isrcs+artist-rels+release-rels+url-rels+recording-rels+work-rels+label-rels+place-rels+event-rels+area-rels+instrument-rels+series-rels+work-rels&fmt=json + // https://musicbrainz.org/ws/2/release/cbaf43b4-0d8f-4b58-9173-9fe7298e04e9?inc=aliases+artist-credits+labels+discids+recordings+release-groups+media+discids+recordings+artist-credits+isrcs+artist-rels+release-rels+url-rels+recording-rels+work-rels+label-rels+place-rels+event-rels+area-rels+instrument-rels+series-rels+work-rels&fmt=json let library_guard = library.lock().unwrap(); let elapsed = now.elapsed().as_secs(); @@ -148,6 +149,13 @@ pub async fn process_library(path_to_library: web::Path) -> impl Respond let json = serde_json::to_string(data_to_serialize).unwrap(); save_config(&json).await.unwrap(); + match populate_search_data().await { + Ok(_) => {}, + Err(e) => { + error!("Failed to populate search data: {:?}", e); + } + } + HttpResponse::Ok() .content_type("application/json; charset=utf-8") .body(json)