mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2026-08-06 20:08:48 +02:00
Compare commits
44
Commits
@@ -36,8 +36,8 @@ android {
|
|||||||
applicationId "com.audiobookshelf.app"
|
applicationId "com.audiobookshelf.app"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 108
|
versionCode 109
|
||||||
versionName "0.9.77-beta"
|
versionName "0.9.78-beta"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
"appAuthRedirectScheme": "com.audiobookshelf.app"
|
"appAuthRedirectScheme": "com.audiobookshelf.app"
|
||||||
|
|||||||
@@ -41,8 +41,11 @@ data class DownloadItemPart(
|
|||||||
val destinationUri = Uri.fromFile(destinationFile)
|
val destinationUri = Uri.fromFile(destinationFile)
|
||||||
val finalDestinationUri = Uri.fromFile(finalDestinationFile)
|
val finalDestinationUri = Uri.fromFile(finalDestinationFile)
|
||||||
|
|
||||||
var downloadUrl = "${DeviceManager.serverAddress}${serverPath}?token=${DeviceManager.token}"
|
var downloadUrl = "${DeviceManager.serverAddress}${serverPath}"
|
||||||
if (serverPath.endsWith("/cover")) downloadUrl += "&format=jpeg&raw=1" // For cover images force to jpeg
|
|
||||||
|
downloadUrl += if (serverPath.endsWith("/cover")) "?raw=1" // Download raw cover image
|
||||||
|
else "?token=${DeviceManager.token}"
|
||||||
|
|
||||||
val downloadUri = Uri.parse(downloadUrl)
|
val downloadUri = Uri.parse(downloadUrl)
|
||||||
Log.d("DownloadItemPart", "Audio File Destination Uri: $destinationUri | Final Destination Uri: $finalDestinationUri | Download URI $downloadUri")
|
Log.d("DownloadItemPart", "Audio File Destination Uri: $destinationUri | Final Destination Uri: $finalDestinationUri | Download URI $downloadUri")
|
||||||
return DownloadItemPart(
|
return DownloadItemPart(
|
||||||
@@ -77,7 +80,7 @@ data class DownloadItemPart(
|
|||||||
val isInternalStorage get() = localFolderId.startsWith("internal-")
|
val isInternalStorage get() = localFolderId.startsWith("internal-")
|
||||||
|
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val serverUrl get() = "${DeviceManager.serverAddress}${serverPath}?token=${DeviceManager.token}"
|
val serverUrl get() = uri.toString()
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
fun getDownloadRequest(): DownloadManager.Request {
|
fun getDownloadRequest(): DownloadManager.Request {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
<covers-book-cover v-if="libraryItem || localLibraryItemCoverSrc" ref="cover" :library-item="libraryItem" :download-cover="localLibraryItemCoverSrc" :width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" raw @imageLoaded="coverImageLoaded" />
|
<covers-book-cover v-if="libraryItem || localLibraryItemCoverSrc" ref="cover" :library-item="libraryItem" :download-cover="localLibraryItemCoverSrc" :width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" raw @imageLoaded="coverImageLoaded" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="syncStatus === $constants.SyncStatus.FAILED" class="absolute top-0 left-0 w-full h-full flex items-center justify-center z-30">
|
<div v-if="syncStatus === $constants.SyncStatus.FAILED" class="absolute top-0 left-0 w-full h-full flex items-center justify-center z-30" @click.stop="showSyncsFailedDialog">
|
||||||
<span class="material-icons text-error text-3xl">error</span>
|
<span class="material-icons text-error text-3xl">error</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -107,6 +107,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { Capacitor } from '@capacitor/core'
|
import { Capacitor } from '@capacitor/core'
|
||||||
import { AbsAudioPlayer } from '@/plugins/capacitor'
|
import { AbsAudioPlayer } from '@/plugins/capacitor'
|
||||||
|
import { Dialog } from '@capacitor/dialog'
|
||||||
import { FastAverageColor } from 'fast-average-color'
|
import { FastAverageColor } from 'fast-average-color'
|
||||||
import WrappingMarquee from '@/assets/WrappingMarquee.js'
|
import WrappingMarquee from '@/assets/WrappingMarquee.js'
|
||||||
|
|
||||||
@@ -390,6 +391,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
showSyncsFailedDialog() {
|
||||||
|
Dialog.alert({
|
||||||
|
title: this.$strings.HeaderProgressSyncFailed,
|
||||||
|
message: this.$strings.MessageProgressSyncFailed,
|
||||||
|
cancelText: this.$strings.ButtonOk
|
||||||
|
})
|
||||||
|
},
|
||||||
clickChaptersBtn() {
|
clickChaptersBtn() {
|
||||||
if (!this.chapters.length) return
|
if (!this.chapters.length) return
|
||||||
this.showChapterModal = true
|
this.showChapterModal = true
|
||||||
|
|||||||
@@ -42,9 +42,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
userToken() {
|
|
||||||
return this.$store.getters['user/getToken']
|
|
||||||
},
|
|
||||||
_author() {
|
_author() {
|
||||||
return this.author || {}
|
return this.author || {}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -94,8 +94,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Podcast Num Episodes Incomplete -->
|
<!-- Podcast Num Episodes Incomplete -->
|
||||||
<div v-else-if="numEpisodesIncomplete && !isSelectionMode" class="absolute rounded-full bg-black bg-opacity-90 box-shadow-md z-10 flex items-center justify-center" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', width: 1.25 * sizeMultiplier + 'rem', height: 1.25 * sizeMultiplier + 'rem' }">
|
<div v-else-if="numEpisodesIncomplete && !isSelectionMode" class="absolute rounded-full bg-yellow-400 box-shadow-md z-10 flex items-center justify-center" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', width: 1.25 * sizeMultiplier + 'rem', height: 1.25 * sizeMultiplier + 'rem' }">
|
||||||
<p class="text-white" :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">{{ numEpisodesIncomplete }}</p>
|
<p class="text-black" :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">{{ numEpisodesIncomplete }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -21,7 +21,13 @@
|
|||||||
<p class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ displayAuthor }}</p>
|
<p class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ displayAuthor }}</p>
|
||||||
<p v-if="displaySortLine" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ displaySortLine }}</p>
|
<p v-if="displaySortLine" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ displaySortLine }}</p>
|
||||||
<p v-if="duration" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ $elapsedPretty(duration) }}</p>
|
<p v-if="duration" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ $elapsedPretty(duration) }}</p>
|
||||||
<p v-if="episodes" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ episodes }}</p>
|
|
||||||
|
<p v-if="numEpisodesIncomplete" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">
|
||||||
|
{{ $getString('LabelNumEpisodesIncomplete', [numEpisodes, numEpisodesIncomplete]) }}
|
||||||
|
</p>
|
||||||
|
<p v-else-if="numEpisodes" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">
|
||||||
|
{{ $getString('LabelNumEpisodes', [numEpisodes]) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="localLibraryItem || isLocal" class="absolute top-0 right-0 z-20" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }">
|
<div v-if="localLibraryItem || isLocal" class="absolute top-0 right-0 z-20" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }">
|
||||||
@@ -106,12 +112,13 @@ export default {
|
|||||||
isPodcast() {
|
isPodcast() {
|
||||||
return this.mediaType === 'podcast'
|
return this.mediaType === 'podcast'
|
||||||
},
|
},
|
||||||
episodes() {
|
numEpisodes() {
|
||||||
if (this.isPodcast) {
|
if (this.isLocal && this.isPodcast && this.media.episodes) return this.media.episodes.length
|
||||||
return this.$getString('LabelNumEpisodes', [this.media.numEpisodes])
|
return this.media.numEpisodes
|
||||||
} else {
|
},
|
||||||
return null
|
numEpisodesIncomplete() {
|
||||||
}
|
if (this.isLocal) return 0
|
||||||
|
return this._libraryItem.numEpisodesIncomplete || 0
|
||||||
},
|
},
|
||||||
placeholderUrl() {
|
placeholderUrl() {
|
||||||
return '/book_placeholder.jpg'
|
return '/book_placeholder.jpg'
|
||||||
|
|||||||
@@ -3,12 +3,19 @@
|
|||||||
<div v-show="!loggedIn" class="mt-8 bg-primary overflow-hidden shadow rounded-lg px-4 py-6 w-full">
|
<div v-show="!loggedIn" class="mt-8 bg-primary overflow-hidden shadow rounded-lg px-4 py-6 w-full">
|
||||||
<!-- list of server connection configs -->
|
<!-- list of server connection configs -->
|
||||||
<template v-if="!showForm">
|
<template v-if="!showForm">
|
||||||
<div v-for="config in serverConnectionConfigs" :key="config.id" class="flex items-center py-4 my-1 border-b border-fg/10 relative" @click="connectToServer(config)">
|
<div v-for="config in serverConnectionConfigs" :key="config.id" class="border-b border-fg/10 py-4">
|
||||||
<span class="material-icons-outlined text-xl text-fg-muted">dns</span>
|
<div class="flex items-center my-1 relative" @click="connectToServer(config)">
|
||||||
<p class="pl-3 pr-6 text-base text-fg">{{ config.name }}</p>
|
<span class="material-icons-outlined text-xl text-fg-muted">dns</span>
|
||||||
|
<p class="pl-3 pr-6 text-base text-fg">{{ config.name }}</p>
|
||||||
|
|
||||||
<div class="absolute top-0 right-0 h-full px-4 flex items-center" @click.stop="editServerConfig(config)">
|
<div class="absolute top-0 right-0 h-full px-4 flex items-center" @click.stop="editServerConfig(config)">
|
||||||
<span class="material-icons text-lg text-fg-muted">more_vert</span>
|
<span class="material-icons text-lg text-fg-muted">more_vert</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- warning message if server connection config is using an old user id -->
|
||||||
|
<div v-if="!checkIdUuid(config.userId)" class="flex flex-nowrap justify-between items-center space-x-4 pt-4">
|
||||||
|
<p class="text-xs text-warning">{{ $strings.MessageOldServerConnectionWarning }}</p>
|
||||||
|
<ui-btn class="text-xs whitespace-nowrap" :padding-x="2" :padding-y="1" @click="showOldUserIdWarningDialog">{{ $strings.LabelMoreInfo }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="my-1 py-4 w-full">
|
<div class="my-1 py-4 w-full">
|
||||||
@@ -141,6 +148,16 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
showOldUserIdWarningDialog() {
|
||||||
|
Dialog.alert({
|
||||||
|
title: 'Old Server Connection Warning',
|
||||||
|
message: this.$strings.MessageOldServerConnectionWarningHelp,
|
||||||
|
cancelText: this.$strings.ButtonOk
|
||||||
|
})
|
||||||
|
},
|
||||||
|
checkIdUuid(userId) {
|
||||||
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId)
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Initiates the login process using OpenID via OAuth2.0.
|
* Initiates the login process using OpenID via OAuth2.0.
|
||||||
* 1. Verifying the server's address
|
* 1. Verifying the server's address
|
||||||
|
|||||||
@@ -39,9 +39,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
userToken() {
|
|
||||||
return this.$store.getters['user/getToken']
|
|
||||||
},
|
|
||||||
_author() {
|
_author() {
|
||||||
return this.author || {}
|
return this.author || {}
|
||||||
},
|
},
|
||||||
@@ -61,9 +58,9 @@ export default {
|
|||||||
if (!this.imagePath || !this.serverAddress) return null
|
if (!this.imagePath || !this.serverAddress) return null
|
||||||
if (process.env.NODE_ENV !== 'production' && this.serverAddress.startsWith('http://192.168')) {
|
if (process.env.NODE_ENV !== 'production' && this.serverAddress.startsWith('http://192.168')) {
|
||||||
// Testing
|
// Testing
|
||||||
return `http://localhost:3333/api/authors/${this.authorId}/image?token=${this.userToken}&ts=${this.updatedAt}`
|
return `http://localhost:3333/api/authors/${this.authorId}/image?ts=${this.updatedAt}`
|
||||||
}
|
}
|
||||||
return `${this.serverAddress}/api/authors/${this.authorId}/image?token=${this.userToken}&ts=${this.updatedAt}`
|
return `${this.serverAddress}/api/authors/${this.authorId}/image?ts=${this.updatedAt}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -141,9 +141,6 @@ export default {
|
|||||||
},
|
},
|
||||||
authorBottom() {
|
authorBottom() {
|
||||||
return 0.75 * this.sizeMultiplier
|
return 0.75 * this.sizeMultiplier
|
||||||
},
|
|
||||||
userToken() {
|
|
||||||
return this.$store.getters['user/getToken']
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<div class="w-full h-9 bg-bg relative z-20">
|
<div class="w-full h-9 bg-bg relative z-20">
|
||||||
<div id="bookshelf-toolbar" class="absolute top-0 left-0 w-full h-full z-20 flex items-center px-2">
|
<div id="bookshelf-toolbar" class="absolute top-0 left-0 w-full h-full z-20 flex items-center px-2">
|
||||||
<div class="flex items-center w-full text-sm">
|
<div class="flex items-center w-full text-sm">
|
||||||
<p v-show="!selectedSeriesName" class="pt-1">{{ totalEntities }} {{ entityTitle }}</p>
|
<p v-show="!selectedSeriesName" class="pt-1">{{ $formatNumber(totalEntities) }} {{ entityTitle }}</p>
|
||||||
<p v-show="selectedSeriesName" class="ml-2 pt-1">{{ selectedSeriesName }} ({{ totalEntities }})</p>
|
<p v-show="selectedSeriesName" class="ml-2 pt-1">{{ selectedSeriesName }} ({{ $formatNumber(totalEntities) }})</p>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<span v-if="page == 'library' || seriesBookPage" class="material-icons px-2" @click="changeView">{{ !bookshelfListView ? 'view_list' : 'grid_view' }}</span>
|
<span v-if="page == 'library' || seriesBookPage" class="material-icons px-2" @click="changeView">{{ !bookshelfListView ? 'view_list' : 'grid_view' }}</span>
|
||||||
<template v-if="page === 'library'">
|
<template v-if="page === 'library'">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="wrapper" class="modal modal-bg w-screen fixed bottom-0 left-0 flex items-center justify-center z-50" :class="halfScreen ? 'h-[50vh] min-h-[400px]' : 'h-screen'" @click.stop @touchstart.stop @touchend.stop>
|
<div ref="wrapper" class="modal modal-bg w-screen fixed bottom-0 left-0 flex items-center justify-center z-50" :class="threeQuartersScreen ? 'h-[75vh] min-h-[400px]' : 'h-screen'" @click.stop @touchstart.stop @touchend.stop>
|
||||||
<div ref="content" class="relative text-fg h-full w-full bg-bg">
|
<div ref="content" class="relative text-fg h-full w-full bg-bg">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
@@ -11,7 +11,7 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
value: Boolean,
|
value: Boolean,
|
||||||
processing: Boolean,
|
processing: Boolean,
|
||||||
halfScreen: Boolean
|
threeQuartersScreen: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ export default {
|
|||||||
text: this.$strings.LabelSize,
|
text: this.$strings.LabelSize,
|
||||||
value: 'size'
|
value: 'size'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: this.$strings.LabelNumberOfEpisodes,
|
||||||
|
value: 'media.numTracks'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: this.$strings.LabelFileBirthtime,
|
text: this.$strings.LabelFileBirthtime,
|
||||||
value: 'birthtimeMs'
|
value: 'birthtimeMs'
|
||||||
|
|||||||
@@ -54,15 +54,15 @@
|
|||||||
</modals-fullscreen-modal>
|
</modals-fullscreen-modal>
|
||||||
|
|
||||||
<!-- ereader settings modal -->
|
<!-- ereader settings modal -->
|
||||||
<modals-fullscreen-modal v-model="showSettingsModal" :theme="ereaderTheme">
|
<modals-fullscreen-modal v-model="showSettingsModal" :theme="ereaderTheme" threeQuartersScreen>
|
||||||
<div style="box-shadow: 0px -8px 8px #11111155">
|
<div style="box-shadow: 0px -8px 8px #11111155">
|
||||||
<div class="flex items-end justify-between h-20 px-4 pb-2 mb-6">
|
<div class="flex items-end justify-between h-14 px-4 pb-2 mb-6">
|
||||||
<h1 class="text-lg">{{ $strings.HeaderEreaderSettings }}</h1>
|
<h1 class="text-lg">{{ $strings.HeaderEreaderSettings }}</h1>
|
||||||
<button class="flex" @click="showSettingsModal = false">
|
<button class="flex" @click="showSettingsModal = false">
|
||||||
<span class="material-icons">close</span>
|
<span class="material-icons">close</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full overflow-y-auto overflow-x-hidden h-full max-h-[calc(100vh-85px)]">
|
<div class="w-full overflow-y-auto overflow-x-hidden h-full max-h-[calc(75vh-85px)]">
|
||||||
<div class="w-full h-full px-4">
|
<div class="w-full h-full px-4">
|
||||||
<div class="flex items-center mb-6">
|
<div class="flex items-center mb-6">
|
||||||
<div class="w-32">
|
<div class="w-32">
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<ui-toggle-btns v-model="ereaderSettings.navigateWithVolumeWhilePlaying" name="navigate-volume-playing" :items="onOffToggleButtonItems" @input="settingsUpdated" />
|
<ui-toggle-btns v-model="ereaderSettings.navigateWithVolumeWhilePlaying" name="navigate-volume-playing" :items="onOffToggleButtonItems" @input="settingsUpdated" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center mb-6">
|
||||||
<div class="w-32">
|
<div class="w-32">
|
||||||
<p class="text-sm">{{ $strings.LabelKeepScreenAwake }}</p>
|
<p class="text-sm">{{ $strings.LabelKeepScreenAwake }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,22 +33,22 @@
|
|||||||
<div class="flex justify-between pt-12">
|
<div class="flex justify-between pt-12">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-center">{{ $strings.LabelStatsWeekListening }}</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsWeekListening }}</p>
|
||||||
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ totalMinutesListeningThisWeek }}</p>
|
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(totalMinutesListeningThisWeek) }}</p>
|
||||||
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-center">{{ $strings.LabelStatsDailyAverage }}</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsDailyAverage }}</p>
|
||||||
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ averageMinutesPerDay }}</p>
|
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(averageMinutesPerDay) }}</p>
|
||||||
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-center">{{ $strings.LabelStatsBestDay }}</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsBestDay }}</p>
|
||||||
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ mostListenedDay }}</p>
|
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(mostListenedDay) }}</p>
|
||||||
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-center">{{ $strings.LabelStatsDays }}</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsDays }}</p>
|
||||||
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ daysInARow }}</p>
|
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(daysInARow) }}</p>
|
||||||
<p class="text-sm text-center">{{ $strings.LabelStatsInARow }}</p>
|
<p class="text-sm text-center">{{ $strings.LabelStatsInARow }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -50,9 +50,6 @@ export default {
|
|||||||
libraryItemId() {
|
libraryItemId() {
|
||||||
return this.libraryItem.id
|
return this.libraryItem.id
|
||||||
},
|
},
|
||||||
userToken() {
|
|
||||||
return this.$store.getters['user/getToken']
|
|
||||||
},
|
|
||||||
ebookFiles() {
|
ebookFiles() {
|
||||||
return (this.libraryItem.libraryFiles || []).filter((lf) => lf.fileType === 'ebook')
|
return (this.libraryItem.libraryFiles || []).filter((lf) => lf.fileType === 'ebook')
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ export default {
|
|||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
userToken() {
|
|
||||||
return this.$store.getters['user/getToken']
|
|
||||||
},
|
|
||||||
userCanUpdate() {
|
userCanUpdate() {
|
||||||
return this.$store.getters['user/getUserCanUpdate']
|
return this.$store.getters['user/getUserCanUpdate']
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -744,12 +744,12 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = Icons;
|
ASSETCATALOG_COMPILER_APPICON_NAME = Icons;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 34;
|
CURRENT_PROJECT_VERSION = 35;
|
||||||
DEVELOPMENT_TEAM = 7UFJ7D8V6A;
|
DEVELOPMENT_TEAM = 7UFJ7D8V6A;
|
||||||
INFOPLIST_FILE = App/Info.plist;
|
INFOPLIST_FILE = App/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
MARKETING_VERSION = 0.9.77;
|
MARKETING_VERSION = 0.9.78;
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app.dev;
|
PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app.dev;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -768,12 +768,12 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = Icons;
|
ASSETCATALOG_COMPILER_APPICON_NAME = Icons;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 34;
|
CURRENT_PROJECT_VERSION = 35;
|
||||||
DEVELOPMENT_TEAM = 7UFJ7D8V6A;
|
DEVELOPMENT_TEAM = 7UFJ7D8V6A;
|
||||||
INFOPLIST_FILE = App/Info.plist;
|
INFOPLIST_FILE = App/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
MARKETING_VERSION = 0.9.77;
|
MARKETING_VERSION = 0.9.78;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-app",
|
"name": "audiobookshelf-app",
|
||||||
"version": "0.9.77-beta",
|
"version": "0.9.78-beta",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "audiobookshelf-app",
|
"name": "audiobookshelf-app",
|
||||||
"version": "0.9.77-beta",
|
"version": "0.9.78-beta",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@byteowls/capacitor-filesharer": "^6.0.0",
|
"@byteowls/capacitor-filesharer": "^6.0.0",
|
||||||
"@capacitor-community/keep-awake": "^5.0.1",
|
"@capacitor-community/keep-awake": "^5.0.1",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-app",
|
"name": "audiobookshelf-app",
|
||||||
"version": "0.9.77-beta",
|
"version": "0.9.78-beta",
|
||||||
"author": "advplyr",
|
"author": "advplyr",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nuxt --hostname 0.0.0.0 --port 1337",
|
"dev": "nuxt --hostname 0.0.0.0 --port 1337",
|
||||||
|
|||||||
@@ -366,9 +366,6 @@ export default {
|
|||||||
user() {
|
user() {
|
||||||
return this.$store.state.user.user
|
return this.$store.state.user.user
|
||||||
},
|
},
|
||||||
userToken() {
|
|
||||||
return this.$store.getters['user/getToken']
|
|
||||||
},
|
|
||||||
userItemProgress() {
|
userItemProgress() {
|
||||||
if (this.isPodcast) return null
|
if (this.isPodcast) return null
|
||||||
if (this.isLocal) return this.localItemProgress
|
if (this.isLocal) return this.localItemProgress
|
||||||
|
|||||||
+3
-3
@@ -10,21 +10,21 @@
|
|||||||
<div class="flex text-center justify-center">
|
<div class="flex text-center justify-center">
|
||||||
<div class="flex p-2">
|
<div class="flex p-2">
|
||||||
<div class="px-3">
|
<div class="px-3">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ userItemsFinished.length }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ $formatNumber(userItemsFinished.length) }}</p>
|
||||||
<p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsItemsFinished }}</p>
|
<p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsItemsFinished }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex p-2">
|
<div class="flex p-2">
|
||||||
<div class="px-1">
|
<div class="px-1">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ totalDaysListened }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ $formatNumber(totalDaysListened) }}</p>
|
||||||
<p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsDaysListened }}</p>
|
<p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsDaysListened }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex p-2">
|
<div class="flex p-2">
|
||||||
<div class="px-1">
|
<div class="px-1">
|
||||||
<p class="text-4xl md:text-5xl font-bold">{{ totalMinutesListening }}</p>
|
<p class="text-4xl md:text-5xl font-bold">{{ $formatNumber(totalMinutesListening) }}</p>
|
||||||
<p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsMinutesListening }}</p>
|
<p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsMinutesListening }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ Vue.prototype.$getString = (key, subs) => {
|
|||||||
return Vue.prototype.$strings[key]
|
return Vue.prototype.$strings[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vue.prototype.$formatNumber = (num) => {
|
||||||
|
return Intl.NumberFormat(Vue.prototype.$languageCodes.current).format(num)
|
||||||
|
}
|
||||||
|
|
||||||
var translations = {
|
var translations = {
|
||||||
[defaultCode]: enUsStrings
|
[defaultCode]: enUsStrings
|
||||||
}
|
}
|
||||||
|
|||||||
+65
-56
@@ -44,62 +44,71 @@ export const state = () => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const getters = {
|
export const getters = {
|
||||||
getDownloadItem: state => (libraryItemId, episodeId = null) => {
|
getDownloadItem:
|
||||||
return state.itemDownloads.find(i => {
|
(state) =>
|
||||||
// if (episodeId && !i.episodes.some(e => e.id == episodeId)) return false
|
(libraryItemId, episodeId = null) => {
|
||||||
if (episodeId && i.episodeId !== episodeId) return false
|
return state.itemDownloads.find((i) => {
|
||||||
return i.libraryItemId == libraryItemId
|
// if (episodeId && !i.episodes.some(e => e.id == episodeId)) return false
|
||||||
})
|
if (episodeId && i.episodeId !== episodeId) return false
|
||||||
},
|
return i.libraryItemId == libraryItemId
|
||||||
getLibraryItemCoverSrc: (state, getters, rootState, rootGetters) => (libraryItem, placeholder, raw = false) => {
|
})
|
||||||
if (!libraryItem) return placeholder
|
},
|
||||||
const media = libraryItem.media
|
getLibraryItemCoverSrc:
|
||||||
if (!media || !media.coverPath || media.coverPath === placeholder) return placeholder
|
(state, getters, rootState, rootGetters) =>
|
||||||
|
(libraryItem, placeholder, raw = false) => {
|
||||||
|
if (!libraryItem) return placeholder
|
||||||
|
const media = libraryItem.media
|
||||||
|
if (!media || !media.coverPath || media.coverPath === placeholder) return placeholder
|
||||||
|
|
||||||
// Absolute URL covers (should no longer be used)
|
// Absolute URL covers (should no longer be used)
|
||||||
if (media.coverPath.startsWith('http:') || media.coverPath.startsWith('https:')) return media.coverPath
|
if (media.coverPath.startsWith('http:') || media.coverPath.startsWith('https:')) return media.coverPath
|
||||||
|
|
||||||
const userToken = rootGetters['user/getToken']
|
const serverAddress = rootGetters['user/getServerAddress']
|
||||||
const serverAddress = rootGetters['user/getServerAddress']
|
if (!serverAddress) return placeholder
|
||||||
if (!userToken || !serverAddress) return placeholder
|
|
||||||
|
|
||||||
const lastUpdate = libraryItem.updatedAt || Date.now()
|
const lastUpdate = libraryItem.updatedAt || Date.now()
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') { // Testing
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
// return `http://localhost:3333/api/items/${libraryItem.id}/cover?token=${userToken}&ts=${lastUpdate}`
|
// Testing
|
||||||
}
|
// return `http://localhost:3333/api/items/${libraryItem.id}/cover?ts=${lastUpdate}`
|
||||||
|
}
|
||||||
|
|
||||||
const url = new URL(`${serverAddress}/api/items/${libraryItem.id}/cover`)
|
const url = new URL(`${serverAddress}/api/items/${libraryItem.id}/cover`)
|
||||||
return `${url}?token=${userToken}&ts=${lastUpdate}${raw ? '&raw=1' : ''}`
|
return `${url}?ts=${lastUpdate}${raw ? '&raw=1' : ''}`
|
||||||
},
|
},
|
||||||
getLibraryItemCoverSrcById: (state, getters, rootState, rootGetters) => (libraryItemId, placeholder = null) => {
|
getLibraryItemCoverSrcById:
|
||||||
if (!placeholder) placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
|
(state, getters, rootState, rootGetters) =>
|
||||||
if (!libraryItemId) return placeholder
|
(libraryItemId, placeholder = null) => {
|
||||||
const userToken = rootGetters['user/getToken']
|
if (!placeholder) placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
|
||||||
const serverAddress = rootGetters['user/getServerAddress']
|
if (!libraryItemId) return placeholder
|
||||||
if (!userToken || !serverAddress) return placeholder
|
const serverAddress = rootGetters['user/getServerAddress']
|
||||||
|
if (!serverAddress) return placeholder
|
||||||
|
|
||||||
const url = new URL(`${serverAddress}/api/items/${libraryItemId}/cover`)
|
const url = new URL(`${serverAddress}/api/items/${libraryItemId}/cover`)
|
||||||
return `${url}?token=${userToken}`
|
return url.toString()
|
||||||
},
|
},
|
||||||
getLocalMediaProgressById: (state) => (localLibraryItemId, episodeId = null) => {
|
getLocalMediaProgressById:
|
||||||
return state.localMediaProgress.find(lmp => {
|
(state) =>
|
||||||
if (episodeId != null && lmp.localEpisodeId != episodeId) return false
|
(localLibraryItemId, episodeId = null) => {
|
||||||
return lmp.localLibraryItemId == localLibraryItemId
|
return state.localMediaProgress.find((lmp) => {
|
||||||
})
|
if (episodeId != null && lmp.localEpisodeId != episodeId) return false
|
||||||
},
|
return lmp.localLibraryItemId == localLibraryItemId
|
||||||
getLocalMediaProgressByServerItemId: (state) => (libraryItemId, episodeId = null) => {
|
})
|
||||||
return state.localMediaProgress.find(lmp => {
|
},
|
||||||
if (episodeId != null && lmp.episodeId != episodeId) return false
|
getLocalMediaProgressByServerItemId:
|
||||||
return lmp.libraryItemId == libraryItemId
|
(state) =>
|
||||||
})
|
(libraryItemId, episodeId = null) => {
|
||||||
},
|
return state.localMediaProgress.find((lmp) => {
|
||||||
getJumpForwardIcon: state => (jumpForwardTime) => {
|
if (episodeId != null && lmp.episodeId != episodeId) return false
|
||||||
const item = state.jumpForwardItems.find(i => i.value == jumpForwardTime)
|
return lmp.libraryItemId == libraryItemId
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getJumpForwardIcon: (state) => (jumpForwardTime) => {
|
||||||
|
const item = state.jumpForwardItems.find((i) => i.value == jumpForwardTime)
|
||||||
return item ? item.icon : 'forward_10'
|
return item ? item.icon : 'forward_10'
|
||||||
},
|
},
|
||||||
getJumpBackwardsIcon: state => (jumpBackwardsTime) => {
|
getJumpBackwardsIcon: (state) => (jumpBackwardsTime) => {
|
||||||
const item = state.jumpBackwardsItems.find(i => i.value == jumpBackwardsTime)
|
const item = state.jumpBackwardsItems.find((i) => i.value == jumpBackwardsTime)
|
||||||
return item ? item.icon : 'replay_10'
|
return item ? item.icon : 'replay_10'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,7 +125,7 @@ export const mutations = {
|
|||||||
state.isModalOpen = val
|
state.isModalOpen = val
|
||||||
},
|
},
|
||||||
addUpdateItemDownload(state, downloadItem) {
|
addUpdateItemDownload(state, downloadItem) {
|
||||||
var index = state.itemDownloads.findIndex(i => i.id == downloadItem.id)
|
var index = state.itemDownloads.findIndex((i) => i.id == downloadItem.id)
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
state.itemDownloads.splice(index, 1, downloadItem)
|
state.itemDownloads.splice(index, 1, downloadItem)
|
||||||
} else {
|
} else {
|
||||||
@@ -124,7 +133,7 @@ export const mutations = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateDownloadItemPart(state, downloadItemPart) {
|
updateDownloadItemPart(state, downloadItemPart) {
|
||||||
const downloadItem = state.itemDownloads.find(i => i.id == downloadItemPart.downloadItemId)
|
const downloadItem = state.itemDownloads.find((i) => i.id == downloadItemPart.downloadItemId)
|
||||||
if (!downloadItem) {
|
if (!downloadItem) {
|
||||||
console.error('updateDownloadItemPart: Download item not found for itemPart', JSON.stringify(downloadItemPart))
|
console.error('updateDownloadItemPart: Download item not found for itemPart', JSON.stringify(downloadItemPart))
|
||||||
return
|
return
|
||||||
@@ -132,7 +141,7 @@ export const mutations = {
|
|||||||
|
|
||||||
let totalBytes = 0
|
let totalBytes = 0
|
||||||
let totalBytesDownloaded = 0
|
let totalBytesDownloaded = 0
|
||||||
downloadItem.downloadItemParts = downloadItem.downloadItemParts.map(dip => {
|
downloadItem.downloadItemParts = downloadItem.downloadItemParts.map((dip) => {
|
||||||
let newDip = dip.id == downloadItemPart.id ? downloadItemPart : dip
|
let newDip = dip.id == downloadItemPart.id ? downloadItemPart : dip
|
||||||
|
|
||||||
totalBytes += newDip.completed ? Number(newDip.bytesDownloaded) : Number(newDip.fileSize)
|
totalBytes += newDip.completed ? Number(newDip.bytesDownloaded) : Number(newDip.fileSize)
|
||||||
@@ -149,7 +158,7 @@ export const mutations = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeItemDownload(state, id) {
|
removeItemDownload(state, id) {
|
||||||
state.itemDownloads = state.itemDownloads.filter(i => i.id != id)
|
state.itemDownloads = state.itemDownloads.filter((i) => i.id != id)
|
||||||
},
|
},
|
||||||
setBookshelfListView(state, val) {
|
setBookshelfListView(state, val) {
|
||||||
state.bookshelfListView = val
|
state.bookshelfListView = val
|
||||||
@@ -164,7 +173,7 @@ export const mutations = {
|
|||||||
if (!prog || !prog.id) {
|
if (!prog || !prog.id) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var index = state.localMediaProgress.findIndex(lmp => lmp.id == prog.id)
|
var index = state.localMediaProgress.findIndex((lmp) => lmp.id == prog.id)
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
state.localMediaProgress.splice(index, 1, prog)
|
state.localMediaProgress.splice(index, 1, prog)
|
||||||
} else {
|
} else {
|
||||||
@@ -172,10 +181,10 @@ export const mutations = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeLocalMediaProgress(state, id) {
|
removeLocalMediaProgress(state, id) {
|
||||||
state.localMediaProgress = state.localMediaProgress.filter(lmp => lmp.id != id)
|
state.localMediaProgress = state.localMediaProgress.filter((lmp) => lmp.id != id)
|
||||||
},
|
},
|
||||||
removeLocalMediaProgressForItem(state, llid) {
|
removeLocalMediaProgressForItem(state, llid) {
|
||||||
state.localMediaProgress = state.localMediaProgress.filter(lmp => lmp.localLibraryItemId !== llid)
|
state.localMediaProgress = state.localMediaProgress.filter((lmp) => lmp.localLibraryItemId !== llid)
|
||||||
},
|
},
|
||||||
setLastSearch(state, val) {
|
setLastSearch(state, val) {
|
||||||
state.lastSearch = val
|
state.lastSearch = val
|
||||||
@@ -203,4 +212,4 @@ export const mutations = {
|
|||||||
state.rssFeedEntity = entity
|
state.rssFeedEntity = entity
|
||||||
state.showRSSFeedOpenCloseModal = true
|
state.showRSSFeedOpenCloseModal = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"ButtonManageLocalFiles": "Manage Local Files",
|
"ButtonManageLocalFiles": "Manage Local Files",
|
||||||
"ButtonNewFolder": "New Folder",
|
"ButtonNewFolder": "New Folder",
|
||||||
"ButtonNextEpisode": "Next Episode",
|
"ButtonNextEpisode": "Next Episode",
|
||||||
|
"ButtonOk": "Ok",
|
||||||
"ButtonOpenFeed": "Open Feed",
|
"ButtonOpenFeed": "Open Feed",
|
||||||
"ButtonOverride": "Override",
|
"ButtonOverride": "Override",
|
||||||
"ButtonPause": "Pause",
|
"ButtonPause": "Pause",
|
||||||
@@ -75,6 +76,7 @@
|
|||||||
"HeaderPlaybackSettings": "Playback Settings",
|
"HeaderPlaybackSettings": "Playback Settings",
|
||||||
"HeaderPlaylist": "Playlist",
|
"HeaderPlaylist": "Playlist",
|
||||||
"HeaderPlaylistItems": "Playlist Items",
|
"HeaderPlaylistItems": "Playlist Items",
|
||||||
|
"HeaderProgressSyncFailed": "Progress Sync Failed",
|
||||||
"HeaderRSSFeed": "RSS Feed",
|
"HeaderRSSFeed": "RSS Feed",
|
||||||
"HeaderRSSFeedGeneral": "RSS Details",
|
"HeaderRSSFeedGeneral": "RSS Details",
|
||||||
"HeaderRSSFeedIsOpen": "RSS Feed is Open",
|
"HeaderRSSFeedIsOpen": "RSS Feed is Open",
|
||||||
@@ -195,6 +197,8 @@
|
|||||||
"LabelNotFinished": "Not Finished",
|
"LabelNotFinished": "Not Finished",
|
||||||
"LabelNotStarted": "Not Started",
|
"LabelNotStarted": "Not Started",
|
||||||
"LabelNumEpisodes": "{0} episodes",
|
"LabelNumEpisodes": "{0} episodes",
|
||||||
|
"LabelNumEpisodesIncomplete": "{0} episodes, {1} incomplete",
|
||||||
|
"LabelNumberOfEpisodes": "# of Episodes",
|
||||||
"LabelOff": "Off",
|
"LabelOff": "Off",
|
||||||
"LabelOn": "On",
|
"LabelOn": "On",
|
||||||
"LabelPassword": "Password",
|
"LabelPassword": "Password",
|
||||||
@@ -308,7 +312,10 @@
|
|||||||
"MessageNoSeries": "No series",
|
"MessageNoSeries": "No series",
|
||||||
"MessageNoUpdatesWereNecessary": "No updates were necessary",
|
"MessageNoUpdatesWereNecessary": "No updates were necessary",
|
||||||
"MessageNoUserPlaylists": "You have no playlists",
|
"MessageNoUserPlaylists": "You have no playlists",
|
||||||
|
"MessageOldServerConnectionWarning": "Server connection config is using an old user ID. Please delete and re-add this server connection.",
|
||||||
|
"MessageOldServerConnectionWarningHelp": "You originally set up the connection to this server prior to the database migration in 2.3.0, released June 2023. A future server update will remove the ability to sign in with this old connection. Please delete the existing server connection and connect again (using the same server address and credentials). If you have any downloaded media on this device, the media will need to be downloaded again to sync with the server.",
|
||||||
"MessagePodcastSearchField": "Enter search term or RSS feed URL",
|
"MessagePodcastSearchField": "Enter search term or RSS feed URL",
|
||||||
|
"MessageProgressSyncFailed": "The most recent attempt to report your listening progress to the server has failed. Progress sync requests will continue to be attempted every 15 seconds to 1 minute while media is playing.",
|
||||||
"MessageReportBugsAndContribute": "Report bugs, request features, and contribute on",
|
"MessageReportBugsAndContribute": "Report bugs, request features, and contribute on",
|
||||||
"MessageSeriesAlreadyDownloaded": "You have already downloaded all books in this series.",
|
"MessageSeriesAlreadyDownloaded": "You have already downloaded all books in this series.",
|
||||||
"MessageSeriesDownloadConfirm": "Download missing {0} book(s) with {1} file(s), totaling {2} to folder {3}?",
|
"MessageSeriesDownloadConfirm": "Download missing {0} book(s) with {1} file(s), totaling {2} to folder {3}?",
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
"ButtonPlaying": "Toistetaan",
|
"ButtonPlaying": "Toistetaan",
|
||||||
"ButtonPlaylists": "Soittolistat",
|
"ButtonPlaylists": "Soittolistat",
|
||||||
"ButtonRead": "Lue",
|
"ButtonRead": "Lue",
|
||||||
|
"ButtonReadLess": "Lue vähemmän",
|
||||||
|
"ButtonReadMore": "Lue enemmän",
|
||||||
"ButtonRemove": "Poista",
|
"ButtonRemove": "Poista",
|
||||||
"ButtonRemoveFromServer": "Poista palvelimelta",
|
"ButtonRemoveFromServer": "Poista palvelimelta",
|
||||||
"ButtonSave": "Tallenna",
|
"ButtonSave": "Tallenna",
|
||||||
@@ -52,6 +54,7 @@
|
|||||||
"ButtonYes": "Kyllä",
|
"ButtonYes": "Kyllä",
|
||||||
"HeaderAccount": "Tili",
|
"HeaderAccount": "Tili",
|
||||||
"HeaderAdvanced": "Edistynyt",
|
"HeaderAdvanced": "Edistynyt",
|
||||||
|
"HeaderAndroidAutoSettings": "Android Auto -asetukset",
|
||||||
"HeaderAudioTracks": "Ääniraidat",
|
"HeaderAudioTracks": "Ääniraidat",
|
||||||
"HeaderChapters": "Luvut",
|
"HeaderChapters": "Luvut",
|
||||||
"HeaderCollection": "Kokoelma",
|
"HeaderCollection": "Kokoelma",
|
||||||
@@ -86,6 +89,7 @@
|
|||||||
"HeaderYourStats": "Tilastosi",
|
"HeaderYourStats": "Tilastosi",
|
||||||
"LabelAddToPlaylist": "Lisää soittolistaan",
|
"LabelAddToPlaylist": "Lisää soittolistaan",
|
||||||
"LabelAddedAt": "Lisätty listalle",
|
"LabelAddedAt": "Lisätty listalle",
|
||||||
|
"LabelAddedDate": "Lisätty {0}",
|
||||||
"LabelAll": "Kaikki",
|
"LabelAll": "Kaikki",
|
||||||
"LabelAllowSeekingOnMediaControls": "Salli kelaaminen ilmoituksen säätimillä",
|
"LabelAllowSeekingOnMediaControls": "Salli kelaaminen ilmoituksen säätimillä",
|
||||||
"LabelAlways": "Aina",
|
"LabelAlways": "Aina",
|
||||||
@@ -128,8 +132,10 @@
|
|||||||
"LabelEbook": "E-kirja",
|
"LabelEbook": "E-kirja",
|
||||||
"LabelEbooks": "E-kirjat",
|
"LabelEbooks": "E-kirjat",
|
||||||
"LabelEnable": "Ota käyttöön",
|
"LabelEnable": "Ota käyttöön",
|
||||||
|
"LabelEnableMp3IndexSeeking": "Ota mp3-hakemistohaku käyttöön",
|
||||||
"LabelEnd": "Loppu",
|
"LabelEnd": "Loppu",
|
||||||
"LabelEndOfChapter": "Luvun loppu",
|
"LabelEndOfChapter": "Luvun loppu",
|
||||||
|
"LabelEndTime": "Päättymisaika",
|
||||||
"LabelEpisode": "Jakso",
|
"LabelEpisode": "Jakso",
|
||||||
"LabelFeedURL": "Syötteen URL",
|
"LabelFeedURL": "Syötteen URL",
|
||||||
"LabelFile": "Tiedosto",
|
"LabelFile": "Tiedosto",
|
||||||
@@ -138,6 +144,8 @@
|
|||||||
"LabelFilename": "Tiedostonimi",
|
"LabelFilename": "Tiedostonimi",
|
||||||
"LabelFinished": "Valmis",
|
"LabelFinished": "Valmis",
|
||||||
"LabelFolder": "Kansio",
|
"LabelFolder": "Kansio",
|
||||||
|
"LabelFontBoldness": "Kirjasintyyppien lihavointi",
|
||||||
|
"LabelFontScale": "Kirjasintyyppien skaalautuminen",
|
||||||
"LabelGenre": "Lajityyppi",
|
"LabelGenre": "Lajityyppi",
|
||||||
"LabelGenres": "Lajityypit",
|
"LabelGenres": "Lajityypit",
|
||||||
"LabelHapticFeedback": "Tuntopalaute",
|
"LabelHapticFeedback": "Tuntopalaute",
|
||||||
@@ -145,14 +153,18 @@
|
|||||||
"LabelHost": "Isäntä",
|
"LabelHost": "Isäntä",
|
||||||
"LabelInProgress": "Kesken",
|
"LabelInProgress": "Kesken",
|
||||||
"LabelIncomplete": "Keskeneräinen",
|
"LabelIncomplete": "Keskeneräinen",
|
||||||
|
"LabelInternalAppStorage": "Sovelluksen sisäinen tallennustila",
|
||||||
"LabelJumpBackwardsTime": "Hyppää taaksepäin ajassa",
|
"LabelJumpBackwardsTime": "Hyppää taaksepäin ajassa",
|
||||||
"LabelJumpForwardsTime": "Hyppää eteenpäin ajassa",
|
"LabelJumpForwardsTime": "Hyppää eteenpäin ajassa",
|
||||||
"LabelLanguage": "Kieli",
|
"LabelLanguage": "Kieli",
|
||||||
|
"LabelLayout": "Asettelu",
|
||||||
|
"LabelLayoutSinglePage": "Yksi sivu",
|
||||||
"LabelLight": "Vaalea",
|
"LabelLight": "Vaalea",
|
||||||
"LabelLineSpacing": "Riviväli",
|
"LabelLineSpacing": "Riviväli",
|
||||||
"LabelListenAgain": "Kuuntele uudelleen",
|
"LabelListenAgain": "Kuuntele uudelleen",
|
||||||
"LabelLocalBooks": "Paikalliset kirjat",
|
"LabelLocalBooks": "Paikalliset kirjat",
|
||||||
"LabelLocalPodcasts": "Paikalliset podcastit",
|
"LabelLocalPodcasts": "Paikalliset podcastit",
|
||||||
|
"LabelLockOrientation": "Lukitse suunta",
|
||||||
"LabelLockPlayer": "Lukitse soitin",
|
"LabelLockPlayer": "Lukitse soitin",
|
||||||
"LabelLow": "Matala",
|
"LabelLow": "Matala",
|
||||||
"LabelMediaType": "Mediatyyppi",
|
"LabelMediaType": "Mediatyyppi",
|
||||||
@@ -163,11 +175,15 @@
|
|||||||
"LabelNarrator": "Lukija",
|
"LabelNarrator": "Lukija",
|
||||||
"LabelNarrators": "Lukijat",
|
"LabelNarrators": "Lukijat",
|
||||||
"LabelNavigateWithVolume": "Navigoi äänenvoimakkuus-painikkeilla",
|
"LabelNavigateWithVolume": "Navigoi äänenvoimakkuus-painikkeilla",
|
||||||
|
"LabelNavigateWithVolumeMirrored": "Peilattu",
|
||||||
|
"LabelNavigateWithVolumeWhilePlaying": "Salli siirtyminen äänenvoimakkuuspainikkeilla toiston aikana",
|
||||||
"LabelNever": "Ei koskaan",
|
"LabelNever": "Ei koskaan",
|
||||||
"LabelNewestAuthors": "Uusimmat kirjailijat",
|
"LabelNewestAuthors": "Uusimmat kirjailijat",
|
||||||
"LabelNewestEpisodes": "Uusimmat jaksot",
|
"LabelNewestEpisodes": "Uusimmat jaksot",
|
||||||
"LabelNo": "Ei",
|
"LabelNo": "Ei",
|
||||||
|
"LabelNotFinished": "Ei valmis",
|
||||||
"LabelNotStarted": "Ei aloitettu",
|
"LabelNotStarted": "Ei aloitettu",
|
||||||
|
"LabelNumEpisodes": "{0} jaksoa",
|
||||||
"LabelOff": "Pois päältä",
|
"LabelOff": "Pois päältä",
|
||||||
"LabelOn": "Päällä",
|
"LabelOn": "Päällä",
|
||||||
"LabelPassword": "Salasana",
|
"LabelPassword": "Salasana",
|
||||||
@@ -176,7 +192,10 @@
|
|||||||
"LabelPlaybackSpeed": "Toistonopeus",
|
"LabelPlaybackSpeed": "Toistonopeus",
|
||||||
"LabelPodcast": "Podcast",
|
"LabelPodcast": "Podcast",
|
||||||
"LabelPodcasts": "Podcastit",
|
"LabelPodcasts": "Podcastit",
|
||||||
|
"LabelProgress": "Edistyminen",
|
||||||
|
"LabelPubDate": "Julkaisupäivä",
|
||||||
"LabelPublishYear": "Julkaisuvuosi",
|
"LabelPublishYear": "Julkaisuvuosi",
|
||||||
|
"LabelPublishedDate": "Julkaistu {0}",
|
||||||
"LabelRSSFeedPreventIndexing": "Estä indeksointi",
|
"LabelRSSFeedPreventIndexing": "Estä indeksointi",
|
||||||
"LabelRandomly": "Satunnaisesti",
|
"LabelRandomly": "Satunnaisesti",
|
||||||
"LabelRead": "Lue",
|
"LabelRead": "Lue",
|
||||||
|
|||||||
+23
-21
@@ -55,7 +55,7 @@
|
|||||||
"HeaderAudioTracks": "Ljudspår",
|
"HeaderAudioTracks": "Ljudspår",
|
||||||
"HeaderChapters": "Kapitel",
|
"HeaderChapters": "Kapitel",
|
||||||
"HeaderCollection": "Samling",
|
"HeaderCollection": "Samling",
|
||||||
"HeaderCollectionItems": "Samlingselement",
|
"HeaderCollectionItems": "Böcker i samlingen",
|
||||||
"HeaderConnectionStatus": "Anslutnings Status",
|
"HeaderConnectionStatus": "Anslutnings Status",
|
||||||
"HeaderDataSettings": "Data Inställningar",
|
"HeaderDataSettings": "Data Inställningar",
|
||||||
"HeaderDetails": "Detaljer",
|
"HeaderDetails": "Detaljer",
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
"HeaderEbookFiles": "E-boksfiler",
|
"HeaderEbookFiles": "E-boksfiler",
|
||||||
"HeaderEpisodes": "Avsnitt",
|
"HeaderEpisodes": "Avsnitt",
|
||||||
"HeaderEreaderSettings": "E-boksinställningar",
|
"HeaderEreaderSettings": "E-boksinställningar",
|
||||||
"HeaderLatestEpisodes": "Senaste avsnitt",
|
"HeaderLatestEpisodes": "Senaste avsnitten",
|
||||||
"HeaderLibraries": "Bibliotek",
|
"HeaderLibraries": "Bibliotek",
|
||||||
"HeaderLocalFolders": "Lokala Kataloger",
|
"HeaderLocalFolders": "Lokala Kataloger",
|
||||||
"HeaderLocalLibraryItems": "Lokala Bibliotek Filer",
|
"HeaderLocalLibraryItems": "Lokala Bibliotek Filer",
|
||||||
@@ -71,16 +71,16 @@
|
|||||||
"HeaderOpenRSSFeed": "Öppna RSS-flöde",
|
"HeaderOpenRSSFeed": "Öppna RSS-flöde",
|
||||||
"HeaderPlaybackSettings": "Uppspelningsinställningar",
|
"HeaderPlaybackSettings": "Uppspelningsinställningar",
|
||||||
"HeaderPlaylist": "Spellista",
|
"HeaderPlaylist": "Spellista",
|
||||||
"HeaderPlaylistItems": "Spellistobjekt",
|
"HeaderPlaylistItems": "Böcker i spellistan",
|
||||||
"HeaderRSSFeed": "RSS flöde",
|
"HeaderRSSFeed": "RSS flöde",
|
||||||
"HeaderRSSFeedGeneral": "RSS-information",
|
"HeaderRSSFeedGeneral": "RSS-information",
|
||||||
"HeaderRSSFeedIsOpen": "RSS-flödet är öppet",
|
"HeaderRSSFeedIsOpen": "RSS-flödet är öppet",
|
||||||
"HeaderSelectDownloadLocation": "Välj Nedladdnings Plats",
|
"HeaderSelectDownloadLocation": "Välj Nedladdnings Plats",
|
||||||
"HeaderSettings": "Inställningar",
|
"HeaderSettings": "Inställningar",
|
||||||
"HeaderSleepTimer": "Sovtidtagare",
|
"HeaderSleepTimer": "Timer för att sova",
|
||||||
"HeaderSleepTimerSettings": "Sovtimer Inställningar",
|
"HeaderSleepTimerSettings": "Sovtimer Inställningar",
|
||||||
"HeaderStatsMinutesListeningChart": "Minuters lyssning (senaste 7 dagar)",
|
"HeaderStatsMinutesListeningChart": "Minuters lyssning (senaste 7 dagarna)",
|
||||||
"HeaderStatsRecentSessions": "Senaste sessioner",
|
"HeaderStatsRecentSessions": "Senaste tillfällena",
|
||||||
"HeaderTableOfContents": "Innehållsförteckning",
|
"HeaderTableOfContents": "Innehållsförteckning",
|
||||||
"HeaderUserInterfaceSettings": "Användargränssnittsinställningar",
|
"HeaderUserInterfaceSettings": "Användargränssnittsinställningar",
|
||||||
"HeaderYourStats": "Dina statistik",
|
"HeaderYourStats": "Dina statistik",
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
"LabelChapterTrack": "Kapitel Spår",
|
"LabelChapterTrack": "Kapitel Spår",
|
||||||
"LabelChapters": "Kapitel",
|
"LabelChapters": "Kapitel",
|
||||||
"LabelClosePlayer": "Stäng spelaren",
|
"LabelClosePlayer": "Stäng spelaren",
|
||||||
"LabelCollapseSeries": "Fäll ihop serie",
|
"LabelCollapseSeries": "Komprimera serier",
|
||||||
"LabelComplete": "Komplett",
|
"LabelComplete": "Komplett",
|
||||||
"LabelContinueBooks": "Fortsätt Böcker",
|
"LabelContinueBooks": "Fortsätt Böcker",
|
||||||
"LabelContinueEpisodes": "Fortsätt Episoder",
|
"LabelContinueEpisodes": "Fortsätt Episoder",
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
"LabelDownloaded": "Nedladdat",
|
"LabelDownloaded": "Nedladdat",
|
||||||
"LabelDuration": "Varaktighet",
|
"LabelDuration": "Varaktighet",
|
||||||
"LabelEbook": "E-bok",
|
"LabelEbook": "E-bok",
|
||||||
"LabelEbooks": "Eböcker",
|
"LabelEbooks": "E-böcker",
|
||||||
"LabelEnable": "Aktivera",
|
"LabelEnable": "Aktivera",
|
||||||
"LabelEnableMp3IndexSeeking": "Aktivera mp3 index sökning",
|
"LabelEnableMp3IndexSeeking": "Aktivera mp3 index sökning",
|
||||||
"LabelEnableMp3IndexSeekingHelp": "Den här inställningen bör endast aktiveras om du har mp3-filer som inte söker korrekt. Felaktig sökning beror med största sannolikhet på MP3-filer med variabel birate (VBR). Den här inställningen tvingar fram indexsökning, där en tid-till-byte-mappning byggs upp när filen läses. I vissa fall med stora MP3-filer blir det en fördröjning vid sökning mot slutet av filen.",
|
"LabelEnableMp3IndexSeekingHelp": "Den här inställningen bör endast aktiveras om du har mp3-filer som inte söker korrekt. Felaktig sökning beror med största sannolikhet på MP3-filer med variabel birate (VBR). Den här inställningen tvingar fram indexsökning, där en tid-till-byte-mappning byggs upp när filen läses. I vissa fall med stora MP3-filer blir det en fördröjning vid sökning mot slutet av filen.",
|
||||||
@@ -136,8 +136,8 @@
|
|||||||
"LabelEpisode": "Avsnitt",
|
"LabelEpisode": "Avsnitt",
|
||||||
"LabelFeedURL": "Flödes-URL",
|
"LabelFeedURL": "Flödes-URL",
|
||||||
"LabelFile": "Fil",
|
"LabelFile": "Fil",
|
||||||
"LabelFileBirthtime": "Födelse-tidpunkt för fil",
|
"LabelFileBirthtime": "Tidpunkt, filen skapades",
|
||||||
"LabelFileModified": "Fil ändrad",
|
"LabelFileModified": "Tidpunkt, filen ändrades",
|
||||||
"LabelFilename": "Filnamn",
|
"LabelFilename": "Filnamn",
|
||||||
"LabelFinished": "Avslutad",
|
"LabelFinished": "Avslutad",
|
||||||
"LabelFolder": "Mapp",
|
"LabelFolder": "Mapp",
|
||||||
@@ -146,8 +146,8 @@
|
|||||||
"LabelGenre": "Genre",
|
"LabelGenre": "Genre",
|
||||||
"LabelGenres": "Genrer",
|
"LabelGenres": "Genrer",
|
||||||
"LabelHapticFeedback": "Haptisk feedback",
|
"LabelHapticFeedback": "Haptisk feedback",
|
||||||
"LabelHasEbook": "Har E-bok",
|
"LabelHasEbook": "Har e-bok",
|
||||||
"LabelHasSupplementaryEbook": "Har komplimenterande E-bok",
|
"LabelHasSupplementaryEbook": "Har kompletterande e-bok",
|
||||||
"LabelHeavy": "Tung",
|
"LabelHeavy": "Tung",
|
||||||
"LabelHigh": "Hög",
|
"LabelHigh": "Hög",
|
||||||
"LabelHost": "Värd",
|
"LabelHost": "Värd",
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
"LabelNewestEpisodes": "Senast tillagda avsnitt",
|
"LabelNewestEpisodes": "Senast tillagda avsnitt",
|
||||||
"LabelNo": "Nej",
|
"LabelNo": "Nej",
|
||||||
"LabelNotFinished": "Ej avslutad",
|
"LabelNotFinished": "Ej avslutad",
|
||||||
"LabelNotStarted": "Inte påbörjad",
|
"LabelNotStarted": "Ej påbörjad",
|
||||||
"LabelOff": "Av",
|
"LabelOff": "Av",
|
||||||
"LabelOn": "På",
|
"LabelOn": "På",
|
||||||
"LabelPassword": "Lösenord",
|
"LabelPassword": "Lösenord",
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
"LabelRandomly": "Slumpartat",
|
"LabelRandomly": "Slumpartat",
|
||||||
"LabelRead": "Läst",
|
"LabelRead": "Läst",
|
||||||
"LabelReadAgain": "Läs igen",
|
"LabelReadAgain": "Läs igen",
|
||||||
"LabelRecentSeries": "Senaste serier",
|
"LabelRecentSeries": "Senaste serierna",
|
||||||
"LabelRecentlyAdded": "Nyligen tillagd",
|
"LabelRecentlyAdded": "Nyligen tillagd",
|
||||||
"LabelRemoveFromPlaylist": "Ta bort från spellista",
|
"LabelRemoveFromPlaylist": "Ta bort från spellista",
|
||||||
"LabelScaleElapsedTimeBySpeed": "Skaländra uppspelningsposition efter uppspelningshastighet.",
|
"LabelScaleElapsedTimeBySpeed": "Skaländra uppspelningsposition efter uppspelningshastighet.",
|
||||||
@@ -217,17 +217,17 @@
|
|||||||
"LabelShakeSensitivity": "Skakkänslighet",
|
"LabelShakeSensitivity": "Skakkänslighet",
|
||||||
"LabelShowAll": "Visa alla",
|
"LabelShowAll": "Visa alla",
|
||||||
"LabelSize": "Storlek",
|
"LabelSize": "Storlek",
|
||||||
"LabelSleepTimer": "Sleeptimer",
|
"LabelSleepTimer": "Timer för sova",
|
||||||
"LabelStart": "Starta",
|
"LabelStart": "Starta",
|
||||||
"LabelStartTime": "Starttid",
|
"LabelStartTime": "Starttid",
|
||||||
"LabelStatsBestDay": "Bästa dag",
|
"LabelStatsBestDay": "Bästa dag",
|
||||||
"LabelStatsDailyAverage": "Dagligt genomsnitt",
|
"LabelStatsDailyAverage": "Dagligt genomsnitt",
|
||||||
"LabelStatsDays": "Dagar",
|
"LabelStatsDays": "Dagar",
|
||||||
"LabelStatsDaysListened": "Dagar lyssnade",
|
"LabelStatsDaysListened": "dagars lyssnande",
|
||||||
"LabelStatsInARow": "i rad",
|
"LabelStatsInARow": "i rad",
|
||||||
"LabelStatsItemsFinished": "Objekt avslutade",
|
"LabelStatsItemsFinished": "böcker avslutade",
|
||||||
"LabelStatsMinutes": "minuter",
|
"LabelStatsMinutes": "minuter",
|
||||||
"LabelStatsMinutesListening": "Minuter av lyssnande",
|
"LabelStatsMinutesListening": "minuters lyssnande",
|
||||||
"LabelStatsWeekListening": "Veckans lyssnande",
|
"LabelStatsWeekListening": "Veckans lyssnande",
|
||||||
"LabelStreamingUsingCellular": "Strömma över mobildata",
|
"LabelStreamingUsingCellular": "Strömma över mobildata",
|
||||||
"LabelTag": "Tagg",
|
"LabelTag": "Tagg",
|
||||||
@@ -247,6 +247,8 @@
|
|||||||
"LabelUsername": "Användarnamn",
|
"LabelUsername": "Användarnamn",
|
||||||
"LabelVeryHigh": "Väldigt hög",
|
"LabelVeryHigh": "Väldigt hög",
|
||||||
"LabelVeryLow": "Väldigt låg",
|
"LabelVeryLow": "Väldigt låg",
|
||||||
|
"LabelYearReviewHide": "Dölj årets sammanställning",
|
||||||
|
"LabelYearReviewShow": "Visa årets sammanställning",
|
||||||
"LabelYourBookmarks": "Dina bokmärken",
|
"LabelYourBookmarks": "Dina bokmärken",
|
||||||
"LabelYourProgress": "Din framsteg",
|
"LabelYourProgress": "Din framsteg",
|
||||||
"MessageAndroid10Downloads": "Android 10 och lägre använder intern applagring för nedladdningar.",
|
"MessageAndroid10Downloads": "Android 10 och lägre använder intern applagring för nedladdningar.",
|
||||||
@@ -282,7 +284,7 @@
|
|||||||
"MessageNoChapters": "Inga kapitel",
|
"MessageNoChapters": "Inga kapitel",
|
||||||
"MessageNoItems": "Inga objekt",
|
"MessageNoItems": "Inga objekt",
|
||||||
"MessageNoItemsFound": "Inga objekt hittades",
|
"MessageNoItemsFound": "Inga objekt hittades",
|
||||||
"MessageNoListeningSessions": "Inga lyssningssessioner",
|
"MessageNoListeningSessions": "Inga lyssningstillfällen",
|
||||||
"MessageNoMediaFolders": "Inga Mediamappar",
|
"MessageNoMediaFolders": "Inga Mediamappar",
|
||||||
"MessageNoNetworkConnection": "Ingen nätverksanslutning",
|
"MessageNoNetworkConnection": "Ingen nätverksanslutning",
|
||||||
"MessageNoPodcastsFound": "Inga podcasts hittade",
|
"MessageNoPodcastsFound": "Inga podcasts hittade",
|
||||||
@@ -298,8 +300,8 @@
|
|||||||
"ToastBookmarkRemoveFailed": "Det gick inte att ta bort bokmärket",
|
"ToastBookmarkRemoveFailed": "Det gick inte att ta bort bokmärket",
|
||||||
"ToastBookmarkUpdateFailed": "Det gick inte att uppdatera bokmärket",
|
"ToastBookmarkUpdateFailed": "Det gick inte att uppdatera bokmärket",
|
||||||
"ToastDownloadNotAllowedOnCellular": "Nedladdning tillåts inte över mobildata",
|
"ToastDownloadNotAllowedOnCellular": "Nedladdning tillåts inte över mobildata",
|
||||||
"ToastItemMarkedAsFinishedFailed": "Misslyckades med att markera som färdig",
|
"ToastItemMarkedAsFinishedFailed": "Misslyckades med att markera den som avslutad",
|
||||||
"ToastItemMarkedAsNotFinishedFailed": "Misslyckades med att markera som ej färdig",
|
"ToastItemMarkedAsNotFinishedFailed": "Misslyckades med att markera den som ej avslutad",
|
||||||
"ToastPlaylistCreateFailed": "Det gick inte att skapa spellistan",
|
"ToastPlaylistCreateFailed": "Det gick inte att skapa spellistan",
|
||||||
"ToastPodcastCreateFailed": "Misslyckades med att skapa podcasten",
|
"ToastPodcastCreateFailed": "Misslyckades med att skapa podcasten",
|
||||||
"ToastPodcastCreateSuccess": "Podcasten skapad framgångsrikt",
|
"ToastPodcastCreateSuccess": "Podcasten skapad framgångsrikt",
|
||||||
|
|||||||
+9
-1
@@ -29,6 +29,7 @@
|
|||||||
"ButtonManageLocalFiles": "Керування локальними файлами",
|
"ButtonManageLocalFiles": "Керування локальними файлами",
|
||||||
"ButtonNewFolder": "Нова тека",
|
"ButtonNewFolder": "Нова тека",
|
||||||
"ButtonNextEpisode": "Наступний епізод",
|
"ButtonNextEpisode": "Наступний епізод",
|
||||||
|
"ButtonOk": "Добре",
|
||||||
"ButtonOpenFeed": "Відкрити стрічку",
|
"ButtonOpenFeed": "Відкрити стрічку",
|
||||||
"ButtonOverride": "Перевизначити",
|
"ButtonOverride": "Перевизначити",
|
||||||
"ButtonPause": "Призупинити",
|
"ButtonPause": "Призупинити",
|
||||||
@@ -75,6 +76,7 @@
|
|||||||
"HeaderPlaybackSettings": "Налаштування відтворення",
|
"HeaderPlaybackSettings": "Налаштування відтворення",
|
||||||
"HeaderPlaylist": "Список відтворення",
|
"HeaderPlaylist": "Список відтворення",
|
||||||
"HeaderPlaylistItems": "Елементи списку відтворення",
|
"HeaderPlaylistItems": "Елементи списку відтворення",
|
||||||
|
"HeaderProgressSyncFailed": "Помилка синхронізації прогресу",
|
||||||
"HeaderRSSFeed": "RSS-канал",
|
"HeaderRSSFeed": "RSS-канал",
|
||||||
"HeaderRSSFeedGeneral": "Деталі RSS",
|
"HeaderRSSFeedGeneral": "Деталі RSS",
|
||||||
"HeaderRSSFeedIsOpen": "RSS-канал відкрито",
|
"HeaderRSSFeedIsOpen": "RSS-канал відкрито",
|
||||||
@@ -163,6 +165,7 @@
|
|||||||
"LabelInternalAppStorage": "Внутрішня пам'ять додатку",
|
"LabelInternalAppStorage": "Внутрішня пам'ять додатку",
|
||||||
"LabelJumpBackwardsTime": "Час відмотування назад",
|
"LabelJumpBackwardsTime": "Час відмотування назад",
|
||||||
"LabelJumpForwardsTime": "Час перемотування вперед",
|
"LabelJumpForwardsTime": "Час перемотування вперед",
|
||||||
|
"LabelKeepScreenAwake": "Тримайте екран активним",
|
||||||
"LabelLanguage": "Мова",
|
"LabelLanguage": "Мова",
|
||||||
"LabelLayout": "Вигляд",
|
"LabelLayout": "Вигляд",
|
||||||
"LabelLayoutAuto": "Авто",
|
"LabelLayoutAuto": "Авто",
|
||||||
@@ -194,6 +197,8 @@
|
|||||||
"LabelNotFinished": "Незавершені",
|
"LabelNotFinished": "Незавершені",
|
||||||
"LabelNotStarted": "Непочаті",
|
"LabelNotStarted": "Непочаті",
|
||||||
"LabelNumEpisodes": "{0} епізодів",
|
"LabelNumEpisodes": "{0} епізодів",
|
||||||
|
"LabelNumEpisodesIncomplete": "{0} серій, {1} не завершено",
|
||||||
|
"LabelNumberOfEpisodes": "Кількість серій",
|
||||||
"LabelOff": "Вимкнути",
|
"LabelOff": "Вимкнути",
|
||||||
"LabelOn": "Увімкнено",
|
"LabelOn": "Увімкнено",
|
||||||
"LabelPassword": "Пароль",
|
"LabelPassword": "Пароль",
|
||||||
@@ -233,7 +238,7 @@
|
|||||||
"LabelSize": "Розмір",
|
"LabelSize": "Розмір",
|
||||||
"LabelSleepTimer": "Таймер вимкнення",
|
"LabelSleepTimer": "Таймер вимкнення",
|
||||||
"LabelStart": "Початок",
|
"LabelStart": "Початок",
|
||||||
"LabelStartTime": "Час початку",
|
"LabelStartTime": "Час Початку",
|
||||||
"LabelStatsBestDay": "Найкращий день",
|
"LabelStatsBestDay": "Найкращий день",
|
||||||
"LabelStatsDailyAverage": "В середньому за добу",
|
"LabelStatsDailyAverage": "В середньому за добу",
|
||||||
"LabelStatsDays": "Днів",
|
"LabelStatsDays": "Днів",
|
||||||
@@ -307,7 +312,10 @@
|
|||||||
"MessageNoSeries": "Серії відсутні",
|
"MessageNoSeries": "Серії відсутні",
|
||||||
"MessageNoUpdatesWereNecessary": "Оновлень не потрібно",
|
"MessageNoUpdatesWereNecessary": "Оновлень не потрібно",
|
||||||
"MessageNoUserPlaylists": "У вас немає списків відтворення",
|
"MessageNoUserPlaylists": "У вас немає списків відтворення",
|
||||||
|
"MessageOldServerConnectionWarning": "Конфігурація підключення до сервера використовує старий ідентифікатор користувача. Видаліть і додайте це підключення до сервера заново.",
|
||||||
|
"MessageOldServerConnectionWarningHelp": "Ви спочатку налаштували з’єднання з цим сервером перед міграцією бази даних у версії 2.3.0, випущеній у червні 2023 року. Майбутнє оновлення сервера скасує можливість входу за допомогою цього старого з’єднання. Будь ласка, видаліть існуюче підключення до сервера та підключіться знову (використовуючи ту саму адресу сервера та облікові дані). Якщо на цьому пристрої є будь-які завантажені медіафайли, їх потрібно буде завантажити ще раз, щоб синхронізувати із сервером.",
|
||||||
"MessagePodcastSearchField": "Введіть пошуковий запит або URL RSS-стрічки",
|
"MessagePodcastSearchField": "Введіть пошуковий запит або URL RSS-стрічки",
|
||||||
|
"MessageProgressSyncFailed": "Остання спроба повідомити про прогрес прослуховування на сервер не вдалася. Під час відтворення мультимедійних файлів кожні 15 секунд – 1 хвилину надсилатимуться запити на синхронізацію.",
|
||||||
"MessageReportBugsAndContribute": "Повідомляйте про помилки, пропонуйте функції та долучайтеся на",
|
"MessageReportBugsAndContribute": "Повідомляйте про помилки, пропонуйте функції та долучайтеся на",
|
||||||
"MessageSeriesAlreadyDownloaded": "Ви вже завантажили всі книги в цій серії.",
|
"MessageSeriesAlreadyDownloaded": "Ви вже завантажили всі книги в цій серії.",
|
||||||
"MessageSeriesDownloadConfirm": "Завантажити відсутні {0} книгу(ок) з {1} файл(ів), загалом {2}, до папки {3}?",
|
"MessageSeriesDownloadConfirm": "Завантажити відсутні {0} книгу(ок) з {1} файл(ів), загалом {2}, до папки {3}?",
|
||||||
|
|||||||
Reference in New Issue
Block a user