Merge branch 'main' into develop/jellyseerr

This commit is contained in:
Damontecres 2026-01-02 17:07:42 -05:00
commit cf73239c46
No known key found for this signature in database
40 changed files with 1333 additions and 502 deletions

View file

@ -23,8 +23,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.unit.dp
import androidx.datastore.core.DataStore
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.lifecycle.compose.LifecycleEventEffect
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
@ -46,6 +47,7 @@ import com.github.damontecres.wholphin.services.ImageUrlService
import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.PlaybackLifecycleObserver
import com.github.damontecres.wholphin.services.RefreshRateService
import com.github.damontecres.wholphin.services.ServerEventListener
import com.github.damontecres.wholphin.services.SetupDestination
import com.github.damontecres.wholphin.services.SetupNavigationManager
import com.github.damontecres.wholphin.services.UpdateChecker
@ -113,6 +115,14 @@ class MainActivity : AppCompatActivity() {
@Inject
lateinit var tvProviderSchedulerService: TvProviderSchedulerService
// Note: unused but injected to ensure it is created
@Inject
lateinit var serverEventListener: ServerEventListener
// Note: unused but injected to ensure it is created
@Inject
lateinit var datePlayedInvalidationService: DatePlayedInvalidationService
private var signInAuto = true
@OptIn(ExperimentalTvMaterial3Api::class)
@ -232,13 +242,12 @@ class MainActivity : AppCompatActivity() {
var showContent by remember {
mutableStateOf(true)
}
if (!preferences.appPreferences.signInAutomatically) {
LifecycleStartEffect(Unit) {
onStopOrDispose {
showContent = false
}
LifecycleEventEffect(Lifecycle.Event.ON_STOP) {
if (!preferences.appPreferences.signInAutomatically) {
showContent = false
}
}
if (showContent) {
ApplicationContent(
user = current.user,

View file

@ -14,4 +14,5 @@ data class LocalTrailer(
data class RemoteTrailer(
override val name: String,
val url: String,
val subtitle: String?,
) : Trailer

View file

@ -20,6 +20,10 @@ class PlaybackLifecycleObserver
private var wasPlaying: Boolean? = null
override fun onStart(owner: LifecycleOwner) {
val lastDest = navigationManager.backStack.lastOrNull()
if (lastDest is Destination.Playback || lastDest is Destination.PlaybackList) {
navigationManager.goBack()
}
wasPlaying = null
}
@ -40,9 +44,6 @@ class PlaybackLifecycleObserver
}
override fun onStop(owner: LifecycleOwner) {
if (navigationManager.backStack.lastOrNull() is Destination.Playback) {
navigationManager.goBack()
}
themeSongPlayer.stop()
}
}

View file

@ -95,13 +95,13 @@ class RefreshRateService
} catch (ex: InterruptedException) {
Timber.w(ex, "Exception waiting for refresh rate switch")
}
val targetRate = (targetMode.refreshRate * 100).roundToInt()
val targetRate = (targetMode.refreshRate * 1000).roundToInt()
val isSeamless =
targetRate == (display.mode.refreshRate * 100).roundToInt() ||
targetRate == (currentDisplayMode.refreshRate * 1000).roundToInt() ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
display.mode.alternativeRefreshRates
.map { (it * 100).roundToInt() }
.any { targetRate % it == 0 }
currentDisplayMode.alternativeRefreshRates
.map { (it * 1000).roundToInt() }
.any { it % targetRate == 0 }
} else {
false
}

View file

@ -104,7 +104,9 @@ class ThemeSongPlayer
}
fun stop() {
Timber.v("Stopping theme song")
player.stop()
if (player.isPlaying) {
Timber.v("Stopping theme song")
player.stop()
}
}
}

View file

@ -22,31 +22,53 @@ class TrailerService
@param:ApplicationContext private val context: Context,
private val api: ApiClient,
) {
suspend fun getTrailers(item: BaseItem): List<Trailer> {
val remoteTrailers =
item.data.remoteTrailers
?.mapNotNull { t ->
t.url?.let { url ->
val name =
t.name
// TODO would be nice to clean up the trailer name
fun getRemoteTrailers(item: BaseItem): List<Trailer> =
item.data.remoteTrailers
?.mapNotNull { t ->
t.url?.let { url ->
val name =
t.name
// TODO would be nice to clean up the trailer name
// ?.replace(item.name ?: "", "")
// ?.removePrefix(" - ")
?: context.getString(R.string.trailer)
RemoteTrailer(name, url)
}
}.orEmpty()
.sortedBy { it.name }
val localTrailerCount = item.data.localTrailerCount ?: 0
?: context.getString(R.string.trailer)
val subtitle =
when (url.toUri().host) {
"youtube.com", "www.youtube.com" -> "YouTube"
else -> null
}
RemoteTrailer(name, url, subtitle)
}
}.orEmpty()
.sortedWith(
compareBy(
{
// Try to show official trailers first & teasers last
when {
it.name.contains("Official Trailer", true) -> 0
it.name.contains("Official Theatrical Trailer", true) -> 0
it.name.contains("Teaser", true) -> 10
it.name.contains("Trailer", true) -> 1
else -> 5
}
},
{
it.name
},
),
)
suspend fun getLocalTrailers(item: BaseItem): List<Trailer> {
val localTrailerCount = item.data.localTrailerCount ?: return emptyList()
val localTrailers =
if (localTrailerCount > 0) {
api.userLibraryApi.getLocalTrailers(item.id).content.map {
LocalTrailer(BaseItem.Companion.from(it, api))
LocalTrailer(BaseItem.from(it, api))
}
} else {
listOf()
}
return localTrailers + remoteTrailers
return localTrailers
}
companion object {

View file

@ -28,9 +28,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.compose.LifecycleEventEffect
import androidx.media3.common.Player
import coil3.request.ErrorResult
import com.github.damontecres.wholphin.data.model.BaseItem
@ -182,10 +180,10 @@ fun RequestOrRestoreFocus(
debugKey?.let { Timber.v("RequestOrRestoreFocus: %s", it) }
focusRequester.tryRequestFocus()
}
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
debugKey?.let { Timber.v("RequestOrRestoreFocus onResume: %s", it) }
focusRequester.tryRequestFocus()
}
// LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
// debugKey?.let { Timber.v("RequestOrRestoreFocus onResume: %s", it) }
// focusRequester.tryRequestFocus()
// }
}
}

View file

@ -169,6 +169,7 @@ class CollectionFolderViewModel
context.getString(R.string.error_loading_collection, itemId),
) + Dispatchers.IO,
) {
super.itemId = itemId
itemId.toUUIDOrNull()?.let {
fetchItem(it)
}
@ -206,7 +207,7 @@ class CollectionFolderViewModel
) {
if (collectionFilter.useSavedLibraryDisplayInfo) {
serverRepository.currentUser.value?.let { user ->
viewModelScope.launch(Dispatchers.IO) {
viewModelScope.launchIO {
val libraryDisplayInfo =
LibraryDisplayInfo(
userId = user.rowId,

View file

@ -9,6 +9,7 @@ import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
@ -239,47 +240,48 @@ fun DialogPopupContent(
) {
val elevatedContainerColor =
MaterialTheme.colorScheme.surfaceColorAtElevation(elevation)
LazyColumn(
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier =
modifier
// .widthIn(min = 520.dp, max = 300.dp)
// .dialogFocusable()
.graphicsLayer {
this.clip = true
this.shape = RoundedCornerShape(28.0.dp)
}.drawBehind { drawRect(color = elevatedContainerColor) }
.padding(PaddingValues(24.dp)),
) {
stickyHeader {
Text(
text = title,
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSurface,
)
}
items(dialogItems) {
when (it) {
is DialogItemDivider -> {
HorizontalDivider(Modifier.height(16.dp))
}
Text(
text = title,
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSurface,
)
LazyColumn(
modifier = Modifier,
) {
items(dialogItems) {
when (it) {
is DialogItemDivider -> {
HorizontalDivider(Modifier.height(16.dp))
}
is DialogItem -> {
ListItem(
selected = false,
enabled = !waiting && it.enabled,
onClick = {
if (dismissOnClick) {
onDismissRequest.invoke()
}
it.onClick.invoke()
},
headlineContent = it.headlineContent,
overlineContent = it.overlineContent,
supportingContent = it.supportingContent,
leadingContent = it.leadingContent,
trailingContent = it.trailingContent,
modifier = Modifier,
)
is DialogItem -> {
ListItem(
selected = false,
enabled = !waiting && it.enabled,
onClick = {
if (dismissOnClick) {
onDismissRequest.invoke()
}
it.onClick.invoke()
},
headlineContent = it.headlineContent,
overlineContent = it.overlineContent,
supportingContent = it.supportingContent,
leadingContent = it.leadingContent,
trailingContent = it.trailingContent,
modifier = Modifier,
)
}
}
}
}

View file

@ -21,7 +21,10 @@ import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
@ -40,6 +43,7 @@ import androidx.tv.material3.Icon
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.model.Trailer
import com.github.damontecres.wholphin.ui.FontAwesome
import com.github.damontecres.wholphin.ui.PreviewTvSpec
import com.github.damontecres.wholphin.ui.data.SortAndDirection
@ -59,10 +63,12 @@ fun ExpandablePlayButtons(
resumePosition: Duration,
watched: Boolean,
favorite: Boolean,
trailers: List<Trailer>?,
playOnClick: (position: Duration) -> Unit,
watchOnClick: () -> Unit,
favoriteOnClick: () -> Unit,
moreOnClick: () -> Unit,
trailerOnClick: (Trailer) -> Unit,
buttonOnFocusChanged: (FocusState) -> Unit,
modifier: Modifier = Modifier,
) {
@ -134,6 +140,16 @@ fun ExpandablePlayButtons(
)
}
if (trailers != null) {
item("trailers") {
TrailerButton(
trailers = trailers,
trailerOnClick = trailerOnClick,
modifier = Modifier.onFocusChanged(buttonOnFocusChanged),
)
}
}
// More button
item("more") {
ExpandablePlayButton(
@ -229,6 +245,7 @@ fun ExpandableFaButton(
),
contentPadding = DefaultButtonPadding,
interactionSource = interactionSource,
enabled = enabled,
) {
Box(
modifier =
@ -255,6 +272,42 @@ fun ExpandableFaButton(
}
}
@Composable
fun TrailerButton(
trailers: List<Trailer>,
trailerOnClick: (Trailer) -> Unit,
modifier: Modifier = Modifier,
) {
var showDialog by remember { mutableStateOf(false) }
ExpandableFaButton(
title =
if (trailers.isEmpty()) {
R.string.no_trailers
} else if (trailers.size == 1) {
R.string.play_trailer
} else {
R.string.trailers
},
iconStringRes = R.string.fa_film,
enabled = trailers.isNotEmpty(),
onClick = {
if (trailers.size == 1) {
trailerOnClick.invoke(trailers.first())
} else {
showDialog = true
}
},
modifier = modifier,
)
if (showDialog) {
TrailerDialog(
onDismissRequest = { showDialog = false },
trailers = trailers,
onClick = trailerOnClick,
)
}
}
@PreviewTvSpec
@Composable
private fun ExpandablePlayButtonsPreview() {
@ -268,6 +321,8 @@ private fun ExpandablePlayButtonsPreview() {
favoriteOnClick = {},
moreOnClick = {},
buttonOnFocusChanged = {},
trailers = listOf(),
trailerOnClick = {},
modifier = Modifier,
)
}

View file

@ -0,0 +1,51 @@
package com.github.damontecres.wholphin.ui.components
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.res.stringResource
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.model.LocalTrailer
import com.github.damontecres.wholphin.data.model.RemoteTrailer
import com.github.damontecres.wholphin.data.model.Trailer
@Composable
fun TrailerDialog(
onDismissRequest: () -> Unit,
trailers: List<Trailer>,
onClick: (Trailer) -> Unit,
) {
val trailersStr = stringResource(R.string.play_trailer)
val localStr = stringResource(R.string.local)
val externalStr = stringResource(R.string.external_track)
val params =
remember(trailers) {
DialogParams(
fromLongClick = false,
title = trailersStr,
items =
trailers.map { trailer ->
DialogItem(
headlineContent = {
Text(trailer.name)
},
supportingContent = {
val subtitle =
when (trailer) {
is LocalTrailer -> localStr
is RemoteTrailer -> trailer.subtitle ?: externalStr
}
Text(
text = subtitle,
)
},
onClick = { onClick.invoke(trailer) },
)
},
)
}
DialogPopup(
params = params,
onDismissRequest = onDismissRequest,
)
}

View file

@ -196,210 +196,224 @@ fun <T : CardGridItem> CardGrid(
}
}
var longPressing by remember { mutableStateOf(false) }
Row(
// horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier =
modifier
.fillMaxSize()
.onKeyEvent {
if (DEBUG) Timber.d("onKeyEvent: ${it.nativeKeyEvent}")
if (useBackToJump && it.key == Key.Back && it.nativeKeyEvent.isLongPress) {
longPressing = true
val newPosition = previouslyFocusedIndex
if (DEBUG) Timber.d("Back long pressed: newPosition=$newPosition")
if (newPosition > 0) {
focusOn(newPosition)
scope.launch(ExceptionHandler()) {
gridState.scrollToItem(newPosition, -columns)
firstFocus.tryRequestFocus()
}
}
return@onKeyEvent true
} else if (it.type == KeyEventType.KeyUp) {
if (longPressing && it.key == Key.Back) {
longPressing = false
return@onKeyEvent true
}
longPressing = false
}
if (it.type != KeyEventType.KeyUp) {
return@onKeyEvent false
} else if (useBackToJump && it.key == Key.Back && focusedIndex > 0) {
jumpToTop()
return@onKeyEvent true
} else if (isPlayKeyUp(it)) {
val item = pager.getOrNull(focusedIndex)
if (item?.playable == true) {
Timber.v("Clicked play on ${item.id}")
onClickPlay.invoke(focusedIndex, item)
}
return@onKeyEvent true
} else if (useJumpRemoteButtons && isForwardButton(it)) {
jump(jump1)
return@onKeyEvent true
} else if (useJumpRemoteButtons && isBackwardButton(it)) {
jump(-jump1)
return@onKeyEvent true
} else {
return@onKeyEvent false
}
},
) {
if (showJumpButtons && pager.isNotEmpty()) {
JumpButtons(
jump1 = jump1,
jump2 = jump2,
jumpClick = { jump(it) },
modifier = Modifier.align(Alignment.CenterVertically),
if (pager.isEmpty()) {
Box(
contentAlignment = Alignment.Center,
modifier = modifier.fillMaxSize(),
) {
Text(
text = stringResource(R.string.no_results),
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSurface,
textAlign = TextAlign.Center,
)
}
Box(
modifier = Modifier.weight(1f),
) {
LazyVerticalGrid(
columns = GridCells.Fixed(columns),
horizontalArrangement = Arrangement.spacedBy(spacing),
verticalArrangement = Arrangement.spacedBy(spacing),
state = gridState,
contentPadding = PaddingValues(16.dp),
modifier =
Modifier
.fillMaxSize()
.focusGroup()
.focusRestorer(firstFocus)
.focusProperties {
onExit = {
// Leaving the grid, so "forget" the position
// focusedIndex = -1
}
onEnter = {
if (focusedIndex < 0 && gridState.firstVisibleItemIndex <= startPosition) {
focusedIndex = startPosition
} else {
var longPressing by remember { mutableStateOf(false) }
Row(
// horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier =
modifier
.fillMaxSize()
.onKeyEvent {
if (DEBUG) Timber.d("onKeyEvent: ${it.nativeKeyEvent}")
if (useBackToJump && it.key == Key.Back && it.nativeKeyEvent.isLongPress) {
longPressing = true
val newPosition = previouslyFocusedIndex
if (DEBUG) Timber.d("Back long pressed: newPosition=$newPosition")
if (newPosition > 0) {
focusOn(newPosition)
scope.launch(ExceptionHandler()) {
gridState.scrollToItem(newPosition, -columns)
firstFocus.tryRequestFocus()
}
}
},
) {
items(pager.size) { index ->
val mod =
if ((index == focusedIndex) or (focusedIndex < 0 && index == 0)) {
if (DEBUG) Timber.d("Adding firstFocus to focusedIndex $index")
Modifier
.focusRequester(firstFocus)
.focusRequester(gridFocusRequester)
.focusRequester(alphabetFocusRequester)
} else {
Modifier
return@onKeyEvent true
} else if (it.type == KeyEventType.KeyUp) {
if (longPressing && it.key == Key.Back) {
longPressing = false
return@onKeyEvent true
}
longPressing = false
}
val item = pager[index]
cardContent(
item,
{
if (item != null) {
focusedIndex = index
onClickItem.invoke(index, item)
if (it.type != KeyEventType.KeyUp) {
return@onKeyEvent false
} else if (useBackToJump && it.key == Key.Back && focusedIndex > 0) {
jumpToTop()
return@onKeyEvent true
} else if (isPlayKeyUp(it)) {
val item = pager.getOrNull(focusedIndex)
if (item?.playable == true) {
Timber.v("Clicked play on ${item.id}")
onClickPlay.invoke(focusedIndex, item)
}
},
{ if (item != null) onLongClickItem.invoke(index, item) },
mod
.ifElse(index == 0, Modifier.focusRequester(zeroFocus))
.onFocusChanged { focusState ->
if (DEBUG) {
Timber.v(
"$index isFocused=${focusState.isFocused}",
)
return@onKeyEvent true
} else if (useJumpRemoteButtons && isForwardButton(it)) {
jump(jump1)
return@onKeyEvent true
} else if (useJumpRemoteButtons && isBackwardButton(it)) {
jump(-jump1)
return@onKeyEvent true
} else {
return@onKeyEvent false
}
},
) {
if (showJumpButtons && pager.isNotEmpty()) {
JumpButtons(
jump1 = jump1,
jump2 = jump2,
jumpClick = { jump(it) },
modifier = Modifier.align(Alignment.CenterVertically),
)
}
Box(
modifier = Modifier.weight(1f),
) {
LazyVerticalGrid(
columns = GridCells.Fixed(columns),
horizontalArrangement = Arrangement.spacedBy(spacing),
verticalArrangement = Arrangement.spacedBy(spacing),
state = gridState,
contentPadding = PaddingValues(16.dp),
modifier =
Modifier
.fillMaxSize()
.focusGroup()
.focusRestorer(firstFocus)
.focusProperties {
onExit = {
// Leaving the grid, so "forget" the position
// focusedIndex = -1
}
if (focusState.isFocused) {
// Focused, so set that up
focusOn(index)
positionCallback?.invoke(columns, index)
} else if (focusedIndex == index) {
onEnter = {
if (focusedIndex < 0 && gridState.firstVisibleItemIndex <= startPosition) {
focusedIndex = startPosition
}
}
},
) {
items(pager.size) { index ->
val mod =
if ((index == focusedIndex) or (focusedIndex < 0 && index == 0)) {
if (DEBUG) Timber.d("Adding firstFocus to focusedIndex $index")
Modifier
.focusRequester(firstFocus)
.focusRequester(gridFocusRequester)
.focusRequester(alphabetFocusRequester)
} else {
Modifier
}
val item = pager[index]
cardContent(
item,
{
if (item != null) {
focusedIndex = index
onClickItem.invoke(index, item)
}
},
{ if (item != null) onLongClickItem.invoke(index, item) },
mod
.ifElse(index == 0, Modifier.focusRequester(zeroFocus))
.onFocusChanged { focusState ->
if (DEBUG) {
Timber.v(
"$index isFocused=${focusState.isFocused}",
)
}
if (focusState.isFocused) {
// Focused, so set that up
focusOn(index)
positionCallback?.invoke(columns, index)
} else if (focusedIndex == index) {
// savedFocusedIndex = index
// // Was focused on this, so mark unfocused
// focusedIndex = -1
}
},
)
}
},
)
}
}
}
if (pager.isEmpty()) {
if (pager.isEmpty()) {
// focusedIndex = -1
Box(modifier = Modifier.fillMaxSize()) {
Text(
text = stringResource(R.string.no_results),
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.align(Alignment.Center),
)
Box(modifier = Modifier.fillMaxSize()) {
Text(
text = stringResource(R.string.no_results),
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.align(Alignment.Center),
)
}
}
}
if (showFooter) {
// Footer
Box(
modifier =
Modifier
.align(Alignment.BottomCenter)
.background(AppColors.TransparentBlack50),
) {
val index = (focusedIndex + 1).takeIf { it > 0 } ?: "?"
if (showFooter) {
// Footer
Box(
modifier =
Modifier
.align(Alignment.BottomCenter)
.background(AppColors.TransparentBlack50),
) {
val index = (focusedIndex + 1).takeIf { it > 0 } ?: "?"
// if (focusedIndex >= 0) {
// focusedIndex + 1
// } else {
// max(savedFocusedIndex, focusedIndexOnExit) + 1
// }
Text(
modifier = Modifier.padding(4.dp),
color = MaterialTheme.colorScheme.onBackground,
text = "$index / ${pager.size}",
)
Text(
modifier = Modifier.padding(4.dp),
color = MaterialTheme.colorScheme.onBackground,
text = "$index / ${pager.size}",
)
}
}
}
}
val context = LocalContext.current
val letters = context.getString(R.string.jump_letters)
// Letters
val currentLetter =
remember(focusedIndex) {
pager
.getOrNull(focusedIndex)
?.sortName
?.first()
?.uppercaseChar()
?.let {
if (it >= '0' && it <= '9') {
'#'
} else if (it >= 'A' && it <= 'Z') {
it
} else {
null
}
}
?: letters[0]
}
if (showLetterButtons && pager.isNotEmpty()) {
AlphabetButtons(
letters = letters,
currentLetter = currentLetter,
modifier =
Modifier
.align(Alignment.CenterVertically)
.padding(end = 16.dp),
// Add end padding to push away from edge
letterClicked = { letter ->
scope.launch(ExceptionHandler()) {
val jumpPosition =
withContext(Dispatchers.IO) {
letterPosition.invoke(letter)
val context = LocalContext.current
val letters = context.getString(R.string.jump_letters)
// Letters
val currentLetter =
remember(focusedIndex) {
pager
.getOrNull(focusedIndex)
?.sortName
?.first()
?.uppercaseChar()
?.let {
if (it >= '0' && it <= '9') {
'#'
} else if (it >= 'A' && it <= 'Z') {
it
} else {
null
}
Timber.d("Alphabet jump to $jumpPosition")
if (jumpPosition >= 0) {
pager.getOrNull(jumpPosition)
gridState.scrollToItem(jumpPosition)
focusOn(jumpPosition)
alphabetFocus = true
}
}
},
)
?: letters[0]
}
if (showLetterButtons && pager.isNotEmpty()) {
AlphabetButtons(
letters = letters,
currentLetter = currentLetter,
modifier =
Modifier
.align(Alignment.CenterVertically)
.padding(end = 16.dp),
// Add end padding to push away from edge
letterClicked = { letter ->
scope.launch(ExceptionHandler()) {
val jumpPosition =
withContext(Dispatchers.IO) {
letterPosition.invoke(letter)
}
Timber.d("Alphabet jump to $jumpPosition")
if (jumpPosition >= 0) {
pager.getOrNull(jumpPosition)
gridState.scrollToItem(jumpPosition)
focusOn(jumpPosition)
alphabetFocus = true
}
}
},
)
}
}
}
}

View file

@ -27,7 +27,7 @@ abstract class ItemViewModel(
) : ViewModel() {
val item = MutableLiveData<BaseItem?>(null)
lateinit var itemId: String
lateinit var itemUuid: UUID
var itemUuid: UUID? = null
suspend fun fetchItem(itemId: UUID): BaseItem =
withContext(Dispatchers.IO) {

View file

@ -155,8 +155,10 @@ class PersonViewModel
fun setFavorite(favorite: Boolean) {
viewModelScope.launchIO {
favoriteWatchManager.setFavorite(itemUuid, favorite)
fetchAndSetItem(itemUuid)
itemUuid?.let {
favoriteWatchManager.setFavorite(it, favorite)
fetchAndSetItem(it)
}
}
}
}

View file

@ -25,7 +25,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.compose.LifecycleStartEffect
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ChosenStreams
import com.github.damontecres.wholphin.data.model.BaseItem
@ -112,12 +111,12 @@ fun EpisodeDetails(
LoadingState.Success -> {
item?.let { ep ->
LifecycleStartEffect(destination.itemId) {
LifecycleResumeEffect(destination.itemId) {
viewModel.maybePlayThemeSong(
destination.itemId,
preferences.appPreferences.interfacePreferences.playThemeSongs,
)
onStopOrDispose {
onPauseOrDispose {
viewModel.release()
}
}
@ -335,6 +334,8 @@ fun EpisodeDetailsContent(
}
}
},
trailers = null,
trailerOnClick = {},
modifier =
Modifier
.fillMaxWidth()

View file

@ -8,9 +8,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.relocation.bringIntoViewRequester
import androidx.compose.runtime.Composable
@ -23,25 +20,18 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusRestorer
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ChosenStreams
import com.github.damontecres.wholphin.data.ExtrasItem
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.Chapter
import com.github.damontecres.wholphin.data.model.LocalTrailer
import com.github.damontecres.wholphin.data.model.Person
import com.github.damontecres.wholphin.data.model.RemoteTrailer
import com.github.damontecres.wholphin.data.model.Trailer
import com.github.damontecres.wholphin.data.model.aspectRatioFloat
import com.github.damontecres.wholphin.preferences.UserPreferences
@ -143,12 +133,12 @@ fun MovieDetails(
LoadingState.Success -> {
item?.let { movie ->
LifecycleStartEffect(destination.itemId) {
LifecycleResumeEffect(destination.itemId) {
viewModel.maybePlayThemeSong(
destination.itemId,
preferences.appPreferences.interfacePreferences.playThemeSongs,
)
onStopOrDispose {
onPauseOrDispose {
viewModel.release()
}
}
@ -437,6 +427,11 @@ fun MovieDetailsContent(
}
}
},
trailers = trailers,
trailerOnClick = {
position = TRAILER_ROW
trailerOnClick.invoke(it)
},
modifier =
Modifier
.fillMaxWidth()
@ -464,21 +459,6 @@ fun MovieDetailsContent(
)
}
}
if (trailers.isNotEmpty()) {
item {
TrailerRow(
trailers = trailers,
onClickTrailer = {
position = TRAILER_ROW
trailerOnClick.invoke(it)
},
modifier =
Modifier
.fillMaxWidth()
.focusRequester(focusRequesters[TRAILER_ROW]),
)
}
}
if (chapters.isNotEmpty()) {
item {
ChapterRow(
@ -546,78 +526,3 @@ fun MovieDetailsContent(
}
}
}
@Composable
fun TrailerRow(
trailers: List<Trailer>,
onClickTrailer: (Trailer) -> Unit,
modifier: Modifier = Modifier,
) {
val state = rememberLazyListState()
val firstFocus = remember { FocusRequester() }
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier,
) {
Text(
text = stringResource(R.string.trailers),
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onBackground,
)
LazyRow(
state = state,
horizontalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 8.dp),
modifier =
Modifier
.fillMaxWidth()
.focusRestorer(firstFocus),
) {
itemsIndexed(trailers) { index, item ->
val cardModifier =
if (index == 0) {
Modifier.focusRequester(firstFocus)
} else {
Modifier
}
when (item) {
is LocalTrailer -> {
SeasonCard(
item = item.baseItem,
onClick = { onClickTrailer.invoke(item) },
onLongClick = {},
imageHeight = Cards.height2x3,
imageWidth = Dp.Unspecified,
showImageOverlay = false,
modifier = cardModifier,
)
}
is RemoteTrailer -> {
val subtitle =
when (item.url.toUri().host) {
"youtube.com", "www.youtube.com" -> "YouTube"
else -> null
}
SeasonCard(
title = item.name,
subtitle = subtitle,
name = item.name,
imageUrl = null,
isFavorite = false,
isPlayed = false,
unplayedItemCount = 0,
playedPercentage = 0.0,
onClick = { onClickTrailer.invoke(item) },
onLongClick = {},
modifier = cardModifier,
showImageOverlay = false,
imageHeight = Cards.height2x3,
imageWidth = Dp.Unspecified,
)
}
}
}
}
}
}

View file

@ -25,6 +25,7 @@ import com.github.damontecres.wholphin.services.TrailerService
import com.github.damontecres.wholphin.services.UserPreferencesService
import com.github.damontecres.wholphin.ui.SlimItemFields
import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.letNotEmpty
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.setValueOnMain
import com.github.damontecres.wholphin.util.ExceptionHandler
@ -116,16 +117,19 @@ class MovieViewModel
item,
userPreferencesService.getCurrent(),
)
val remoteTrailers = trailerService.getRemoteTrailers(item)
withContext(Dispatchers.Main) {
this@MovieViewModel.item.value = item
chosenStreams.value = result
this@MovieViewModel.trailers.value = remoteTrailers
loading.value = LoadingState.Success
backdropService.submit(item)
}
viewModelScope.launchIO {
val trailers = trailerService.getTrailers(item)
withContext(Dispatchers.Main) {
this@MovieViewModel.trailers.value = trailers
trailerService.getLocalTrailers(item).letNotEmpty { localTrailers ->
withContext(Dispatchers.Main) {
this@MovieViewModel.trailers.value = localTrailers + remoteTrailers
}
}
}
viewModelScope.launchIO {

View file

@ -45,6 +45,8 @@ fun FocusedEpisodeFooter(
watchOnClick = watchOnClick,
favoriteOnClick = favoriteOnClick,
buttonOnFocusChanged = buttonOnFocusChanged,
trailers = null,
trailerOnClick = {},
modifier = Modifier.fillMaxWidth(),
)
}

View file

@ -34,7 +34,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R
@ -62,6 +62,7 @@ import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.components.Optional
import com.github.damontecres.wholphin.ui.components.OverviewText
import com.github.damontecres.wholphin.ui.components.SeriesQuickDetails
import com.github.damontecres.wholphin.ui.components.TrailerButton
import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialog
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialogInfo
@ -70,7 +71,6 @@ import com.github.damontecres.wholphin.ui.detail.PlaylistDialog
import com.github.damontecres.wholphin.ui.detail.PlaylistLoadingState
import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForHome
import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItemsForPerson
import com.github.damontecres.wholphin.ui.detail.movie.TrailerRow
import com.github.damontecres.wholphin.ui.letNotEmpty
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.rememberInt
@ -124,12 +124,12 @@ fun SeriesDetails(
LoadingState.Success -> {
item?.let { item ->
LifecycleStartEffect(destination.itemId) {
LifecycleResumeEffect(destination.itemId) {
viewModel.maybePlayThemeSong(
destination.itemId,
preferences.appPreferences.interfacePreferences.playThemeSongs,
)
onStopOrDispose {
onPauseOrDispose {
viewModel.release()
}
}
@ -411,6 +411,18 @@ fun SeriesDetailsContent(
}
},
)
TrailerButton(
trailers = trailers,
trailerOnClick = trailerOnClick,
modifier =
Modifier.onFocusChanged {
if (it.isFocused) {
scope.launch(ExceptionHandler()) {
bringIntoViewRequester.bringIntoView()
}
}
},
)
}
}
item {
@ -472,21 +484,6 @@ fun SeriesDetailsContent(
)
}
}
if (trailers.isNotEmpty()) {
item {
TrailerRow(
trailers = trailers,
onClickTrailer = {
position = TRAILER_ROW
trailerOnClick.invoke(it)
},
modifier =
Modifier
.fillMaxWidth()
.focusRequester(focusRequesters[TRAILER_ROW]),
)
}
}
if (extras.isNotEmpty()) {
item {
ExtrasRow(

View file

@ -16,11 +16,12 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleStartEffect
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.map
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.ui.RequestOrRestoreFocus
import com.github.damontecres.wholphin.ui.components.DialogParams
import com.github.damontecres.wholphin.ui.components.DialogPopup
import com.github.damontecres.wholphin.ui.components.ErrorMessage
@ -37,7 +38,6 @@ import com.github.damontecres.wholphin.ui.detail.buildMoreDialogItems
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.rememberInt
import com.github.damontecres.wholphin.ui.seasonEpisode
import com.github.damontecres.wholphin.ui.tryRequestFocus
import com.github.damontecres.wholphin.util.LoadingState
import kotlinx.coroutines.flow.update
import kotlinx.serialization.Serializable
@ -158,19 +158,21 @@ fun SeriesOverview(
LoadingState.Success -> {
series?.let { series ->
LaunchedEffect(Unit) {
RequestOrRestoreFocus(
when (rowFocused) {
EPISODE_ROW -> episodeRowFocusRequester.tryRequestFocus()
CAST_AND_CREW_ROW -> castCrewRowFocusRequester.tryRequestFocus()
GUEST_STAR_ROW -> guestStarRowFocusRequester.tryRequestFocus()
}
}
LifecycleStartEffect(destination.itemId) {
EPISODE_ROW -> episodeRowFocusRequester
CAST_AND_CREW_ROW -> castCrewRowFocusRequester
GUEST_STAR_ROW -> guestStarRowFocusRequester
else -> episodeRowFocusRequester
},
"series_overview",
)
LifecycleResumeEffect(destination.itemId) {
viewModel.maybePlayThemeSong(
destination.itemId,
preferences.appPreferences.interfacePreferences.playThemeSongs,
)
onStopOrDispose {
onPauseOrDispose {
viewModel.release()
}
}

View file

@ -49,7 +49,6 @@ import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.Person
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.ui.AspectRatios
import com.github.damontecres.wholphin.ui.RequestOrRestoreFocus
import com.github.damontecres.wholphin.ui.cards.BannerCard
import com.github.damontecres.wholphin.ui.cards.PersonRow
import com.github.damontecres.wholphin.ui.components.ErrorMessage
@ -107,6 +106,7 @@ fun SeriesOverviewContent(
val scrollState = rememberScrollState()
val scrollConnection = rememberDelayedNestedScroll()
var requestFocusAfterSeason by remember { mutableStateOf(false) }
Box(
modifier =
modifier
@ -147,6 +147,7 @@ fun SeriesOverviewContent(
onClick = {
selectedTabIndex = it
onChangeSeason.invoke(it)
requestFocusAfterSeason = true
},
modifier =
Modifier
@ -181,8 +182,14 @@ fun SeriesOverviewContent(
}
is EpisodeList.Success -> {
if (requestFocusAfterSeason) {
// Changing seasons, so move focus once the new episodes are loaded
LaunchedEffect(Unit) {
firstItemFocusRequester.tryRequestFocus()
requestFocusAfterSeason = false
}
}
val state = rememberLazyListState(position.episodeRowIndex)
RequestOrRestoreFocus(firstItemFocusRequester)
LazyRow(
state = state,

View file

@ -165,8 +165,9 @@ class SeriesViewModel
}
}
}
val remoteTrailers = trailerService.getRemoteTrailers(item)
withContext(Dispatchers.Main) {
this@SeriesViewModel.trailers.value = remoteTrailers
this@SeriesViewModel.position.update {
it.copy(
episodeRowIndex =
@ -179,9 +180,10 @@ class SeriesViewModel
}
if (seriesPageType == SeriesPageType.DETAILS) {
viewModelScope.launchIO {
val trailers = trailerService.getTrailers(item)
withContext(Dispatchers.Main) {
this@SeriesViewModel.trailers.value = trailers
trailerService.getLocalTrailers(item).letNotEmpty { localTrailers ->
withContext(Dispatchers.Main) {
this@SeriesViewModel.trailers.value = localTrailers + remoteTrailers
}
}
}
viewModelScope.launchIO {
@ -221,9 +223,6 @@ class SeriesViewModel
) {
viewModelScope.launchIO {
themeSongPlayer.playThemeFor(seriesId, playThemeSongs)
addCloseable {
themeSongPlayer.stop()
}
}
}

View file

@ -234,7 +234,7 @@ fun HomePageContent(
val listState = rememberLazyListState()
val rowFocusRequesters = remember(homeRows.size) { List(homeRows.size) { FocusRequester() } }
var focused by remember { mutableStateOf(false) }
var focused by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(homeRows) {
if (!focused) {
homeRows
@ -246,6 +246,8 @@ fun HomePageContent(
listState.animateScrollToItem(position.row)
focused = true
}
} else {
rowFocusRequesters.getOrNull(position.row)?.tryRequestFocus()
}
}
LaunchedEffect(position) {

View file

@ -157,6 +157,7 @@ class PlaybackViewModel
internal lateinit var item: BaseItem
internal var forceTranscoding: Boolean = false
private var activityListener: TrackActivityPlaybackListener? = null
private val jobs = mutableListOf<Job>()
val nextUp = MutableLiveData<BaseItem?>()
private var isPlaylist = false
@ -166,20 +167,22 @@ class PlaybackViewModel
val subtitleSearchLanguage = MutableLiveData<String>(Locale.current.language)
init {
viewModelScope.launch(ExceptionHandler()) { controllerViewState.observe() }
player.addListener(this)
(player as? ExoPlayer)?.addAnalyticsListener(this)
addCloseable { player.removeListener(this@PlaybackViewModel) }
addCloseable { (player as? ExoPlayer)?.removeAnalyticsListener(this@PlaybackViewModel) }
addCloseable {
player.removeListener(this@PlaybackViewModel)
(player as? ExoPlayer)?.removeAnalyticsListener(this@PlaybackViewModel)
this@PlaybackViewModel.activityListener?.let {
it.release()
player.removeListener(it)
}
jobs.forEach { it.cancel() }
player.release()
}
addCloseable { player.release() }
subscribe()
listenForTranscodeReason()
viewModelScope.launch(ExceptionHandler()) { controllerViewState.observe() }
player.addListener(this)
(player as? ExoPlayer)?.addAnalyticsListener(this)
jobs.add(subscribe())
jobs.add(listenForTranscodeReason())
}
/**
@ -874,7 +877,7 @@ class PlaybackViewModel
}
}
private fun listenForTranscodeReason() {
private fun listenForTranscodeReason(): Job =
viewModelScope.launchIO {
currentPlayback.collectLatest {
if (it != null) {
@ -905,7 +908,6 @@ class PlaybackViewModel
}
}
}
}
private var lastInteractionDate: Date = Date()
@ -1026,11 +1028,13 @@ class PlaybackViewModel
}
fun release() {
Timber.v("release")
activityListener?.release()
player.release()
activityListener = null
}
fun subscribe() {
fun subscribe(): Job =
api.webSocket
.subscribe<PlaystateMessage>()
.onEach { message ->
@ -1085,7 +1089,6 @@ class PlaybackViewModel
}
}
}.launchIn(viewModelScope)
}
/**
* Atomically update [currentMediaInfo]

View file

@ -109,6 +109,7 @@ class MpvPlayer(
Timber.v("config-dir=${context.filesDir.path}")
MPVLib.addLogObserver(mpvLogger)
Timber.v("Creating MPVLib")
MPVLib.create(context)
MPVLib.setOptionString("config", "yes")
MPVLib.setOptionString("config-dir", context.filesDir.path)
@ -127,6 +128,7 @@ class MpvPlayer(
MPVLib.setOptionString("demuxer-max-bytes", "${cacheMegs * 1024 * 1024}")
MPVLib.setOptionString("demuxer-max-back-bytes", "${cacheMegs * 1024 * 1024}")
Timber.v("Initializing MPVLib")
MPVLib.initialize()
MPVLib.setOptionString("force-window", "no")
@ -466,7 +468,6 @@ class MpvPlayer(
override fun clearVideoSurfaceHolder(surfaceHolder: SurfaceHolder?): Unit = throw UnsupportedOperationException()
override fun setVideoSurfaceView(surfaceView: SurfaceView?) {
throwIfReleased()
if (DEBUG) Timber.v("setVideoSurfaceView")
val surface = surfaceView?.holder?.surface
if (surface != null && surface.isValid) {
@ -635,9 +636,9 @@ class MpvPlayer(
val title = it.label ?: "External Subtitles"
Timber.v("Adding external subtitle track '$title'")
if (it.language.isNotNullOrBlank()) {
MPVLib.command(arrayOf("sub-add", url, "auto", title, it.language!!))
MPVLib.command(arrayOf("sub-add", url, "select", title, it.language!!))
} else {
MPVLib.command(arrayOf("sub-add", url, "auto", title))
MPVLib.command(arrayOf("sub-add", url, "select", title))
}
}
}
@ -837,7 +838,18 @@ class MpvPlayer(
override fun handleMessage(msg: Message): Boolean {
val cmd = MpvCommand.entries[msg.what]
Timber.v("handleMessage: cmd=$cmd")
Timber.d("handleMessage: cmd=$cmd")
if (isReleased && cmd != MpvCommand.DESTROY) {
Timber.w("Player is released, ignoring command %s", cmd)
return true
}
if (surface == null && !cmd.isLifecycle) {
// If libmpv isn't ready, re-enqueue the messages
// Note: this means nothing will play until it is attached to a surface,
// so MpvPlayer can't be used for background audio/music playback
Timber.v("MPV is not initialized/attached yet, requeue cmd %s", cmd)
internalHandler.sendMessageDelayed(Message.obtain(msg), 50)
}
when (cmd) {
MpvCommand.PLAY_PAUSE -> {
val playWhenReady = msg.obj as Boolean
@ -894,6 +906,7 @@ class MpvPlayer(
MPVLib.detachSurface()
MPVLib.setPropertyString("vo", "null")
MPVLib.setPropertyString("force-window", "no")
Timber.d("Detached surface")
}
if (surface != null) {
MPVLib.attachSurface(surface)
@ -1035,14 +1048,16 @@ private data class MediaAndPosition(
val startPositionMs: Long,
)
enum class MpvCommand {
PLAY_PAUSE,
SEEK,
SET_TRACK_SELECTION,
SET_SPEED,
SET_SUBTITLE_DELAY,
LOAD_FILE,
ATTACH_SURFACE,
INITIALIZE,
DESTROY,
enum class MpvCommand(
val isLifecycle: Boolean,
) {
PLAY_PAUSE(false),
SEEK(false),
SET_TRACK_SELECTION(false),
SET_SPEED(false),
SET_SUBTITLE_DELAY(false),
LOAD_FILE(false),
ATTACH_SURFACE(true),
INITIALIZE(true),
DESTROY(true),
}

View file

@ -210,7 +210,7 @@ fun createDeviceProfile(
"main",
"baseline",
"constrained baseline",
if (supportsAVCHigh10) "main 10" else null,
if (supportsAVCHigh10) "high 10" else null,
)
}
}

View file

@ -239,7 +239,7 @@
<string name="send_app_logs_summary">Nützlich zum Debuggen</string>
<string name="send_crash_reports">Sende Absturzmeldung</string>
<string name="skip_back_on_resume_preference">Zurückspringen wenn wiedergabe fortgesetzt wird</string>
<string name="skip_commercials_behavior">Überspringe Werbung verhalten</string>
<string name="skip_commercials_behavior">Werbung überspringen</string>
<string name="skip_forward_preference">Vorspringen</string>
<string name="skip_intro_behavior">Überspringe Intro verhalten</string>
<string name="skip_outro_behavior">Überspringe Outro verhalten</string>
@ -286,4 +286,39 @@
<string name="remove">Entfernen</string>
<string name="dolby_vision">Dolby Vision</string>
<string name="dolby_atmos">Dolby Atmos</string>
<string name="ends_at">Endet um %1$s</string>
<string name="enter_server_address">Server Adresse eingeben</string>
<string name="no_servers_found">Keine Server gefunden</string>
<string name="media_information">Medieninformation</string>
<string name="played">Abgespielt</string>
<string name="mpv_use_gpu_next">MPV: Benutze gpu-next</string>
<string name="mpv_conf">mpv.conf bearbeiten</string>
<string name="discard_change">Änderungen verwerfen?</string>
<string name="subtitle_margin">Abstand</string>
<string name="enter_pin">PIN Eingeben</string>
<string name="sign_in_auto">Automatisch anmelden</string>
<string name="require_pin_code">Profil benötigt PIN</string>
<string name="confirm_pin">PIN bestätigen</string>
<string name="incorrect">Falsch</string>
<string name="pin_too_short">PIN muss 4 Zeichen oder länger sein</string>
<string name="will_remove_pin">PIN wird entfernt</string>
<string name="view_options">Anzeigeoptionen</string>
<string name="columns">Spalten</string>
<string name="spacing">Abstände</string>
<string name="aspect_ratio">Seitenverhältnis</string>
<string name="show_details">Details anzeigen</string>
<string name="image_type">Bild Typ</string>
<string name="automatic">Automatisch</string>
<string name="username_or_password">Verwende Benutzername/Passwort</string>
<string name="login">Anmelden</string>
<string name="title">Titel</string>
<string name="profile">Profil</string>
<string name="resolution">Auflösung</string>
<string name="framerate">Bildrate</string>
<string name="language">Sprache</string>
<string name="channels">Kanäle</string>
<string name="yes">Ja</string>
<string name="no">Nein</string>
<string name="show_titles">Titel anzeigen</string>
<string name="live_tv_repeat">Wiederholen</string>
</resources>

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="add_favorite">Favorito</string>
<string name="add_server">Agregar servidor</string>
<string name="add_user">Agregar usuario</string>
<string name="add_favorite">Añadir a Favoritos</string>
<string name="add_server">Añadir servidor</string>
<string name="add_user">Añadir usuario</string>
<string name="audio">Audio</string>
<string name="birthplace">Lugar de nacimiento</string>
<string name="bitrate">Tasa de bits</string>
@ -170,8 +170,8 @@
</plurals>
<plurals name="theme_songs">
<item quantity="one">Canciones principales</item>
<item quantity="many"></item>
<item quantity="other"></item>
<item quantity="many"/>
<item quantity="other"/>
</plurals>
<plurals name="theme_videos">
<item quantity="one">Vídeos temáticos</item>
@ -303,4 +303,76 @@
<string name="font">Fuente</string>
<string name="background">Fondo</string>
<string name="official_rating">Clasificación parental</string>
<string name="ends_at">Termina en %1$s</string>
<string name="enter_server_address">Introduzca la dirección del servidor</string>
<string name="no_servers_found">No se encontraron servidores</string>
<string name="media_information">Información multimedia</string>
<string name="mpv_use_gpu_next">MPV: Usar gpu-next</string>
<string name="mpv_conf">Editar mpv.conf</string>
<string name="discard_change">¿Descartar los cambios?</string>
<string name="subtitle_margin">Margen</string>
<string name="verbose_logging">Registro detallado</string>
<string name="enter_pin">Introducir PIN</string>
<string name="sign_in_auto">Iniciar sesión automáticamente</string>
<string name="use_server_credentials">Iniciar sesión a través del servidor</string>
<string name="press_enter_to_confirm">Pulsa el centro para confirmar</string>
<string name="require_pin_code">Requerir PIN para el perfil</string>
<string name="confirm_pin">Confirmar PIN</string>
<string name="incorrect">Incorrecto</string>
<string name="pin_too_short">El PIN debe tener 4 teclas o más</string>
<string name="will_remove_pin">Se eliminará el PIN</string>
<string name="image_cache_size">Tamaño de la caché de disco de imágenes (MB)</string>
<string name="view_options">Opciones de visualización</string>
<string name="columns">Columnas</string>
<string name="spacing">Espaciado</string>
<string name="aspect_ratio">Relación de aspecto</string>
<string name="show_details">Mostrar detalles</string>
<string name="image_type">Tipo de imagen</string>
<string name="cast_and_crew"><![CDATA[Reparto y equipo]]></string>
<string name="guest_stars">Estrellas invitadas</string>
<string name="edge_size">Tamaño del borde</string>
<string name="refresh_rate_switching">Cambio de frecuencia de actualización</string>
<string name="automatic">Automático</string>
<string name="username_or_password">Usar nombre de usuario/contraseña</string>
<string name="login">Iniciar sesión</string>
<string name="general">General</string>
<string name="container">Contenedor</string>
<string name="title">Título</string>
<string name="codec">Codec</string>
<string name="profile">Perfil</string>
<string name="level">Nivel</string>
<string name="resolution">Resolución</string>
<string name="anamorphic">Anamórfico</string>
<string name="interlaced">Entrelazado</string>
<string name="framerate">Frecuencia de fotogramas</string>
<string name="bit_depth">Profundidad de bits</string>
<string name="video_range">Rango de vídeo</string>
<string name="video_range_type">Tipo de rango de vídeo</string>
<string name="color_space">Espacio de color</string>
<string name="color_transfer">Transferencia de color</string>
<string name="color_primaries">Primarias de color</string>
<string name="pixel_format">Formato de píxel</string>
<string name="ref_frames">Fotogramas de referencia</string>
<string name="nal">NAL</string>
<string name="language">Idioma</string>
<string name="layout">Distribución</string>
<string name="channels">Canales</string>
<string name="sample_rate">Frecuencia de muestreo</string>
<string name="avc">AVC</string>
<string name="yes"></string>
<string name="no">No</string>
<string name="sdr">SDR</string>
<string name="hdr">HDR</string>
<string name="hdr10">HDR10</string>
<string name="hdr10_plus">HDR10+</string>
<string name="hlg">HLG</string>
<string name="bit_unit">bit</string>
<string name="sample_rate_unit">Hz</string>
<string name="show_titles">Mostrar títulos</string>
<string name="live_tv_repeat">Repetir</string>
<string name="favorite_channels_at_beginning">Mostrar primero los canales favoritos</string>
<string name="sort_channels_recently_watched">Ordenar los canales por vistos recientemente</string>
<string name="color_code_programs">Programas codificados por colores</string>
<string name="subtitle_delay">Retardo de subtítulos</string>
<string name="backdrop_display">Estilo del fondo</string>
</resources>

View file

@ -358,4 +358,5 @@
<string name="enter_server_address">Sisesta serveri aadress</string>
<string name="no_servers_found">Ühtegi serverit ei leidu</string>
<string name="backdrop_display">Tausta dekoratsioon</string>
<string name="ends_at">Lõppeb kell %1$s</string>
</resources>

View file

@ -370,4 +370,9 @@
<string name="ref_frames">Images de référence</string>
<string name="sort_channels_recently_watched">Trier les chaînes par date de visionnage</string>
<string name="color_code_programs">Classer les programmes par code couleur</string>
<string name="ends_at">Terminera à %1$s</string>
<string name="enter_server_address">Entrez l\'adresse du serveur</string>
<string name="no_servers_found">Aucun serveur trouvé</string>
<string name="subtitle_delay">Décalage des sous-titres</string>
<string name="backdrop_display">Style d\'arrière-plan</string>
</resources>

View file

@ -1,36 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="about">Névjegy</string>
<string name="add_favorite">Kedvenc</string>
<string name="add_favorite">Hozzáadás kedvencekhez</string>
<string name="add_server">Szerver hozzáadása</string>
<string name="add_user">Felhasználó hozzáadása</string>
<string name="audio">Audio</string>
<string name="audio">Hang</string>
<string name="birthplace">Születési hely</string>
<string name="bitrate">Bitráta</string>
<string name="born">Született</string>
<string name="cancel">Mégse</string>
<string name="chapters">Fejezetek</string>
<string name="choose_stream">Válassz %1$s</string>
<string name="clear_image_cache">Kép gyorsítótár törlése</string>
<string name="choose_stream">%1$s kiválasztása</string>
<string name="clear_image_cache">Képgyorsítótár törlése</string>
<string name="collection">Gyűjtemény</string>
<string name="collections">Gyűjtemények</string>
<string name="community_rating">Közösségi értékelés</string>
<string name="compose_error_message_title">Hiba történt! Nyomd meg a gombot, hogy elküldd a naplófájlokat a szervernek.</string>
<string name="compose_error_message_title">Hiba történt! Nyomja meg a gombot, hogy elküldje a naplófájlokat a szervernek.</string>
<string name="confirm">Megerősít</string>
<string name="critic_rating">Kritikusi értékelés</string>
<string name="decimal_seconds">%.1f másodperc</string>
<string name="default_track">Alapértelmezett</string>
<string name="delete">Törlés</string>
<string name="directed_by">Rendezte %1$s</string>
<string name="directed_by">Rendezte: %1$s</string>
<string name="director">Rendező</string>
<string name="disabled">Letiltva</string>
<string name="discovered_servers">Felfedezett szerverek</string>
<string name="download_and_update"><![CDATA[Letöltés & Frissítés]]></string>
<string name="downloading">Letöltés folyamatban…</string>
<string name="enabled">Engedélyezve</string>
<string name="enter_server_url">Add meg a szerver IP-t vagy URL-t</string>
<string name="enter_server_url">Adja meg a szerver IP-t vagy URL-t</string>
<string name="episodes">Epizódok</string>
<string name="error_loading_collection">Hiba a gyűjtemény betöltése során: %1$s</string>
<string name="error_loading_collection">Hiba a következő gyűjtemény betöltése során: %1$s</string>
<string name="external_track">Külső</string>
<string name="favorites">Kedvencek</string>
<string name="active_recordings">Aktív felvételek</string>
@ -38,28 +38,28 @@
<string name="cancel_series_recording">Sorozatfelvétel leállítása</string>
<string name="commercial">Reklám</string>
<string name="continue_watching">Megtekintés folytatása</string>
<string name="died">Halott</string>
<string name="died">Elhunyt</string>
<string name="file_size">Méret</string>
<string name="forced_track">Kényszerített</string>
<string name="forced_track">Kiegészítő</string>
<string name="genres">Műfajok</string>
<string name="go_to_series">Ugrás a sorozathoz</string>
<string name="go_to">Ugrás</string>
<string name="go_to">Ugrás ide:</string>
<string name="hide_controller_timeout">Lejátszási gombok elrejtése</string>
<string name="hide_debug_info">Hibajavítási infó elrejtése</string>
<string name="hide_debug_info">Hibakeresési infó elrejtése</string>
<string name="hide">Elrejt</string>
<string name="home">Kezdőlap</string>
<string name="immediate">Azonnal</string>
<string name="intro">Intro</string>
<string name="intro">Intró</string>
<string name="jump_letters">#ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
<string name="library">Könyvtár</string>
<string name="license_info">Lincenc információk</string>
<string name="live_tv">Élő TV</string>
<string name="loading">Betöltés…</string>
<string name="mark_entire_series_as_played">Megjelölöd az egész sorozatot megnézettként?</string>
<string name="mark_entire_series_as_unplayed">Megjelölöd az egész sorozatot megnézetlenként?</string>
<string name="mark_entire_series_as_played">Megjelöli az egész sorozatot megnézettként?</string>
<string name="mark_entire_series_as_unplayed">Megjelöli az egész sorozatot megnézetlenként?</string>
<string name="mark_unwatched">Jelölés megnézetlenként</string>
<string name="mark_watched">Jelölés megnézettként</string>
<string name="max_bitrate">Max bitráta</string>
<string name="max_bitrate">Maximális bitráta</string>
<string name="more_like_this">Hasonlóak</string>
<string name="more">Továbbiak</string>
<string name="movies">Filmek</string>
@ -70,15 +70,15 @@
<string name="no_scheduled_recordings">Nincs időzített felvétel</string>
<string name="no_update_available">Nincs elérhető frissítés</string>
<string name="none">Nincs</string>
<string name="outro">Outro</string>
<string name="outro">Stáblista</string>
<string name="path">Elérési út</string>
<string name="people">Emberek</string>
<string name="people">Stábtagok</string>
<string name="play_count">Lejátszások száma</string>
<string name="play_from_here">Lejátszás innen</string>
<string name="play">Lejátszás</string>
<string name="playback_debug_info">Lejátszás hibakeresési adatainak mutatása</string>
<string name="playback_speed">Lejátszási sebesség</string>
<string name="playback">Visszajátszás</string>
<string name="playback">Lejátszás</string>
<string name="playlist">Lejátszási lista</string>
<string name="playlists">Lejátszási listák</string>
<string name="preview">Előnézet</string>
@ -87,9 +87,9 @@
<string name="recently_added_in">Nemrég hozzáadva: %1$s</string>
<string name="recently_added">Nemrég hozzáadott</string>
<string name="recently_recorded">Nemrég rögzített</string>
<string name="recently_released">Nemrég kiadott</string>
<string name="recently_released">Nemrég megjelent</string>
<string name="recommended">Ajánlott</string>
<string name="record_program">Program felvétele</string>
<string name="record_program">Műsor felvétele</string>
<string name="record_series">Sorozat felvétele</string>
<string name="remove_favorite">Törlés a kedvencekből</string>
<string name="restart">Újraindítás</string>
@ -100,117 +100,263 @@
<string name="searching">Keresés…</string>
<string name="select_server">Szerver kiválasztása</string>
<string name="select_user">Felhasználó kiválasztása</string>
<string name="show_debug_info">Hibakeresési info megjelenítése</string>
<string name="show_debug_info">Hibakeresési infó megjelenítése</string>
<string name="show_next_up_when">Következő mutatása</string>
<string name="show">Megmutat</string>
<string name="shuffle">Véletlenszerű</string>
<string name="skip">Átugrás</string>
<string name="sort_by_date_added">Hozzáadva</string>
<string name="sort_by_date_added">Hozzáadás dátuma</string>
<string name="sort_by_date_episode_added">Epizód hozzáadásának dátuma</string>
<string name="sort_by_date_played">Lejátszás dátuma</string>
<string name="sort_by_date_released">Megjelenés dátuma</string>
<string name="sort_by_name">Név</string>
<string name="sort_by_random">Random</string>
<string name="sort_by_random">Véletlenszerűen</string>
<string name="studios">Stúdiók</string>
<string name="submit">Beküld</string>
<string name="subtitle_download_too_long">A letöltés sok időt vesz igénybe, előfordulhat, hogy újra kell indítanod a lejátszást</string>
<string name="subtitle_download_too_long">A letöltés sok időt vesz igénybe, előfordulhat, hogy újra kell indítani a lejátszást</string>
<string name="subtitle">Felirat</string>
<string name="subtitles">Feliratok</string>
<string name="suggestions">Ajánlások</string>
<string name="switch_servers">Váltás szerverek között</string>
<string name="switch_servers">Váltás másik szerverre</string>
<string name="switch_user">Váltás</string>
<string name="top_unwatched">Legjobbra értékelt nem megtekintett</string>
<string name="top_unwatched">Legjobbra értékelt, nem megnézett</string>
<string name="trailer">Előzetes</string>
<plurals name="trailers">
<item quantity="one">Előzetesek</item>
<item quantity="other"></item>
<item quantity="other"/>
</plurals>
<string name="tv_dvr_schedule">DVR Időzítés</string>
<string name="tv_guide">Műsorújság</string>
<string name="tv_season">Évad</string>
<string name="tv_seasons">Évadok</string>
<string name="tv_shows">Sorozatok</string>
<string name="ui_interface">Felület</string>
<string name="ui_interface">Kezelőfelület</string>
<string name="unknown">Ismeretlen</string>
<string name="updates">Frissítések</string>
<string name="version">Verzió</string>
<string name="video_scale">Képarány</string>
<string name="video_scale">Kép méretezése</string>
<string name="video">Videó</string>
<string name="videos">Videók</string>
<string name="watch_live">Nézd élőben</string>
<string name="watch_live">Nézze élőben</string>
<string name="years_old">%1$d éves</string>
<string name="play_with_transcoding">Lejátszás átalakítással</string>
<string name="show_clock">Aktuális idő mutatása</string>
<string name="aired_episode_order">Sorrend epízód vetítése alapján</string>
<string name="aired_episode_order">Sorrend epizód vetítése alapján</string>
<string name="create_playlist">Új lejátszási lista létrehozása</string>
<string name="add_to_playlist">Hozzáadás lejátszási listához</string>
<string name="one_click_pause">Szüneteltetés egy klikkel</string>
<string name="one_click_pause_summary_on">Nyomd a D-Pad közepét megállításhoz/lejátszáshoz</string>
<string name="one_click_pause_summary_on">Nyomja le a D-Pad közepét megállításhoz/lejátszáshoz</string>
<string name="italic_font">Dőlt betűk</string>
<string name="font">Betűtípus</string>
<string name="background">Háttérszín</string>
<string name="font">Betűk stílusa</string>
<string name="background">Háttér</string>
<string name="success">Sikeres</string>
<string name="official_rating">Szülői besorolás</string>
<string name="runtime_sort">Műsoridő</string>
<string name="official_rating">Korhatár-besorolás</string>
<string name="runtime_sort">Hossz</string>
<string name="extras">Extrák</string>
<plurals name="other_extras">
<item quantity="one">Egyéb</item>
<item quantity="other"></item>
<item quantity="other">Egyebek</item>
</plurals>
<plurals name="behind_the_scenes">
<item quantity="one">Színfalak mögött</item>
<item quantity="other"></item>
<item quantity="other"/>
</plurals>
<plurals name="theme_songs">
<item quantity="one">Téma zenék</item>
<item quantity="other"></item>
<item quantity="one">Főcímdal</item>
<item quantity="other">Főcímdalok</item>
</plurals>
<plurals name="theme_videos">
<item quantity="one">Téma videók</item>
<item quantity="other"></item>
<item quantity="one">Téma videó</item>
<item quantity="other">Téma videók</item>
</plurals>
<plurals name="clips">
<item quantity="one">Klippek</item>
<item quantity="other"></item>
<item quantity="one">Klip</item>
<item quantity="other">Klipek</item>
</plurals>
<plurals name="deleted_scenes">
<item quantity="one">Törölt jelenetek</item>
<item quantity="other"></item>
<item quantity="one">Törölt jelenet</item>
<item quantity="other">Törölt jelenetek</item>
</plurals>
<plurals name="interviews">
<item quantity="one">Interjúk</item>
<item quantity="other"></item>
<item quantity="one">Interjú</item>
<item quantity="other">Interjúk</item>
</plurals>
<plurals name="scenes">
<item quantity="one">Jelenetek</item>
<item quantity="other"></item>
<item quantity="one">Jelenet</item>
<item quantity="other">Jelenetek</item>
</plurals>
<plurals name="samples">
<item quantity="one">Minták</item>
<item quantity="other"></item>
<item quantity="one">Minta</item>
<item quantity="other">Minták</item>
</plurals>
<plurals name="featurettes">
<item quantity="one">Rövidfilmek</item>
<item quantity="other"></item>
<item quantity="one">Rövidfilm</item>
<item quantity="other">Rövidfilmek</item>
</plurals>
<plurals name="shorts">
<item quantity="one">Rövidek</item>
<item quantity="other"></item>
<item quantity="one">Rövid</item>
<item quantity="other">Rövidek</item>
</plurals>
<plurals name="downloads">
<item quantity="one">%s letöltés</item>
<item quantity="other">%s letöltések</item>
<item quantity="other">%s letöltés</item>
</plurals>
<plurals name="hours">
<item quantity="one">%d óra</item>
<item quantity="other">%d órák</item>
<item quantity="other">%d óra</item>
</plurals>
<plurals name="items">
<item quantity="one">%d elem</item>
<item quantity="other">%d elemek</item>
<item quantity="other">%d elem</item>
</plurals>
<plurals name="seconds">
<item quantity="one">%d másodperc</item>
<item quantity="other">%d másodpercek</item>
<item quantity="other">%d másodperc</item>
</plurals>
<string name="ends_at">%1$s-kor ér véget</string>
<string name="no_servers_found">Nem található szerver</string>
<string name="recap">Összefoglaló</string>
<string name="media_information">Médiainformáció</string>
<string name="ac3_supported">A készülék támogatja az AC3/Dolby Digital formátumot</string>
<string name="advanced_settings">Haladó beállítások</string>
<string name="advanced_ui">Haladó kezelőfelület-beállítások</string>
<string name="app_theme">Alkalmazás témája</string>
<string name="auto_check_for_updates">Frissítések automatikus keresése</string>
<string name="auto_play_next_delay">Késleltetés a következő elem lejátszása előtt</string>
<string name="auto_play_next">Következő elem automatikus lejátszása</string>
<string name="check_for_updates">Frissítések keresése</string>
<string name="combine_continue_next_summary">Csak sorozatok esetén</string>
<string name="direct_play_ass">ASS feliratok közvetlen lejátszása</string>
<string name="direct_play_pgs">PGS feliratok közvetlen lejátszása</string>
<string name="downmix_stereo">Mindig konvertálja sztereóvá</string>
<string name="ffmpeg_extension_pref">FFmpeg dekóder modul használata</string>
<string name="global_content_scale">Tartalom alapértelmezett méretezése</string>
<string name="install_update">Frissítés telepítése</string>
<string name="installed_version">Telepített verzió</string>
<string name="max_homepage_items">Maximális elemek soronként a kezdőlapon</string>
<string name="nav_drawer_pins_summary">Válassza ki az alapértelmezett elemeket, amelyek megjelennek, a többi el lesz rejtve</string>
<string name="nav_drawer_pins">Navigációs menü elemeinek testreszabása</string>
<string name="nav_drawer_switch_on_focus_summary_off">Kattintson az oldalak közti váltáshoz</string>
<string name="pass_out_protection">Automatikus leállítás inaktivitás esetén</string>
<string name="play_theme_music">Főcímdal lejátszása</string>
<string name="remember_selected_tab">Kiválasztott lapok megjegyzése</string>
<string name="rewatch_next_up">Újranézés engedélyezése a Következő menüben</string>
<string name="seek_bar_steps">Előre/hátra ugrás intervallum</string>
<string name="send_app_logs_summary">Hibakereséshez hasznos</string>
<string name="send_app_logs">Naplófájlok küldése a jelenlegi szerverre</string>
<string name="send_crash_reports_summary">Megpróbálja elküldeni az legutóbb csatlakozott szerverre</string>
<string name="send_crash_reports">Összeomlási napló küldése</string>
<string name="settings">Beállítások</string>
<string name="skip_back_on_resume_preference">Visszaugrás a lejátszás folytatásakor</string>
<string name="skip_back_preference">Visszaugrás</string>
<string name="skip_commercials_behavior">Reklám-átugrás viselkedés</string>
<string name="skip_forward_preference">Előreugrás</string>
<string name="skip_intro_behavior">Intró-átugrás viselkedés</string>
<string name="skip_outro_behavior">Stáblista-átugrás viselkedés</string>
<string name="skip_previews_behavior">Előzetes-átugrás viselkedés</string>
<string name="skip_recap_behavior">Összefoglaló-átugrás viselkedés</string>
<string name="update_available">Frissítés érhető el</string>
<string name="update_url_summary">Az alkalmazás frissítéseinek ellenőrzésére használt URL</string>
<string name="update_url">Frissítés URL</string>
<string name="font_size">Betűméret</string>
<string name="font_color">Betűszín</string>
<string name="font_opacity">Betűk áttetszősége</string>
<string name="edge_style">Szegély stílusa</string>
<string name="edge_color">Szegély színe</string>
<string name="background_opacity">Háttér áttetszősége</string>
<string name="background_style">Háttér típusa</string>
<string name="subtitle_style">Felirat stílusa</string>
<string name="background_color">Háttér színe</string>
<string name="reset">Visszaállítás</string>
<string name="bold_font">Félkövér betűk</string>
<string name="mpv_hardware_decoding">MPV: hardveres dekódolás használata</string>
<string name="disable_if_crash">Tiltsa le, ha összeomlást tapasztal</string>
<string name="mpv_options">MPV beállítások</string>
<string name="exoplayer_options">ExoPlayer beállítások</string>
<string name="skip_segment_unknown">Szegmens átugrása</string>
<string name="skip_segment_commercial">Reklám átugrása</string>
<string name="skip_segment_preview">Előzetes átugrása</string>
<string name="skip_segment_recap">Összefoglaló átugrása</string>
<string name="skip_segment_outro">Stáblista átugrása</string>
<string name="skip_segment_intro">Intró átugrása</string>
<string name="played">Lejátszott</string>
<string name="filter">Szűrő</string>
<string name="year">Év</string>
<string name="decade">Évtized</string>
<string name="remove">Eltávolítás</string>
<string name="dolby_vision">Dolby Vision</string>
<string name="dolby_atmos">Dolby Atmos</string>
<string name="mpv_use_gpu_next">MPV: gpu-next használata</string>
<string name="mpv_conf">mpv.conf szerkesztése</string>
<string name="discard_change">Elveti a változtatásokat?</string>
<string name="subtitle_margin">Függőleges eltolás</string>
<string name="verbose_logging">Részletes naplózás</string>
<string name="enter_pin">Adja meg a PIN-kódot</string>
<string name="sign_in_auto">Automatikus bejelentkezés</string>
<string name="use_server_credentials">Bejelentkezés szerveren keresztül</string>
<string name="press_enter_to_confirm">Nyomja meg a középső gombot a megerősítéshez</string>
<string name="require_pin_code">Kérjen PIN-kódot a profillal történő bejelentkezéshez</string>
<string name="confirm_pin">PIN-kód megerősítése</string>
<string name="incorrect">Helytelen</string>
<string name="pin_too_short">A PIN-kódnak legalább 4 karakterből kell állnia</string>
<string name="will_remove_pin">PIN-kód eltávolítása</string>
<string name="view_options">Nézetbeállítások</string>
<string name="columns">Oszlopok</string>
<string name="spacing">Helyköz</string>
<string name="aspect_ratio">Képarány</string>
<string name="show_details">Részletek mutatása</string>
<string name="image_type">Kép típusa</string>
<string name="guest_stars">Vendégszereplők</string>
<string name="edge_size">Szegély mérete</string>
<string name="refresh_rate_switching">Tartalomhoz igazodó képfrissítési gyakoriság</string>
<string name="automatic">Automatikus</string>
<string name="username_or_password">Felhasználónév/jelszó használata</string>
<string name="login">Bejelentkezés</string>
<string name="general">Általános</string>
<string name="container">Konténer</string>
<string name="title">Cím</string>
<string name="codec">Kodek</string>
<string name="profile">Profil</string>
<string name="level">Szint</string>
<string name="resolution">Felbontás</string>
<string name="anamorphic">Anamorfikus</string>
<string name="interlaced">Váltottsoros</string>
<string name="framerate">Képfrissítés</string>
<string name="bit_depth">Színmélység</string>
<string name="video_range">Feketeszint tartomány</string>
<string name="video_range_type">Feketeszint tartomány típusa</string>
<string name="color_space">Színtér</string>
<string name="color_transfer">Színátviteli jellemző</string>
<string name="color_primaries">Alapszínek</string>
<string name="pixel_format">Pixelformátum</string>
<string name="ref_frames">Referencia-képkockák</string>
<string name="nal">NAL</string>
<string name="language">Nyelv</string>
<string name="layout">Elrendezés</string>
<string name="channels">Csatornák</string>
<string name="sample_rate">Mintavételezés</string>
<string name="avc">AVC</string>
<string name="yes">Igen</string>
<string name="no">Nem</string>
<string name="sdr">SDR</string>
<string name="hdr">HDR</string>
<string name="hdr10">HDR10</string>
<string name="hdr10_plus">HDR10+</string>
<string name="hlg">HLG</string>
<string name="bit_unit">bit</string>
<string name="sample_rate_unit">Hz</string>
<string name="show_titles">Címek mutatása</string>
<string name="live_tv_repeat">Ismétlés</string>
<string name="favorite_channels_at_beginning">A kedvenc csatornákat mutassa először</string>
<string name="sort_channels_recently_watched">Legutóbb nézett csatornák előre sorolása</string>
<string name="color_code_programs">Műsorok kategória szerinti színezése</string>
<string name="subtitle_delay">Felirat késleltetése</string>
<string name="backdrop_display">Háttér stílusa</string>
<string name="enter_server_address">Adja meg a szerver címét</string>
<string name="combine_continue_next"><![CDATA[Folytatás & Következő menü összevonása]]></string>
<string name="player_backend">Lejátszás backend</string>
<string name="image_cache_size">Kép gyorsítótár méret (MB)</string>
<string name="cast_and_crew"><![CDATA[Stábtagok]]></string>
<string name="nav_drawer_switch_on_focus">Navigációs menü oldalainak váltása fókusznál</string>
<string name="playback_overrides">Lejátszás felülbírálatai</string>
</resources>

View file

@ -332,4 +332,8 @@
<string name="resolution">Resolusi</string>
<string name="sample_rate">Sampel rate</string>
<string name="spacing">Jarak</string>
<string name="ends_at">Berakhir pada %1$s</string>
<string name="enter_server_address">Masukkan alamat server</string>
<string name="no_servers_found">Server tidak ditemukan</string>
<string name="subtitle_delay">Penundaan subtitel</string>
</resources>

View file

@ -371,4 +371,8 @@
<string name="sort_channels_recently_watched">Ordina canali per ultimo guardato</string>
<string name="color_code_programs">Codifica colori per i programmi</string>
<string name="subtitle_delay">Ritardo sottotitoli</string>
<string name="enter_server_address">Inserisci indirizzo server</string>
<string name="no_servers_found">Nessun server trovato</string>
<string name="backdrop_display">Stile backdrop</string>
<string name="ends_at">Termina alle %1$s</string>
</resources>

View file

@ -1,3 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="about">אודות</string>
<string name="active_recordings">הקלטות פעילות</string>
<string name="add_favorite">הוספה למועדפים</string>
<string name="add_server">הוסף שרת</string>
<string name="add_user">הוסף משתמש</string>
<string name="audio">שמע</string>
<string name="birthplace">מקום לידה</string>
<string name="bitrate">קצב נתונים</string>
<string name="cancel_recording">בטל הקלטה</string>
<string name="cancel_series_recording">בטל הקלטת סדרה</string>
<string name="cancel">בטל</string>
<string name="chapters">פרקים</string>
<string name="clear_image_cache">נקה זיכרון מטמון</string>
<string name="collection">אוסף</string>
<string name="collections">אוספים</string>
<string name="commercial">מסחרי</string>
<string name="community_rating">דירוג קהילתי</string>
<string name="compose_error_message_title">אירעה שגיאה! לחץ על הכפתור על מנת לשלוח יומני אירועים לשרת שלך.</string>
<string name="confirm">לאשר</string>
<string name="continue_watching">המשך צפייה</string>
<string name="critic_rating">דירוג מבקרים</string>
<string name="decimal_seconds">%.1f שניות</string>
<string name="default_track">ברירת מחדל</string>
<string name="delete">מחק</string>
<string name="died">מת</string>
<string name="directed_by">בבימויו של %1$s</string>
<string name="director">במאי</string>
<string name="disabled">מושבת</string>
<string name="born">נולד</string>
<string name="choose_stream">בחר %1$s</string>
</resources>

View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="about">Ɣef</string>
<string name="audio">Imesli</string>
<string name="birthplace">Adig n tlalit</string>
<string name="bitrate">Aktum</string>
<string name="cancel">Semmet</string>
<string name="chapters">Ixfawen</string>
<string name="collection">Tagrumma</string>
<string name="collections">Tigrummiwin</string>
<string name="confirm">Serggeg</string>
<string name="default_track">Amezwer</string>
<string name="delete">Kkes</string>
<string name="died">Yemmut</string>
<string name="hide">Ffer-it</string>
<string name="home">Tazwara</string>
<string name="jump_letters">#ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
<string name="library">Tamkarḍit</string>
<string name="restart">Ales asekker</string>
<string name="resume">Kemmel</string>
<string name="save">Sekles</string>
<string name="search">Nadi</string>
<string name="searching">Yettnadi…</string>
<string name="show">Sken-d</string>
<string name="sort_by_name">Isem</string>
<string name="sort_by_random">Agacuṛan</string>
<string name="version">Lqem</string>
<string name="video">Tavidyut</string>
<string name="videos">Tividyutin</string>
<string name="font">Tasefsit</string>
<string name="background">Agilal</string>
<string name="success">Yedda</string>
<string name="year">Aseggas</string>
<string name="automatic">Awurman</string>
<string name="login">Tuqqna</string>
<string name="general">Amatu</string>
<string name="container">Amagbar</string>
<string name="title">Azwel</string>
<string name="codec">Akudak</string>
<string name="profile">Amaɣnu</string>
<string name="level">Aswir</string>
<string name="hdr10">HDR10</string>
<string name="hdr10_plus">HDR10+</string>
<string name="hlg">HLG</string>
<string name="choose_stream">Fren %1$s</string>
</resources>

View file

@ -3,12 +3,12 @@
<string name="about">Om</string>
<string name="active_recordings">Aktive opptak</string>
<string name="add_favorite">Favoritt</string>
<string name="add_server">Legg til Server</string>
<string name="add_user">Legg til Brukar</string>
<string name="add_server">Legg til server</string>
<string name="add_user">Legg til brukar</string>
<string name="audio">Lyd</string>
<string name="birthplace">Fødestad</string>
<string name="bitrate">Bitrate</string>
<string name="born">Født</string>
<string name="born">Fødd</string>
<string name="cancel_recording">Avbryt opptak</string>
<string name="cancel_series_recording">Avbryt opptak av serie</string>
<string name="cancel">Avbryt</string>
@ -21,4 +21,342 @@
<string name="delete">Slett</string>
<string name="died">Dødd</string>
<string name="directed_by">Regissert av %1$s</string>
<string name="ac3_supported">Eininga støttar AC3/Dolby Digital</string>
<string name="clear_image_cache">Tøm biletmellomlager</string>
<string name="commercial">Reklame</string>
<string name="community_rating">Brukarvurdering</string>
<string name="compose_error_message_title">Ein feil har oppstått! Trykk på knappen for å sende loggar til servaren din.</string>
<string name="continue_watching">Hald fram med å sjå</string>
<string name="critic_rating">Meldevurdering</string>
<string name="decimal_seconds">%.1f sekund</string>
<string name="director">Regissør</string>
<string name="disabled">Deaktivert</string>
<string name="discovered_servers">Funne servarar</string>
<string name="download_and_update"><![CDATA[Last ned og oppdater]]></string>
<string name="downloading">Lastar ned…</string>
<string name="enabled">Aktivert</string>
<string name="enter_server_url">Oppgi servar-IP eller URL</string>
<string name="enter_server_address">Oppgi servaradresse</string>
<string name="episodes">Episodar</string>
<string name="error_loading_collection">Feil ved lasting av samling %1$s</string>
<string name="external_track">Ekstern</string>
<string name="favorites">Favorittar</string>
<string name="file_size">Storleik</string>
<string name="forced_track">Tvungen</string>
<string name="genres">Sjangrar</string>
<string name="go_to_series">Gå til serie</string>
<string name="go_to">Gå til</string>
<string name="hide_controller_timeout">Gøym avspelingskontrollar</string>
<string name="hide_debug_info">Gøym feilsøkingsinfo</string>
<string name="hide">Gøym</string>
<string name="home">Heim</string>
<string name="immediate">Omgåande</string>
<string name="intro">Intro</string>
<string name="jump_letters">#ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ</string>
<string name="library">Bibliotek</string>
<string name="license_info">Lisensinformasjon</string>
<string name="live_tv">Direkte-TV</string>
<string name="loading">Lastar…</string>
<string name="mark_entire_series_as_played">Marker heile serien som sett?</string>
<string name="mark_entire_series_as_unplayed">Marker heile serien som usett?</string>
<string name="mark_unwatched">Marker som usett</string>
<string name="mark_watched">Marker som sett</string>
<string name="max_bitrate">Maks bitrate</string>
<string name="more_like_this">Meir som dette</string>
<string name="more">Meir</string>
<string name="movies">Filmar</string>
<string name="name">Namn</string>
<string name="next_up">Neste</string>
<string name="no_data">Ingen data</string>
<string name="no_results">Ingen resultat</string>
<string name="no_servers_found">Ingen servarar funne</string>
<string name="no_scheduled_recordings">Ingen planlagde opptak</string>
<string name="no_update_available">Ingen oppdatering tilgjengeleg</string>
<string name="outro">Outro</string>
<string name="path">Filveg</string>
<string name="people">Folk</string>
<string name="play_count">Antall avspelingar</string>
<string name="play_from_here">Spel av herfrå</string>
<string name="play">Spel av</string>
<string name="playback_debug_info">Vis feilsøkingsinfo for avspeling</string>
<string name="playback_speed">Avspelingsfart</string>
<string name="playback">Avspeling</string>
<string name="playlist">Speleliste</string>
<string name="playlists">Spelelister</string>
<string name="preview">Førehandsvising</string>
<string name="profile_specific_settings">Innstillingar for brukarprofil</string>
<string name="queue"></string>
<string name="recap">Samandrag</string>
<string name="recently_added_in">Sist lagt til i %1$s</string>
<string name="recently_added">Sist lagt til</string>
<string name="recently_recorded">Sist tatt opp</string>
<string name="recently_released">Sist utgitt</string>
<string name="recommended">Tilrådd</string>
<string name="record_program">Ta opp program</string>
<string name="record_series">Ta opp serie</string>
<string name="remove_favorite">Fjern favoritt</string>
<string name="restart">Start på nytt</string>
<string name="resume">Hald fram</string>
<string name="save">Lagre</string>
<string name="search_and_download"><![CDATA[Søk og last ned]]></string>
<string name="search">Søk</string>
<string name="searching">Søker…</string>
<string name="select_server">Vel servar</string>
<string name="select_user">Vel brukar</string>
<string name="show_debug_info">Vis feilsøkingsinfo</string>
<string name="show_next_up_when">Vis \'Neste\'</string>
<string name="show">Serie</string>
<string name="shuffle">Tilfeldig rekkjefølgje</string>
<string name="skip">Hopp over</string>
<string name="sort_by_date_added">Dato lagt til</string>
<string name="sort_by_date_episode_added">Dato episode lagt til</string>
<string name="sort_by_date_played">Dato spela av</string>
<string name="sort_by_date_released">Utginningsdato</string>
<string name="sort_by_name">Namn</string>
<string name="sort_by_random">Tilfeldig</string>
<string name="studios">Studio</string>
<string name="submit">Send inn</string>
<string name="subtitle">Undertekst</string>
<string name="subtitles">Undertekstar</string>
<string name="suggestions">Forslag</string>
<string name="switch_servers">Byt servar</string>
<string name="switch_user">Byt brukar</string>
<string name="top_unwatched">Best vurderte usette</string>
<string name="trailer">Trailer</string>
<plurals name="trailers">
<item quantity="one">Trailerar</item>
<item quantity="other"/>
</plurals>
<string name="tv_dvr_schedule">DVR-plan</string>
<string name="tv_guide">Programoversikt</string>
<string name="tv_season">Sesong</string>
<string name="tv_seasons">Sesongar</string>
<string name="tv_shows">TV-seriar</string>
<string name="ui_interface">Grensesnitt</string>
<string name="unknown">Ukjend</string>
<string name="updates">Oppdateringar</string>
<string name="version">Versjon</string>
<string name="video_scale">Videoskalering</string>
<string name="video">Video</string>
<string name="videos">Videoar</string>
<string name="watch_live">Sjå direkte</string>
<string name="years_old">%1$d år gammal</string>
<string name="play_with_transcoding">Spel av med transkoding</string>
<string name="media_information">Mediainformasjon</string>
<string name="show_clock">Vis klokke</string>
<string name="aired_episode_order">Rekkjefølgje etter sendedato</string>
<string name="create_playlist">Lag ny speleliste</string>
<string name="add_to_playlist">Legg til i speleliste</string>
<string name="one_click_pause">Pause med eitt klikk</string>
<string name="one_click_pause_summary_on">Trykk i midten på styreputa for å pause/spele av</string>
<string name="italic_font">Kursiv skrift</string>
<string name="font">Skrifttype</string>
<string name="background">Bakgrunn</string>
<string name="success">Fullført</string>
<string name="official_rating">Aldersgrense</string>
<string name="runtime_sort">Speltid</string>
<string name="extras">Ekstra</string>
<plurals name="other_extras">
<item quantity="one">Anna</item>
<item quantity="other"/>
</plurals>
<plurals name="behind_the_scenes">
<item quantity="one">Bak kulissane</item>
<item quantity="other"/>
</plurals>
<plurals name="theme_songs">
<item quantity="one">Temasongar</item>
<item quantity="other"/>
</plurals>
<plurals name="theme_videos">
<item quantity="one">Temavideoar</item>
<item quantity="other"/>
</plurals>
<plurals name="clips">
<item quantity="one">Klipp</item>
<item quantity="other"/>
</plurals>
<plurals name="deleted_scenes">
<item quantity="one">Sletta sener</item>
<item quantity="other"/>
</plurals>
<plurals name="interviews">
<item quantity="one">Intervju</item>
<item quantity="other"/>
</plurals>
<plurals name="scenes">
<item quantity="one">Scener</item>
<item quantity="other"/>
</plurals>
<plurals name="samples">
<item quantity="one">Smakebitar</item>
<item quantity="other"/>
</plurals>
<plurals name="featurettes">
<item quantity="one">Bakomfilmar</item>
<item quantity="other"/>
</plurals>
<plurals name="shorts">
<item quantity="one">Kortfilmar</item>
<item quantity="other"/>
</plurals>
<string name="advanced_settings">Avanserte innstillingar</string>
<string name="advanced_ui">Avansert grensesnitt</string>
<string name="app_theme">App-tema</string>
<string name="auto_check_for_updates">Sjekk automatisk etter oppdateringar</string>
<string name="auto_play_next_delay">Forseinking før neste vert spela av</string>
<string name="auto_play_next">Spel neste automatisk</string>
<string name="check_for_updates">Sjekk etter oppdateringar</string>
<string name="combine_continue_next_summary">Gjeld berre TV-seriar</string>
<string name="combine_continue_next">Slå saman \'Hald fram med å sjå\' og \'Neste\'</string>
<string name="direct_play_ass">Direkteavspeling av ASS-undertekstar</string>
<string name="direct_play_pgs">Direkteavspeling av PGS-undertekstar</string>
<string name="downmix_stereo">Alltid nedmiks til stereo</string>
<string name="ffmpeg_extension_pref">Bruk FFmpeg-dekodermodul</string>
<string name="global_content_scale">Standard innhaldsskalering</string>
<string name="install_update">Installer oppdatering</string>
<string name="installed_version">Installert versjon</string>
<string name="max_homepage_items">Maks element på rader på heimskjermen</string>
<string name="nav_drawer_pins">Tilpass element i navigasjonsskuffa</string>
<string name="nav_drawer_switch_on_focus_summary_off">Klikk for å byte side</string>
<string name="nav_drawer_switch_on_focus">Byt side i navigasjonsskuffa ved fokus</string>
<string name="pass_out_protection">Svevn-beskyttelse</string>
<string name="play_theme_music">Spel temamusikk</string>
<string name="playback_overrides">Overstyring av avspeling</string>
<string name="remember_selected_tab">Hugs valde faner</string>
<string name="rewatch_next_up">Tillat gjensjåing i \'Neste\'</string>
<string name="seek_bar_steps">Steglengde for søkelinje</string>
<string name="send_app_logs_summary">Nyttig for feilsøking</string>
<string name="send_app_logs">Send app-loggar til gjeldande servar</string>
<string name="send_crash_reports_summary">Vil prøve å sende til sist tilkopla servar</string>
<string name="send_crash_reports">Send krasjrapportar</string>
<string name="settings">Innstillingar</string>
<string name="skip_back_on_resume_preference">Hopp tilbake ved framhald av avspeling</string>
<string name="skip_back_preference">Hopp tilbake</string>
<string name="skip_commercials_behavior">Handling for overhopping av reklame</string>
<string name="skip_forward_preference">Hopp framover</string>
<string name="skip_intro_behavior">Handling for overhopping av intro</string>
<string name="skip_outro_behavior">Handling for overhopping av outro</string>
<string name="skip_previews_behavior">Handling for overhopping av førehandsvising</string>
<string name="skip_recap_behavior">Handling for overhopping av samandrag</string>
<string name="update_available">Oppdatering tilgjengeleg</string>
<string name="update_url_summary">URL for sjekk av app-oppdateringar</string>
<string name="update_url">URL for oppdatering</string>
<string name="font_size">Skriftstorleik</string>
<string name="font_color">Skriftfarge</string>
<string name="font_opacity">Gjennomsiktigheit for skrift</string>
<string name="edge_style">Kantstil</string>
<string name="edge_color">Kantfarge</string>
<string name="background_opacity">Gjennomsiktigheit for bakgrunn</string>
<string name="background_style">Bakgrunnsstil</string>
<string name="subtitle_style">Stil for undertekst</string>
<string name="background_color">Bakgrunnsfarge</string>
<string name="reset">Nullstill</string>
<string name="bold_font">Feit skrift</string>
<string name="player_backend">Avspelingsmotor</string>
<string name="mpv_hardware_decoding">MPV: Bruk maskinvaredekoding</string>
<string name="disable_if_crash">Deaktiver dersom appen krasjar</string>
<string name="mpv_options">MPV-val</string>
<string name="exoplayer_options">ExoPlayer-val</string>
<string name="skip_segment_unknown">Hopp over segment</string>
<string name="skip_segment_commercial">Hopp over reklame</string>
<string name="skip_segment_preview">Hopp over førehandsvising</string>
<string name="skip_segment_recap">Hopp over samandrag</string>
<string name="skip_segment_outro">Hopp over outro</string>
<string name="skip_segment_intro">Hopp over intro</string>
<string name="played">Sett</string>
<string name="filter">Filter</string>
<string name="year">År</string>
<string name="decade">Tiår</string>
<string name="remove">Fjern</string>
<string name="dolby_vision">Dolby Vision</string>
<string name="dolby_atmos">Dolby Atmos</string>
<string name="mpv_use_gpu_next">MPV: Bruk gpu-next</string>
<string name="mpv_conf">Rediger mpv.conf</string>
<string name="discard_change">Forkast endringar?</string>
<string name="subtitle_margin">Marg</string>
<string name="verbose_logging">Detaljert logging</string>
<string name="enter_pin">Tast inn PIN</string>
<string name="sign_in_auto">Logg inn automatisk</string>
<string name="use_server_credentials">Logg inn via servar</string>
<string name="press_enter_to_confirm">Trykk i midten for å bekrefte</string>
<string name="require_pin_code">Krev PIN for profil</string>
<string name="confirm_pin">Bekreft PIN</string>
<string name="incorrect">Feil</string>
<string name="pin_too_short">PIN må vere 4 tastar eller lenger</string>
<string name="will_remove_pin">Vil fjerne PIN</string>
<string name="image_cache_size">Storleik på biletmellomlager (MB)</string>
<string name="view_options">Visingsval</string>
<string name="columns">Kolonner</string>
<string name="spacing">Mellomrom</string>
<string name="aspect_ratio">Bileteforhold</string>
<string name="show_details">Vis detaljar</string>
<string name="image_type">Bilettype</string>
<string name="cast_and_crew"><![CDATA[Skodespelarar og medarbeidarar]]></string>
<string name="guest_stars">Gjesteroller</string>
<string name="edge_size">Kantstorleik</string>
<string name="refresh_rate_switching">Byting av bildeoppdateringsfrekvens</string>
<string name="automatic">Automatisk</string>
<string name="username_or_password">Bruk brukarnamn/passord</string>
<string name="login">Logg inn</string>
<string name="general">Generelt</string>
<string name="container">Containar</string>
<string name="title">Tittel</string>
<string name="codec">Kodek</string>
<string name="profile">Profil</string>
<string name="level">Nivå</string>
<string name="resolution">Oppløysing</string>
<string name="anamorphic">Anamorfisk</string>
<string name="interlaced">Linjefletta</string>
<string name="framerate">Bildefrekvens</string>
<string name="bit_depth">Bit-dybde</string>
<string name="video_range">Videoområde</string>
<string name="video_range_type">Type videoområde</string>
<string name="color_space">Fargerom</string>
<string name="color_transfer">Fargeoverføring</string>
<string name="color_primaries">Fargeprimærar</string>
<string name="pixel_format">Pikselformat</string>
<string name="ref_frames">Referanserammer</string>
<string name="nal">NAL</string>
<string name="language">Språk</string>
<string name="layout">Layout</string>
<string name="channels">Kanalar</string>
<string name="sample_rate">Samplingsfrekvens</string>
<string name="avc">AVC</string>
<string name="yes">Ja</string>
<string name="no">Nei</string>
<string name="sdr">SDR</string>
<string name="hdr">HDR</string>
<string name="hdr10">HDR10</string>
<string name="hdr10_plus">HDR10+</string>
<string name="hlg">HLG</string>
<string name="bit_unit">bit</string>
<string name="sample_rate_unit">Hz</string>
<string name="show_titles">Vis titlar</string>
<string name="live_tv_repeat">Repeter</string>
<string name="favorite_channels_at_beginning">Vis favorittkanalar først</string>
<string name="sort_channels_recently_watched">Sorter kanalar etter sist sett</string>
<string name="color_code_programs">Fargekod program</string>
<string name="subtitle_delay">Undertekstforseinking</string>
<string name="backdrop_display">Bakgrunnsstil</string>
<string name="none">Ingen</string>
<string name="subtitle_download_too_long">Nedlastinga tek lang tid, du må kanskje starte avspelinga på nytt</string>
<plurals name="downloads">
<item quantity="one">%s nedlasting</item>
<item quantity="other">%s nedlastingar</item>
</plurals>
<plurals name="hours">
<item quantity="one">%d time</item>
<item quantity="other">%d timar</item>
</plurals>
<plurals name="items">
<item quantity="one">%d element</item>
<item quantity="other">%d elementer</item>
</plurals>
<plurals name="seconds">
<item quantity="one">%d sekund</item>
<item quantity="other">%d sekund</item>
</plurals>
<string name="nav_drawer_pins_summary">Vel standardelementa som skal visast, andre vert skjulde</string>
<string name="ends_at">Sluttar %1$s</string>
</resources>

View file

@ -371,4 +371,8 @@
<string name="sort_channels_recently_watched">Ordenar canais por visualizações recentes</string>
<string name="color_code_programs">Codificação de cores para os programas</string>
<string name="subtitle_delay">Atraso da legenda</string>
<string name="enter_server_address">Insira o endereço do servidor</string>
<string name="no_servers_found">Nenhum servidor encontrado</string>
<string name="backdrop_display">Estilo de fundo</string>
<string name="ends_at">Termina às %1$s</string>
</resources>

View file

@ -339,4 +339,8 @@
<string name="sort_channels_recently_watched">按最近观看的频道排序</string>
<string name="color_code_programs">节目颜色标记</string>
<string name="subtitle_delay">字幕延迟</string>
<string name="enter_server_address">输入服务器地址</string>
<string name="no_servers_found">未找到服务器</string>
<string name="backdrop_display">背景幕样式</string>
<string name="ends_at">结束于 %1$s</string>
</resources>

View file

@ -183,8 +183,8 @@
<string name="jump_letters">#ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
<string name="license_info">授權資訊</string>
<string name="live_tv">電視直播</string>
<string name="mark_entire_series_as_played">標記整部電視劇為已觀看?</string>
<string name="mark_entire_series_as_unplayed">標記整部電視劇為未觀看?</string>
<string name="mark_entire_series_as_played">標記整部劇為已觀看?</string>
<string name="mark_entire_series_as_unplayed">標記整部劇為未觀看?</string>
<string name="mark_unwatched">標記為未觀看</string>
<string name="mark_watched">標記為已觀看</string>
<string name="max_bitrate">最大位元率</string>
@ -299,4 +299,48 @@
<string name="username_or_password">使用帳號/密碼</string>
<string name="login">登入</string>
<string name="subtitle_delay">字幕同步</string>
<string name="show_titles">顯示標題</string>
<string name="enter_server_address">輸入伺服器位址</string>
<string name="no_servers_found">未找到伺服器</string>
<string name="backdrop_display">背景圖樣式</string>
<string name="color_code_programs">節目顏色標記</string>
<string name="favorite_channels_at_beginning">優先顯示最愛頻道</string>
<string name="sort_channels_recently_watched">按最近觀看的頻道排序</string>
<string name="ends_at">結束於 %1$s</string>
<string name="general">一般</string>
<string name="container">封裝格式</string>
<string name="title">標題</string>
<string name="codec">編碼</string>
<string name="resolution">解析度</string>
<string name="anamorphic">變形寬銀幕</string>
<string name="level">等級</string>
<string name="profile">編碼設定檔</string>
<string name="language">語言</string>
<string name="yes"></string>
<string name="no"></string>
<string name="sdr">SDR</string>
<string name="hdr">HDR</string>
<string name="hdr10">HDR10</string>
<string name="hdr10_plus">HDR10+</string>
<string name="hlg">HLG</string>
<string name="bit_unit">bit</string>
<string name="sample_rate_unit">Hz</string>
<string name="live_tv_repeat">重複</string>
<string name="interlaced">隔行掃描</string>
<string name="ref_frames">參考影格數</string>
<string name="framerate">影格率</string>
<string name="nal">NAL</string>
<string name="bit_depth">位元深度</string>
<string name="avc">AVC</string>
<string name="layout">聲道配置</string>
<string name="channels">聲道數</string>
<string name="video_range">動態範圍</string>
<string name="video_range_type">動態範圍類型</string>
<string name="color_space">色彩空間</string>
<string name="color_transfer">色彩轉換</string>
<string name="color_primaries">色彩原色</string>
<string name="pixel_format">像素格式</string>
<string name="sample_rate">取樣率</string>
<string name="seek_bar_steps">進度條跳轉值</string>
<string name="playback_overrides">播放覆蓋設定</string>
</resources>

View file

@ -399,6 +399,9 @@
<string name="subtitle_delay">Subtitle delay</string>
<string name="backdrop_display">Backdrop style</string>
<string name="resolution_switching">Resolution switching</string>
<string name="local">Local</string>
<string name="play_trailer">Play trailer</string>
<string name="no_trailers">No trailers</string>
<string name="discover">Discover</string>
<string name="request">Request</string>