diff --git a/README.md b/README.md index e11a4006..00e7d618 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,77 @@ -# FFR (Feed to Fediverse Router) +# FFR: Feed to Fediverse Router -A Laravel-based application for routing RSS/Atom feeds to Fediverse platforms like Lemmy. Built with Laravel, Livewire, and FrankenPHP for a modern, single-container deployment. +[![CI](https://forge.lvl0.xyz/lvl0/fedi-feed-router/badges/workflows/ci.yml/badge.svg)](https://forge.lvl0.xyz/lvl0/fedi-feed-router/actions) +[![Release](https://img.shields.io/gitea/v/release/lvl0/fedi-feed-router?gitea_url=https%3A%2F%2Fforge.lvl0.xyz)](https://forge.lvl0.xyz/lvl0/fedi-feed-router/releases) +[![License](https://img.shields.io/badge/license-AGPL--3.0-blue)](LICENSE) + +Routes news articles to Fediverse communities. FFR polls a set of sources, +extracts each article, and posts it to the Lemmy communities you map it to, +either automatically or after you approve it. + +It is meant to run unattended on your own server: point it at a source, map that +source to a community, and let it publish on a schedule you control. + +## Screenshots + +![Dashboard](docs/screenshots/dashboard-dark.png) + +The dashboard, showing article volume over a selected range, approval and publish +success rates, and per-feed breakdowns. + +![Articles](docs/screenshots/articles-light.png) + +The review queue. Each row is one feed and community pairing, grouped by feed, +with the routing shown above the headline. ## Features -- **Feed aggregation** - Fetch articles from multiple RSS/Atom feeds -- **Fediverse publishing** - Automatically post to Lemmy communities -- **Route configuration** - Map feeds to specific channels with keywords -- **Approval workflow** - Optional manual approval before publishing -- **Queue processing** - Background job handling with Laravel Horizon -- **Single container deployment** - Simplified hosting with FrankenPHP +- **Article routing**: map each source to one or more Lemmy communities, with + optional keyword filtering +- **Approval workflow**: review articles before they publish, or let them go out + automatically +- **Publishing controls**: a global interval and an optional daily cap, so a + source returning a large batch cannot flood a community +- **Dashboard**: articles fetched and published over time, approval and publish + success rates, and per-source and per-community breakdowns +- **Activity log**: a chronological record of what the automation has done +- **Health checks**: warnings for sources that stop producing articles and for + platform credentials that stop working +- **Dark theme** +- **Single container**: FrankenPHP serves the app, with MariaDB and Redis + alongside + +## Sources and platforms + +FFR ships with parsers for three sources: + +| Source | Type | +|--------|------| +| VRT News | Website | +| Belga | Website | +| The Guardian | RSS | + +Some sources publish a usable feed and some do not, so a source is either read +from RSS or scraped from its pages. Either way a parser handles it, registered +in `config/feed.php`. + +Adding a source means implementing `ArticleParserInterface` (three methods: +`canParse`, `extractData`, `getSourceName`) and registering it. See +[CONTRIBUTING.md](CONTRIBUTING.md). + +Lemmy is currently the only supported platform. ## Self-hosting -The production image is available at `forge.lvl0.xyz/lvl0/fedi-feed-router:latest`. +Images are published to `forge.lvl0.xyz/lvl0/fedi-feed-router`. The example below +pins a release tag; check [Releases](https://forge.lvl0.xyz/lvl0/fedi-feed-router/releases) +for the current one, and the [CHANGELOG](CHANGELOG.md) before upgrading. ### docker-compose.yml ```yaml services: app: - image: forge.lvl0.xyz/lvl0/fedi-feed-router:latest + image: forge.lvl0.xyz/lvl0/fedi-feed-router:v1.4.0 container_name: ffr_app restart: always ports: @@ -70,42 +121,59 @@ ### docker-compose.yml app_storage: ``` -### Environment Variables +### Environment variables | Variable | Required | Description | |----------|----------|-------------| | `APP_KEY` | Yes | Encryption key. Generate with: `echo "base64:$(openssl rand -base64 32)"` | -| `APP_URL` | Yes | Your domain (e.g., `https://ffr.example.com`) | +| `APP_URL` | Yes | Your domain (e.g. `https://ffr.example.com`) | | `DB_DATABASE` | Yes | Database name | | `DB_USERNAME` | Yes | Database user | | `DB_PASSWORD` | Yes | Database password | | `DB_ROOT_PASSWORD` | Yes | MariaDB root password | +## Usage + +On first run FFR walks you through onboarding. After that: + +1. **Add a channel** on the Channels page. A channel is a Lemmy community on a + given instance, together with the account that posts to it. The community is + picked from the instance, so a typo cannot create a channel that fails later. +2. **Add a feed** on the Feeds page, choosing one of the supported sources. +3. **Add a route** on the Routes page, mapping a feed to a channel. Keywords on a + route restrict it to articles that match. + +Articles are then discovered on a schedule. Each one becomes a row per matching +route, so an article routed to three communities is three separate decisions. +Approve one on the Articles page and it publishes to that route's community; +publishing failures come back to you on the Failed tab rather than retrying +silently. + +Publishing runs every five minutes, one article per run, bounded by the daily cap +if you set one. + ## Development ### NixOS / Nix ```bash git clone https://forge.lvl0.xyz/lvl0/fedi-feed-router.git -cd ffr +cd fedi-feed-router nix-shell ``` -The shell will display available commands and optionally start the containers for you. - -#### Available Commands +The shell prints the available commands and can start the containers for you. | Command | Description | |---------|-------------| -| `dev-up` | Start development environment | -| `dev-down` | Stop development environment | -| `dev-restart` | Restart containers | -| `dev-logs` | Follow app logs | -| `dev-logs-db` | Follow database logs | -| `dev-shell` | Enter app container | -| `dev-artisan ` | Run artisan commands | - -#### Services +| `dev-up` | Start the development environment | +| `dev-down` | Stop the development environment | +| `dev-restart` | Restart the containers | +| `dev-rebuild` | Rebuild the images | +| `dev-shell` | Enter the app container | +| `dev-artisan ` | Run an artisan command | +| `dev-logs` | Follow the application log | +| `dev-logs-db` | Follow the database log | | Service | URL | |---------|-----| @@ -114,14 +182,22 @@ #### Services | MariaDB | localhost:3307 | | Redis | localhost:6380 | -### Other Platforms +### Other platforms Contributions welcome for development setup instructions on other platforms. +## Contributing + +Issues and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for +the development setup, the checks that run in CI, and the commit conventions. + +For bugs and questions, use +[Issues](https://forge.lvl0.xyz/lvl0/fedi-feed-router/issues). + +## Note on AI assistance + +This project was developed with AI assistance. + ## License -This project is open-source software licensed under the [AGPL-3.0 license](LICENSE). - -## Support - -For issues and questions, please use [Issues](https://forge.lvl0.xyz/lvl0/fedi-feed-router/issues). +FFR is free software, licensed under the [GNU AGPL-3.0](LICENSE). diff --git a/composer.json b/composer.json index a8aa0cae..0254fbae 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "$schema": "https://getcomposer.org/schema.json", "name": "lvl0/fedi-feed-router", "type": "project", - "description": "Routes RSS and Atom feeds to Fediverse platforms such as Lemmy.", + "description": "Routes news articles from RSS and scraped sources to Fediverse communities.", "keywords": [ "fediverse", "lemmy", diff --git a/docs/screenshots/articles-light.png b/docs/screenshots/articles-light.png new file mode 100644 index 00000000..ed1dd9f7 Binary files /dev/null and b/docs/screenshots/articles-light.png differ diff --git a/docs/screenshots/channels-dark.png b/docs/screenshots/channels-dark.png new file mode 100644 index 00000000..0de52acb Binary files /dev/null and b/docs/screenshots/channels-dark.png differ diff --git a/docs/screenshots/dashboard-dark.png b/docs/screenshots/dashboard-dark.png new file mode 100644 index 00000000..6d88fbf1 Binary files /dev/null and b/docs/screenshots/dashboard-dark.png differ diff --git a/docs/screenshots/feeds-dark.png b/docs/screenshots/feeds-dark.png new file mode 100644 index 00000000..a7886335 Binary files /dev/null and b/docs/screenshots/feeds-dark.png differ diff --git a/docs/screenshots/routes-edit-dark.png b/docs/screenshots/routes-edit-dark.png new file mode 100644 index 00000000..3576b714 Binary files /dev/null and b/docs/screenshots/routes-edit-dark.png differ