Aniyomi Documentation

repository·main·Indexed 27 days ago

https://github.com/aniyomiorg/aniyomi

An Android-based media player and reader for anime, cartoons, and series, built on the Mihon (formerly Tachiyomi) architecture. Features include mpv-android playback, tracker integration with services like MyAnimeList and AniList, library management, and support for Android 8.0 or higher.

Tokens
1.7K
Snippets
3
Records
6
Agent score
93%

What's inside Aniyomi

  1. Overview of Aniyomi features

    main

    Aniyomi is a full-featured player and reader for anime, cartoons, and series on Android. Key capabilities include:

    • Media Playback & Reading: Local content support, configurable reader (multiple viewers, reading directions), and a configurable player built on mpv-android.
    • Tracker Integration: Supports MyAnimeList, AniList, Kitsu, MangaUpdates, Shikimori, Simkl, and Bangumi.
    • Library Management: Categories for organization, scheduled updates for new chapters/episodes, and local or cloud-based backups.
    • Customization: Light and dark themes.
  2. Generate baseline profiles for the app

    main

    Baseline profiles enable Ahead-of-Time (AOT) compilation for critical user paths during app launch. If you modify code that affects app startup, you must re-generate the baseline profile.

    To generate a new profile:

    1. Select the devBenchmark build variant in your IDE.
    2. Run the BaselineProfileGenerator benchmark test on an AOSP Android Emulator.
    3. Copy the resulting baseline profile from the emulator to app/src/main/baseline-prof.txt in the project root.
  3. Override getPackageName() for WebView spoofing

    main

    The App class overrides getPackageName() to prevent detection by websites via the X-Requested-With header in WebView requests. If the call stack indicates a Chromium-based request, it returns a spoofed package name provided by WebViewUtil.spoofedPackageName(applicationContext). Otherwise, it returns the standard package name.

    override fun getPackageName(): String {
        try {
            val stackTrace = Looper.getMainLooper().thread.stackTrace
            val isChromiumCall = stackTrace.any { trace ->
                trace.className.equals("org.chromium.base.BuildInfo", ignoreCase = true) &&
                    setOf("getAll", "getPackageName", "<init>").any { trace.methodName.equals(it) }
            }
    
            if (isChromiumCall) return WebViewUtil.spoofedPackageName(applicationContext)
        } catch (_: Exception) {
        }
    
        return super.getPackageName()
    }
  4. Implement SingletonImageLoader.Factory in Aniyomi

    main

    The App class implements SingletonImageLoader.Factory to provide a custom ImageLoader instance for the application using the Coil library. The implementation configures several components including:

    • Network Fetcher: Uses OkHttpNetworkFetcherFactory with a client from NetworkHelper.
    • Decoders: Includes TachiyomiImageDecoder.Factory().
    • Fetchers: Includes BufferedSourceFetcher.Factory(), MangaCoverFetcher.MangaFactory, MangaCoverFetcher.MangaCoverFactory, AnimeImageFetcher.AnimeFactory, and AnimeImageFetcher.AnimeCoverFactory.
    • Keyers: Includes AnimeKeyer, MangaKeyer, AnimeCoverKeyer, and MangaCoverKeyer.

    Additional configurations:

    • Crossfade: Duration is scaled by animatorDurationScale.
    • Memory Optimization: Uses allowRgb565(true) on low-RAM devices via DeviceUtil.isLowRamDevice().
    • Concurrency: Limits parallelism for fetching (Dispatchers.IO.limitedParallelism(8)) and decoding (Dispatchers.IO.limitedParallelism(3)).
    override fun newImageLoader(context: Context): ImageLoader {
        return ImageLoader.Builder(this).apply {
            val callFactoryLazy = lazy { Injekt.get<NetworkHelper>().client }
            components {
                add(OkHttpNetworkFetcherFactory(callFactoryLazy::value))
                add(TachiyomiImageDecoder.Factory())
                add(BufferedSourceFetcher.Factory())
                add(MangaCoverFetcher.MangaFactory(callFactoryLazy))
                add(MangaCoverFetcher.MangaCoverFactory(callFactoryLazy))
                add(AnimeImageFetcher.AnimeFactory(callFactoryLazy))
                add(AnimeImageFetcher.AnimeCoverFactory(callFactoryLazy))
                add(AnimeKeyer())
                add(MangaKeyer())
                add(AnimeCoverKeyer())
                add(MangaCoverKeyer())
            }
            crossfade((300 * this@App.animatorDurationScale).toInt())
            allowRgb565(DeviceUtil.isLowRamDevice(this@App))
            if (networkPreferences.verboseLogging().get()) logger(DebugLogger())
            fetcherCoroutineContext(Dispatchers.IO.limitedParallelism(8))
            decoderCoroutineContext(Dispatchers.IO.limitedParallelism(3))
        }.build()
    }
  5. Handle Application Lifecycle with SecureActivityDelegate

    main

    The App class implements DefaultLifecycleObserver to manage security states via SecureActivityDelegate.

    • When the application starts (onStart), call SecureActivityDelegate.onApplicationStart().
    • When the application stops (onStop), call SecureActivityDelegate.onApplicationStopped().
    override fun onStart(owner: LifecycleOwner) {
        SecureActivityDelegate.onApplicationStart()
    }
    
    override fun onStop(owner: LifecycleOwner) {
        SecureActivityDelegate.onApplicationStopped()
    }