Skip to main content

Monitor and filter Fediverse hashtags, curate quality content, and distribute via external tools like Zhongli

Project description

FenLiu (分流)

Created by marvin8 with assistance from Claude and DeepSeek AI assistants.

⚠️ DISCLAIMER / PROVISO: This project is a work in progress with major changes still happening. It is in no way anywhere close to finished and is only borderline useful for actual production use. Expect breaking changes, incomplete features, and significant architectural evolution as development continues.

Divide the Fediverse content flow

FenLiu is a web application that monitors Fediverse hashtags, filters spam, allows human review, learns from feedback, and exports quality content for boosting. Inspired by the ancient Chinese Dujiangyan irrigation system (256 BC) that separated silt from water, FenLiu applies 2,300-year engineering wisdom to modern digital content streams.

Current Status — v0.7.1

Fully functional spam filtering and content management system with complete Curated Queue integration, flexible pattern-based user blocking, automated queue lifecycle management, production-ready containerization, and ML training data collection.

Latest (v0.7.1): Random post selection for the Curated Queue API. 411 tests passing.

Documentation

📚 Live Docs: https://marvinsmastodontools.codeberg.page/fenliu/

The docs/ folder contains full MkDocs documentation covering installation, API reference, pattern blocking, Curated Queue integration, and more.

mkdocs serve   # serve locally with hot reload
mkdocs build   # build static site

Features

Core Functionality

  • Hashtag Monitoring: Monitor multiple Fediverse hashtags with customizable instance sources and scheduling
  • Spam Scoring: Rule-based detection (0-100 scale) with 7 intelligent detection rules
  • Manual Review Interface: Approve/reject posts with scoring; pagination, bulk actions, and auto-refresh
  • Curated Queue Export: Reliable API-driven queue with ack/nack/error pattern

Reblog Controls (Export Filters)

  • Pattern-Based User Blocking: exact, suffix, prefix, and contains matching modes
  • Hashtag Blocklist: Exclude posts containing blocked hashtags
  • Attachments-Only Mode: Export only posts with media attachments
  • Auto-Reject on Fetch: Automatically reject blocked content before review
  • Blocklist Refresh: Apply Settings changes to the review page instantly

Web Interface

  • Dashboard, Streams Management, Review Workflow, Pattern Blocking Settings, Queue Preview, Statistics
  • Responsive design — no external JavaScript dependencies

REST API

  • Hashtag streams, posts, curated queue, reblog controls, statistics, health
  • API key authentication for queue endpoints

Technical Quality

  • 411 tests, 100% passing
  • Comprehensive type hints; zero type errors under ty check
  • All functions pass ruff and complexipy checks
  • Alembic migrations run automatically on startup

Quick Start

Prerequisites: Python 3.12+, uv package manager

uv sync -U --all-groups
fenliu --reload --debug

Open http://localhost:8000, create a hashtag stream, fetch posts, and review them.

Container Deployment

podman build -t fenliu -f Containerfile .
cp .env.example .env   # edit with your settings
podman run -d -p 8000:8000 --env-file .env \
  -v fenliu-data:/app/data -v fenliu-logs:/app/logs fenliu

See the Container Deployment guide for full details.

API Endpoints

All curated queue endpoints require X-API-Key header (generate in Settings).

Streams & Posts:

  • GET /api/v1/streams — List streams
  • POST /api/v1/streams — Create stream
  • GET/PUT/DELETE /api/v1/streams/{id} — Stream operations
  • POST /api/v1/streams/{id}/fetch — Fetch posts for stream
  • POST /api/v1/streams/fetch-all — Fetch all active streams
  • GET /api/v1/posts — List posts with filtering
  • PATCH /api/v1/posts/{id} — Update post (review, approve, score)
  • GET /api/v1/stats — Application statistics

Curated Queue:

  • GET /api/v1/curated/next — Next post (204 if empty); ?random=true for random selection
  • POST /api/v1/curated/{post_id}/ack — Confirm successful reblog
  • POST /api/v1/curated/{post_id}/nack — Return to queue (transient failure)
  • POST /api/v1/curated/{post_id}/error — Mark permanently failed
  • POST /api/v1/curated/{post_id}/requeue — Return errored post to queue
  • POST /api/v1/curated/cleanup — Delete old delivered posts
  • POST /api/v1/curated/trim-pending — Trim excess pending posts

Reblog Controls:

  • GET/PUT /api/v1/reblog-controls/settings — Reblog filter settings
  • GET/POST /api/v1/reblog-controls/blocked-users — Blocked users (pattern-based)
  • DELETE /api/v1/reblog-controls/blocked-users/{id} — Remove blocked user
  • GET/POST /api/v1/reblog-controls/blocked-hashtags — Blocked hashtags
  • DELETE /api/v1/reblog-controls/blocked-hashtags/{id} — Remove blocked hashtag
  • POST /api/v1/reblog-controls/reject-blocked — Bulk reject matching posts

