diff --git a/AGENTS.md b/AGENTS.md index c31e91b..48775f0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # AGENTS.md -Flutter FFI package bridging to Aniyomi (Kotlin/Java) via JNI. +Flutter FFI package bridging to Unyo Core JVM runtime via JNI. ## Project Type @@ -59,7 +59,7 @@ jnigen/ ├── sanime.yaml, video.yaml, etc. # Per-class generation configs assets/ -└── aniyomibridge-core.jar # Java library (source of JNI bindings) +└── unyo-core.jar # Java library (source of JNI bindings) jre/ ├── linux/customjre/ # Custom JRE for Linux builds @@ -70,9 +70,9 @@ jre/ The `lib/jmodels/j*.dart` files are **auto-generated** from Java classes via JNIGen: -- Source JAR: `assets/aniyomibridge-core.jar` +- Source JAR: `assets/unyo-core.jar` - Configs: `jnigen/*.yaml` (one per Java class) -- Generated classes mirror `eu.kanade.tachiyomi.*` and `dev.k3vinb5.aniyomibridge.*` +- Generated classes mirror `eu.kanade.tachiyomi.*` and `dev.k3vinb5.unyo.core.*` **Never manually edit `jmodels/j*.dart` files**—regenerate via: ```bash diff --git a/JNI_SPECIFICATION.md b/JNI_SPECIFICATION.md deleted file mode 100644 index fce7669..0000000 --- a/JNI_SPECIFICATION.md +++ /dev/null @@ -1,625 +0,0 @@ -# AniyomiBridge JNI Specification - -> **Version:** 2.0 (Post-Multi-Module Refactor) -> **Target:** Flutter JNI integration for `aniyomibridge-core-1.0.0.jar` -> **Main Class:** `dev.k3vinb5.aniyomibridge.AniyomiBridge` - ---- - -## Overview - -This document specifies the public Java API exposed by `AniyomiBridge.java` for consumption via JNI from Flutter. It covers every method, its signature, the data models that cross the JNI boundary, and the behavioral changes introduced during the multi-module refactor. - -**Key architectural fact:** `AniyomiBridge` is a **singleton-like stateful object**. It maintains internal maps of loaded anime/manga sources keyed by `packageName`. You create one instance and call methods on it. All source lookup is done internally via these maps. - ---- - -## Table of Contents - -1. [Initialization](#1-initialization) -2. [Extension Lifecycle (Anime)](#2-extension-lifecycle-anime) -3. [Extension Lifecycle (Manga)](#3-extension-lifecycle-manga) -4. [Querying Loaded Extensions](#4-querying-loaded-extensions) -5. [Preferences API](#5-preferences-api) -6. [Content Fetching (Anime)](#6-content-fetching-anime) -7. [Content Fetching (Manga)](#7-content-fetching-manga) -8. [Data Models](#8-data-models) -9. [Error Handling](#9-error-handling) -10. [Breaking Changes from v1](#10-breaking-changes-from-v1) -11. [JNI Implementation Notes](#11-jni-implementation-notes) - ---- - -## 1. Initialization - -### `static void init()` - -Must be called **once** before any other operation. Performs global JVM-level setup: - -- Installs ByteBuddy agent for runtime bytecode patching -- Initializes Injekt dependency injection module - -**JNI signature:** -``` -(env)->CallStaticVoidMethod(aniyomiBridgeClass, initMethod); -``` - -**Thread safety:** Safe to call from any thread, but should only be called once. Not synchronized externally — caller must ensure single invocation. - -**Throws:** Nothing directly, but ByteBuddy installation can fail if the JVM doesn't support instrumentation. - ---- - -## 2. Extension Lifecycle (Anime) - -### `void loadAnimeExtension(String extensionUrl, String basePath, String packageName)` - -Downloads an APK from `extensionUrl`, converts it to JAR via dex2jar, loads the main extension class, and registers it as an `AnimeHttpSource`. - -| Parameter | Description | -|-----------|-------------| -| `extensionUrl` | Full HTTPS URL to the `.apk` file | -| `basePath` | Local directory path where the converted `.jar` will be cached | -| `packageName` | The Android package name (e.g., `eu.kanade.tachiyomi.animeextension.en.animepahe`). Used as the **internal key** for all subsequent lookups. | - -**Behavior:** -- Downloads APK if not already present -- Converts APK → JAR using dex2jar -- Inspects JAR to find the main extension class -- Loads class via isolated `URLClassLoader` -- Applies ByteBuddy patches to the extension's JVM classes -- If the source implements `ConfigurableAnimeSource`, automatically calls `setupPreferenceScreen()` with a managed `PreferenceScreen` -- Stores the source in an internal `ConcurrentHashMap` keyed by `packageName` - -**Throws:** `UnyoCoreException` on any failure (download, dex2jar, class loading, casting). - ---- - -### `void unloadAnimeExtension(String packageName)` - -Unloads an anime extension and cleans up resources. - -| Parameter | Description | -|-----------|-------------| -| `packageName` | The same `packageName` passed to `loadAnimeExtension` | - -**Behavior:** -- Closes the extension's `URLClassLoader` -- Deletes the cached JAR file from disk -- Removes the source from internal maps - -**Throws:** `UnyoCoreException` on cleanup failure. - ---- - -## 3. Extension Lifecycle (Manga) - -### `void loadMangaExtension(String extensionUrl, String basePath, String packageName)` - -Identical to `loadAnimeExtension` but for manga sources implementing `CatalogueSource`. - -| Parameter | Description | -|-----------|-------------| -| `extensionUrl` | Full HTTPS URL to the `.apk` file | -| `basePath` | Local directory path where the converted `.jar` will be cached | -| `packageName` | Android package name, used as internal key | - -**Behavior:** Same as anime version, but casts to `CatalogueSource` and calls `ConfigurableSource.setupPreferenceScreen()` if applicable. - -**Throws:** `UnyoCoreException` - ---- - -### `void unloadMangaExtension(String packageName)` - -Unloads a manga extension. - -| Parameter | Description | -|-----------|-------------| -| `packageName` | The same `packageName` passed to `loadMangaExtension` | - -**Throws:** `UnyoCoreException` - ---- - -## 4. Querying Loaded Extensions - -### `List getAnimeLoadedExtensions()` - -Returns a list of loaded anime extension package names. - -**Return:** `java.util.List` — package names of all currently loaded anime sources. - ---- - -### `List getMangaLoadedExtensions()` - -Returns a list of loaded manga extension package names. - -**Return:** `java.util.List` — package names of all currently loaded manga sources. - ---- - -## 5. Preferences API - -> **New in v2.** Previously, preferences were not exposed to Flutter. Now they are fully readable and writable. - -When a `ConfigurableAnimeSource` or `ConfigurableSource` is loaded, `AniyomiBridge` automatically calls `setupPreferenceScreen(screen)` and creates a `PreferenceScreen` backed by file-based `SharedPreferences` (stored under `~/.aniyomibridge/shared_prefs/.xml`). - -### `List getAnimePreferences(String packageName)` - -Reads all preferences registered by an anime extension. - -| Parameter | Description | -|-----------|-------------| -| `packageName` | Package name of the loaded anime extension | - -**Return:** `java.util.List` - -**Behavior:** -- Returns empty list if source is not configurable -- Iterates all `Preference` objects on the source's `PreferenceScreen` -- Reads current value from `SharedPreferences` (or default if never set) -- Returns typed values based on preference type - -**Supported preference types:** - -| Type | Java Type | Value Type | -|------|-----------|------------| -| `SwitchPreferenceCompat` | `Boolean` | `true` / `false` | -| `ListPreference` | `String` | Selected entry value | -| `EditTextPreference` | `String` | User input text | -| `MultiSelectListPreference` | `Set` | Selected values | -| `Preference` (fallback) | `null` | No value | - ---- - -### `void setAnimePreference(String packageName, String key, Object value)` - -Sets a single preference value for an anime extension. - -| Parameter | Description | -|-----------|-------------| -| `packageName` | Package name of the loaded anime extension | -| `key` | Preference key (from `getAnimePreferences`) | -| `value` | Value to set. Must match the expected type: `Boolean`, `String`, or `Set` | - -**Throws:** `UnyoCoreException` if source not configurable, key not found, or type mismatch. - ---- - -### `void setAnimePreferences(String packageName, Map values)` - -Batch-updates multiple preferences for an anime extension. - -| Parameter | Description | -|-----------|-------------| -| `packageName` | Package name of the loaded anime extension | -| `values` | `java.util.Map` of `key → value` pairs | - -**Behavior:** Iterates the map and calls `setAnimePreference` logic for each entry. Fails fast on first error. - -**Throws:** `UnyoCoreException` - -> **Note:** Manga preferences API is **not yet exposed** in `AniyomiBridge.java`. If needed, the same pattern applies using `CatalogueSource` / `ConfigurableSource`. - ---- - -## 6. Content Fetching (Anime) - -All content-fetching methods are **synchronous blocking calls** that internally run Kotlin coroutines via `runBlocking`. Call them from background threads in Flutter. - -### `List getAnimeSearchResults(String query, int page, String packageName)` - -Searches for anime using the specified extension. - -| Parameter | Description | -|-----------|-------------| -| `query` | Search query string | -| `page` | Page number (1-based) | -| `packageName` | Package name of the loaded anime extension | - -**Return:** `java.util.List` - -**Throws:** `UnyoCoreException` wrapping any network or parsing error. - ---- - -### `List getEpisodeList(SAnime anime, String packageName)` - -Fetches the episode list for a given anime. - -| Parameter | Description | -|-----------|-------------| -| `anime` | `SAnime` object (from search results or previous call) | -| `packageName` | Package name of the loaded anime extension | - -**Return:** `java.util.List` - -**Throws:** `UnyoCoreException` - ---- - -### `List