Merge remote-tracking branch 'upstream/master'

This commit is contained in:
yuuzhan 2023-06-09 15:42:13 -04:00
commit b3f9a40f18
227 changed files with 11338 additions and 3382 deletions

View file

@ -9,10 +9,17 @@
</div>
<div v-if="enableBackups" class="mb-6">
<div class="flex items-center pl-6">
<span class="material-icons-outlined text-2xl text-black-50">schedule</span>
<p class="text-gray-100 px-2">{{ scheduleDescription }}</p>
<span class="material-icons text-lg text-black-50 hover:text-yellow-500 cursor-pointer" @click="showCronBuilder = !showCronBuilder">edit</span>
<div class="flex items-center pl-6 mb-2">
<span class="material-icons-outlined text-2xl text-black-50 mr-2">schedule</span>
<div class="w-48"><span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.HeaderSchedule }}:</span></div>
<div class="text-gray-100">{{ scheduleDescription }}</div>
<span class="material-icons text-lg text-black-50 hover:text-yellow-500 cursor-pointer ml-2" @click="showCronBuilder = !showCronBuilder">edit</span>
</div>
<div v-if="nextBackupDate" class="flex items-center pl-6 py-0.5 px-2">
<span class="material-icons-outlined text-2xl text-black-50 mr-2">event</span>
<div class="w-48"><span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelNextBackupDate }}:</span></div>
<div class="text-gray-100">{{ nextBackupDate }}</div>
</div>
</div>
@ -64,10 +71,21 @@ export default {
serverSettings() {
return this.$store.state.serverSettings
},
dateFormat() {
return this.serverSettings.dateFormat
},
timeFormat() {
return this.serverSettings.timeFormat
},
scheduleDescription() {
if (!this.cronExpression) return ''
const parsed = this.$parseCronExpression(this.cronExpression)
return parsed ? parsed.description : 'Custom cron expression ' + this.cronExpression
return parsed ? parsed.description : `${this.$strings.LabelCustomCronExpression} ${this.cronExpression}`
},
nextBackupDate() {
if (!this.cronExpression) return ''
const parsed = this.$getNextScheduledDate(this.cronExpression)
return this.$formatJsDatetime(parsed, this.dateFormat, this.timeFormat) || ''
}
},
methods: {
@ -90,15 +108,15 @@ export default {
updateServerSettings(payload) {
this.updatingServerSettings = true
this.$store
.dispatch('updateServerSettings', payload)
.then((success) => {
console.log('Updated Server Settings', success)
this.updatingServerSettings = false
})
.catch((error) => {
console.error('Failed to update server settings', error)
this.updatingServerSettings = false
})
.dispatch('updateServerSettings', payload)
.then((success) => {
console.log('Updated Server Settings', success)
this.updatingServerSettings = false
})
.catch((error) => {
console.error('Failed to update server settings', error)
this.updatingServerSettings = false
})
},
initServerSettings() {
this.newServerSettings = this.serverSettings ? { ...this.serverSettings } : {}
@ -113,4 +131,4 @@ export default {
this.initServerSettings()
}
}
</script>
</script>

View file

@ -0,0 +1,244 @@
<template>
<div>
<app-settings-content :header-text="$strings.HeaderEmailSettings" :description="''">
<form @submit.prevent="submitForm">
<div class="flex items-center -mx-1 mb-2">
<div class="w-full md:w-3/4 px-1">
<ui-text-input-with-label ref="hostInput" v-model="newSettings.host" :disabled="savingSettings" :label="$strings.LabelHost" />
</div>
<div class="w-full md:w-1/4 px-1">
<ui-text-input-with-label ref="portInput" v-model="newSettings.port" type="number" :disabled="savingSettings" :label="$strings.LabelPort" />
</div>
</div>
<div class="flex items-center mb-2 py-3">
<ui-toggle-switch labeledBy="email-settings-secure" v-model="newSettings.secure" :disabled="savingSettings" />
<ui-tooltip :text="$strings.LabelEmailSettingsSecureHelp">
<div class="pl-4 flex items-center">
<span id="email-settings-secure">{{ $strings.LabelEmailSettingsSecure }}</span>
<span class="material-icons text-lg pl-1">info_outlined</span>
</div>
</ui-tooltip>
</div>
<div class="flex items-center -mx-1 mb-2">
<div class="w-full md:w-1/2 px-1">
<ui-text-input-with-label ref="userInput" v-model="newSettings.user" :disabled="savingSettings" :label="$strings.LabelUsername" />
</div>
<div class="w-full md:w-1/2 px-1">
<ui-text-input-with-label ref="passInput" v-model="newSettings.pass" type="password" :disabled="savingSettings" :label="$strings.LabelPassword" />
</div>
</div>
<div class="flex items-center -mx-1 mb-2">
<div class="w-full md:w-1/2 px-1">
<ui-text-input-with-label ref="fromInput" v-model="newSettings.fromAddress" :disabled="savingSettings" :label="$strings.LabelEmailSettingsFromAddress" />
</div>
</div>
<div class="flex items-center justify-between pt-4">
<ui-btn :loading="sendingTest" :disabled="savingSettings || !newSettings.host" type="button" @click="sendTestClick">{{ $strings.ButtonTest }}</ui-btn>
<ui-btn :loading="savingSettings" :disabled="!hasUpdates" type="submit">{{ $strings.ButtonSave }}</ui-btn>
</div>
</form>
<div v-show="loading" class="absolute top-0 left-0 w-full h-full bg-black bg-opacity-25 flex items-center justify-center">
<ui-loading-indicator />
</div>
</app-settings-content>
<app-settings-content :header-text="$strings.HeaderEReaderDevices" showAddButton :description="''" @clicked="addNewDeviceClick">
<table v-if="existingEReaderDevices.length" class="tracksTable my-4">
<tr>
<th class="text-left">{{ $strings.LabelName }}</th>
<th class="text-left">{{ $strings.LabelEmail }}</th>
<th class="w-40"></th>
</tr>
<tr v-for="device in existingEReaderDevices" :key="device.name">
<td>
<p class="text-sm md:text-base text-gray-100">{{ device.name }}</p>
</td>
<td class="text-left">
<p class="text-sm md:text-base text-gray-100">{{ device.email }}</p>
</td>
<td class="w-40">
<div class="flex justify-end items-center h-10">
<ui-icon-btn icon="edit" borderless :size="8" icon-font-size="1.1rem" :disabled="deletingDeviceName === device.name" class="mx-1" @click="editDeviceClick(device)" />
<ui-icon-btn icon="delete" borderless :size="8" icon-font-size="1.1rem" :disabled="deletingDeviceName === device.name" @click="deleteDeviceClick(device)" />
</div>
</td>
</tr>
</table>
<div v-else class="text-center py-4">
<p class="text-lg text-gray-100">No Devices</p>
</div>
</app-settings-content>
<modals-emails-e-reader-device-modal v-model="showEReaderDeviceModal" :existing-devices="existingEReaderDevices" :ereader-device="selectedEReaderDevice" @update="ereaderDevicesUpdated" />
</div>
</template>
<script>
export default {
data() {
return {
loading: false,
savingSettings: false,
sendingTest: false,
deletingDeviceName: null,
settings: null,
newSettings: {
host: null,
port: 465,
secure: true,
user: null,
pass: null,
fromAddress: null
},
newEReaderDevice: {
name: '',
email: ''
},
selectedEReaderDevice: null,
showEReaderDeviceModal: false
}
},
computed: {
hasUpdates() {
if (!this.settings) return true
for (const key in this.newSettings) {
if (key === 'ereaderDevices') continue
if (this.newSettings[key] !== this.settings[key]) return true
}
return false
},
existingEReaderDevices() {
return this.settings?.ereaderDevices || []
}
},
methods: {
editDeviceClick(device) {
this.selectedEReaderDevice = device
this.showEReaderDeviceModal = true
},
deleteDeviceClick(device) {
const payload = {
message: `Are you sure you want to delete e-reader device "${device.name}"?`,
callback: (confirmed) => {
if (confirmed) {
this.deleteDevice(device)
}
},
type: 'yesNo'
}
this.$store.commit('globals/setConfirmPrompt', payload)
},
deleteDevice(device) {
const payload = {
ereaderDevices: this.existingEReaderDevices.filter((d) => d.name !== device.name)
}
this.deletingDeviceName = device.name
this.$axios
.$patch(`/emails/ereader-devices`, payload)
.then((data) => {
this.ereaderDevicesUpdated(data.ereaderDevices)
this.$toast.success('Device deleted')
})
.catch((error) => {
console.error('Failed to delete device', error)
this.$toast.error('Failed to delete device')
})
.finally(() => {
this.deletingDeviceName = null
})
},
ereaderDevicesUpdated(ereaderDevices) {
this.settings.ereaderDevices = ereaderDevices
this.newSettings.ereaderDevices = ereaderDevices.map((d) => ({ ...d }))
},
addNewDeviceClick() {
this.selectedEReaderDevice = null
this.showEReaderDeviceModal = true
},
sendTestClick() {
this.sendingTest = true
this.$axios
.$post('/api/emails/test')
.then(() => {
this.$toast.success('Test Email Sent')
})
.catch((error) => {
console.error('Failed to send test email', error)
const errorMsg = error.response.data || 'Failed to send test email'
this.$toast.error(errorMsg)
})
.finally(() => {
this.sendingTest = false
})
},
validateForm() {
for (const ref of [this.$refs.hostInput, this.$refs.portInput, this.$refs.userInput, this.$refs.passInput, this.$refs.fromInput]) {
if (ref?.blur) ref.blur()
}
if (this.newSettings.port) {
this.newSettings.port = Number(this.newSettings.port)
}
return true
},
submitForm() {
if (!this.validateForm()) return
const updatePayload = {
host: this.newSettings.host,
port: this.newSettings.port,
secure: this.newSettings.secure,
user: this.newSettings.user,
pass: this.newSettings.pass,
fromAddress: this.newSettings.fromAddress
}
this.savingSettings = true
this.$axios
.$patch('/api/emails/settings', updatePayload)
.then((data) => {
this.settings = data.settings
this.newSettings = {
...data.settings
}
this.$toast.success('Email settings updated')
})
.catch((error) => {
console.error('Failed to update email settings', error)
this.$toast.error('Failed to update email settings')
})
.finally(() => {
this.savingSettings = false
})
},
init() {
this.loading = true
this.$axios
.$get(`/api/emails/settings`)
.then((data) => {
this.settings = data.settings
this.newSettings = {
...this.settings
}
})
.catch((error) => {
console.error('Failed to get email settings', error)
this.$toast.error('Failed to load email settings')
})
.finally(() => {
this.loading = false
})
}
},
mounted() {
this.init()
},
beforeDestroy() {}
}
</script>

View file

@ -39,11 +39,15 @@
<ui-multi-select v-model="newServerSettings.sortingPrefixes" small :items="newServerSettings.sortingPrefixes" :label="$strings.LabelPrefixesToIgnore" @input="updateSortingPrefixes" :disabled="updatingServerSettings" />
</div>
<div class="flex items-center py-2">
<div class="flex items-center py-2 mb-2">
<ui-toggle-switch labeledBy="settings-chromecast-support" v-model="newServerSettings.chromecastEnabled" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('chromecastEnabled', val)" />
<p class="pl-4" id="settings-chromecast-support">{{ $strings.LabelSettingsChromecastSupport }}</p>
</div>
<div class="w-44 mb-2">
<ui-dropdown v-model="newServerSettings.metadataFileFormat" small :items="metadataFileFormats" label="Metadata File Format" @input="updateMetadataFileFormat" :disabled="updatingServerSettings" />
</div>
<div class="pt-4">
<h2 class="font-semibold">{{ $strings.HeaderSettingsDisplay }}</h2>
</div>
@ -68,8 +72,14 @@
</ui-tooltip>
</div>
<div class="py-2">
<div class="flex-grow py-2">
<ui-dropdown :label="$strings.LabelSettingsDateFormat" v-model="newServerSettings.dateFormat" :items="dateFormats" small class="max-w-52" @input="(val) => updateSettingsKey('dateFormat', val)" />
<p class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelExample }}: {{ dateExample }}</p>
</div>
<div class="flex-grow py-2">
<ui-dropdown :label="$strings.LabelSettingsTimeFormat" v-model="newServerSettings.timeFormat" :items="timeFormats" small class="max-w-52" @input="(val) => updateSettingsKey('timeFormat', val)" />
<p class="text-xs ml-1 text-white text-opacity-60">{{ $strings.LabelExample }}: {{ timeExample }}</p>
</div>
<div class="py-2">
@ -276,7 +286,17 @@ export default {
useBookshelfView: false,
isPurgingCache: false,
newServerSettings: {},
showConfirmPurgeCache: false
showConfirmPurgeCache: false,
metadataFileFormats: [
{
text: '.json',
value: 'json'
},
{
text: '.abs',
value: 'abs'
}
]
}
},
watch: {
@ -311,6 +331,17 @@ export default {
},
dateFormats() {
return this.$store.state.globals.dateFormats
},
timeFormats() {
return this.$store.state.globals.timeFormats
},
dateExample() {
const date = new Date(2014, 2, 25)
return this.$formatJsDate(date, this.newServerSettings.dateFormat)
},
timeExample() {
const date = new Date(2014, 2, 25, 17, 30, 0)
return this.$formatJsTime(date, this.newServerSettings.timeFormat)
}
},
methods: {
@ -346,6 +377,10 @@ export default {
this.updateSettingsKey('defaultRenameString', this.newServerSettings.defaultRenameString)
this.$store.commit('setDefaultRenameString', this.newServerSettings.defaultRenameString)
},
updateMetadataFileFormat(val) {
if (this.serverSettings.metadataFileFormat === val) return
this.updateSettingsKey('metadataFileFormat', val)
},
updateSettingsKey(key, val) {
this.updateServerSettings({
[key]: val
@ -355,8 +390,7 @@ export default {
this.updatingServerSettings = true
this.$store
.dispatch('updateServerSettings', payload)
.then((success) => {
console.log('Updated Server Settings', success)
.then(() => {
this.updatingServerSettings = false
this.$toast.success('Server settings updated')
@ -442,4 +476,4 @@ export default {
this.initServerSettings()
}
}
</script>
</script>

View file

@ -17,8 +17,8 @@
<ui-text-input v-else v-model="newTagName" />
<div class="flex-grow" />
<template v-if="editingTag !== tag">
<ui-icon-btn v-if="editingTag !== tag" icon="edit" borderless :size="8" icon-font-size="1.1rem" class="mx-1" @click="editTagClick(tag)" />
<ui-icon-btn v-if="editingTag !== tag" icon="delete" borderless :size="8" icon-font-size="1.1rem" @click="removeTagClick(tag)" />
<ui-icon-btn icon="edit" borderless :size="8" icon-font-size="1.1rem" class="mx-1" @click="editTagClick(tag)" />
<ui-icon-btn icon="delete" borderless :size="8" icon-font-size="1.1rem" @click="removeTagClick(tag)" />
</template>
<template v-else>
<ui-btn color="success" small class="mx-2" @click.stop="saveTagClick">{{ $strings.ButtonSave }}</ui-btn>

View file

@ -60,6 +60,25 @@
</div>
</template>
</div>
<div class="w-80 my-6 mx-auto">
<h1 class="text-2xl mb-4">{{ $strings.HeaderStatsLargestItems }}</h1>
<p v-if="!top10LargestItems.length">{{ $strings.MessageNoItems }}</p>
<template v-for="(ab, index) in top10LargestItems">
<div :key="index" class="w-full py-2">
<div class="flex items-center mb-1">
<p class="text-sm text-white text-opacity-70 w-44 pr-2 truncate">
{{ index + 1 }}.&nbsp;&nbsp;&nbsp;&nbsp;<nuxt-link :to="`/item/${ab.id}`" class="hover:underline">{{ ab.title }}</nuxt-link>
</p>
<div class="flex-grow rounded-full h-2.5 bg-primary bg-opacity-0 overflow-hidden">
<div class="bg-yellow-400 h-full rounded-full" :style="{ width: Math.round((100 * ab.size) / largestItemSize) + '%' }" />
</div>
<div class="w-4 ml-3">
<p class="text-sm font-bold">{{ $bytesPretty(ab.size) }}</p>
</div>
</div>
</div>
</template>
</div>
</div>
</app-settings-content>
</div>
@ -105,6 +124,13 @@ export default {
if (!this.top10LongestItems.length) return 0
return this.top10LongestItems[0].duration
},
top10LargestItems() {
return this.libraryStats ? this.libraryStats.largestItems || [] : []
},
largestItemSize() {
if (!this.top10LargestItems.length) return 0
return this.top10LargestItems[0].size
},
authorsWithCount() {
return this.libraryStats ? this.libraryStats.authorsWithCount : []
},
@ -135,4 +161,4 @@ export default {
this.init()
}
}
</script>
</script>

View file

@ -39,7 +39,7 @@
<p class="text-xs font-mono">{{ $secondsToTimestamp(session.currentTime) }}</p>
</td>
<td class="text-center hidden sm:table-cell">
<ui-tooltip v-if="session.updatedAt" direction="top" :text="$formatDate(session.updatedAt, 'MMMM do, yyyy HH:mm')">
<ui-tooltip v-if="session.updatedAt" direction="top" :text="$formatDatetime(session.updatedAt, dateFormat, timeFormat)">
<p class="text-xs text-gray-200">{{ $dateDistanceFromNow(session.updatedAt) }}</p>
</ui-tooltip>
</td>
@ -52,9 +52,53 @@
</div>
</div>
<p v-else class="text-white text-opacity-50">{{ $strings.MessageNoListeningSessions }}</p>
<!-- open listening sessions table -->
<p v-if="openListeningSessions.length" class="text-lg mb-4 mt-8">Open Listening Sessions</p>
<div v-if="openListeningSessions.length" class="block max-w-full">
<table class="userSessionsTable">
<tr class="bg-primary bg-opacity-40">
<th class="w-48 min-w-48 text-left">{{ $strings.LabelItem }}</th>
<th class="w-20 min-w-20 text-left hidden md:table-cell">{{ $strings.LabelUser }}</th>
<th class="w-32 min-w-32 text-left hidden md:table-cell">{{ $strings.LabelPlayMethod }}</th>
<th class="w-32 min-w-32 text-left hidden sm:table-cell">{{ $strings.LabelDeviceInfo }}</th>
<th class="w-32 min-w-32">{{ $strings.LabelTimeListened }}</th>
<th class="w-16 min-w-16">{{ $strings.LabelLastTime }}</th>
<th class="flex-grow hidden sm:table-cell">{{ $strings.LabelLastUpdate }}</th>
</tr>
<tr v-for="session in openListeningSessions" :key="`open-${session.id}`" class="cursor-pointer" @click="showSession(session)">
<td class="py-1 max-w-48">
<p class="text-xs text-gray-200 truncate">{{ session.displayTitle }}</p>
<p class="text-xs text-gray-400 truncate">{{ session.displayAuthor }}</p>
</td>
<td class="hidden md:table-cell">
<p v-if="filteredUserUsername" class="text-xs">{{ filteredUserUsername }}</p>
<p v-else class="text-xs">{{ session.user ? session.user.username : 'N/A' }}</p>
</td>
<td class="hidden md:table-cell">
<p class="text-xs">{{ getPlayMethodName(session.playMethod) }}</p>
</td>
<td class="hidden sm:table-cell">
<p class="text-xs" v-html="getDeviceInfoString(session.deviceInfo)" />
</td>
<td class="text-center">
<p class="text-xs font-mono">{{ $elapsedPretty(session.timeListening) }}</p>
</td>
<td class="text-center hover:underline" @click.stop="clickCurrentTime(session)">
<p class="text-xs font-mono">{{ $secondsToTimestamp(session.currentTime) }}</p>
</td>
<td class="text-center hidden sm:table-cell">
<ui-tooltip v-if="session.updatedAt" direction="top" :text="$formatDatetime(session.updatedAt, dateFormat, timeFormat)">
<p class="text-xs text-gray-200">{{ $dateDistanceFromNow(session.updatedAt) }}</p>
</ui-tooltip>
</td>
</tr>
</table>
</div>
</app-settings-content>
<modals-listening-session-modal v-model="showSessionModal" :session="selectedSession" @removedSession="removedSession" />
<modals-listening-session-modal v-model="showSessionModal" :session="selectedSession" @removedSession="removedSession" @closedSession="closedSession" />
</div>
</template>
@ -81,6 +125,7 @@ export default {
showSessionModal: false,
selectedSession: null,
listeningSessions: [],
openListeningSessions: [],
numPages: 0,
total: 0,
currentPage: 0,
@ -105,9 +150,18 @@ export default {
if (!this.userFilter) return null
var user = this.users.find((u) => u.id === this.userFilter)
return user ? user.username : null
},
dateFormat() {
return this.$store.state.serverSettings.dateFormat
},
timeFormat() {
return this.$store.state.serverSettings.timeFormat
}
},
methods: {
closedSession() {
this.loadOpenSessions()
},
removedSession() {
// If on last page and this was the last session then load prev page
if (this.currentPage == this.numPages - 1) {
@ -149,7 +203,7 @@ export default {
episodeId: episode.id,
title: episode.title,
subtitle: libraryItem.media.metadata.title,
caption: episode.publishedAt ? `Published ${this.$formatDate(episode.publishedAt, 'MMM do, yyyy')}` : 'Unknown publish date',
caption: episode.publishedAt ? `Published ${this.$formatDate(episode.publishedAt, this.dateFormat)}` : 'Unknown publish date',
duration: episode.audioFile.duration || null,
coverPath: libraryItem.media.coverPath || null
}
@ -216,7 +270,7 @@ export default {
async loadSessions(page) {
var userFilterQuery = this.selectedUser ? `&user=${this.selectedUser}` : ''
const data = await this.$axios.$get(`/api/sessions?page=${page}&itemsPerPage=${this.itemsPerPage}${userFilterQuery}`).catch((err) => {
console.error('Failed to load listening sesions', err)
console.error('Failed to load listening sessions', err)
return null
})
if (!data) {
@ -230,8 +284,24 @@ export default {
this.listeningSessions = data.sessions
this.userFilter = data.userFilter
},
async loadOpenSessions() {
const data = await this.$axios.$get('/api/sessions/open').catch((err) => {
console.error('Failed to load open sessions', err)
return null
})
if (!data) {
this.$toast.error('Failed to load open sessions')
return
}
this.openListeningSessions = (data.sessions || []).map((s) => {
s.open = true
return s
})
},
init() {
this.loadSessions(0)
this.loadOpenSessions()
}
},
mounted() {
@ -266,4 +336,4 @@ export default {
padding: 4px 8px;
font-size: 0.75rem;
}
</style>
</style>

View file

@ -79,12 +79,12 @@
<p class="text-sm">{{ Math.floor(item.progress * 100) }}%</p>
</td>
<td class="text-center hidden sm:table-cell">
<ui-tooltip v-if="item.startedAt" direction="top" :text="$formatDate(item.startedAt, 'MMMM do, yyyy HH:mm')">
<ui-tooltip v-if="item.startedAt" direction="top" :text="$formatDatetime(item.startedAt, dateFormat, timeFormat)">
<p class="text-sm">{{ $dateDistanceFromNow(item.startedAt) }}</p>
</ui-tooltip>
</td>
<td class="text-center hidden sm:table-cell">
<ui-tooltip v-if="item.lastUpdate" direction="top" :text="$formatDate(item.lastUpdate, 'MMMM do, yyyy HH:mm')">
<ui-tooltip v-if="item.lastUpdate" direction="top" :text="$formatDatetime(item.lastUpdate, dateFormat, timeFormat)">
<p class="text-sm">{{ $dateDistanceFromNow(item.lastUpdate) }}</p>
</ui-tooltip>
</td>
@ -149,6 +149,12 @@ export default {
latestSession() {
if (!this.listeningSessions.sessions || !this.listeningSessions.sessions.length) return null
return this.listeningSessions.sessions[0]
},
dateFormat() {
return this.$store.state.serverSettings.dateFormat
},
timeFormat() {
return this.$store.state.serverSettings.timeFormat
}
},
methods: {

View file

@ -46,7 +46,7 @@
<p class="text-xs font-mono">{{ $secondsToTimestamp(session.currentTime) }}</p>
</td>
<td class="text-center hidden sm:table-cell">
<ui-tooltip v-if="session.updatedAt" direction="top" :text="$formatDate(session.updatedAt, 'MMMM do, yyyy HH:mm')">
<ui-tooltip v-if="session.updatedAt" direction="top" :text="$formatDatetime(session.updatedAt, dateFormat, timeFormat)">
<p class="text-xs text-gray-200">{{ $dateDistanceFromNow(session.updatedAt) }}</p>
</ui-tooltip>
</td>
@ -96,6 +96,12 @@ export default {
},
userOnline() {
return this.$store.getters['users/getIsUserOnline'](this.user.id)
},
dateFormat() {
return this.$store.state.serverSettings.dateFormat
},
timeFormat() {
return this.$store.state.serverSettings.timeFormat
}
},
methods: {
@ -140,7 +146,7 @@ export default {
episodeId: episode.id,
title: episode.title,
subtitle: libraryItem.media.metadata.title,
caption: episode.publishedAt ? `Published ${this.$formatDate(episode.publishedAt, 'MMM do, yyyy')}` : 'Unknown publish date',
caption: episode.publishedAt ? `Published ${this.$formatDate(episode.publishedAt, this.dateFormat)}` : 'Unknown publish date',
duration: episode.audioFile.duration || null,
coverPath: libraryItem.media.coverPath || null
}
@ -252,4 +258,4 @@ export default {
padding: 4px 8px;
font-size: 0.75rem;
}
</style>
</style>