PinePods Search API Documentation
🔍 Overview
The PinePods Search API is a high-performance Rust-based Actix Web application that provides comprehensive podcast and YouTube channel discovery capabilities. The API supports multiple search providers and offers detailed content information retrieval.
✨ Key Features
- Multi-Provider Search: PodcastIndex, iTunes, and YouTube Data API v3 support
- Flexible Search Types: Search by podcast title, person/host, or YouTube channels
- Real-time Statistics: Built-in usage tracking and analytics
- High Performance: Rust-based with async processing
- CORS Enabled: Ready for web application integration
- Containerized: Docker-ready deployment
🚀 Quick Start
Getting Required API Keys
Before setting up the search API container, you'll need to obtain API keys from both services:
Podcast Index API Key
- Visit https://api.podcastindex.org/signup
- Fill out the signup form with:
- Your email address
- A description of your intended use (e.g., "Self-hosted podcast management with Pinepods")
- Submit the form and wait for approval (usually within 24-48 hours)
- Once approved, you'll receive an email with your API Key and API Secret
- Keep these credentials secure
YouTube Data API v3 Key
- Go to the Google Cloud Console
- Create a new project or select an existing one:
- Click "Select a project" at the top
- Click "New Project"
- Enter a project name (e.g., "Pinepods Search API")
- Click "Create"
- Enable the YouTube Data API v3:
- In the left sidebar, go to "APIs & Services" → "Library"
- Search for "YouTube Data API v3"
- Click on it and press "Enable"
- Create API credentials:
- Go to "APIs & Services" → "Credentials"
- Click "+ CREATE CREDENTIALS" → "API key"
- Your API key will be generated
- (Optional) Click "Restrict Key" to limit usage to YouTube Data API v3 for security
- Copy the API key for use in your configuration
Environment Configuration
Create an environment file with your API credentials:
# Required for PodcastIndex searches
API_KEY=your_podcastindex_api_key
API_SECRET=your_podcastindex_api_secret
# Optional for YouTube channel searches
YOUTUBE_API_KEY=your_youtube_api_key
# Optional: Logging level
RUST_LOG=info
Docker Deployment
version: '3.8'
services:
pinepods-search-api:
image: madeofpendletonwool/pinepods_backend:latest
container_name: pinepods-search-api
env_file: .env
ports:
- "5000:5000"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/api/search"]
interval: 30s
timeout: 10s
retries: 3
PinePods Integration
Update your PinePods configuration:
# For local deployment
API_URL: 'http://localhost:5000/api/search'
# For production with domain
API_URL: 'https://your-domain.com/api/search'
📚 API Reference
Base URL
http://localhost:5000
Authentication
The API handles authentication automatically using configured environment variables. No additional authentication headers are required from clients.
🔗 Endpoints
1. Universal Search
Endpoint: GET /api/search
Description: Search for podcasts across multiple providers or YouTube channels
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | Yes* | - | Search term or query |
index | string | No | podcastindex | Search provider: podcastindex, itunes, or youtube |
search_type | string | No | term | Search type: term or person (PodcastIndex only) |
*When both query and index are omitted, returns a health check response.
Provider-Specific Features
PodcastIndex (Recommended)
- Term Search:
/search/byterm- General podcast search - Person Search:
/search/byperson- Search by host/person name - Advanced Metadata: Rich podcast information
- Privacy Focused: No user tracking
iTunes
- Term Search Only: Basic podcast discovery
- Limited Metadata: Standard iTunes podcast data
YouTube
- Channel Search: Discover YouTube channels
- Rich Media: Thumbnails, subscriber counts, recent videos
- Real-time Data: Live statistics and content
Example Requests
# Health Check
curl -X GET 'http://localhost:5000/api/search'
# Returns: "Test connection successful"
# PodcastIndex Term Search
curl -X GET 'http://localhost:5000/api/search?query=python%20podcast&index=podcastindex'
# PodcastIndex Person Search
curl -X GET 'http://localhost:5000/api/search?query=joe%20rogan&index=podcastindex&search_type=person'
# iTunes Search
curl -X GET 'http://localhost:5000/api/search?query=tech%20news&index=itunes'
# YouTube Channel Search
curl -X GET 'http://localhost:5000/api/search?query=programming&index=youtube'
2. Podcast Details
Endpoint: GET /api/podcast
Description: Retrieve detailed information for a specific podcast using its feed ID
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | PodcastIndex feed ID |
Example Request
curl -X GET 'http://localhost:5000/api/podcast?id=920666'
3. YouTube Channel Details
Endpoint: GET /api/youtube/channel
Description: Get comprehensive YouTube channel information including statistics and recent videos
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | YouTube Channel ID |
Example Request
curl -X GET 'http://localhost:5000/api/youtube/channel?id=UCXuqSBlHAE6Xw-yeJA0Tunw'
4. API Statistics
Endpoint: GET /api/stats
Description: Retrieve real-time API usage statistics and metrics
Example Request
curl -X GET 'http://localhost:5000/api/stats'
📄 Response Formats
PodcastIndex Search Response
{
"status": "true",
"feeds": [
{
"id": 920666,
"title": "Python Bytes",
"url": "https://pythonbytes.fm/episodes/rss",
"originalUrl": "https://pythonbytes.fm/episodes/rss",
"link": "https://pythonbytes.fm",
"description": "Python Bytes is a weekly podcast...",
"author": "Michael Kennedy and Brian Okken",
"ownerName": "Michael Kennedy",
"image": "https://pythonbytes.fm/static/img/podcast-logo.png",
"artwork": "https://pythonbytes.fm/static/img/podcast-logo.png",
"lastUpdateTime": 1640995200,
"lastCrawlTime": 1640995800,
"lastParseTime": 1640995850,
"lastGoodHttpStatusTime": 1640995900,
"lastHttpStatus": 200,
"contentType": "application/rss+xml",
"itunesId": 1173964558,
"generator": "custom",
"language": "en",
"type": 0,
"dead": 0,
"crawlErrors": 0,
"parseErrors": 0
}
],
"count": 25,
"query": "python podcast",
"description": "Found matching feeds."
}
iTunes Search Response
{
"resultCount": 25,
"results": [
{
"wrapperType": "track",
"kind": "podcast",
"collectionId": 1173964558,
"trackId": 1173964558,
"artistName": "Michael Kennedy and Brian Okken",
"collectionName": "Python Bytes",
"trackName": "Python Bytes",
"collectionCensoredName": "Python Bytes",
"trackCensoredName": "Python Bytes",
"collectionViewUrl": "https://podcasts.apple.com/us/podcast/python-bytes/id1173964558",
"feedUrl": "https://pythonbytes.fm/episodes/rss",
"trackViewUrl": "https://podcasts.apple.com/us/podcast/python-bytes/id1173964558",
"artworkUrl30": "https://is1-ssl.mzstatic.com/image/thumb/Podcasts123/v4/f4/89/c4/f489c4e7-35cb-474d-bf4f-0ccf67e861b0/mza_2029009828340268613.jpg/30x30bb.jpg",
"artworkUrl60": "https://is1-ssl.mzstatic.com/image/thumb/Podcasts123/v4/f4/89/c4/f489c4e7-35cb-474d-bf4f-0ccf67e861b0/mza_2029009828340268613.jpg/60x60bb.jpg",
"artworkUrl100": "https://is1-ssl.mzstatic.com/image/thumb/Podcasts123/v4/f4/89/c4/f489c4e7-35cb-474d-bf4f-0ccf67e861b0/mza_2029009828340268613.jpg/100x100bb.jpg",
"collectionPrice": 0.00,
"trackPrice": 0.00,
"releaseDate": "2024-01-15T08:00:00Z",
"collectionExplicitness": "cleaned",
"trackExplicitness": "cleaned",
"trackCount": 350,
"trackTimeMillis": 1800000,
"country": "USA",
"currency": "USD",
"primaryGenreName": "Technology",
"contentAdvisoryRating": "Clean",
"genreIds": ["1318", "26", "1528"]
}
]
}
YouTube Channel Search Response
{
"results": [
{
"channelId": "UCXuqSBlHAE6Xw-yeJA0Tunw",
"name": "Linus Tech Tips",
"description": "We make videos and stuff, cool eh?",
"thumbnailUrl": "https://yt3.ggpht.com/ytc/AKedOLQDwRAKGBtB4wWJKcAABhCRYrvhSGJr5yLO=s240-c-k-c0x00ffffff-no-rj",
"url": "https://www.youtube.com/channel/UCXuqSBlHAE6Xw-yeJA0Tunw"
}
]
}
YouTube Channel Details Response
{
"channelId": "UCXuqSBlHAE6Xw-yeJA0Tunw",
"name": "Linus Tech Tips",
"description": "We make entertaining videos about technology...",
"thumbnailUrl": "https://yt3.ggpht.com/ytc/AKedOLQDwRAKGBtB4wWJKcAABhCRYrvhSGJr5yLO=s800-c-k-c0x00ffffff-no-rj",
"url": "https://www.youtube.com/channel/UCXuqSBlHAE6Xw-yeJA0Tunw",
"subscriberCount": 15400000,
"videoCount": 6000,
"recentVideos": [
{
"id": "dQw4w9WgXcQ",
"title": "Latest Tech Review",
"description": "Today we're looking at...",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"thumbnail": "https://i.ytimg.com/vi/dQw4w9WgXcQ/mqdefault.jpg",
"publishedAt": "2024-01-15T10:00:00Z",
"duration": "PT10M30S"
}
]
}
API Statistics Response
{
"api_usage": {
"itunes_hits": 1250,
"podcast_index_hits": 3420,
"youtube_hits": 890,
"total_hits": 5560
},
"timestamp": "2024-01-15T14:30:00.000Z"
}
⚠️ Error Handling
HTTP Status Codes
| Status Code | Description | Common Causes |
|---|---|---|
200 | Success | Request completed successfully |
400 | Bad Request | Invalid parameters or malformed request |
404 | Not Found | Resource not found (podcast ID, channel ID) |
500 | Internal Server Error | API credentials missing, external API failure |
503 | Service Unavailable | External API rate limiting or downtime |
Error Response Format
{
"error": "API_KEY not set",
"status": 500,
"timestamp": "2024-01-15T14:30:00.000Z"
}
Common Error Messages
"API_KEY not set"- PodcastIndex API key missing"API_SECRET not set"- PodcastIndex API secret missing"YouTube API key not configured"- YouTube API key missing"Channel not found"- YouTube channel ID invalid"Failed to parse response body"- External API returned invalid data
🔧 Configuration Reference
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
API_KEY | Yes (for PodcastIndex) | - | PodcastIndex API Key |
API_SECRET | Yes (for PodcastIndex) | - | PodcastIndex API Secret |
YOUTUBE_API_KEY | No | - | YouTube Data API v3 Key |
RUST_LOG | No | info | Logging level (error, warn, info, debug, trace) |
Network Configuration
- Port:
5000(configurable in source) - Binding:
0.0.0.0:5000(all interfaces) - CORS: Enabled for all origins (self-hosted friendly)
- Timeout: 30 seconds for external API calls
- User-Agent:
PodPeopleDB/1.0
💡 Best Practices
Search Provider Selection
-
PodcastIndex (Recommended)
- ✅ Privacy-focused, no tracking
- ✅ Rich metadata and advanced search
- ✅ Person/host search capability
- ✅ Open-source friendly
- ✅ Fast and reliable
-
iTunes
- ✅ No API key required
- ❌ Limited search capabilities
- ❌ Basic metadata only
- ❌ Apple ecosystem focused
-
YouTube
- ✅ Video content discovery
- ✅ Real-time statistics
- ✅ Rich media thumbnails
- ❌ Requires API key with quotas
Performance Optimization
- Caching: Implement client-side caching for frequently accessed content
- Rate Limiting: Respect external API rate limits (PodcastIndex: no limit, YouTube: quota-based)
- Batch Requests: Use appropriate search result limits (max 25-50 results)
- Error Handling: Implement retry logic with exponential backoff
Security Considerations
- API Keys: Store in environment variables, never in code
- CORS: Configure appropriately for your domain in production
- HTTPS: Use HTTPS in production deployments
- Input Validation: Sanitize search queries on the client side
🔍 Troubleshooting
Common Issues
"API_KEY not set" Error
# Check environment variables are loaded
docker exec -it pinepods-search-api env | grep API
# Verify .env file format (no spaces around =)
API_KEY=your_key_here
API_SECRET=your_secret_here
No Search Results
# Test API connectivity
curl -v http://localhost:5000/api/search
# Check specific provider
curl -v "http://localhost:5000/api/search?query=test&index=podcastindex"
YouTube Search Not Working
# Verify YouTube API key
curl -v "http://localhost:5000/api/search?query=test&index=youtube"
# Check YouTube API quota in Google Cloud Console
Logging and Monitoring
# View API logs
docker logs pinepods-search-api
# Follow logs in real-time
docker logs -f pinepods-search-api
# Set debug logging
# In .env file:
RUST_LOG=debug
Health Checks
# Basic health check
curl http://localhost:5000/api/search
# Expected: "Test connection successful"
# API statistics
curl http://localhost:5000/api/stats
# Expected: JSON with usage statistics
📈 Monitoring and Analytics
The API provides built-in usage tracking accessible via the /api/stats endpoint:
- Request Counting: Tracks usage per provider
- Real-time Statistics: Live usage data
- Timestamp Tracking: When statistics were generated
- Total Aggregation: Combined usage across all providers
Integrate with your monitoring solution:
# Prometheus metrics endpoint (manual implementation)
curl http://localhost:5000/api/stats
# Example integration with monitoring script
#!/bin/bash
STATS=$(curl -s http://localhost:5000/api/stats)
echo "pinepods_api_total_requests $(echo $STATS | jq '.api_usage.total_hits')"
🚀 Production Deployment
Docker Compose (Production)
version: '3.8'
services:
pinepods-search-api:
image: madeofpendletonwool/pinepods_backend:latest
container_name: pinepods-search-api
env_file: .env.production
ports:
- "127.0.0.1:5000:5000" # Bind to localhost only
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/api/search"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
reservations:
cpus: '0.25'
memory: 128M
Reverse Proxy (Nginx)
server {
listen 80;
server_name api.yourdomain.com;
location /api/ {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# CORS headers (if needed)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
# Caching for static responses
location /api/stats {
expires 30s;
add_header Cache-Control "public, no-transform";
}
}
}
This documentation covers PinePods Search API v1.0. For the latest updates and additional information, visit the PinePods GitHub repository.