2022-03-23 17:59:14 -05:00
< template >
2023-06-04 15:52:36 -05:00
< div id = "item-page" class = "w-full h-full px-3 pb-4 overflow-y-auto overflow-x-hidden relative bg-bg" >
2023-01-26 17:14:06 -06:00
< div class = "fixed top-0 left-0 w-full h-full pointer-events-none p-px z-10" >
2023-01-13 16:46:42 -06:00
< div class = "w-full h-full" : style = "{ backgroundColor: coverRgb }" / >
2023-01-11 18:00:05 -06:00
< div class = "w-full h-full absolute top-0 left-0" style = "background: linear-gradient(169deg, rgba(0, 0, 0, 0.4) 0%, rgba(55, 56, 56, 1) 80%)" / >
< / div >
< div class = "z-10 relative" >
2023-02-26 00:34:58 +01:00
<!-- cover -- >
2023-01-13 17:30:48 -06:00
< div class = "w-full flex justify-center relative mb-4" >
2023-02-09 23:57:59 +01:00
< div style = "width: 0; transform: translateX(-50vw); overflow: visible" >
< div style = "width: 150vw; overflow: hidden" >
2023-02-09 18:13:30 -06:00
< div id = "coverBg" style = "filter: blur(5vw)" >
2023-02-09 23:57:59 +01:00
< covers-book-cover :library-item = "libraryItem" :width = "coverWidth" :book-cover-aspect-ratio = "bookCoverAspectRatio" @imageLoaded ="coverImageLoaded" / >
< / div >
< / div >
< / div >
2023-01-11 18:00:05 -06:00
< div class = "relative" @ click = "showFullscreenCover = true" >
2023-03-19 17:13:33 -05:00
< covers-book-cover :library-item = "libraryItem" :width = "coverWidth" :book-cover-aspect-ratio = "bookCoverAspectRatio" no -bg raw @imageLoaded ="coverImageLoaded" / >
2023-01-12 17:04:47 -06:00
< div v-if = "!isPodcast" class="absolute bottom-0 left-0 h-1 shadow-sm z-10" :class="userIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: coverWidth * progressPercent + 'px' }" > < / div >
2023-01-11 18:00:05 -06:00
< / div >
2022-03-23 17:59:14 -05:00
< / div >
2023-02-26 00:34:58 +01:00
<!-- title -- >
< div class = "text-center mb-2" >
< h1 class = "text-xl font-semibold" > { { title } } < / h1 >
< p v-if = "subtitle" class="text-gray-100 text-base" > {{ subtitle }} < / p >
< / div >
2022-12-03 17:43:47 -06:00
2023-01-11 18:00:05 -06:00
<!-- Show an indicator for local library items whether they are linked to a server item and if that server item is connected -- >
2023-02-10 23:12:53 +01:00
< p v-if = "isLocal && serverLibraryItemId" style="font-size: 10px" class="text-success text-center py-1 uppercase tracking-widest" > connected < / p >
< p v -else -if = " isLocal & & libraryItem.serverAddress " style = "font-size: 10px" class = "text-gray-400 text-center py-1" > { { libraryItem . serverAddress } } < / p >
2022-06-02 17:57:37 -05:00
2023-01-13 17:30:48 -06:00
<!-- action buttons -- >
2023-02-26 00:34:58 +01:00
< div class = "col-span-full" >
2023-05-20 14:49:55 -05:00
< div v-if = "showPlay || showRead" class="flex mt-4 -mx-1" >
< ui-btn v-if = "showPlay" color="success" class="flex items-center justify-center flex-grow mx-1" :padding-x="4" @click="playClick" >
< span class = "material-icons" > { { playerIsPlaying ? 'pause' : 'play_arrow' } } < / span >
< span class = "px-1 text-sm" > { { playerIsPlaying ? 'Pause' : isPodcast ? 'Next Episode' : hasLocal ? 'Play' : 'Stream' } } < / span >
2023-01-13 17:30:48 -06:00
< / ui-btn >
< ui-btn v-if = "showRead" color="info" class="flex items-center justify-center mx-1" :class="showPlay ? '' : 'flex-grow'" :padding-x="2" @click="readBook" >
< span class = "material-icons" > auto _stories < / span >
< span v-if = "!showPlay" class="px-2 text-base" > Read {{ ebookFormat }} < / span >
< / ui-btn >
< ui-btn v-if = "showDownload" :color="downloadItem ? 'warning' : 'primary'" class="flex items-center justify-center mx-1" :padding-x="2" @click="downloadClick" >
< span class = "material-icons" : class = "downloadItem ? 'animate-pulse' : ''" > { { downloadItem ? 'downloading' : 'download' } } < / span >
< / ui-btn >
< ui-btn color = "primary" class = "flex items-center justify-center mx-1" :padding-x = "2" @click ="moreButtonPress" >
< span class = "material-icons" > more _vert < / span >
< / ui-btn >
< / div >
2023-02-26 00:34:58 +01:00
< div v-if = "!isPodcast && progressPercent > 0" class="px-4 py-2 bg-primary text-sm font-semibold rounded-md text-gray-200 mt-4 text-center" :class="resettingProgress ? 'opacity-25' : ''" >
< p > Your Progress : { { Math . round ( progressPercent * 100 ) } } % < / p >
2023-03-25 17:40:46 -05:00
< p v-if = "!useEBookProgress && !userIsFinished" class="text-gray-400 text-xs" > {{ $ elapsedPretty ( userTimeRemaining ) }} remaining < / p >
< p v -else -if = " userIsFinished " class = "text-gray-400 text-xs" > Finished { { $formatDate ( userProgressFinishedAt ) } } < / p >
2023-02-26 00:34:58 +01:00
< / div >
2023-01-13 17:30:48 -06:00
< / div >
2023-01-28 11:58:16 -06:00
< div v-if = "downloadItem" class="py-3" >
2023-02-04 15:52:06 -06:00
< p v-if = "downloadItem.itemProgress == 1" class="text-center text-lg" > Download complete. Processing... < / p >
< p v -else class = "text-center text-lg" > Downloading ! ( { { Math . round ( downloadItem . itemProgress * 100 ) } } % ) < / p >
2023-01-28 11:58:16 -06:00
< / div >
2023-01-11 18:00:05 -06:00
<!-- metadata -- >
2023-06-19 17:42:15 -05:00
< div id = "metadata" class = "grid gap-2 my-2" style >
2023-03-06 15:27:12 -06:00
< div v-if = "podcastAuthor || (bookAuthors && bookAuthors.length)" class="text-white text-opacity-60 uppercase text-sm" > Author < / div >
2023-02-13 00:14:04 +01:00
< div v-if = "podcastAuthor" class="text-sm" > {{ podcastAuthor }} < / div >
< div v -else -if = " bookAuthors & & bookAuthors.length " class = "text-sm" >
< template v-for = "(author, index) in bookAuthors" >
2023-08-30 23:33:58 +02:00
< nuxt-link :key = "author.id" :to = "`/bookshelf/library?filter=authors.${$encode(author.id)}`" class = "underline" > { { author . name } } < / n u x t - l i n k
2023-09-17 11:37:31 -05:00
> < span :key = "`${author.id}-comma`" v-if = "index < bookAuthors.length - 1" > , < / span >
2023-02-13 00:14:04 +01:00
< / template >
< / div >
2023-05-19 17:57:36 -05:00
< div v-if = "podcastType" class="text-white text-opacity-60 uppercase text-sm" > Type < / div >
< div v-if = "podcastType" class="text-sm capitalize" > {{ podcastType }} < / div >
2023-02-26 12:59:44 +01:00
< div v-if = "series && series.length" class="text-white text-opacity-60 uppercase text-sm" > Series < / div >
2023-02-12 22:51:04 +01:00
< div v-if = "series && series.length" class="truncate text-sm" >
< template v-for = "(series, index) in seriesList" >
2023-07-12 16:56:23 -05:00
< nuxt-link :key = "series.id" :to = "`/bookshelf/series/${series.id}`" class = "underline" > { { series . text } } < / n u x t - l i n k
2023-09-17 11:37:31 -05:00
> < span :key = "`${series.id}-comma`" v-if = "index < seriesList.length - 1" > , < / span >
2023-02-12 22:51:04 +01:00
< / template >
< / div >
2023-02-26 12:59:44 +01:00
< div v-if = "numTracks" class="text-white text-opacity-60 uppercase text-sm" > Duration < / div >
2023-02-26 00:34:58 +01:00
< div v-if = "numTracks" class="text-sm" > {{ $ elapsedPretty ( duration ) }} < / div >
2023-03-06 15:27:12 -06:00
< div v-if = "narrators && narrators.length" class="text-white text-opacity-60 uppercase text-sm" > {{ narrators.length = = = 1 ? ' Narrator ' : ' Narrators ' }} < / div >
< div v-if = "narrators && narrators.length" class="truncate text-sm" >
2023-01-11 18:00:05 -06:00
< template v-for = "(narrator, index) in narrators" >
2023-07-12 16:56:23 -05:00
< nuxt-link :key = "narrator" :to = "`/bookshelf/library?filter=narrators.${$encode(narrator)}`" class = "underline" > { { narrator } } < / n u x t - l i n k
2023-09-17 11:37:31 -05:00
> < span :key = "index" v-if = "index < narrators.length - 1" > , < / span >
2023-01-11 18:00:05 -06:00
< / template >
< / div >
2022-06-04 10:19:31 -05:00
2023-03-06 15:27:12 -06:00
< div v-if = "genres.length" class="text-white text-opacity-60 uppercase text-sm" > {{ genres.length = = = 1 ? ' Genre ' : ' Genres ' }} < / div >
< div v-if = "genres.length" class="truncate text-sm" >
2023-01-11 18:00:05 -06:00
< template v-for = "(genre, index) in genres" >
2023-07-12 16:56:23 -05:00
< nuxt-link :key = "genre" :to = "`/bookshelf/library?filter=genres.${$encode(genre)}`" class = "underline" > { { genre } } < / n u x t - l i n k
2023-09-17 11:37:31 -05:00
> < span :key = "index" v-if = "index < genres.length - 1" > , < / span >
2023-01-11 18:00:05 -06:00
< / template >
< / div >
2023-01-08 17:04:08 +01:00
2023-03-06 15:27:12 -06:00
< div v-if = "publishedYear" class="text-white text-opacity-60 uppercase text-sm" > Published < / div >
< div v-if = "publishedYear" class="text-sm" > {{ publishedYear }} < / div >
2022-12-03 17:43:47 -06:00
< / div >
2023-03-06 15:51:11 -06:00
< div v-if = "description" class="w-full py-2" >
2023-03-06 15:27:12 -06:00
< p ref = "description" class = "text-sm text-justify whitespace-pre-line font-light" : class = "{ 'line-clamp-4': !showFullDescription }" style = "hyphens: auto" > { { description } } < / p >
2023-03-06 15:51:11 -06:00
< div v-if = "descriptionClamped" class="text-white text-sm py-2" @click="showFullDescription = !showFullDescription" >
2023-03-06 15:27:12 -06:00
{ { showFullDescription ? 'Read less' : 'Read more' } }
< span class = "material-icons align-middle text-base -mt-px" > { { showFullDescription ? 'expand_less' : 'expand_more' } } < / span >
< / div >
2023-01-11 18:00:05 -06:00
< / div >
2022-04-02 19:43:43 -05:00
2023-03-06 15:27:12 -06:00
<!-- tables -- >
2023-01-11 18:00:05 -06:00
< tables-podcast-episodes-table v-if = "isPodcast" :library-item="libraryItem" :local-library-item-id="localLibraryItemId" :episodes="episodes" :local-episodes="localLibraryItemEpisodes" :is-local="isLocal" / >
2022-04-10 20:31:47 -05:00
2023-03-06 15:27:12 -06:00
< tables-chapters-table v-if = "numChapters" :library-item="libraryItem" @playAtTimestamp="playAtTimestamp" / >
< tables-tracks-table v-if = "numTracks" :tracks="tracks" :library-item-id="libraryItemId" / >
2023-06-11 13:36:19 -05:00
< tables-ebook-files-table v-if = "ebookFiles.length" :library-item="libraryItem" / >
2023-03-06 15:27:12 -06:00
<!-- modals -- >
2023-01-11 18:00:05 -06:00
< modals-select-local-folder-modal v-model = "showSelectLocalFolder" :media-type="mediaType" @select="selectedLocalFolder" / >
2022-06-02 17:57:37 -05:00
2023-01-30 07:57:34 -06:00
< modals-dialog v-model = "showMoreMenu" :items="moreMenuItems" @action="moreMenuAction" / >
2022-06-02 17:57:37 -05:00
2023-01-11 18:00:05 -06:00
< modals-item-details-modal v-model = "showDetailsModal" :library-item="libraryItem" / >
2022-06-24 17:20:13 -05:00
2023-01-11 18:00:05 -06:00
< modals-fullscreen-cover v-model = "showFullscreenCover" :library-item="libraryItem" / >
< / div >
2022-03-23 17:59:14 -05:00
< / div >
< / template >
< script >
import { Dialog } from '@capacitor/dialog'
2022-04-04 19:08:27 -05:00
import { AbsFileSystem , AbsDownloader } from '@/plugins/capacitor'
2023-01-11 18:00:05 -06:00
import { FastAverageColor } from 'fast-average-color'
2022-03-23 17:59:14 -05:00
export default {
async asyncData ( { store , params , redirect , app } ) {
2023-02-25 16:33:06 -06:00
const libraryItemId = params . id
let libraryItem = null
2022-04-03 17:07:26 -05:00
if ( libraryItemId . startsWith ( 'local' ) ) {
libraryItem = await app . $db . getLocalLibraryItem ( libraryItemId )
2022-06-01 19:38:26 -05:00
console . log ( 'Got lli' , libraryItemId )
2022-04-03 17:07:26 -05:00
} else if ( store . state . user . serverConnectionConfig ) {
2023-06-24 14:45:25 -05:00
libraryItem = await app . $axios . $get ( ` /api/items/ ${ libraryItemId } ?expanded=1&include=rssfeed ` ) . catch ( ( error ) => {
2022-03-23 17:59:14 -05:00
console . error ( 'Failed' , error )
return false
} )
2023-02-25 16:33:06 -06:00
2022-04-07 18:46:58 -05:00
if ( libraryItem ) {
2023-02-25 16:33:06 -06:00
const localLibraryItem = await app . $db . getLocalLibraryItemByLId ( libraryItemId )
2022-04-07 18:46:58 -05:00
if ( localLibraryItem ) {
console . log ( 'Library item has local library item also' , localLibraryItem . id )
libraryItem . localLibraryItem = localLibraryItem
}
}
2022-03-23 17:59:14 -05:00
}
if ( ! libraryItem ) {
console . error ( 'No item...' , params . id )
return redirect ( '/' )
}
return {
2023-06-24 14:45:25 -05:00
libraryItem ,
rssFeed : libraryItem . rssFeed || null
2022-03-23 17:59:14 -05:00
}
} ,
data ( ) {
return {
2022-04-02 19:43:43 -05:00
resettingProgress : false ,
2022-04-23 00:27:03 -04:00
isProcessingReadUpdate : false ,
2022-06-02 17:57:37 -05:00
showSelectLocalFolder : false ,
showMoreMenu : false ,
2022-06-24 17:20:13 -05:00
showDetailsModal : false ,
2023-01-11 18:00:05 -06:00
showFullscreenCover : false ,
coverRgb : 'rgb(55, 56, 56)' ,
2023-01-12 17:04:47 -06:00
coverBgIsLight : false ,
2023-02-26 12:10:18 +01:00
windowWidth : 0 ,
2023-03-06 15:27:12 -06:00
descriptionClamped : false ,
showFullDescription : false
2022-03-23 17:59:14 -05:00
}
} ,
computed : {
isIos ( ) {
return this . $platform === 'ios'
} ,
2022-05-22 15:49:42 -05:00
userCanDownload ( ) {
return this . $store . getters [ 'user/getUserCanDownload' ]
} ,
2023-06-24 14:45:25 -05:00
userIsAdminOrUp ( ) {
return this . $store . getters [ 'user/getIsAdminOrUp' ]
} ,
2022-04-03 17:07:26 -05:00
isLocal ( ) {
return this . libraryItem . isLocal
} ,
2022-04-07 18:46:58 -05:00
hasLocal ( ) {
// Server library item has matching local library item
return this . isLocal || this . libraryItem . localLibraryItem
} ,
localLibraryItem ( ) {
if ( this . isLocal ) return this . libraryItem
return this . libraryItem . localLibraryItem || null
} ,
2022-04-15 20:48:39 -05:00
localLibraryItemId ( ) {
2023-05-20 16:29:54 -05:00
return this . localLibraryItem ? . id || null
2022-04-15 20:48:39 -05:00
} ,
localLibraryItemEpisodes ( ) {
if ( ! this . isPodcast || ! this . localLibraryItem ) return [ ]
var podcastMedia = this . localLibraryItem . media
2023-05-20 16:29:54 -05:00
return podcastMedia ? . episodes || [ ]
2022-04-15 20:48:39 -05:00
} ,
2022-05-04 19:31:56 -05:00
serverLibraryItemId ( ) {
if ( ! this . isLocal ) return this . libraryItem . id
// Check if local library item is connected to the current server
if ( ! this . libraryItem . serverAddress || ! this . libraryItem . libraryItemId ) return null
if ( this . $store . getters [ 'user/getServerAddress' ] === this . libraryItem . serverAddress ) {
return this . libraryItem . libraryItemId
}
return null
2022-03-23 17:59:14 -05:00
} ,
bookCoverAspectRatio ( ) {
2022-10-22 08:59:10 -05:00
return this . $store . getters [ 'libraries/getBookCoverAspectRatio' ]
2022-03-23 17:59:14 -05:00
} ,
libraryItemId ( ) {
return this . libraryItem . id
} ,
2022-04-02 19:43:43 -05:00
mediaType ( ) {
return this . libraryItem . mediaType
} ,
2022-04-10 20:31:47 -05:00
isPodcast ( ) {
return this . mediaType == 'podcast'
} ,
2022-03-23 17:59:14 -05:00
media ( ) {
return this . libraryItem . media || { }
} ,
mediaMetadata ( ) {
return this . media . metadata || { }
} ,
title ( ) {
return this . mediaMetadata . title
} ,
2022-08-07 10:35:01 -05:00
subtitle ( ) {
return this . mediaMetadata . subtitle
} ,
2022-12-03 17:43:47 -06:00
genres ( ) {
return this . mediaMetadata . genres || [ ]
} ,
publishedYear ( ) {
return this . mediaMetadata . publishedYear
} ,
2023-05-19 17:57:36 -05:00
podcastType ( ) {
return this . mediaMetadata . type
} ,
2022-06-04 10:19:31 -05:00
podcastAuthor ( ) {
if ( ! this . isPodcast ) return null
return this . mediaMetadata . author || ''
} ,
bookAuthors ( ) {
if ( this . isPodcast ) return null
return this . mediaMetadata . authors || [ ]
2022-03-23 17:59:14 -05:00
} ,
2022-06-04 10:19:31 -05:00
narrators ( ) {
2022-06-02 17:57:37 -05:00
if ( this . isPodcast ) return null
2022-06-04 10:19:31 -05:00
return this . mediaMetadata . narrators || [ ]
2022-06-02 17:57:37 -05:00
} ,
2022-03-23 17:59:14 -05:00
description ( ) {
return this . mediaMetadata . description || ''
} ,
series ( ) {
return this . mediaMetadata . series || [ ]
} ,
2022-06-04 10:19:31 -05:00
seriesList ( ) {
if ( this . isPodcast ) return null
return this . series . map ( ( se ) => {
var text = se . name
if ( se . sequence ) text += ` # ${ se . sequence } `
return {
... se ,
text
}
} )
2022-05-04 19:31:56 -05:00
} ,
2022-03-23 17:59:14 -05:00
duration ( ) {
2022-03-28 19:53:53 -05:00
return this . media . duration
2022-03-23 17:59:14 -05:00
} ,
2022-04-07 18:46:58 -05:00
user ( ) {
return this . $store . state . user . user
} ,
2022-03-23 17:59:14 -05:00
userToken ( ) {
return this . $store . getters [ 'user/getToken' ]
} ,
userItemProgress ( ) {
2023-02-07 16:44:23 -06:00
if ( this . isPodcast ) return null
2023-05-20 16:29:54 -05:00
if ( this . isLocal ) return this . localItemProgress
return this . serverItemProgress
} ,
localItemProgress ( ) {
if ( this . isPodcast ) return null
return this . $store . getters [ 'globals/getLocalMediaProgressById' ] ( this . localLibraryItemId )
} ,
serverItemProgress ( ) {
if ( this . isPodcast ) return null
return this . $store . getters [ 'user/getUserMediaProgress' ] ( this . serverLibraryItemId )
2022-03-23 17:59:14 -05:00
} ,
userIsFinished ( ) {
return this . userItemProgress ? ! ! this . userItemProgress . isFinished : false
} ,
userTimeRemaining ( ) {
if ( ! this . userItemProgress ) return 0
2023-01-08 14:50:21 -06:00
const duration = this . userItemProgress . duration || this . duration
2022-03-23 17:59:14 -05:00
return duration - this . userItemProgress . currentTime
} ,
2023-03-25 17:40:46 -05:00
useEBookProgress ( ) {
if ( ! this . userItemProgress || this . userItemProgress . progress ) return false
return this . userItemProgress . ebookProgress > 0
} ,
2022-03-23 17:59:14 -05:00
progressPercent ( ) {
2023-03-25 17:40:46 -05:00
if ( this . useEBookProgress ) return Math . max ( Math . min ( 1 , this . userItemProgress . ebookProgress ) , 0 )
2022-03-23 17:59:14 -05:00
return this . userItemProgress ? Math . max ( Math . min ( 1 , this . userItemProgress . progress ) , 0 ) : 0
} ,
userProgressFinishedAt ( ) {
return this . userItemProgress ? this . userItemProgress . finishedAt : 0
} ,
isStreaming ( ) {
2023-06-19 12:37:44 -05:00
return this . isPlaying && ! this . $store . getters [ 'getIsCurrentSessionLocal' ]
2022-03-23 17:59:14 -05:00
} ,
isPlaying ( ) {
2023-06-19 12:37:44 -05:00
if ( this . localLibraryItemId && this . $store . getters [ 'getIsMediaStreaming' ] ( this . localLibraryItemId ) ) return true
return this . $store . getters [ 'getIsMediaStreaming' ] ( this . libraryItemId )
2022-03-23 17:59:14 -05:00
} ,
2023-05-20 14:49:55 -05:00
playerIsPlaying ( ) {
return this . $store . state . playerIsPlaying && ( this . isStreaming || this . isPlaying )
} ,
2023-03-06 15:27:12 -06:00
tracks ( ) {
return this . media . tracks || [ ]
} ,
2022-03-23 17:59:14 -05:00
numTracks ( ) {
2023-03-06 15:27:12 -06:00
return this . tracks . length || 0
2022-03-23 17:59:14 -05:00
} ,
2022-06-02 17:57:37 -05:00
numChapters ( ) {
if ( ! this . media . chapters ) return 0
return this . media . chapters . length || 0
} ,
2022-03-23 17:59:14 -05:00
isMissing ( ) {
return this . libraryItem . isMissing
} ,
2023-05-20 14:49:55 -05:00
isInvalid ( ) {
return this . libraryItem . isInvalid
2022-03-23 17:59:14 -05:00
} ,
showPlay ( ) {
2023-05-20 14:49:55 -05:00
return ! this . isMissing && ! this . isInvalid && ( this . numTracks || this . episodes . length )
2022-03-23 17:59:14 -05:00
} ,
showRead ( ) {
2022-12-06 17:07:27 -06:00
return this . ebookFile
2022-03-23 17:59:14 -05:00
} ,
2022-05-22 15:49:42 -05:00
showDownload ( ) {
2023-05-20 14:49:55 -05:00
if ( this . isPodcast || this . hasLocal ) return false
2023-06-19 17:42:15 -05:00
return this . user && this . userCanDownload && ( this . showPlay || this . showRead )
2022-05-22 15:49:42 -05:00
} ,
2023-06-11 13:36:19 -05:00
libraryFiles ( ) {
return this . libraryItem . libraryFiles || [ ]
} ,
ebookFiles ( ) {
return this . libraryFiles . filter ( ( lf ) => lf . fileType === 'ebook' )
} ,
2022-03-28 19:53:53 -05:00
ebookFile ( ) {
return this . media . ebookFile
2022-03-23 17:59:14 -05:00
} ,
ebookFormat ( ) {
2022-03-28 19:53:53 -05:00
if ( ! this . ebookFile ) return null
return this . ebookFile . ebookFormat
2022-03-23 17:59:14 -05:00
} ,
2022-04-07 18:46:58 -05:00
downloadItem ( ) {
return this . $store . getters [ 'globals/getDownloadItem' ] ( this . libraryItemId )
} ,
2022-04-10 20:31:47 -05:00
episodes ( ) {
return this . media . episodes || [ ]
2022-05-04 19:31:56 -05:00
} ,
isCasting ( ) {
return this . $store . state . isCasting
2022-06-02 17:57:37 -05:00
} ,
2023-06-24 14:45:25 -05:00
showRSSFeedOption ( ) {
if ( ! this . serverLibraryItemId ) return false
if ( ! this . rssFeed && ! this . episodes . length && ! this . tracks . length ) return false // Cannot open RSS feed with no episodes/tracks
// If rss feed is open then show feed url to users otherwise just show to admins
return this . userIsAdminOrUp || this . rssFeed
} ,
2022-06-02 17:57:37 -05:00
moreMenuItems ( ) {
2022-12-10 14:26:58 -06:00
const items = [ ]
2023-01-13 17:30:48 -06:00
if ( ! this . isPodcast ) {
2023-01-14 18:01:12 -06:00
// TODO: Implement on iOS
if ( ! this . isIos ) {
items . push ( {
text : 'History' ,
2023-02-08 23:09:52 +01:00
value : 'history' ,
icon : 'history'
2023-01-14 18:01:12 -06:00
} )
}
2023-02-08 22:27:56 +01:00
if ( ! this . userIsFinished ) {
items . push ( {
text : 'Mark as Finished' ,
2023-02-08 23:09:52 +01:00
value : 'markFinished' ,
icon : 'beenhere'
2023-02-08 22:27:56 +01:00
} )
}
2023-02-07 22:21:35 +01:00
2023-02-08 22:27:56 +01:00
if ( this . progressPercent > 0 ) {
2023-02-07 22:21:35 +01:00
items . push ( {
text : 'Discard Progress' ,
2023-02-08 23:09:52 +01:00
value : 'discardProgress' ,
icon : 'backspace'
2023-02-07 22:21:35 +01:00
} )
}
2023-01-13 17:30:48 -06:00
}
2023-06-17 12:49:24 -05:00
if ( ! this . isPodcast && this . serverLibraryItemId ) {
items . push ( {
text : 'Add to Playlist' ,
value : 'playlist' ,
icon : 'playlist_add'
} )
}
2023-06-24 14:45:25 -05:00
if ( this . showRSSFeedOption ) {
items . push ( {
text : this . rssFeed ? 'RSS Feed' : 'Open RSS Feed' ,
value : 'rssFeed' ,
icon : 'rss_feed'
} )
}
2022-12-10 14:26:58 -06:00
if ( this . localLibraryItemId ) {
items . push ( {
text : 'Manage Local Files' ,
2023-02-08 23:09:52 +01:00
value : 'manageLocal' ,
icon : 'folder'
2022-12-10 14:26:58 -06:00
} )
2022-12-03 17:05:43 -06:00
2023-06-17 12:49:24 -05:00
if ( ! this . isPodcast ) {
items . push ( {
text : 'Delete Local Item' ,
value : 'deleteLocal' ,
icon : 'delete'
} )
}
2022-06-02 17:57:37 -05:00
}
2022-12-10 14:26:58 -06:00
2023-01-13 17:30:48 -06:00
items . push ( {
text : 'More Info' ,
2023-02-08 23:09:52 +01:00
value : 'details' ,
icon : 'info'
2023-01-13 17:30:48 -06:00
} )
2022-12-10 14:26:58 -06:00
return items
2023-01-12 17:04:47 -06:00
} ,
coverWidth ( ) {
let width = this . windowWidth - 94
if ( width > 325 ) return 325
else if ( width < 0 ) return 175
if ( width * this . bookCoverAspectRatio > 325 ) width = 325 / this . bookCoverAspectRatio
return width
2023-01-14 18:01:12 -06:00
} ,
mediaId ( ) {
if ( this . isPodcast ) return null
return this . serverLibraryItemId || this . localLibraryItemId
2022-03-23 17:59:14 -05:00
}
} ,
methods : {
2023-06-17 12:49:24 -05:00
async deleteLocalItem ( ) {
await this . $hapticsImpact ( )
let confirmMessage = 'Remove local files of this item from your device?'
if ( this . serverLibraryItemId ) {
confirmMessage += ' The files on the server and your progress will be unaffected.'
}
const { value } = await Dialog . confirm ( {
title : 'Confirm' ,
message : confirmMessage
} )
if ( value ) {
const res = await AbsFileSystem . deleteItem ( this . localLibraryItem )
if ( res ? . success ) {
this . $toast . success ( 'Deleted successfully' )
if ( this . isLocal ) {
// If local then redirect to server version when available
if ( this . serverLibraryItemId ) {
this . $router . replace ( ` /item/ ${ this . serverLibraryItemId } ` )
} else {
this . $router . replace ( '/bookshelf' )
}
} else {
// Remove localLibraryItem
this . $delete ( this . libraryItem , 'localLibraryItem' )
}
} else this . $toast . error ( 'Failed to delete' )
}
} ,
2023-01-11 18:00:05 -06:00
async coverImageLoaded ( fullCoverUrl ) {
if ( ! fullCoverUrl ) return
const fac = new FastAverageColor ( )
fac
. getColorAsync ( fullCoverUrl )
. then ( ( color ) => {
this . coverRgb = color . rgba
this . coverBgIsLight = color . isLight
} )
. catch ( ( e ) => {
console . log ( e )
} )
} ,
2022-06-02 17:57:37 -05:00
moreMenuAction ( action ) {
this . showMoreMenu = false
if ( action === 'manageLocal' ) {
2023-01-30 07:57:34 -06:00
this . $nextTick ( ( ) => {
this . $router . push ( ` /localMedia/item/ ${ this . localLibraryItemId } ` )
} )
2022-06-02 17:57:37 -05:00
} else if ( action === 'details' ) {
this . showDetailsModal = true
2022-12-03 17:05:43 -06:00
} else if ( action === 'playlist' ) {
this . $store . commit ( 'globals/setSelectedPlaylistItems' , [ { libraryItem : this . libraryItem , episode : null } ] )
this . $store . commit ( 'globals/setShowPlaylistsAddCreateModal' , true )
2023-01-13 17:30:48 -06:00
} else if ( action === 'markFinished' ) {
if ( this . isProcessingReadUpdate ) return
this . toggleFinished ( )
2023-01-14 18:01:12 -06:00
} else if ( action === 'history' ) {
this . $router . push ( ` /media/ ${ this . mediaId } /history?title= ${ this . title } ` )
2023-02-07 22:21:35 +01:00
} else if ( action === 'discardProgress' ) {
this . clearProgressClick ( )
2023-06-17 12:49:24 -05:00
} else if ( action === 'deleteLocal' ) {
this . deleteLocalItem ( )
2023-06-24 14:45:25 -05:00
} else if ( action === 'rssFeed' ) {
this . clickRSSFeed ( )
2022-06-02 17:57:37 -05:00
}
} ,
2023-06-24 14:45:25 -05:00
clickRSSFeed ( ) {
this . $store . commit ( 'globals/setRSSFeedOpenCloseModal' , {
id : this . serverLibraryItemId ,
name : this . title ,
type : 'item' ,
feed : this . rssFeed ,
hasEpisodesWithoutPubDate : this . episodes . some ( ( ep ) => ! ep . pubDate )
} )
} ,
2022-06-02 17:57:37 -05:00
moreButtonPress ( ) {
this . showMoreMenu = true
} ,
2022-03-23 17:59:14 -05:00
readBook ( ) {
2023-05-21 15:02:49 -05:00
if ( this . localLibraryItem ? . media ? . ebookFile ) {
// Has local ebook file
2023-06-11 11:12:52 -05:00
this . $store . commit ( 'showReader' , { libraryItem : this . localLibraryItem , keepProgress : true } )
2023-05-21 15:02:49 -05:00
} else {
2023-06-11 11:12:52 -05:00
this . $store . commit ( 'showReader' , { libraryItem : this . libraryItem , keepProgress : true } )
2023-05-21 15:02:49 -05:00
}
2022-03-23 17:59:14 -05:00
} ,
2023-03-06 15:27:12 -06:00
playAtTimestamp ( seconds ) {
2023-03-06 16:59:49 -06:00
this . play ( seconds )
2023-03-06 15:27:12 -06:00
} ,
2023-05-20 14:49:55 -05:00
async playClick ( ) {
await this . $hapticsImpact ( )
if ( this . playerIsPlaying ) {
this . $eventBus . $emit ( 'pause-item' )
} else {
this . play ( )
}
2023-03-06 16:59:49 -06:00
} ,
async play ( startTime = null ) {
2022-08-11 17:36:27 -05:00
if ( this . isPodcast ) {
this . episodes . sort ( ( a , b ) => {
return String ( b . publishedAt ) . localeCompare ( String ( a . publishedAt ) , undefined , { numeric : true , sensitivity : 'base' } )
} )
2022-12-10 14:26:58 -06:00
let episode = this . episodes . find ( ( ep ) => {
2022-08-11 17:36:27 -05:00
var podcastProgress = null
if ( ! this . isLocal ) {
podcastProgress = this . $store . getters [ 'user/getUserMediaProgress' ] ( this . libraryItemId , ep . id )
} else {
podcastProgress = this . $store . getters [ 'globals/getLocalMediaProgressById' ] ( this . libraryItemId , ep . id )
}
return ! podcastProgress || ! podcastProgress . isFinished
} )
if ( ! episode ) episode = this . episodes [ 0 ]
2023-03-06 15:27:12 -06:00
const episodeId = episode . id
2022-08-11 17:36:27 -05:00
2022-12-10 14:26:58 -06:00
let localEpisode = null
2022-08-11 17:36:27 -05:00
if ( this . hasLocal && ! this . isLocal ) {
localEpisode = this . localLibraryItem . media . episodes . find ( ( ep ) => ep . serverEpisodeId == episodeId )
} else if ( this . isLocal ) {
localEpisode = episode
}
2023-09-11 17:08:15 -05:00
const serverEpisodeId = ! this . isLocal ? episodeId : localEpisode ? . serverEpisodeId || null
2022-08-11 17:36:27 -05:00
if ( serverEpisodeId && this . serverLibraryItemId && this . isCasting ) {
// If casting and connected to server for local library item then send server library item id
this . $eventBus . $emit ( 'play-item' , { libraryItemId : this . serverLibraryItemId , episodeId : serverEpisodeId } )
2023-03-06 15:27:12 -06:00
} else if ( localEpisode ) {
2022-08-11 17:36:27 -05:00
this . $eventBus . $emit ( 'play-item' , { libraryItemId : this . localLibraryItem . id , episodeId : localEpisode . id , serverLibraryItemId : this . serverLibraryItemId , serverEpisodeId } )
2023-03-06 15:27:12 -06:00
} else {
this . $eventBus . $emit ( 'play-item' , { libraryItemId : this . libraryItemId , episodeId } )
2022-08-11 17:36:27 -05:00
}
} else {
// Audiobook
2023-03-06 15:27:12 -06:00
let libraryItemId = this . libraryItemId
// When casting use server library item
2022-08-11 17:36:27 -05:00
if ( this . hasLocal && this . serverLibraryItemId && this . isCasting ) {
2023-03-06 15:27:12 -06:00
libraryItemId = this . serverLibraryItemId
} else if ( this . hasLocal ) {
libraryItemId = this . localLibraryItem . id
2022-08-11 17:36:27 -05:00
}
2023-03-06 15:27:12 -06:00
// If start time and is not already streaming then ask for confirmation
if ( startTime !== null && startTime !== undefined && ! this . $store . getters [ 'getIsMediaStreaming' ] ( libraryItemId , null ) ) {
const { value } = await Dialog . confirm ( {
title : 'Confirm' ,
message : ` Start playback for " ${ this . title } " at ${ this . $secondsToTimestamp ( startTime ) } ? `
} )
if ( ! value ) return
2022-08-11 17:36:27 -05:00
}
2023-03-06 15:27:12 -06:00
this . $eventBus . $emit ( 'play-item' , { libraryItemId , serverLibraryItemId : this . serverLibraryItemId , startTime } )
}
2022-03-23 17:59:14 -05:00
} ,
async clearProgressClick ( ) {
2023-01-08 15:32:15 -06:00
await this . $hapticsImpact ( )
2023-01-13 17:30:48 -06:00
2022-03-23 17:59:14 -05:00
const { value } = await Dialog . confirm ( {
title : 'Confirm' ,
message : 'Are you sure you want to reset your progress?'
} )
if ( value ) {
this . resettingProgress = true
2023-05-20 16:29:54 -05:00
const serverMediaProgressId = this . serverItemProgress ? . id
if ( this . localLibraryItemId ) {
await this . $db . removeLocalMediaProgress ( this . localLibraryItemId )
this . $store . commit ( 'globals/removeLocalMediaProgressForItem' , this . localLibraryItemId )
}
if ( this . serverLibraryItemId && serverMediaProgressId ) {
2023-09-17 12:43:50 -05:00
await this . $nativeHttp
. delete ( ` /api/me/progress/ ${ serverMediaProgressId } ` )
2022-04-09 12:03:37 -05:00
. then ( ( ) => {
console . log ( 'Progress reset complete' )
this . $toast . success ( ` Your progress was reset ` )
2023-05-20 16:29:54 -05:00
this . $store . commit ( 'user/removeMediaProgress' , serverMediaProgressId )
2022-04-09 12:03:37 -05:00
} )
. catch ( ( error ) => {
console . error ( 'Progress reset failed' , error )
} )
}
this . resettingProgress = false
2022-03-23 17:59:14 -05:00
}
} ,
itemUpdated ( libraryItem ) {
2023-06-24 14:45:25 -05:00
if ( libraryItem . id === this . serverLibraryItemId ) {
2022-03-23 17:59:14 -05:00
console . log ( 'Item Updated' )
this . libraryItem = libraryItem
2023-03-06 15:27:12 -06:00
this . checkDescriptionClamped ( )
2022-03-23 17:59:14 -05:00
}
} ,
2022-04-02 19:43:43 -05:00
async selectFolder ( ) {
// Select and save the local folder for media type
2022-04-04 19:08:27 -05:00
var folderObj = await AbsFileSystem . selectFolder ( { mediaType : this . mediaType } )
2022-04-02 19:43:43 -05:00
if ( folderObj . error ) {
return this . $toast . error ( ` Error: ${ folderObj . error || 'Unknown Error' } ` )
}
return folderObj
} ,
selectedLocalFolder ( localFolder ) {
this . showSelectLocalFolder = false
this . download ( localFolder )
} ,
2022-12-08 00:28:28 -05:00
async downloadClick ( ) {
2022-04-07 18:46:58 -05:00
if ( this . downloadItem ) {
return
}
2023-01-08 15:32:15 -06:00
await this . $hapticsImpact ( )
2022-05-14 09:08:52 -05:00
if ( this . isIos ) {
// no local folders on iOS
this . startDownload ( )
} else {
this . download ( )
}
} ,
async download ( selectedLocalFolder = null ) {
2022-04-02 19:43:43 -05:00
// Get the local folder to download to
2023-06-04 14:59:55 -05:00
let localFolder = selectedLocalFolder
2022-04-02 19:43:43 -05:00
if ( ! localFolder ) {
2023-06-04 14:59:55 -05:00
const localFolders = ( await this . $db . getLocalFolders ( ) ) || [ ]
2022-04-02 19:43:43 -05:00
console . log ( 'Local folders loaded' , localFolders . length )
2023-06-04 14:59:55 -05:00
const foldersWithMediaType = localFolders . filter ( ( lf ) => {
2022-04-02 19:43:43 -05:00
console . log ( 'Checking local folder' , lf . mediaType )
return lf . mediaType == this . mediaType
} )
console . log ( 'Folders with media type' , this . mediaType , foldersWithMediaType . length )
2023-06-04 14:59:55 -05:00
const internalStorageFolder = foldersWithMediaType . find ( ( f ) => f . id === ` internal- ${ this . mediaType } ` )
2022-04-02 19:43:43 -05:00
if ( ! foldersWithMediaType . length ) {
2023-06-03 17:24:32 -05:00
localFolder = {
id : ` internal- ${ this . mediaType } ` ,
2023-06-04 14:59:55 -05:00
name : 'Internal App Storage' ,
2023-06-03 17:24:32 -05:00
mediaType : this . mediaType
}
2023-06-04 14:59:55 -05:00
} else if ( foldersWithMediaType . length === 1 && internalStorageFolder ) {
localFolder = internalStorageFolder
2022-04-02 19:43:43 -05:00
} else {
2023-06-04 14:59:55 -05:00
this . $store . commit ( 'globals/showSelectLocalFolderModal' , {
mediaType : this . mediaType ,
callback : ( folder ) => {
this . download ( folder )
}
} )
2022-04-02 19:43:43 -05:00
return
}
}
console . log ( 'Local folder' , JSON . stringify ( localFolder ) )
2023-05-21 15:02:49 -05:00
let startDownloadMessage = ` Start download for " ${ this . title } " with ${ this . numTracks } audio track ${ this . numTracks == 1 ? '' : 's' } to folder ${ localFolder . name } ? `
if ( ! this . isIos && this . showRead ) {
if ( this . numTracks > 0 ) {
startDownloadMessage = ` Start download for " ${ this . title } " with ${ this . numTracks } audio track ${ this . numTracks == 1 ? '' : 's' } and ebook file to folder ${ localFolder . name } ? `
} else {
startDownloadMessage = ` Start download for " ${ this . title } " with ebook file to folder ${ localFolder . name } ? `
}
}
2022-04-02 19:43:43 -05:00
const { value } = await Dialog . confirm ( {
title : 'Confirm' ,
message : startDownloadMessage
} )
if ( value ) {
this . startDownload ( localFolder )
}
} ,
2022-05-14 09:08:52 -05:00
async startDownload ( localFolder = null ) {
const payload = {
libraryItemId : this . libraryItemId
}
if ( localFolder ) {
console . log ( 'Starting download to local folder' , localFolder . name )
payload . localFolderId = localFolder . id
}
var downloadRes = await AbsDownloader . downloadLibraryItem ( payload )
2022-04-07 18:46:58 -05:00
if ( downloadRes && downloadRes . error ) {
2022-04-02 19:43:43 -05:00
var errorMsg = downloadRes . error || 'Unknown error'
console . error ( 'Download error' , errorMsg )
2022-04-03 19:16:17 -05:00
this . $toast . error ( errorMsg )
2022-03-23 17:59:14 -05:00
}
2022-04-07 18:46:58 -05:00
} ,
newLocalLibraryItem ( item ) {
if ( item . libraryItemId == this . libraryItemId ) {
console . log ( 'New local library item' , item . id )
this . $set ( this . libraryItem , 'localLibraryItem' , item )
}
2022-04-23 00:27:03 -04:00
} ,
2022-04-24 22:02:22 -04:00
async toggleFinished ( ) {
2023-01-08 15:32:15 -06:00
await this . $hapticsImpact ( )
2023-01-13 17:30:48 -06:00
// Show confirm if item has progress since it will reset
if ( this . userItemProgress && this . userItemProgress . progress > 0 && ! this . userIsFinished ) {
const { value } = await Dialog . confirm ( {
title : 'Confirm' ,
message : 'Are you sure you want to mark this item as Finished?'
} )
if ( ! value ) return
}
2022-04-23 00:27:03 -04:00
this . isProcessingReadUpdate = true
2022-04-28 13:21:47 -04:00
if ( this . isLocal ) {
2023-06-18 14:26:04 -05:00
const isFinished = ! this . userIsFinished
const payload = await this . $db . updateLocalMediaProgressFinished ( { localLibraryItemId : this . localLibraryItemId , isFinished } )
2022-04-24 22:02:22 -04:00
console . log ( 'toggleFinished payload' , JSON . stringify ( payload ) )
2023-06-18 14:26:04 -05:00
if ( payload ? . error ) {
this . $toast . error ( payload ? . error || 'Unknown error' )
2022-04-24 22:02:22 -04:00
} else {
2023-06-18 14:26:04 -05:00
const localMediaProgress = payload . localMediaProgress
2022-04-24 22:02:22 -04:00
console . log ( 'toggleFinished localMediaProgress' , JSON . stringify ( localMediaProgress ) )
if ( localMediaProgress ) {
this . $store . commit ( 'globals/updateLocalMediaProgress' , localMediaProgress )
}
}
this . isProcessingReadUpdate = false
} else {
2023-06-18 14:26:04 -05:00
const updatePayload = {
2022-04-24 22:02:22 -04:00
isFinished : ! this . userIsFinished
}
2023-09-17 12:43:50 -05:00
this . $nativeHttp
. patch ( ` /api/me/progress/ ${ this . libraryItemId } ` , updatePayload )
2022-04-24 22:02:22 -04:00
. catch ( ( error ) => {
console . error ( 'Failed' , error )
this . $toast . error ( ` Failed to mark as ${ updatePayload . isFinished ? 'Finished' : 'Not Finished' } ` )
} )
2023-06-18 14:26:04 -05:00
. finally ( ( ) => {
this . isProcessingReadUpdate = false
} )
2022-04-24 22:02:22 -04:00
}
2022-08-25 17:58:29 -05:00
} ,
libraryChanged ( libraryId ) {
if ( this . libraryItem . libraryId !== libraryId ) {
this . $router . replace ( '/bookshelf' )
}
2023-01-12 17:04:47 -06:00
} ,
2023-03-06 15:27:12 -06:00
checkDescriptionClamped ( ) {
2023-03-06 15:51:11 -06:00
if ( this . showFullDescription ) return
if ( ! this . $refs . description ) {
this . descriptionClamped = false
} else {
this . descriptionClamped = this . $refs . description . scrollHeight > this . $refs . description . clientHeight
}
2023-03-06 15:27:12 -06:00
} ,
2023-01-12 17:04:47 -06:00
windowResized ( ) {
this . windowWidth = window . innerWidth
2023-03-06 15:27:12 -06:00
this . checkDescriptionClamped ( )
2023-06-24 14:45:25 -05:00
} ,
rssFeedOpen ( data ) {
if ( data . entityId === this . serverLibraryItemId ) {
console . log ( 'RSS Feed Opened' , data )
this . rssFeed = data
}
} ,
rssFeedClosed ( data ) {
if ( data . entityId === this . serverLibraryItemId ) {
console . log ( 'RSS Feed Closed' , data )
this . rssFeed = null
}
2023-09-11 17:08:15 -05:00
} ,
async setLibrary ( ) {
if ( ! this . libraryItem . libraryId ) return
await this . $store . dispatch ( 'libraries/fetch' , this . libraryItem . libraryId )
this . $localStore . setLastLibraryId ( this . libraryItem . libraryId )
2022-04-24 22:02:22 -04:00
}
2022-03-23 17:59:14 -05:00
} ,
mounted ( ) {
2023-09-11 17:08:15 -05:00
// If library of this item is different from current library then switch libraries
if ( this . $store . state . libraries . currentLibraryId !== this . libraryItem . libraryId ) {
this . setLibrary ( )
}
2023-01-12 17:04:47 -06:00
this . windowWidth = window . innerWidth
window . addEventListener ( 'resize' , this . windowResized )
2022-08-25 17:58:29 -05:00
this . $eventBus . $on ( 'library-changed' , this . libraryChanged )
2022-04-07 18:46:58 -05:00
this . $eventBus . $on ( 'new-local-library-item' , this . newLocalLibraryItem )
2022-12-10 10:12:58 -06:00
this . $socket . $on ( 'item_updated' , this . itemUpdated )
2023-06-24 14:45:25 -05:00
this . $socket . $on ( 'rss_feed_open' , this . rssFeedOpen )
this . $socket . $on ( 'rss_feed_closed' , this . rssFeedClosed )
2023-03-06 15:27:12 -06:00
this . checkDescriptionClamped ( )
2023-06-04 15:52:36 -05:00
// Set last scroll position if was set for this item
if ( this . $store . state . lastItemScrollData . id === this . libraryItemId && window [ 'item-page' ] ) {
window [ 'item-page' ] . scrollTop = this . $store . state . lastItemScrollData . scrollTop || 0
}
2022-03-23 17:59:14 -05:00
} ,
beforeDestroy ( ) {
2023-01-12 17:04:47 -06:00
window . removeEventListener ( 'resize' , this . windowResized )
2022-08-25 17:58:29 -05:00
this . $eventBus . $off ( 'library-changed' , this . libraryChanged )
2022-04-07 18:46:58 -05:00
this . $eventBus . $off ( 'new-local-library-item' , this . newLocalLibraryItem )
2022-12-10 10:12:58 -06:00
this . $socket . $off ( 'item_updated' , this . itemUpdated )
2023-06-24 14:45:25 -05:00
this . $socket . $off ( 'rss_feed_open' , this . rssFeedOpen )
this . $socket . $off ( 'rss_feed_closed' , this . rssFeedClosed )
2023-06-04 15:52:36 -05:00
// Set scroll position
if ( window [ 'item-page' ] ) {
this . $store . commit ( 'setLastItemScrollData' , { scrollTop : window [ 'item-page' ] . scrollTop || 0 , id : this . libraryItemId } )
}
2022-03-23 17:59:14 -05:00
}
}
2022-06-02 17:57:37 -05:00
< / script >
< style >
. title - container {
width : calc ( 100 % - 64 px ) ;
max - width : calc ( 100 % - 64 px ) ;
}
2023-02-09 23:57:59 +01:00
# coverBg > div {
width : 150 vw ! important ;
max - width : 150 vw ! important ;
}
2023-02-26 12:59:44 +01:00
@ media only screen and ( max - width : 500 px ) {
# metadata {
grid - template - columns : auto 1 fr ;
}
}
@ media only screen and ( min - width : 500 px ) {
# metadata {
grid - template - columns : auto 1 fr auto 1 fr ;
}
}
2022-12-08 00:28:28 -05:00
< / style >