import styled from "@emotion/styled"; import { Link as DefaultLink } from "@tanstack/react-router"; import axios from "axios"; import { ProgressBar } from "baseui/progress-bar"; import { LabelXSmall } from "baseui/typography"; import { useAtom, useAtomValue } from "jotai"; import _ from "lodash"; import { useCallback, useEffect, useRef } from "react"; import { playerAtom } from "../../../atoms/player"; import { userNowPlayingAtom } from "../../../atoms/userNowplaying"; import { API_URL } from "../../../consts"; import { useTimeFormat } from "../../../hooks/useFormat"; import styles from "./styles"; const Cover = styled.img` width: 54px; height: 54px; margin-right: 16px; border-radius: 5px; `; const Link = styled(DefaultLink)` text-decoration: none; &:hover { text-decoration: underline; } `; type NowPlayingProps = { did: string; }; function NowPlaying({ did }: NowPlayingProps) { const { formatTime } = useTimeFormat(); const progressInterval = useRef(null); const lastFetchedRef = useRef(0); const nowPlayingInterval = useRef(null); const [nowPlaying, setNowPlaying] = useAtom(userNowPlayingAtom); const player = useAtomValue(playerAtom); const fetchCurrentlyPlaying = useCallback(async () => { if (player === "rockbox" || player === null) { const [rockbox, spotify] = await Promise.all([ axios.get(`${API_URL}/now-playing`, { headers: { authorization: `Bearer ${localStorage.getItem("token")}`, }, params: { did, }, }), axios.get(`${API_URL}/spotify/currently-playing`, { headers: { authorization: `Bearer ${localStorage.getItem("token")}`, }, params: { did, }, }), ]); if (rockbox.data.title) { setNowPlaying({ ...nowPlaying, [did]: { title: rockbox.data.title, artist: rockbox.data.album_artist || rockbox.data.artist, artistUri: rockbox.data.artist_uri, songUri: rockbox.data.song_uri, albumUri: rockbox.data.album_uri, duration: rockbox.data.length, progress: rockbox.data.elapsed, albumArt: _.get(rockbox.data, "album_art"), isPlaying: rockbox.data.is_playing, }, }); } else { if (!spotify.data.item) { setNowPlaying({ ...nowPlaying, [did]: null, }); } } if (rockbox.data.title) { return; } } const { data } = await axios.get(`${API_URL}/spotify/currently-playing`, { headers: { authorization: `Bearer ${localStorage.getItem("token")}`, }, params: { did, }, }); if (data.item) { setNowPlaying({ ...nowPlaying, [did]: { title: data.item.name, artist: data.item.artists[0].name, artistUri: data.artistUri, songUri: data.songUri, albumUri: data.albumUri, duration: data.item.duration_ms, progress: data.progress_ms, albumArt: _.get(data, "item.album.images.0.url"), isPlaying: data.is_playing, }, }); } else { setNowPlaying({ ...nowPlaying, [did]: null, }); } lastFetchedRef.current = Date.now(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [setNowPlaying, did, player]); const startProgressTracking = useCallback(() => { if (progressInterval.current) { clearInterval(progressInterval.current); } progressInterval.current = window.setInterval(() => { setNowPlaying((prev) => { if (!prev[did] || !prev[did].duration) { return prev; } if (prev[did].progress >= prev[did].duration) { setTimeout(fetchCurrentlyPlaying, 2000); return prev; } if (prev[did].isPlaying) { const progress = prev[did].progress + 100; return { ...prev, [did]: { ...prev[did], progress, }, }; } return prev; }); }, 100); }, [fetchCurrentlyPlaying, setNowPlaying, did]); useEffect(() => { startProgressTracking(); return () => { if (progressInterval.current) { clearInterval(progressInterval.current); } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { if (nowPlayingInterval.current) { clearInterval(nowPlayingInterval.current); } nowPlayingInterval.current = window.setInterval(() => { fetchCurrentlyPlaying(); }, 15000); fetchCurrentlyPlaying(); return () => { if (nowPlayingInterval.current) { clearInterval(nowPlayingInterval.current); } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( <> {!!nowPlaying[did]?.duration && ( <>
{!!nowPlaying[did]?.albumUri && ( )} {!nowPlaying[did]?.albumUri && ( )}
{nowPlaying[did]?.songUri && ( {nowPlaying[did]?.title} )} {!nowPlaying[did]?.songUri && (
{nowPlaying[did]?.title}
)}
{!!nowPlaying[did]?.artistUri?.split("at://")[1] && ( {nowPlaying[did]?.artist} )} {!nowPlaying[did]?.artistUri?.split("at://")[1] && (
{nowPlaying[did]?.artist}
)}
{formatTime(nowPlaying[did]?.progress || 0)}
{formatTime(nowPlaying[did]?.duration || 0)}
)} ); } export default NowPlaying;