System: GET /health, GET /info

See the API docs for full reference.

Configuration

Key environment variables (see .env.example for full list):

Variable Default Description
DATABASE_URL sqlite:///./fenliu.db Database connection
DEFAULT_INSTANCE mastodon.social Default Fediverse instance
RESERVE_TIMEOUT_SECONDS 300 Queue reservation timeout
VERY_HIGH_THRESHOLD 76 Spam score: very high
LOW_MAX_THRESHOLD 25 Spam score: low
DEBUG false Enable debug logging

Development

uv run pytest                    # run tests
uv run ruff check .              # lint
uv run complexipy .              # complexity check
uv run ty check                  # type check
nox                              # full CI simulation

alembic upgrade head             # apply migrations
alembic revision --autogenerate -m "description"  # new migration

Project Structure

fenliu/
├── src/fenliu/
│   ├── main.py                  # PyView application and LiveViews
│   ├── models.py                # SQLAlchemy models
│   ├── schemas.py               # Pydantic validation
│   ├── api/                     # REST API (curated, reblog_controls, api_keys)
│   ├── services/                # Business logic (spam scoring, fediverse, scheduler)
│   ├── templates/               # HTML templates
│   └── static/                  # CSS and assets
├── alembic/                     # Database migrations
├── tests/                       # Test suite (402 tests)
└── docs/                        # MkDocs documentation

Technical Stack

  • Framework: PyView (Starlette-based LiveView)
  • Database: SQLAlchemy + SQLite, Alembic migrations
  • Validation: Pydantic v2
  • Fediverse: minimal-activitypub
  • Frontend: Jinja2 + Tailwind CSS, no external JS
  • Testing: pytest (411 tests)
  • Tooling: ruff, ty, complexipy, uv

What's New in v0.7.1

  • Random queue selection: GET /api/v1/curated/next?random=true returns a randomly chosen eligible post instead of the oldest. If the chosen author has more than one pending post, their oldest is returned to avoid consecutive same-author posts
  • 9 new tests for random selection behaviour; 411 total

Previous Release — v0.7.0

  • Review pagination: 20 posts/page with prev/next navigation
  • Bulk actions: Approve All / Reject All for the current page
  • Auto-refresh: Empty page reloads automatically when more posts exist
  • ML training snapshots: ReviewFeedback captures 12 feature fields at review time — survives queue cleanup
  • Bug fix: Stream deletion cascade fixed (Post → ReviewFeedback)

Previous Release — v0.6.0

  • Queue Lifecycle Management: Auto-delete delivered posts (7-day retention), trim excess pending with weighted random deletion, cleanup and trim-pending API endpoints
  • Production Containerization: Multi-stage build (~207 MB), non-root user, persistent volumes, automatic migrations on startup

Previous Release — v0.5.3

  • Pattern-Based User Blocking: exact, suffix, prefix, and contains matching modes — see PATTERN_BLOCKING_FEATURE.md
  • Blocklist Refresh: Apply Settings changes to the review page without losing progress

Cultural Context

"FenLiu" (分流) means "divide the flow" in Chinese, inspired by the Dujiangyan irrigation system (256 BC). This project applies the same engineering wisdom to digital content streams.

Key Resources

License

AGPL-3.0 — see LICENSE file.

Contributing

  1. Follow existing code style (ruff, comprehensive type hints)
  2. Write tests for new functionality
  3. Run nox before submitting changes
  4. Run alembic upgrade head after pulling changes with new migrations

v0.7.1 · Phase 4 In Progress · 411 tests ✅ · Codeberg

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fenliu-0.7.2.tar.gz (423.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fenliu-0.7.2-py3-none-any.whl (437.7 kB view details)

Uploaded Python 3

File details

Details for the file fenliu-0.7.2.tar.gz.

File metadata

  • Download URL: fenliu-0.7.2.tar.gz
  • Upload date:
  • Size: 423.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fenliu-0.7.2.tar.gz
Algorithm Hash digest
SHA256 505e9fe42314b6e064c95d1312f84b8aae5fd5c6defa279572e07e78c03068b6
MD5 851227e0b90c4f7e6a2b596872eebea2
BLAKE2b-256 20675c8c504a46a5b9b48b8edd6f929563ccf0654e9d046a7e64c4aa6f2039a7

See more details on using hashes here.

File details

Details for the file fenliu-0.7.2-py3-none-any.whl.

File metadata

  • Download URL: fenliu-0.7.2-py3-none-any.whl
  • Upload date:
  • Size: 437.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fenliu-0.7.2-py3-none-any.whl
Algorithm Hash digest
SHA256 3e5753c054609c1b4f6c7b33e7de7eb045d28c4e18abb7f7d525b630306087c9
MD5 24b7c0a6f182ff4ba1894d3bb10f921b
BLAKE2b-256 b279d8c2916e904420ccaacf23a4b92897026755a892c6b76a0cb167bac95aa7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page