# Contributing ## Prerequisites - Python 3.11+ - [just](https://github.com/casey/just) (task runner) - Git ## Quick Start ```bash # Clone the repository git clone https://github.com/RJNY/Obtainium-Emulation-Pack.git cd Obtainium-Emulation-Pack just add-app # interactive CLI to add a new app just test --verbose --apks # verify configs resolve to real APKs (with full details) just build # test, validate, normalize, and generate all output files ``` ## Project Structure ``` justfile # Primary task runner (run `just` to see commands) utility.just # Private helper recipes (imported by justfile) src/ applications.json # Source of truth - all app definitions scripts/ constants.py # Shared constants and Obtainium source schema utils.py # Shared utility functions and .env loader help_formatter.py # Styled argparse help formatter (ANSI colors) validate-json.py # Validates applications.json test-apps.py # Live-tests configs resolve to downloadable APKs add-app.py # Interactive CLI to add a new app generate-table.py # Generates the README table generate-readme.py # Stitches markdown files into README minify-json.py # Creates release JSON files normalize-json.py # Normalize key order and backfill defaults process-test-results.py # Processes scheduled test results, manages GitHub issues release.py # Automated release workflow (tag, push, gh release) pages/ header.md # README header/intro table.md # Generated - app tables (do not edit) faq.md # FAQ section footer.md # Short section linking here (stitched into README) obtainium-emulation-pack-latest.json # Standard release obtainium-emulation-pack-dual-screen-latest.json # Dual-screen release ``` ## Adding a New Application ### Option A: Quick Add (Recommended for GitHub apps) Use the interactive CLI to quickly add a new app: ```bash just add-app ``` This will: - Prompt you for the GitHub URL - Auto-detect the source, author, and app name - Ask for the Android package ID and category - Generate proper Obtainium settings - Add the app to `applications.json` > **Tip:** To find the package ID, open the app in Obtainium - the package ID is displayed directly below the source URL (e.g., `com.example.android`). After running, execute `just build` to regenerate all files. ### Option B: Manual Add (For complex configs or non-GitHub sources) #### Step 1: Export the app config from Obtainium 1. Open Obtainium on your device 2. Add the app you want to include (configure it how you want) 3. Long-press the app and select "Export" 4. Choose "Obtainium Export" format 5. Transfer the JSON to your computer #### Step 2: Add the app to applications.json Open `src/applications.json` and add your app to the `apps` array: ```json { "id": "com.example.emulator", "url": "https://github.com/example/emulator", "author": "example", "name": "Example Emulator", "preferredApkIndex": 0, "additionalSettings": { "apkFilterRegEx": "arm64", "about": "Example emulator description" }, "categories": ["Emulator"], "overrideSource": "GitHub" } ``` > **Note:** `additionalSettings` is a **sparse JSON object** - only include values that differ from the defaults. The full settings are hydrated automatically at export time. See `scripts/constants.py` for the schema and default values. #### Step 3: Add meta fields (optional) Add a `meta` object to customize how the app appears: ```json { "id": "com.example.emulator", "url": "https://github.com/example/emulator", "author": "example", "name": "Example Emulator", "preferredApkIndex": 0, "additionalSettings": { "apkFilterRegEx": "arm64", "about": "Example emulator description" }, "categories": ["Emulator"], "overrideSource": "GitHub", "meta": { "nameOverride": "Example Emu", "urlOverride": "https://example-emu.org" } } ``` #### Step 4: Validate, test, and regenerate ```bash just test AppName --verbose --apks # verify your app config resolves to a real APK just validate # check for structural errors just build # test, validate, normalize, and generate all output files ``` ## CI ### Pull request / push checks Pull requests and pushes to `main` are checked by GitHub Actions (`ci.yml`, single job): 1. **Validate** - structural checks, regex syntax, source types 2. **Test** - verifies all app configs resolve to real APKs 3. **Generate** - normalizes, generates README, builds release JSONs 4. **Diff check** - fails if generated files are out of date All steps must pass before merging. ### Scheduled tests A separate workflow (`scheduled-test.yml`) runs daily at ~6 AM Central. It live-tests every app config and automatically creates GitHub issues for any failures. When a previously failing app starts passing again, the issue is auto-closed. You can dry-run this locally with `just test-cron`. ## Pre-Commit Checklist Before committing, run `just build`, then verify: - [ ] `just test` passes (all app configs resolve to downloadable APKs) - [ ] `obtainium-emulation-pack-latest.json` has been updated - [ ] `obtainium-emulation-pack-dual-screen-latest.json` has been updated - [ ] `README.md` has been updated - [ ] The README table shows a friendly application name (use `nameOverride` if not) - [ ] The README table links to the correct homepage (use `urlOverride` if not) - [ ] Beta apps are excluded with `meta.excludeFromExport: true` ## Available Commands Run `just` to see all available commands. Recipes with `*args` accept `-h` for help. | Command | Description | | ----------------------------- | ----------------------------------------------------------- | | `just add-app` | Interactive CLI to add a new app | | `just validate` | Validate applications.json (structure, regex, source types) | | `just normalize` | Normalize key order and backfill defaults | | `just test` | Live-test all app configs resolve to downloadable APKs | | `just test AppName` | Live-test a single app by name (partial match) | | `just test --verbose --apks` | Live-test all apps with full APK URL details | | `just test-cron` | Dry-run the scheduled test workflow (no issues created) | | `just generate` | Generate all output files (README, release JSONs) | | `just generate table` | Generate the README table only | | `just generate readme` | Generate README (includes table) | | `just generate standard` | Generate standard release JSON only | | `just generate dual-screen` | Generate dual-screen release JSON only | | `just build` | Test, validate, normalize, and generate all output files | | `just release` | Tag, push, and create a GitHub release | ## Meta Field Reference These fields in the `meta` object control how apps are processed: | Field | Type | Default | Description | | --------------------- | ------ | ------- | ------------------------------------------------------------------- | | `excludeFromExport` | bool | `false` | Exclude from both release JSON files. Use for beta/unstable apps. | | `excludeFromTable` | bool | `false` | Exclude from the README table. | | `includeInStandard` | bool | `true` | Include in standard release. Set `false` for dual-screen-only apps. | | `includeInDualScreen` | bool | `true` | Include in dual-screen release. Set `false` for standard-only apps. | | `nameOverride` | string | `null` | Override the display name in the README table. | | `urlOverride` | string | `null` | Override the homepage link in the README table. | ## Categories Apps are organized into categories that appear as sections in the README table: | Category | Description | | -------------- | ---------------------------------------------------------------- | | `Emulator` | Console/handheld emulators (Dolphin, RetroArch, PPSSPP, etc.) | | `Frontend` | Emulator launchers and game library managers (Daijisho, Pegasus) | | `Utilities` | Helper apps (Syncthing, OdinTools, LED controllers, etc.) | | `PC Emulation` | Windows/PC game layers (Winlator, etc.) | | `Streaming` | Game streaming clients (Moonlight, etc.) | | `Track Only` | Version tracking without APK downloads (drivers, meta-packages) | An app can belong to multiple categories. ## Dual-Screen vs Standard The pack supports two variants: - **Standard** (`obtainium-emulation-pack-latest.json`): For regular Android devices - **Dual-Screen** (`obtainium-emulation-pack-dual-screen-latest.json`): For dual-screen devices (AYN Thor, Anbernic RG DS, etc.) Some apps have dual-screen-specific forks (e.g., Cemu, MelonDS). Use the `includeInStandard` and `includeInDualScreen` flags to control which variant(s) include each app. **Why this matters:** Apps with the same Android package ID (`id` field) will conflict in Obtainium. If two apps share an ID (like standard Cemu and dual-screen Cemu), they **must not** both appear in the same JSON file. Example: Standard Cemu excluded from dual-screen, dual-screen fork excluded from standard: ```json // Standard Cemu - exclude from dual-screen JSON { "id": "info.cemu.cemu", "name": "Cemu", "url": "https://github.com/SSimco/Cemu", "categories": ["Emulator"], "meta": { "includeInDualScreen": false } } // Dual-screen Cemu fork - exclude from standard JSON { "id": "info.cemu.cemu", "name": "Cemu", "url": "https://github.com/SapphireRhodonite/Cemu", "categories": ["Emulator"], "meta": { "includeInStandard": false } } ``` ## Choosing the Right Category and Variant Use this decision tree: 1. **Is this app device-specific?** (e.g., AYN Thor frontend) - Yes: Set `includeInStandard: false` and use appropriate category - No: Continue to step 2 2. **Does this app share an ID with another app in the pack?** (e.g., forks, beta builds, dual-screen variants) - Yes: Only one app per ID can be in each release JSON. Options: - Use `includeInStandard`/`includeInDualScreen` to split between variants - Use `excludeFromExport: true` on the less stable version (e.g., nightly builds) - No: App can be in both variants (default) 3. **Is this app stable and ready for users?** - Yes: Include normally - No: Set `excludeFromExport: true` (still visible in table but not in release JSONs)