Implement support for multiple catalogs and dynamic discovery#463
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd6cf638f2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
|
|
||
| suspend fun fetchCatalogPackManifest(packUrl: String): Result<CatalogPackManifest> { | ||
| val json = fetchUrl(packUrl) |
There was a problem hiding this comment.
Validate pack URLs before fetching
When a user pastes a pack URL without a scheme, such as arvio.app/packs/foo.json, or a malformed deep-link parameter, this new path passes it directly into fetchUrl; that helper builds the OkHttp Request before its try, so Request.Builder().url(...) throws and the ViewModel coroutine dies instead of setting packError. Normalize/validate the manifest URL or catch around request construction before calling fetchUrl.
Useful? React with 👍 / 👎.
| "author": "ARVIO Team", | ||
| "version": "1.0.0", | ||
| "description": "All the trending movies, popular lists, and upcoming releases you need for a perfect movie night.", | ||
| "url": "https://arvio.app/packs/cinema-essentials.json", |
There was a problem hiding this comment.
Point bundled packs at real manifests
The discovery page and /packs.json advertise these /packs/*.json manifest URLs, but this commit only adds /packs.json; repo-wide search for the four filenames and find web/public -maxdepth 3 -type f show no corresponding files or rewrites. With the static fallback or copied URL, every bundled pack's Install action fetches a 404 and Android shows Failed to fetch catalog pack from URL, so the advertised packs cannot be installed.
Useful? React with 👍 / 👎.
| null | ||
| } ?: return Result.failure(IllegalArgumentException("Failed to parse catalog pack manifest")) | ||
|
|
||
| if (manifest.id.isBlank() || manifest.name.isBlank()) { |
There was a problem hiding this comment.
Reject manifests without catalog items
This only validates id and name, but Gson can deserialize missing or null catalogs/item fields into Kotlin non-null vals; a malformed external manifest then reaches pendingPack.catalogs.size in the import dialog or item.url in addCatalogPack and crashes instead of displaying an import error. Validate catalogs is non-empty and each item has a nonblank name and url before returning success.
Useful? React with 👍 / 👎.
67e08b1 to
bce5de4
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a893a59ed5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| </intent-filter> | ||
|
|
||
| <!-- App Link: https://arvio.app/install-pack?url=... --> | ||
| <intent-filter android:autoVerify="true"> |
There was a problem hiding this comment.
Add Digital Asset Links for HTTPS installs
This HTTPS intent filter only works as an Android App Link if arvio.app serves a matching Digital Asset Links file for this package/signing certificate. I checked the repo with rg "assetlinks|install-pack" and there is no web/public/.well-known/assetlinks.json or Next route serving it, so on Android 12+ a shared https://arvio.app/install-pack?... link will stay in the browser/default handler instead of reaching parseInstallPackUrl; add the assetlinks response (or avoid advertising the HTTPS app-link path).
Useful? React with 👍 / 👎.
| onConfirm = { manifest -> | ||
| viewModel.confirmInstallPack(uiState.pendingPackUrl ?: "") |
There was a problem hiding this comment.
Install the manifest the user approved
When the user confirms the previewed pack, this discards the manifest passed by the dialog and starts installation from pendingPackUrl, and addCatalogPack fetches that URL again. If the manifest changes between preview and click (or the second fetch fails), the app installs/fails based on content that was not what the user approved; pass the already-loaded manifest into the install path or bind the second fetch to the previewed content.
Useful? React with 👍 / 👎.
|
This is a great feature and should make adding and organizing catalogs much easier. The builds pass, but a few things still need fixing before merge:
Please also clean the trailing whitespace and, ideally, add focused tests for duplicate URLs, duplicate pack IDs, malformed manifests, and preview/confirmation consistency. After these changes it should be ready for another review. |
a893a59 to
9f019de
Compare
Catalog Pack Improvements and Netlify Backend MigrationAll requested fixes have been implemented, verified, and pushed to the remote branch feature/catalog-packs. Both Android builds and Next.js static production builds compile successfully, and new unit tests have been added to verify correctness. Summary of Changes
Verification and Build Status
|
|
The Android/catalog-pack side now looks good and the builds/tests pass. Before fully merging, please fix the public catalog-packs-submit endpoint: |
701fef3 to
3f19d38
Compare
|
It needs to be rebased. |
00a62dc to
2b72114
Compare
…alformed URL checks, and create advertised manifests
…n in Settings screen
Walkthrough: - Updated empty Trakt sources in classics-franchises.json with active MDBList URLs. - Fixed the tv-binge.json 'Latest Airing' catalog URL to point to TV shows. - Derived unique pack IDs (hashing normalized pack URL and manifest ID) and updated catalog stable IDs to prevent duplication/deletion conflicts. - Added duplicate catalog URL detection and rejection in CatalogRepository.kt. - Migrated dynamic catalog discovery from Supabase to Netlify backend via a DB migration, /catalog-packs-list, and /catalog-packs-submit serverless functions. - Updated SettingsViewModel.kt to pass pre-downloaded pendingPackManifest on install confirmation, avoiding a second download. - Removed HTTPS App Link filter from AndroidManifest.xml. - Added focused unit tests in CatalogPackTest.kt.
…ections - Allow HTTPS manifest URLs only. - Block localhost, private/link-local IPs, carrier-grade NAT, and cloud metadata addresses (after DNS resolution and redirects). - Enforce manual redirect handling (max 3 redirects) with secure IP checking at each hop. - Configure AbortController timeout (4s) and maximum body size limits (512 KB). - Validate content-type headers to ensure application/json or text/plain. - Added database-backed submission rate limiting (SHA-256 hashed IPs for privacy, max 5/hour, 10s cooldown). - Added unique normalized URL checks in DB and migration schema. - Added comprehensive unit tests covering blocked internal URLs, oversized/slow responses, duplicate submissions, and rate limits. - Removed extra blank line in CatalogModels.kt to pass git diff check.
…player' The VLC button did nothing on Android: it used the iOS-only vlc-x-callback:// scheme, which Android VLC doesn't register. Android launches players via an intent:// URL — now VLC on Android fires a proper intent (org.videolan.vlc, with a browser_fallback_url). Also, on Android the second external button is now 'Open in player' — an intent chooser listing every installed video player (VLC, MX Player, Just Player, …) — instead of Infuse, which is iOS-only. iOS keeps VLC + Infuse. Applies to the source picker, the in-player source panel, and the player error screen; live-TV/VOD default handoff inherits the intent fix too. Verified: generated intent:// URLs are well-formed (scheme, VIEW action, video/* or x-mpegurl mime, package for VLC / none for chooser, encoded subtitle + fallback). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2b72114 to
bda44eb
Compare
This pull request introduces a "Catalog Pack" system, allowing users to import and manage groups of content catalogs via a single URL, improving catalog organization and onboarding. It adds deep link and app link support for installing packs, updates navigation and UI to handle pack installation flows, and provides repository and ViewModel logic for fetching, installing, and removing catalog packs. The catalog data model is extended to support pack metadata, and a sample
packs.jsonis added for available packs.Catalog Pack System and Deep Link Integration
arvio://install-pack?url=...) and app link (https://arvio.app/install-pack?url=...) to trigger catalog pack installation from external sources.Catalog Pack Data Model and Repository Enhancements
CatalogConfigmodel: AddspackIdandpackNamefields, computed properties for effective pack identification, and a flag for bulk deletability. IntroducesCatalogPackManifestandCatalogPackItemdata classes to represent pack manifests. [1] [2]CatalogRepository: Implements methods to fetch pack manifests, add packs (validates and imports all catalogs in a pack), and remove packs (bulk delete by pack ID). [1] [2]Settings UI and ViewModel Support
SettingsViewModel: Adds state and methods for loading, confirming, and removing catalog packs, handling loading and error states, and updating UI accordingly. [1] [2] [3]Demo Data
web/public/packs.jsonwith sample catalog pack definitions for testing and onboarding.Minor Fixes
TraktRepository.version.json.