| name | jellyfin-api |
| description | Jellyfin API patterns and JellyfinClient usage for MyFlix |
Jellyfin API Skill
When to Use
Apply when making API calls, handling authentication, or working with media data.
JellyfinClient Configuration
jellyfinClient.configure(
serverUrl = "https://jellyfin.example.com",
accessToken = authResponse.accessToken,
userId = authResponse.user.id,
deviceId = "myflix_${System.currentTimeMillis()}"
)
if (jellyfinClient.isAuthenticated) { }
jellyfinClient.logout()
Common API Calls
Libraries
jellyfinClient.getLibraries().onSuccess { libraries ->
val moviesLib = LibraryFinder.findMoviesLibrary(libraries)
val showsLib = LibraryFinder.findShowsLibrary(libraries)
}
Latest Content
jellyfinClient.getLatestMovies(libraryId, limit = 12)
jellyfinClient.getLatestSeries(libraryId, limit = 12)
jellyfinClient.getLatestEpisodes(libraryId, limit = 12)
Resume & Next Up
jellyfinClient.getResume(limit = 12)
jellyfinClient.getNextUp(limit = 12)
Item Details
jellyfinClient.getItem(itemId).onSuccess { item ->
}
jellyfinClient.getSeasons(seriesId)
jellyfinClient.getEpisodes(seriesId, seasonId)
jellyfinClient.getSimilarItems(itemId, limit = 12)
Collections & Genres
jellyfinClient.getCollections()
jellyfinClient.getCollectionItems(collectionId)
jellyfinClient.getGenres(libraryId)
jellyfinClient.getItemsByGenre(genreName, libraryId, limit = 20)
Search
jellyfinClient.search(query, limit = 20)
Image URLs
jellyfinClient.getPrimaryImageUrl(itemId, imageTag, maxWidth = 400)
jellyfinClient.getBackdropUrl(itemId, backdropTag, maxWidth = 1920)
jellyfinClient.getThumbUrl(itemId, thumbTag, maxWidth = 600)
jellyfinClient.getBlurredBackdropUrl(itemId, backdropTag, blur = 20)
jellyfinClient.getUserImageUrl(userId)
Playback Reporting
jellyfinClient.reportPlaybackStart(itemId, mediaSourceId, positionTicks = 0)
jellyfinClient.reportPlaybackProgress(itemId, positionTicks, isPaused = false)
jellyfinClient.reportPlaybackStopped(itemId, positionTicks)
User Actions
jellyfinClient.setPlayed(itemId, played = true)
jellyfinClient.setFavorite(itemId, favorite = true)
Caching
jellyfinClient.clearCache()
jellyfinClient.invalidateCache("resume", "nextup", "item:$itemId")
Field Selection Constants
The client optimizes requests by selecting only needed fields:
CARD: Overview, ImageTags, BackdropImageTags, UserData, Ratings
EPISODE_CARD: Above + SeriesName, SeasonName
DETAIL: Full info including MediaSources, Genres, People, etc.
SERIES_DETAIL: Above + ChildCount, RecursiveItemCount
Data Models
JellyfinItem
data class JellyfinItem(
val id: String,
val name: String,
val type: String,
val overview: String?,
val productionYear: Int?,
val officialRating: String?,
val communityRating: Float?,
val criticRating: Int?,
val runTimeTicks: Long?,
val seriesId: String?,
val seriesName: String?,
val seasonName: String?,
val indexNumber: Int?,
val parentIndexNumber: Int?,
val imageTags: ImageTags?,
val backdropImageTags: List<String>?,
val userData: UserData?,
val premiereDate: String?,
val status: String?,
val genres: List<String>?,
val studios: List<Studio>?,
val people: List<Person>?,
val mediaSources: List<MediaSource>?,
val mediaStreams: List<MediaStream>?
)
UserData
data class UserData(
val playbackPositionTicks: Long?,
val playCount: Int?,
val isFavorite: Boolean,
val played: Boolean,
val lastPlayedDate: String?
)
Authentication Flow
Quick Connect
jellyfinClient.quickConnectFlow(serverUrl).collect { state ->
when (state) {
is QuickConnectFlowState.WaitingForApproval -> {
}
is QuickConnectFlowState.Authenticated -> {
}
is QuickConnectFlowState.Error -> {
}
}
}
Username/Password
jellyfinClient.authenticate(serverUrl, username, password)
.onSuccess { authResponse ->
jellyfinClient.configure(
serverUrl,
authResponse.accessToken,
authResponse.user.id,
deviceId
)
}
Error Handling Pattern
suspend fun loadData() {
isLoading = true
errorMessage = null
jellyfinClient.getData()
.onSuccess { data ->
items = data
}
.onFailure { e ->
errorMessage = "Failed to load: ${e.message ?: "Unknown error"}"
}
isLoading = false
}