Skip to content

Commit 6371498

Browse files
committed
add a youtube rss
1 parent 36490ad commit 6371498

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

Diff for: app/api/youtube/rss.json/route.tsx

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { NextResponse } from 'next/server';
2+
import { Feed } from 'feed';
3+
4+
const YOUTUBE_API_KEY = process.env.YOUTUBE_API_KEY as string;
5+
const CHANNEL_ID = process.env.YOUTUBE_CHANNEL_ID as string;
6+
7+
interface PlaylistItem {
8+
id: string;
9+
snippet: {
10+
title: string;
11+
description: string;
12+
};
13+
}
14+
15+
interface PlaylistItemsResponse {
16+
items: {
17+
snippet: {
18+
title: string;
19+
description: string;
20+
resourceId: {
21+
videoId: string;
22+
};
23+
publishedAt: string;
24+
};
25+
}[];
26+
nextPageToken?: string;
27+
}
28+
29+
async function fetchPodcastPlaylists(channelId: string): Promise<PlaylistItem[]> {
30+
const url = `https://www.googleapis.com/youtube/v3/playlists?key=${YOUTUBE_API_KEY}&channelId=${channelId}&part=snippet&maxResults=50`;
31+
const response = await fetch(url);
32+
const data = await response.json();
33+
return data.items.filter((playlist: PlaylistItem) =>
34+
playlist.snippet.title.toLowerCase().includes('podcast') ||
35+
playlist.snippet.description.toLowerCase().includes('podcast')
36+
);
37+
}
38+
39+
async function fetchPlaylistItems(playlistId: string, pageToken: string = ''): Promise<PlaylistItemsResponse> {
40+
const url = `https://www.googleapis.com/youtube/v3/playlistItems?key=${YOUTUBE_API_KEY}&playlistId=${playlistId}&part=snippet&maxResults=50${pageToken ? `&pageToken=${pageToken}` : ''}`;
41+
const response = await fetch(url);
42+
return response.json();
43+
}
44+
45+
export async function GET() {
46+
try {
47+
const feed = new Feed({
48+
title: 'YouTube Channel Podcast Feed',
49+
description: 'Latest podcast episodes from the YouTube channel',
50+
id: `https://www.youtube.com/channel/${CHANNEL_ID}`,
51+
link: `https://www.youtube.com/channel/${CHANNEL_ID}`,
52+
language: 'en',
53+
image: 'https://www.youtube.com/img/desktop/yt_1200.png',
54+
favicon: 'https://www.youtube.com/favicon.ico',
55+
copyright: `All rights reserved ${new Date().getFullYear()}, YouTube`,
56+
updated: new Date(),
57+
generator: 'Next.js using Feed for Node.js',
58+
feedLinks: {
59+
json: `${process.env.NEXT_PUBLIC_BASE_URL}/api/podcast-feed`,
60+
atom: `${process.env.NEXT_PUBLIC_BASE_URL}/api/podcast-feed?format=atom`,
61+
},
62+
});
63+
64+
const podcastPlaylists = await fetchPodcastPlaylists(CHANNEL_ID);
65+
66+
for (const playlist of podcastPlaylists) {
67+
let pageToken: string | undefined = '';
68+
do {
69+
const data = await fetchPlaylistItems(playlist.id, pageToken);
70+
71+
data.items.forEach(item => {
72+
feed.addItem({
73+
title: item.snippet.title,
74+
id: item.snippet.resourceId.videoId,
75+
link: `https://www.youtube.com/watch?v=${item.snippet.resourceId.videoId}`,
76+
description: item.snippet.description,
77+
date: new Date(item.snippet.publishedAt),
78+
image: `https://img.youtube.com/vi/${item.snippet.resourceId.videoId}/maxresdefault.jpg`,
79+
});
80+
});
81+
82+
pageToken = data.nextPageToken;
83+
} while (pageToken);
84+
}
85+
86+
return NextResponse.json(JSON.parse(feed.json1()));
87+
} catch (error) {
88+
console.error('Error generating podcast feed:', error);
89+
return NextResponse.json({ error: 'Error generating podcast feed' }, { status: 500 });
90+
}
91+
}

0 commit comments

Comments
 (0)