mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-06-20 20:05:44 +02:00
Add:Player setting to scale elapsed time by playback speed #1028
- Moved player settings to new playerSettings key in storage preferences
This commit is contained in:
parent
5e7d039454
commit
3fe943e989
20 changed files with 118 additions and 82 deletions
|
@ -15,7 +15,7 @@
|
|||
<p class="top-4 absolute left-0 right-0 mx-auto text-center uppercase tracking-widest text-opacity-75" :class="{ 'text-black text-opacity-75': coverBgIsLight }" style="font-size: 10px">{{ isDirectPlayMethod ? $strings.LabelPlaybackDirect : isLocalPlayMethod ? $strings.LabelPlaybackLocal : $strings.LabelPlaybackTranscode }}</p>
|
||||
</div>
|
||||
|
||||
<div v-if="useChapterTrack && useTotalTrack && showFullscreen" class="absolute total-track w-full z-30 px-6">
|
||||
<div v-if="playerSettings.useChapterTrack && playerSettings.useTotalTrack && showFullscreen" class="absolute total-track w-full z-30 px-6">
|
||||
<div class="flex">
|
||||
<p class="font-mono text-fg" style="font-size: 0.8rem">{{ currentTimePretty }}</p>
|
||||
<div class="flex-grow" />
|
||||
|
@ -66,17 +66,17 @@
|
|||
<div v-else class="w-full h-full absolute top-0 left-0 pointer-events-none" style="background: var(--gradient-minimized-audio-player)" />
|
||||
|
||||
<div id="playerControls" class="absolute right-0 bottom-0 mx-auto" style="max-width: 414px">
|
||||
<div class="flex items-center max-w-full" :class="lockUi ? 'justify-center' : 'justify-between'">
|
||||
<span v-show="showFullscreen && !lockUi" class="material-icons next-icon text-fg cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpChapterStart">first_page</span>
|
||||
<span v-show="!lockUi" class="material-icons jump-icon text-fg cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpBackwards">{{ jumpBackwardsIcon }}</span>
|
||||
<div class="flex items-center max-w-full" :class="playerSettings.lockUi ? 'justify-center' : 'justify-between'">
|
||||
<span v-show="showFullscreen && !playerSettings.lockUi" class="material-icons next-icon text-fg cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpChapterStart">first_page</span>
|
||||
<span v-show="!playerSettings.lockUi" class="material-icons jump-icon text-fg cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpBackwards">{{ jumpBackwardsIcon }}</span>
|
||||
<div class="play-btn cursor-pointer shadow-sm flex items-center justify-center rounded-full text-primary mx-4 relative overflow-hidden" :style="{ backgroundColor: coverRgb }" :class="{ 'animate-spin': seekLoading }" @mousedown.prevent @mouseup.prevent @click.stop="playPauseClick">
|
||||
<div v-if="!coverBgIsLight" class="absolute top-0 left-0 w-full h-full bg-white bg-opacity-20 pointer-events-none" />
|
||||
|
||||
<span v-if="!isLoading" class="material-icons" :class="{ 'text-white': coverRgb && !coverBgIsLight }">{{ seekLoading ? 'autorenew' : !isPlaying ? 'play_arrow' : 'pause' }}</span>
|
||||
<widgets-spinner-icon v-else class="h-8 w-8" />
|
||||
</div>
|
||||
<span v-show="!lockUi" class="material-icons jump-icon text-fg cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpForward">{{ jumpForwardIcon }}</span>
|
||||
<span v-show="showFullscreen && !lockUi" class="material-icons next-icon text-fg cursor-pointer" :class="nextChapter && !isLoading ? 'text-opacity-75' : 'text-opacity-10'" @click.stop="jumpNextChapter">last_page</span>
|
||||
<span v-show="!playerSettings.lockUi" class="material-icons jump-icon text-fg cursor-pointer" :class="isLoading ? 'text-opacity-10' : 'text-opacity-75'" @click.stop="jumpForward">{{ jumpForwardIcon }}</span>
|
||||
<span v-show="showFullscreen && !playerSettings.lockUi" class="material-icons next-icon text-fg cursor-pointer" :class="nextChapter && !isLoading ? 'text-opacity-75' : 'text-opacity-10'" @click.stop="jumpNextChapter">last_page</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -90,7 +90,7 @@
|
|||
<div ref="readyTrack" class="h-full bg-track-buffered absolute top-0 left-0 rounded-full pointer-events-none" />
|
||||
<div ref="bufferedTrack" class="h-full bg-track absolute top-0 left-0 rounded-full pointer-events-none" />
|
||||
<div ref="playedTrack" class="h-full bg-track-cursor absolute top-0 left-0 rounded-full pointer-events-none" />
|
||||
<div ref="trackCursor" class="h-7 w-7 rounded-full absolute pointer-events-auto flex items-center justify-center" :style="{ top: '-11px' }" :class="{ 'opacity-0': lockUi || !showFullscreen }" @touchstart="touchstartCursor">
|
||||
<div ref="trackCursor" class="h-7 w-7 rounded-full absolute pointer-events-auto flex items-center justify-center" :style="{ top: '-11px' }" :class="{ 'opacity-0': playerSettings.lockUi || !showFullscreen }" @touchstart="touchstartCursor">
|
||||
<div class="bg-track-cursor rounded-full w-3.5 h-3.5 pointer-events-none" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -98,7 +98,7 @@
|
|||
</div>
|
||||
|
||||
<modals-chapters-modal v-model="showChapterModal" :current-chapter="currentChapter" :chapters="chapters" :playback-rate="currentPlaybackRate" @select="selectChapter" />
|
||||
<modals-dialog v-model="showMoreMenuDialog" :items="menuItems" @action="clickMenuAction" />
|
||||
<modals-dialog v-model="showMoreMenuDialog" :items="menuItems" width="80vw" @action="clickMenuAction" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -146,9 +146,12 @@ export default {
|
|||
touchStartY: 0,
|
||||
touchStartTime: 0,
|
||||
touchEndY: 0,
|
||||
useChapterTrack: false,
|
||||
useTotalTrack: true,
|
||||
lockUi: false,
|
||||
playerSettings: {
|
||||
useChapterTrack: false,
|
||||
useTotalTrack: true,
|
||||
scaleElapsedTimeBySpeed: true,
|
||||
lockUi: false
|
||||
},
|
||||
isLoading: false,
|
||||
isDraggingCursor: false,
|
||||
draggingTouchStartX: 0,
|
||||
|
@ -164,7 +167,7 @@ export default {
|
|||
showFullscreen(val) {
|
||||
this.updateScreenSize()
|
||||
this.$store.commit('setPlayerFullscreen', !!val)
|
||||
document.querySelector('body').style.backgroundColor = this.showFullscreen ? this.coverRgb : ""
|
||||
document.querySelector('body').style.backgroundColor = this.showFullscreen ? this.coverRgb : ''
|
||||
},
|
||||
bookCoverAspectRatio() {
|
||||
this.updateScreenSize()
|
||||
|
@ -187,17 +190,22 @@ export default {
|
|||
{
|
||||
text: this.$strings.LabelTotalTrack,
|
||||
value: 'total_track',
|
||||
icon: this.useTotalTrack ? 'check_box' : 'check_box_outline_blank'
|
||||
icon: this.playerSettings.useTotalTrack ? 'check_box' : 'check_box_outline_blank'
|
||||
},
|
||||
{
|
||||
text: this.$strings.LabelChapterTrack,
|
||||
value: 'chapter_track',
|
||||
icon: this.useChapterTrack ? 'check_box' : 'check_box_outline_blank'
|
||||
icon: this.playerSettings.useChapterTrack ? 'check_box' : 'check_box_outline_blank'
|
||||
},
|
||||
{
|
||||
text: this.lockUi ? this.$strings.LabelUnlockPlayer : this.$strings.LabelLockPlayer,
|
||||
text: this.$strings.LabelScaleElapsedTimeBySpeed,
|
||||
value: 'scale_elapsed_time',
|
||||
icon: this.playerSettings.scaleElapsedTimeBySpeed ? 'check_box' : 'check_box_outline_blank'
|
||||
},
|
||||
{
|
||||
text: this.playerSettings.lockUi ? this.$strings.LabelUnlockPlayer : this.$strings.LabelLockPlayer,
|
||||
value: 'lock',
|
||||
icon: this.lockUi ? 'lock' : 'lock_open'
|
||||
icon: this.playerSettings.lockUi ? 'lock' : 'lock_open'
|
||||
},
|
||||
{
|
||||
text: this.$strings.LabelClosePlayer,
|
||||
|
@ -322,11 +330,14 @@ export default {
|
|||
},
|
||||
currentTimePretty() {
|
||||
let currentTimeToUse = this.isDraggingCursor ? this.draggingCurrentTime : this.currentTime
|
||||
return this.$secondsToTimestamp(currentTimeToUse / this.currentPlaybackRate)
|
||||
if (this.playerSettings.scaleElapsedTimeBySpeed) {
|
||||
currentTimeToUse = currentTimeToUse / this.currentPlaybackRate
|
||||
}
|
||||
return this.$secondsToTimestamp(currentTimeToUse)
|
||||
},
|
||||
timeRemaining() {
|
||||
let currentTimeToUse = this.isDraggingCursor ? this.draggingCurrentTime : this.currentTime
|
||||
if (this.useChapterTrack && this.currentChapter) {
|
||||
if (this.playerSettings.useChapterTrack && this.currentChapter) {
|
||||
var currChapTime = currentTimeToUse - this.currentChapter.start
|
||||
return (this.currentChapterDuration - currChapTime) / this.currentPlaybackRate
|
||||
}
|
||||
|
@ -494,7 +505,7 @@ export default {
|
|||
this.updateReadyTrack()
|
||||
},
|
||||
updateReadyTrack() {
|
||||
if (this.useChapterTrack) {
|
||||
if (this.playerSettings.useChapterTrack) {
|
||||
if (this.$refs.totalReadyTrack) {
|
||||
this.$refs.totalReadyTrack.style.width = this.readyTrackWidth + 'px'
|
||||
}
|
||||
|
@ -511,11 +522,14 @@ export default {
|
|||
}
|
||||
|
||||
let currentTime = this.isDraggingCursor ? this.draggingCurrentTime : this.currentTime
|
||||
if (this.useChapterTrack && this.currentChapter) {
|
||||
if (this.playerSettings.useChapterTrack && this.currentChapter) {
|
||||
currentTime = Math.max(0, currentTime - this.currentChapter.start)
|
||||
}
|
||||
if (this.playerSettings.scaleElapsedTimeBySpeed) {
|
||||
currentTime = currentTime / this.currentPlaybackRate
|
||||
}
|
||||
|
||||
ts.innerText = this.$secondsToTimestamp(currentTime / this.currentPlaybackRate)
|
||||
ts.innerText = this.$secondsToTimestamp(currentTime)
|
||||
},
|
||||
timeupdate() {
|
||||
if (!this.$refs.playedTrack) {
|
||||
|
@ -543,7 +557,7 @@ export default {
|
|||
let bufferedPercent = this.bufferedTime / this.totalDuration
|
||||
const totalBufferedPercent = bufferedPercent
|
||||
|
||||
if (this.useChapterTrack && this.currentChapter) {
|
||||
if (this.playerSettings.useChapterTrack && this.currentChapter) {
|
||||
const currChapTime = currentTimeToUse - this.currentChapter.start
|
||||
percentDone = currChapTime / this.currentChapterDuration
|
||||
bufferedPercent = Math.max(0, Math.min(1, (this.bufferedTime - this.currentChapter.start) / this.currentChapterDuration))
|
||||
|
@ -557,7 +571,7 @@ export default {
|
|||
this.$refs.trackCursor.style.left = ptWidth - 14 + 'px'
|
||||
}
|
||||
|
||||
if (this.useChapterTrack) {
|
||||
if (this.playerSettings.useChapterTrack) {
|
||||
if (this.$refs.totalPlayedTrack) this.$refs.totalPlayedTrack.style.width = Math.round(totalPercentDone * this.trackWidth) + 'px'
|
||||
if (this.$refs.totalBufferedTrack) this.$refs.totalBufferedTrack.style.width = Math.round(totalBufferedPercent * this.trackWidth) + 'px'
|
||||
}
|
||||
|
@ -584,7 +598,7 @@ export default {
|
|||
}
|
||||
},
|
||||
async touchstartCursor(e) {
|
||||
if (!e || !e.touches || !this.$refs.track || !this.showFullscreen || this.lockUi) return
|
||||
if (!e || !e.touches || !this.$refs.track || !this.showFullscreen || this.playerSettings.lockUi) return
|
||||
|
||||
await this.$hapticsImpact()
|
||||
this.isDraggingCursor = true
|
||||
|
@ -670,7 +684,7 @@ export default {
|
|||
let duration = this.totalDuration
|
||||
let minTime = 0
|
||||
let maxTime = duration
|
||||
if (this.useChapterTrack && this.currentChapter) {
|
||||
if (this.playerSettings.useChapterTrack && this.currentChapter) {
|
||||
duration = this.currentChapterDuration
|
||||
minTime = this.currentChapter.start
|
||||
maxTime = minTime + duration
|
||||
|
@ -690,37 +704,40 @@ export default {
|
|||
if (action === 'history') {
|
||||
this.$router.push(`/media/${this.mediaId}/history?title=${this.title}`)
|
||||
this.showFullscreen = false
|
||||
} else if (action === 'scale_elapsed_time') {
|
||||
this.playerSettings.scaleElapsedTimeBySpeed = !this.playerSettings.scaleElapsedTimeBySpeed
|
||||
this.updateTimestamp()
|
||||
this.savePlayerSettings()
|
||||
} else if (action === 'lock') {
|
||||
this.lockUi = !this.lockUi
|
||||
this.$localStore.setPlayerLock(this.lockUi)
|
||||
this.playerSettings.lockUi = !this.playerSettings.lockUi
|
||||
this.savePlayerSettings()
|
||||
} else if (action === 'chapter_track') {
|
||||
this.useChapterTrack = !this.useChapterTrack
|
||||
this.useTotalTrack = !this.useChapterTrack || this.useTotalTrack
|
||||
this.playerSettings.useChapterTrack = !this.playerSettings.useChapterTrack
|
||||
this.playerSettings.useTotalTrack = !this.playerSettings.useChapterTrack || this.playerSettings.useTotalTrack
|
||||
|
||||
this.updateTimestamp()
|
||||
this.updateTrack()
|
||||
this.updateReadyTrack()
|
||||
this.updateUseChapterTrack()
|
||||
this.$localStore.setUseTotalTrack(this.useTotalTrack)
|
||||
this.savePlayerSettings()
|
||||
} else if (action === 'total_track') {
|
||||
this.useTotalTrack = !this.useTotalTrack
|
||||
this.useChapterTrack = !this.useTotalTrack || this.useChapterTrack
|
||||
this.playerSettings.useTotalTrack = !this.playerSettings.useTotalTrack
|
||||
this.playerSettings.useChapterTrack = !this.playerSettings.useTotalTrack || this.playerSettings.useChapterTrack
|
||||
|
||||
this.updateTimestamp()
|
||||
this.updateTrack()
|
||||
this.updateReadyTrack()
|
||||
this.updateUseChapterTrack()
|
||||
this.$localStore.setUseTotalTrack(this.useTotalTrack)
|
||||
this.savePlayerSettings()
|
||||
} else if (action === 'close') {
|
||||
this.closePlayback()
|
||||
}
|
||||
})
|
||||
},
|
||||
updateUseChapterTrack() {
|
||||
this.$localStore.setUseChapterTrack(this.useChapterTrack)
|
||||
// Chapter track in NowPlaying only supported on iOS for now
|
||||
if (this.$platform === 'ios') {
|
||||
AbsAudioPlayer.setChapterTrack({ enabled: this.useChapterTrack })
|
||||
AbsAudioPlayer.setChapterTrack({ enabled: this.playerSettings.useChapterTrack })
|
||||
}
|
||||
},
|
||||
forceCloseDropdownMenu() {
|
||||
|
@ -739,6 +756,30 @@ export default {
|
|||
this.isLoading = false
|
||||
this.playbackSession = null
|
||||
},
|
||||
async loadPlayerSettings() {
|
||||
const savedPlayerSettings = await this.$localStore.getPlayerSettings()
|
||||
if (!savedPlayerSettings) {
|
||||
// In 0.9.72-beta 'useChapterTrack', 'useTotalTrack' and 'playerLock' was replaced with 'playerSettings' JSON object
|
||||
// Check if this old key was set and if so migrate them over to 'playerSettings'
|
||||
const chapterTrackPref = await this.$localStore.getPreferenceByKey('useChapterTrack')
|
||||
if (chapterTrackPref) {
|
||||
this.playerSettings.useChapterTrack = chapterTrackPref === '1'
|
||||
const totalTrackPref = await this.$localStore.getPreferenceByKey('useTotalTrack')
|
||||
this.playerSettings.useTotalTrack = totalTrackPref === '1'
|
||||
const playerLockPref = await this.$localStore.getPreferenceByKey('playerLock')
|
||||
this.playerSettings.lockUi = playerLockPref === '1'
|
||||
}
|
||||
this.savePlayerSettings()
|
||||
} else {
|
||||
this.playerSettings.useChapterTrack = !!savedPlayerSettings.useChapterTrack
|
||||
this.playerSettings.useTotalTrack = !!savedPlayerSettings.useTotalTrack
|
||||
this.playerSettings.lockUi = !!savedPlayerSettings.lockUi
|
||||
this.playerSettings.scaleElapsedTimeBySpeed = !!savedPlayerSettings.scaleElapsedTimeBySpeed
|
||||
}
|
||||
},
|
||||
savePlayerSettings() {
|
||||
return this.$localStore.setPlayerSettings({ ...this.playerSettings })
|
||||
},
|
||||
//
|
||||
// Listeners from audio AbsAudioPlayer
|
||||
//
|
||||
|
@ -805,9 +846,7 @@ export default {
|
|||
this.updateTimestamp()
|
||||
},
|
||||
async init() {
|
||||
this.useChapterTrack = await this.$localStore.getUseChapterTrack()
|
||||
this.useTotalTrack = await this.$localStore.getUseTotalTrack()
|
||||
this.lockUi = await this.$localStore.getPlayerLock()
|
||||
await this.loadPlayerSettings()
|
||||
|
||||
this.onPlaybackSessionListener = AbsAudioPlayer.addListener('onPlaybackSession', this.onPlaybackSession)
|
||||
this.onPlaybackClosedListener = AbsAudioPlayer.addListener('onPlaybackClosed', this.onPlaybackClosed)
|
||||
|
|
|
@ -40,7 +40,7 @@ export default {
|
|||
default: '16px'
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
type: [String, Number],
|
||||
default: 300
|
||||
}
|
||||
},
|
||||
|
|
|
@ -42,56 +42,20 @@ class LocalStorage {
|
|||
}
|
||||
}
|
||||
|
||||
async setUseChapterTrack(useChapterTrack) {
|
||||
async setPlayerSettings(playerSettings) {
|
||||
try {
|
||||
await Preferences.set({ key: 'useChapterTrack', value: useChapterTrack ? '1' : '0' })
|
||||
await Preferences.set({ key: 'playerSettings', value: JSON.stringify(playerSettings) })
|
||||
} catch (error) {
|
||||
console.error('[LocalStorage] Failed to set use chapter track', error)
|
||||
console.error('[LocalStorage] Failed to set player settings', error)
|
||||
}
|
||||
}
|
||||
|
||||
async getUseChapterTrack() {
|
||||
async getPlayerSettings() {
|
||||
try {
|
||||
var obj = await Preferences.get({ key: 'useChapterTrack' }) || {}
|
||||
return obj.value === '1'
|
||||
const playerSettingsObj = await Preferences.get({ key: 'playerSettings' }) || {}
|
||||
return playerSettingsObj.value ? JSON.parse(playerSettingsObj.value) : null
|
||||
} catch (error) {
|
||||
console.error('[LocalStorage] Failed to get use chapter track', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async setUseTotalTrack(useTotalTrack) {
|
||||
try {
|
||||
await Preferences.set({ key: 'useTotalTrack', value: useTotalTrack ? '1' : '0' })
|
||||
} catch (error) {
|
||||
console.error('[LocalStorage] Failed to set use total track', error)
|
||||
}
|
||||
}
|
||||
|
||||
async getUseTotalTrack() {
|
||||
try {
|
||||
var obj = await Preferences.get({ key: 'useTotalTrack' }) || {}
|
||||
return obj.value === '1'
|
||||
} catch (error) {
|
||||
console.error('[LocalStorage] Failed to get use total track', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async setPlayerLock(lock) {
|
||||
try {
|
||||
await Preferences.set({ key: 'playerLock', value: lock ? '1' : '0' })
|
||||
} catch (error) {
|
||||
console.error('[LocalStorage] Failed to set player lock', error)
|
||||
}
|
||||
}
|
||||
|
||||
async getPlayerLock() {
|
||||
try {
|
||||
var obj = await Preferences.get({ key: 'playerLock' }) || {}
|
||||
return obj.value === '1'
|
||||
} catch (error) {
|
||||
console.error('[LocalStorage] Failed to get player lock', error)
|
||||
console.error('[LocalStorage] Failed to get player settings', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +143,22 @@ class LocalStorage {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get preference value by key
|
||||
*
|
||||
* @param {string} key
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async getPreferenceByKey(key) {
|
||||
try {
|
||||
const obj = await Preferences.get({ key }) || {}
|
||||
return obj.value || null
|
||||
} catch (error) {
|
||||
console.error(`[LocalStorage] Failed to get preference "${key}"`, error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Vlastní jméno vlastníka",
|
||||
"LabelRSSFeedPreventIndexing": "Zabránit indexování",
|
||||
"LabelRSSFeedSlug": "RSS kanál Slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Sezóna",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Série",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Brugerdefineret ejerens navn",
|
||||
"LabelRSSFeedPreventIndexing": "Forhindrer indeksering",
|
||||
"LabelRSSFeedSlug": "RSS-feed-slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Sæson",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Serie",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Benutzerdefinierter Name des Eigentümers",
|
||||
"LabelRSSFeedPreventIndexing": "Indizierung verhindern",
|
||||
"LabelRSSFeedSlug": "RSS Feed Schlagwort",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Staffel",
|
||||
"LabelSelectADevice": "Wähle ein Gerät",
|
||||
"LabelSeries": "Serien",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Custom owner Name",
|
||||
"LabelRSSFeedPreventIndexing": "Prevent Indexing",
|
||||
"LabelRSSFeedSlug": "RSS Feed Slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Season",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Series",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Nombre de dueño personalizado",
|
||||
"LabelRSSFeedPreventIndexing": "Prevenir Indexado",
|
||||
"LabelRSSFeedSlug": "Fuente RSS Slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Temporada",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Series",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Nom propriétaire personnalisé",
|
||||
"LabelRSSFeedPreventIndexing": "Empêcher l’indexation",
|
||||
"LabelRSSFeedSlug": "Identificateur d’adresse du Flux RSS ",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Saison",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Séries",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Custom owner Name",
|
||||
"LabelRSSFeedPreventIndexing": "Prevent Indexing",
|
||||
"LabelRSSFeedSlug": "RSS Feed Slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Season",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Series",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Custom owner Name",
|
||||
"LabelRSSFeedPreventIndexing": "Prevent Indexing",
|
||||
"LabelRSSFeedSlug": "RSS Feed Slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Season",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Series",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Custom owner Name",
|
||||
"LabelRSSFeedPreventIndexing": "Prevent Indexing",
|
||||
"LabelRSSFeedSlug": "RSS Feed Slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Sezona",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Serije",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Nome del proprietario personalizzato",
|
||||
"LabelRSSFeedPreventIndexing": "Impedisci l'indicizzazione",
|
||||
"LabelRSSFeedSlug": "RSS Feed Slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Stagione",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Serie",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Pasirinktinis savininko vardas",
|
||||
"LabelRSSFeedPreventIndexing": "Neleisti indeksuoti",
|
||||
"LabelRSSFeedSlug": "RSS srauto identifikatorius",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Sezonas",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Serija",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Aangepaste naam eigenaar",
|
||||
"LabelRSSFeedPreventIndexing": "Voorkom indexering",
|
||||
"LabelRSSFeedSlug": "RSS-feed slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Seizoen",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Serie",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Tilpasset eier Navn",
|
||||
"LabelRSSFeedPreventIndexing": "Forhindre indeksering",
|
||||
"LabelRSSFeedSlug": "RSS Feed Slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Sesong",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Serier",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Custom owner Name",
|
||||
"LabelRSSFeedPreventIndexing": "Prevent Indexing",
|
||||
"LabelRSSFeedSlug": "RSS Feed Slug",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Sezon",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Serie",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Пользовательское Имя владельца",
|
||||
"LabelRSSFeedPreventIndexing": "Запретить индексирование",
|
||||
"LabelRSSFeedSlug": "Встроить RSS-канал",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Сезон",
|
||||
"LabelSelectADevice": "Выбор девайса",
|
||||
"LabelSeries": "Серия",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "Anpassat ägarnamn",
|
||||
"LabelRSSFeedPreventIndexing": "Förhindra indexering",
|
||||
"LabelRSSFeedSlug": "RSS-flödesslag",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "Säsong",
|
||||
"LabelSelectADevice": "Select a device",
|
||||
"LabelSeries": "Serie",
|
||||
|
|
|
@ -194,6 +194,7 @@
|
|||
"LabelRSSFeedCustomOwnerName": "自定义所有者名称",
|
||||
"LabelRSSFeedPreventIndexing": "防止索引",
|
||||
"LabelRSSFeedSlug": "RSS 源段",
|
||||
"LabelScaleElapsedTimeBySpeed": "Scale Elapsed Time by Speed",
|
||||
"LabelSeason": "季",
|
||||
"LabelSelectADevice": "选择设备",
|
||||
"LabelSeries": "系列",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue