mirror of
https://github.com/FranP-code/spooky-spotify-showcase.git
synced 2025-10-13 00:02:36 +00:00
Base structure of top songs/artists
This commit is contained in:
170
src/app/_components/spotify-data.tsx
Normal file
170
src/app/_components/spotify-data.tsx
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
import SpotifyWebApi from "spotify-web-api-node";
|
||||||
|
|
||||||
|
const TRACKS_LIMIT = 20;
|
||||||
|
|
||||||
|
export default async function SpotifyData({
|
||||||
|
accessToken,
|
||||||
|
refreshToken,
|
||||||
|
}: {
|
||||||
|
accessToken: string;
|
||||||
|
refreshToken: string;
|
||||||
|
}) {
|
||||||
|
const spotifyApi = new SpotifyWebApi({
|
||||||
|
clientId: process.env.SPOTIFY_CLIENT_ID,
|
||||||
|
clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
|
||||||
|
redirectUri: process.env.SPOTIFY_REDIRECT_URI,
|
||||||
|
});
|
||||||
|
spotifyApi.setAccessToken(accessToken);
|
||||||
|
|
||||||
|
const albumsData = await spotifyApi.getMySavedAlbums({ limit: 20 });
|
||||||
|
const albums = albumsData.body.items;
|
||||||
|
|
||||||
|
const artistsData = await spotifyApi.getMyTopArtists({
|
||||||
|
limit: 20,
|
||||||
|
time_range: "short_term",
|
||||||
|
});
|
||||||
|
const artists = artistsData.body.items;
|
||||||
|
|
||||||
|
const tracksData = await spotifyApi.getMyTopTracks({
|
||||||
|
limit: TRACKS_LIMIT,
|
||||||
|
time_range: "short_term",
|
||||||
|
});
|
||||||
|
const tracks = tracksData.body.items.map((track, i) => ({
|
||||||
|
...track,
|
||||||
|
position: i + 1,
|
||||||
|
}));
|
||||||
|
const tracksByAlbum = tracksData.body.items.reduce((acc, track) => {
|
||||||
|
if (!acc[track.album.id]) {
|
||||||
|
const tracksWithAlbum = tracks.filter(
|
||||||
|
(t) => t.album.id === track.album.id,
|
||||||
|
);
|
||||||
|
acc[track.album.id] = {
|
||||||
|
album: track.album,
|
||||||
|
position:
|
||||||
|
tracksWithAlbum.reduce(
|
||||||
|
(acc, _track) => TRACKS_LIMIT / _track.position + acc,
|
||||||
|
0,
|
||||||
|
) / tracksWithAlbum.length,
|
||||||
|
tracks: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
acc[track.album.id].tracks.push(track);
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
console.log("Albums:", albums);
|
||||||
|
console.log("Artists:", artists);
|
||||||
|
console.log("Tracks:", tracks);
|
||||||
|
console.log("Tracks by album:", tracksByAlbum);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* <h3>Tracks images</h3>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tracks.map((track) => {
|
||||||
|
if (!track.album.images[0])
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
key={track.id}
|
||||||
|
src="https://via.placeholder.com/150"
|
||||||
|
alt={track.name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
style={{ width: "150px", height: "150px" }}
|
||||||
|
key={track.id}
|
||||||
|
src={track.album.images[0].url}
|
||||||
|
alt={track.name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
<h3>Tracks by album</h3>
|
||||||
|
{Object.values(tracksByAlbum)
|
||||||
|
.sort((a, b) => b.position - a.position)
|
||||||
|
.map((album) => (
|
||||||
|
<div key={album.album.id}>
|
||||||
|
<h4>{album.album.name}</h4>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style={{ width: "150px", height: "150px" }}
|
||||||
|
src={album.album.images[0].url}
|
||||||
|
alt={album.album.name}
|
||||||
|
/>
|
||||||
|
<ul>
|
||||||
|
{album.tracks.map((track) => (
|
||||||
|
<li key={track.id}>{track.name}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<h3>Albums images</h3>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{albums.map((album) => {
|
||||||
|
if (!album.album.images[0])
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
key={album.album.id}
|
||||||
|
src="https://via.placeholder.com/150"
|
||||||
|
alt={album.album.name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
style={{ width: "150px", height: "150px" }}
|
||||||
|
key={album.album.id}
|
||||||
|
src={album.album.images[0].url}
|
||||||
|
alt={album.album.name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Artists images</h3>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{artists.map((artist) => {
|
||||||
|
if (!artist.images[0])
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
key={artist.id}
|
||||||
|
src="https://via.placeholder.com/150"
|
||||||
|
alt={artist.name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
style={{ width: "150px", height: "150px" }}
|
||||||
|
key={artist.id}
|
||||||
|
src={artist.images[0].url}
|
||||||
|
alt={artist.name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ const spotifyApi = new SpotifyWebApi({
|
|||||||
const state = process.env.SPOTIFY_STATE as string;
|
const state = process.env.SPOTIFY_STATE as string;
|
||||||
|
|
||||||
export async function GET(req: NextApiRequest, res: NextApiResponse) {
|
export async function GET(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const scopes = ["user-library-read", "user-read-private"];
|
const scopes = ["user-library-read", "user-read-private", "user-top-read"];
|
||||||
const authorizeURL = spotifyApi.createAuthorizeURL(scopes, state);
|
const authorizeURL = spotifyApi.createAuthorizeURL(scopes, state);
|
||||||
|
|
||||||
console.log(authorizeURL);
|
console.log(authorizeURL);
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import Link from "next/link";
|
|||||||
import { LatestPost } from "@/app/_components/post";
|
import { LatestPost } from "@/app/_components/post";
|
||||||
import { api, HydrateClient } from "@/trpc/server";
|
import { api, HydrateClient } from "@/trpc/server";
|
||||||
import SpotifyLogin from "./_components/spotify-login";
|
import SpotifyLogin from "./_components/spotify-login";
|
||||||
import { NextApiRequest } from "next";
|
import SpotifyData from "./_components/spotify-data";
|
||||||
import { NextResponse } from "next/server";
|
import SpotifyWebApi from "spotify-web-api-node";
|
||||||
|
|
||||||
export default async function Home({
|
export default async function Home({
|
||||||
searchParams,
|
searchParams,
|
||||||
@@ -15,10 +15,34 @@ export default async function Home({
|
|||||||
|
|
||||||
const access_token = searchParams?.access_token;
|
const access_token = searchParams?.access_token;
|
||||||
const refresh_token = searchParams?.refresh_token;
|
const refresh_token = searchParams?.refresh_token;
|
||||||
const userLogged = access_token && refresh_token;
|
let userIsLogged = !!(
|
||||||
|
access_token &&
|
||||||
|
refresh_token &&
|
||||||
|
typeof access_token === "string" &&
|
||||||
|
typeof refresh_token === "string"
|
||||||
|
);
|
||||||
|
|
||||||
|
const spotifyApi = new SpotifyWebApi({
|
||||||
|
clientId: process.env.SPOTIFY_CLIENT_ID,
|
||||||
|
clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
|
||||||
|
redirectUri: process.env.SPOTIFY_REDIRECT_URI,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (userIsLogged)
|
||||||
|
try {
|
||||||
|
spotifyApi.setAccessToken(access_token as string);
|
||||||
|
await spotifyApi.getMe();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
userIsLogged = false;
|
||||||
|
}
|
||||||
void api.post.getLatest.prefetch();
|
void api.post.getLatest.prefetch();
|
||||||
|
|
||||||
|
console.log({
|
||||||
|
access_token,
|
||||||
|
refresh_token,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HydrateClient>
|
<HydrateClient>
|
||||||
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||||
@@ -55,7 +79,14 @@ export default async function Home({
|
|||||||
{hello ? hello.greeting : "Loading tRPC query..."}
|
{hello ? hello.greeting : "Loading tRPC query..."}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<SpotifyLogin />
|
{userIsLogged ? (
|
||||||
|
<SpotifyData
|
||||||
|
accessToken={access_token as string}
|
||||||
|
refreshToken={refresh_token as string}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<SpotifyLogin />
|
||||||
|
)}
|
||||||
<LatestPost />
|
<LatestPost />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Reference in New Issue
Block a user