diff --git a/package.json b/package.json
index b9bf870..603d48e 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,7 @@
"name": "music-chart",
"version": "0.1.0",
"private": true,
+ "type": "module",
"scripts": {
"dev": "next dev",
"build": "next build",
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
deleted file mode 100644
index a490e51..0000000
--- a/pnpm-workspace.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-ignoredBuiltDependencies:
- - '@tailwindcss/oxide'
- - sharp
- - unrs-resolver
diff --git a/src/app/charts/page.tsx b/src/app/charts/page.tsx
index e03c541..a3ec997 100644
--- a/src/app/charts/page.tsx
+++ b/src/app/charts/page.tsx
@@ -8,15 +8,22 @@ export default async function Charts() {
// const playlistId = "2fmFoUa7WNxIfvUg2jghxD";
const tracksList = await useTrackList();
+ const koraTracksList = await useTrackList({
+ playlistId: "1Gg5BI7b5xljyHnGXXrX0E",
+ });
+ const usaTracksList = await useTrackList({
+ playlistId: "0TyhU3nPbWY8BNObcPXt4u",
+ });
+ console.log("koraTracksList", koraTracksList);
return (
diff --git a/src/app/homepage/page.tsx b/src/app/homepage/page.tsx
index 1be9518..d23419a 100644
--- a/src/app/homepage/page.tsx
+++ b/src/app/homepage/page.tsx
@@ -15,7 +15,7 @@ export default async function HomePage() {
-
+
-
+
-
+
diff --git a/src/features/chart/components/ChartComponent.tsx b/src/features/chart/components/ChartComponent.tsx
index 0f199e5..c8cb35f 100644
--- a/src/features/chart/components/ChartComponent.tsx
+++ b/src/features/chart/components/ChartComponent.tsx
@@ -1,7 +1,48 @@
-export default function ChartComponent(tracksList: any) {
+import Image from "next/image";
+import { TrackItem } from "@/shared/types/SpotifyTrack";
+
+interface ChartComponentProps {
+ tracksList: TrackItem[];
+ title: string;
+ className?: string;
+}
+
+export default function ChartComponent({
+ tracksList,
+ title,
+ className = "",
+}: ChartComponentProps) {
return (
-
-
차트 컴포넌트
+
+
+ {title}
+
+ {tracksList.map((item, index) => (
+
+
+
+
+ {item.track.name}
+
+
+ {item.track.artists.map((artist) => artist.name).join(", ")}
+
+
+
+ ))}
);
}
diff --git a/src/features/chart/components/ChartTop.tsx b/src/features/chart/components/ChartTop.tsx
index 3c2236d..21460ef 100644
--- a/src/features/chart/components/ChartTop.tsx
+++ b/src/features/chart/components/ChartTop.tsx
@@ -1,6 +1,8 @@
import Image from "next/image";
import Miniplayer from "@/features/chart/components/Miniplayer";
+import InterviewList from "@/features/homepage/components/InterviewList";
+
import { getYoutubeTrackIdVideo } from "@/features/tracks/hooks/getYoutube";
import { TrackItem } from "@/shared/types/SpotifyTrack";
@@ -20,22 +22,26 @@ export default async function ChartTop({
return
트랙이 없습니다.
;
}
return (
-
+
- Top 1
+ Global Top 1
-
-
+ {musicVideo && musicVideo.length > 0 ? (
+
+ ) : (
+
뮤직비디오를 찾을 수 없습니다.
+ )}
+ {/*
*/}
{/*클릭시 해당 트랙 페이지로 이동*/}
-
맵을 통한 3개 인터뷰
+
diff --git a/src/features/homepage/components/InterviewList.tsx b/src/features/homepage/components/InterviewList.tsx
index b0bda3e..7a64119 100644
--- a/src/features/homepage/components/InterviewList.tsx
+++ b/src/features/homepage/components/InterviewList.tsx
@@ -1,9 +1,19 @@
-import getTrackIdInterview from "@/features/tracks/hooks/getTrackIdInterview";
import Link from "next/link";
+
+import getTrackIdInterview from "@/features/tracks/hooks/getTrackIdInterview";
+
import { formatDate } from "@/lib/utils/date";
-export default async function InterviewList() {
- const LATEST_INTERVIEWS_QUERY = `artist interview site:rollingstone.com OR site:billboard.com OR site:pitchfork.com OR site:complex.com`;
+export default async function InterviewList({
+ artistName,
+ className = "",
+ slice = 5,
+}: {
+ artistName?: string;
+ className?: string;
+ slice?: number;
+}) {
+ const LATEST_INTERVIEWS_QUERY = `${artistName} artist interview site:rollingstone.com OR site:billboard.com OR site:pitchfork.com OR site:complex.com`;
const interviews = await getTrackIdInterview(LATEST_INTERVIEWS_QUERY);
const sortedInterviews = interviews
@@ -21,12 +31,12 @@ export default async function InterviewList() {
return dateB - dateA;
});
return (
-
+
Latest Interviews
- {sortedInterviews.slice(0, 5).map((interview) => (
+ {sortedInterviews.slice(0, slice).map((interview) => (
-
{
- const API_KEY = process.env.GOOGLE_API_KEY!;
- const CSE_ID = process.env.GOOGLE_CSE_ID!;
+ try {
+ const API_KEY = process.env.GOOGLE_API_KEY!;
+ const CSE_ID = process.env.GOOGLE_CSE_ID!;
- const res = await fetch(
- `https://www.googleapis.com/customsearch/v1?key=${API_KEY}&cx=${CSE_ID}&q=${encodeURIComponent(
- who + " interview"
- )}`,
- {
- next: { revalidate: 60 * 60 * 24 },
+ const res = await fetch(
+ `https://www.googleapis.com/customsearch/v1?key=${API_KEY}&cx=${CSE_ID}&q=${encodeURIComponent(
+ who
+ )}`,
+ {
+ next: { revalidate: 60 * 60 * 24 },
+ }
+ );
+
+ if (!res.ok) {
+ throw new Error("Failed to fetch YouTube videos");
}
- );
- if (!res.ok) {
- throw new Error("Failed to fetch YouTube videos");
+ const data = await res.json();
+ return data.items || [];
+ } catch (error) {
+ console.error("getTrackIdInterview() 에러:", error);
+ return [];
}
-
- const data = await res.json();
- return data.items || [];
}
-
// 사용법: const interviews = await getTrackIdInterview(who);
diff --git a/src/features/tracks/hooks/getYoutube.ts b/src/features/tracks/hooks/getYoutube.ts
index 9d6c318..4025390 100644
--- a/src/features/tracks/hooks/getYoutube.ts
+++ b/src/features/tracks/hooks/getYoutube.ts
@@ -5,45 +5,51 @@ import { connectToDB } from "@/lib/mongo";
export async function getYoutubeTrackIdVideo(
trackName: string
): Promise {
- const db = await connectToDB();
- const collection = db.collection("musicVideos");
-
- const cached = await collection.findOne({ trackName });
-
- if (cached) {
- return cached.videos;
- }
-
- const baseUrl = process.env.BASE_URL || "http://127.0.0.1:3000";
-
- const res = await fetch(
- `${baseUrl}/api/youtube-search?q=${encodeURIComponent(trackName)}`
- );
-
- if (!res.ok) {
- throw new Error("유튜브 검색에 실패했습니다");
- }
-
- const data = await res.json();
- const videos = data.items || [];
-
- if (videos.length === 0) {
- throw new Error("비디오를 찾을 수 없습니다");
- }
-
- await collection.updateOne(
- { trackName },
- {
- $set: {
- trackName,
- videos,
- updatedAt: Date.now(),
+ try {
+ const db = await connectToDB();
+ const collection = db.collection("musicVideos");
+
+ const cached = await collection.findOne({ trackName });
+
+ if (cached) {
+ return cached.videos;
+ }
+
+ const baseUrl = process.env.BASE_URL || "http://127.0.0.1:3000";
+
+ const res = await fetch(
+ `${baseUrl}/api/youtube-search?q=${encodeURIComponent(trackName)}`
+ );
+
+ if (!res.ok) {
+ throw new Error("유튜브 검색에 실패했습니다");
+ return [];
+ }
+
+ const data = await res.json();
+ const videos = data.items || [];
+
+ if (videos.length === 0) {
+ throw new Error("비디오를 찾을 수 없습니다");
+ return [];
+ }
+
+ await collection.updateOne(
+ { trackName },
+ {
+ $set: {
+ trackName,
+ videos,
+ updatedAt: Date.now(),
+ },
},
- },
- { upsert: true }
- );
-
- return videos;
+ { upsert: true }
+ );
+ return videos;
+ } catch (error) {
+ console.error("getYoutubeTrackIdVideo() 에러:", error);
+ return [];
+ }
}
// 유튜브 채널 가져오는 함수
diff --git a/src/shared/hooks/useTrackList.ts b/src/shared/hooks/useTrackList.ts
index 89d09a4..4d93562 100644
--- a/src/shared/hooks/useTrackList.ts
+++ b/src/shared/hooks/useTrackList.ts
@@ -1,8 +1,10 @@
import getTopTrackPlaylist from "@/features/chart/hooks/getTopTrackPlaylist";
-export default async function useTrackList() {
- const playlistId = "2fmFoUa7WNxIfvUg2jghxD";
- const tracksList = await getTopTrackPlaylist(playlistId);
+export default async function useTrackList({
+ playlistId,
+}: { playlistId?: string } = {}) {
+ const finalPlaylistId = playlistId || "2fmFoUa7WNxIfvUg2jghxD";
+ const tracksList = await getTopTrackPlaylist(finalPlaylistId);
return tracksList;
}