A service that provides RSS feeds for Hardcover.app "want to read" lists, similar to Goodreads RSS feeds.
- 📚 Fetch "want to read" lists from Hardcover.app using the official GraphQL API
- 📡 Generate RSS feeds in Goodreads format
- 🔄 Automatic background refresh (configurable interval)
- 💾 Redis caching for improved performance
- 🚀 RESTful API for managing users
- 🐳 Docker containerization
- 📊 Health monitoring endpoints
- Clone the repository:
git clone <repository-url>
cd hardcover_rss- Set up your environment variables:
# Copy the example environment file
cp env.example .env
# Edit .env and add your Hardcover API token
# Get your token from https://hardcover.app/settings/api- Start the service with pre-built images:
./deploy.sh- Clone the repository:
git clone <repository-url>
cd hardcover_rss- Set up your environment variables:
# Copy the example environment file
cp env.example .env
# Edit .env and add your Hardcover API token
# Get your token from https://hardcover.app/settings/api- Build and start the service:
docker-compose up -d- Add a user to track:
curl -X POST "http://localhost:8000/users" \
-H "Content-Type: application/json" \
-d '{"username": "your_hardcover_username"}'- Access the RSS feed:
http://localhost:8000/feed/your_hardcover_username
- Build the image:
docker build -t hardcover-rss .- Run with Redis:
# Start Redis
docker run -d --name redis redis:7-alpine
# Start the service (replace 'your_token_here' with your actual token)
docker run -d --name hardcover-rss \
-p 8000:8000 \
-e HARDCOVER_API_TOKEN="your_token_here" \
-e REDIS_URL="redis://host.docker.internal:6379" \
hardcover-rssNote: For production use, consider using environment files or Docker secrets instead of passing tokens directly in the command line.
POST /users- Add a new user to trackGET /users- List all registered usersDELETE /users/{username}- Remove a user from tracking
GET /feed/{username}- Get RSS feed for a specific userGET /feeds- List all available feeds
GET /health- Health check and statusPOST /refresh/{username}- Manually refresh a user's feedPOST /refresh- Manually refresh all feeds
| Variable | Description | Default |
|---|---|---|
HARDCOVER_API_TOKEN |
Your Hardcover API token | Required |
HARDCOVER_API_URL |
Hardcover GraphQL API URL | https://api.hardcover.app/v1/graphql |
REFRESH_INTERVAL |
Background refresh interval (seconds) | 3600 |
CACHE_TTL |
Cache TTL (seconds) | 1800 |
LOG_LEVEL |
Logging level | INFO |
REDIS_URL |
Redis connection URL | redis://localhost:6379 |
Copy env.example to .env and update with your values:
cp env.example .envExample .env file:
HARDCOVER_API_TOKEN=your_token_here
REFRESH_INTERVAL=3600
CACHE_TTL=1800
LOG_LEVEL=INFO
REDIS_URL=redis://redis:6379Security Note: Never commit your .env file to version control. The .env file is already included in .gitignore.
curl -X POST "http://localhost:8000/users" \
-H "Content-Type: application/json" \
-d '{
"username": "john_doe",
"display_name": "John Doe"
}'curl "http://localhost:8000/feed/john_doe"curl "http://localhost:8000/health"The service generates RSS feeds in a format similar to Goodreads, including:
- Book title and author
- Book description
- Publication year and page count
- Average rating
- Date added to want-to-read list
- Direct links to Hardcover book pages
- Install dependencies:
pip install -r requirements.txt- Set environment variables:
export HARDCOVER_API_TOKEN="your_token_here"
export REDIS_URL="redis://localhost:6379"- Start Redis:
docker run -d --name redis redis:7-alpine- Run the service:
python -m uvicorn app.main:app --reloadThe service includes health checks and error handling. You can test the API using the interactive documentation at http://localhost:8000/docs.
Pre-built Docker images are available on GitHub Container Registry:
# Pull the latest image (recommended)
docker pull ghcr.io/bfarkas/hardcover-rss:latest
# Or use a specific version
docker pull ghcr.io/bfarkas/hardcover-rss:v1.0.0
# Or use the main branch
docker pull ghcr.io/bfarkas/hardcover-rss:mainlatest- Latest stable release (same as main branch)main- Latest commit on main branchv*- Versioned releases (e.g.,v1.0.0,v1.1.0)main-<sha>- Specific commit builds
# Start Redis
docker run -d --name redis redis:7-alpine
# Start the service
docker run -d --name hardcover-rss \
-p 8000:8000 \
-e HARDCOVER_API_TOKEN="your_token_here" \
-e REDIS_URL="redis://host.docker.internal:6379" \
ghcr.io/bfarkas/hardcover-rss:latest- FastAPI: Web framework for the REST API
- GraphQL: Communication with Hardcover API
- Redis: Caching layer for user data
- APScheduler: Background job scheduling
- Feedgen: RSS feed generation
- Docker: Containerization
The service provides several monitoring endpoints:
/health- Overall service health- Cache statistics
- Scheduler job status
- Registered user count
- User not found: Ensure the username exists on Hardcover.app
- API token issues: Verify your Hardcover API token is valid
- Redis connection: Check Redis is running and accessible
- Rate limiting: The service includes delays between API calls
If you encounter Redis connection problems:
# Test Redis connectivity
./test-redis.sh
# For Docker deployments, ensure Redis is running:
docker-compose up -d redis
# For local development, start Redis:
docker run -d --name redis redis:7-alpine
# Check if Redis is accessible:
redis-cli pingCommon Redis URL patterns:
- Docker Compose:
redis://redis:6379 - Local development:
redis://localhost:6379 - Docker with host Redis:
redis://host.docker.internal:6379 - Remote Redis:
redis://your-redis-server:6379
Check the service logs:
docker-compose logs hardcover-rssThis project is licensed under the MIT License.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
To ensure your target application recognizes this service as a Goodreads RSS feed, the service must be accessible at a hostname containing goodreads (e.g., goodreads).
Important:
- The
extra_hostsentry should be added to the target application's service in yourdocker-compose.yml, not to thehardcover-rssservice itself. - This will map the hostname
goodreadsto the IP address of thehardcover-rsscontainer, allowing the target application to resolve and connect to it as if it were Goodreads.
Suppose your target application is called myapp and your RSS service is hardcover-rss:
services:
hardcover-rss:
# ... existing config ...
myapp:
# ... existing config ...
extra_hosts:
- "goodreads:hardcover-rss"Or, if you want to map to a specific IP (e.g., when running outside Docker Compose networking):
extra_hosts:
- "goodreads:127.0.0.1"This ensures that when your target application tries to access http://goodreads:8000/list_rss/USERNAME, it will be routed to your Hardcover RSS service.