mirror of
https://github.com/svemagie/indiekit-endpoint-youtube.git
synced 2026-04-02 15:54:59 +02:00
317 lines
8.4 KiB
Markdown
317 lines
8.4 KiB
Markdown
# @rmdes/indiekit-endpoint-youtube
|
|
|
|
[](https://www.npmjs.com/package/@rmdes/indiekit-endpoint-youtube)
|
|
[](https://opensource.org/licenses/MIT)
|
|
|
|
YouTube channel endpoint for [Indiekit](https://getindiekit.com/).
|
|
|
|
Display latest videos and live streaming status from any YouTube channel (or multiple channels) on your IndieWeb site.
|
|
|
|
## Installation
|
|
|
|
Install from npm:
|
|
|
|
```bash
|
|
npm install @rmdes/indiekit-endpoint-youtube
|
|
```
|
|
|
|
## Features
|
|
|
|
- **Single or Multi-Channel** - Monitor one channel or aggregate multiple channels
|
|
- **Admin Dashboard** - Overview of channel(s) with latest videos in Indiekit's admin UI
|
|
- **Live Status** - Shows when channel is live streaming (with animated badge)
|
|
- **Upcoming Streams** - Display scheduled upcoming live streams
|
|
- **Latest Videos** - Grid of recent uploads with thumbnails, duration, view counts
|
|
- **Public JSON API** - For integration with static site generators like Eleventy
|
|
- **Quota Efficient** - Uses YouTube API efficiently (playlist method vs search)
|
|
- **Smart Caching** - Respects API rate limits while staying current
|
|
|
|
## Configuration
|
|
|
|
### Single Channel
|
|
|
|
Add to your `indiekit.config.js`:
|
|
|
|
```javascript
|
|
import YouTubeEndpoint from "@rmdes/indiekit-endpoint-youtube";
|
|
|
|
export default {
|
|
plugins: [
|
|
new YouTubeEndpoint({
|
|
mountPath: "/youtube",
|
|
apiKey: process.env.YOUTUBE_API_KEY,
|
|
channelId: process.env.YOUTUBE_CHANNEL_ID,
|
|
// OR use channel handle instead:
|
|
// channelHandle: "@YourChannel",
|
|
cacheTtl: 300_000, // 5 minutes
|
|
liveCacheTtl: 60_000, // 1 minute for live status
|
|
limits: {
|
|
videos: 10,
|
|
},
|
|
}),
|
|
],
|
|
};
|
|
```
|
|
|
|
### Multiple Channels
|
|
|
|
Monitor multiple YouTube channels simultaneously:
|
|
|
|
```javascript
|
|
import YouTubeEndpoint from "@rmdes/indiekit-endpoint-youtube";
|
|
|
|
export default {
|
|
plugins: [
|
|
new YouTubeEndpoint({
|
|
mountPath: "/youtube",
|
|
apiKey: process.env.YOUTUBE_API_KEY,
|
|
channels: [
|
|
{ id: "UC...", name: "Main Channel" },
|
|
{ handle: "@SecondChannel", name: "Second Channel" },
|
|
{ id: "UC...", name: "Third Channel" },
|
|
],
|
|
cacheTtl: 300_000,
|
|
liveCacheTtl: 60_000,
|
|
limits: {
|
|
videos: 10,
|
|
},
|
|
}),
|
|
],
|
|
};
|
|
```
|
|
|
|
In multi-channel mode:
|
|
- Dashboard shows all channels with separate sections
|
|
- API endpoints aggregate data from all channels
|
|
- Videos are sorted by date across all channels
|
|
- Live status shows any channel that is currently live
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Required | Description |
|
|
|----------|----------|-------------|
|
|
| `YOUTUBE_API_KEY` | Yes | YouTube Data API v3 key |
|
|
| `YOUTUBE_CHANNEL_ID` | Yes* | Channel ID (starts with `UC...`) |
|
|
| `YOUTUBE_CHANNEL_HANDLE` | Yes* | Channel handle (e.g., `@YourChannel`) |
|
|
|
|
*Either `channelId` or `channelHandle` is required for single-channel mode. In multi-channel mode, use the `channels` array instead.
|
|
|
|
### Getting a YouTube API Key
|
|
|
|
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
|
2. Create a new project or select an existing one
|
|
3. Enable the "YouTube Data API v3"
|
|
4. Go to Credentials > Create Credentials > API Key
|
|
5. (Optional) Restrict the key to YouTube Data API only
|
|
|
|
### Finding Your Channel ID
|
|
|
|
- Go to your YouTube channel
|
|
- The URL will be `youtube.com/channel/UC...` - the `UC...` part is your channel ID
|
|
- Or use a tool like [Comment Picker](https://commentpicker.com/youtube-channel-id.php)
|
|
|
|
## Routes
|
|
|
|
### Admin Routes (require authentication)
|
|
|
|
| Route | Description |
|
|
|-------|-------------|
|
|
| `GET /youtube/` | Dashboard with channel info, live status, latest videos |
|
|
| `POST /youtube/refresh` | Clear cache and refresh data (returns JSON) |
|
|
|
|
### Public API Routes (JSON)
|
|
|
|
| Route | Description |
|
|
|-------|-------------|
|
|
| `GET /youtube/api/videos` | Latest videos (supports `?limit=N`) |
|
|
| `GET /youtube/api/channel` | Channel information |
|
|
| `GET /youtube/api/live` | Live streaming status (efficient by default) |
|
|
| `GET /youtube/api/live?full=true` | Live status using search API (more accurate, costs more quota) |
|
|
|
|
### Example: Eleventy Integration
|
|
|
|
```javascript
|
|
// _data/youtube.js
|
|
import EleventyFetch from "@11ty/eleventy-fetch";
|
|
|
|
export default async function() {
|
|
const baseUrl = process.env.SITE_URL || "https://example.com";
|
|
|
|
const [channel, videos, live] = await Promise.all([
|
|
EleventyFetch(`${baseUrl}/youtube/api/channel`, { duration: "15m", type: "json" }),
|
|
EleventyFetch(`${baseUrl}/youtube/api/videos?limit=6`, { duration: "5m", type: "json" }),
|
|
EleventyFetch(`${baseUrl}/youtube/api/live`, { duration: "1m", type: "json" }),
|
|
]);
|
|
|
|
return {
|
|
channel: channel.channel,
|
|
videos: videos.videos,
|
|
isLive: live.isLive,
|
|
liveStream: live.stream,
|
|
};
|
|
}
|
|
```
|
|
|
|
## API Response Examples
|
|
|
|
### GET /youtube/api/live
|
|
|
|
**Single channel:**
|
|
```json
|
|
{
|
|
"isLive": true,
|
|
"isUpcoming": false,
|
|
"stream": {
|
|
"videoId": "abc123",
|
|
"title": "Live Stream Title",
|
|
"thumbnail": "https://i.ytimg.com/vi/abc123/mqdefault.jpg",
|
|
"url": "https://www.youtube.com/watch?v=abc123"
|
|
},
|
|
"cached": true
|
|
}
|
|
```
|
|
|
|
**Multi-channel:**
|
|
```json
|
|
{
|
|
"isLive": true,
|
|
"isUpcoming": false,
|
|
"stream": {
|
|
"videoId": "abc123",
|
|
"title": "Live Stream Title"
|
|
},
|
|
"liveStatuses": [
|
|
{
|
|
"channelConfigName": "Main Channel",
|
|
"isLive": true,
|
|
"stream": { "videoId": "abc123" }
|
|
},
|
|
{
|
|
"channelConfigName": "Second Channel",
|
|
"isLive": false,
|
|
"stream": null
|
|
}
|
|
],
|
|
"cached": true
|
|
}
|
|
```
|
|
|
|
### GET /youtube/api/videos
|
|
|
|
**Single channel:**
|
|
```json
|
|
{
|
|
"videos": [
|
|
{
|
|
"id": "abc123",
|
|
"title": "Video Title",
|
|
"thumbnail": "https://i.ytimg.com/vi/abc123/mqdefault.jpg",
|
|
"duration": 3661,
|
|
"durationFormatted": "1:01:01",
|
|
"viewCount": 12345,
|
|
"publishedAt": "2024-01-15T10:00:00Z",
|
|
"url": "https://www.youtube.com/watch?v=abc123",
|
|
"isLive": false
|
|
}
|
|
],
|
|
"count": 10,
|
|
"cached": true
|
|
}
|
|
```
|
|
|
|
**Multi-channel:**
|
|
```json
|
|
{
|
|
"videos": [],
|
|
"videosByChannel": {
|
|
"Main Channel": [],
|
|
"Second Channel": []
|
|
},
|
|
"count": 20,
|
|
"cached": true
|
|
}
|
|
```
|
|
|
|
### GET /youtube/api/channel
|
|
|
|
**Single channel:**
|
|
```json
|
|
{
|
|
"channel": {
|
|
"id": "UC...",
|
|
"title": "Channel Name",
|
|
"description": "Channel description",
|
|
"thumbnail": "https://...",
|
|
"subscriberCount": 12345,
|
|
"videoCount": 100,
|
|
"viewCount": 999999
|
|
},
|
|
"cached": true
|
|
}
|
|
```
|
|
|
|
**Multi-channel:**
|
|
```json
|
|
{
|
|
"channels": [
|
|
{ "id": "UC...", "title": "Channel 1", "configName": "Main Channel" },
|
|
{ "id": "UC...", "title": "Channel 2", "configName": "Second Channel" }
|
|
],
|
|
"channel": {},
|
|
"cached": true
|
|
}
|
|
```
|
|
|
|
## Options
|
|
|
|
| Option | Default | Description |
|
|
|--------|---------|-------------|
|
|
| `mountPath` | `/youtube` | URL path for the endpoint |
|
|
| `apiKey` | - | YouTube Data API key |
|
|
| `channelId` | - | Channel ID (UC...) - single channel mode |
|
|
| `channelHandle` | - | Channel handle (@...) - single channel mode |
|
|
| `channels` | `null` | Array of channels for multi-channel mode |
|
|
| `cacheTtl` | `300000` | Cache TTL in ms (5 min) |
|
|
| `liveCacheTtl` | `60000` | Live status cache TTL in ms (1 min) |
|
|
| `limits.videos` | `10` | Number of videos to fetch per channel |
|
|
|
|
### Channels Array Format
|
|
|
|
For multi-channel mode, the `channels` option accepts an array of objects:
|
|
|
|
```javascript
|
|
channels: [
|
|
{ id: "UC...", name: "Display Name" }, // Using channel ID
|
|
{ handle: "@username", name: "Display Name" }, // Using handle
|
|
{ id: "UC..." } // Name defaults to channel title
|
|
]
|
|
```
|
|
|
|
Either `id` or `handle` is required. The `name` field is optional and used for display purposes.
|
|
|
|
## Quota Efficiency
|
|
|
|
YouTube Data API has a daily quota (10,000 units by default). This plugin is optimized:
|
|
|
|
| Operation | Quota Cost | Method |
|
|
|-----------|------------|--------|
|
|
| Get videos | 2 units | Uses uploads playlist (not search) |
|
|
| Get channel | 1 unit | Cached for 24 hours |
|
|
| Check live status (efficient) | 2 units | Checks recent videos |
|
|
| Check live status (full) | 100 units | Only when explicitly requested |
|
|
|
|
**Single channel:** With default settings (5-min cache), ~600 units/day.
|
|
|
|
**Multi-channel:** Quota usage scales linearly. 3 channels = ~1,800 units/day.
|
|
|
|
## Requirements
|
|
|
|
- Indiekit >= 1.0.0-beta.25
|
|
- YouTube Data API v3 enabled
|
|
- Valid API key with YouTube Data API access
|
|
- Node.js >= 20
|
|
|
|
## License
|
|
|
|
MIT
|