Commit Graph

16 Commits

Author SHA1 Message Date
primal
1066f42189 Refactor large Go files into focused modules
Split dashboard.go (3,528 lines) into:
- routes.go: HTTP route registration
- api_domains.go: Domain API handlers
- api_feeds.go: Feed API handlers
- api_publish.go: Publishing API handlers
- api_search.go: Search API handlers
- templates.go: HTML templates
- dashboard.go: Stats functions only (235 lines)

Split publisher.go (1,502 lines) into:
- pds_auth.go: Authentication and account management
- pds_records.go: Record operations (upload, update, delete)
- handle.go: Handle derivation from feed URLs
- image.go: Image processing and favicon fetching
- publisher.go: Core types and PublishItem (439 lines)

Split feed.go (1,137 lines) into:
- item.go: Item struct and DB operations
- feed_check.go: Feed checking and processing
- feed.go: Feed struct and DB operations (565 lines)

Also includes domain import batch size increase (1k -> 100k).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 22:25:02 -05:00
primal
3999e96f26 Dashboard UI overhaul: inline feed details, TLD filtering, status improvements
- Feed details now expand inline instead of navigating to new page
- Add TLD section headers with domains sorted by TLD then name
- Add TLD filter button to show/hide domain sections by TLD
- Feed status behavior: pass creates account, hold crawls only, skip stops, drop cleans up
- Auto-follow new accounts from directory account (1440.news)
- Fix handle derivation (removed duplicate .1440.news suffix)
- Increase domain import batch size to 100k
- Various bug fixes for account creation and profile updates

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 20:51:05 -05:00
primal
5908a8c03e Full cleanup when revoking feed publish status
When setting publish_status to deny, now performs complete cleanup:
- Deletes all posts from the feed account on PDS
- Deletes the PDS account itself
- Clears published_at timestamps on all items
- Clears the publish_account field on the feed

Added Publisher methods:
- DeleteAllPosts: lists and deletes all posts from an account
- DeleteRecord: deletes a single AT Protocol record
- DeleteAccount: deletes account via PDS admin API

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 13:37:02 -05:00
primal
254b751799 Add rich text links, language filter, and domain deny feature
- Use labeled links (Article · Audio) instead of raw URLs in posts
- Add language filter dropdown to dashboard with toggle selection
- Auto-deny feeds with no language on discovery
- Add deny/undeny buttons for domains to block crawling
- Denied domains set feeds to dead status, preventing future checks

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 12:36:58 -05:00
primal
f4f80e91cc Add enclosure support for podcast/media items
- Load enclosure fields in GetAllUnpublishedItems query
- Only include enclosure URL if it fits within post length limit
- Shorter video/audio enclosures will be included when they fit

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 22:36:28 -05:00
primal
1609220a27 Limit handle subdomain to 18 chars (PDS restriction)
The PDS restricts the first segment of local handles to 18 characters,
not the AT Protocol spec of 63. Added abbreviation map for long
category names:
- science-and-environment -> sci-env
- entertainment-and-arts -> ent-arts
- technology -> tech (when needed)
- etc.

Fixes "Handle too long" errors for BBC category feeds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 22:22:59 -05:00
primal
1f092c87e9 Add automatic image resize for blobs exceeding size limit
Bluesky has a ~976KB blob limit. Images larger than 900KB are now
automatically resized using CatmullRom scaling and re-encoded as
JPEG with 85% quality. Iteratively scales down (90%, 72%, 58%...)
until under limit, with minimum dimensions of 100x100.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 22:10:10 -05:00
primal
c54005b5ba Upgrade BBC images from 240px to 800px for better quality
BBC CDN supports larger image sizes by changing the URL path.
Upgrade /standard/240/ and /standard/480/ to /standard/800/.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 21:49:11 -05:00
primal
5975df6771 Use PubDate for TID/rkey generation for consistent ordering
Both createdAt and rkey now use the original publication date,
so posts sort consistently by their original publication time.
Falls back to DiscoveredAt if PubDate is not available.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 21:32:07 -05:00
primal
bce6c93242 Use original publication date for post createdAt
Posts now use the item pub_date for the createdAt field instead
of the current time, so posts show their original publication time.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 21:29:44 -05:00
primal
a1f02cd0bc Fix image embeds and rkey collisions
- Add image_urls to GetAllUnpublishedItems query
- Add aspectRatio to image embeds (required by Bluesky)
- Add image decoding to get dimensions (width/height)
- Fix rkey collision by using XOR of multiple hash bytes

The rkey collision was caused by using only 2 hash bytes (10 bits)
which had ~0.1% collision rate per pair of items with same timestamp.
Now XORs 8 hash bytes for better entropy distribution.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 21:24:35 -05:00
primal
4e4e8c939a Add favicon as profile picture for feed accounts
Fetches the site's favicon and uses it as the avatar when creating
or updating feed account profiles. Tries common favicon locations
(/favicon.ico, /favicon.png, /apple-touch-icon.png) then falls back
to Google's favicon service.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 21:05:50 -05:00
primal
39714858e5 Fix subdomain length limit to match AT Protocol spec
AT Protocol allows 63 characters per label, not 18. The previous
limit was incorrectly truncating category names like
"science-and-environment" and "entertainment-and-arts".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 20:53:42 -05:00
primal
27c3fa1a3c Fix handle derivation for two-part TLDs and categories
Rewrite DeriveHandleFromFeed to properly handle domains like BBC:
- Handle two-part TLDs (co.uk, com.au, etc.)
- Skip noise subdomains (feeds, www, news, rss)
- Map bbci -> bbc for cleaner handles
- Include category from path (technology, sport, world, etc.)

Before: feeds.bbci.co.uk/news/technology/rss.xml -> news-co.1440.news
After:  feeds.bbci.co.uk/news/technology/rss.xml -> bbc-technology.1440.news

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 20:48:26 -05:00
primal
f4afb29980 Migrate from SQLite to PostgreSQL
- Replace modernc.org/sqlite with jackc/pgx/v5
- Update all SQL queries for PostgreSQL syntax ($1, $2 placeholders)
- Use snake_case column names throughout
- Replace SQLite FTS5 with PostgreSQL tsvector/tsquery full-text search
- Add connection pooling with pgxpool
- Support Docker secrets for database password
- Add trigger to normalize feed URLs (strip https://, http://, www.)
- Fix anchor feed detection regex to avoid false positives
- Connect app container to atproto network for PostgreSQL access
- Add version indicator to dashboard UI

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 20:38:13 -05:00
primal
75835d771d Add AT Protocol publishing, media support, and SQLite stability
Publishing:
- Add publisher.go for posting feed items to AT Protocol PDS
- Support deterministic rkeys from SHA256(guid + discoveredAt)
- Handle multiple URLs in posts with facets for each link
- Image embed support (app.bsky.embed.images) for up to 4 images
- External embed with thumbnail fallback
- Podcast/audio enclosure URLs included in post text

Media extraction:
- Parse RSS enclosures (audio, video, images)
- Extract Media RSS content and thumbnails
- Extract images from HTML content in descriptions
- Store enclosure and imageUrls in items table

SQLite stability improvements:
- Add synchronous=NORMAL and wal_autocheckpoint pragmas
- Connection pool tuning (idle conns, max lifetime)
- Periodic WAL checkpoint every 5 minutes
- Hourly integrity checks with PRAGMA quick_check
- Daily hot backup via VACUUM INTO
- Docker stop_grace_period: 30s for graceful shutdown

Dashboard:
- Feed publishing UI and API endpoints
- Account creation with invite codes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 15:30:02 -05:00