This commit is contained in:
2025-09-12 22:39:35 -04:00
parent 1d0b310228
commit 3afc944a67
6 changed files with 55 additions and 33 deletions

View File

@@ -7,6 +7,7 @@ import { usePrimeReactThemeSwitcher } from '@/hooks/usePrimeReactThemeSwitcher.j
import CustomToastContainer from '../components/ToastProvider.jsx'; import CustomToastContainer from '../components/ToastProvider.jsx';
import 'primereact/resources/themes/bootstrap4-light-blue/theme.css'; import 'primereact/resources/themes/bootstrap4-light-blue/theme.css';
import 'primereact/resources/primereact.min.css'; import 'primereact/resources/primereact.min.css';
import "primeicons/primeicons.css";
const LoginPage = lazy(() => import('./Login.jsx')); const LoginPage = lazy(() => import('./Login.jsx'));
const LyricSearch = lazy(() => import('./LyricSearch')); const LyricSearch = lazy(() => import('./LyricSearch'));
@@ -14,7 +15,7 @@ const MediaRequestForm = lazy(() => import('./TRip/MediaRequestForm.jsx'));
const RequestManagement = lazy(() => import('./TRip/RequestManagement.jsx')); const RequestManagement = lazy(() => import('./TRip/RequestManagement.jsx'));
const Player = lazy(() => import('./AudioPlayer.jsx')); const Player = lazy(() => import('./AudioPlayer.jsx'));
export default function Root({ child }) { export default function Root({ child, user = undefined }) {
window.toast = toast; window.toast = toast;
const theme = document.documentElement.getAttribute("data-theme") const theme = document.documentElement.getAttribute("data-theme")
usePrimeReactThemeSwitcher(theme); usePrimeReactThemeSwitcher(theme);
@@ -34,7 +35,7 @@ export default function Root({ child }) {
</Alert> */} </Alert> */}
{child == "LoginPage" && (<LoginPage client:only="react" />)} {child == "LoginPage" && (<LoginPage client:only="react" />)}
{child == "LyricSearch" && (<LyricSearch client:only="react" />)} {child == "LyricSearch" && (<LyricSearch client:only="react" />)}
{child == "Player" && (<Player client:only="react" />)} {child == "Player" && (<Player client:only="react" user={user} />)}
{child == "Memes" && <Memes client:only="react" />} {child == "Memes" && <Memes client:only="react" />}
{child == "qs2.MediaRequestForm" && <MediaRequestForm client:only="react" />} {child == "qs2.MediaRequestForm" && <MediaRequestForm client:only="react" />}
{child == "qs2.RequestManagement" && <RequestManagement client:only="react" />} {child == "qs2.RequestManagement" && <RequestManagement client:only="react" />}

View File

@@ -5,6 +5,7 @@ import Pause from "@mui/icons-material/Pause";
import "@styles/player.css"; import "@styles/player.css";
import { API_URL } from "@/config"; import { API_URL } from "@/config";
import { requireAuthHook } from "@/hooks/requireAuthHook";
const STATIONS = { const STATIONS = {
main: { label: "Main" }, main: { label: "Main" },
@@ -14,7 +15,8 @@ const STATIONS = {
pop: { label: "Pop" }, pop: { label: "Pop" },
}; };
export default function Player() {
export default function Player({ user }) {
const [activeStation, setActiveStation] = useState("main"); const [activeStation, setActiveStation] = useState("main");
const [isPlaying, setIsPlaying] = useState(false); const [isPlaying, setIsPlaying] = useState(false);
const [trackTitle, setTrackTitle] = useState(""); const [trackTitle, setTrackTitle] = useState("");
@@ -270,7 +272,8 @@ export default function Player() {
))} ))}
</div> </div>
<div className="c-containter"> <div className="c-containter">
<div className="music-container mt-8"> {user ? <span>Hello, {user.user}</span> : <span>Not logged in</span>}
< div className="music-container mt-8">
<section className="album-cover"> <section className="album-cover">
<div className="music-player__album" title="Album"> <div className="music-player__album" title="Album">
{trackAlbum} {trackAlbum}
@@ -328,7 +331,7 @@ export default function Player() {
</section> </section>
</div> </div>
<audio ref={audioElement} preload="none" /> <audio ref={audioElement} preload="none" />
</div> </div >
</> </>
); );
} }

View File

