Skip to content

Support custom/private repositories end-to-end in the current PocketBase-backed UI #657

Description

@Yo-19

🌟 Briefly describe the feature

Reconnect the existing multi-repository JSON support to the current PocketBase-backed UI so enabled custom repositories (including private repositories readable with GITHUB_TOKEN) can be synchronized, displayed, opened, and downloaded end-to-end.

📝 Detailed description

The repository already contains most of the required building blocks:

  • repository management with enabled repositories and priority;
  • githubJsonService.syncJsonFiles() / syncJsonFilesForRepo() for multi-repository JSON sync;
  • githubJsonService.getScriptBySlug() and getScriptCards() for JSON-backed scripts;
  • Script.repository_url / ScriptCard.repository_url for custom sources;
  • scriptDownloaderService.getRepoUrlForScript() and resolveScriptPath() so downloads can come from a script-specific repository and explicit install_methods[].script paths.

However, the current main UI path is PocketBase-only in a few key places:

  1. scripts.resyncScripts refreshes PocketBase data / logo cache but does not call the existing multi-repository JSON sync.
  2. getScriptCardsWithCategories returns PocketBase cards only, so synced custom JSON scripts are not displayed.
  3. getScriptBySlug, loadScript, and checkScriptFiles stop when PocketBase has no matching record instead of falling back to the JSON-backed custom repository service.

I verified the existing components with a non-destructive proof of concept using an enabled private GitHub repository:

  • GitHub Contents API for json/ returned HTTP 200 with the configured token;
  • raw downloads for json/<slug>.json, ct/<slug>.sh, and install/<slug>-install.sh returned HTTP 200;
  • direct githubJsonService.syncJsonFiles() successfully synchronized the custom JSON and injected repository_url;
  • merging custom githubJsonService.getScriptCards(repo.url) cards with the PocketBase cards (PocketBase wins on duplicate slug) made the custom script visible in the current UI;
  • falling back from PocketBase to githubJsonService.getScriptBySlug(slug) in getScriptBySlug, loadScript, and checkScriptFiles allowed the existing downloader to fetch both the CT script and install script from the custom repository;
  • no changes were required in scriptDownloaderService for repository selection: its existing repository_url support handled the custom source correctly.

A minimal upstream design could be:

  • expose an explicit repository sync mutation/button that calls the existing multi-repository JSON sync (or integrate it into an appropriate existing sync flow);
  • merge cards from enabled custom repositories into getScriptCardsWithCategories, excluding the main Community Scripts repo to avoid duplicates and giving PocketBase precedence by slug;
  • when PocketBase has no record, fall back to githubJsonService.getScriptBySlug() for detail/download/check routes;
  • extend the same fallback to multi-download if desired;
  • keep PocketBase as the authoritative source for official Community Scripts and use local JSON/custom repos only as an additive source.

This preserves the current architecture while making the already-present custom repository functionality usable end-to-end.

💡 Why is this useful?

This enables private or self-maintained script catalogs without requiring users to publish their scripts to the official Community Scripts repository. It is especially useful for homelab operators who maintain private deployment scripts but still want the same PVE Scripts Local UX for discovery, download, and installation.

It also avoids duplicating infrastructure already present in the codebase: repository management, JSON sync, source provenance, and repository-aware downloading already exist; the missing piece is primarily wiring them back into the current PocketBase-backed UI/runtime paths.

I can provide the small POC diff / test details if that would help with implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions