diff --git a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt index b383842f..ed6b8894 100644 --- a/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt +++ b/app/phone/src/main/java/dev/jdtech/jellyfin/fragments/MovieFragment.kt @@ -325,8 +325,8 @@ class MovieFragment : Fragment() { it.displayProfiles.firstOrNull()?.apply { videoProfileChip.text = this.raw videoProfileChip.isVisible = when (this) { - DisplayProfile.HDR, DisplayProfile.HDR10, + DisplayProfile.HDR10_PLUS, DisplayProfile.HLG, -> { videoProfileChip.chipStartPadding = .0f diff --git a/app/tv/src/main/java/dev/jdtech/jellyfin/ui/MovieScreen.kt b/app/tv/src/main/java/dev/jdtech/jellyfin/ui/MovieScreen.kt index 338b98d3..a0f05924 100644 --- a/app/tv/src/main/java/dev/jdtech/jellyfin/ui/MovieScreen.kt +++ b/app/tv/src/main/java/dev/jdtech/jellyfin/ui/MovieScreen.kt @@ -61,6 +61,7 @@ import dev.jdtech.jellyfin.viewmodels.MovieViewModel import dev.jdtech.jellyfin.viewmodels.PlayerItemsEvent import dev.jdtech.jellyfin.viewmodels.PlayerViewModel import org.jellyfin.sdk.model.api.BaseItemPerson +import org.jellyfin.sdk.model.api.PersonKind import java.util.UUID import dev.jdtech.jellyfin.core.R as CoreR @@ -343,6 +344,7 @@ private fun MovieScreenLayoutPreview() { director = BaseItemPerson( id = UUID.randomUUID(), name = "Robert Rodriguez", + type = PersonKind.DIRECTOR, ), writers = emptyList(), videoMetadata = VideoMetadata( diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 00000000..3f87d39f --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "buildSrc" \ No newline at end of file diff --git a/core/src/main/java/dev/jdtech/jellyfin/di/ApiModule.kt b/core/src/main/java/dev/jdtech/jellyfin/di/ApiModule.kt index 3074ee44..482b910b 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/di/ApiModule.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/di/ApiModule.kt @@ -35,8 +35,10 @@ object ApiModule { val user = serverWithAddressAndUser.user jellyfinApi.apply { - api.baseUrl = serverAddress.address - api.accessToken = user?.accessToken + api.update( + baseUrl = serverAddress.address, + accessToken = user?.accessToken, + ) userId = user?.id } diff --git a/core/src/main/java/dev/jdtech/jellyfin/dialogs/SortDialogFragment.kt b/core/src/main/java/dev/jdtech/jellyfin/dialogs/SortDialogFragment.kt index 7a93955a..d5aa2e60 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/dialogs/SortDialogFragment.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/dialogs/SortDialogFragment.kt @@ -44,7 +44,7 @@ class SortDialogFragment( when (sortType) { "sortBy" -> { val sortByOptions = resources.getStringArray(R.array.sort_by_options) - val sortByValues = SortBy.values() + val sortByValues = SortBy.entries builder .setTitle(getString(R.string.sort_by)) .setSingleChoiceItems( @@ -64,7 +64,7 @@ class SortDialogFragment( } "sortOrder" -> { val sortByOptions = resources.getStringArray(R.array.sort_order_options) - val sortOrderValues = SortOrder.values() + val sortOrderValues = SortOrder.entries builder .setTitle(getString(R.string.sort_order)) diff --git a/core/src/main/java/dev/jdtech/jellyfin/utils/CoreExtensions.kt b/core/src/main/java/dev/jdtech/jellyfin/utils/CoreExtensions.kt index c0aa0100..7f8503ce 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/utils/CoreExtensions.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/utils/CoreExtensions.kt @@ -18,7 +18,7 @@ fun BaseItemDto.toView(): View { return View( id = id, name = name ?: "", - type = CollectionType.fromString(collectionType), + type = CollectionType.fromString(collectionType?.serialName), ) } diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/AddServerViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/AddServerViewModel.kt index ea5afe93..c483e4e3 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/AddServerViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/AddServerViewModel.kt @@ -202,8 +202,10 @@ constructor( appPreferences.currentServer = server.id jellyfinApi.apply { - api.baseUrl = recommendedServerInfo.address - api.accessToken = null + api.update( + baseUrl = recommendedServerInfo.address, + accessToken = null, + ) } _uiState.emit(UiState.Normal) diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt index 0a5044bd..36a0ad17 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt @@ -11,6 +11,7 @@ import dev.jdtech.jellyfin.models.HomeSection import dev.jdtech.jellyfin.models.UiText import dev.jdtech.jellyfin.repository.JellyfinRepository import dev.jdtech.jellyfin.utils.toView +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch @@ -41,13 +42,12 @@ class HomeViewModel @Inject internal constructor( viewModelScope.launch { try { repository.postCapabilities() - } catch (_: Exception) { - } + } catch (_: Exception) { } } } fun loadData() { - viewModelScope.launch { + viewModelScope.launch(Dispatchers.Default) { _uiState.emit(UiState.Loading) try { val items = mutableListOf() @@ -93,7 +93,7 @@ class HomeViewModel @Inject internal constructor( private suspend fun loadViews() = repository .getUserViews() - .filter { view -> CollectionType.fromString(view.collectionType) in CollectionType.supported } + .filter { view -> CollectionType.fromString(view.collectionType?.serialName) in CollectionType.supported } .map { view -> view to repository.getLatestMedia(view.id) } .filter { (_, latest) -> latest.isNotEmpty() } .map { (view, latest) -> view.toView().apply { items = latest } } diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/LoginViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/LoginViewModel.kt index 7f2f2314..43ad3e91 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/LoginViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/LoginViewModel.kt @@ -19,7 +19,6 @@ import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.jellyfin.sdk.api.client.extensions.authenticateWithQuickConnect -import org.jellyfin.sdk.api.client.extensions.brandingApi import org.jellyfin.sdk.model.api.AuthenticateUserByName import org.jellyfin.sdk.model.api.AuthenticationResult import javax.inject.Inject @@ -72,7 +71,7 @@ constructor( private fun loadDisclaimer() { viewModelScope.launch { - loginDisclaimer = jellyfinApi.api.brandingApi.getBrandingOptions().content.loginDisclaimer + loginDisclaimer = jellyfinApi.brandingApi.getBrandingOptions().content.loginDisclaimer _uiState.emit(UiState.Normal(loginDisclaimer)) } } @@ -104,7 +103,7 @@ constructor( private fun loadQuickConnectAvailable() { viewModelScope.launch { try { - val isEnabled by jellyfinApi.quickConnectApi.getEnabled() + val isEnabled by jellyfinApi.quickConnectApi.getQuickConnectEnabled() if (isEnabled) { _quickConnectUiState.emit(QuickConnectUiState.Normal) } @@ -155,12 +154,12 @@ constructor( } quickConnectJob = viewModelScope.launch { try { - var quickConnectState = jellyfinApi.quickConnectApi.initiate().content + var quickConnectState = jellyfinApi.quickConnectApi.initiateQuickConnect().content _quickConnectUiState.emit(QuickConnectUiState.Waiting(quickConnectState.code)) while (!quickConnectState.authenticated) { - quickConnectState = jellyfinApi.quickConnectApi.connect(quickConnectState.secret).content delay(5000L) + quickConnectState = jellyfinApi.quickConnectApi.getQuickConnectState(quickConnectState.secret).content } val authenticationResult by jellyfinApi.userApi.authenticateWithQuickConnect( secret = quickConnectState.secret, @@ -189,7 +188,7 @@ constructor( insertUser(appPreferences.currentServer!!, user) jellyfinApi.apply { - api.accessToken = authenticationResult.accessToken + api.update(accessToken = authenticationResult.accessToken) userId = authenticationResult.user?.id } } diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/MovieViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/MovieViewModel.kt index 989dc775..d4c077db 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/MovieViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/MovieViewModel.kt @@ -30,6 +30,8 @@ import kotlinx.coroutines.withContext import org.jellyfin.sdk.model.api.BaseItemPerson import org.jellyfin.sdk.model.api.MediaStream import org.jellyfin.sdk.model.api.MediaStreamType +import org.jellyfin.sdk.model.api.PersonKind +import org.jellyfin.sdk.model.api.VideoRangeType import java.io.File import java.util.UUID import javax.inject.Inject @@ -119,7 +121,7 @@ constructor( private suspend fun getActors(item: FindroidMovie): List { val actors: List withContext(Dispatchers.Default) { - actors = item.people.filter { it.type == "Actor" } + actors = item.people.filter { it.type == PersonKind.ACTOR } } return actors } @@ -127,7 +129,7 @@ constructor( private suspend fun getDirector(item: FindroidMovie): BaseItemPerson? { val director: BaseItemPerson? withContext(Dispatchers.Default) { - director = item.people.firstOrNull { it.type == "Director" } + director = item.people.firstOrNull { it.type == PersonKind.DIRECTOR } } return director } @@ -135,7 +137,7 @@ constructor( private suspend fun getWriters(item: FindroidMovie): List { val writers: List withContext(Dispatchers.Default) { - writers = item.people.filter { it.type == "Writer" } + writers = item.people.filter { it.type == PersonKind.WRITER } } return writers } @@ -213,9 +215,9 @@ constructor( DisplayProfile.DOLBY_VISION } else { when (videoRangeType) { - DisplayProfile.HDR.raw -> DisplayProfile.HDR - DisplayProfile.HDR10.raw -> DisplayProfile.HDR10 - DisplayProfile.HLG.raw -> DisplayProfile.HLG + VideoRangeType.HDR10 -> DisplayProfile.HDR10 + VideoRangeType.HDR10_PLUS -> DisplayProfile.HDR10_PLUS + VideoRangeType.HLG -> DisplayProfile.HLG else -> DisplayProfile.SDR } }, diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt index b61682dc..6725b56d 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerAddressesViewModel.kt @@ -74,7 +74,9 @@ constructor( server.currentServerAddressId = address.id database.update(server) - jellyfinApi.api.baseUrl = address.address + jellyfinApi.api.update( + baseUrl = address.address, + ) eventsChannel.send(ServerAddressesEvent.NavigateToHome) } @@ -84,7 +86,9 @@ constructor( viewModelScope.launch(Dispatchers.IO) { try { val jellyfinApi = JellyfinApi(context) - jellyfinApi.api.baseUrl = address + jellyfinApi.api.update( + baseUrl = address, + ) val systemInfo by jellyfinApi.systemApi.getPublicSystemInfo() if (systemInfo.id != currentServerId) { return@launch diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt index 3e13f73d..e18a5d08 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt @@ -101,8 +101,10 @@ constructor( // If server has no selected user, navigate to login fragment if (user == null) { jellyfinApi.apply { - api.baseUrl = serverAddress.address - api.accessToken = null + api.update( + baseUrl = serverAddress.address, + accessToken = null, + ) userId = null } appPreferences.currentServer = server.id @@ -111,8 +113,10 @@ constructor( } jellyfinApi.apply { - api.baseUrl = serverAddress.address - api.accessToken = user.accessToken + api.update( + baseUrl = serverAddress.address, + accessToken = user.accessToken, + ) userId = user.id } diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ShowViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ShowViewModel.kt index 5806ebd3..9fe2fe28 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ShowViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/ShowViewModel.kt @@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.jellyfin.sdk.model.api.BaseItemPerson +import org.jellyfin.sdk.model.api.PersonKind import java.util.UUID import javax.inject.Inject @@ -100,7 +101,7 @@ constructor( private suspend fun getActors(item: FindroidShow): List { val actors: List withContext(Dispatchers.Default) { - actors = item.people.filter { it.type == "Actor" } + actors = item.people.filter { it.type == PersonKind.ACTOR } } return actors } @@ -108,7 +109,7 @@ constructor( private suspend fun getDirector(item: FindroidShow): BaseItemPerson? { val director: BaseItemPerson? withContext(Dispatchers.Default) { - director = item.people.firstOrNull { it.type == "Director" } + director = item.people.firstOrNull { it.type == PersonKind.DIRECTOR } } return director } @@ -116,7 +117,7 @@ constructor( private suspend fun getWriters(item: FindroidShow): List { val writers: List withContext(Dispatchers.Default) { - writers = item.people.filter { it.type == "Writer" } + writers = item.people.filter { it.type == PersonKind.WRITER } } return writers } diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/UserSelectViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/UserSelectViewModel.kt index 98a10284..62cdd68e 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/UserSelectViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/UserSelectViewModel.kt @@ -19,7 +19,7 @@ import javax.inject.Inject class UserSelectViewModel @Inject constructor( - private val appPreferences: AppPreferences, + appPreferences: AppPreferences, private val jellyfinApi: JellyfinApi, private val database: ServerDatabaseDao, ) : ViewModel() { @@ -71,7 +71,9 @@ constructor( database.update(server) jellyfinApi.apply { - api.accessToken = user.accessToken + api.update( + accessToken = user.accessToken, + ) userId = user.id } diff --git a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/UsersViewModel.kt b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/UsersViewModel.kt index 26317828..43ce5e74 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/viewmodels/UsersViewModel.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/viewmodels/UsersViewModel.kt @@ -73,7 +73,9 @@ constructor( database.update(server) jellyfinApi.apply { - api.accessToken = user.accessToken + api.update( + accessToken = user.accessToken, + ) userId = user.id } diff --git a/core/src/main/java/dev/jdtech/jellyfin/work/SyncWorker.kt b/core/src/main/java/dev/jdtech/jellyfin/work/SyncWorker.kt index 6fb25a7c..1c43afd5 100644 --- a/core/src/main/java/dev/jdtech/jellyfin/work/SyncWorker.kt +++ b/core/src/main/java/dev/jdtech/jellyfin/work/SyncWorker.kt @@ -40,8 +40,10 @@ class SyncWorker @AssistedInject constructor( val serverAddress = serverWithAddressesAndUsers.addresses.firstOrNull { it.id == server.currentServerAddressId } ?: continue for (user in serverWithAddressesAndUsers.users) { jellyfinApi.apply { - api.baseUrl = serverAddress.address - api.accessToken = user.accessToken + api.update( + baseUrl = serverAddress.address, + accessToken = user.accessToken, + ) userId = user.id } val movies = database.getMoviesByServerId(server.id).map { it.toFindroidMovie(database, user.id) } @@ -66,17 +68,16 @@ class SyncWorker @AssistedInject constructor( try { when (userData.played) { - true -> jellyfinApi.playStateApi.markPlayedItem(user.id, item.id) - false -> jellyfinApi.playStateApi.markUnplayedItem(user.id, item.id) + true -> jellyfinApi.playStateApi.markPlayedItem(item.id, user.id) + false -> jellyfinApi.playStateApi.markUnplayedItem(item.id, user.id) } when (userData.favorite) { - true -> jellyfinApi.userLibraryApi.markFavoriteItem(user.id, item.id) - false -> jellyfinApi.userLibraryApi.unmarkFavoriteItem(user.id, item.id) + true -> jellyfinApi.userLibraryApi.markFavoriteItem(item.id, user.id) + false -> jellyfinApi.userLibraryApi.unmarkFavoriteItem(item.id, user.id) } jellyfinApi.playStateApi.onPlaybackStopped( - userId = user.id, itemId = item.id, positionTicks = userData.playbackPositionTicks, ) diff --git a/core/src/main/res/values-bg/strings.xml b/core/src/main/res/values-bg/strings.xml index 37d2d1fb..cab09c09 100644 --- a/core/src/main/res/values-bg/strings.xml +++ b/core/src/main/res/values-bg/strings.xml @@ -1,8 +1,8 @@ Неподдържана версия на сървъра: %1$s. Моля ъпдейтнете вашия сървър - Сървърът няма id, изглежда, че има нещо не е наред със сървъра - Премахнете сървъра + Сървърът няма id, изглежда, че нещо не е наред със сървъра + Премахване на сървъра Сортирайте по Свалете при роуминг Използвайте експерименталният mpv плейър за да пускане на видеа. mpv поддържа повече кодекси за видео, аудио и субтитри. @@ -13,11 +13,11 @@ Грешно потребителско име или парола Не е Jellyfin сървър: %1$s Сървърът реагира твърде бавно: %1$s - Премахнете - Отменете + Премахване + Отменяне Начало - Свържете се - Влезнете + Свързване + Вход Сигурни ли сте, че искате да премахнете сървъра %1$s Моята медия Адрес на сървъра @@ -27,10 +27,10 @@ Настройки Свалени Вижте всички - Проблем с зареждането на датата + Проблем с зареждането на информацията Опитайте отново Жанрове - Директор + Режисьор Писатели Сезони Пуснете медията @@ -46,7 +46,7 @@ Вие нямате нищо свалено Търсене Език - Предпочитан аудо език + Предпочитан аудио език Предпочитан език на субтитрите Сървъри Плейър @@ -57,7 +57,7 @@ ТВ Предавания Скрийте Ред на сортиране - Свалете с мобилна дата + Свалете с мобилни данни Възходящ mpv плейър Свалете @@ -71,7 +71,7 @@ Проблем при подготовката на елементите на плейъра. Вижте детайли Вижте детайли - За + Описание Политика за поверителност Информация за приложението Непозната грешка @@ -84,95 +84,112 @@ Постер на сериала Няма резултати от търсенето Свалени - Кеширайте снимките на диска за да ускорите времето за зареждане. Ще има ефект след рестартиране на приложението. + Кеширайте снимките на диска, за да ускорите времето за зареждане. Ще има ефект след рестартиране на приложението. Приложението ще използва това количество MB от вашето дисково пространство, за да съхранява изображения от сървъра на Jellyfin. По-големи стойности може да са от полза при по-бавни мрежи. Низходящ [%1$s] %2$s (%3$s) %1$d мин - Tamanho - Buscando - Tempo limite da solicitação (ms) - Saída de áudio + Размер + Търсене + Лимит на заявките (ms) + Изход на аудиото %1$d-%2$d. %3$s S%1$d:E%2$d-%3$d - %4$s - Pano de fundo de %1$s - Usuários - Sem conexão com o servidor Jellyfin, para assistir off-line, ative o modo off-line - Ao usar o Findroid, você concorda com a Política de Privacidade, que afirma que não coletamos quaisquer dados - Aplicativo Jellyfin nativo de terceiros - Cores dinâmicas - Detalhes - Aperte para preencher a tela com o vídeo - Lembre-se do nível de brilho - Deslize para cima e para baixo no lado direito da tela para alterar o volume e no lado esquerdo para alterar o brilho - Classificação IMDB - data adicionada - Buscar incremento de volta (ms) - Saida de video - Requer que o plugin Confused Polar Bears Intro Skipper esteja instalado no servidor - Remover usuário - Tem certeza de que deseja remover o usuário %1$s - Conexão rápida - Exibe informações detalhadas sobre áudio, vídeo e legendas - CC - Temperatura - Ícone do modo off-line - Fique online - Selecione o local de armazenamento - Luz - Use tema AMOLED com fundo preto puro - Siga o sistema - Bibliotecas - Tema escuro AMOLED - Procure gesto - Deslize horizontalmente para avançar ou retroceder - Indicador baixado - Idioma do aplicativo - Episódios - pôster de %1$s - Gestos do jogador - Gestos de volume e brilho - Título - Use cores dinâmicas do Material You (disponível apenas no Android 12+) - Avaliação parental - Data de reprodução - Procure incremento direto (ms) - Legendas - Personalize a aparência das legendas - Rede - Tempo limite do soquete (ms) - Decodificação de hardware - Requer que o plugin Jellyscrub do Nicknsy esteja instalado no servidor - Adicionar endereço - Audio - Vídeo - Exibir informações extras - Externo - %1$s (%2$d MB grátis) - Cancelar transferência - Preparando transferência - Tem certeza de que deseja cancelar a transferência\? - Pare de baixar - O local de armazenamento não está disponível - Interno - Remover endereço do servidor - Tem certeza de que deseja remover o endereço do servidor %1$s - Data de lançamento - Selecione a versão - Escuro - Capitão de introdução - Truque - Endereços - Adicionar endereço do servidor - Gesto de zoom - Tempo limite de conexão (ms) - Adicionar usuário - Adicionar - Imagem em imagem - Gesto inicial picture-in-picture - Use o botão home ou gesto para entrar picture-in-picture enquanto o vídeo está sendo reproduzido - Legendas - Modo offline - Erro ao baixar - Este item requer %1$s de armazenamento gratuito, mas apenas %2$s está disponível + Фон на %1$s + Потребители + Няма връзка към Jellyfin сървъра, за да гледате офлайн пуснете Режим без Интернет + При ползването на Findroid, вие се съгласявате с Политиката за поверителност , която гласи, че не събираме никаква информация + Неофициално приложение за Jellyfin с \"native\" елементи + Динамични цветове + Детайли + Плъзнете с два пръста, за да изпълните екрана + Запомни ниво на яркост + Плъзнете нагоре и надолу на дяснатата страна на екрана, за да промените звука, и на лявата страна, за да промените яркостта + IMDB оценка + Дата Добавен + Инкремент за връщане назад(ms) + Изхода на видеото + Изисква Confused Polar Bears Intro Skipper да бъде инсталиран на сървъра + Премахване на потребител + Сигурни ли сте, че искате да премахнете потребител %1$s + Бързо Свързване + Показва детайлна информация за Аудио, Видео и Субтитри + Затворени субтитри + временно + Режим без Интернет иконка + Свържи се с Интернет + Изберете локация на диска + Светла + Използвайте AMOLED тема с чисто черен фон + Следвай системата + Библиотеки + AMOLED тъмна тема + Жест за търсене + Плъзнете хоризонтално, за да върнете назад или да пропуснете напред + Индикатор за сваленост + Език на приложението + Епизоди + Постер на %1$s + Жестове на плейъра + Жестове за яркост и звук + Заглавие + Използвай динамични Material You цветове (възможно единствено на Android 12+) + Оценка за родителски контрол + Дата пускан + Инкремент за пропускане напред(ms) + Субтитри + Персонализирайте външния вид на субтитрите + Мрежа + Лимит на сокета (ms) + Хардуерно декодиране + Изисква Jellyscrub на nicknsy да бъде инсталиран на сървъра + Добави адрес + Аудио + Видео + Покажи Допълнителна информация + Външно + %1$s (%2$d MB свободни) + Отмени свалянето + Подготвяне на свалянето + Сигурни ли сте, че искате на отмените свалянето? + Спри свалянето + Локацията на диска е недостъпна + Вътрежно + Премахване на адрес на сървър + Сигурни ли сте, че искате да премахнете адреса на сървъра %1$s + Дата на издаване + Изберете версия + Тъмна + Пропускане на интрота + Trick Play + Адреси + Добави адрес на сървър + Жест за приближаване (zoom) + Лимит на свързването (ms) + Добави потребител + Добави + Режим Картина-в-картина + Жест за Режим Картина-в-картина + Използайте Home бутона или жест, за да влезете в режим Картина-в-картина + Субтитри + Режим без Интернет + Грешка при сваляне + Тази медия изисква %1$s свободно място, но има само %2$s свободно + Махни от любими + Тази колекция не съдържа никаква медия + Започни в максимизиран режим + Отвори видео в максимизиран режим по подразбиране + Дълго задържане на Лявата / Дясната страна, за пропускане на глава (отменя жеста за 2x скорост) + Маркери за глави + Показвай маркери за глави на времевата линия + Не са намерени сървъри + Не са намерени потребители + Избери потребител + Телевизия На Живо + Пусни + Маркирай като гледано + Махни маркирано като гледано + Гледай трейлър + Добави към любими + Пропусни глава \ No newline at end of file diff --git a/data/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt b/data/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt index 61858953..f19c318e 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt @@ -4,6 +4,7 @@ import android.content.Context import dev.jdtech.jellyfin.Constants import dev.jdtech.jellyfin.data.BuildConfig import org.jellyfin.sdk.api.client.HttpClientOptions +import org.jellyfin.sdk.api.client.extensions.brandingApi import org.jellyfin.sdk.api.client.extensions.devicesApi import org.jellyfin.sdk.api.client.extensions.itemsApi import org.jellyfin.sdk.api.client.extensions.mediaInfoApi @@ -19,6 +20,8 @@ import org.jellyfin.sdk.api.client.extensions.videosApi import org.jellyfin.sdk.createJellyfin import org.jellyfin.sdk.model.ClientInfo import java.util.UUID +import kotlin.time.DurationUnit +import kotlin.time.toDuration /** * Jellyfin API class using org.jellyfin.sdk:jellyfin-platform-android @@ -40,25 +43,26 @@ class JellyfinApi( } val api = jellyfin.createApi( httpClientOptions = HttpClientOptions( - requestTimeout = requestTimeout, - connectTimeout = connectTimeout, - socketTimeout = socketTimeout, + requestTimeout = requestTimeout.toDuration(DurationUnit.MILLISECONDS), + connectTimeout = connectTimeout.toDuration(DurationUnit.MILLISECONDS), + socketTimeout = socketTimeout.toDuration(DurationUnit.MILLISECONDS), ), ) var userId: UUID? = null + val brandingApi = api.brandingApi val devicesApi = api.devicesApi - val systemApi = api.systemApi - val userApi = api.userApi - val viewsApi = api.userViewsApi val itemsApi = api.itemsApi - val userLibraryApi = api.userLibraryApi - val showsApi = api.tvShowsApi - val sessionApi = api.sessionApi - val videosApi = api.videosApi val mediaInfoApi = api.mediaInfoApi val playStateApi = api.playStateApi val quickConnectApi = api.quickConnectApi + val sessionApi = api.sessionApi + val showsApi = api.tvShowsApi + val systemApi = api.systemApi + val userApi = api.userApi + val userLibraryApi = api.userLibraryApi + val videosApi = api.videosApi + val viewsApi = api.userViewsApi companion object { @Volatile diff --git a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidCollection.kt b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidCollection.kt index 6607011c..d73110e0 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidCollection.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidCollection.kt @@ -25,7 +25,7 @@ data class FindroidCollection( fun BaseItemDto.toFindroidCollection( jellyfinRepository: JellyfinRepository, ): FindroidCollection? { - val type = CollectionType.fromString(collectionType) + val type = CollectionType.fromString(collectionType?.serialName) if (type !in CollectionType.supported) { return null diff --git a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMediaStream.kt b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMediaStream.kt index 8ed130a8..772aa84b 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMediaStream.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMediaStream.kt @@ -3,6 +3,7 @@ package dev.jdtech.jellyfin.models import dev.jdtech.jellyfin.repository.JellyfinRepository import org.jellyfin.sdk.model.api.MediaStream import org.jellyfin.sdk.model.api.MediaStreamType +import org.jellyfin.sdk.model.api.VideoRangeType data class FindroidMediaStream( val title: String, @@ -13,7 +14,7 @@ data class FindroidMediaStream( val isExternal: Boolean, val path: String?, val channelLayout: String?, - val videoRangeType: String?, + val videoRangeType: VideoRangeType?, val height: Int?, val width: Int?, val videoDoViTitle: String?, @@ -46,7 +47,7 @@ fun FindroidMediaStreamDto.toFindroidMediaStream(): FindroidMediaStream { isExternal = isExternal, path = path, channelLayout = channelLayout, - videoRangeType = videoRangeType, + videoRangeType = VideoRangeType.fromNameOrNull(videoRangeType ?: ""), height = height, width = width, videoDoViTitle = videoDoViTitle, diff --git a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMediaStreamDto.kt b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMediaStreamDto.kt index 1be318b2..5a24db18 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMediaStreamDto.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/models/FindroidMediaStreamDto.kt @@ -39,7 +39,7 @@ fun FindroidMediaStream.toFindroidMediaStreamDto(id: UUID, sourceId: String, pat isExternal = isExternal, path = path, channelLayout = channelLayout, - videoRangeType = videoRangeType, + videoRangeType = videoRangeType?.name, height = height, width = width, videoDoViTitle = videoDoViTitle, diff --git a/data/src/main/java/dev/jdtech/jellyfin/models/VideoMetadata.kt b/data/src/main/java/dev/jdtech/jellyfin/models/VideoMetadata.kt index 7395bde1..cbc25f0e 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/models/VideoMetadata.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/models/VideoMetadata.kt @@ -18,8 +18,8 @@ enum class Resolution(val raw: String) { enum class DisplayProfile(val raw: String) { SDR("SDR"), - HDR("HDR"), HDR10("HDR10"), + HDR10_PLUS("HDR10+"), DOLBY_VISION("Vision"), HLG("HLG"), } diff --git a/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt b/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt index f01252df..6a79b74c 100644 --- a/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt +++ b/data/src/main/java/dev/jdtech/jellyfin/repository/JellyfinRepositoryImpl.kt @@ -43,6 +43,8 @@ import org.jellyfin.sdk.model.api.DlnaProfileType import org.jellyfin.sdk.model.api.GeneralCommandType import org.jellyfin.sdk.model.api.ItemFields import org.jellyfin.sdk.model.api.ItemFilter +import org.jellyfin.sdk.model.api.ItemSortBy +import org.jellyfin.sdk.model.api.MediaType import org.jellyfin.sdk.model.api.PlaybackInfoDto import org.jellyfin.sdk.model.api.PublicSystemInfo import org.jellyfin.sdk.model.api.SortOrder @@ -68,38 +70,38 @@ class JellyfinRepositoryImpl( } override suspend fun getItem(itemId: UUID): BaseItemDto = withContext(Dispatchers.IO) { - jellyfinApi.userLibraryApi.getItem(jellyfinApi.userId!!, itemId).content + jellyfinApi.userLibraryApi.getItem(itemId, jellyfinApi.userId!!).content } override suspend fun getEpisode(itemId: UUID): FindroidEpisode = withContext(Dispatchers.IO) { jellyfinApi.userLibraryApi.getItem( - jellyfinApi.userId!!, itemId, + jellyfinApi.userId!!, ).content.toFindroidEpisode(this@JellyfinRepositoryImpl, database)!! } override suspend fun getMovie(itemId: UUID): FindroidMovie = withContext(Dispatchers.IO) { jellyfinApi.userLibraryApi.getItem( - jellyfinApi.userId!!, itemId, + jellyfinApi.userId!!, ).content.toFindroidMovie(this@JellyfinRepositoryImpl, database) } override suspend fun getShow(itemId: UUID): FindroidShow = withContext(Dispatchers.IO) { jellyfinApi.userLibraryApi.getItem( - jellyfinApi.userId!!, itemId, + jellyfinApi.userId!!, ).content.toFindroidShow(this@JellyfinRepositoryImpl) } override suspend fun getSeason(itemId: UUID): FindroidSeason = withContext(Dispatchers.IO) { jellyfinApi.userLibraryApi.getItem( - jellyfinApi.userId!!, itemId, + jellyfinApi.userId!!, ).content.toFindroidSeason(this@JellyfinRepositoryImpl) } @@ -127,7 +129,7 @@ class JellyfinRepositoryImpl( parentId = parentId, includeItemTypes = includeTypes, recursive = recursive, - sortBy = listOf(sortBy.sortString), + sortBy = listOf(ItemSortBy.fromName(sortBy.sortString)), sortOrder = listOf(sortOrder), startIndex = startIndex, limit = limit, @@ -253,7 +255,8 @@ class JellyfinRepositoryImpl( jellyfinApi.showsApi.getNextUp( jellyfinApi.userId!!, limit = 24, - seriesId = seriesId?.toString(), + seriesId = seriesId, + enableResumable = false, ).content.items .orEmpty() .mapNotNull { it.toFindroidEpisode(this@JellyfinRepositoryImpl) } @@ -303,23 +306,10 @@ class JellyfinRepositoryImpl( DirectPlayProfile(type = DlnaProfileType.AUDIO), ), transcodingProfiles = emptyList(), - responseProfiles = emptyList(), subtitleProfiles = listOf( SubtitleProfile("srt", SubtitleDeliveryMethod.EXTERNAL), SubtitleProfile("ass", SubtitleDeliveryMethod.EXTERNAL), ), - xmlRootAttributes = emptyList(), - supportedMediaTypes = "", - enableAlbumArtInDidl = false, - enableMsMediaReceiverRegistrar = false, - enableSingleAlbumArtLimit = false, - enableSingleSubtitleLimit = false, - ignoreTranscodeByteRangeRequests = false, - maxAlbumArtHeight = 1_000_000_000, - maxAlbumArtWidth = 1_000_000_000, - requiresPlainFolders = false, - requiresPlainVideoItems = false, - timelineOffsetSeconds = 0, ), maxStreamingBitrate = 1_000_000_000, ), @@ -444,7 +434,7 @@ class JellyfinRepositoryImpl( Timber.d("Sending capabilities") withContext(Dispatchers.IO) { jellyfinApi.sessionApi.postCapabilities( - playableMediaTypes = listOf("Video"), + playableMediaTypes = listOf(MediaType.VIDEO), supportedCommands = listOf( GeneralCommandType.VOLUME_UP, GeneralCommandType.VOLUME_DOWN, @@ -468,7 +458,7 @@ class JellyfinRepositoryImpl( override suspend fun postPlaybackStart(itemId: UUID) { Timber.d("Sending start $itemId") withContext(Dispatchers.IO) { - jellyfinApi.playStateApi.onPlaybackStart(jellyfinApi.userId!!, itemId) + jellyfinApi.playStateApi.onPlaybackStart(itemId) } } @@ -495,7 +485,6 @@ class JellyfinRepositoryImpl( } try { jellyfinApi.playStateApi.onPlaybackStopped( - jellyfinApi.userId!!, itemId, positionTicks = positionTicks, ) @@ -515,7 +504,6 @@ class JellyfinRepositoryImpl( database.setPlaybackPositionTicks(itemId, jellyfinApi.userId!!, positionTicks) try { jellyfinApi.playStateApi.onPlaybackProgress( - jellyfinApi.userId!!, itemId, positionTicks = positionTicks, isPaused = isPaused, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4e1305f4..67b9580b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,15 +1,15 @@ [versions] -aboutlibraries = "11.2.0" +aboutlibraries = "11.2.1" android-desugar-jdk-libs = "2.0.4" -android-plugin = "8.4.1" +android-plugin = "8.4.2" androidx-activity = "1.9.0" -androidx-appcompat = "1.6.1" -androidx-compose-bom = "2024.05.00" +androidx-appcompat = "1.7.0" +androidx-compose-bom = "2024.06.00" androidx-compose-material3 = "1.2.1" androidx-constraintlayout = "2.1.4" androidx-core = "1.13.1" androidx-hilt = "1.2.0" -androidx-lifecycle = "2.8.0" +androidx-lifecycle = "2.8.2" androidx-media3 = "1.3.1" androidx-navigation = "2.7.7" androidx-paging = "3.3.0" @@ -28,11 +28,11 @@ androidx-work = "2.9.0" coil = "2.6.0" hilt = "2.51.1" compose-destinations = "1.10.2" -jellyfin = "1.4.7" +jellyfin = "1.5.0-beta.3" junit = "4.13.2" kotlin = "2.0.0" -kotlinx-serialization = "1.6.3" -ksp = "2.0.0-1.0.21" +kotlinx-serialization = "1.7.0" +ksp = "2.0.0-1.0.22" ktlint = "12.1.1" libmpv = "0.2.0" material = "1.12.0" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a..a4413138 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a42..b740cf13 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/player/video/src/main/res/values-bg/strings.xml b/player/video/src/main/res/values-bg/strings.xml index 7fc902d3..24051bd4 100644 --- a/player/video/src/main/res/values-bg/strings.xml +++ b/player/video/src/main/res/values-bg/strings.xml @@ -4,15 +4,16 @@ Изберете писта за субтитри Изберете скорост на възпроизвеждане Изберете версия - Externo - Voltar - Retroceder - Bloqueia o reprodutor - Barra de progresso - Avanço rápido - Passe para frente - Truques - Pausa na reprodução - Sair do reprodutor - Insira imagem em imagem + Външно + Пусни предишен + Върни назад + Заключи контролите + Индикарор за прогрес + Пропусни напред + Пусни следващ + Trickplay + Начало пауза + Излез от плейъра + Влез в режим картина-в-картина + Нищо \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 8d13d3f3..8a24003c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") +rootProject.name = "findroid" + include(":app:phone") include(":app:tv") include(":core")