@@ -268,7 +268,7 @@ export default function MediaRequestForm() {
if (albumsToFetch.length === 0) return; if (albumsToFetch.length === 0) return;
const fetchTracksSequentially = async () => { const fetchTracksSequentially = async () => {
const minDelay = 500; // ms between API requests const minDelay = 650; // ms between API requests
setIsFetching(true); setIsFetching(true);
const totalAlbums = albumsToFetch.length; const totalAlbums = albumsToFetch.length;

View File

@@ -308,38 +308,56 @@ export default function RequestManagement() {
emptyMessage="No requests found." emptyMessage="No requests found."
onRowClick={handleRowClick} onRowClick={handleRowClick}
> >
<Column field="id" header="ID" style={{ width: "8rem" }} body={(row) => textWithEllipsis(row.id, "6rem")} />
<Column
field="id"
header="ID"
style={{ width: "6rem" }}
body={(row) => (
<span title={row.id}>
{row.id.split("-").slice(-1)[0]}
</span>
)}
/>
<Column field="target" header="Target" sortable style={{ width: "12rem" }} body={(row) => textWithEllipsis(row.target, "10rem")} /> <Column field="target" header="Target" sortable style={{ width: "12rem" }} body={(row) => textWithEllipsis(row.target, "10rem")} />
<Column field="tracks" header="# Tracks" style={{ width: "8rem" }} body={(row) => row.tracks} /> <Column field="tracks" header="# Tracks" style={{ width: "8rem" }} body={(row) => row.tracks} />
<Column field="status" header="Status" body={statusBodyTemplate} style={{ width: "10rem", textAlign: "center" }} sortable /> <Column field="status" header="Status" body={statusBodyTemplate} style={{ width: "10rem", textAlign: "center" }} sortable />
<Column field="progress" header="Progress" body={(row) => formatProgress(row.progress)} style={{ width: "8rem", textAlign: "center" }} sortable /> <Column field="progress" header="Progress" body={(row) => formatProgress(row.progress)} style={{ width: "8rem", textAlign: "center" }} sortable />
<Column
field="tarball"
header="Tarball"
body={(row) => {
const url = tarballUrl(row.tarball, row.quality || "FLAC");
return url ? (
<a
href={url}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:underline truncate block"
title={url.split("/").pop()}
>
{truncate(url.split("/").pop(), 16)}
</a>
) : (
"—"
);
}}
style={{ width: "10rem" }}
/>
<Column <Column
field="quality" field="quality"
header="Quality" header="Quality"
body={qualityBodyTemplate} body={qualityBodyTemplate}
style={{ width: "6rem", textAlign: "center" }} style={{ width: "6rem", textAlign: "center" }}
sortable /> sortable />
<Column
field="tarball"
header={
<span className="flex items-center">
<i className="pi pi-download mr-1" /> {/* download icon in header */}
Tarball
</span>
}
body={(row) => {
const url = tarballUrl(row.tarball, row.quality || "FLAC");
const encodedURL = encodeURI(url);
if (!url) return "—";
const fileName = url.split("/").pop();
return (
<a
href={encodedURL}
target="_blank"
rel="noopener noreferrer"
className="truncate text-blue-500 hover:underline"
title={fileName}
>
{truncate(fileName, 16)}
</a>
);
}}
style={{ width: "10rem" }}
/>
</DataTable> </DataTable>
</div> </div>
@@ -402,7 +420,7 @@ export default function RequestManagement() {
<p> <p>
<strong>Tarball:</strong>{" "} <strong>Tarball:</strong>{" "}
<a <a
href={tarballUrl(selectedRequest.tarball, selectedRequest.quality)} href={encodeURI(tarballUrl(selectedRequest.tarball, selectedRequest.quality))}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-blue-500 hover:underline" className="text-blue-500 hover:underline"

View File

@@ -9,7 +9,7 @@ const navItems = [
{ label: "Memes", href: "/memes" }, { label: "Memes", href: "/memes" },
{ label: "TRip", href: "/TRip", auth: true }, { label: "TRip", href: "/TRip", auth: true },
{ label: "Status", href: "https://status.boatson.boats", icon: ExitToApp }, { label: "Status", href: "https://status.boatson.boats", icon: ExitToApp },
{ label: "Git", href: "https://kode.boatson.boats", icon: ExitToApp }, // { label: "Git", href: "https://kode.boatson.boats", icon: ExitToApp },
]; ];

View File

@@ -1,13 +1,13 @@
--- ---
import Base from "../layouts/Base.astro"; import Base from "../layouts/Base.astro";
import Root from "../components/AppLayout.jsx"; import Root from "../components/AppLayout.jsx";
import "@styles/player.css"; import { requireAuthHook } from "@/hooks/requireAuthHook";
const user = await requireAuthHook(Astro);
--- ---
<Base> <Base>
<section> <section>
<div class="prose prose-neutral dark:prose-invert"> <div class="prose prose-neutral dark:prose-invert">
<Root child="Player" client:only="react"> <Root child="Player" user={user} client:only="react">
</Root> </Root>
</section> </section>
</Base> </Base>