From dbb70fc743d1830510e4c0579c59afa58d1db77d Mon Sep 17 00:00:00 2001 From: codey Date: Thu, 14 Aug 2025 11:40:02 -0400 Subject: [PATCH] misc --- src/components/AppLayout.jsx | 1 - src/components/AudioPlayer.jsx | 7 +- src/components/Footer.astro | 4 +- src/components/TRip/MediaRequestForm.jsx | 128 ++++++++++++++++++----- src/config.js | 3 +- src/pages/TRip/index.astro | 3 +- src/pages/TRip/requests.astro | 4 +- 7 files changed, 112 insertions(+), 38 deletions(-) diff --git a/src/components/AppLayout.jsx b/src/components/AppLayout.jsx index 6e87b59..6228178 100644 --- a/src/components/AppLayout.jsx +++ b/src/components/AppLayout.jsx @@ -14,7 +14,6 @@ const MediaRequestForm = lazy(() => import('./TRip/MediaRequestForm.jsx')); const RequestManagement = lazy(() => import('./TRip/RequestManagement.jsx')); const Player = lazy(() => import('./AudioPlayer.jsx')); - export default function Root({ child }) { window.toast = toast; const theme = document.documentElement.getAttribute("data-theme") diff --git a/src/components/AudioPlayer.jsx b/src/components/AudioPlayer.jsx index 54541f7..24b6938 100644 --- a/src/components/AudioPlayer.jsx +++ b/src/components/AudioPlayer.jsx @@ -11,7 +11,6 @@ const STATIONS = { rock: { label: "Rock" }, rap: { label: "Rap" }, electronic: { label: "Electronic" }, - classical: { label: "Classical" }, pop: { label: "Pop" }, }; @@ -84,8 +83,8 @@ export default function Player() { const hls = new Hls({ lowLatencyMode: true, abrEnabled: false, - liveSyncDuration: 2.5, // seconds behind live edge target - liveMaxLatencyDuration: 3.5, // max allowed latency before catchup + liveSyncDuration: 1.0, // seconds behind live edge target + liveMaxLatencyDuration: 2.0, // max allowed latency before catchup liveCatchUpPlaybackRate: 1.05, // playback speed when catching up }); @@ -111,8 +110,6 @@ export default function Player() { // Update elapsed time smoothly useEffect(() => { - if (!isPlaying) return; - const intervalId = setInterval(() => { const now = Date.now(); const deltaSec = (now - lastUpdateTimestamp.current) / 1000; diff --git a/src/components/Footer.astro b/src/components/Footer.astro index bf8e7d8..6c5d72d 100644 --- a/src/components/Footer.astro +++ b/src/components/Footer.astro @@ -1,10 +1,10 @@ --- -import { metaData, API_URL } from "../config"; +import { metaData, ENVIRONMENT } from "../config"; import RandomMsg from "../components/RandomMsg"; import { buildTime, buildNumber } from '../utils/buildTime.js'; const YEAR = new Date().getFullYear(); -var ENVIRONMENT = (Astro.url.hostname === "localhost") ? "Dev": "Prod"; + --- diff --git a/src/components/TRip/MediaRequestForm.jsx b/src/components/TRip/MediaRequestForm.jsx index d24ea33..7a7e353 100644 --- a/src/components/TRip/MediaRequestForm.jsx +++ b/src/components/TRip/MediaRequestForm.jsx @@ -4,7 +4,7 @@ import { Button } from "@mui/joy"; import { Accordion, AccordionTab } from "primereact/accordion"; import { AutoComplete } from "primereact/autocomplete"; import BreadcrumbNav from "./BreadcrumbNav"; -import { API_URL } from "@/config"; +import { API_URL, ENVIRONMENT } from "@/config"; export default function MediaRequestForm() { const [type, setType] = useState("artist"); @@ -25,6 +25,8 @@ export default function MediaRequestForm() { const debounceTimeout = useRef(null); const autoCompleteRef = useRef(null); + const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // Helper for delays + // Helper fetch wrapper that includes cookies automatically const authFetch = async (url, options = {}) => { const opts = { @@ -55,10 +57,17 @@ export default function MediaRequestForm() { debounceTimeout.current = setTimeout(async () => { try { + // Ensure at least 600ms between actual requests + const now = Date.now(); + if (!searchArtists.lastCall) searchArtists.lastCall = 0; + const elapsed = now - searchArtists.lastCall; + const minDelay = 600; // ms + if (elapsed < minDelay) await delay(minDelay - elapsed); + + searchArtists.lastCall = Date.now(); + const res = await authFetch( - `${API_URL}/trip/get_artists_by_name?artist=${encodeURIComponent( - query - )}`, + `${API_URL}/trip/get_artists_by_name?artist=${encodeURIComponent(query)}` ); if (!res.ok) throw new Error("API error"); const data = await res.json(); @@ -67,9 +76,11 @@ export default function MediaRequestForm() { toast.error("Failed to fetch artist suggestions."); setArtistSuggestions([]); } - }, 300); + }, 500); // debounce 500ms }; + + //helpers for string truncation const truncate = (text, maxLen) => maxLen <= 3 @@ -205,18 +216,23 @@ export default function MediaRequestForm() { if (type !== "artist" || albums.length === 0) return; let isCancelled = false; - const albumsToFetch = albums.filter((a) => !tracksByAlbum[a.id]); - if (albumsToFetch.length === 0) return; const fetchTracksSequentially = async () => { + const minDelay = 600; // ms between API requests for (const album of albumsToFetch) { if (isCancelled) break; setLoadingAlbumId(album.id); try { + const now = Date.now(); + if (!fetchTracksSequentially.lastCall) fetchTracksSequentially.lastCall = 0; + const elapsed = now - fetchTracksSequentially.lastCall; + if (elapsed < minDelay) await delay(minDelay - elapsed); + fetchTracksSequentially.lastCall = Date.now(); + const res = await authFetch(`${API_URL}/trip/get_tracks_by_album_id/${album.id}`); if (!res.ok) throw new Error("API error"); const data = await res.json(); @@ -299,7 +315,12 @@ export default function MediaRequestForm() { try { // Example: simulate submission delay await new Promise((resolve) => setTimeout(resolve, 1500)); - toast.success("Request submitted!"); + const allSelectedIds = Object.values(selectedTracks) + .filter(arr => Array.isArray(arr)) // skip null entries + .flat(); + toast.success(`Request submitted! (${allSelectedIds.length} tracks)`); + console.debug("Requested: ", selectedTracks); + console.debug("Flattened: ", allSelectedIds); } catch (err) { toast.error("Failed to submit request."); } finally { @@ -310,23 +331,75 @@ export default function MediaRequestForm() { return (
+ /* Accordion tab backgrounds & text */ + .p-accordion-tab { + background-color: #ffffff; + color: #000000; + } + [data-theme="dark"] .p-accordion-tab { + background-color: #1e1e1e; + color: #ffffff; + } + + /* Accordion header link */ + .p-accordion-header .p-accordion-header-link { + background-color: #f9f9f9; + color: #000000; + } + [data-theme="dark"] .p-accordion-header .p-accordion-header-link { + background-color: #1e1e1e !important; + color: #ffffff !important; + } + + /* Accordion content panel */ + .p-accordion-content { + background-color: #fafafa; + color: #000000; + } + [data-theme="dark"] .p-accordion-content { + background-color: #2a2a2a; + color: #ffffff; + } + + /* Track list UL/LI styling */ + .p-accordion-content ul { + padding-left: 0; + margin: 0; + list-style: none; + } + [data-theme="dark"] .p-accordion-content ul { + color: #ffffff; + } + + /* Track items */ + .p-accordion-content li { + background-color: #fff; + border-bottom: 1px solid #e5e5e5; + } + [data-theme="dark"] .p-accordion-content li { + background-color: #2a2a2a; + border-bottom: 1px solid #444; + } + + /* Checkboxes inside track list */ + .p-accordion-content input[type="checkbox"] { + accent-color: #1d4ed8; /* optional for consistent dark mode styling */ + } + + /* Loading spinner (optional darker style) */ + [data-theme="dark"] .animate-spin { + border-color: #555; + border-top-color: #1d4ed8; + } + + /* Small text like audio quality, duration, version */ + .p-accordion-content span { + color: #555; + } + [data-theme="dark"] .p-accordion-content span { + color: #aaa; + } + `} @@ -369,6 +442,7 @@ export default function MediaRequestForm() { field="artist" completeMethod={searchArtists} onChange={handleArtistChange} + minLength={3} placeholder="Artist" dropdown className="w-full" @@ -454,13 +528,13 @@ export default function MediaRequestForm() { checked={selected?.includes(String(track.id))} onChange={() => toggleTrack(id, track.id)} className="cursor-pointer" - aria-label={`Select track ${track.title}`} + aria-label={`Select track ${track.title} `} /> diff --git a/src/config.js b/src/config.js index ef749a9..3cf57b5 100644 --- a/src/config.js +++ b/src/config.js @@ -13,4 +13,5 @@ export const socialLinks = { }; export const MAJOR_VERSION = "0.0" -export const RELEASE_FLAG = "Alpha"; \ No newline at end of file +export const RELEASE_FLAG = "Alpha"; +export const ENVIRONMENT = import.meta.env.DEV ? "Dev" : "Prod"; \ No newline at end of file diff --git a/src/pages/TRip/index.astro b/src/pages/TRip/index.astro index 1a7ed50..ead22e6 100644 --- a/src/pages/TRip/index.astro +++ b/src/pages/TRip/index.astro @@ -1,8 +1,9 @@ --- -import MediaRequestForm from "@/components/qs2/MediaRequestForm" +import MediaRequestForm from "@/components/TRip/MediaRequestForm" import Base from "@/layouts/Base.astro"; import Root from "@/components/AppLayout.jsx"; import { verifyToken } from "@/utils/jwt"; +import { ENVIRONMENT } from "@/config"; const token = Astro.cookies.get("access_token")?.value; let user = null; diff --git a/src/pages/TRip/requests.astro b/src/pages/TRip/requests.astro index 586297c..52ae2f3 100644 --- a/src/pages/TRip/requests.astro +++ b/src/pages/TRip/requests.astro @@ -3,14 +3,16 @@ import MediaRequestForm from "@/components/TRip/MediaRequestForm" import Base from "@/layouts/Base.astro"; import Root from "@/components/AppLayout.jsx"; import { verifyToken } from "@/utils/jwt"; +import { ENVIRONMENT } from "@/config"; const token = Astro.cookies.get("access_token")?.value; let user = null; try { + const IS_DEV = (ENVIRONMENT==="Dev"); if (token) { user = verifyToken(token); - if (user) { + if (IS_DEV) { console.log("Verified!", user); } else { throw Error("Authentication required");