mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Merge branch 'master' into feat/book-series-info
This commit is contained in:
		
						commit
						0f338a5961
					
				@ -31,13 +31,6 @@
 | 
				
			|||||||
          <p cy-id="placeholderAuthorText" aria-hidden="true" class="text-center" style="color: rgb(247 223 187); opacity: 0.75" :style="{ fontSize: authorFontSize + 'em' }">{{ authorCleaned }}</p>
 | 
					          <p cy-id="placeholderAuthorText" aria-hidden="true" class="text-center" style="color: rgb(247 223 187); opacity: 0.75" :style="{ fontSize: authorFontSize + 'em' }">{{ authorCleaned }}</p>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div v-if="seriesSequenceList" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-20 text-right" :style="{ top: 0.375 + 'em', right: 0.375 + 'em', padding: `${0.1}em ${0.25}em` }" style="background-color: #78350f">
 | 
					 | 
				
			||||||
          <p :style="{ fontSize: 0.8 + 'em' }">#{{ seriesSequenceList }}</p>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div v-else-if="booksInSeries" class="absolute rounded-lg bg-black bg-opacity-90 box-shadow-md z-20" :style="{ top: 0.375 + 'em', right: 0.375 + 'em', padding: `${0.1}em ${0.25}em` }" style="background-color: #cd9d49dd">
 | 
					 | 
				
			||||||
          <p :style="{ fontSize: 0.8 + 'em' }">{{ booksInSeries }}</p>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <!-- No progress shown for podcasts (unless showing podcast episode) -->
 | 
					        <!-- No progress shown for podcasts (unless showing podcast episode) -->
 | 
				
			||||||
        <div cy-id="progressBar" v-if="!isPodcast || episodeProgress" class="absolute bottom-0 left-0 h-1e max-w-full z-20 rounded-b box-shadow-progressbar" :class="itemIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: coverWidth * userProgressPercent + 'px' }"></div>
 | 
					        <div cy-id="progressBar" v-if="!isPodcast || episodeProgress" class="absolute bottom-0 left-0 h-1e max-w-full z-20 rounded-b box-shadow-progressbar" :class="itemIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: coverWidth * userProgressPercent + 'px' }"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -244,6 +237,7 @@ export default {
 | 
				
			|||||||
      return this.mediaMetadata.series
 | 
					      return this.mediaMetadata.series
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    seriesName() {
 | 
					    seriesName() {
 | 
				
			||||||
 | 
					      if (this.collapsedSeries?.name) return this.collapsedSeries.name
 | 
				
			||||||
      return this.series?.name || null
 | 
					      return this.series?.name || null
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    seriesSequence() {
 | 
					    seriesSequence() {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div ref="container" class="w-full rounded-lg bg-primary box-shadow-md overflow-y-auto overflow-x-hidden" style="max-height: 80vh">
 | 
					    <div ref="container" class="w-full rounded-lg bg-bg box-shadow-md overflow-y-auto overflow-x-hidden" style="max-height: 80vh">
 | 
				
			||||||
      <div v-if="show" class="w-full h-full py-4">
 | 
					      <div v-if="show" class="w-full h-full py-4">
 | 
				
			||||||
        <div class="w-full overflow-y-auto overflow-x-hidden max-h-96">
 | 
					        <div class="w-full overflow-y-auto overflow-x-hidden max-h-96">
 | 
				
			||||||
          <div class="flex px-8 items-center py-2">
 | 
					          <div class="flex px-8 items-center py-2">
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div ref="container" class="w-full rounded-lg bg-primary box-shadow-md overflow-y-auto overflow-x-hidden" style="max-height: 80vh">
 | 
					    <div ref="container" class="w-full rounded-lg bg-bg box-shadow-md overflow-y-auto overflow-x-hidden" style="max-height: 80vh">
 | 
				
			||||||
      <div v-if="show" class="w-full h-full">
 | 
					      <div v-if="show" class="w-full h-full">
 | 
				
			||||||
        <div class="py-4 px-4">
 | 
					        <div class="py-4 px-4">
 | 
				
			||||||
          <h1 v-if="!showBatchCollectionModal" class="text-2xl">{{ $strings.LabelAddToCollection }}</h1>
 | 
					          <h1 v-if="!showBatchCollectionModal" class="text-2xl">{{ $strings.LabelAddToCollection }}</h1>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="flex items-center px-4 py-2 justify-start relative hover:bg-bg" @mouseover="mouseover" @mouseleave="mouseleave">
 | 
					  <div class="flex items-center px-4 py-2 justify-start relative hover:bg-black-400" @mouseover="mouseover" @mouseleave="mouseleave">
 | 
				
			||||||
    <div v-if="isBookIncluded" class="absolute top-0 left-0 h-full w-1 bg-success z-10" />
 | 
					    <div v-if="isBookIncluded" class="absolute top-0 left-0 h-full w-1 bg-success z-10" />
 | 
				
			||||||
    <div class="w-20 max-w-20 text-center">
 | 
					    <div class="w-20 max-w-20 text-center">
 | 
				
			||||||
      <covers-collection-cover :book-items="books" :width="80" :height="40 * bookCoverAspectRatio" :book-cover-aspect-ratio="bookCoverAspectRatio" />
 | 
					      <covers-collection-cover :book-items="books" :width="80" :height="40 * bookCoverAspectRatio" :book-cover-aspect-ratio="bookCoverAspectRatio" />
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div ref="container" class="w-full rounded-lg bg-primary box-shadow-md overflow-y-auto overflow-x-hidden" style="max-height: 80vh">
 | 
					    <div ref="container" class="w-full rounded-lg bg-bg box-shadow-md overflow-y-auto overflow-x-hidden" style="max-height: 80vh">
 | 
				
			||||||
      <div v-if="show" class="w-full h-full">
 | 
					      <div v-if="show" class="w-full h-full">
 | 
				
			||||||
        <div class="py-4 px-4">
 | 
					        <div class="py-4 px-4">
 | 
				
			||||||
          <h1 v-if="!isBatch" class="text-2xl">{{ $strings.LabelAddToPlaylist }}</h1>
 | 
					          <h1 v-if="!isBatch" class="text-2xl">{{ $strings.LabelAddToPlaylist }}</h1>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="flex items-center px-4 py-2 justify-start relative hover:bg-bg" @mouseover="mouseover" @mouseleave="mouseleave">
 | 
					  <div class="flex items-center px-4 py-2 justify-start relative hover:bg-black-400" @mouseover="mouseover" @mouseleave="mouseleave">
 | 
				
			||||||
    <div v-if="isItemIncluded" class="absolute top-0 left-0 h-full w-1 bg-success z-10" />
 | 
					    <div v-if="isItemIncluded" class="absolute top-0 left-0 h-full w-1 bg-success z-10" />
 | 
				
			||||||
    <div class="w-16 max-w-16 text-center">
 | 
					    <div class="w-16 max-w-16 text-center">
 | 
				
			||||||
      <covers-playlist-cover :items="items" :width="64" :height="64" />
 | 
					      <covers-playlist-cover :items="items" :width="64" :height="64" />
 | 
				
			||||||
 | 
				
			|||||||
@ -351,8 +351,10 @@ export default {
 | 
				
			|||||||
  background-color: white;
 | 
					  background-color: white;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
trix-editor {
 | 
					trix-editor {
 | 
				
			||||||
  max-height: calc(4 * 1lh);
 | 
					  height: calc(4 * 1lh);
 | 
				
			||||||
 | 
					  min-height: calc(4 * 1lh);
 | 
				
			||||||
  overflow-y: auto;
 | 
					  overflow-y: auto;
 | 
				
			||||||
 | 
					  resize: vertical;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
trix-editor * {
 | 
					trix-editor * {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								client/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								client/package-lock.json
									
									
									
										generated
									
									
									
								
							@ -1,12 +1,12 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "audiobookshelf-client",
 | 
					  "name": "audiobookshelf-client",
 | 
				
			||||||
  "version": "2.18.1",
 | 
					  "version": "2.19.0",
 | 
				
			||||||
  "lockfileVersion": 3,
 | 
					  "lockfileVersion": 3,
 | 
				
			||||||
  "requires": true,
 | 
					  "requires": true,
 | 
				
			||||||
  "packages": {
 | 
					  "packages": {
 | 
				
			||||||
    "": {
 | 
					    "": {
 | 
				
			||||||
      "name": "audiobookshelf-client",
 | 
					      "name": "audiobookshelf-client",
 | 
				
			||||||
      "version": "2.18.1",
 | 
					      "version": "2.19.0",
 | 
				
			||||||
      "license": "ISC",
 | 
					      "license": "ISC",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@nuxtjs/axios": "^5.13.6",
 | 
					        "@nuxtjs/axios": "^5.13.6",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "audiobookshelf-client",
 | 
					  "name": "audiobookshelf-client",
 | 
				
			||||||
  "version": "2.18.1",
 | 
					  "version": "2.19.0",
 | 
				
			||||||
  "buildNumber": 1,
 | 
					  "buildNumber": 1,
 | 
				
			||||||
  "description": "Self-hosted audiobook and podcast client",
 | 
					  "description": "Self-hosted audiobook and podcast client",
 | 
				
			||||||
  "main": "index.js",
 | 
					  "main": "index.js",
 | 
				
			||||||
 | 
				
			|||||||
@ -414,11 +414,8 @@ export default {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      const audioEl = this.audioEl || document.createElement('audio')
 | 
					      const audioEl = this.audioEl || document.createElement('audio')
 | 
				
			||||||
      var src = audioTrack.contentUrl + `?token=${this.userToken}`
 | 
					      var src = audioTrack.contentUrl + `?token=${this.userToken}`
 | 
				
			||||||
      if (this.$isDev) {
 | 
					 | 
				
			||||||
        src = `${process.env.serverUrl}${src}`
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      audioEl.src = src
 | 
					      audioEl.src = `${process.env.serverUrl}${src}`
 | 
				
			||||||
      audioEl.id = 'chapter-audio'
 | 
					      audioEl.id = 'chapter-audio'
 | 
				
			||||||
      document.body.appendChild(audioEl)
 | 
					      document.body.appendChild(audioEl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
export default class AudioTrack {
 | 
					export default class AudioTrack {
 | 
				
			||||||
  constructor(track, userToken) {
 | 
					  constructor(track, userToken, routerBasePath) {
 | 
				
			||||||
    this.index = track.index || 0
 | 
					    this.index = track.index || 0
 | 
				
			||||||
    this.startOffset = track.startOffset || 0 // Total time of all previous tracks
 | 
					    this.startOffset = track.startOffset || 0 // Total time of all previous tracks
 | 
				
			||||||
    this.duration = track.duration || 0
 | 
					    this.duration = track.duration || 0
 | 
				
			||||||
@ -9,20 +9,27 @@ export default class AudioTrack {
 | 
				
			|||||||
    this.metadata = track.metadata || {}
 | 
					    this.metadata = track.metadata || {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.userToken = userToken
 | 
					    this.userToken = userToken
 | 
				
			||||||
 | 
					    this.routerBasePath = routerBasePath || ''
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Used for CastPlayer
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  get fullContentUrl() {
 | 
					  get fullContentUrl() {
 | 
				
			||||||
    if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
 | 
					    if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (process.env.NODE_ENV === 'development') {
 | 
					    if (process.env.NODE_ENV === 'development') {
 | 
				
			||||||
      return `${process.env.serverUrl}${this.contentUrl}?token=${this.userToken}`
 | 
					      return `${process.env.serverUrl}${this.contentUrl}?token=${this.userToken}`
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return `${window.location.origin}${this.contentUrl}?token=${this.userToken}`
 | 
					    return `${window.location.origin}${this.routerBasePath}${this.contentUrl}?token=${this.userToken}`
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Used for LocalPlayer
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  get relativeContentUrl() {
 | 
					  get relativeContentUrl() {
 | 
				
			||||||
    if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
 | 
					    if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return this.contentUrl + `?token=${this.userToken}`
 | 
					    return `${this.routerBasePath}${this.contentUrl}?token=${this.userToken}`
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -226,7 +226,7 @@ export default class PlayerHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    console.log('[PlayerHandler] Preparing Session', session)
 | 
					    console.log('[PlayerHandler] Preparing Session', session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var audioTracks = session.audioTracks.map((at) => new AudioTrack(at, this.userToken))
 | 
					    var audioTracks = session.audioTracks.map((at) => new AudioTrack(at, this.userToken, this.ctx.$config.routerBasePath))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.ctx.playerLoading = true
 | 
					    this.ctx.playerLoading = true
 | 
				
			||||||
    this.isHlsTranscode = true
 | 
					    this.isHlsTranscode = true
 | 
				
			||||||
 | 
				
			|||||||
@ -5,11 +5,13 @@
 | 
				
			|||||||
  "ButtonAddLibrary": "Tilføj Bibliotek",
 | 
					  "ButtonAddLibrary": "Tilføj Bibliotek",
 | 
				
			||||||
  "ButtonAddPodcasts": "Tilføj podcasts",
 | 
					  "ButtonAddPodcasts": "Tilføj podcasts",
 | 
				
			||||||
  "ButtonAddUser": "Tilføj bruger",
 | 
					  "ButtonAddUser": "Tilføj bruger",
 | 
				
			||||||
  "ButtonAddYourFirstLibrary": "Tilføj din første bibliotek",
 | 
					  "ButtonAddYourFirstLibrary": "Tilføj dit første bibliotek",
 | 
				
			||||||
  "ButtonApply": "Anvend",
 | 
					  "ButtonApply": "Anvend",
 | 
				
			||||||
  "ButtonApplyChapters": "Anvend kapitler",
 | 
					  "ButtonApplyChapters": "Anvend kapitler",
 | 
				
			||||||
  "ButtonAuthors": "Forfattere",
 | 
					  "ButtonAuthors": "Forfattere",
 | 
				
			||||||
  "ButtonBack": "Tilbage",
 | 
					  "ButtonBack": "Tilbage",
 | 
				
			||||||
 | 
					  "ButtonBatchEditPopulateFromExisting": "Opret fra eksisterende",
 | 
				
			||||||
 | 
					  "ButtonBatchEditPopulateMapDetails": "Opret fra kortlægnings detaljer",
 | 
				
			||||||
  "ButtonBrowseForFolder": "Gennemse mappe",
 | 
					  "ButtonBrowseForFolder": "Gennemse mappe",
 | 
				
			||||||
  "ButtonCancel": "Annuller",
 | 
					  "ButtonCancel": "Annuller",
 | 
				
			||||||
  "ButtonCancelEncode": "Annuller kodning",
 | 
					  "ButtonCancelEncode": "Annuller kodning",
 | 
				
			||||||
@ -91,7 +93,7 @@
 | 
				
			|||||||
  "ButtonScrollLeft": "Rul til Venstre",
 | 
					  "ButtonScrollLeft": "Rul til Venstre",
 | 
				
			||||||
  "ButtonScrollRight": "Rul til Højre",
 | 
					  "ButtonScrollRight": "Rul til Højre",
 | 
				
			||||||
  "ButtonSearch": "Søg",
 | 
					  "ButtonSearch": "Søg",
 | 
				
			||||||
  "ButtonSelectFolderPath": "Vælg Mappen Sti",
 | 
					  "ButtonSelectFolderPath": "Vælg Mappe Sti",
 | 
				
			||||||
  "ButtonSeries": "Serier",
 | 
					  "ButtonSeries": "Serier",
 | 
				
			||||||
  "ButtonSetChaptersFromTracks": "Sæt kapitler fra spor",
 | 
					  "ButtonSetChaptersFromTracks": "Sæt kapitler fra spor",
 | 
				
			||||||
  "ButtonShare": "Del",
 | 
					  "ButtonShare": "Del",
 | 
				
			||||||
@ -213,7 +215,7 @@
 | 
				
			|||||||
  "LabelAbridgedChecked": "Forkortet (kontrolleret)",
 | 
					  "LabelAbridgedChecked": "Forkortet (kontrolleret)",
 | 
				
			||||||
  "LabelAbridgedUnchecked": "Uforkortet (ikke kontrolleret)",
 | 
					  "LabelAbridgedUnchecked": "Uforkortet (ikke kontrolleret)",
 | 
				
			||||||
  "LabelAccessibleBy": "Tilgængelig af",
 | 
					  "LabelAccessibleBy": "Tilgængelig af",
 | 
				
			||||||
  "LabelAccountType": "Kontotype",
 | 
					  "LabelAccountType": "Brugertype",
 | 
				
			||||||
  "LabelAccountTypeAdmin": "Administrator",
 | 
					  "LabelAccountTypeAdmin": "Administrator",
 | 
				
			||||||
  "LabelAccountTypeGuest": "Gæst",
 | 
					  "LabelAccountTypeGuest": "Gæst",
 | 
				
			||||||
  "LabelAccountTypeUser": "Bruger",
 | 
					  "LabelAccountTypeUser": "Bruger",
 | 
				
			||||||
@ -224,7 +226,7 @@
 | 
				
			|||||||
  "LabelAddToPlaylistBatch": "Tilføj {0} Elementer til Afspilningsliste",
 | 
					  "LabelAddToPlaylistBatch": "Tilføj {0} Elementer til Afspilningsliste",
 | 
				
			||||||
  "LabelAddedAt": "Tilføjet",
 | 
					  "LabelAddedAt": "Tilføjet",
 | 
				
			||||||
  "LabelAddedDate": "Tilføjet {0}",
 | 
					  "LabelAddedDate": "Tilføjet {0}",
 | 
				
			||||||
  "LabelAdminUsersOnly": "Kun Administratorbrugere",
 | 
					  "LabelAdminUsersOnly": "Kun Administratorer",
 | 
				
			||||||
  "LabelAll": "Alle",
 | 
					  "LabelAll": "Alle",
 | 
				
			||||||
  "LabelAllUsers": "Alle Brugere",
 | 
					  "LabelAllUsers": "Alle Brugere",
 | 
				
			||||||
  "LabelAllUsersExcludingGuests": "Alle bruger eksklusiv gæster",
 | 
					  "LabelAllUsersExcludingGuests": "Alle bruger eksklusiv gæster",
 | 
				
			||||||
@ -443,7 +445,7 @@
 | 
				
			|||||||
  "LabelNarrator": "Fortæller",
 | 
					  "LabelNarrator": "Fortæller",
 | 
				
			||||||
  "LabelNarrators": "Fortællere",
 | 
					  "LabelNarrators": "Fortællere",
 | 
				
			||||||
  "LabelNew": "Ny",
 | 
					  "LabelNew": "Ny",
 | 
				
			||||||
  "LabelNewPassword": "Nyt kodeord",
 | 
					  "LabelNewPassword": "Ny adgangskode",
 | 
				
			||||||
  "LabelNewestAuthors": "Nyeste forfattere",
 | 
					  "LabelNewestAuthors": "Nyeste forfattere",
 | 
				
			||||||
  "LabelNewestEpisodes": "Nyeste episoder",
 | 
					  "LabelNewestEpisodes": "Nyeste episoder",
 | 
				
			||||||
  "LabelNextBackupDate": "Næste sikkerhedskopi dato",
 | 
					  "LabelNextBackupDate": "Næste sikkerhedskopi dato",
 | 
				
			||||||
@ -465,12 +467,12 @@
 | 
				
			|||||||
  "LabelNumberOfBooks": "Antal bøger",
 | 
					  "LabelNumberOfBooks": "Antal bøger",
 | 
				
			||||||
  "LabelNumberOfEpisodes": "# afsnit",
 | 
					  "LabelNumberOfEpisodes": "# afsnit",
 | 
				
			||||||
  "LabelOpenIDAdvancedPermsClaimDescription": "Navnet af OpenID claimet som indeholder avancerede brugerhandlinger inden i applikationen som vil gælde for ikke administrative roller (<b>hvis konfigureret</b>). Hvis et claim mangler fra svaret vil adgang til ABS blive nægtet. Hvis en enkelt indstilling/option mangler, vil det bliver behandlet som <code>false</code>. Sørg for at identity provider's claim matcher den forventede struktur:",
 | 
					  "LabelOpenIDAdvancedPermsClaimDescription": "Navnet af OpenID claimet som indeholder avancerede brugerhandlinger inden i applikationen som vil gælde for ikke administrative roller (<b>hvis konfigureret</b>). Hvis et claim mangler fra svaret vil adgang til ABS blive nægtet. Hvis en enkelt indstilling/option mangler, vil det bliver behandlet som <code>false</code>. Sørg for at identity provider's claim matcher den forventede struktur:",
 | 
				
			||||||
  "LabelOpenIDClaims": "Efterlad de følgende indstillinger tomme for at deaktivere avancerede grupper og adgangsstyring for automatisk at tilføje dem til 'User' gruppen.",
 | 
					  "LabelOpenIDClaims": "Efterlad de følgende indstillinger tomme for at deaktivere avanceret gruppe og adgangsindstilling, ved automatisk at assigne 'Bruger' grupper.",
 | 
				
			||||||
  "LabelOpenIDGroupClaimDescription": "Navnet af det OpenID claim som skal indeholde brugerens grupper. Mest kendt som <code>groups</code>. <b>hvis konfigureret</b>, vil applikationen automatiske tildele roller baseret p[ brugerens gruppemedlemsskaber, givet disse grupper er navngivet (uden forbehold for store og små bogstaver) 'admin', 'user' eller 'guest' i claimet. Claimet burde indeholde en liste (og hvis brugeren tilhøre flere grupper) som applikationen vil tildele roller med højeste adgangsnvieau. Hvis ingen grupper matcher vil adgang blive nægtet.",
 | 
					  "LabelOpenIDGroupClaimDescription": "Navnet af det OpenID claim som skal indeholde brugerens grupper. Mest kendt som <code>groups</code>. <b>hvis konfigureret</b>, vil applikationen automatiske tildele roller baseret p[ brugerens gruppemedlemsskaber, givet disse grupper er navngivet (uden forbehold for store og små bogstaver) 'admin', 'user' eller 'guest' i claimet. Claimet burde indeholde en liste (og hvis brugeren tilhøre flere grupper) som applikationen vil tildele roller med højeste adgangsnvieau. Hvis ingen grupper matcher vil adgang blive nægtet.",
 | 
				
			||||||
  "LabelOpenRSSFeed": "Åbn RSS-feed",
 | 
					  "LabelOpenRSSFeed": "Åbn RSS-feed",
 | 
				
			||||||
  "LabelOverwrite": "Overskriv",
 | 
					  "LabelOverwrite": "Overskriv",
 | 
				
			||||||
  "LabelPaginationPageXOfY": "Side {0} af {1}",
 | 
					  "LabelPaginationPageXOfY": "Side {0} af {1}",
 | 
				
			||||||
  "LabelPassword": "Kodeord",
 | 
					  "LabelPassword": "Adgangskode",
 | 
				
			||||||
  "LabelPath": "Sti",
 | 
					  "LabelPath": "Sti",
 | 
				
			||||||
  "LabelPermanent": "Permanent",
 | 
					  "LabelPermanent": "Permanent",
 | 
				
			||||||
  "LabelPermissionsAccessAllLibraries": "Kan få adgang til alle biblioteker",
 | 
					  "LabelPermissionsAccessAllLibraries": "Kan få adgang til alle biblioteker",
 | 
				
			||||||
@ -484,6 +486,7 @@
 | 
				
			|||||||
  "LabelPersonalYearReview": "Dit år i review ({0})",
 | 
					  "LabelPersonalYearReview": "Dit år i review ({0})",
 | 
				
			||||||
  "LabelPhotoPathURL": "Foto sti/URL",
 | 
					  "LabelPhotoPathURL": "Foto sti/URL",
 | 
				
			||||||
  "LabelPlayMethod": "Afspilningsmetode",
 | 
					  "LabelPlayMethod": "Afspilningsmetode",
 | 
				
			||||||
 | 
					  "LabelPlaybackRateIncrementDecrement": "Afspilningshastighed øges/sænkes med",
 | 
				
			||||||
  "LabelPlayerChapterNumberMarker": "{0} af {1}",
 | 
					  "LabelPlayerChapterNumberMarker": "{0} af {1}",
 | 
				
			||||||
  "LabelPlaylists": "Afspilningslister",
 | 
					  "LabelPlaylists": "Afspilningslister",
 | 
				
			||||||
  "LabelPodcast": "Podcast",
 | 
					  "LabelPodcast": "Podcast",
 | 
				
			||||||
@ -573,12 +576,12 @@
 | 
				
			|||||||
  "LabelSettingsLibraryMarkAsFinishedWhen": "Marker medie indhold som færdigt når",
 | 
					  "LabelSettingsLibraryMarkAsFinishedWhen": "Marker medie indhold som færdigt når",
 | 
				
			||||||
  "LabelSettingsOnlyShowLaterBooksInContinueSeries": "Spring til tidligere bøger i Fortsæt serie",
 | 
					  "LabelSettingsOnlyShowLaterBooksInContinueSeries": "Spring til tidligere bøger i Fortsæt serie",
 | 
				
			||||||
  "LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Fortsæt Serien siden hylde viser de første bøger som ikke er startet i serier med mindst en bog som ikke er startet og ingen bøger i gang. Aktivering af denne indstilling vil fortsætte serien fra den sidst gennemførte bog modsat den først ikke startede bog.",
 | 
					  "LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Fortsæt Serien siden hylde viser de første bøger som ikke er startet i serier med mindst en bog som ikke er startet og ingen bøger i gang. Aktivering af denne indstilling vil fortsætte serien fra den sidst gennemførte bog modsat den først ikke startede bog.",
 | 
				
			||||||
  "LabelSettingsParseSubtitles": "Fortolk undertekster",
 | 
					  "LabelSettingsParseSubtitles": "Fortolk undertitler",
 | 
				
			||||||
  "LabelSettingsParseSubtitlesHelp": "Udtræk undertekster fra lydbogsmappenavne.<br>Undertitler skal adskilles af \" - \"<br>f.eks. \"Bogtitel - En undertitel her\" har undertitlen \"En undertitel her\"",
 | 
					  "LabelSettingsParseSubtitlesHelp": "Udtræk undertekster fra lydbogsmappenavne.<br>Undertitler skal adskilles af \" - \"<br>f.eks. \"Bogtitel - En undertitel her\" har undertitlen \"En undertitel her\"",
 | 
				
			||||||
  "LabelSettingsPreferMatchedMetadata": "Foretræk matchede metadata",
 | 
					  "LabelSettingsPreferMatchedMetadata": "Foretræk matchede metadata",
 | 
				
			||||||
  "LabelSettingsPreferMatchedMetadataHelp": "Matchede data vil tilsidesætte elementdetaljer ved brug af Hurtig Match. Som standard udfylder Hurtig Match kun manglende detaljer.",
 | 
					  "LabelSettingsPreferMatchedMetadataHelp": "Matchede data vil tilsidesætte elementdetaljer ved brug af Hurtig Match. Som standard udfylder Hurtig Match kun manglende detaljer.",
 | 
				
			||||||
  "LabelSettingsSkipMatchingBooksWithASIN": "Spring over matchende bøger, der allerede har en ASIN",
 | 
					  "LabelSettingsSkipMatchingBooksWithASIN": "Spring over matchende bøger, der allerede har en ASIN",
 | 
				
			||||||
  "LabelSettingsSkipMatchingBooksWithISBN": "Spring over matchende bøger, der allerede har en ISBN",
 | 
					  "LabelSettingsSkipMatchingBooksWithISBN": "Spring matchende bøger over, som allerede har et ISBN-nummer",
 | 
				
			||||||
  "LabelSettingsSortingIgnorePrefixes": "Ignorer præfikser ved sortering",
 | 
					  "LabelSettingsSortingIgnorePrefixes": "Ignorer præfikser ved sortering",
 | 
				
			||||||
  "LabelSettingsSortingIgnorePrefixesHelp": "f.eks. for præfikset \"the\" vil bogtitlen \"The Book Title\" blive sorteret som \"Book Title, The\"",
 | 
					  "LabelSettingsSortingIgnorePrefixesHelp": "f.eks. for præfikset \"the\" vil bogtitlen \"The Book Title\" blive sorteret som \"Book Title, The\"",
 | 
				
			||||||
  "LabelSettingsSquareBookCovers": "Brug kvadratiske bogomslag",
 | 
					  "LabelSettingsSquareBookCovers": "Brug kvadratiske bogomslag",
 | 
				
			||||||
@ -662,7 +665,7 @@
 | 
				
			|||||||
  "LabelTrailer": "Trailer",
 | 
					  "LabelTrailer": "Trailer",
 | 
				
			||||||
  "LabelType": "Type",
 | 
					  "LabelType": "Type",
 | 
				
			||||||
  "LabelUnabridged": "Uforkortet",
 | 
					  "LabelUnabridged": "Uforkortet",
 | 
				
			||||||
  "LabelUndo": "Undo",
 | 
					  "LabelUndo": "Fortryd",
 | 
				
			||||||
  "LabelUnknown": "Ukendt",
 | 
					  "LabelUnknown": "Ukendt",
 | 
				
			||||||
  "LabelUnknownPublishDate": "Ukendt publiceringsdato",
 | 
					  "LabelUnknownPublishDate": "Ukendt publiceringsdato",
 | 
				
			||||||
  "LabelUpdateCover": "Opdater omslag",
 | 
					  "LabelUpdateCover": "Opdater omslag",
 | 
				
			||||||
@ -704,8 +707,11 @@
 | 
				
			|||||||
  "MessageBackupsLocationEditNote": "Note: Opdatering af backup sti vil ikke fjerne eller modificere eksisterende backups",
 | 
					  "MessageBackupsLocationEditNote": "Note: Opdatering af backup sti vil ikke fjerne eller modificere eksisterende backups",
 | 
				
			||||||
  "MessageBackupsLocationNoEditNote": "Note: Backup sti er sat igennem miljøvariabel og kan ikke ændres her.",
 | 
					  "MessageBackupsLocationNoEditNote": "Note: Backup sti er sat igennem miljøvariabel og kan ikke ændres her.",
 | 
				
			||||||
  "MessageBackupsLocationPathEmpty": "Backup sti kan ikke være tom",
 | 
					  "MessageBackupsLocationPathEmpty": "Backup sti kan ikke være tom",
 | 
				
			||||||
 | 
					  "MessageBatchEditPopulateMapDetailsAllHelp": "Opret felter slået til med data fra alle genstande. Felter med flere værdier vil blive sammenflettet",
 | 
				
			||||||
 | 
					  "MessageBatchEditPopulateMapDetailsItemHelp": "Opret kort med værdier der er slået til fra felter med data fra denne genstand",
 | 
				
			||||||
  "MessageBatchQuickMatchDescription": "Quick Match vil forsøge at tilføje manglende omslag og metadata til de valgte elementer. Aktivér indstillingerne nedenfor for at tillade Quick Match at overskrive eksisterende omslag og/eller metadata.",
 | 
					  "MessageBatchQuickMatchDescription": "Quick Match vil forsøge at tilføje manglende omslag og metadata til de valgte elementer. Aktivér indstillingerne nedenfor for at tillade Quick Match at overskrive eksisterende omslag og/eller metadata.",
 | 
				
			||||||
  "MessageBookshelfNoCollections": "Du har ikke oprettet nogen samlinger endnu",
 | 
					  "MessageBookshelfNoCollections": "Du har ikke oprettet nogen samlinger endnu",
 | 
				
			||||||
 | 
					  "MessageBookshelfNoCollectionsHelp": "Samlinger er offentlige. Alle brugere med adgang til biblioteket kan se dem.",
 | 
				
			||||||
  "MessageBookshelfNoRSSFeeds": "Ingen RSS-feeds er åbne",
 | 
					  "MessageBookshelfNoRSSFeeds": "Ingen RSS-feeds er åbne",
 | 
				
			||||||
  "MessageBookshelfNoResultsForFilter": "Ingen resultater for filter \"{0}: {1}\"",
 | 
					  "MessageBookshelfNoResultsForFilter": "Ingen resultater for filter \"{0}: {1}\"",
 | 
				
			||||||
  "MessageBookshelfNoResultsForQuery": "Intet resultat for query",
 | 
					  "MessageBookshelfNoResultsForQuery": "Intet resultat for query",
 | 
				
			||||||
@ -816,6 +822,7 @@
 | 
				
			|||||||
  "MessageNoTasksRunning": "Ingen opgaver kører",
 | 
					  "MessageNoTasksRunning": "Ingen opgaver kører",
 | 
				
			||||||
  "MessageNoUpdatesWereNecessary": "Ingen opdateringer var nødvendige",
 | 
					  "MessageNoUpdatesWereNecessary": "Ingen opdateringer var nødvendige",
 | 
				
			||||||
  "MessageNoUserPlaylists": "Du har ingen afspilningslister",
 | 
					  "MessageNoUserPlaylists": "Du har ingen afspilningslister",
 | 
				
			||||||
 | 
					  "MessageNoUserPlaylistsHelp": "Playlister er private. Kun brugere som opretter dem kan se dem.",
 | 
				
			||||||
  "MessageNotYetImplemented": "Endnu ikke implementeret",
 | 
					  "MessageNotYetImplemented": "Endnu ikke implementeret",
 | 
				
			||||||
  "MessageOpmlPreviewNote": "Note: Dette er en forhåndsvisning af den indlæste OPML fil. Podcast titel vil blive taget fra RSS feedet.",
 | 
					  "MessageOpmlPreviewNote": "Note: Dette er en forhåndsvisning af den indlæste OPML fil. Podcast titel vil blive taget fra RSS feedet.",
 | 
				
			||||||
  "MessageOr": "eller",
 | 
					  "MessageOr": "eller",
 | 
				
			||||||
 | 
				
			|||||||
@ -645,7 +645,7 @@
 | 
				
			|||||||
  "LabelTimeToShift": "Zeit bis zum Wechsel in Sekunden",
 | 
					  "LabelTimeToShift": "Zeit bis zum Wechsel in Sekunden",
 | 
				
			||||||
  "LabelTitle": "Titel",
 | 
					  "LabelTitle": "Titel",
 | 
				
			||||||
  "LabelToolsEmbedMetadata": "Metadaten einbetten",
 | 
					  "LabelToolsEmbedMetadata": "Metadaten einbetten",
 | 
				
			||||||
  "LabelToolsEmbedMetadataDescription": "Bettet die Metadaten einschließlich des Titelbildes und der Kapitel in die Audiodatein ein.",
 | 
					  "LabelToolsEmbedMetadataDescription": "Bettet die Metadaten einschließlich des Titelbildes und der Kapitel in die Audiodateien ein.",
 | 
				
			||||||
  "LabelToolsM4bEncoder": "M4B Kodierer",
 | 
					  "LabelToolsM4bEncoder": "M4B Kodierer",
 | 
				
			||||||
  "LabelToolsMakeM4b": "M4B-Datei erstellen",
 | 
					  "LabelToolsMakeM4b": "M4B-Datei erstellen",
 | 
				
			||||||
  "LabelToolsMakeM4bDescription": "Erstellt eine M4B-Datei (Endung \".m4b\") welche mehrere mp3-Dateien in einer einzigen Datei inkl. derer Metadaten (Beschreibung, Titelbild, Kapitel, ...) zusammenfasst. M4B-Datei können darüber hinaus Lesezeichen speichern und mit einem Abspielschutz (Passwort) versehen werden.",
 | 
					  "LabelToolsMakeM4bDescription": "Erstellt eine M4B-Datei (Endung \".m4b\") welche mehrere mp3-Dateien in einer einzigen Datei inkl. derer Metadaten (Beschreibung, Titelbild, Kapitel, ...) zusammenfasst. M4B-Datei können darüber hinaus Lesezeichen speichern und mit einem Abspielschutz (Passwort) versehen werden.",
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,8 @@
 | 
				
			|||||||
  "ButtonApplyChapters": "Appliquer aux chapitres",
 | 
					  "ButtonApplyChapters": "Appliquer aux chapitres",
 | 
				
			||||||
  "ButtonAuthors": "Auteurs",
 | 
					  "ButtonAuthors": "Auteurs",
 | 
				
			||||||
  "ButtonBack": "Retour",
 | 
					  "ButtonBack": "Retour",
 | 
				
			||||||
 | 
					  "ButtonBatchEditPopulateFromExisting": "Remplir à partir de l'existant",
 | 
				
			||||||
 | 
					  "ButtonBatchEditPopulateMapDetails": "Remplir les détails de la carte",
 | 
				
			||||||
  "ButtonBrowseForFolder": "Naviguer vers le répertoire",
 | 
					  "ButtonBrowseForFolder": "Naviguer vers le répertoire",
 | 
				
			||||||
  "ButtonCancel": "Annuler",
 | 
					  "ButtonCancel": "Annuler",
 | 
				
			||||||
  "ButtonCancelEncode": "Annuler l’encodage",
 | 
					  "ButtonCancelEncode": "Annuler l’encodage",
 | 
				
			||||||
@ -484,6 +486,7 @@
 | 
				
			|||||||
  "LabelPersonalYearReview": "Bilan de l’année ({0})",
 | 
					  "LabelPersonalYearReview": "Bilan de l’année ({0})",
 | 
				
			||||||
  "LabelPhotoPathURL": "Chemin / URL des photos",
 | 
					  "LabelPhotoPathURL": "Chemin / URL des photos",
 | 
				
			||||||
  "LabelPlayMethod": "Méthode d’écoute",
 | 
					  "LabelPlayMethod": "Méthode d’écoute",
 | 
				
			||||||
 | 
					  "LabelPlaybackRateIncrementDecrement": "Augmentation/Diminition de la vitesse de lecture",
 | 
				
			||||||
  "LabelPlayerChapterNumberMarker": "{0} sur {1}",
 | 
					  "LabelPlayerChapterNumberMarker": "{0} sur {1}",
 | 
				
			||||||
  "LabelPlaylists": "Listes de lecture",
 | 
					  "LabelPlaylists": "Listes de lecture",
 | 
				
			||||||
  "LabelPodcast": "Podcast",
 | 
					  "LabelPodcast": "Podcast",
 | 
				
			||||||
@ -704,6 +707,7 @@
 | 
				
			|||||||
  "MessageBackupsLocationEditNote": "Remarque : Mettre à jour l'emplacement de sauvegarde ne déplacera pas ou ne modifiera pas les sauvegardes existantes",
 | 
					  "MessageBackupsLocationEditNote": "Remarque : Mettre à jour l'emplacement de sauvegarde ne déplacera pas ou ne modifiera pas les sauvegardes existantes",
 | 
				
			||||||
  "MessageBackupsLocationNoEditNote": "Remarque : l’emplacement de sauvegarde est défini via une variable d’environnement et ne peut pas être modifié ici.",
 | 
					  "MessageBackupsLocationNoEditNote": "Remarque : l’emplacement de sauvegarde est défini via une variable d’environnement et ne peut pas être modifié ici.",
 | 
				
			||||||
  "MessageBackupsLocationPathEmpty": "L'emplacement de secours ne peut pas être vide",
 | 
					  "MessageBackupsLocationPathEmpty": "L'emplacement de secours ne peut pas être vide",
 | 
				
			||||||
 | 
					  "MessageBatchEditPopulateMapDetailsAllHelp": "Remplir les champs disponibles avec les données de tous les éléments. les champs avec des valeurs multiples seront fusionnés",
 | 
				
			||||||
  "MessageBatchQuickMatchDescription": "La recherche par correspondance rapide tentera d’ajouter les couvertures et métadonnées manquantes pour les éléments sélectionnés. Activez les options ci-dessous pour permettre la Recherche par correspondance d’écraser les couvertures et/ou métadonnées existantes.",
 | 
					  "MessageBatchQuickMatchDescription": "La recherche par correspondance rapide tentera d’ajouter les couvertures et métadonnées manquantes pour les éléments sélectionnés. Activez les options ci-dessous pour permettre la Recherche par correspondance d’écraser les couvertures et/ou métadonnées existantes.",
 | 
				
			||||||
  "MessageBookshelfNoCollections": "Vous n’avez pas encore de collections",
 | 
					  "MessageBookshelfNoCollections": "Vous n’avez pas encore de collections",
 | 
				
			||||||
  "MessageBookshelfNoRSSFeeds": "Aucun flux RSS n’est ouvert",
 | 
					  "MessageBookshelfNoRSSFeeds": "Aucun flux RSS n’est ouvert",
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,8 @@
 | 
				
			|||||||
  "ButtonApplyChapters": "Primijeni poglavlja",
 | 
					  "ButtonApplyChapters": "Primijeni poglavlja",
 | 
				
			||||||
  "ButtonAuthors": "Autori",
 | 
					  "ButtonAuthors": "Autori",
 | 
				
			||||||
  "ButtonBack": "Natrag",
 | 
					  "ButtonBack": "Natrag",
 | 
				
			||||||
 | 
					  "ButtonBatchEditPopulateFromExisting": "Popuni iz postojećeg",
 | 
				
			||||||
 | 
					  "ButtonBatchEditPopulateMapDetails": "Popuni mapirane pojedinosti",
 | 
				
			||||||
  "ButtonBrowseForFolder": "Pronađi mapu",
 | 
					  "ButtonBrowseForFolder": "Pronađi mapu",
 | 
				
			||||||
  "ButtonCancel": "Odustani",
 | 
					  "ButtonCancel": "Odustani",
 | 
				
			||||||
  "ButtonCancelEncode": "Otkaži kodiranje",
 | 
					  "ButtonCancelEncode": "Otkaži kodiranje",
 | 
				
			||||||
@ -288,7 +290,7 @@
 | 
				
			|||||||
  "LabelCustomCronExpression": "Prilagođeni CRON izraz:",
 | 
					  "LabelCustomCronExpression": "Prilagođeni CRON izraz:",
 | 
				
			||||||
  "LabelDatetime": "Datum i vrijeme",
 | 
					  "LabelDatetime": "Datum i vrijeme",
 | 
				
			||||||
  "LabelDays": "Dani",
 | 
					  "LabelDays": "Dani",
 | 
				
			||||||
  "LabelDeleteFromFileSystemCheckbox": "Izbriši datoteke (uklonite oznaku ako stavku želite izbrisati samo iz baze podataka)",
 | 
					  "LabelDeleteFromFileSystemCheckbox": "Izbriši datoteke (uklonite kvačicu ako stavku želite izbrisati samo iz baze podataka)",
 | 
				
			||||||
  "LabelDescription": "Opis",
 | 
					  "LabelDescription": "Opis",
 | 
				
			||||||
  "LabelDeselectAll": "Odznači sve",
 | 
					  "LabelDeselectAll": "Odznači sve",
 | 
				
			||||||
  "LabelDevice": "Uređaj",
 | 
					  "LabelDevice": "Uređaj",
 | 
				
			||||||
@ -399,7 +401,7 @@
 | 
				
			|||||||
  "LabelLastBookAdded": "Zadnja dodana knjiga",
 | 
					  "LabelLastBookAdded": "Zadnja dodana knjiga",
 | 
				
			||||||
  "LabelLastBookUpdated": "Zadnja ažurirana knjiga",
 | 
					  "LabelLastBookUpdated": "Zadnja ažurirana knjiga",
 | 
				
			||||||
  "LabelLastSeen": "Zadnji puta viđen",
 | 
					  "LabelLastSeen": "Zadnji puta viđen",
 | 
				
			||||||
  "LabelLastTime": "Zadnji puta",
 | 
					  "LabelLastTime": "Zadnje vrijeme",
 | 
				
			||||||
  "LabelLastUpdate": "Zadnje ažuriranje",
 | 
					  "LabelLastUpdate": "Zadnje ažuriranje",
 | 
				
			||||||
  "LabelLayout": "Prikaz",
 | 
					  "LabelLayout": "Prikaz",
 | 
				
			||||||
  "LabelLayoutSinglePage": "Jedna stranica",
 | 
					  "LabelLayoutSinglePage": "Jedna stranica",
 | 
				
			||||||
@ -484,6 +486,7 @@
 | 
				
			|||||||
  "LabelPersonalYearReview": "Vaš godišnji pregled ({0})",
 | 
					  "LabelPersonalYearReview": "Vaš godišnji pregled ({0})",
 | 
				
			||||||
  "LabelPhotoPathURL": "Putanja ili URL fotografije",
 | 
					  "LabelPhotoPathURL": "Putanja ili URL fotografije",
 | 
				
			||||||
  "LabelPlayMethod": "Način reprodukcije",
 | 
					  "LabelPlayMethod": "Način reprodukcije",
 | 
				
			||||||
 | 
					  "LabelPlaybackRateIncrementDecrement": "Korak povećanja/smanjenja brzine reprodukcije",
 | 
				
			||||||
  "LabelPlayerChapterNumberMarker": "{0} od {1}",
 | 
					  "LabelPlayerChapterNumberMarker": "{0} od {1}",
 | 
				
			||||||
  "LabelPlaylists": "Popisi za izvođenje",
 | 
					  "LabelPlaylists": "Popisi za izvođenje",
 | 
				
			||||||
  "LabelPodcast": "Podcast",
 | 
					  "LabelPodcast": "Podcast",
 | 
				
			||||||
@ -704,8 +707,11 @@
 | 
				
			|||||||
  "MessageBackupsLocationEditNote": "Napomena: Uređivanje lokacije za sigurnosne kopije ne premješta ili mijenja postojeće sigurnosne kopije",
 | 
					  "MessageBackupsLocationEditNote": "Napomena: Uređivanje lokacije za sigurnosne kopije ne premješta ili mijenja postojeće sigurnosne kopije",
 | 
				
			||||||
  "MessageBackupsLocationNoEditNote": "Napomena: Lokacija za sigurnosne kopije zadana je kroz varijablu okoline i ovdje se ne može izmijeniti.",
 | 
					  "MessageBackupsLocationNoEditNote": "Napomena: Lokacija za sigurnosne kopije zadana je kroz varijablu okoline i ovdje se ne može izmijeniti.",
 | 
				
			||||||
  "MessageBackupsLocationPathEmpty": "Putanja do lokacije za sigurnosne kopije ne može ostati prazna",
 | 
					  "MessageBackupsLocationPathEmpty": "Putanja do lokacije za sigurnosne kopije ne može ostati prazna",
 | 
				
			||||||
 | 
					  "MessageBatchEditPopulateMapDetailsAllHelp": "Nadopunjuje omogućena polja podatcima iz svih stavki. Polja s višestrukim podatcima će se spojiti",
 | 
				
			||||||
 | 
					  "MessageBatchEditPopulateMapDetailsItemHelp": "Popuni omogućena polja mapiranih pojedinosti s podatcima iz ove stavke",
 | 
				
			||||||
  "MessageBatchQuickMatchDescription": "Brzo prepoznavanje za odabrane će stavke pokušati dodati naslovnice i meta-podatke koji nedostaju. Uključite donje opcije ako želite da Brzo prepoznavanje prepiše postojeće naslovnice i/ili meta-podatke.",
 | 
					  "MessageBatchQuickMatchDescription": "Brzo prepoznavanje za odabrane će stavke pokušati dodati naslovnice i meta-podatke koji nedostaju. Uključite donje opcije ako želite da Brzo prepoznavanje prepiše postojeće naslovnice i/ili meta-podatke.",
 | 
				
			||||||
  "MessageBookshelfNoCollections": "Niste izradili niti jednu zbirku",
 | 
					  "MessageBookshelfNoCollections": "Niste izradili niti jednu zbirku",
 | 
				
			||||||
 | 
					  "MessageBookshelfNoCollectionsHelp": "Zbirke su javne. Svi korisnici s pristupom knjižnici mogu ih vidjeti.",
 | 
				
			||||||
  "MessageBookshelfNoRSSFeeds": "Nema otvorenih RSS izvora",
 | 
					  "MessageBookshelfNoRSSFeeds": "Nema otvorenih RSS izvora",
 | 
				
			||||||
  "MessageBookshelfNoResultsForFilter": "Nema rezultata za filter \"{0}: {1}\"",
 | 
					  "MessageBookshelfNoResultsForFilter": "Nema rezultata za filter \"{0}: {1}\"",
 | 
				
			||||||
  "MessageBookshelfNoResultsForQuery": "Vaš upit nema rezultata",
 | 
					  "MessageBookshelfNoResultsForQuery": "Vaš upit nema rezultata",
 | 
				
			||||||
@ -721,7 +727,7 @@
 | 
				
			|||||||
  "MessageConfirmDeleteDevice": "Sigurno želite izbrisati e-čitač \"{0}\"?",
 | 
					  "MessageConfirmDeleteDevice": "Sigurno želite izbrisati e-čitač \"{0}\"?",
 | 
				
			||||||
  "MessageConfirmDeleteFile": "Ovo će izbrisati datoteke s datotečnog sustava. Jeste li sigurni?",
 | 
					  "MessageConfirmDeleteFile": "Ovo će izbrisati datoteke s datotečnog sustava. Jeste li sigurni?",
 | 
				
			||||||
  "MessageConfirmDeleteLibrary": "Sigurno želite trajno izbrisati knjižnicu \"{0}\"?",
 | 
					  "MessageConfirmDeleteLibrary": "Sigurno želite trajno izbrisati knjižnicu \"{0}\"?",
 | 
				
			||||||
  "MessageConfirmDeleteLibraryItem": "Ovo će izbrisati knjižničku stavku iz datoteke i vašeg datotečnog sustava. Jeste li sigurni?",
 | 
					  "MessageConfirmDeleteLibraryItem": "Ovo će izbrisati knjižničku stavku iz baze podataka i s datotečnog sustava. Jeste li sigurni?",
 | 
				
			||||||
  "MessageConfirmDeleteLibraryItems": "Ovo će izbrisati {0} knjižničkih stavki iz baze podataka i datotečnog sustava. Jeste li sigurni?",
 | 
					  "MessageConfirmDeleteLibraryItems": "Ovo će izbrisati {0} knjižničkih stavki iz baze podataka i datotečnog sustava. Jeste li sigurni?",
 | 
				
			||||||
  "MessageConfirmDeleteMetadataProvider": "Sigurno želite izbrisati prilagođenog pružatelja meta-podataka \"{0}\"?",
 | 
					  "MessageConfirmDeleteMetadataProvider": "Sigurno želite izbrisati prilagođenog pružatelja meta-podataka \"{0}\"?",
 | 
				
			||||||
  "MessageConfirmDeleteNotification": "Sigurno želite izbrisati ovu obavijest?",
 | 
					  "MessageConfirmDeleteNotification": "Sigurno želite izbrisati ovu obavijest?",
 | 
				
			||||||
@ -816,6 +822,7 @@
 | 
				
			|||||||
  "MessageNoTasksRunning": "Nema zadataka koji se izvode",
 | 
					  "MessageNoTasksRunning": "Nema zadataka koji se izvode",
 | 
				
			||||||
  "MessageNoUpdatesWereNecessary": "Ažuriranje nije bilo potrebno",
 | 
					  "MessageNoUpdatesWereNecessary": "Ažuriranje nije bilo potrebno",
 | 
				
			||||||
  "MessageNoUserPlaylists": "Nemate popisa za izvođenje",
 | 
					  "MessageNoUserPlaylists": "Nemate popisa za izvođenje",
 | 
				
			||||||
 | 
					  "MessageNoUserPlaylistsHelp": "Popisi za izvođenje su privatni. Može ih vidjeti samo korisnik koji ih je izradio.",
 | 
				
			||||||
  "MessageNotYetImplemented": "Još nije implementirano",
 | 
					  "MessageNotYetImplemented": "Još nije implementirano",
 | 
				
			||||||
  "MessageOpmlPreviewNote": "Napomena: Ovo je pretpregled raščlanjene OPML datoteke. Stvarni naslov podcasta preuzet će se iz RSS izvora.",
 | 
					  "MessageOpmlPreviewNote": "Napomena: Ovo je pretpregled raščlanjene OPML datoteke. Stvarni naslov podcasta preuzet će se iz RSS izvora.",
 | 
				
			||||||
  "MessageOr": "ili",
 | 
					  "MessageOr": "ili",
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +1,3 @@
 | 
				
			|||||||
{}
 | 
					{
 | 
				
			||||||
 | 
					  "ButtonAdd": "追加"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,8 @@
 | 
				
			|||||||
  "ButtonApplyChapters": "Применить главы",
 | 
					  "ButtonApplyChapters": "Применить главы",
 | 
				
			||||||
  "ButtonAuthors": "Авторы",
 | 
					  "ButtonAuthors": "Авторы",
 | 
				
			||||||
  "ButtonBack": "Назад",
 | 
					  "ButtonBack": "Назад",
 | 
				
			||||||
 | 
					  "ButtonBatchEditPopulateFromExisting": "Заполнить из существующих",
 | 
				
			||||||
 | 
					  "ButtonBatchEditPopulateMapDetails": "Заполнить данные карты",
 | 
				
			||||||
  "ButtonBrowseForFolder": "Выбрать папку",
 | 
					  "ButtonBrowseForFolder": "Выбрать папку",
 | 
				
			||||||
  "ButtonCancel": "Отмена",
 | 
					  "ButtonCancel": "Отмена",
 | 
				
			||||||
  "ButtonCancelEncode": "Отменить кодирование",
 | 
					  "ButtonCancelEncode": "Отменить кодирование",
 | 
				
			||||||
@ -301,7 +303,7 @@
 | 
				
			|||||||
  "LabelDownload": "Скачать",
 | 
					  "LabelDownload": "Скачать",
 | 
				
			||||||
  "LabelDownloadNEpisodes": "Скачать {0} эпизодов",
 | 
					  "LabelDownloadNEpisodes": "Скачать {0} эпизодов",
 | 
				
			||||||
  "LabelDownloadable": "Загружаемый",
 | 
					  "LabelDownloadable": "Загружаемый",
 | 
				
			||||||
  "LabelDuration": "Длина",
 | 
					  "LabelDuration": "Продолжительность",
 | 
				
			||||||
  "LabelDurationComparisonExactMatch": "(точное совпадение)",
 | 
					  "LabelDurationComparisonExactMatch": "(точное совпадение)",
 | 
				
			||||||
  "LabelDurationComparisonLonger": "({0} дольше)",
 | 
					  "LabelDurationComparisonLonger": "({0} дольше)",
 | 
				
			||||||
  "LabelDurationComparisonShorter": "({0} короче)",
 | 
					  "LabelDurationComparisonShorter": "({0} короче)",
 | 
				
			||||||
@ -432,7 +434,7 @@
 | 
				
			|||||||
  "LabelMetadataProvider": "Провайдер",
 | 
					  "LabelMetadataProvider": "Провайдер",
 | 
				
			||||||
  "LabelMinute": "Минуты",
 | 
					  "LabelMinute": "Минуты",
 | 
				
			||||||
  "LabelMinutes": "Минуты",
 | 
					  "LabelMinutes": "Минуты",
 | 
				
			||||||
  "LabelMissing": "Потеряно",
 | 
					  "LabelMissing": "Отсутствует",
 | 
				
			||||||
  "LabelMissingEbook": "Нет e-книги",
 | 
					  "LabelMissingEbook": "Нет e-книги",
 | 
				
			||||||
  "LabelMissingSupplementaryEbook": "Нет дополнительной e-книги",
 | 
					  "LabelMissingSupplementaryEbook": "Нет дополнительной e-книги",
 | 
				
			||||||
  "LabelMobileRedirectURIs": "Разрешенные URI перенаправления с мобильных устройств",
 | 
					  "LabelMobileRedirectURIs": "Разрешенные URI перенаправления с мобильных устройств",
 | 
				
			||||||
@ -463,7 +465,7 @@
 | 
				
			|||||||
  "LabelNotificationsMaxQueueSize": "Макс. размер очереди для событий уведомлений",
 | 
					  "LabelNotificationsMaxQueueSize": "Макс. размер очереди для событий уведомлений",
 | 
				
			||||||
  "LabelNotificationsMaxQueueSizeHelp": "События ограничены 1 в секунду. События будут игнорированы если в очереди максимальное количество. Это предотвращает спам сообщениями.",
 | 
					  "LabelNotificationsMaxQueueSizeHelp": "События ограничены 1 в секунду. События будут игнорированы если в очереди максимальное количество. Это предотвращает спам сообщениями.",
 | 
				
			||||||
  "LabelNumberOfBooks": "Количество книг",
 | 
					  "LabelNumberOfBooks": "Количество книг",
 | 
				
			||||||
  "LabelNumberOfEpisodes": "# Эпизодов",
 | 
					  "LabelNumberOfEpisodes": "# из эпизодов",
 | 
				
			||||||
  "LabelOpenIDAdvancedPermsClaimDescription": "Имя утверждения OpenID, содержащего расширенные разрешения на действия пользователя в приложении, которые будут применяться к ролям, не являющимся администраторами (<b>если они настроены</b>). Если утверждение отсутствует в ответе, в доступе к ABS будет отказано. Если одна опция отсутствует, она будет рассматриваться как <code>false</code>. Убедитесь, что утверждение поставщика удостоверений соответствует ожидаемой структуре:",
 | 
					  "LabelOpenIDAdvancedPermsClaimDescription": "Имя утверждения OpenID, содержащего расширенные разрешения на действия пользователя в приложении, которые будут применяться к ролям, не являющимся администраторами (<b>если они настроены</b>). Если утверждение отсутствует в ответе, в доступе к ABS будет отказано. Если одна опция отсутствует, она будет рассматриваться как <code>false</code>. Убедитесь, что утверждение поставщика удостоверений соответствует ожидаемой структуре:",
 | 
				
			||||||
  "LabelOpenIDClaims": "Оставьте следующие параметры пустыми, чтобы отключить расширенное назначение групп и разрешений, будет автоматически присвоена группа «Пользователь».",
 | 
					  "LabelOpenIDClaims": "Оставьте следующие параметры пустыми, чтобы отключить расширенное назначение групп и разрешений, будет автоматически присвоена группа «Пользователь».",
 | 
				
			||||||
  "LabelOpenIDGroupClaimDescription": "Имя утверждения OpenID, содержащего список групп пользователя. Обычно их называют <code>groups</code>. <b>Если эта настройка</b> настроена, приложение будет автоматически назначать роли на основе членства пользователя в группах при условии, что эти группы названы в утверждении без учета регистра \"admin\", \"user\" или \"guest\". Утверждение должно содержать список, и если пользователь принадлежит к нескольким группам, то приложение назначит роль, соответствующую самому высокому уровню доступа. Если ни одна из групп не совпадает, доступ будет запрещен.",
 | 
					  "LabelOpenIDGroupClaimDescription": "Имя утверждения OpenID, содержащего список групп пользователя. Обычно их называют <code>groups</code>. <b>Если эта настройка</b> настроена, приложение будет автоматически назначать роли на основе членства пользователя в группах при условии, что эти группы названы в утверждении без учета регистра \"admin\", \"user\" или \"guest\". Утверждение должно содержать список, и если пользователь принадлежит к нескольким группам, то приложение назначит роль, соответствующую самому высокому уровню доступа. Если ни одна из групп не совпадает, доступ будет запрещен.",
 | 
				
			||||||
@ -484,6 +486,7 @@
 | 
				
			|||||||
  "LabelPersonalYearReview": "Итоги прошедшего года ({0})",
 | 
					  "LabelPersonalYearReview": "Итоги прошедшего года ({0})",
 | 
				
			||||||
  "LabelPhotoPathURL": "Путь к фото/URL",
 | 
					  "LabelPhotoPathURL": "Путь к фото/URL",
 | 
				
			||||||
  "LabelPlayMethod": "Метод воспроизведения",
 | 
					  "LabelPlayMethod": "Метод воспроизведения",
 | 
				
			||||||
 | 
					  "LabelPlaybackRateIncrementDecrement": "Величина увеличения/уменьшения скорости воспроизведения",
 | 
				
			||||||
  "LabelPlayerChapterNumberMarker": "{0} из {1}",
 | 
					  "LabelPlayerChapterNumberMarker": "{0} из {1}",
 | 
				
			||||||
  "LabelPlaylists": "Плейлисты",
 | 
					  "LabelPlaylists": "Плейлисты",
 | 
				
			||||||
  "LabelPodcast": "Подкаст",
 | 
					  "LabelPodcast": "Подкаст",
 | 
				
			||||||
@ -651,7 +654,7 @@
 | 
				
			|||||||
  "LabelToolsMakeM4bDescription": "Создает .M4B файл аудиокниги с встроенными метаданными, обложкой и главами.",
 | 
					  "LabelToolsMakeM4bDescription": "Создает .M4B файл аудиокниги с встроенными метаданными, обложкой и главами.",
 | 
				
			||||||
  "LabelToolsSplitM4b": "Разделить M4B на MP3 файлы",
 | 
					  "LabelToolsSplitM4b": "Разделить M4B на MP3 файлы",
 | 
				
			||||||
  "LabelToolsSplitM4bDescription": "Создает MP3 файла из M4B, разделяет на главы с встроенными метаданными, обложкой и главами.",
 | 
					  "LabelToolsSplitM4bDescription": "Создает MP3 файла из M4B, разделяет на главы с встроенными метаданными, обложкой и главами.",
 | 
				
			||||||
  "LabelTotalDuration": "Общая длина",
 | 
					  "LabelTotalDuration": "Общая продолжительность",
 | 
				
			||||||
  "LabelTotalTimeListened": "Всего прослушано",
 | 
					  "LabelTotalTimeListened": "Всего прослушано",
 | 
				
			||||||
  "LabelTrackFromFilename": "Трек из Имени файла",
 | 
					  "LabelTrackFromFilename": "Трек из Имени файла",
 | 
				
			||||||
  "LabelTrackFromMetadata": "Трек из Метаданных",
 | 
					  "LabelTrackFromMetadata": "Трек из Метаданных",
 | 
				
			||||||
@ -704,8 +707,11 @@
 | 
				
			|||||||
  "MessageBackupsLocationEditNote": "Примечание: Обновление местоположения резервной копии не приведет к перемещению или изменению существующих резервных копий",
 | 
					  "MessageBackupsLocationEditNote": "Примечание: Обновление местоположения резервной копии не приведет к перемещению или изменению существующих резервных копий",
 | 
				
			||||||
  "MessageBackupsLocationNoEditNote": "Примечание: Местоположение резервного копирования задается с помощью переменной среды и не может быть изменено здесь.",
 | 
					  "MessageBackupsLocationNoEditNote": "Примечание: Местоположение резервного копирования задается с помощью переменной среды и не может быть изменено здесь.",
 | 
				
			||||||
  "MessageBackupsLocationPathEmpty": "Путь к расположению резервной копии не может быть пустым",
 | 
					  "MessageBackupsLocationPathEmpty": "Путь к расположению резервной копии не может быть пустым",
 | 
				
			||||||
 | 
					  "MessageBatchEditPopulateMapDetailsAllHelp": "Заполнить включенные поля данными из всех элементов. Поля с несколькими значениями будут объединены",
 | 
				
			||||||
 | 
					  "MessageBatchEditPopulateMapDetailsItemHelp": "Заполнить активированные поля сведений о карте данными из этого элемента",
 | 
				
			||||||
  "MessageBatchQuickMatchDescription": "Быстрый Поиск попытается добавить отсутствующие обложки и метаданные для выбранных элементов. Включите параметры ниже, чтобы разрешить Быстрому Поиску перезаписывать существующие обложки и/или метаданные.",
 | 
					  "MessageBatchQuickMatchDescription": "Быстрый Поиск попытается добавить отсутствующие обложки и метаданные для выбранных элементов. Включите параметры ниже, чтобы разрешить Быстрому Поиску перезаписывать существующие обложки и/или метаданные.",
 | 
				
			||||||
  "MessageBookshelfNoCollections": "Вы еще не создали ни одной коллекции",
 | 
					  "MessageBookshelfNoCollections": "Вы еще не создали ни одной коллекции",
 | 
				
			||||||
 | 
					  "MessageBookshelfNoCollectionsHelp": "Коллекции являются общедоступными. Все пользователи, имеющие доступ к библиотеке, могут их просматривать.",
 | 
				
			||||||
  "MessageBookshelfNoRSSFeeds": "Нет открытых RSS-каналов",
 | 
					  "MessageBookshelfNoRSSFeeds": "Нет открытых RSS-каналов",
 | 
				
			||||||
  "MessageBookshelfNoResultsForFilter": "Нет Результатов для фильтра \"{0}: {1}\"",
 | 
					  "MessageBookshelfNoResultsForFilter": "Нет Результатов для фильтра \"{0}: {1}\"",
 | 
				
			||||||
  "MessageBookshelfNoResultsForQuery": "Нет результатов для запроса",
 | 
					  "MessageBookshelfNoResultsForQuery": "Нет результатов для запроса",
 | 
				
			||||||
@ -816,6 +822,7 @@
 | 
				
			|||||||
  "MessageNoTasksRunning": "Нет выполняемых задач",
 | 
					  "MessageNoTasksRunning": "Нет выполняемых задач",
 | 
				
			||||||
  "MessageNoUpdatesWereNecessary": "Обновления не требовались",
 | 
					  "MessageNoUpdatesWereNecessary": "Обновления не требовались",
 | 
				
			||||||
  "MessageNoUserPlaylists": "У вас нет плейлистов",
 | 
					  "MessageNoUserPlaylists": "У вас нет плейлистов",
 | 
				
			||||||
 | 
					  "MessageNoUserPlaylistsHelp": "Списки воспроизведения являются конфиденциальными. Только пользователь, который их создает, может их видеть.",
 | 
				
			||||||
  "MessageNotYetImplemented": "Пока не реализовано",
 | 
					  "MessageNotYetImplemented": "Пока не реализовано",
 | 
				
			||||||
  "MessageOpmlPreviewNote": "Примечание: Это предварительный просмотр разобранного файла OPML. Фактическое название подкаста будет взято из RSS-канала.",
 | 
					  "MessageOpmlPreviewNote": "Примечание: Это предварительный просмотр разобранного файла OPML. Фактическое название подкаста будет взято из RSS-канала.",
 | 
				
			||||||
  "MessageOr": "или",
 | 
					  "MessageOr": "или",
 | 
				
			||||||
 | 
				
			|||||||
@ -434,7 +434,7 @@
 | 
				
			|||||||
  "LabelMetadataProvider": "Ponudnik metapodatkov",
 | 
					  "LabelMetadataProvider": "Ponudnik metapodatkov",
 | 
				
			||||||
  "LabelMinute": "Minuta",
 | 
					  "LabelMinute": "Minuta",
 | 
				
			||||||
  "LabelMinutes": "Minute",
 | 
					  "LabelMinutes": "Minute",
 | 
				
			||||||
  "LabelMissing": "Manjkajoče",
 | 
					  "LabelMissing": "Manjka",
 | 
				
			||||||
  "LabelMissingEbook": "Nima nobene e-knjige",
 | 
					  "LabelMissingEbook": "Nima nobene e-knjige",
 | 
				
			||||||
  "LabelMissingSupplementaryEbook": "Nima nobene dodatne e-knjige",
 | 
					  "LabelMissingSupplementaryEbook": "Nima nobene dodatne e-knjige",
 | 
				
			||||||
  "LabelMobileRedirectURIs": "Dovoljeni mobilni preusmeritveni URI-ji",
 | 
					  "LabelMobileRedirectURIs": "Dovoljeni mobilni preusmeritveni URI-ji",
 | 
				
			||||||
@ -486,6 +486,7 @@
 | 
				
			|||||||
  "LabelPersonalYearReview": "Pregled tvojega leta ({0})",
 | 
					  "LabelPersonalYearReview": "Pregled tvojega leta ({0})",
 | 
				
			||||||
  "LabelPhotoPathURL": "Slika pot/URL",
 | 
					  "LabelPhotoPathURL": "Slika pot/URL",
 | 
				
			||||||
  "LabelPlayMethod": "Metoda predvajanja",
 | 
					  "LabelPlayMethod": "Metoda predvajanja",
 | 
				
			||||||
 | 
					  "LabelPlaybackRateIncrementDecrement": "Korak povečanja/zmanjšanja hitrosti predvajanja",
 | 
				
			||||||
  "LabelPlayerChapterNumberMarker": "{0} od {1}",
 | 
					  "LabelPlayerChapterNumberMarker": "{0} od {1}",
 | 
				
			||||||
  "LabelPlaylists": "Seznami predvajanja",
 | 
					  "LabelPlaylists": "Seznami predvajanja",
 | 
				
			||||||
  "LabelPodcast": "Podcast",
 | 
					  "LabelPodcast": "Podcast",
 | 
				
			||||||
@ -710,6 +711,7 @@
 | 
				
			|||||||
  "MessageBatchEditPopulateMapDetailsItemHelp": "Napolni omogočena polja s podrobnostmi zemljevida s podatki iz tega elementa",
 | 
					  "MessageBatchEditPopulateMapDetailsItemHelp": "Napolni omogočena polja s podrobnostmi zemljevida s podatki iz tega elementa",
 | 
				
			||||||
  "MessageBatchQuickMatchDescription": "Hitro ujemanje bo poskušal dodati manjkajoče naslovnice in metapodatke za izbrane elemente. Omogočite spodnje možnosti, da omogočite hitremu ujemanju, da prepiše obstoječe naslovnice in/ali metapodatke.",
 | 
					  "MessageBatchQuickMatchDescription": "Hitro ujemanje bo poskušal dodati manjkajoče naslovnice in metapodatke za izbrane elemente. Omogočite spodnje možnosti, da omogočite hitremu ujemanju, da prepiše obstoječe naslovnice in/ali metapodatke.",
 | 
				
			||||||
  "MessageBookshelfNoCollections": "Ustvaril nisi še nobene zbirke",
 | 
					  "MessageBookshelfNoCollections": "Ustvaril nisi še nobene zbirke",
 | 
				
			||||||
 | 
					  "MessageBookshelfNoCollectionsHelp": "Zbirke so javne. Vsi uporabniki z dostopom do knjižnice jih lahko vidijo.",
 | 
				
			||||||
  "MessageBookshelfNoRSSFeeds": "Noben vir RSS ni odprt",
 | 
					  "MessageBookshelfNoRSSFeeds": "Noben vir RSS ni odprt",
 | 
				
			||||||
  "MessageBookshelfNoResultsForFilter": "Ni rezultatov za filter \"{0}: {1}\"",
 | 
					  "MessageBookshelfNoResultsForFilter": "Ni rezultatov za filter \"{0}: {1}\"",
 | 
				
			||||||
  "MessageBookshelfNoResultsForQuery": "Ni rezultatov za poizvedbo",
 | 
					  "MessageBookshelfNoResultsForQuery": "Ni rezultatov za poizvedbo",
 | 
				
			||||||
@ -820,6 +822,7 @@
 | 
				
			|||||||
  "MessageNoTasksRunning": "Nobeno opravili ne teče",
 | 
					  "MessageNoTasksRunning": "Nobeno opravili ne teče",
 | 
				
			||||||
  "MessageNoUpdatesWereNecessary": "Posodobitve niso bile potrebne",
 | 
					  "MessageNoUpdatesWereNecessary": "Posodobitve niso bile potrebne",
 | 
				
			||||||
  "MessageNoUserPlaylists": "Nimate seznamov predvajanja",
 | 
					  "MessageNoUserPlaylists": "Nimate seznamov predvajanja",
 | 
				
			||||||
 | 
					  "MessageNoUserPlaylistsHelp": "Seznami predvajanj so zasebni. Samo uporabniki, ki jih ustvarijo, jih lahko vidijo.",
 | 
				
			||||||
  "MessageNotYetImplemented": "Še ni implementirano",
 | 
					  "MessageNotYetImplemented": "Še ni implementirano",
 | 
				
			||||||
  "MessageOpmlPreviewNote": "Opomba: To je predogled razčlenjene datoteke OPML. Dejanski naslov podcasta bo vzet iz vira RSS.",
 | 
					  "MessageOpmlPreviewNote": "Opomba: To je predogled razčlenjene datoteke OPML. Dejanski naslov podcasta bo vzet iz vira RSS.",
 | 
				
			||||||
  "MessageOr": "ali",
 | 
					  "MessageOr": "ali",
 | 
				
			||||||
 | 
				
			|||||||
@ -110,7 +110,7 @@
 | 
				
			|||||||
  "HeaderAccount": "Konto",
 | 
					  "HeaderAccount": "Konto",
 | 
				
			||||||
  "HeaderAddCustomMetadataProvider": "Addera egen källa för metadata",
 | 
					  "HeaderAddCustomMetadataProvider": "Addera egen källa för metadata",
 | 
				
			||||||
  "HeaderAdvanced": "Avancerad",
 | 
					  "HeaderAdvanced": "Avancerad",
 | 
				
			||||||
  "HeaderAppriseNotificationSettings": "Apprise Meddelandeinställningar",
 | 
					  "HeaderAppriseNotificationSettings": "Inställningar av meddelanden med Apprise",
 | 
				
			||||||
  "HeaderAudioTracks": "Ljudspår",
 | 
					  "HeaderAudioTracks": "Ljudspår",
 | 
				
			||||||
  "HeaderAudiobookTools": "Hantering av ljudboksfil",
 | 
					  "HeaderAudiobookTools": "Hantering av ljudboksfil",
 | 
				
			||||||
  "HeaderAuthentication": "Autentisering",
 | 
					  "HeaderAuthentication": "Autentisering",
 | 
				
			||||||
@ -153,6 +153,7 @@
 | 
				
			|||||||
  "HeaderMetadataToEmbed": "Metadata som kommer att adderas",
 | 
					  "HeaderMetadataToEmbed": "Metadata som kommer att adderas",
 | 
				
			||||||
  "HeaderNewAccount": "Nytt konto",
 | 
					  "HeaderNewAccount": "Nytt konto",
 | 
				
			||||||
  "HeaderNewLibrary": "Nytt bibliotek",
 | 
					  "HeaderNewLibrary": "Nytt bibliotek",
 | 
				
			||||||
 | 
					  "HeaderNotificationCreate": "Addera ett meddelande",
 | 
				
			||||||
  "HeaderNotifications": "Meddelanden",
 | 
					  "HeaderNotifications": "Meddelanden",
 | 
				
			||||||
  "HeaderOpenRSSFeed": "Öppna RSS-flöde",
 | 
					  "HeaderOpenRSSFeed": "Öppna RSS-flöde",
 | 
				
			||||||
  "HeaderOtherFiles": "Andra filer",
 | 
					  "HeaderOtherFiles": "Andra filer",
 | 
				
			||||||
@ -205,7 +206,7 @@
 | 
				
			|||||||
  "LabelAccountTypeUser": "Användare",
 | 
					  "LabelAccountTypeUser": "Användare",
 | 
				
			||||||
  "LabelActivity": "Aktivitet",
 | 
					  "LabelActivity": "Aktivitet",
 | 
				
			||||||
  "LabelAddToCollection": "Lägg till i en samling",
 | 
					  "LabelAddToCollection": "Lägg till i en samling",
 | 
				
			||||||
  "LabelAddToCollectionBatch": "Lägg till {0} böcker i en Samling",
 | 
					  "LabelAddToCollectionBatch": "Lägg till {0} böcker i samlingen",
 | 
				
			||||||
  "LabelAddToPlaylist": "Lägg till i en spellista",
 | 
					  "LabelAddToPlaylist": "Lägg till i en spellista",
 | 
				
			||||||
  "LabelAddToPlaylistBatch": "Lägg till {0} objekt i Spellistan",
 | 
					  "LabelAddToPlaylistBatch": "Lägg till {0} objekt i Spellistan",
 | 
				
			||||||
  "LabelAddedAt": "Datum adderad",
 | 
					  "LabelAddedAt": "Datum adderad",
 | 
				
			||||||
@ -215,7 +216,7 @@
 | 
				
			|||||||
  "LabelAllUsers": "Alla användare",
 | 
					  "LabelAllUsers": "Alla användare",
 | 
				
			||||||
  "LabelAllUsersExcludingGuests": "Alla användare utom gäster",
 | 
					  "LabelAllUsersExcludingGuests": "Alla användare utom gäster",
 | 
				
			||||||
  "LabelAllUsersIncludingGuests": "Alla användare inklusive gäster",
 | 
					  "LabelAllUsersIncludingGuests": "Alla användare inklusive gäster",
 | 
				
			||||||
  "LabelAlreadyInYourLibrary": "Redan i din samling",
 | 
					  "LabelAlreadyInYourLibrary": "Finns redan i samlingen",
 | 
				
			||||||
  "LabelApiToken": "API-token",
 | 
					  "LabelApiToken": "API-token",
 | 
				
			||||||
  "LabelAppend": "Lägg till",
 | 
					  "LabelAppend": "Lägg till",
 | 
				
			||||||
  "LabelAudioBitrate": "Bitrate för ljud (t.ex. 128k)",
 | 
					  "LabelAudioBitrate": "Bitrate för ljud (t.ex. 128k)",
 | 
				
			||||||
@ -483,7 +484,7 @@
 | 
				
			|||||||
  "LabelSelectEpisodesShowing": "Välj {0} avsnitt som visas",
 | 
					  "LabelSelectEpisodesShowing": "Välj {0} avsnitt som visas",
 | 
				
			||||||
  "LabelSelectUsers": "Välj användare",
 | 
					  "LabelSelectUsers": "Välj användare",
 | 
				
			||||||
  "LabelSendEbookToDevice": "Skicka e-bok till...",
 | 
					  "LabelSendEbookToDevice": "Skicka e-bok till...",
 | 
				
			||||||
  "LabelSequence": "Sekvens",
 | 
					  "LabelSequence": "Sekvensnummer",
 | 
				
			||||||
  "LabelSeries": "Serier",
 | 
					  "LabelSeries": "Serier",
 | 
				
			||||||
  "LabelSeriesName": "Serienamn",
 | 
					  "LabelSeriesName": "Serienamn",
 | 
				
			||||||
  "LabelSeriesProgress": "Status för serier",
 | 
					  "LabelSeriesProgress": "Status för serier",
 | 
				
			||||||
@ -637,7 +638,7 @@
 | 
				
			|||||||
  "MessageAddToPlayerQueue": "Lägg till i spellistan",
 | 
					  "MessageAddToPlayerQueue": "Lägg till i spellistan",
 | 
				
			||||||
  "MessageAppriseDescription": "För att använda den här funktionen behöver du ha en instans av <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> igång eller en API som hanterar dessa begäranden. <br />Apprise API-urlen bör vara hela URL-sökvägen för att skicka meddelandet, t.ex., om din API-instans är tillgänglig på <code>http://192.168.1.1:8337</code>, bör du ange <code>http://192.168.1.1:8337/notify</code>.",
 | 
					  "MessageAppriseDescription": "För att använda den här funktionen behöver du ha en instans av <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> igång eller en API som hanterar dessa begäranden. <br />Apprise API-urlen bör vara hela URL-sökvägen för att skicka meddelandet, t.ex., om din API-instans är tillgänglig på <code>http://192.168.1.1:8337</code>, bör du ange <code>http://192.168.1.1:8337/notify</code>.",
 | 
				
			||||||
  "MessageBackupsDescription": "Säkerhetskopior inkluderar användare, användarnas framsteg, biblioteksobjekt, serverinställningar<br>och bilder lagrade i <code>/metadata/items</code> & <code>/metadata/authors</code>.<br>De inkluderar <strong>INTE</strong> några filer lagrade i dina biblioteksmappar.",
 | 
					  "MessageBackupsDescription": "Säkerhetskopior inkluderar användare, användarnas framsteg, biblioteksobjekt, serverinställningar<br>och bilder lagrade i <code>/metadata/items</code> & <code>/metadata/authors</code>.<br>De inkluderar <strong>INTE</strong> några filer lagrade i dina biblioteksmappar.",
 | 
				
			||||||
  "MessageBackupsLocationEditNote": "OBS: När du ändrar plats för säkerhetskopiorna så flyttas INTE gamla säkerhetskopior dit",
 | 
					  "MessageBackupsLocationEditNote": "OBS: När du ändrar plats för säkerhetskopiorna så flyttas INTE gamla säkerhetskopior dit.",
 | 
				
			||||||
  "MessageBackupsLocationNoEditNote": "OBS: Platsen där säkerhetskopiorna lagras bestäms av en central inställning och kan inte ändras här.",
 | 
					  "MessageBackupsLocationNoEditNote": "OBS: Platsen där säkerhetskopiorna lagras bestäms av en central inställning och kan inte ändras här.",
 | 
				
			||||||
  "MessageBackupsLocationPathEmpty": "Uppgiften om platsen för lagring av säkerhetskopior kan inte lämnas tom",
 | 
					  "MessageBackupsLocationPathEmpty": "Uppgiften om platsen för lagring av säkerhetskopior kan inte lämnas tom",
 | 
				
			||||||
  "MessageBatchQuickMatchDescription": "Quick Match kommer försöka lägga till saknade omslag och metadata för de valda föremålen. Aktivera alternativen nedan för att tillåta Quick Match att överskriva befintliga omslag och/eller metadata.",
 | 
					  "MessageBatchQuickMatchDescription": "Quick Match kommer försöka lägga till saknade omslag och metadata för de valda föremålen. Aktivera alternativen nedan för att tillåta Quick Match att överskriva befintliga omslag och/eller metadata.",
 | 
				
			||||||
@ -660,8 +661,10 @@
 | 
				
			|||||||
  "MessageConfirmDeleteLibraryItem": "Detta kommer att radera objektet från databasen och ditt filsystem. Är du säker?",
 | 
					  "MessageConfirmDeleteLibraryItem": "Detta kommer att radera objektet från databasen och ditt filsystem. Är du säker?",
 | 
				
			||||||
  "MessageConfirmDeleteLibraryItems": "Detta kommer att radera {0} biblioteksobjekt från databasen och ditt filsystem. Är du säker?",
 | 
					  "MessageConfirmDeleteLibraryItems": "Detta kommer att radera {0} biblioteksobjekt från databasen och ditt filsystem. Är du säker?",
 | 
				
			||||||
  "MessageConfirmDeleteMetadataProvider": "Är du säker på att du vill radera din egen källa för metadata \"{0}\"?",
 | 
					  "MessageConfirmDeleteMetadataProvider": "Är du säker på att du vill radera din egen källa för metadata \"{0}\"?",
 | 
				
			||||||
 | 
					  "MessageConfirmDeleteNotification": "Är du säker på att du vill radera detta meddelande?",
 | 
				
			||||||
  "MessageConfirmDeleteSession": "Är du säker på att du vill radera detta lyssningstillfälle?",
 | 
					  "MessageConfirmDeleteSession": "Är du säker på att du vill radera detta lyssningstillfälle?",
 | 
				
			||||||
  "MessageConfirmForceReScan": "Är du säker på att du vill tvinga omgenomsökning?",
 | 
					  "MessageConfirmEmbedMetadataInAudioFiles": "Är du säker på att du vill infoga metadata i {0} ljudfiler?",
 | 
				
			||||||
 | 
					  "MessageConfirmForceReScan": "Är du säker på att du vill starta en ny skanning?",
 | 
				
			||||||
  "MessageConfirmMarkAllEpisodesFinished": "Är du säker på att du vill markera alla avsnitt som avslutade?",
 | 
					  "MessageConfirmMarkAllEpisodesFinished": "Är du säker på att du vill markera alla avsnitt som avslutade?",
 | 
				
			||||||
  "MessageConfirmMarkAllEpisodesNotFinished": "Är du säker på att du vill markera alla avsnitt som ej avslutade?",
 | 
					  "MessageConfirmMarkAllEpisodesNotFinished": "Är du säker på att du vill markera alla avsnitt som ej avslutade?",
 | 
				
			||||||
  "MessageConfirmMarkItemFinished": "Är du säker på att du vill markera \"{0}\" som avslutad?",
 | 
					  "MessageConfirmMarkItemFinished": "Är du säker på att du vill markera \"{0}\" som avslutad?",
 | 
				
			||||||
@ -678,7 +681,7 @@
 | 
				
			|||||||
  "MessageConfirmRemoveEpisode": "Är du säker på att du vill ta bort avsnittet \"{0}\"?",
 | 
					  "MessageConfirmRemoveEpisode": "Är du säker på att du vill ta bort avsnittet \"{0}\"?",
 | 
				
			||||||
  "MessageConfirmRemoveEpisodes": "Är du säker på att du vill ta bort {0} avsnitt?",
 | 
					  "MessageConfirmRemoveEpisodes": "Är du säker på att du vill ta bort {0} avsnitt?",
 | 
				
			||||||
  "MessageConfirmRemoveListeningSessions": "Är du säker på att du vill radera {0} lyssningstillfällen?",
 | 
					  "MessageConfirmRemoveListeningSessions": "Är du säker på att du vill radera {0} lyssningstillfällen?",
 | 
				
			||||||
  "MessageConfirmRemoveMetadataFiles": "Är du säker på att du vill radera 'metadata.{0}' filerna i alla mappar i ditt bibliotek?",
 | 
					  "MessageConfirmRemoveMetadataFiles": "Är du säker på att du vill radera filerna 'metadata.{0}' i alla mappar i ditt bibliotek?",
 | 
				
			||||||
  "MessageConfirmRemoveNarrator": "Är du säker på att du vill ta bort uppläsaren \"{0}\"?",
 | 
					  "MessageConfirmRemoveNarrator": "Är du säker på att du vill ta bort uppläsaren \"{0}\"?",
 | 
				
			||||||
  "MessageConfirmRemovePlaylist": "Är du säker på att du vill ta bort din spellista \"{0}\"?",
 | 
					  "MessageConfirmRemovePlaylist": "Är du säker på att du vill ta bort din spellista \"{0}\"?",
 | 
				
			||||||
  "MessageConfirmRenameGenre": "Är du säker på att du vill byta namn på kategorin \"{0}\" till \"{1}\" för alla objekt?",
 | 
					  "MessageConfirmRenameGenre": "Är du säker på att du vill byta namn på kategorin \"{0}\" till \"{1}\" för alla objekt?",
 | 
				
			||||||
@ -748,7 +751,7 @@
 | 
				
			|||||||
  "MessageOr": "eller",
 | 
					  "MessageOr": "eller",
 | 
				
			||||||
  "MessagePauseChapter": "Pausa kapiteluppspelning",
 | 
					  "MessagePauseChapter": "Pausa kapiteluppspelning",
 | 
				
			||||||
  "MessagePlayChapter": "Lyssna på kapitlets början",
 | 
					  "MessagePlayChapter": "Lyssna på kapitlets början",
 | 
				
			||||||
  "MessagePlaylistCreateFromCollection": "Skapa spellista från samling",
 | 
					  "MessagePlaylistCreateFromCollection": "Skapa en spellista från samlingen",
 | 
				
			||||||
  "MessagePleaseWait": "Vänta ett ögonblick...",
 | 
					  "MessagePleaseWait": "Vänta ett ögonblick...",
 | 
				
			||||||
  "MessagePodcastHasNoRSSFeedForMatching": "Podcasten har ingen RSS-flödes-URL att använda för matchning",
 | 
					  "MessagePodcastHasNoRSSFeedForMatching": "Podcasten har ingen RSS-flödes-URL att använda för matchning",
 | 
				
			||||||
  "MessageQuickMatchDescription": "Adderar uppgifter som saknas samt en omslagsbild från<br>första träffen i resultatet vid sökningen från '{0}'.<br>Skriver inte över befintliga uppgifter om inte<br>inställningen 'Prioritera matchad metadata' är aktiverad.",
 | 
					  "MessageQuickMatchDescription": "Adderar uppgifter som saknas samt en omslagsbild från<br>första träffen i resultatet vid sökningen från '{0}'.<br>Skriver inte över befintliga uppgifter om inte<br>inställningen 'Prioritera matchad metadata' är aktiverad.",
 | 
				
			||||||
@ -760,6 +763,7 @@
 | 
				
			|||||||
  "MessageResetChaptersConfirm": "Är du säker på att du vill återställa alla kapitel och ångra de ändringarna du gjort?",
 | 
					  "MessageResetChaptersConfirm": "Är du säker på att du vill återställa alla kapitel och ångra de ändringarna du gjort?",
 | 
				
			||||||
  "MessageRestoreBackupConfirm": "Är du säker på att du vill läsa in säkerhetskopian som skapades den",
 | 
					  "MessageRestoreBackupConfirm": "Är du säker på att du vill läsa in säkerhetskopian som skapades den",
 | 
				
			||||||
  "MessageRestoreBackupWarning": "Att återställa en säkerhetskopia kommer att skriva över hela databasen som finns i /config och omslagsbilder i /metadata/items & /metadata/authors.<br /><br />Säkerhetskopior ändrar inte några filer i dina biblioteksmappar. Om du har aktiverat serverinställningar för att lagra omslagskonst och metadata i dina biblioteksmappar säkerhetskopieras eller skrivs de inte över.<br /><br />Alla klienter som använder din server kommer att uppdateras automatiskt.",
 | 
					  "MessageRestoreBackupWarning": "Att återställa en säkerhetskopia kommer att skriva över hela databasen som finns i /config och omslagsbilder i /metadata/items & /metadata/authors.<br /><br />Säkerhetskopior ändrar inte några filer i dina biblioteksmappar. Om du har aktiverat serverinställningar för att lagra omslagskonst och metadata i dina biblioteksmappar säkerhetskopieras eller skrivs de inte över.<br /><br />Alla klienter som använder din server kommer att uppdateras automatiskt.",
 | 
				
			||||||
 | 
					  "MessageScheduleLibraryScanNote": "För de flesta användare rekommenderas att denna funktion ej aktiveras. Istället bör funktionen 'Watcher' vara aktiverad. Watcher kommer då automatiskt identifiera förändringar i biblioteket. För vissa filsystem (som t.ex. NFS) fungerar inte Watcher. Då kan schemalagda skanningar av biblioteken användas istället.",
 | 
				
			||||||
  "MessageSearchResultsFor": "Sökresultat för",
 | 
					  "MessageSearchResultsFor": "Sökresultat för",
 | 
				
			||||||
  "MessageSelected": "{0} valda",
 | 
					  "MessageSelected": "{0} valda",
 | 
				
			||||||
  "MessageServerCouldNotBeReached": "Servern kunde inte nås",
 | 
					  "MessageServerCouldNotBeReached": "Servern kunde inte nås",
 | 
				
			||||||
@ -783,15 +787,15 @@
 | 
				
			|||||||
  "MessageXLibraryIsEmpty": "Biblioteket {0} är tomt!",
 | 
					  "MessageXLibraryIsEmpty": "Biblioteket {0} är tomt!",
 | 
				
			||||||
  "MessageYourAudiobookDurationIsLonger": "Varaktigheten på din ljudbok är längre än den hittade varaktigheten",
 | 
					  "MessageYourAudiobookDurationIsLonger": "Varaktigheten på din ljudbok är längre än den hittade varaktigheten",
 | 
				
			||||||
  "MessageYourAudiobookDurationIsShorter": "Varaktigheten på din ljudbok är kortare än den hittade varaktigheten",
 | 
					  "MessageYourAudiobookDurationIsShorter": "Varaktigheten på din ljudbok är kortare än den hittade varaktigheten",
 | 
				
			||||||
  "NoteChangeRootPassword": "Rotanvändaren är den enda användaren som kan ha ett tomt lösenord",
 | 
					  "NoteChangeRootPassword": "Användaren 'root' är den enda användaren som kan vara utan lösenord",
 | 
				
			||||||
  "NoteChapterEditorTimes": "OBS: Starttiden för första kapitlet måste vara 0:00 och starttiden för det sista kapitlet får inte överstiga ljudbokens totala varaktighet.",
 | 
					  "NoteChapterEditorTimes": "OBS: Starttiden för första kapitlet måste vara 0:00 och starttiden för det sista kapitlet får inte överstiga ljudbokens totala varaktighet.",
 | 
				
			||||||
  "NoteFolderPicker": "Obs: Mappar som redan är kartlagda kommer inte att visas",
 | 
					  "NoteFolderPicker": "OBS: Mappar som redan är kopplade kommer inte att visas",
 | 
				
			||||||
  "NoteRSSFeedPodcastAppsHttps": "Varning: De flesta podcastappar kräver att RSS-flödets URL används med HTTPS",
 | 
					  "NoteRSSFeedPodcastAppsHttps": "VARNING: De flesta applikationer för podcasts kräver att URL:en för RSS-flödet använder HTTPS",
 | 
				
			||||||
  "NoteRSSFeedPodcastAppsPubDate": "Varning: 1 eller flera av dina avsnitt har inte ett publiceringsdatum. Vissa podcastappar kräver detta.",
 | 
					  "NoteRSSFeedPodcastAppsPubDate": "VARNING: Ett eller flera av dina avsnitt har inte ett publiceringsdatum. Vissa applikationer för podcasts kräver detta.",
 | 
				
			||||||
  "NoteUploaderFoldersWithMediaFiles": "Mappar med flera mediefiler hanteras som separata objekt i biblioteket.",
 | 
					  "NoteUploaderFoldersWithMediaFiles": "Mappar som innehåller mediefiler hanteras som separata objekt i biblioteket.",
 | 
				
			||||||
  "NoteUploaderOnlyAudioFiles": "Om du bara laddar upp ljudfiler kommer varje ljudfil att hanteras som en separat ljudbok.",
 | 
					  "NoteUploaderOnlyAudioFiles": "Om du bara laddar upp ljudfiler kommer varje ljudfil att hanteras som en separat ljudbok.",
 | 
				
			||||||
  "NoteUploaderUnsupportedFiles": "Oaccepterade filer ignoreras. När du väljer eller släpper en mapp ignoreras andra filer som inte finns i ett objektmapp.",
 | 
					  "NoteUploaderUnsupportedFiles": "Oaccepterade filer ignoreras. När du väljer eller släpper en mapp ignoreras andra filer som inte finns i ett objektmapp.",
 | 
				
			||||||
  "PlaceholderNewCollection": "Nytt samlingsnamn",
 | 
					  "PlaceholderNewCollection": "Nytt namn på samlingen",
 | 
				
			||||||
  "PlaceholderNewFolderPath": "Nytt sökväg till mappen",
 | 
					  "PlaceholderNewFolderPath": "Nytt sökväg till mappen",
 | 
				
			||||||
  "PlaceholderNewPlaylist": "Nytt namn på spellistan",
 | 
					  "PlaceholderNewPlaylist": "Nytt namn på spellistan",
 | 
				
			||||||
  "PlaceholderSearch": "Sök...",
 | 
					  "PlaceholderSearch": "Sök...",
 | 
				
			||||||
@ -851,7 +855,9 @@
 | 
				
			|||||||
  "ToastDeviceTestEmailFailed": "Misslyckades med att skicka ett testmail",
 | 
					  "ToastDeviceTestEmailFailed": "Misslyckades med att skicka ett testmail",
 | 
				
			||||||
  "ToastDeviceTestEmailSuccess": "Ett testmail har skickats",
 | 
					  "ToastDeviceTestEmailSuccess": "Ett testmail har skickats",
 | 
				
			||||||
  "ToastEmailSettingsUpdateSuccess": "Inställningarna av e-post har uppdaterats",
 | 
					  "ToastEmailSettingsUpdateSuccess": "Inställningarna av e-post har uppdaterats",
 | 
				
			||||||
 | 
					  "ToastEncodeCancelSucces": "Omkodningen avbruten",
 | 
				
			||||||
  "ToastFailedToLoadData": "Misslyckades med att ladda data",
 | 
					  "ToastFailedToLoadData": "Misslyckades med att ladda data",
 | 
				
			||||||
 | 
					  "ToastFailedToUpdate": "Misslyckades med att uppdatera",
 | 
				
			||||||
  "ToastInvalidImageUrl": "Felaktig URL-adress till omslagsbilden",
 | 
					  "ToastInvalidImageUrl": "Felaktig URL-adress till omslagsbilden",
 | 
				
			||||||
  "ToastInvalidMaxEpisodesToDownload": "Ogiltigt maximalt antal avsnitt att ladda ner",
 | 
					  "ToastInvalidMaxEpisodesToDownload": "Ogiltigt maximalt antal avsnitt att ladda ner",
 | 
				
			||||||
  "ToastInvalidUrl": "Felaktig URL-adress",
 | 
					  "ToastInvalidUrl": "Felaktig URL-adress",
 | 
				
			||||||
@ -878,7 +884,12 @@
 | 
				
			|||||||
  "ToastNameRequired": "Ett namn måste anges",
 | 
					  "ToastNameRequired": "Ett namn måste anges",
 | 
				
			||||||
  "ToastNewUserCreatedFailed": "Misslyckades med att skapa kontot \"{0}\"",
 | 
					  "ToastNewUserCreatedFailed": "Misslyckades med att skapa kontot \"{0}\"",
 | 
				
			||||||
  "ToastNewUserCreatedSuccess": "Ett nytt konto har skapats",
 | 
					  "ToastNewUserCreatedSuccess": "Ett nytt konto har skapats",
 | 
				
			||||||
 | 
					  "ToastNewUserLibraryError": "Minst ett bibliotek måste anges",
 | 
				
			||||||
 | 
					  "ToastNewUserPasswordError": "Ett lösenord måste anges. Endast användaren 'root' kan vara utan lösenord.",
 | 
				
			||||||
 | 
					  "ToastNewUserUsernameError": "Ange ett användarnamn",
 | 
				
			||||||
  "ToastNoUpdatesNecessary": "Inga uppdateringar var nödvändiga",
 | 
					  "ToastNoUpdatesNecessary": "Inga uppdateringar var nödvändiga",
 | 
				
			||||||
 | 
					  "ToastNotificationCreateFailed": "Misslyckades med att skapa meddelandet",
 | 
				
			||||||
 | 
					  "ToastNotificationDeleteFailed": "Misslyckades med att radera meddelandet",
 | 
				
			||||||
  "ToastPlaylistCreateFailed": "Det gick inte att skapa spellistan",
 | 
					  "ToastPlaylistCreateFailed": "Det gick inte att skapa spellistan",
 | 
				
			||||||
  "ToastPlaylistCreateSuccess": "Spellistan skapad",
 | 
					  "ToastPlaylistCreateSuccess": "Spellistan skapad",
 | 
				
			||||||
  "ToastPlaylistRemoveSuccess": "Spellistan har tagits bort",
 | 
					  "ToastPlaylistRemoveSuccess": "Spellistan har tagits bort",
 | 
				
			||||||
@ -887,11 +898,14 @@
 | 
				
			|||||||
  "ToastPodcastCreateSuccess": "Podcasten skapad framgångsrikt",
 | 
					  "ToastPodcastCreateSuccess": "Podcasten skapad framgångsrikt",
 | 
				
			||||||
  "ToastProviderCreatedFailed": "Misslyckades med att addera en källa",
 | 
					  "ToastProviderCreatedFailed": "Misslyckades med att addera en källa",
 | 
				
			||||||
  "ToastProviderCreatedSuccess": "En ny källa har adderats",
 | 
					  "ToastProviderCreatedSuccess": "En ny källa har adderats",
 | 
				
			||||||
 | 
					  "ToastProviderNameAndUrlRequired": "Ett namn och en URL-adress krävs",
 | 
				
			||||||
  "ToastProviderRemoveSuccess": "Källan har tagits bort",
 | 
					  "ToastProviderRemoveSuccess": "Källan har tagits bort",
 | 
				
			||||||
  "ToastRSSFeedCloseFailed": "Misslyckades med att stänga RSS-flödet",
 | 
					  "ToastRSSFeedCloseFailed": "Misslyckades med att stänga RSS-flödet",
 | 
				
			||||||
  "ToastRSSFeedCloseSuccess": "RSS-flödet stängt",
 | 
					  "ToastRSSFeedCloseSuccess": "RSS-flödet stängt",
 | 
				
			||||||
 | 
					  "ToastRemoveFailed": "Misslyckades med att radera",
 | 
				
			||||||
  "ToastRemoveItemFromCollectionFailed": "Misslyckades med att ta bort objektet från samlingen",
 | 
					  "ToastRemoveItemFromCollectionFailed": "Misslyckades med att ta bort objektet från samlingen",
 | 
				
			||||||
  "ToastRemoveItemFromCollectionSuccess": "Objektet borttaget från samlingen",
 | 
					  "ToastRemoveItemFromCollectionSuccess": "Objektet borttaget från samlingen",
 | 
				
			||||||
 | 
					  "ToastRenameFailed": "Misslyckades med att ändra namn",
 | 
				
			||||||
  "ToastSelectAtLeastOneUser": "Åtminstone en användare måste väljas",
 | 
					  "ToastSelectAtLeastOneUser": "Åtminstone en användare måste väljas",
 | 
				
			||||||
  "ToastSendEbookToDeviceFailed": "Misslyckades med att skicka e-boken till enheten",
 | 
					  "ToastSendEbookToDeviceFailed": "Misslyckades med att skicka e-boken till enheten",
 | 
				
			||||||
  "ToastSendEbookToDeviceSuccess": "E-boken skickad till enheten \"{0}\"",
 | 
					  "ToastSendEbookToDeviceSuccess": "E-boken skickad till enheten \"{0}\"",
 | 
				
			||||||
@ -912,5 +926,6 @@
 | 
				
			|||||||
  "ToastUserDeleteSuccess": "Användaren borttagen",
 | 
					  "ToastUserDeleteSuccess": "Användaren borttagen",
 | 
				
			||||||
  "ToastUserPasswordChangeSuccess": "Lösenordet har ändrats",
 | 
					  "ToastUserPasswordChangeSuccess": "Lösenordet har ändrats",
 | 
				
			||||||
  "ToastUserPasswordMismatch": "Lösenorden är inte identiska",
 | 
					  "ToastUserPasswordMismatch": "Lösenorden är inte identiska",
 | 
				
			||||||
  "ToastUserPasswordMustChange": "Det nya lösenordet kan inte vara samma som det gamla"
 | 
					  "ToastUserPasswordMustChange": "Det nya lösenordet kan inte vara samma som det gamla",
 | 
				
			||||||
 | 
					  "ToastUserRootRequireName": "Ett användarnamn för 'root' måste anges"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								client/strings/tr.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								client/strings/tr.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{}
 | 
				
			||||||
@ -434,7 +434,7 @@
 | 
				
			|||||||
  "LabelMetadataProvider": "Джерело метаданих",
 | 
					  "LabelMetadataProvider": "Джерело метаданих",
 | 
				
			||||||
  "LabelMinute": "Хвилина",
 | 
					  "LabelMinute": "Хвилина",
 | 
				
			||||||
  "LabelMinutes": "Хвилини",
 | 
					  "LabelMinutes": "Хвилини",
 | 
				
			||||||
  "LabelMissing": "Бракує",
 | 
					  "LabelMissing": "Відсутня",
 | 
				
			||||||
  "LabelMissingEbook": "Без електронної книги",
 | 
					  "LabelMissingEbook": "Без електронної книги",
 | 
				
			||||||
  "LabelMissingSupplementaryEbook": "Без додаткової електронної книги",
 | 
					  "LabelMissingSupplementaryEbook": "Без додаткової електронної книги",
 | 
				
			||||||
  "LabelMobileRedirectURIs": "Дозволені адреси перенаправлення",
 | 
					  "LabelMobileRedirectURIs": "Дозволені адреси перенаправлення",
 | 
				
			||||||
@ -486,6 +486,7 @@
 | 
				
			|||||||
  "LabelPersonalYearReview": "Ваші підсумки року ({0})",
 | 
					  "LabelPersonalYearReview": "Ваші підсумки року ({0})",
 | 
				
			||||||
  "LabelPhotoPathURL": "Шлях/URL фото",
 | 
					  "LabelPhotoPathURL": "Шлях/URL фото",
 | 
				
			||||||
  "LabelPlayMethod": "Метод відтворення",
 | 
					  "LabelPlayMethod": "Метод відтворення",
 | 
				
			||||||
 | 
					  "LabelPlaybackRateIncrementDecrement": "Величина збільшення/зменшення швидкості відтворення",
 | 
				
			||||||
  "LabelPlayerChapterNumberMarker": "{0} з {1}",
 | 
					  "LabelPlayerChapterNumberMarker": "{0} з {1}",
 | 
				
			||||||
  "LabelPlaylists": "Списки відтворення",
 | 
					  "LabelPlaylists": "Списки відтворення",
 | 
				
			||||||
  "LabelPodcast": "Подкаст",
 | 
					  "LabelPodcast": "Подкаст",
 | 
				
			||||||
@ -710,6 +711,7 @@
 | 
				
			|||||||
  "MessageBatchEditPopulateMapDetailsItemHelp": "Заповніть увімкнені поля деталей карти даними з цього елемента",
 | 
					  "MessageBatchEditPopulateMapDetailsItemHelp": "Заповніть увімкнені поля деталей карти даними з цього елемента",
 | 
				
			||||||
  "MessageBatchQuickMatchDescription": "Швидкий пошук спробує знайти відсутні обкладинки та метадані обраних елементів. Увімкніть налаштування нижче, аби дозволити заміну наявних обкладинок та/або метаданих під час швидкого пошуку.",
 | 
					  "MessageBatchQuickMatchDescription": "Швидкий пошук спробує знайти відсутні обкладинки та метадані обраних елементів. Увімкніть налаштування нижче, аби дозволити заміну наявних обкладинок та/або метаданих під час швидкого пошуку.",
 | 
				
			||||||
  "MessageBookshelfNoCollections": "Ви не створили жодної добірки",
 | 
					  "MessageBookshelfNoCollections": "Ви не створили жодної добірки",
 | 
				
			||||||
 | 
					  "MessageBookshelfNoCollectionsHelp": "Колекції публічні. Їх можуть бачити всі користувачі, які мають доступ до бібліотеки.",
 | 
				
			||||||
  "MessageBookshelfNoRSSFeeds": "Немає відкритих RSS-каналів",
 | 
					  "MessageBookshelfNoRSSFeeds": "Немає відкритих RSS-каналів",
 | 
				
			||||||
  "MessageBookshelfNoResultsForFilter": "Немає результатів з фільтром \"{0}: {1}\"",
 | 
					  "MessageBookshelfNoResultsForFilter": "Немає результатів з фільтром \"{0}: {1}\"",
 | 
				
			||||||
  "MessageBookshelfNoResultsForQuery": "Немає результатів за запитом",
 | 
					  "MessageBookshelfNoResultsForQuery": "Немає результатів за запитом",
 | 
				
			||||||
@ -820,6 +822,7 @@
 | 
				
			|||||||
  "MessageNoTasksRunning": "Немає активних завдань",
 | 
					  "MessageNoTasksRunning": "Немає активних завдань",
 | 
				
			||||||
  "MessageNoUpdatesWereNecessary": "Оновлень не потрібно",
 | 
					  "MessageNoUpdatesWereNecessary": "Оновлень не потрібно",
 | 
				
			||||||
  "MessageNoUserPlaylists": "У вас немає списків відтворення",
 | 
					  "MessageNoUserPlaylists": "У вас немає списків відтворення",
 | 
				
			||||||
 | 
					  "MessageNoUserPlaylistsHelp": "Списки відтворення приватні. Лише користувач, який їх створює, може бачити їх.",
 | 
				
			||||||
  "MessageNotYetImplemented": "Ще не реалізовано",
 | 
					  "MessageNotYetImplemented": "Ще не реалізовано",
 | 
				
			||||||
  "MessageOpmlPreviewNote": "Примітка: це попередній перегляд OPML-файлу. Актуальна назва подкасту буде завантажена з RSS-каналу.",
 | 
					  "MessageOpmlPreviewNote": "Примітка: це попередній перегляд OPML-файлу. Актуальна назва подкасту буде завантажена з RSS-каналу.",
 | 
				
			||||||
  "MessageOr": "або",
 | 
					  "MessageOr": "або",
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,8 @@
 | 
				
			|||||||
  "ButtonApplyChapters": "应用到章节",
 | 
					  "ButtonApplyChapters": "应用到章节",
 | 
				
			||||||
  "ButtonAuthors": "作者",
 | 
					  "ButtonAuthors": "作者",
 | 
				
			||||||
  "ButtonBack": "返回",
 | 
					  "ButtonBack": "返回",
 | 
				
			||||||
 | 
					  "ButtonBatchEditPopulateFromExisting": "用现有内容填充",
 | 
				
			||||||
 | 
					  "ButtonBatchEditPopulateMapDetails": "填充地图详细信息",
 | 
				
			||||||
  "ButtonBrowseForFolder": "浏览文件夹",
 | 
					  "ButtonBrowseForFolder": "浏览文件夹",
 | 
				
			||||||
  "ButtonCancel": "取消",
 | 
					  "ButtonCancel": "取消",
 | 
				
			||||||
  "ButtonCancelEncode": "取消编码",
 | 
					  "ButtonCancelEncode": "取消编码",
 | 
				
			||||||
@ -432,7 +434,7 @@
 | 
				
			|||||||
  "LabelMetadataProvider": "元数据提供商",
 | 
					  "LabelMetadataProvider": "元数据提供商",
 | 
				
			||||||
  "LabelMinute": "分钟",
 | 
					  "LabelMinute": "分钟",
 | 
				
			||||||
  "LabelMinutes": "分钟",
 | 
					  "LabelMinutes": "分钟",
 | 
				
			||||||
  "LabelMissing": "丢失",
 | 
					  "LabelMissing": "丢失的",
 | 
				
			||||||
  "LabelMissingEbook": "没有电子书",
 | 
					  "LabelMissingEbook": "没有电子书",
 | 
				
			||||||
  "LabelMissingSupplementaryEbook": "没有补充电子书",
 | 
					  "LabelMissingSupplementaryEbook": "没有补充电子书",
 | 
				
			||||||
  "LabelMobileRedirectURIs": "允许移动应用重定向 URI",
 | 
					  "LabelMobileRedirectURIs": "允许移动应用重定向 URI",
 | 
				
			||||||
@ -484,6 +486,7 @@
 | 
				
			|||||||
  "LabelPersonalYearReview": "你的年度回顾 ({0})",
 | 
					  "LabelPersonalYearReview": "你的年度回顾 ({0})",
 | 
				
			||||||
  "LabelPhotoPathURL": "图片路径或 URL",
 | 
					  "LabelPhotoPathURL": "图片路径或 URL",
 | 
				
			||||||
  "LabelPlayMethod": "播放方法",
 | 
					  "LabelPlayMethod": "播放方法",
 | 
				
			||||||
 | 
					  "LabelPlaybackRateIncrementDecrement": "播放速率增加/减少量",
 | 
				
			||||||
  "LabelPlayerChapterNumberMarker": "{0} 于 {1}",
 | 
					  "LabelPlayerChapterNumberMarker": "{0} 于 {1}",
 | 
				
			||||||
  "LabelPlaylists": "播放列表",
 | 
					  "LabelPlaylists": "播放列表",
 | 
				
			||||||
  "LabelPodcast": "播客",
 | 
					  "LabelPodcast": "播客",
 | 
				
			||||||
@ -704,8 +707,11 @@
 | 
				
			|||||||
  "MessageBackupsLocationEditNote": "注意: 更新备份位置不会移动或修改现有备份",
 | 
					  "MessageBackupsLocationEditNote": "注意: 更新备份位置不会移动或修改现有备份",
 | 
				
			||||||
  "MessageBackupsLocationNoEditNote": "注意: 备份位置是通过环境变量设置的, 不能在此处更改.",
 | 
					  "MessageBackupsLocationNoEditNote": "注意: 备份位置是通过环境变量设置的, 不能在此处更改.",
 | 
				
			||||||
  "MessageBackupsLocationPathEmpty": "备份位置路径不能为空",
 | 
					  "MessageBackupsLocationPathEmpty": "备份位置路径不能为空",
 | 
				
			||||||
 | 
					  "MessageBatchEditPopulateMapDetailsAllHelp": "使用所有项目的数据填充已启用的字段. 具有多个值的字段将被合并",
 | 
				
			||||||
 | 
					  "MessageBatchEditPopulateMapDetailsItemHelp": "使用此项目的数据填充已启用的地图详细信息字段",
 | 
				
			||||||
  "MessageBatchQuickMatchDescription": "快速匹配将尝试为所选项目添加缺少的封面和元数据. 启用以下选项以允许快速匹配覆盖现有封面和或元数据.",
 | 
					  "MessageBatchQuickMatchDescription": "快速匹配将尝试为所选项目添加缺少的封面和元数据. 启用以下选项以允许快速匹配覆盖现有封面和或元数据.",
 | 
				
			||||||
  "MessageBookshelfNoCollections": "你尚未进行任何收藏",
 | 
					  "MessageBookshelfNoCollections": "你尚未进行任何收藏",
 | 
				
			||||||
 | 
					  "MessageBookshelfNoCollectionsHelp": "收藏是公开的. 所有有权访问图书馆的用户都可以看到它们.",
 | 
				
			||||||
  "MessageBookshelfNoRSSFeeds": "没有打开的 RSS 源",
 | 
					  "MessageBookshelfNoRSSFeeds": "没有打开的 RSS 源",
 | 
				
			||||||
  "MessageBookshelfNoResultsForFilter": "过滤器无结果 \"{0}: {1}\"",
 | 
					  "MessageBookshelfNoResultsForFilter": "过滤器无结果 \"{0}: {1}\"",
 | 
				
			||||||
  "MessageBookshelfNoResultsForQuery": "没有可查询的结果",
 | 
					  "MessageBookshelfNoResultsForQuery": "没有可查询的结果",
 | 
				
			||||||
@ -816,6 +822,7 @@
 | 
				
			|||||||
  "MessageNoTasksRunning": "没有正在运行的任务",
 | 
					  "MessageNoTasksRunning": "没有正在运行的任务",
 | 
				
			||||||
  "MessageNoUpdatesWereNecessary": "无需更新",
 | 
					  "MessageNoUpdatesWereNecessary": "无需更新",
 | 
				
			||||||
  "MessageNoUserPlaylists": "你没有播放列表",
 | 
					  "MessageNoUserPlaylists": "你没有播放列表",
 | 
				
			||||||
 | 
					  "MessageNoUserPlaylistsHelp": "播放列表是私密的. 只有创建播放列表的用户才能看到.",
 | 
				
			||||||
  "MessageNotYetImplemented": "尚未实施",
 | 
					  "MessageNotYetImplemented": "尚未实施",
 | 
				
			||||||
  "MessageOpmlPreviewNote": "注意: 这是解析的OPML文件的预览. 实际的播客标题将从 RSS 提要中获取.",
 | 
					  "MessageOpmlPreviewNote": "注意: 这是解析的OPML文件的预览. 实际的播客标题将从 RSS 提要中获取.",
 | 
				
			||||||
  "MessageOr": "或",
 | 
					  "MessageOr": "或",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -1,12 +1,12 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "audiobookshelf",
 | 
					  "name": "audiobookshelf",
 | 
				
			||||||
  "version": "2.18.1",
 | 
					  "version": "2.19.0",
 | 
				
			||||||
  "lockfileVersion": 3,
 | 
					  "lockfileVersion": 3,
 | 
				
			||||||
  "requires": true,
 | 
					  "requires": true,
 | 
				
			||||||
  "packages": {
 | 
					  "packages": {
 | 
				
			||||||
    "": {
 | 
					    "": {
 | 
				
			||||||
      "name": "audiobookshelf",
 | 
					      "name": "audiobookshelf",
 | 
				
			||||||
      "version": "2.18.1",
 | 
					      "version": "2.19.0",
 | 
				
			||||||
      "license": "GPL-3.0",
 | 
					      "license": "GPL-3.0",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "axios": "^0.27.2",
 | 
					        "axios": "^0.27.2",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "audiobookshelf",
 | 
					  "name": "audiobookshelf",
 | 
				
			||||||
  "version": "2.18.1",
 | 
					  "version": "2.19.0",
 | 
				
			||||||
  "buildNumber": 1,
 | 
					  "buildNumber": 1,
 | 
				
			||||||
  "description": "Self-hosted audiobook and podcast server",
 | 
					  "description": "Self-hosted audiobook and podcast server",
 | 
				
			||||||
  "main": "index.js",
 | 
					  "main": "index.js",
 | 
				
			||||||
 | 
				
			|||||||
@ -286,7 +286,7 @@ class Book extends Model {
 | 
				
			|||||||
      const track = structuredClone(af)
 | 
					      const track = structuredClone(af)
 | 
				
			||||||
      track.title = af.metadata.filename
 | 
					      track.title = af.metadata.filename
 | 
				
			||||||
      track.startOffset = startOffset
 | 
					      track.startOffset = startOffset
 | 
				
			||||||
      track.contentUrl = `${global.RouterBasePath}/api/items/${libraryItemId}/file/${track.ino}`
 | 
					      track.contentUrl = `/api/items/${libraryItemId}/file/${track.ino}`
 | 
				
			||||||
      startOffset += track.duration
 | 
					      startOffset += track.duration
 | 
				
			||||||
      return track
 | 
					      return track
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@ -365,7 +365,7 @@ class Book extends Model {
 | 
				
			|||||||
    if (payload.metadata) {
 | 
					    if (payload.metadata) {
 | 
				
			||||||
      const metadataStringKeys = ['title', 'subtitle', 'publishedYear', 'publishedDate', 'publisher', 'description', 'isbn', 'asin', 'language']
 | 
					      const metadataStringKeys = ['title', 'subtitle', 'publishedYear', 'publishedDate', 'publisher', 'description', 'isbn', 'asin', 'language']
 | 
				
			||||||
      metadataStringKeys.forEach((key) => {
 | 
					      metadataStringKeys.forEach((key) => {
 | 
				
			||||||
        if (typeof payload.metadata[key] === 'string' && this[key] !== payload.metadata[key]) {
 | 
					        if ((typeof payload.metadata[key] === 'string' || payload.metadata[key] === null) && this[key] !== payload.metadata[key]) {
 | 
				
			||||||
          this[key] = payload.metadata[key] || null
 | 
					          this[key] = payload.metadata[key] || null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (key === 'title') {
 | 
					          if (key === 'title') {
 | 
				
			||||||
 | 
				
			|||||||
@ -202,8 +202,9 @@ class Podcast extends Model {
 | 
				
			|||||||
        } else if (key === 'itunesPageUrl') {
 | 
					        } else if (key === 'itunesPageUrl') {
 | 
				
			||||||
          newKey = 'itunesPageURL'
 | 
					          newKey = 'itunesPageURL'
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (typeof payload.metadata[key] === 'string' && payload.metadata[key] !== this[newKey]) {
 | 
					        if ((typeof payload.metadata[key] === 'string' || payload.metadata[key] === null) && payload.metadata[key] !== this[newKey]) {
 | 
				
			||||||
          this[newKey] = payload.metadata[key]
 | 
					          this[newKey] = payload.metadata[key] || null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (key === 'title') {
 | 
					          if (key === 'title') {
 | 
				
			||||||
            this.titleIgnorePrefix = getTitleIgnorePrefix(this.title)
 | 
					            this.titleIgnorePrefix = getTitleIgnorePrefix(this.title)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
				
			|||||||
@ -169,7 +169,7 @@ class PodcastEpisode extends Model {
 | 
				
			|||||||
    const track = structuredClone(this.audioFile)
 | 
					    const track = structuredClone(this.audioFile)
 | 
				
			||||||
    track.startOffset = 0
 | 
					    track.startOffset = 0
 | 
				
			||||||
    track.title = this.audioFile.metadata.filename
 | 
					    track.title = this.audioFile.metadata.filename
 | 
				
			||||||
    track.contentUrl = `${global.RouterBasePath}/api/items/${libraryItemId}/file/${track.ino}`
 | 
					    track.contentUrl = `/api/items/${libraryItemId}/file/${track.ino}`
 | 
				
			||||||
    return track
 | 
					    return track
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,7 @@ class AudioTrack {
 | 
				
			|||||||
    this.duration = audioFile.duration
 | 
					    this.duration = audioFile.duration
 | 
				
			||||||
    this.title = audioFile.metadata.filename || ''
 | 
					    this.title = audioFile.metadata.filename || ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.contentUrl = `${global.RouterBasePath}/api/items/${itemId}/file/${audioFile.ino}`
 | 
					    this.contentUrl = `/api/items/${itemId}/file/${audioFile.ino}`
 | 
				
			||||||
    this.mimeType = audioFile.mimeType
 | 
					    this.mimeType = audioFile.mimeType
 | 
				
			||||||
    this.codec = audioFile.codec || null
 | 
					    this.codec = audioFile.codec || null
 | 
				
			||||||
    this.metadata = audioFile.metadata.clone()
 | 
					    this.metadata = audioFile.metadata.clone()
 | 
				
			||||||
@ -44,4 +44,4 @@ class AudioTrack {
 | 
				
			|||||||
    this.mimeType = 'application/vnd.apple.mpegurl'
 | 
					    this.mimeType = 'application/vnd.apple.mpegurl'
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
module.exports = AudioTrack
 | 
					module.exports = AudioTrack
 | 
				
			||||||
 | 
				
			|||||||
@ -286,10 +286,23 @@ module.exports.downloadFile = (url, filepath, contentTypeFilter = null) => {
 | 
				
			|||||||
          return reject(new Error(`Invalid content type "${response.headers?.['content-type'] || ''}"`))
 | 
					          return reject(new Error(`Invalid content type "${response.headers?.['content-type'] || ''}"`))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const totalSize = parseInt(response.headers['content-length'], 10)
 | 
				
			||||||
 | 
					        let downloadedSize = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Write to filepath
 | 
					        // Write to filepath
 | 
				
			||||||
        const writer = fs.createWriteStream(filepath)
 | 
					        const writer = fs.createWriteStream(filepath)
 | 
				
			||||||
        response.data.pipe(writer)
 | 
					        response.data.pipe(writer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let lastProgress = 0
 | 
				
			||||||
 | 
					        response.data.on('data', (chunk) => {
 | 
				
			||||||
 | 
					          downloadedSize += chunk.length
 | 
				
			||||||
 | 
					          const progress = totalSize ? Math.round((downloadedSize / totalSize) * 100) : 0
 | 
				
			||||||
 | 
					          if (progress >= lastProgress + 5) {
 | 
				
			||||||
 | 
					            Logger.debug(`[fileUtils] File "${Path.basename(filepath)}" download progress: ${progress}% (${downloadedSize}/${totalSize} bytes)`)
 | 
				
			||||||
 | 
					            lastProgress = progress
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        writer.on('finish', resolve)
 | 
					        writer.on('finish', resolve)
 | 
				
			||||||
        writer.on('error', reject)
 | 
					        writer.on('error', reject)
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
				
			|||||||
@ -35,11 +35,18 @@ module.exports.nameToLastFirst = (firstLast) => {
 | 
				
			|||||||
  return `${nameObj.last_name}, ${nameObj.first_name}`
 | 
					  return `${nameObj.last_name}, ${nameObj.first_name}`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Handle any name string
 | 
					/**
 | 
				
			||||||
 | 
					 * Parses a name string into an array of names
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {string} nameString - The name string to parse
 | 
				
			||||||
 | 
					 * @returns {{ names: string[] }} Array of names
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
module.exports.parse = (nameString) => {
 | 
					module.exports.parse = (nameString) => {
 | 
				
			||||||
  if (!nameString) return null
 | 
					  if (!nameString) return null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var splitNames = []
 | 
					  let splitNames = []
 | 
				
			||||||
 | 
					  const isCommaSeparated = nameString.includes(',')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Example &LF: Friedman, Milton & Friedman, Rose
 | 
					  // Example &LF: Friedman, Milton & Friedman, Rose
 | 
				
			||||||
  if (nameString.includes('&')) {
 | 
					  if (nameString.includes('&')) {
 | 
				
			||||||
    nameString.split('&').forEach((asa) => (splitNames = splitNames.concat(asa.split(','))))
 | 
					    nameString.split('&').forEach((asa) => (splitNames = splitNames.concat(asa.split(','))))
 | 
				
			||||||
@ -59,17 +66,18 @@ module.exports.parse = (nameString) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var names = []
 | 
					  let names = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 1 name FIRST LAST
 | 
					  // 1 name FIRST LAST
 | 
				
			||||||
  if (splitNames.length === 1) {
 | 
					  if (splitNames.length === 1) {
 | 
				
			||||||
    names.push(parseName(nameString))
 | 
					    names.push(parseName(nameString))
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    var firstChunkIsALastName = checkIsALastName(splitNames[0])
 | 
					    // Determines whether this is formatted as last, first or first last (only if using comma separator)
 | 
				
			||||||
    var isEvenNum = splitNames.length % 2 === 0
 | 
					    // Example: "Smith; James Jones" -> ["Smith", "James Jones"]
 | 
				
			||||||
 | 
					    let firstChunkIsALastName = !isCommaSeparated ? false : checkIsALastName(splitNames[0])
 | 
				
			||||||
 | 
					    let isEvenNum = splitNames.length % 2 === 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!isEvenNum && firstChunkIsALastName) {
 | 
					    if (!isEvenNum && firstChunkIsALastName) {
 | 
				
			||||||
      // console.error('Multi-name LAST,FIRST entry has a straggler (could be roman numerals or a suffix), ignore it')
 | 
					 | 
				
			||||||
      splitNames = splitNames.slice(0, splitNames.length - 1)
 | 
					      splitNames = splitNames.slice(0, splitNames.length - 1)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										99
									
								
								test/server/utils/parsers/parseNameString.test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								test/server/utils/parsers/parseNameString.test.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					const chai = require('chai')
 | 
				
			||||||
 | 
					const expect = chai.expect
 | 
				
			||||||
 | 
					const { parse, nameToLastFirst } = require('../../../../server/utils/parsers/parseNameString')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('parseNameString', () => {
 | 
				
			||||||
 | 
					  describe('parse', () => {
 | 
				
			||||||
 | 
					    it('returns null if nameString is empty', () => {
 | 
				
			||||||
 | 
					      const result = parse('')
 | 
				
			||||||
 | 
					      expect(result).to.be.null
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('parses single name in First Last format', () => {
 | 
				
			||||||
 | 
					      const result = parse('John Smith')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Smith'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('parses single name in Last, First format', () => {
 | 
				
			||||||
 | 
					      const result = parse('Smith, John')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Smith'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('parses multiple names separated by &', () => {
 | 
				
			||||||
 | 
					      const result = parse('John Smith & Jane Doe')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('parses multiple names separated by "and"', () => {
 | 
				
			||||||
 | 
					      const result = parse('John Smith and Jane Doe')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('parses multiple names separated by comma and "and"', () => {
 | 
				
			||||||
 | 
					      const result = parse('John Smith, Jane Doe and John Doe')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Smith', 'Jane Doe', 'John Doe'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('parses multiple names separated by semicolon', () => {
 | 
				
			||||||
 | 
					      const result = parse('John Smith; Jane Doe')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('parses multiple names in Last, First format', () => {
 | 
				
			||||||
 | 
					      const result = parse('Smith, John, Doe, Jane')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Smith', 'Jane Doe'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('parses multiple names with single word name', () => {
 | 
				
			||||||
 | 
					      const result = parse('John Smith, Jones, James Doe, Ludwig von Mises')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Smith', 'Jones', 'James Doe', 'Ludwig von Mises'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('parses multiple names with single word name listed first (semicolon separator)', () => {
 | 
				
			||||||
 | 
					      const result = parse('Jones; John Smith; James Doe; Ludwig von Mises')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['Jones', 'John Smith', 'James Doe', 'Ludwig von Mises'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('handles names with suffixes', () => {
 | 
				
			||||||
 | 
					      const result = parse('Smith, John Jr.')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Jr. Smith'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('handles compound last names', () => {
 | 
				
			||||||
 | 
					      const result = parse('von Mises, Ludwig')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['Ludwig von Mises'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('handles Chinese/Japanese/Korean names', () => {
 | 
				
			||||||
 | 
					      const result = parse('张三, 李四')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['张三', '李四'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('removes duplicate names', () => {
 | 
				
			||||||
 | 
					      const result = parse('John Smith & John Smith')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Smith'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('filters out empty names', () => {
 | 
				
			||||||
 | 
					      const result = parse('John Smith,')
 | 
				
			||||||
 | 
					      expect(result.names).to.deep.equal(['John Smith'])
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('nameToLastFirst', () => {
 | 
				
			||||||
 | 
					    it('converts First Last to Last, First format', () => {
 | 
				
			||||||
 | 
					      const result = nameToLastFirst('John Smith')
 | 
				
			||||||
 | 
					      expect(result).to.equal('Smith, John')
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('returns last name only when no first name', () => {
 | 
				
			||||||
 | 
					      const result = nameToLastFirst('Smith')
 | 
				
			||||||
 | 
					      expect(result).to.equal('Smith')
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('handles names with middle names', () => {
 | 
				
			||||||
 | 
					      const result = nameToLastFirst('John Middle Smith')
 | 
				
			||||||
 | 
					      expect(result).to.equal('Smith, John Middle')
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user