This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
# Run tests
go test -race -v ./... # Run all tests from root
go test -race -v ./app/... # Run app tests
go test -race -v ./app/proc # Test specific package
go test -race -v ./app/proc -run TestStore # Run specific test
# Lint code
golangci-lint run ./... # Lint entire codebase from root
golangci-lint run ./app/... # Lint app directory
# Build application
cd app && go build -o feed-master # Build binary
docker build -t feed-master . # Build Docker image
# Format and normalize
gofmt -s -w $(find . -type f -name "*.go" -not -path "./vendor/*")
goimports -w $(find . -type f -name "*.go" -not -path "./vendor/*")Feed Master is a Go service that aggregates RSS feeds and YouTube content into unified feeds:
- app/main.go: Entry point with CLI flags, initializes Processor and Server
- app/proc: Core feed processing logic
Processor: Orchestrates feed fetching, filtering, and notificationsStore: BoltDB persistence layer for feed itemsTelegram/Twitter: Notification handlers
- app/feed: RSS feed parsing and generation utilities
- app/youtube: YouTube channel/playlist processing
Service: Downloads videos as audio, manages channel RSS generationfeed.Downloader: Handles yt-dlp interactionsstore.BoltDB: Persists YouTube metadata
- app/api: HTTP endpoints for RSS feeds and admin operations
- Public:
/rss/{name},/list,/yt/rss/{channel} - Admin:
/yt/rss/generate,/yt/entry/{channel}/{video}(DELETE)
- Public:
- app/config: YAML configuration loading and validation
- Feed Aggregation: Multiple source feeds → normalized → single output feed
- YouTube Integration: Uses yt-dlp for audio extraction, serves files via HTTP
- Storage: BoltDB for both feed items and YouTube metadata
- Notifications: Template-based messages to Telegram/Twitter on new items
- Concurrent Processing: Uses go-pkgz/syncs for controlled parallelism
- Error Handling: pkg/errors for wrapping, lgr for structured logging
Tests use testify with table-driven patterns:
func TestFeature(t *testing.T) {
tests := []struct {
name string
input Type
want Result
wantErr bool
}{
{"case 1", input1, expected1, false},
{"error case", badInput, nil, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// test implementation
})
}
}Config loaded from YAML (see _example/etc/):
feeds: Named feed configurations with sources, filters, notificationsyoutube: Channel definitions, download settings, file locationssystem: Update intervals, limits, base URL
- Web: chi/v5 router with go-pkgz/rest middlewares
- Storage: etcd.io/bbolt
- Testing: stretchr/testify
- YouTube: External yt-dlp binary
- Notifications: tucnak/telebot.v2, ChimeraCoder/anaconda
The processor tests in app/proc may fail if test data contains dates older than 1 year. The processor skips RSS items older than 1 year (see processor.go:83). If tests fail with "no bucket for feed1" errors:
- Check the dates in
app/proc/testdata/rss1.xmlandapp/proc/testdata/rss2.xml - Update the year in
<pubDate>tags to be within the last year - Example: Change
<pubDate>Sat, 19 Mar 2024 19:35:46 EST</pubDate>to<pubDate>Sat, 19 Mar 2025 19:35:46 EST</pubDate>
- Server: master.feed-master.com (direct SSH access)
- Location:
/srv - Deployment: Docker Compose
- Config on server:
/srv/etc/fm.yml - Config source:
/dev.umputun/system/hosts/master.feed-master.com/etc/fm.yml - Deployment Makefile:
/dev.umputun/system/hosts/master.feed-master.com/Makefile
Key Makefile targets in /dev.umputun/system/hosts/master.feed-master.com/Makefile:
make restart-feed-master- Deploy config and restart (syncs fm.yml + cookies, pulls images, restarts feed-master and nginx)make deploy- Full deployment (syncs etc/, var/, docker-compose.yml, pulls and starts)make update- Pull images and restart without syncing config
Check logs on production:
ssh master.feed-master.com "docker logs feed-master 2>&1 | tail -100"YouTube download issues (common problem):
- Issues are often related to yt-dlp: https://github.com/yt-dlp/yt-dlp
- yt-dlp template configured in
fm.ymlunderyoutube.dl_template
yt-dlp configuration flags (in dl_template):
--remote-components ejs:github- Required for JS challenge solving (uses deno runtime in container)--extractor-args "youtubepot-bgutilhttp:base_url=http://bgutil-provider:4416"- bgutil PO token provider for bot detection bypass- Format selector
bestaudio[ext=m4a]/bestaudio/bestpreferred overbestaudio*/bestto avoid HLS 403 errors --cookies /srv/etc/yt-cookies.txt- YouTube authentication cookies
Cookie file format:
- Must use Netscape cookie format with TAB separators (not spaces)
- Common cause of yt-dlp auth failures: cookies saved with spaces instead of tabs
- Cookie file location:
/srv/etc/yt-cookies.txton server, source athosts/master.feed-master.com/etc/yt-cookies.txt