This commit is contained in:
thePR0M3TH3AN committed 2026-03-15 17:12:48 -04:00
1 parent b97ea97c6e
commit db4f11ba6d
2 files changed
+1508

No files matched your search

+370
View File
@@ -0,0 +1,370 @@
# AGENTS.md
## Purpose
This repository contains a Python tool that incrementally syncs downloadable file claims from configured LBRY/Odysee channels into a structured local archive.
Primary goals:
1. Resolve configured channels to stable LBRY identities.
2. Enumerate downloadable claims published by those channels.
3. Download only new claims or new versions.
4. Preserve old versions instead of overwriting them.
5. Maintain deterministic local structure and persistent state.
This project prioritizes correctness, repeatability, and safe incremental behavior over cleverness.
---
## Non-negotiable rules
- Do not scrape Odysee HTML pages when the local LBRY daemon can provide the same metadata.
- Prefer stable identifiers over presentation-layer names:
- channel identity = `channel_claim_id`
- claim identity = `claim_id`
- version identity = `sd_hash` if available, otherwise a deterministic fallback
- Never use title or filename alone as identity.
- Never overwrite an existing downloaded version in place.
- Never mark a download as complete in state unless the file exists and metadata is written.
- Keep changes small and targeted. Do not do unrelated refactors.
- Do not add new dependencies unless they clearly reduce complexity or improve reliability.
- Do not add cloud services, databases, or background workers unless explicitly requested.
---
## Expected architecture
Agents should preserve this separation of concerns:
- `main.py`
- entry point
- orchestration
- summary logging
- `config_loader.py`
- load and validate YAML config
- `lbry_client.py`
- all JSON-RPC communication with local `lbrynet` daemon
- isolate daemon/API compatibility here
- `planner.py`
- compare discovered claims against local state
- decide: skip / new / new_version / redownload_missing
- `downloader.py`
- execute downloads
- write metadata files
- finalize state updates
- `state_db.py`
- load/save state
- atomic writes only
- `models.py`
- dataclasses / typed structures
- `utils.py`
- slugifying, hashing, time helpers, filesystem helpers
If the implementation diverges from this shape, preserve the same boundaries.
---
## Filesystem contract
Default base directory is expected to be:
`~/Documents/lbry-downloads`
Expected structure:
```text
lbry-downloads/
config.yaml
state/
database.json
run-history.jsonl
channels/
<channel_slug>__<channel_claim_id>/
channel.json
claims/
<claim_slug>__<claim_id>/
claim.json
versions/
<version_token>/
<downloaded_file>
metadata.json
download.json
checksums.txt
````
Rules:
* Sanitize filesystem names.
* Preserve extensions when possible.
* Keep folder names deterministic.
* Store metadata beside each downloaded file version.
* Do not flatten version folders.
---
## State management rules
State is a core feature, not a convenience.
Requirements:
* Persistent state must exist across runs.
* State writes must be atomic.
* A claim may have multiple versions.
* A rerun must skip already-downloaded versions.
* If state says a version exists but the local file is missing, treat it as `redownload_missing`.
* Keep prior versions on disk unless the user explicitly asks for pruning.
Preferred initial format:
* JSON state database for v1
* append-only `run-history.jsonl` for auditability
Do not silently delete historical records.
---
## Channel handling rules
Accepted user inputs may include:
* Odysee channel URLs
* LBRY URIs
* channel claim IDs
Normalization rules:
* Accept convenient input forms.
* Resolve to canonical LBRY metadata as early as possible.
* Store and operate on `channel_claim_id` internally.
* If a channel display name changes, keep continuity through the claim ID.
Do not build logic around URL string shape beyond initial parsing.
---
## Download rules
A claim should be downloaded only if it is actually downloadable through the daemon.
Include by default:
* downloadable stream/file claims
Exclude by default:
* reposts
* channels
* collections
* unsupported claim types
If repost support is added, make it config-driven and default-off.
For every successful download:
1. create channel / claim / version folders
2. download into the version folder
3. write normalized metadata
4. write raw or near-raw daemon response
5. optionally write checksum file
6. update state only after success
Do not reorder that sequence.
---
## Version detection rules
Use this priority order for version identity:
1. `sd_hash`
2. `stream_hash`
3. `txid:nout`
4. deterministic hash of normalized metadata JSON
Interpretation:
* same `claim_id` + same version token => skip
* same `claim_id` + different version token => new version
* unseen `claim_id` => new claim
Do not use title changes, filename changes, or folder names as version signals.
---
## Logging and reporting
Logging should be useful during long sync runs.
Always log:
* daemon connectivity result
* channel resolution result
* scan progress
* per-claim action decision
* download success/failure
* final summary counts
Preferred summary fields:
* channels scanned
* claims examined
* new downloads
* new versions
* skipped existing
* redownloaded missing
* failures
Make logs concise and grep-friendly.
---
## Error handling
Prefer graceful degradation over hard failure.
Rules:
* If daemon is unavailable, fail fast with a clear message.
* If one channel fails to resolve, log it and continue with the rest.
* If one claim fails, log it and continue.
* Do not write partial success to state.
* Do not swallow exceptions silently.
* If adding retries, keep them bounded and explicit.
Avoid “best guess” behavior when metadata is incomplete. Prefer a logged skip.
---
## Configuration rules
Expected config file is YAML.
Config should cover:
* daemon API URL
* timeout
* base output directory
* state file path
* max workers
* dry-run
* checksum writing
* verification of existing files
* repost inclusion
* channel list
Agents may extend config, but must follow these rules:
* add defaults conservatively
* preserve backwards compatibility where practical
* validate new fields explicitly
* do not remove existing config keys without migration notes
---
## Development workflow
Before finishing changes:
1. run formatting
2. run linting if configured
3. run tests if present
4. run a dry-run against sample config if practical
5. verify no obvious regression in path/state/version logic
If the repo has a `Makefile`, `pyproject.toml`, `justfile`, or documented task runner, use that instead of inventing commands.
Preferred commands when available:
```bash
python -m pytest
python -m ruff check .
python -m ruff format .
python main.py --dry-run
```
If these tools are not configured in the repo, do not add them casually.
---
## Code style
* Target readable Python over clever Python.
* Prefer small pure functions for planning and normalization logic.
* Keep daemon I/O isolated from business logic.
* Add types where they materially improve clarity.
* Use dataclasses or clearly documented dict schemas.
* Avoid deeply nested control flow.
* Keep path logic deterministic and testable.
When changing behavior, update:
* config comments/examples
* state schema notes if relevant
* any sample output or CLI docs
---
## Testing priorities
If tests exist or are added, prioritize these cases:
1. channel input normalization
2. slug/path sanitization
3. version token generation
4. skip vs new vs new-version decisions
5. missing-file redownload behavior
6. atomic state write behavior
7. metadata normalization stability
The most valuable tests are the ones that prevent duplicate downloads or broken state.
---
## Safe change policy
Safe changes:
* bug fixes in normalization, planning, downloading, or state handling
* clearer logging
* improved config validation
* additional tests
* daemon compatibility fixes isolated to client wrapper
Changes that need extra caution:
* state schema changes
* path layout changes
* version token logic changes
* concurrency changes
* anything that could duplicate downloads or orphan files
For high-impact changes, preserve backwards compatibility or document a migration path.
---
## Things agents should not do
* Do not replace the daemon-based approach with scraping.
* Do not switch persistence to SQLite unless explicitly requested.
* Do not add async/concurrency complexity unless needed.
* Do not rename major folders or config keys casually.
* Do not remove version history.
* Do not “clean up” files automatically without an explicit retention policy.
* Do not assume Odysee URL formats are permanent.
* Do not assume filenames are unique.
* Do not commit secrets, auth tokens, or machine-specific absolute paths.
---
## When uncertain
When faced with an ambiguous implementation choice, prefer:
1. stable identifiers over names
2. deterministic behavior over convenience
3. append-only/history-preserving behavior over destructive updates
4. explicit logging over silent magic
5. compatibility in `lbry_client.py` over leaking API quirks through the codebase
This project is an incremental archive/sync tool. Protect the archive first.
+1138
View File
File diff suppressed because it is too large. Load diff