Understanding entry-source-api¶
The Entry API separates three questions:
- What appears in a catalogue?
- What can the user open from an entry?
- Which renderer should consume the resolved media?
Catalogue lifecycle¶
Every UnifiedSource implements the same suspending operations:
suspend fun getPopularContent(page: Int): EntryPageResult<SEntry>
suspend fun getLatestUpdates(page: Int): EntryPageResult<SEntry>
suspend fun getSearchContent(
page: Int,
query: String,
filters: EntryFilterList,
): EntryPageResult<SEntry>
suspend fun getContentDetails(entry: SEntry): SEntry
suspend fun getChapterList(entry: SEntry): List<SEntryChapter>
suspend fun getMedia(
chapter: SEntryChapter,
selection: PlaybackSelection = PlaybackSelection(),
): EntryMedia
Return hasNextPage = true only when requesting the next page can produce more results.
EntryHttpSource adds a shared network client, headers, URL helpers, catalogue metadata, and a stable-ID algorithm. EntryImageHttpSource adds image requests and chapter URL support.
Entries¶
Create catalogue results with SEntry.create():
val entry = SEntry.create().apply {
url = "/title/example"
title = "Example"
thumbnailUrl = "https://example.com/cover.jpg"
status = SEntry.ONGOING
type = EntryType.MANGA
}
The entry URL is its identity inside a source. Keep it stable and prefer a relative URL when extending EntryHttpSource.
EntryType belongs to each entry rather than to the extension or source, so a catalogue can return both.
When enriching an existing entry, copy it rather than discarding fields already discovered by the catalogue:
return entry.copy().apply {
initialized = true
description = parsedDescription
genre = parsedGenres
type = parsedType
}
Chapters¶
SEntryChapter represents an openable unit. The name can be a chapter, episode, movie, gallery, or another user-facing label:
val chapter = SEntryChapter.create().apply {
url = "/title/example/chapter-1"
name = "Chapter 1"
chapterNumber = 1.0
dateUpload = uploadTimeMillis
}
Keep chapter URLs stable after release. Katari uses source, entry, and chapter identity to preserve library and history state.
Image media¶
Image sources return EntryMedia.ImagePages:
return EntryMedia.ImagePages(
imageUrls.mapIndexed { index, imageUrl ->
EntryImagePage(
index = index,
url = imageUrl,
imageUrl = imageUrl,
)
},
)
Use EntryImageHttpSource when the source can use its default image loading behavior. Override getImageUrl() or imageRequest() when pages require a separate resolution request or special headers.
Playback media¶
Video sources return a playback descriptor:
return EntryMedia.Playback(
PlaybackDescriptor(
selection = selection,
streams = listOf(
VideoStream(
request = VideoRequest(
url = streamUrl,
headers = mapOf("Referer" to "$baseUrl/"),
),
label = "1080p",
type = VideoStreamType.HLS,
),
),
),
)
PlaybackDescriptor can also advertise dub and source-quality options. If a requested option is unavailable, return the actual fallback in descriptor.selection. Implement SubtitleSource when subtitle tracks are resolved separately from the streams.
Filters¶
Return EntryFilterList from getFilterList() and inspect the same filter types in getSearchContent():
private class SortFilter : EntryFilter.Select<String>(
name = "Sort",
values = arrayOf("Popular", "Newest"),
)
override fun getFilterList() = EntryFilterList(SortFilter())
Filter state is mutable. Treat the list received by getSearchContent() as the user's current selection rather than retaining an older copy.
Optional capabilities¶
A source can opt into additional behavior by implementing focused interfaces:
ConfigurableSourceadds an Android preference screen scoped to the source.SubtitleSourceresolves external video subtitles.EntryPreviewSourcesupplies media for catalogue previews.ResolvableSourceresolves supported external URLs.EntryItemOrientationProviderchooses catalogue item orientation.EmptyChapterListSource,IncrementalChapterSource, andChapterNumberRecognitionSourcedescribe chapter-list behavior.UnmeteredSourcedeclares that requests do not consume metered network data.
Prefer capabilities over checking concrete source classes. This lets Katari add new content behavior without creating another parallel extension API.
Stable source identity¶
EntryHttpSource derives its ID from name, lang, and versionId unless the source overrides id. Changing any of those inputs changes the generated ID. Once an extension has users, preserve its source ID or provide an intentional migration path.
The complete public contracts are available in entry-source-api/src.