Add Live TV & DVR Support (#49)

Closes #1 

Adds support for Live TV & DVR functionality.

TODO:
- [x] EPG / TV Guide
- [x] View DVR schedule
- [x] Play live TV channel
- [x] Record program
- [x] Record Series
- [x] Cancel recordings
- [x] Access previously recorded content
This commit is contained in:
damontecres 2025-10-23 22:46:16 -04:00 committed by GitHub
parent a35ecb6570
commit 05f3811149
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 1915 additions and 15 deletions

View file

@ -17,10 +17,12 @@ import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.Response
import org.jellyfin.sdk.api.client.extensions.genresApi
import org.jellyfin.sdk.api.client.extensions.itemsApi
import org.jellyfin.sdk.api.client.extensions.liveTvApi
import org.jellyfin.sdk.api.client.extensions.playlistsApi
import org.jellyfin.sdk.api.client.extensions.suggestionsApi
import org.jellyfin.sdk.api.client.extensions.tvShowsApi
import org.jellyfin.sdk.model.api.BaseItemDtoQueryResult
import org.jellyfin.sdk.model.api.GetProgramsDto
import org.jellyfin.sdk.model.api.request.GetEpisodesRequest
import org.jellyfin.sdk.model.api.request.GetGenresRequest
import org.jellyfin.sdk.model.api.request.GetItemsRequest
@ -317,3 +319,22 @@ val GetGenresRequestHandler =
request: GetGenresRequest,
): Response<BaseItemDtoQueryResult> = api.genresApi.getGenres(request)
}
val GetProgramsDtoHandler =
object : RequestHandler<GetProgramsDto> {
override fun prepare(
request: GetProgramsDto,
startIndex: Int,
limit: Int,
enableTotalRecordCount: Boolean,
): GetProgramsDto =
request.copy(
startIndex = startIndex,
limit = limit,
)
override suspend fun execute(
api: ApiClient,
request: GetProgramsDto,
): Response<BaseItemDtoQueryResult> = api.liveTvApi.getPrograms(request)
}

View file

@ -19,8 +19,14 @@ val supportItemKinds =
BaseItemKind.VIDEO,
BaseItemKind.SEASON,
BaseItemKind.COLLECTION_FOLDER,
BaseItemKind.FOLDER,
BaseItemKind.USER_VIEW,
BaseItemKind.TRAILER,
BaseItemKind.TV_CHANNEL,
BaseItemKind.TV_PROGRAM,
BaseItemKind.LIVE_TV_CHANNEL,
BaseItemKind.LIVE_TV_PROGRAM,
BaseItemKind.RECORDING,
)
val supportedCollectionTypes =
@ -30,4 +36,5 @@ val supportedCollectionTypes =
CollectionType.HOMEVIDEOS,
CollectionType.PLAYLISTS,
CollectionType.BOXSETS,
CollectionType.LIVETV,
)

View file

@ -0,0 +1,11 @@
package com.github.damontecres.wholphin.util
class LazyList<Source, Transform>(
private val source: List<Source>,
private val transform: (Source) -> Transform,
) : AbstractList<Transform>() {
override fun get(index: Int): Transform = transform.invoke(source[index])
override val size: Int
get() = source.size
}

View file

@ -49,6 +49,7 @@ class TrackActivityPlaybackListener(
isMuted = false,
audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled },
subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled },
liveStreamId = playback.liveStreamId,
),
)
}
@ -78,6 +79,7 @@ class TrackActivityPlaybackListener(
positionTicks = position,
failed = false,
playSessionId = playback.playSessionId,
liveStreamId = playback.liveStreamId,
),
)
}
@ -114,6 +116,7 @@ class TrackActivityPlaybackListener(
playSessionId = playback.playSessionId,
audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled },
subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled },
liveStreamId = playback.liveStreamId,
),
)
}