### Building GET Request with Query Parameters Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Demonstrates how to construct an HTTP GET request with query parameters using OkHttp. ```APIDOC ## Building GET Request with Query Parameters ### Description Builds an HTTP GET request with specified query parameters. ### Method GET ### Endpoint ``` https://api.example.com/search?q=manga title&page=1&limit=20 ``` ### Parameters #### Path Parameters * None #### Query Parameters * **q** (String) - Required - The search query for manga title. * **page** (String) - Required - The page number for the search results. * **limit** (String) - Required - The maximum number of results per page. ### Request Example ```kotlin val url = "https://api.example.com/search".toHttpUrl().newBuilder() .addQueryParameter("q", "manga title") .addQueryParameter("page", "1") .addQueryParameter("limit", "20") .build() val request = GET(url) val response = httpClient.newCall(request).await() ``` ``` -------------------------------- ### Full Source Implementation Example Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-other-interfaces.md A comprehensive example demonstrating the implementation of HttpSource and ConfigurableSource for a manga website. It includes methods for fetching popular manga, searching, parsing details, and handling configurations. ```kotlin import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.model.* import eu.kanade.tachiyomi.network.Requests.* import eu.kanade.tachiyomi.util.JsoupExtensions.* import okhttp3.Request import okhttp3.Response class MangaSiteSource : HttpSource(), ConfigurableSource { override val baseUrl = "https://mangasite.example.com" override val lang = "en" override val name = "MangaSite" override val supportsLatest = true // Configuration override fun setupPreferenceScreen(screen: PreferenceScreen) { screen.addPreference(EditTextPreference(screen.context).apply { key = "api_key" title = "API Key" setDefaultValue("") }) } // Popular manga override fun popularMangaRequest(page: Int): Request { return GET("$baseUrl/popular?page=$page") } override fun popularMangaParse(response: Response): MangasPage { val document = response.asJsoup() val mangas = document.select("div.manga-item").map { SManga.create().apply { url = it.select("a").attr("href") title = it.select("h3").text() thumbnail_url = it.select("img").attr("src") } } val hasNextPage = document.select("a.next").isNotEmpty() return MangasPage(mangas, hasNextPage) } // Search override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { val url = "$baseUrl/search".toHttpUrl().newBuilder() .addQueryParameter("q", query) .addQueryParameter("page", page.toString()) .build() return GET(url) } override fun searchMangaParse(response: Response): MangasPage { return popularMangaParse(response) // Same format } // Latest override fun latestUpdatesRequest(page: Int): Request { return GET("$baseUrl/latest?page=$page") } override fun latestUpdatesParse(response: Response): MangasPage { return popularMangaParse(response) } // Manga details override fun mangaDetailsParse(response: Response): SManga { val document = response.asJsoup() return SManga.create().apply { title = document.select("h1.title").text() author = document.select("div.author").text() artist = document.select("div.artist").text() description = document.select("div.description").text() status = when { document.text().contains("Ongoing") -> SManga.ONGOING document.text().contains("Completed") -> SManga.COMPLETED else -> SManga.UNKNOWN } genre = document.select("div.genres a").joinToString(", ") { it.text() } thumbnail_url = document.select("img.cover").attr("src") } } // Chapters override fun chapterListParse(response: Response): List { val document = response.asJsoup() return document.select("tr.chapter").map { SChapter.create().apply { url = it.select("a").attr("href") name = it.select("td.name a").text() chapter_number = it.select("td.number").text().toFloatOrNull() ?: 0f date_upload = parseDate(it.select("td.date").text()) } } } // Pages override fun pageListParse(response: Response): List { val document = response.asJsoup() return document.select("img.page").mapIndexed { idx, img -> Page(idx, url = img.attr("data-src")) } } // Image URL override fun imageUrlParse(response: Response): String { return response.asJsoup().select("img#main-image").attr("src") } // Filters override fun getFilterList() = FilterList( Filter.Header("Filters"), GenreFilter(), StatusFilter() ) private fun parseDate(dateStr: String): Long { // Parse date string to unix timestamp return System.currentTimeMillis() } private class GenreFilter : Filter.CheckBox("Action") private class StatusFilter : Filter.Select( "Status", arrayOf("Any", "Ongoing", "Completed") ) } ``` -------------------------------- ### Build GET Request with Query Parameters Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Constructs an HTTP GET request with specified query parameters. Ensure you have an HTTP client instance and use await() to asynchronously execute the call. ```kotlin val url = "https://api.example.com/search".toHttpUrl().newBuilder() .addQueryParameter("q", "manga title") .addQueryParameter("page", "1") .addQueryParameter("limit", "20") .build() val request = GET(url) val response = httpClient.newCall(request).await() ``` -------------------------------- ### Example Usage of GenresGroup Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/filter-guide.md Example of a concrete GenresGroup implementation and how to access its state within a search request. Initially, no genres are selected. ```kotlin private class GenresGroup : Filter.Group( "Genres", listOf( "Action", "Adventure", "Comedy", "Drama", "Fantasy", "Horror", "Romance", "Sci-Fi" ), state = emptyList() // None selected initially ) // In searchMangaRequest: val genresGroup = filters.filterIsInstance().firstOrNull() val selectedGenres = genresGroup?.state ?: emptyList() ``` -------------------------------- ### OkHttp GET Request Builder Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/MANIFEST.md Demonstrates how to construct a GET request using OkHttp, both with a URL string and an HttpUrl object. These are fundamental for making network requests. ```kotlin val request1 = GET("https://example.com/api/data") val request2 = GET(HttpUrl.get("https://example.com/api/data")) ``` -------------------------------- ### Build GET Request with Query Parameters Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/README.md Construct an HTTP GET request with query parameters for searching manga or fetching paginated data. Use toHttpUrl().newBuilder() to add parameters like 'q' and 'page'. ```kotlin val url = "$baseUrl/search".toHttpUrl().newBuilder() .addQueryParameter("q", query) .addQueryParameter("page", page.toString()) .build() GET(url) ``` -------------------------------- ### Build GET Request Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md Constructs a GET request to a specified URL. Supports adding custom headers. ```kotlin GET("$baseUrl/manga/123") ``` ```kotlin GET("$baseUrl/search?q=title", headers = headersBuilder().add("Custom", "Header").build()) ``` -------------------------------- ### Populate SChapter Object Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md Example of how to create and populate an `SChapter` object. Required fields include `url`, `name`, `chapter_number`, and `date_upload`. `scanlator` is optional. ```kotlin SChapter.create().apply { url = "" // Required name = "" // Required chapter_number = 1f // Required date_upload = System.currentTimeMillis() // Required scanlator = null // Optional } ``` -------------------------------- ### MangaSiteSource Implementation Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-other-interfaces.md An example implementation of an HttpSource and ConfigurableSource for a manga website. ```APIDOC ## MangaSiteSource ### Description This class implements `HttpSource` and `ConfigurableSource` to fetch manga data from a specific website. ### Configuration Provides a preference screen for API key configuration. ### Methods - **popularMangaRequest**: Fetches popular manga for a given page. - **popularMangaParse**: Parses the response to extract popular manga details. - **searchMangaRequest**: Constructs a request for searching manga. - **searchMangaParse**: Parses the search results. - **latestUpdatesRequest**: Fetches the latest manga updates. - **latestUpdatesParse**: Parses the latest updates response. - **mangaDetailsParse**: Parses the details of a specific manga. - **chapterListParse**: Parses the list of chapters for a manga. - **pageListParse**: Parses the list of pages for a chapter. - **imageUrlParse**: Parses the image URL for a page. - **getFilterList**: Returns the available filters for searching. ``` -------------------------------- ### Example Usage of SortFilter Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/filter-guide.md Example of a concrete SortFilter implementation and how to access and interpret its state within a search request. It demonstrates sorting by 'Latest' in descending order. ```kotlin private class SortFilter : Filter.Sort( "Sort", arrayOf("Latest", "Popular", "Rating", "Views"), state = Sort.Selection(0, false) // Sort by Latest, descending ) // In searchMangaRequest: val sortFilter = filters.filterIsInstance().firstOrNull() val sortSelection = sortFilter?.state if (sortSelection != null) { val fieldName = sortFilter.values[sortSelection.index] val direction = if (sortSelection.ascending) "asc" else "desc" println("Sort by $fieldName $direction") } ``` -------------------------------- ### Populate Model Objects Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md Provides examples for creating and populating SManga, SChapter, and Page model objects. ```APIDOC ### Populate Model Objects ```kotlin SManga.create().apply { url = "" // Required title = "" // Required artist = null // Optional author = null // Optional description = null // Optional genre = null // Optional status = SManga.ONGOING // Required thumbnail_url = null // Optional update_strategy = UpdateStrategy.ALWAYS_UPDATE // Required initialized = false // Required } SChapter.create().apply { url = "" // Required name = "" // Required chapter_number = 1f // Required date_upload = System.currentTimeMillis() // Required scanlator = null // Optional } Page( index = 0, // Required url = "", // Initial URL (may redirect) imageUrl = null, // Resolved image URL (filled by getImageUrl) uri = null // Android URI (optional) ) ``` ``` -------------------------------- ### Build GET HTTP Requests Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/module-architecture.md Constructs GET requests with optional headers and cache control. Supports both String and HttpUrl for the URL. ```kotlin fun GET(url: String, headers: Headers = DEFAULT_HEADERS, cache: CacheControl = DEFAULT_CACHE_CONTROL): Request fun GET(url: HttpUrl, headers: Headers = DEFAULT_HEADERS, cache: CacheControl = DEFAULT_CACHE_CONTROL): Request ``` -------------------------------- ### Create Page Object Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md Example of how to create a `Page` object. Required fields are `index` and `url`. `imageUrl` is filled by `getImageUrl`, and `uri` is an optional Android URI. ```kotlin Page( index = 0, // Required url = "", // Initial URL (may redirect) imageUrl = null, // Resolved image URL (filled by getImageUrl) uri = null // Android URI (optional) ) ``` -------------------------------- ### Setup Preference Screen for Source Configuration Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-other-interfaces.md Implement this method to allow sources to add custom preferences to the application's preference screen. This is useful for providing configuration options specific to a source. ```kotlin import eu.kanade.tachiyomi.source.ConfigurableSource import android.preference.PreferenceScreen import androidx.preference.EditTextPreference import androidx.preference.ListPreference class MySource : HttpSource(), ConfigurableSource { override fun setupPreferenceScreen(screen: PreferenceScreen) { screen.addPreference(EditTextPreference(screen.context).apply { key = "api_key" title = "API Key" summary = "Enter your API key" }) screen.addPreference(ListPreference(screen.context).apply { key = "quality" title = "Image Quality" entries = arrayOf("Low", "Medium", "High") entryValues = arrayOf("low", "medium", "high") setDefaultValue("medium") }) } } ``` -------------------------------- ### GET (String URL) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Creates a GET request using a string URL. Allows customization of headers and cache control. ```APIDOC ## GET (String URL) ### Description Create a GET request with a string URL. ### Method GET ### Endpoint Not applicable (function signature) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```kotlin val request = GET("https://example.com/manga") val request2 = GET( "https://example.com/search?q=title", headers = headersBuilder().add("Accept-Language", "en").build() ) ``` ### Response #### Success Response (200) Not applicable (function returns Request object) #### Response Example Not applicable ``` -------------------------------- ### GET Request with HttpUrl Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Creates a GET request using an HttpUrl object. Allows for building URLs with query parameters. ```kotlin import eu.kanade.tachiyomi.network.Requests.* val httpUrl = "https://example.com/manga".toHttpUrl() .newBuilder() .addQueryParameter("page", "1") .build() val request = GET(httpUrl) ``` -------------------------------- ### GET Request with String URL Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Constructs a GET request using a string URL. Supports custom headers and cache control. ```kotlin import eu.kanade.tachiyomi.network.Requests.* val request = GET("https://example.com/manga") val request2 = GET( "https://example.com/search?q=title", headers = headersBuilder().add("Accept-Language", "en").build() ) ``` -------------------------------- ### Minimal HttpSource Implementation Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/MANIFEST.md A basic implementation of the HttpSource interface, demonstrating the core methods required for a functional extension. This serves as a starting point for creating new sources. ```kotlin class MySource : HttpSource() { override val id: Long = 1L override fun name: String = "My Source" override fun baseUrl: String = "https://example.com" override fun popularMangaRequest(page: Int): Request { return GET("$baseUrl/popular?page=$page") } override fun popularMangaParse(response: Response): MangasPage { val document = response.parseAs() val mangas = document.select("selector-for-manga").map { SManga.create().apply { title = it.select("selector-for-title").text() url = it.select("selector-for-url").attr("href") thumbnailUrl = it.select("selector-for-thumbnail").attr("src") } } val hasNextPage = document.select("selector-for-next-page").isNotEmpty() return MangasPage(mangas, hasNextPage) } override fun mangaDetailsRequest(manga: SManga): Request { return GET(baseUrl + manga.url) } override fun mangaDetailsParse(response: Response): SManga { val document = response.parseAs() return SManga.create().apply { description = document.select("selector-for-description").text() author = document.select("selector-for-author").text() artist = document.select("selector-for-artist").text() thumbnailUrl = document.select("selector-for-thumbnail").attr("src") genre = document.select("selector-for-genre").text() status = parseStatus(document.select("selector-for-status").text()) } } override fun chapterListRequest(manga: SManga): Request { return GET(baseUrl + manga.url.replaceAfterLast("/", "chapterlist")) } override fun chapterListParse(response: Response): List { val document = response.parseAs() return document.select("selector-for-chapter").map { SChapter.create().apply { name = it.select("selector-for-chapter-name").text() url = it.select("selector-for-chapter-url").attr("href") date_upload = it.select("selector-for-chapter-date").text().toLongOrNull() ?: 0L } } } override fun pageListRequest(chapter: SChapter): Request { return GET(baseUrl + chapter.url) } override fun pageListParse(response: Response): List { val document = response.parseAs() return document.select("selector-for-page").map { Page(imageUrl = it.attr("src")) } } private fun parseStatus(status: String): Int = when { status.contains("Ongoing", ignoreCase = true) -> 0 status.contains("Completed", ignoreCase = true) -> 1 else -> 2 } override fun imageUrl(page: Page): Request { return GET(page.imageUrl!!) } } ``` -------------------------------- ### Get Chapter URL Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Retrieves the full URL for a chapter. Available since extensions-lib 1.4. ```kotlin open fun getChapterUrl(chapter: SChapter): String ``` -------------------------------- ### OkHttp URL Parameters Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/MANIFEST.md Shows how to add URL parameters to a GET request. This is essential for filtering or specifying data in API calls. ```kotlin val url = HttpUrl.get("https://example.com/api/search")!!.newBuilder() .addQueryParameter("query", "manga title") .addQueryParameter("page", "1") .build() val request = GET(url) ``` -------------------------------- ### Populate SManga Object Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md Example of how to create and populate an `SManga` object. Required fields include `url`, `title`, `status`, `update_strategy`, and `initialized`. Optional fields like `artist`, `author`, `description`, `genre`, and `thumbnail_url` can be set to null. ```kotlin SManga.create().apply { url = "" // Required title = "" // Required artist = null // Optional author = null // Optional description = null // Optional genre = null // Optional status = SManga.ONGOING // Required thumbnail_url = null // Optional update_strategy = UpdateStrategy.ALWAYS_UPDATE // Required initialized = false // Required } ``` -------------------------------- ### GET (HttpUrl) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Creates a GET request using an HttpUrl object. This function is available since extensions-lib 1.4 and allows for detailed URL construction. ```APIDOC ## GET (HttpUrl) ### Description Create a GET request with an HttpUrl. ### Method GET ### Endpoint Not applicable (function signature) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```kotlin val httpUrl = "https://example.com/manga".toHttpUrl() .newBuilder() .addQueryParameter("page", "1") .build() val request = GET(httpUrl) ``` ### Response #### Success Response (200) Not applicable (function returns Request object) #### Response Example Not applicable ``` -------------------------------- ### Get Manga URL Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Retrieves the full URL for a manga. Available since extensions-lib 1.4. ```kotlin open fun getMangaUrl(manga: SManga): String ``` ```kotlin val fullUrl = source.getMangaUrl(manga) ``` -------------------------------- ### Get Filter List Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Retrieves the list of available filters for this source. ```kotlin override fun getFilterList(): FilterList ``` -------------------------------- ### Separator Filter Example Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/filter-guide.md Provides a visual separator between filter groups. It is non-interactive and can optionally have a label. ```kotlin FilterList( GenreFilter(), Filter.Separator(), StatusFilter(), ) ``` -------------------------------- ### Get Image Response for Page Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Obtains the OkHttp response containing the image data for a specific page. This method is normally not needed to override and is available since extensions-lib 1.5. ```kotlin protected open suspend fun getImage(page: Page): Response ``` -------------------------------- ### Get Page List for Chapter Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Retrieves a list of pages for a given chapter. Pages should be in reading order. This method is normally not needed to override and is available since extensions-lib 1.7. ```kotlin override suspend fun getPageList(chapter: SChapter): List ``` -------------------------------- ### Header Filter Example Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/filter-guide.md Used to display a non-interactive header text within the filter list. Typically used to group other filters. ```kotlin override fun getFilterList() = FilterList( Filter.Header("Search Options"), // ... other filters ) ``` -------------------------------- ### Use Filters in Manga Search Request Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md Construct a search request URL by adding query parameters based on selected filters. This example shows how to add 'genre' if it's not set to 'All'. ```kotlin override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { val url = "$baseUrl/search".toHttpUrl().newBuilder() .addQueryParameter("q", query) filters.filterIsInstance().firstOrNull()?.let { val selected = it.values[it.state] if (selected != "All") url.addQueryParameter("genre", selected) } return GET(url.build()) } ``` -------------------------------- ### Implement getFilterList Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/filter-guide.md An example implementation of the getFilterList method, which returns a FilterList containing various filter components like Headers, custom filters, and Separators. ```kotlin override fun getFilterList() = FilterList( Filter.Header("Advanced Search"), GenreFilter(), CompletedFilter(), LanguageFilter(), Filter.Separator(), StatusFilter() ) ``` -------------------------------- ### Get Image URL for Page Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Fetches the source URL for an image associated with a page. This method is normally not needed to override and is available since extensions-lib 1.5. ```kotlin open suspend fun getImageUrl(page: Page): String ``` -------------------------------- ### Get App Version Information Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/extensions-lib-overview.md Retrieve the host application's version code and name. Useful for constructing User-Agent headers. Note that these values may differ across various forks of the application. ```kotlin AppInfo.getVersionCode(): Int // e.g., 65 AppInfo.getVersionName(): String // e.g., "0.15.1" ``` -------------------------------- ### Get Related Manga List By Extension (Kotlin) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-catalogue-source.md Fetches related manga provided directly by the extension. Results are pushed via a callback. ```kotlin suspend fun getRelatedMangaListByExtension( manga: SManga, pushResults: suspend (relatedManga: Pair>, completed: Boolean) -> Unit, ) ``` -------------------------------- ### Get Popular Manga Page (Kotlin) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-catalogue-source.md Fetches a paginated list of popular manga using coroutines. Ensure you handle potential network or parsing exceptions. ```kotlin try { val page = source.getPopularManga(1) page.mangas.forEach { manga -> println("${manga.title}") } if (page.hasNextPage) println("More pages available") } catch (e: Exception) { println("Error: ${e.message}") } ``` -------------------------------- ### Get Application Version Name Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-other-interfaces.md Retrieve the version name of the host application, useful for User-Agent information. This value can differ between application forks, so logic should not rely on specific names. ```kotlin val versionName = AppInfo.getVersionName() val userAgent = "MyApp/$versionName (Android)" // In a request header val headers = headersBuilder() .add("User-Agent", "MyExtension/${versionName}") .build() ``` -------------------------------- ### Get Application Version Code Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-other-interfaces.md Retrieve the version code of the host application. This is useful for constructing User-Agent strings or performing compatibility checks. Note that this value can differ between application forks. ```kotlin val versionCode = AppInfo.getVersionCode() val userAgent = "MyMangaApp/$versionCode (Android)" ``` -------------------------------- ### Import Network Utilities Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Import path for network utilities and helper classes. ```kotlin import eu.kanade.tachiyomi.network.* ``` -------------------------------- ### Initialize NetworkHelper Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Instantiate NetworkHelper with an Android application context. ```kotlin val networkHelper = NetworkHelper(context) ``` -------------------------------- ### Package Structure Overview Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/module-architecture.md This outlines the directory and file structure of the extensions-lib module, showing the organization of source interfaces, models, network utilities, and helper classes. ```tree eu.kanade.tachiyomi ├── AppInfo.kt // Application version info ├── source/ │ ├── Source.kt // Base source interface │ ├── CatalogueSource.kt // Browsable catalog interface │ ├── ConfigurableSource.kt // Preference configuration │ ├── SourceFactory.kt // Source factory pattern │ ├── UnmeteredSource.kt // Marker for unmetered sources │ ├── model/ │ │ ├── Filter.kt // Filter definitions │ │ ├── FilterList.kt // Filter list wrapper │ │ ├── MangasPage.kt // Paginated manga results │ │ ├── Page.kt // Chapter page model │ │ ├── SChapter.kt // Chapter interface │ │ ├── SManga.kt // Manga interface │ │ └── UpdateStrategy.kt // Manga update strategy enum │ └── online/ │ └── HttpSource.kt // HTTP source base class ├── network/ │ ├── JavaScriptEngine.kt // JavaScript evaluation │ ├── NetworkHelper.kt // HTTP client factory │ ├── OkHttpExtensions.kt // Call/Response extensions │ └── Requests.kt // Request builder functions └── util/ └── JsoupExtensions.kt // HTML parsing extensions ``` -------------------------------- ### HttpSource Convenience Methods Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/extensions-lib-overview.md Optionally override these open methods for further customization of request building, URL generation, chapter preparation, and image retrieval. ```kotlin // Optional overrides for request customization open fun headersBuilder(): Headers.Builder open fun getMangaUrl(manga: SManga): String open fun getChapterUrl(chapter: SChapter): String open fun prepareNewChapter(chapter: SChapter, manga: SManga) open fun getImageUrl(page: Page): String open fun getImage(page: Page): Response ``` -------------------------------- ### Create Source Instances at Runtime Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-other-interfaces.md Implement this factory interface to create multiple source instances dynamically. The application calls this method to instantiate all sources provided by an extension. ```kotlin import eu.kanade.tachiyomi.source.SourceFactory import eu.kanade.tachiyomi.source.Source class MySourceFactory : SourceFactory { override fun createSources(): List { return listOf( MyEnglishSource(), MyJapaneseSource(), MyManhuaSource() ) } } ``` -------------------------------- ### NetworkHelper Class Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md HTTP client factory and configuration helper. Provides a configured OkHttpClient instance for executing HTTP requests. ```APIDOC ## NetworkHelper Class ### Description HTTP client factory and configuration helper. Provides a configured OkHttpClient instance for executing HTTP requests. This client should be reused across the application for optimal connection pooling and resource management. ### Constructor ```kotlin class NetworkHelper(context: Context) ``` #### Parameters - **context** (Context) - Required - Android application context ### Properties #### client ```kotlin val client: OkHttpClient ``` #### Example ```kotlin val networkHelper = NetworkHelper(context) val response = networkHelper.client.newCall(request).execute() ``` ``` -------------------------------- ### Get Latest Updates (Suspend) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Retrieves a page of the latest updates. Normally not needed to override. Available since extensions-lib 1.5. ```kotlin override suspend fun getLatestUpdates(page: Int): MangasPage ``` -------------------------------- ### Import Source Interface Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-source.md Import the base Source interface for creating manga sources. ```kotlin import eu.kanade.tachiyomi.source.Source ``` -------------------------------- ### Get Popular Manga (Suspend) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Retrieves a page of popular manga. Normally not needed to override. Available since extensions-lib 1.5. ```kotlin override suspend fun getPopularManga(page: Int): MangasPage ``` -------------------------------- ### Execute HTTP Request with NetworkHelper Client Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Use the configured OkHttpClient from NetworkHelper to execute an HTTP request. ```kotlin val response = networkHelper.client.newCall(request).execute() ``` -------------------------------- ### Construct Manga URLs with Pagination Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md Demonstrates three common ways to construct URLs for paginated manga listings: by page number, with a query parameter, or using offset and limit. ```kotlin val pageNumber = 1 val url = "$baseUrl/popular/page/$pageNumber" // or val url = "$baseUrl/popular?page=$pageNumber" // or val offset = (pageNumber - 1) * 20 val url = "$baseUrl/popular?offset=$offset&limit=20" ``` -------------------------------- ### SourceFactory for Dynamic Source Creation Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/extensions-lib-overview.md Implement `SourceFactory` to create multiple source instances dynamically at runtime. ```kotlin class MySourceFactory : SourceFactory { override fun createSources(): List { return listOf( EnglishSource(), JapaneseSource(), ChineseSource() ) } } ``` -------------------------------- ### Get Filter List Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-catalogue-source.md Retrieve the available filters for the source's search functionality. This is useful for building custom search UIs. ```kotlin val filters = source.getFilterList() filters.forEach { println("Filter: ${it.name} (${it::class.simpleName})") } ``` -------------------------------- ### Minimal HttpSource Implementation Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md Implement the basic structure of an HttpSource for a manga website. This includes defining source details and parsing methods for popular, search, latest updates, manga details, chapters, pages, and image URLs. A basic filter list is also included. ```kotlin import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.model.* import eu.kanade.tachiyomi.network.Requests.* import eu.kanade.tachiyomi.util.JsoupExtensions.* import okhttp3.Request import okhttp3.Response class MangaSource : HttpSource() { override val baseUrl = "https://mangasite.com" override val lang = "en" override val name = "MangaSite" override val supportsLatest = true override val versionId = 1 // Popular manga override fun popularMangaRequest(page: Int) = GET("$baseUrl/popular?page=$page") override fun popularMangaParse(response: Response): MangasPage { val doc = response.asJsoup() val mangas = doc.select("div.manga").map { el -> SManga.create().apply { url = el.selectFirst("a")?.attr("href") ?: "" title = el.selectFirst("h3")?.text() ?: "" thumbnail_url = el.selectFirst("img")?.attr("src") } } return MangasPage(mangas, hasNextPage = doc.selectFirst("a.next") != null) } // Search override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = GET("$baseUrl/search?q=$query&page=$page") override fun searchMangaParse(response: Response) = popularMangaParse(response) // Latest override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/latest?page=$page") override fun latestUpdatesParse(response: Response) = popularMangaParse(response) // Manga details override fun mangaDetailsParse(response: Response): SManga { val doc = response.asJsoup() return SManga.create().apply { title = doc.selectFirst("h1")?.text() ?: "" author = doc.selectFirst(".author")?.text() description = doc.selectFirst(".description")?.text() status = SManga.ONGOING genre = doc.select(".genre").joinToString(", ") { it.text() } thumbnail_url = doc.selectFirst(".cover")?.attr("src") } } // Chapters override fun chapterListParse(response: Response): List { val doc = response.asJsoup() return doc.select("tr.chapter").map { el -> SChapter.create().apply { url = el.selectFirst("a")?.attr("href") ?: "" name = el.selectFirst("td.name")?.text() ?: "" chapter_number = el.selectFirst("td.num")?.text()?.toFloatOrNull() ?: 0f date_upload = System.currentTimeMillis() } } } // Pages override fun pageListParse(response: Response): List { val doc = response.asJsoup() return doc.select("img.page").mapIndexed { idx, el -> Page(idx, url = el.attr("src")) } } // Image URL override fun imageUrlParse(response: Response) = response.asJsoup().selectFirst("img#main")?.attr("src") ?: "" // Filters override fun getFilterList() = FilterList( Filter.Header("Filters"), GenreFilter() ) private class GenreFilter : Filter.Select( "Genre", arrayOf("All", "Action", "Comedy", "Drama") ) } ``` -------------------------------- ### Get Chapter List (Suspend) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Retrieves the list of chapters for a given manga. Normally not needed to override. Available since extensions-lib 1.4. ```kotlin override suspend fun getChapterList(manga: SManga): List ``` -------------------------------- ### OkHttp POST Request Builder Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/MANIFEST.md Illustrates how to create a POST request using OkHttp. This is used when sending data to a server. ```kotlin val request = POST("https://example.com/api/submit", body = formBody { add("username", "user") add("password", "pass") }) ``` -------------------------------- ### fetchChapterList (Legacy RxJava) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-source.md Fetches all available chapters for a manga using RxJava Observables. This is a legacy method. ```APIDOC ## fetchChapterList (Legacy RxJava) ### Description Fetch all available chapters for a manga. Returns an Observable that emits the chapter list. ### Method `Observable>` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```kotlin source.fetchChapterList(manga) .subscribe( { chapters -> println("Found ${chapters.size} chapters") }, { error -> println("Error: ${error.message}") } ) ``` ### Response #### Success Response `Observable>` - Observable emitting list of chapters #### Response Example (See Request Example for subscription handling) ``` -------------------------------- ### Get Related Manga List (Kotlin) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-catalogue-source.md Retrieves all related manga for a given manga. This method is typically not overridden and handles exceptions via a callback. ```kotlin override suspend fun getRelatedMangaList( manga: SManga, exceptionHandler: (Throwable) -> Unit, pushResults: suspend (relatedManga: Pair>, completed: Boolean) -> Unit, ) ``` -------------------------------- ### Import OkHttp Extensions Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Import the necessary OkHttp extension functions for use in your Kotlin code. ```kotlin import eu.kanade.tachiyomi.network.OkHttpExtensions.* ``` -------------------------------- ### Build URL with Query Parameters Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md Dynamically builds a URL with multiple query parameters. Useful for search or filtering. ```kotlin val url = "$baseUrl/search".toHttpUrl().newBuilder() .addQueryParameter("q", query) .addQueryParameter("page", page.toString()) .addQueryParameter("sort", "latest") .build() GET(url) ``` -------------------------------- ### Get Search Manga (Suspend) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Retrieves search results for a given page, query, and filters. Normally not needed to override. Available since extensions-lib 1.5. ```kotlin override suspend fun getSearchManga(page: Int, query: String, filters: FilterList): MangasPage ``` -------------------------------- ### Import CatalogueSource Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-catalogue-source.md Import the CatalogueSource interface from the library. ```kotlin import eu.kanade.tachiyomi.source.CatalogueSource ``` -------------------------------- ### Mock HTTP Response for Testing Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md A helper function to create a mock `Response` object for testing purposes. It takes HTML content and constructs a response with a 200 OK status. ```kotlin private fun mockResponse(html: String): Response { val request = Request.Builder().url("http://example.com").build() val responseBody = html.toResponseBody("text/html".toMediaType()) return Response.Builder() .request(request) .protocol(Protocol.HTTP_1_1) .code(200) .message("OK") .body(responseBody) .build() } ``` -------------------------------- ### Implement UnmeteredSource Interface Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-other-interfaces.md Implement this interface for sources that do not require traffic considerations, such as self-hosted or local file sources. No methods need to be implemented. ```kotlin import eu.kanade.tachiyomi.source.UnmeteredSource class LocalMangaSource : HttpSource(), UnmeteredSource { // This source accesses local storage, no network traffic concerns override val baseUrl = "file://" override val name = "Local Manga" override val lang = "en" } class SelfHostedSource : HttpSource(), UnmeteredSource { // This source accesses the user's own server, no public traffic concerns override val baseUrl = "http://my-server.local" override val name = "My Server" override val lang = "en" } ``` -------------------------------- ### Get Manga Details (Suspend) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Retrieves updated details for a manga. Normally not needed to override. Available since extensions-lib 1.4. Throws LicensedMangaChaptersException if the manga is licensed. ```kotlin override suspend fun getMangaDetails(manga: SManga): SManga ``` -------------------------------- ### ConfigurableSource Implementation Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/extensions-lib-overview.md Implement `ConfigurableSource` to provide custom preference screens for source configuration within the application. ```kotlin class MySource : HttpSource(), ConfigurableSource { override fun setupPreferenceScreen(screen: PreferenceScreen) { // Add custom preferences for source configuration } } ``` -------------------------------- ### Get Related Manga List By Search (Kotlin) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-catalogue-source.md Finds related manga by searching for keywords extracted from the manga's title. Results are processed via a callback. ```kotlin source.getRelatedMangaListBySearch(manga) { (keyword, mangas), completed -> println("Related by '$keyword': ${mangas.size} titles") if (completed) println("All searches complete") } ``` -------------------------------- ### Get Latest Updates (Kotlin) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-catalogue-source.md Fetches a paginated list of the latest manga updates using coroutines. Exceptions may occur due to network or parsing issues. ```kotlin suspend fun getLatestUpdates(page: Int): MangasPage ``` -------------------------------- ### Create a Manga Object Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/README.md Use this pattern to create a new SManga object and populate its basic properties. Set the status to SManga.ONGOING for ongoing series. ```kotlin SManga.create().apply { url = "..." title = "..." status = SManga.ONGOING thumbnail_url = "..." } ``` -------------------------------- ### Export Multiple Sources with SourceFactory Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/extensions-lib-overview.md Use SourceFactory to provide multiple sources within a single extension. Implement the createSources method to return a list of your source implementations. ```kotlin class MySourceFactory : SourceFactory { override fun createSources() = listOf(EnglishSource(), JapaneseSource()) } ``` -------------------------------- ### NetworkHelper Usage Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/extensions-lib-overview.md Use the configured `NetworkHelper` to execute HTTP requests. The `network` client is typically injected into `HttpSource`. ```kotlin protected val network: NetworkHelper // Injected in HttpSource // Usage val response = network.client.newCall(request).execute() ``` -------------------------------- ### Prepare New Chapter Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Called before inserting a new chapter into the database. Use this to override chapter fields like title or chapter number. Do not modify the manga object. ```kotlin open fun prepareNewChapter(chapter: SChapter, manga: SManga) ``` ```kotlin override fun prepareNewChapter(chapter: SChapter, manga: SManga) { // Adjust chapter number if needed chapter.chapter_number = chapter.name.extractChapterNumber() } ``` -------------------------------- ### Base URL Property Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md The abstract 'baseUrl' property must be implemented by subclasses to provide the base URL of the website without a trailing slash. For example: "http://mysite.com". ```kotlin abstract val baseUrl: String ``` -------------------------------- ### Define Custom Filter Classes Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/filter-guide.md Example of defining custom filter classes for Genre, Completed status, and Language. These extend base Filter classes like Select, CheckBox, and TriState. ```kotlin private class GenreFilter : Filter.Select( "Genre", arrayOf("All", "Action", "Comedy", "Drama", "Fantasy"), state = 0 ) private class CompletedFilter : Filter.CheckBox("Completed Only", false) private class LanguageFilter : Filter.TriState("English Only") ``` -------------------------------- ### Build POST Request Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/quick-start.md Constructs a POST request with a request body. The body content type must be specified. ```kotlin val body = "param=value".toRequestBody("application/x-www-form-urlencoded".toMediaType()) POST("$baseUrl/login", body = body) ``` -------------------------------- ### Simple Genre and Status Filters Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/filter-guide.md Combines basic genre and status filters for straightforward searching. ```kotlin override fun getFilterList() = FilterList( GenreFilter(), StatusFilter() ) ``` -------------------------------- ### Get Related Manga List (Kotlin) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-source.md Use this function to fetch related manga for a specific manga. It supports progressive result pushing and error handling via callbacks. Available since komikku/extensions-lib 1.6. ```kotlin suspend fun getRelatedMangaList( manga: SManga, exceptionHandler: (Throwable) -> Unit, pushResults: suspend (relatedManga: Pair>, completed: Boolean) -> Unit, ) ``` ```kotlin source.getRelatedMangaList( manga, exceptionHandler = { error -> println("Error: ${error.message}") }, pushResults = { (keyword, mangas), completed -> println("Related by '$keyword': ${mangas.size} titles") if (completed) println("Search complete") } ) ``` -------------------------------- ### Get Chapter List (Suspend) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-source.md Fetch all available chapters for a manga using Kotlin coroutines. This suspend function is available since extensions-lib 1.4. Handle potential network or parsing errors with a try-catch block. ```kotlin try { val chapters = source.getChapterList(manga) chapters.forEach { ch -> println("${ch.chapter_number}: ${ch.name}") } } catch (e: Exception) { println("Error: ${e.message}") } ``` -------------------------------- ### Get Manga Details (Suspend) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-source.md Fetch updated manga details using Kotlin coroutines. This suspend function is available since extensions-lib 1.4. Handle potential network or parsing errors with a try-catch block. ```kotlin try { val updated = source.getMangaDetails(manga) println("Title: ${updated.title}, Status: ${updated.status}") } catch (e: Exception) { println("Error: ${e.message}") } ``` -------------------------------- ### Import HttpSource Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-http-source.md Import the HttpSource class from the library. This is required when creating a new source that extends HttpSource. ```kotlin import eu.kanade.tachiyomi.source.online.HttpSource ``` -------------------------------- ### Get Page List (Suspend) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-source.md Fetch the list of pages for a chapter using Kotlin coroutines. Pages should be returned in the expected order. This suspend function is available since komikku/extensions-lib 1.7. Handle potential network or parsing errors with a try-catch block. ```kotlin try { val pages = source.getPageList(chapter) pages.forEachIndexed { idx, page -> println("Page ${idx}: ${page.url}") } } catch (e: Exception) { println("Error: ${e.message}") } ``` -------------------------------- ### Build POST HTTP Requests Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/module-architecture.md Constructs POST requests with optional headers, body, and cache control. ```kotlin fun POST(url: String, headers: Headers = DEFAULT_HEADERS, body: RequestBody = DEFAULT_BODY, cache: CacheControl = DEFAULT_CACHE_CONTROL): Request ``` -------------------------------- ### Use Filters in Search Request Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/filter-guide.md Demonstrates how to extract and apply filter states from a FilterList to build a search query URL. It checks for specific filter types and adds corresponding query parameters. ```kotlin override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { val url = "$baseUrl/search".toHttpUrl().newBuilder() .addQueryParameter("q", query) .addQueryParameter("page", page.toString()) // Extract and apply filters filters.filterIsInstance().firstOrNull()?.let { val genre = it.values[it.state] if (genre != "All") url.addQueryParameter("genre", genre) } filters.filterIsInstance().firstOrNull()?.let { if (it.state) url.addQueryParameter("status", "completed") } filters.filterIsInstance().firstOrNull()?.let { if (it.isIncluded()) url.addQueryParameter("lang", "en") } return GET(url.build()) } ``` -------------------------------- ### Fetch Chapter List (RxJava) Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-source.md Use this method to fetch all available chapters for a manga using RxJava Observables. Subscribe to the Observable to receive a list of chapters or handle errors. ```kotlin source.fetchChapterList(manga) .subscribe( { chapters -> println("Found ${chapters.size} chapters") }, { error -> println("Error: ${error.message}") } ) ``` -------------------------------- ### POST Request Source: https://github.com/komikku-app/extensions-lib/blob/main/_autodocs/api-reference-network.md Builds a POST request with a specified URL, optional headers, and a request body. The body must be properly formatted with a content type. ```kotlin import eu.kanade.tachiyomi.network.Requests.* import okhttp3.RequestBody.Companion.toRequestBody val body = "username=user&password=pass".toRequestBody("application/x-www-form-urlencoded".toMediaType()) val request = POST("https://example.com/login", body = body) ```