wcpan.drive.feed
An HTTP server that watches local filesystem paths with inotify, computes file metadata lazily, and exposes a token-based change log API — similar to Google Drive's changes API. This enables clients to efficiently poll for incremental changes without full directory scans.
Features
- Watches directories recursively via inotify or fanotify (Linux only)
- Computes MD5 hash, MIME type, and image/video dimensions per file
- Token-based change log API: clients request only changes since their last cursor
- Merges intermediate events (e.g. multiple modifies → single update; create+delete → skip)
- No authentication (designed for intranet use)
Requirements
- Linux (inotify or fanotify)
- Python 3.13+
libmagic1andmediainfosystem packages
Installation
# Install system dependencies
apt-get install libmagic1 mediainfo
# Install Python package with your chosen watcher backend
pip install "wcpan-drive-feed[inotify]" # inotify backend
pip install "wcpan-drive-feed[fanotify]" # fanotify backend
Configuration
Create a YAML config file:
host: "0.0.0.0"
port: 8080
database_url: "/data/db/server.db"
watches:
media: /mnt/media
photos: /mnt/photos
watcher:
backend: inotify # or "fanotify"
# Optional:
# exclude:
# - "*.tmp"
# log_path: /data/logs/server.log
The watcher.backend field is required and must be either "inotify" or "fanotify".
Running
wcpan.drive.feed --config=/path/to/server.yaml
The --config flag defaults to /data/server.yaml.
API
GET /api/v1/cursor
Returns the current change log cursor (the latest change ID).
{ "cursor": 42 }
GET /api/v1/changes?cursor=<int>
Returns all changes since the given cursor. Missing cursor defaults to 0. Invalid cursor returns HTTP 400.
{
"cursor": 57,
"changes": [
{
"removed": false,
"node": {
"id": "...",
"parent_id": "...",
"name": "image.jpg",
"is_directory": false,
"ctime": "2026-03-04T12:00:00+00:00",
"mtime": "2026-03-04T12:00:00+00:00",
"mime_type": "image/jpeg",
"hash": "d41d8cd98f00b204e9800998ecf8427e",
"size": 204800,
"is_image": true,
"is_video": false,
"width": 1920,
"height": 1080,
"ms_duration": 0
}
},
{
"removed": true,
"node_id": "..."
}
]
}
Nodes appear in two phases: first with hash: "" immediately after detection, then again with the full hash/MIME/dimensions after metadata computation completes. Clients should treat a second update for the same node as the final state.
GET /api/v1/root
Returns the virtual super-root node (parent of all watch-root directories).
{
"id": "00000000-0000-0000-0000-000000000000",
"parent_id": null,
"name": "",
"is_directory": true,
"ctime": "2026-03-04T12:00:00+00:00",
"mtime": "2026-03-04T12:00:00+00:00",
"mime_type": "",
"hash": "",
"size": 0,
"is_image": false,
"is_video": false,
"width": 0,
"height": 0,
"ms_duration": 0
}
GET /api/v1/nodes/{id}/path
Returns the absolute filesystem path for a node.
{ "path": "/mnt/media/photos/image.jpg" }
Returns HTTP 404 if the node does not exist, HTTP 400 if the node is the super-root.
Development
# Run tests
make test
# Format code
make format
# Lint
make lint
How It Works
- On startup, the server initializes the SQLite database (auto-creates schema; aborts on version mismatch), then scans all configured watch paths and inserts/updates nodes.
- The configured watcher backend (
asyncinotifyor a customfanotifybackend) monitors each path for filesystem events (create, modify, delete, move). - File metadata (MD5, MIME type, image/video dimensions) is computed in a
ThreadPoolExecutorto avoid blocking the event loop. - Every change is appended to a
changestable. The/changesendpoint merges overlapping events per node — the last event wins — so clients always see the effective state. - The server returns HTTP 503 while the startup scan and queue drain are in progress.
Metadata
Release files for wcpan-drive-feed 1.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| wcpan_drive_feed-1.6.0.tar.gz | 89.4 kB | Without provenance | Details for wcpan_drive_feed-1.6.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| wcpan_drive_feed-1.6.0-py3-none-any.whl | Python 3 | none | any | Details for wcpan_drive_feed-1.6.0-py3-none-any.whl |
Total release size: 119.4 kB
Release files / wcpan_drive_feed-1.6.0.tar.gz
| Download URL | wcpan_drive_feed-1.6.0.tar.gz |
|---|---|
| Size | 89.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5267fe0cf5dea58a75d42da72246597afbb6af07bbd30f45191c4c1a46a7cdac
|
|
BLAKE2b-256 checksum How to use checksums |
2f120822395a04b15cfdb9e69218c23487c94f56f21f39c3c08b819a54d73222
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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":null}
|
Release files / wcpan_drive_feed-1.6.0-py3-none-any.whl
| Download URL | wcpan_drive_feed-1.6.0-py3-none-any.whl |
|---|---|
| Size | 30.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ba30bbb8cb82457beb923102581d219bd56f6f039813ec64bf78054790ecc71c
|
|
BLAKE2b-256 checksum How to use checksums |
c6ffbdc51313da1b3501677c797f06fb0607f5f7f2e62a29f4af694dc5f06dda
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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":null}
|
Security for wcpan-drive-feed 1.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.