Skip to content

Search and import repeaters from the RepeaterBook API (#136) - #139

Merged
ww8l merged 1 commit into
mainfrom
issue-136-repeaterbook-api
Oct 11, 2026
Merged

ww8l merged 1 commit into
mainfrom
issue-136-repeaterbook-api

Conversation

@ww8l

@ww8l ww8l commented Oct 11, 2026

Copy link
Copy Markdown
Owner

Closes #136.

CodePlug Magic is approved as a RepeaterBook distributed app. This adds a RepeaterBook button on the Channels page that searches RepeaterBook directly with the user's own token, replacing the export-a-file-then-import step.

Everything is built to the answers in the API application, now committed as docs/repeaterbook-api-commitments.md (with the 2,000-record library cap removed, as agreed with RepeaterBook, and the api.export_row lines corrected).

Token

  • Each user pastes their own rbuapp_ token in Settings → RepeaterBook. It is stored in the OS credential store via the keyring crate: Keychain on macOS, Credential Manager on Windows, Secret Service on Linux.
  • It is never written to SQLite, settings, logs or a backup.
  • It is sent only in the X-RB-App-Token header, over HTTPS, and redirects are refused so the header can't be carried to another host.

Requests

All in commands/rb_api.rs:

  • the exact approved User-Agent;
  • one request in flight, at least 2 s apart, at most 20 an hour;
  • an identical request within 10 minutes is answered from memory, never from disk;
  • 429/5xx: honours Retry-After, otherwise waits 30, 60, then 120 s, then stops and pauses searching;
  • 401/403: stops at once with no retry, and a 403 that is really rate limiting pauses instead of blaming the token.

Search

  • One area per search: a US state, a Canadian province, or a country outside North America.
  • Multi-select band, mode and emergency service.
  • County, city, call sign, on the air only, open only, distance from a town in the library, and hide ones I already have.
  • More than 1,000 matches shows nothing.

Import

  • At most 500 per import. After an import the results stay on screen, and select all picks the next batch not yet imported.
  • Records get source = 'repeaterbook_api' and RepeaterBook's own State ID + Repeater ID. Re-importing refreshes rather than duplicates.
  • A repeater already imported from a RepeaterBook file is taken over, keeping the user's names and edits. The source of an API record can't be edited.

Keeping records

  • Each record's detail panel has a single-record Refresh.
  • Records not refreshed in 12 months are flagged, with a prompt to refresh or delete them.
  • Remove RepeaterBook data deletes every API record and the token together.

Leaving the app

  • API records are left out of the channel export file and refused when importing a channel backup.
  • CHIRP exports put "RepeaterBook.com" in the Comment column.

Attribution

"Data courtesy of RepeaterBook.com", linked to RepeaterBook, appears in:

  • the search dialog and the import summary;
  • each record's detail panel, with its import date;
  • Settings → About, and a new README section.

tauri-plugin-opener is added for these links; its permission is limited to https://www.repeaterbook.com/*.

Verification

  • npm run ci passes: 782 Rust tests, clippy, frontend build.
  • New tests include a local mock server that exercises the real request path: header placement, User-Agent, memory cache, 429 retries then pause, 5xx recovery, 401 stop, 403 rate limit, and ua_mismatch.
  • A live search against RepeaterBook in the dev build worked: Michigan returned 514 repeaters, with one request logged.
  • Not yet exercised live: a rest-of-world country search, single-record Refresh, and a real 429/401 response from RepeaterBook.

🤖 Generated with Claude Code

The app is approved as a RepeaterBook distributed app. Each user pastes
their own rbuapp_ token once; it lives in the OS credential store
(Keychain / Credential Manager / Secret Service) via the keyring crate,
never in SQLite, settings, logs or a backup, and is sent only in the
X-RB-App-Token header over HTTPS with redirects refused.

Every request goes through one path in commands/rb_api.rs that enforces
what the application promised: the exact approved User-Agent, one request
in flight, 2 s spacing, 20 an hour, an identical request within 10
minutes answered from memory, 429/5xx backoff honouring Retry-After else
30/60/120 s then stop, and 401/403 stopping at once.

- Search one US state, Canadian province or country outside North
  America, narrowed by multi-select band / mode / emergency service and
  by county, city, call sign, on-air, open, distance from a library town
  and "hide ones I already have". More than 1,000 matches shows nothing.
- Import at most 500 at a time; after an import the results stay up and
  "select all" picks the next batch not yet imported.
- API records are source 'repeaterbook_api' keyed by RepeaterBook's own
  State ID + Repeater ID; re-import refreshes, a file-imported copy is
  taken over rather than duplicated, the source can't be edited.
- Single-record Refresh, a 12-month stale prompt, and "Remove RepeaterBook
  data" deleting every API record and the token together.
- API records are left out of the channel export file and refused from a
  channel backup; CHIRP exports carry "RepeaterBook.com" in the comment.
- "Data courtesy of RepeaterBook.com" in the dialog, the import summary,
  the detail panel, About, and the README.

docs/repeaterbook-api-commitments.md records the submitted application,
with the 2,000-record library cap removed (agreed with RepeaterBook) and
the api.export_row lines corrected to say what the code does.

Live search verified against RepeaterBook in the dev build (Michigan).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ww8l
ww8l merged commit 16f28a3 into main Oct 11, 2026
3 checks passed
@ww8l
ww8l deleted the issue-136-repeaterbook-api branch October 11, 2026 01:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Repeaterbook API

1 participant