Skip to content

Commit

Permalink
feat: add dance recommendations to track page (#370)
Browse files Browse the repository at this point in the history
  • Loading branch information
cravend authored Apr 18, 2023
2 parents e831441 + fae65ce commit 3036eb6
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 6 deletions.
9 changes: 9 additions & 0 deletions app/app/(music)/track/[id]/TrackView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ const TrackView = ({
artist,
audioFeatures,
recommendations,
danceRecommendations,
}: {
track: SpotifyApi.TrackObjectFull;
artist: SpotifyApi.ArtistObjectFull;
audioFeatures: SpotifyApi.AudioFeaturesResponse;
recommendations: SpotifyApi.RecommendationsFromSeedsResponse;
danceRecommendations: string[];
}) => (
<>
<MusicHeader
Expand Down Expand Up @@ -60,6 +62,13 @@ const TrackView = ({
<div className="divider" />
<h4 className="font-black uppercase pb-2">Track Statistics</h4>
<AudioFeatures audioFeatures={audioFeatures} />
{danceRecommendations.length > 0 && (
<p className="pt-2 text-sm">
You could dance {danceRecommendations[0]}
{danceRecommendations[1] ? ` or ${danceRecommendations[1]}` : ""} to
this!
</p>
)}
<div className="divider" />
<h4 className="font-black uppercase">Similar Tracks</h4>
<TrackList tracks={recommendations.tracks} showAlbum />
Expand Down
15 changes: 14 additions & 1 deletion app/app/(music)/track/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import fetchServer from "@/lib/fetch/fetchServer";
import getDanceRecommendations from "@/lib/getDanceRecommendations";

import TrackView from "./TrackView";

Expand Down Expand Up @@ -39,7 +40,18 @@ const getData = async (id: string) => {
}
);

return { track, artist, audioFeatures, recommendations };
const danceRecommendations = getDanceRecommendations(
audioFeatures.tempo,
audioFeatures.time_signature
);

return {
track,
artist,
audioFeatures,
recommendations,
danceRecommendations,
};
};

const Page = async ({ params }: { params: { id: string } }) => {
Expand All @@ -51,6 +63,7 @@ const Page = async ({ params }: { params: { id: string } }) => {
artist={data.artist}
audioFeatures={data.audioFeatures}
recommendations={data.recommendations}
danceRecommendations={data.danceRecommendations}
/>
);
};
Expand Down
10 changes: 5 additions & 5 deletions components/music/AudioFeatures.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ const AudioFeatures = ({
value: audioFeatures.loudness + 60,
max: 65,
},
];
] as const;

return (
<div className="stats stats-vertical lg:stats-horizontal shadow w-full bg-primary text-primary-content">
{data.map((feature) => (
<div key={feature.name} className="stat">
<div className="stat-title">{feature.name}</div>
<div className="stat-value">
<p className="stat-title text-primary-content">{feature.name}</p>
<p className="stat-value">
{`${Math.round((feature.value / feature.max) * 100)}%`}
</div>
<div className="stat-desc">
</p>
<div className="stat-desc text-primary-content">
<progress
className="progress progress-secondary"
value={feature.value}
Expand Down
156 changes: 156 additions & 0 deletions lib/getDanceRecommendations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/**
* Dance & tempo data from https://www.music4dance.net/home/tempi.
*
* @see https://www.music4dance.net/home/tempi
*/
const DANCE_DATA = [
{
name: "Argentine Tango",
meter: 4,
bpm: [112, 140],
type: "Tango",
styles: ["Social"],
},
{
name: "Bachata",
meter: 4,
bpm: [108, 152],
type: "Latin",
styles: ["Social"],
},
{
name: "Balboa",
meter: 4,
bpm: [160, 260],
type: "Swing",
styles: ["Social"],
},
{
name: "Blues",
meter: 4,
bpm: [40, 100],
type: "Other",
styles: ["Social"],
},
{
name: "Carolina Shag",
meter: 4,
bpm: [108, 132],
type: "Swing",
styles: ["Social"],
},
{
name: "Cha Cha",
meter: 4,
bpm: [120, 124],
type: "Latin",
styles: ["American Rhythm", "International Latin"],
},
{
name: "Charleston",
meter: 4,
bpm: [200, 300],
type: "Swing",
styles: ["Social"],
},
{
name: "Collegiate Shag",
meter: 4,
bpm: [180, 200],
type: "Swing",
styles: ["Social"],
},
{
name: "Country Two Step",
meter: 2,
bpm: [168, 200],
type: "Other",
styles: ["Social"],
},
{
name: "East Coast Swing",
meter: 4,
bpm: [136, 144],
type: "Swing",
styles: ["American Rhythm"],
},
{
name: "Jive",
meter: 4,
bpm: [152, 176],
type: "Swing",
styles: ["International Latin"],
},
{
name: "Lindy Hop (Swing, Jitterbug)",
meter: 4,
bpm: [120, 180],
type: "Swing",
styles: ["Social"],
},
{
name: "Polka",
meter: 2,
bpm: [120, 124],
type: "Other",
styles: ["American Rhythm"],
},
{
name: "Quickstep",
meter: 4,
bpm: [192, 208],
type: "Foxtrot",
styles: ["International Standard"],
},
{
name: "Rumba",
meter: 4,
bpm: [100, 144],
type: "Latin",
styles: ["American Rhythm", "International Latin"],
},
{
name: "Salsa",
meter: 4,
bpm: [160, 220],
type: "Latin",
styles: ["Social"],
},
{
name: "Tango (Ballroom)",
meter: 4,
bpm: [120, 128],
type: "Tango",
styles: ["American Smooth", "International Standard"],
},
{
name: "Viennese Waltz",
meter: 3,
bpm: [159, 174],
type: "Waltz",
styles: ["American Smooth", "International Standard"],
},
{
name: "West Coast Swing",
meter: 4,
bpm: [112, 128],
type: "Swing",
styles: ["American Rhythm"],
},
];

const getDanceRecommendations = (tempo: number, timeSignature: number) =>
DANCE_DATA.filter(
(dance) =>
timeSignature === dance.meter &&
tempo >= dance.bpm[0] &&
tempo <= dance.bpm[1]
)
.sort((a, b) => {
const aMean = (a.bpm[0] + a.bpm[1]) / 2;
const bMean = (b.bpm[0] + b.bpm[1]) / 2;
return Math.abs(tempo - aMean) - Math.abs(tempo - bMean);
})
.map((dance) => dance.name);

export default getDanceRecommendations;

0 comments on commit 3036eb6

Please sign in to comment.