diff --git a/docs/development.md b/docs/development.md index bed7ee5..f64b461 100644 --- a/docs/development.md +++ b/docs/development.md @@ -113,29 +113,37 @@ or ssh — the app installs itself once the TV can reach a URL. ### Your own repository (no review, no waiting) The Homebrew Channel's *Settings → Repositories → Add repository* accepts any -URL that returns `{"packages": [...]}`, where each entry is the same manifest -[`make-manifest.py`](../tools/make-manifest.py) already writes. Point one at -your own git host's release assets and the app shows up in Browse with no -submission process at all — this is what `--repo-out` (on by default) is for. +URL that returns `{"packages": [...]}`. Each entry needs its own `id`/ +`title`/`iconUri` for the Browse grid, plus the full manifest nested under a +`manifest` key for the details screen — [`make-manifest.py`](../tools/make-manifest.py) +builds exactly that shape. Point one at your own git host's release assets and +the app shows up in Browse with no submission process at all — this is what +`--repo-out` (on by default) is for. 1. Bump `version` in `frontend/appinfo.json`, `servicefiles/package.json` and `package.json`. 2. Build the ipk: `./tools/docker-build.sh && ./tools/build.sh package` (or `./tools/build.sh` on Linux with the NDK installed). -3. Create a release tagged e.g. `v1.0.0` and attach three files to it: the - ipk, `frontend/assets/icon.png`, and a repo index generated with - `--base-url` set to that release's asset URL: +3. Create a release — note the **exact tag** Gitea/GitHub gives it, `1.0.0` or + `v1.0.0`, whichever it actually is — and attach three files: the ipk, + `frontend/assets/icon.png`, and a repo index generated with `--base-url` + set to that release's real download URL: ```sh python3 tools/make-manifest.py \ - --base-url https://git.crylia.de/Crylia/lgtv_audio_cap/releases/download/v1.0.0 - # -> out/manifest.json (one app entry) - # -> out/repo.json (that entry wrapped as {"packages": [...]}) + --base-url https://git.crylia.de/Crylia/lgtv_audio_cap/releases/download/1.0.0 + # -> out/manifest.json (one app entry, for the official-repo route below) + # -> out/repo.json ({"packages": [{id, title, iconUri, manifest: {...}}]}) ``` + A mismatched tag in `--base-url` doesn't error — it just makes the icon and + ipk links inside `repo.json` 404 silently, which looks identical to "the + details screen hangs" from the client's point of view. If the app was + already added and only the tag was wrong, re-run with the fixed tag and + re-upload `repo.json`; no need to touch the "Add repository" entry itself, + since its URL didn't change. Attach `out/repo.json` itself too — its own download URL is what you paste - into the TV, and it must match `--base-url` exactly or the ipk/icon links - inside it point at the wrong place. + into the TV. 4. On the TV: Homebrew Channel → gear icon → *Add repository* → paste the `repo.json` release URL → back out to Browse → find *Audio Cap* → Install. diff --git a/tools/make-manifest.py b/tools/make-manifest.py index 270ade3..e4fdc52 100755 --- a/tools/make-manifest.py +++ b/tools/make-manifest.py @@ -6,15 +6,27 @@ The manifest (out/manifest.json) is one app entry: id, ipkUrl, ipkHash, and so on. It is what you submit to webosbrew/apps-repo to get into the official store. -The repo index (out/repo.json) is that same entry wrapped as -`{"packages": [...]}`, which is the format the Homebrew Channel's own -"Add repository" dialog expects (Settings -> Repositories -> Add repository). -Host it anywhere static, paste its URL in, and the app shows up in Browse — -no submission, no review, no shell access to the TV at all. +The repo index (out/repo.json) is `{"packages": [...]}`, which is the format +the Homebrew Channel's own "Add repository" dialog expects (Settings -> +Repositories -> Add repository). Host it anywhere static, paste its URL in, +and the app shows up in Browse — no submission, no review, no shell access to +the TV at all. + +Each package entry embeds the full manifest under a "manifest" key. That is +not decoration: the app's details screen (DetailsPanel.refresh(), read +straight from its source) only ever uses entry.manifest directly, or fetches +entry.manifestUrl if entry.manifest is absent. Ship a repo.json without either +one and the details view calls resolveURL(undefined, ...), throws, and spins +on "Loading" forever with no error shown. Embedding beats a manifestUrl +because there is only one file to keep in sync. python3 tools/make-manifest.py \\ --base-url https://git.example/you/lgtv-audio-cap/releases/download/v1.0.0 +--base-url must be the exact release download URL, tag and all — the icon and +ipk links are absolute, so a tag typo (v1.0.0 vs 1.0.0) 404s silently rather +than falling back to anything. + Defaults to the newest ipk in out/ and writes out/manifest.json + out/repo.json. """ @@ -91,9 +103,23 @@ def main(): print("\nwrote %s" % os.path.relpath(args.out, ROOT), file=sys.stderr) if args.repo_out: + # The grid view (BrowserPanel) reads id/title/iconUri straight off the + # package entry. The details view (DetailsPanel) only ever looks at + # entry.manifest directly, or fetches entry.manifestUrl if that is + # missing — never the entry's own top-level fields. Skipping + # manifestUrl (a second file, a second URL to keep in sync) by + # embedding the manifest here means DetailsPanel takes its + # already-ready fast path and never issues that fetch at all. + package_entry = { + "id": manifest["id"], + "title": manifest["title"], + "iconUri": manifest["iconUri"], + "shortDescription": manifest["appDescription"], + "manifest": manifest, + } os.makedirs(os.path.dirname(args.repo_out) or ".", exist_ok=True) with open(args.repo_out, "w") as fh: - json.dump({"packages": [manifest]}, fh, indent=2) + json.dump({"packages": [package_entry]}, fh, indent=2) fh.write("\n") print("wrote %s" % os.path.relpath(args.repo_out, ROOT), file=sys.stderr)