{"id":50866723,"url":"https://github.com/edonahue/endless-loader","last_synced_at":"2026-06-15T02:06:16.451Z","repository":{"id":352519103,"uuid":"1215446705","full_name":"edonahue/endless-loader","owner":"edonahue","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-09T10:11:50.000Z","size":683,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-09T12:09:15.464Z","etag":null,"topics":["flask","guitar-pedal","music-tech","polyend-endless","python","raspberry-pi"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/edonahue.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-19T23:19:23.000Z","updated_at":"2026-06-09T10:23:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/edonahue/endless-loader","commit_stats":null,"previous_names":["edonahue/endless-loader"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/edonahue/endless-loader","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edonahue%2Fendless-loader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edonahue%2Fendless-loader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edonahue%2Fendless-loader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edonahue%2Fendless-loader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/edonahue","download_url":"https://codeload.github.com/edonahue/endless-loader/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edonahue%2Fendless-loader/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34344441,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flask","guitar-pedal","music-tech","polyend-endless","python","raspberry-pi"],"created_at":"2026-06-15T02:06:15.701Z","updated_at":"2026-06-15T02:06:16.445Z","avatar_url":"https://github.com/edonahue.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Endless Loader\n\n`Endless Loader` is a phone-first web server for browsing local `.endl` patches and loading one selected patch onto a connected Polyend Endless pedal. It is designed for Raspberry Pi OS on Pi 3B/4/5, and it also runs on Ubuntu-family Linux systems including Pop!_OS and standard Ubuntu desktops or mini PCs.\n\n![Endless Loader desktop console](docs/assets/desktop-console.png)\n\n_Part of my [Open Workbench](https://erichdonahue.com/workbench) at [erichdonahue.com](https://erichdonahue.com)._\n\n## What It Does\n\n- Presents patches as a pedal-style control surface with labeled knobs.\n- Discovers the Endless USB storage volume by label or UUID.\n- Mounts the target volume when needed, copies the selected patch, and verifies the write with a read-back hash.\n- Shows clear ready, pending, and error status through the USB panel and floating beacon.\n- Updates an optional 1602 I2C LCD with the current patch name and compact knob labels.\n- Uses optional companion metadata from `edonahue/FxPatchSDK` for richer descriptions, controls, actions, and links.\n- Supports direct host USB control and Docker-friendly helper mode.\n\n## Screenshots\n\nDesktop console:\n\n![Desktop console](docs/assets/desktop-console.png)\n\niPhone-width console:\n\n![Mobile console](docs/assets/mobile-console.png)\n\nUSB not-ready guidance:\n\n![Mobile USB not ready](docs/assets/mobile-usb-not-ready.png)\n\n## Quick Start\n\nInstall system prerequisites on Raspberry Pi OS or Ubuntu-family Linux:\n\n```bash\nsudo apt install python3 python3-venv udisks2 util-linux\n```\n\nInstall the app:\n\n```bash\npython3 -m venv venv\nvenv/bin/pip install -e \".[dev]\"\ncp config.example.toml config.toml\n```\n\nEdit `config.toml`:\n\n```toml\nlibrary_root = \"/path/to/endl/patches\"\n\n[usb]\nmode = \"host\"\nexpected_label = \"ENDLESS\"\nexpected_uuid = \"\"\n```\n\nRun the server:\n\n```bash\nENDLESS_LOADER_CONFIG=config.toml venv/bin/endless-loader\n```\n\nOpen `http://localhost:8080`.\n\n## Platform Support\n\nThe current app code is portable across:\n\n- Raspberry Pi OS on Pi 3B/4/5\n- Ubuntu 22.04+ and other Ubuntu-family distributions with Python 3.10+\n- Pop!_OS as one Ubuntu-family example, not a special-case target\n\nFor `usb.mode = \"host\"`, the host needs:\n\n- `lsblk`\n- `findmnt`\n- `udisksctl`\n\nThose normally come from `util-linux` and `udisks2`.\n\n## USB Certainty Model\n\nWhen `usb.mode = \"host\"`, the app uses:\n\n- `lsblk --json` to discover candidate block devices and partitions\n- `findmnt --json` to determine the current mountpoint and read-only state\n- `udisksctl mount` to mount the matched Endless volume when needed\n- a temp-file copy plus atomic `os.replace` on the target volume\n- `fsync` on the file and containing directory\n- a read-back SHA-256 check when `usb.verify_hash = true`\n- optional `udisksctl unmount` and `power-off` when `usb.auto_eject_after_write = true`\n\nUse `usb.expected_uuid` for the strongest targeting. `usb.expected_label` is useful for first setup, but UUID matching avoids ambiguous writes if multiple removable volumes share a label.\n\n## Docker Helper Mode\n\nDocker runs the web app in `helper` mode so the container does not manage host USB mounts directly.\n\nRun the helper on the host:\n\n```bash\nENDLESS_LOADER_CONFIG=compose.helper.toml venv/bin/endless-loader-usb-helper\n```\n\nStart the container:\n\n```bash\ndocker compose up --build\n```\n\nThe included Compose config routes helper calls to `http://host.docker.internal:8755`.\n\n## Companion Metadata\n\nThe app can show richer patch detail when a companion manifest exists at:\n\n```text\nmetadata/endless_loader_companion.json\n```\n\ninside the `FxPatchSDK` checkout, or at the corresponding raw GitHub URL. A sample companion tree is included under [`samples/fxpatchsdk-companion`](samples/fxpatchsdk-companion).\n\n## More Docs\n\n- [Setup](docs/setup.md)\n- [Troubleshooting](docs/troubleshooting.md)\n- [Design Notes](docs/design.md)\n\n## Screenshot Capture\n\nRegenerate README screenshots with:\n\n```bash\nvenv/bin/python scripts/capture_screenshots.py\n```\n\nThe script requires Firefox on `PATH`.\n\n## Tests\n\nRun the test suite with:\n\n```bash\nvenv/bin/pytest\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedonahue%2Fendless-loader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fedonahue%2Fendless-loader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedonahue%2Fendless-loader/lists"}