Skip to content

Commit

Permalink
Display tracks on episode if available
Browse files Browse the repository at this point in the history
  • Loading branch information
jalvarado91 committed Mar 18, 2024
1 parent d90415c commit aa6dc1a
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 16 deletions.
81 changes: 79 additions & 2 deletions src/client/EpisodesScreen/EpisodeModalSheet/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
HeartFilled,
HeartOutline,
} from "@/client/components/Icons";
import { formatDate } from "@/client/helpers";
import { formatDate, formatTimeSecs } from "@/client/helpers";
import classNames from "classnames";
import { useFavorites, useIsFavoriteFast } from "../FavoritesStore";
import { MobilePlayerControls } from "../Player/MobilePlayerControls";
Expand All @@ -19,7 +19,8 @@ import {
import { useGetEpisode } from "../useEpisodeHooks";
import Sheet from "react-modal-sheet";
import create from "zustand";
import { useEffect } from "react";
import { trpc } from "@/utils/trpc";
import { cn } from "@/lib/utils";

interface EpisodeModalSheetStore {
isOpen: boolean;
Expand Down Expand Up @@ -106,10 +107,86 @@ function EpisodeSheetContent({ episodeId }: { episodeId: string }) {
</a>
<EpisodeSheetFavoriteToggle episodeId={episodeId} />
</div>
<EpisodeTracksList episodeId={episodeId} />
</div>
);
}

function EpisodeTracksList({ episodeId }: { episodeId: string }) {
const progress = usePlayerProgress();
const progressSecs = progress / 1000;

const { data, status } = trpc["episode.getTracks"].useQuery({
episodeId,
});

const loaded = status === "success";
const loadedData = loaded ? (data ? data : []) : [];

const possibleTracks = loadedData.filter((t) =>
t.timestamp ? progressSecs >= t.timestamp : false
);

const currentTrack = possibleTracks.at(-1);

return loaded && loadedData.length > 0 ? (
<>
<div className="py-1" />
<div className="py-4 rounded-lg text-white relative mx-4 bg-accent shadow border-accent">
<div className="absolute rounded-lg inset-0 bg-black/20"></div>
<div className="relative px-4 font-bold text-white text-lg mb-4">
{loadedData.length} Tracks
</div>
<div className="relative space-y">
{loadedData.map((t, i) => {
const isCurrent = currentTrack?.order === t.order;
return (
<div className="flex justify-between items-center px-4 py-2 space-x-4">
<div className="flex items-center space-x-3">
<div
className={cn(
"text-xs h-5 w-5 inline-flex p-1 items-center justify-center relative",
isCurrent && "bg-white text-accent rounded-full"
)}
>
{isCurrent && (
<div className="bg-white animate-ping [animation-duration:1500ms] absolute rounded-full origin-center p-2"></div>
)}
<div className="relative">{t.order}</div>
</div>
<div>
<div
className={cn(
"font-medium text-sm",
isCurrent && "!font-bold"
)}
>
{t.name}
</div>
<div
className={cn(
"text-white/80 text-sm",
isCurrent && "text-white/100"
)}
>
{t.artist}
</div>
</div>
</div>
{t.timestamp ? (
<div className="text-xs">{formatTimeSecs(t.timestamp)}</div>
) : (
<></>
)}
</div>
);
})}
</div>
</div>
</>
) : null;
}

export interface EpisodeSheetFavoriteToggleProps {
episodeId: string;
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/components/Episode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export function Episode(props: EpisodeProps) {
);
}

function PlayingAnimation() {
export function PlayingAnimation() {
const isPlaying = usePlayerPlaying();

return (
Expand Down
51 changes: 38 additions & 13 deletions src/server/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ export type EpisodeTrack = {
links: string[];
};

export type EpisodeTrackProjection = ReturnType<typeof episodeTrackProjection>;
export function episodeTrackProjection(t: EpisodeTrack) {
return {
order: t.order,
name: t.name,
artist: t.artist,
timestamp: t.timestamp,
} as const;
}

export type DBEpisode = {
source: "SOUNDCLOUD" | "MIXCLOUD";
duration: number;
Expand All @@ -34,20 +44,20 @@ export type DBEpisode = {

export type EpisodeProjection = ReturnType<typeof episodeProjection>;
export type EpisodeCollectiveSlugProjection = DBEpisode["collective_slug"];
export function episodeProjection(t: WithId<DBEpisode>) {
export function episodeProjection(e: WithId<DBEpisode>) {
return {
id: t._id.toString(),
source: t.source,
duration: t.duration,
releasedAt: t.release_date
? t.release_date.toISOString()
: t.created_time.toISOString(),
createadAt: t.created_time.toISOString(),
embedPlayerKey: t.key,
name: t.name,
permalinkUrl: t.url,
collectiveSlug: t.collective_slug,
artworkUrl: t.picture_large,
id: e._id.toString(),
source: e.source,
duration: e.duration,
releasedAt: e.release_date
? e.release_date.toISOString()
: e.created_time.toISOString(),
createadAt: e.created_time.toISOString(),
embedPlayerKey: e.key,
name: e.name,
permalinkUrl: e.url,
collectiveSlug: e.collective_slug,
artworkUrl: e.picture_large,
} as const;
}

Expand Down Expand Up @@ -215,6 +225,21 @@ export const episodeRouter = router({

return darkVibrantResult;
}),
"episode.getTracks": publicProcedure
.input(
z.object({
episodeId: z.string(),
})
)
.query(async ({ input, ctx }) => {
const trackCollection = ctx.db.collection<DBEpisode>("tracksOld");
const episode = await trackCollection.findOne({
_id: new ObjectId(input.episodeId),
});

const tracks = episode?.tracks ?? [];
return tracks.map(episodeTrackProjection);
}),
"episode.getFakeStreamUrl": publicProcedure
.input(
z.object({
Expand Down

0 comments on commit aa6dc1a

Please sign in to comment.