diff --git a/assets/aniyomibridge-core.jar b/assets/aniyomibridge-core.jar index 495a773..e5dbeb6 100644 Binary files a/assets/aniyomibridge-core.jar and b/assets/aniyomibridge-core.jar differ diff --git a/example/lib/main.dart b/example/lib/main.dart index 53bc302..bdcf27e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -7,8 +7,8 @@ void main() async { AniyomiBridge bridge = AniyomiBridge(); await Future.delayed(Duration(seconds: 2)); - bridge.loadAnimeExtension("https://kohiden.xyz/Kohi-den/extensions/raw/branch/main/apk/aniyomi-all.animeonsen-v14.7.apk"); - List animes = bridge.getAnimeSearchResults("Shingeki", 1, "animeonsen"); + bridge.loadAnimeExtension("https://gitea.k3vinb5.dev/Backups/kohi-den-extensions/raw/branch/main/apk/aniyomi-en.zoro-v14.60.apk"); + List animes = bridge.getAnimeSearchResults("Shingeki", 1, "hianime"); print(animes); animes.forEach((anime) => print(anime.getTitle().toDartString())); diff --git a/lib/aniyomi_bridge.dart b/lib/aniyomi_bridge.dart index 7b30be8..6d9055d 100644 --- a/lib/aniyomi_bridge.dart +++ b/lib/aniyomi_bridge.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter/services.dart'; import 'package:jni/jni.dart'; +import 'package:k3vinb5_aniyomi_bridge/models/extension.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as path; import 'package:k3vinb5_aniyomi_bridge/jmodels/jvideo.dart'; @@ -12,14 +13,15 @@ import 'package:k3vinb5_aniyomi_bridge/jmodels/jschapter.dart'; import 'package:k3vinb5_aniyomi_bridge/jmodels/jpage.dart'; class AniyomiBridge { - static const String _aniyomiBridgeDir = "aniyomibridge"; static const String _aniyomiBridgeAnimeExtensionsDir = "animeExtensions"; static const String _aniyomiBridgeMangaExtensionsDir = "mangaExtensions"; - static const String _aniyomiBridgeJarName ="aniyomibridge-core.jar"; - static const String _packageAssetsDir = "packages/k3vinb5_aniyomi_bridge/assets"; + static const String _aniyomiBridgeJarName = "aniyomibridge-core.jar"; + static const String _packageAssetsDir = + "packages/k3vinb5_aniyomi_bridge/assets"; static late final JAniyomiBridge _jAniyomiBridge; static late final String _supportDirectoryPath; + bool _isReady = false; AniyomiBridge() { _initJvm(); @@ -35,104 +37,258 @@ class AniyomiBridge { ); JAniyomiBridge.init(); _jAniyomiBridge = JAniyomiBridge(); + _isReady = true; + } + + bool isReady() { + return _isReady; } List getAnimeSearchResults(String query, int page, String source) { - JList? searchResults = _jAniyomiBridge.getAnimeSearchResults(JString.fromString(query), page, JString.fromString(source)); + JList? searchResults = _jAniyomiBridge.getAnimeSearchResults( + JString.fromString(query), + page, + JString.fromString(source), + ); if (searchResults == null) { return []; } - return searchResults.cast().where(_jObjIsNotNull).map((jObj) => jObj!.as(JSAnime.type)).toList(); + return searchResults + .cast() + .where(_jObjIsNotNull) + .map((jObj) => jObj!.as(JSAnime.type)) + .toList(); } List getMangaSearchResults(String query, int page, String source) { - JList? searchResults = _jAniyomiBridge.getMangaSearchResults(JString.fromString(query), page, JString.fromString(source)); + JList? searchResults = _jAniyomiBridge.getMangaSearchResults( + JString.fromString(query), + page, + JString.fromString(source), + ); if (searchResults == null) { return []; } - return searchResults.cast().where(_jObjIsNotNull).map((jObj) => jObj!.as(JSManga.type)).toList(); + return searchResults + .cast() + .where(_jObjIsNotNull) + .map((jObj) => jObj!.as(JSManga.type)) + .toList(); } List getEpisodeList(JSAnime sAnime, String source) { - JList? episodeList = _jAniyomiBridge.getEpisodeList(sAnime, JString.fromString(source)); + JList? episodeList = _jAniyomiBridge.getEpisodeList( + sAnime, + JString.fromString(source), + ); if (episodeList == null) { return []; } - return episodeList.cast().where(_jObjIsNotNull).map((jObj) => jObj!.as(JSEpisode.type)).toList(); + return episodeList + .cast() + .where(_jObjIsNotNull) + .map((jObj) => jObj!.as(JSEpisode.type)) + .toList(); } List getChapterList(JSManga sManga, String source) { - JList? episodeList = _jAniyomiBridge.getEpisodeList(sManga, JString.fromString(source)); + JList? episodeList = _jAniyomiBridge.getEpisodeList( + sManga, + JString.fromString(source), + ); if (episodeList == null) { return []; } - return episodeList.cast().where(_jObjIsNotNull).map((jObj) => jObj!.as(JSChapter.type)).toList(); + return episodeList + .cast() + .where(_jObjIsNotNull) + .map((jObj) => jObj!.as(JSChapter.type)) + .toList(); } List getVideoList(JSEpisode sEpisode, String source) { - JList? videoList = _jAniyomiBridge.getVideoList(sEpisode, JString.fromString(source)); + JList? videoList = _jAniyomiBridge.getVideoList( + sEpisode, + JString.fromString(source), + ); if (videoList == null) { return []; } - return videoList.cast().where(_jObjIsNotNull).map((jObj) => jObj!.as(JVideo.type)).toList(); + return videoList + .cast() + .where(_jObjIsNotNull) + .map((jObj) => jObj!.as(JVideo.type)) + .toList(); } List getPageList(JSChapter sChapter, String source) { - JList? videoList = _jAniyomiBridge.getVideoList(sChapter, JString.fromString(source)); + JList? videoList = _jAniyomiBridge.getVideoList( + sChapter, + JString.fromString(source), + ); if (videoList == null) { return []; } - return videoList.cast().where(_jObjIsNotNull).map((jObj) => jObj!.as(JPage.type)).toList(); + return videoList + .cast() + .where(_jObjIsNotNull) + .map((jObj) => jObj!.as(JPage.type)) + .toList(); } - void loadAnimeExtension(String extensionUrl) { - _jAniyomiBridge.loadAnimeExtension(JString.fromString(extensionUrl), JString.fromString(path.join(_supportDirectoryPath, _aniyomiBridgeAnimeExtensionsDir))); - } + void loadAnimeExtension(String extensionUrl) { + _jAniyomiBridge.loadAnimeExtension( + JString.fromString(extensionUrl), + JString.fromString( + path.join(_supportDirectoryPath, _aniyomiBridgeAnimeExtensionsDir), + ), + ); + } - void loadMangaExtension(String extensionUrl) { - _jAniyomiBridge.loadMangaExtension(JString.fromString(extensionUrl), JString.fromString(path.join(_supportDirectoryPath, _aniyomiBridgeMangaExtensionsDir))); - } + void unloadAnimeExtension(String extensionName, String extensionVersion) { + _jAniyomiBridge.unloadAnimeExtension( + JString.fromString(extensionName), + JString.fromString(extensionVersion), + JString.fromString( + path.join(_supportDirectoryPath, _aniyomiBridgeAnimeExtensionsDir), + ) + ); + } - List? getLoadedAnimeExtensions() { - JList? loadedExtensions = _jAniyomiBridge.getAnimeLoadedExtensions(); - if (loadedExtensions == null) { - return null; - } - return loadedExtensions.cast().map((jStr) => jStr.toDartString()).toList(); - } + void loadMangaExtension(String extensionUrl) { + _jAniyomiBridge.loadMangaExtension( + JString.fromString(extensionUrl), + JString.fromString( + path.join(_supportDirectoryPath, _aniyomiBridgeMangaExtensionsDir), + ), + ); + } - List? getLoadedMangaExtensions() { - JList? loadedExtensions = _jAniyomiBridge.getMangaLoadedExtensions(); + void unloadMangaExtension(String extensionName, String extensionVersion) { + _jAniyomiBridge.unloadMangaExtension( + JString.fromString(extensionName), + JString.fromString(extensionVersion), + JString.fromString( + path.join(_supportDirectoryPath, _aniyomiBridgeMangaExtensionsDir), + ) + ); + } + + Future> getInstalledAnimeExtensions() async{ + Directory animeExtDir = Directory( + path.join(_supportDirectoryPath, _aniyomiBridgeAnimeExtensionsDir), + ); + Set extensions = await animeExtDir + .list() + .where((entityFileSystem) => entityFileSystem is File) + .where((file) => path.extension(file.path) == ".jar") + .map((jarFile) => path.basename(jarFile.path)) + .map( + (jarFileName) => Extension( + name: jarFileName.split("-")[0], + version: jarFileName.split("-")[1], + ), + ) + .toSet(); + return extensions; + } + + Future> getInstalledMangaExtensions() async{ + Directory mangaExtDir = Directory( + path.join(_supportDirectoryPath, _aniyomiBridgeMangaExtensionsDir), + ); + Set extensions = await mangaExtDir + .list() + .where((entityFileSystem) => entityFileSystem is File) + .where((file) => path.extension(file.path) == ".jar") + .map((jarFile) => path.basename(jarFile.path)) + .map( + (jarFileName) => Extension( + name: jarFileName.split("-")[0], + version: jarFileName.split("-")[1], + ), + ) + .toSet(); + return extensions; + } + + List? getLoadedAnimeExtensions() { + JList? loadedExtensions = _jAniyomiBridge + .getAnimeLoadedExtensions(); if (loadedExtensions == null) { return null; } - return loadedExtensions.cast().map((jStr) => jStr.toDartString()).toList(); + return loadedExtensions + .cast() + .map((jStr) => jStr.toDartString()) + .toList(); } - bool Function(JObject? jObj) get _jObjIsNotNull => (jObj) => jObj != null; + List? getLoadedMangaExtensions() { + JList? loadedExtensions = _jAniyomiBridge + .getMangaLoadedExtensions(); + if (loadedExtensions == null) { + return null; + } + return loadedExtensions + .cast() + .map((jStr) => jStr.toDartString()) + .toList(); + } + + bool Function(JObject? jObj) get _jObjIsNotNull => + (jObj) => jObj != null; String _getDylibDir(Directory supportDirectory) { String executablePath = File(Platform.resolvedExecutable).parent.path; if (Platform.isLinux) { - return path.join(executablePath, "jre", "customjre", "lib", "server"); + return path.join(executablePath, "jre", "customjre", "lib", "server"); } else if (Platform.isMacOS) { - return path.join(executablePath, "..", "Resources", "jre", "customjre", "lib", "server"); + return path.join( + executablePath, + "..", + "Resources", + "jre", + "customjre", + "lib", + "server", + ); } else if (Platform.isWindows) { - return path.join(executablePath, "..", "jre", "customjre", "lib", "server"); + return path.join( + executablePath, + "..", + "jre", + "customjre", + "lib", + "server", + ); } else { throw UnsupportedError("Unsupported platform"); } } List _getClassPath(Directory supportDirectory) { - return [path.join(supportDirectory.absolute.path, _aniyomiBridgeDir, _aniyomiBridgeJarName)]; + return [ + path.join( + supportDirectory.absolute.path, + _aniyomiBridgeDir, + _aniyomiBridgeJarName, + ), + ]; } Future _loadJarIfNeeded(Directory supportDirectory) async { - String aniyomiBridgeCorePath = path.join(supportDirectory.path, _aniyomiBridgeDir, _aniyomiBridgeJarName); + String aniyomiBridgeCorePath = path.join( + supportDirectory.path, + _aniyomiBridgeDir, + _aniyomiBridgeJarName, + ); File aniyomiBridgeCore = File(aniyomiBridgeCorePath); if (!(await aniyomiBridgeCore.exists())) { - _copyAssetToFile("$_packageAssetsDir/$_aniyomiBridgeJarName", aniyomiBridgeCorePath); + await _copyAssetToFile( + "$_packageAssetsDir/$_aniyomiBridgeJarName", + aniyomiBridgeCorePath, + ); } } @@ -144,4 +300,4 @@ class AniyomiBridge { await file.writeAsBytes(buffer, flush: true); return file; } -} \ No newline at end of file +} diff --git a/lib/jmodels/janiyomibridge.dart b/lib/jmodels/janiyomibridge.dart index 4a8df7b..75a835c 100644 --- a/lib/jmodels/janiyomibridge.dart +++ b/lib/jmodels/janiyomibridge.dart @@ -151,6 +151,55 @@ class JAniyomiBridge extends jni$_.JObject { ).check(); } + static final _id_unloadAnimeExtension = _class.instanceMethodId( + r'unloadAnimeExtension', + r'(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V', + ); + + static final _unloadAnimeExtension = + jni$_.ProtectedJniExtensions.lookup< + jni$_.NativeFunction< + jni$_.JThrowablePtr Function( + jni$_.Pointer, + jni$_.JMethodIDPtr, + jni$_.VarArgs< + ( + jni$_.Pointer, + jni$_.Pointer, + jni$_.Pointer, + ) + >, + ) + > + >('globalEnv_CallVoidMethod') + .asFunction< + jni$_.JThrowablePtr Function( + jni$_.Pointer, + jni$_.JMethodIDPtr, + jni$_.Pointer, + jni$_.Pointer, + jni$_.Pointer, + ) + >(); + + /// from: `public void unloadAnimeExtension(java.lang.String string, java.lang.String string1, java.lang.String string2)` + void unloadAnimeExtension( + jni$_.JString? string, + jni$_.JString? string1, + jni$_.JString? string2, + ) { + final _$string = string?.reference ?? jni$_.jNullReference; + final _$string1 = string1?.reference ?? jni$_.jNullReference; + final _$string2 = string2?.reference ?? jni$_.jNullReference; + _unloadAnimeExtension( + reference.pointer, + _id_unloadAnimeExtension as jni$_.JMethodIDPtr, + _$string.pointer, + _$string1.pointer, + _$string2.pointer, + ).check(); + } + static final _id_loadMangaExtension = _class.instanceMethodId( r'loadMangaExtension', r'(Ljava/lang/String;Ljava/lang/String;)V', @@ -189,6 +238,55 @@ class JAniyomiBridge extends jni$_.JObject { ).check(); } + static final _id_unloadMangaExtension = _class.instanceMethodId( + r'unloadMangaExtension', + r'(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V', + ); + + static final _unloadMangaExtension = + jni$_.ProtectedJniExtensions.lookup< + jni$_.NativeFunction< + jni$_.JThrowablePtr Function( + jni$_.Pointer, + jni$_.JMethodIDPtr, + jni$_.VarArgs< + ( + jni$_.Pointer, + jni$_.Pointer, + jni$_.Pointer, + ) + >, + ) + > + >('globalEnv_CallVoidMethod') + .asFunction< + jni$_.JThrowablePtr Function( + jni$_.Pointer, + jni$_.JMethodIDPtr, + jni$_.Pointer, + jni$_.Pointer, + jni$_.Pointer, + ) + >(); + + /// from: `public void unloadMangaExtension(java.lang.String string, java.lang.String string1, java.lang.String string2)` + void unloadMangaExtension( + jni$_.JString? string, + jni$_.JString? string1, + jni$_.JString? string2, + ) { + final _$string = string?.reference ?? jni$_.jNullReference; + final _$string1 = string1?.reference ?? jni$_.jNullReference; + final _$string2 = string2?.reference ?? jni$_.jNullReference; + _unloadMangaExtension( + reference.pointer, + _id_unloadMangaExtension as jni$_.JMethodIDPtr, + _$string.pointer, + _$string1.pointer, + _$string2.pointer, + ).check(); + } + static final _id_getAnimeLoadedExtensions = _class.instanceMethodId( r'getAnimeLoadedExtensions', r'()Ljava/util/List;', diff --git a/lib/models/extension.dart b/lib/models/extension.dart new file mode 100644 index 0000000..0d14eee --- /dev/null +++ b/lib/models/extension.dart @@ -0,0 +1,6 @@ +class Extension { + final String name; + final String version; + + Extension({required this.name, required this.version}); +} \ No newline at end of file