2022-03-23 17:59:14 -05:00
< template >
2023-01-11 18:00:05 -06:00
< div class = "w-full h-full px-3 py-4 overflow-y-auto 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-01-13 17:30:48 -06:00
< div class = "w-full flex justify-center relative mb-4" >
2023-01-11 18:00:05 -06:00
< div class = "relative" @ click = "showFullscreenCover = true" >
2023-01-12 17:04:47 -06:00
< covers-book-cover :library-item = "libraryItem" :width = "coverWidth" :book-cover-aspect-ratio = "bookCoverAspectRatio" @imageLoaded ="coverImageLoaded" / >
< 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-01-13 17:30:48 -06:00
< h1 class = "text-xl font-semibold" > { { title } } < / h1 >
2022-03-23 17:59:14 -05:00
2023-01-13 17:30:48 -06:00
< p v-if = "subtitle" class="text-gray-100 text-base py-0.5 mb-0.5" > {{ subtitle }} < / p >
2022-12-03 17:43:47 -06:00
2023-01-11 18:00:05 -06:00
< p v-if = "seriesList && seriesList.length" class="text-sm text-gray-300 py-0.5" >
2023-01-30 07:57:34 -06:00
< template v-for = "(series, index) in seriesList" >
2023-02-04 15:52:06 -06:00
< nuxt-link :key = "series.id" :to = "`/bookshelf/series/${series.id}`" class = "underline" > { { series . text } } < / n u x t - l i n k
> < span :key = "`${series.id}-comma`" v-if = "index < seriesList.length - 1" > , & nbsp ; < / span >
2023-01-30 07:57:34 -06:00
< / template >
2023-01-11 18:00:05 -06:00
< / p >
2022-12-03 17:43:47 -06:00
2023-01-11 18:00:05 -06:00
< p v-if = "podcastAuthor" class="text-sm text-gray-300 py-0.5" > by {{ podcastAuthor }} < / p >
< p v -else -if = " bookAuthors & & bookAuthors.length " class = "text-sm text-gray-300 py-0.5" >
by
2023-01-30 07:57:34 -06:00
< template v-for = "(author, index) in bookAuthors" >
2023-02-04 15:52:06 -06: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
> < span :key = "`${author.id}-comma`" v-if = "index < bookAuthors.length - 1" > , & nbsp ; < / span >
2023-01-30 07:57:34 -06:00
< / template >
2023-01-11 18:00:05 -06:00
< / p >
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 -- >
< p v-if = "isLocal && serverLibraryItemId" style="font-size: 10px" class="text-success py-1 uppercase tracking-widest" > connected < / p >
< p v -else -if = " isLocal & & libraryItem.serverAddress " style = "font-size: 10px" class = "text-gray-400 py-1" > { { libraryItem . serverAddress } } < / p >
2022-06-02 17:57:37 -05:00
2023-01-13 17:30:48 -06:00
<!-- action buttons -- >
< div >
< div v-if = "!isPodcast && progressPercent > 0" class="px-4 py-2 bg-primary text-sm font-semibold rounded-md text-gray-200 mt-4 relative" :class="resettingProgress ? 'opacity-25' : ''" >
< p class = "leading-6" > Your Progress : { { Math . round ( progressPercent * 100 ) } } % < / p >
< p v-if = "progressPercent < 1" class="text-gray-400 text-xs" > {{ $ elapsedPretty ( userTimeRemaining ) }} remaining < / p >
< p v -else class = "text-gray-400 text-xs" > Finished { { $formatDate ( userProgressFinishedAt ) } } < / p >
< / div >
< div v-if = "isLocal" class="flex mt-4 -mx-1" >
< ui-btn v-if = "showPlay" color="success" :disabled="isPlaying" class="flex items-center justify-center flex-grow mx-1" :padding-x="4" @click="playClick" >
< span v-show = "!isPlaying" class="material-icons" > play_arrow < / span >
< span class = "px-1 text-sm" > { { isPlaying ? 'Playing' : 'Play' } } < / span >
< / 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 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 >
< div v -else -if = " ( user & & ( showPlay | | showRead ) ) | | hasLocal " class = "flex mt-4 -mx-1" >
< ui-btn v-if = "showPlay" color="success" :disabled="isPlaying" class="flex items-center justify-center flex-grow mx-1" :padding-x="4" @click="playClick" >
< span v-show = "!isPlaying" class="material-icons" > play_arrow < / span >
< span class = "px-1 text-sm" > { { isPlaying ? ( isStreaming ? 'Streaming' : 'Playing' ) : isPodcast ? 'Next Episode' : hasLocal ? 'Play' : 'Stream' } } < / span >
< / ui-btn >
< ui-btn v-if = "showRead && user" 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 >
< / 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 -- >
< div class = "grid gap-2 my-4" style = "grid-template-columns: max-content auto" >
< div v-if = "narrators && narrators.length" class="text-white text-opacity-60 uppercase text-sm" > Narrators < / div >
< div v-if = "narrators && narrators.length" class="truncate text-sm" >
< template v-for = "(narrator, index) in narrators" >
2023-02-04 15:52:06 -06:00
< nuxt-link :key = "narrator" :to = "`/bookshelf/library?filter=narrators.${$encode(narrator)}`" class = "underline" > { { narrator } } < / n u x t - l i n k
> < 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-01-11 18:00:05 -06:00
< div v-if = "publishedYear" class="text-white text-opacity-60 uppercase text-sm" > Published < / div >
2023-01-30 07:57:34 -06:00
< div v-if = "publishedYear" class="text-sm" > {{ publishedYear }} < / div >
2023-01-08 17:04:08 +01:00
2023-01-11 18:00:05 -06:00
< div v-if = "genres.length" class="text-white text-opacity-60 uppercase text-sm" > Genres < / div >
< div v-if = "genres.length" class="truncate text-sm" >
< template v-for = "(genre, index) in genres" >
2023-02-04 15:52:06 -06:00
< nuxt-link :key = "genre" :to = "`/bookshelf/library?filter=genres.${$encode(genre)}`" class = "underline" > { { genre } } < / n u x t - l i n k
> < span :key = "index" v-if = "index < genres.length - 1" > , < / span >
2023-01-11 18:00:05 -06:00
< / template >
< / div >
2022-12-03 17:43:47 -06:00
< / div >
2023-01-08 17:04:08 +01:00
2023-01-11 18:00:05 -06:00
< div v-if = "numTracks" class="flex text-gray-100 text-xs my-2 -mx-0.5" >
< div class = "bg-primary bg-opacity-80 px-3 py-0.5 rounded-full mx-0.5" >
< p > { { $elapsedPretty ( duration ) } } < / p >
< / div >
<!-- TODO : Local books dont save the size -- >
< div v-if = "size" class="bg-primary bg-opacity-80 px-3 py-0.5 rounded-full mx-0.5" >
< p > { { $bytesPretty ( size ) } } < / p >
< / div >
< div class = "bg-primary bg-opacity-80 px-3 py-0.5 rounded-full mx-0.5" >
< p > { { numTracks } } Track { { numTracks > 1 ? 's' : '' } } < / p >
< / div >
< div v-if = "numChapters" class="bg-primary bg-opacity-80 px-3 py-0.5 rounded-full mx-0.5" >
< p > { { numChapters } } Chapter { { numChapters > 1 ? 's' : '' } } < / p >
< / div >
2022-12-03 17:43:47 -06:00
< / div >
2023-01-11 18:00:05 -06:00
< div class = "w-full py-4" >
< p class = "text-sm" > { { description } } < / p >
< / div >
2022-04-02 19:43:43 -05:00
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-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 } ) {
var libraryItemId = params . id
var libraryItem = null
2022-04-08 18:07:31 -05:00
console . log ( libraryItemId )
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 ) {
2022-03-23 17:59:14 -05:00
libraryItem = await app . $axios . $get ( ` /api/items/ ${ libraryItemId } ?expanded=1 ` ) . catch ( ( error ) => {
console . error ( 'Failed' , error )
return false
} )
2022-04-07 18:46:58 -05:00
// Check if
if ( libraryItem ) {
2022-07-13 16:44:02 -05:00
var 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 {
libraryItem
}
} ,
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 ,
windowWidth : 0
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' ]
} ,
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 ( ) {
return this . localLibraryItem ? this . localLibraryItem . id : null
} ,
localLibraryItemEpisodes ( ) {
if ( ! this . isPodcast || ! this . localLibraryItem ) return [ ]
var podcastMedia = this . localLibraryItem . media
return podcastMedia ? podcastMedia . episodes || [ ] : [ ]
} ,
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
} ,
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
} ,
size ( ) {
2022-03-28 19:53:53 -05:00
return this . media . size
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
2022-04-09 12:03:37 -05:00
if ( this . isLocal ) return this . $store . getters [ 'globals/getLocalMediaProgressById' ] ( this . libraryItemId )
2022-04-08 19:05:32 -05:00
return this . $store . getters [ 'user/getUserMediaProgress' ] ( this . libraryItemId )
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
} ,
progressPercent ( ) {
return this . userItemProgress ? Math . max ( Math . min ( 1 , this . userItemProgress . progress ) , 0 ) : 0
} ,
userProgressStartedAt ( ) {
return this . userItemProgress ? this . userItemProgress . startedAt : 0
} ,
userProgressFinishedAt ( ) {
return this . userItemProgress ? this . userItemProgress . finishedAt : 0
} ,
isStreaming ( ) {
2022-04-10 20:31:47 -05:00
return this . isPlaying && ! this . $store . state . playerIsLocal
2022-03-23 17:59:14 -05:00
} ,
isPlaying ( ) {
2023-01-08 14:50:21 -06:00
if ( this . localLibraryItemId && this . $store . getters [ 'getIsItemStreaming' ] ( this . localLibraryItemId ) ) return true
2022-04-10 20:31:47 -05:00
return this . $store . getters [ 'getIsItemStreaming' ] ( this . libraryItemId )
2022-03-23 17:59:14 -05:00
} ,
numTracks ( ) {
2022-03-28 19:53:53 -05:00
if ( ! this . media . tracks ) return 0
return this . media . 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
} ,
isIncomplete ( ) {
return this . libraryItem . isIncomplete
} ,
showPlay ( ) {
2022-08-11 17:36:27 -05:00
return ! this . isMissing && ! this . isIncomplete && ( 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 ( ) {
2022-08-11 17:36:27 -05:00
if ( this . isPodcast ) return false
2022-05-22 15:49:42 -05:00
return this . user && this . userCanDownload && this . showPlay && ! this . hasLocal
} ,
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
} ,
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' ,
value : 'history'
} )
}
2023-01-13 17:30:48 -06:00
items . push ( {
text : this . userIsFinished ? 'Mark as Not Finished' : 'Mark as Finished' ,
value : 'markFinished'
} )
2023-02-07 22:21:35 +01:00
if ( this . progressPercent > 0 && ! this . userIsFinished ) {
items . push ( {
text : 'Discard Progress' ,
value : 'discardProgress'
} )
}
2023-01-13 17:30:48 -06:00
}
2022-12-10 14:26:58 -06:00
if ( this . localLibraryItemId ) {
items . push ( {
text : 'Manage Local Files' ,
value : 'manageLocal'
} )
}
2022-12-03 17:05:43 -06:00
2022-12-10 14:26:58 -06:00
if ( ! this . isPodcast && this . serverLibraryItemId ) {
items . push ( {
text : 'Add to Playlist' ,
value : 'playlist'
} )
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' ,
value : 'details'
} )
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-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 ( )
2022-06-02 17:57:37 -05:00
}
} ,
moreButtonPress ( ) {
this . showMoreMenu = true
} ,
2022-03-23 17:59:14 -05:00
readBook ( ) {
this . $store . commit ( 'openReader' , this . libraryItem )
} ,
2022-12-08 00:28:28 -05:00
async playClick ( ) {
2022-12-10 14:26:58 -06:00
let episodeId = null
2023-01-08 15:32:15 -06:00
await this . $hapticsImpact ( )
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 ]
episodeId = episode . id
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
}
2022-12-10 14:26:58 -06:00
const serverEpisodeId = ! this . isLocal ? episodeId : localEpisode ? 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 } )
return
}
if ( localEpisode ) {
this . $eventBus . $emit ( 'play-item' , { libraryItemId : this . localLibraryItem . id , episodeId : localEpisode . id , serverLibraryItemId : this . serverLibraryItemId , serverEpisodeId } )
return
}
} else {
// Audiobook
if ( this . hasLocal && 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 } )
return
}
if ( this . hasLocal ) {
this . $eventBus . $emit ( 'play-item' , { libraryItemId : this . localLibraryItem . id , serverLibraryItemId : this . serverLibraryItemId } )
return
}
2022-05-04 19:31:56 -05:00
}
2022-08-11 17:36:27 -05:00
this . $eventBus . $emit ( 'play-item' , { libraryItemId : this . libraryItemId , episodeId } )
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
2022-04-09 12:03:37 -05:00
if ( this . isLocal ) {
2022-04-09 20:29:59 -05:00
// TODO: If connected to server also sync with server
2022-04-09 12:03:37 -05:00
await this . $db . removeLocalMediaProgress ( this . libraryItemId )
2022-06-01 19:38:26 -05:00
this . $store . commit ( 'globals/removeLocalMediaProgressForItem' , this . libraryItemId )
2022-04-09 12:03:37 -05:00
} else {
2022-04-09 20:29:59 -05:00
var progressId = this . userItemProgress . id
2022-04-09 12:03:37 -05:00
await this . $axios
. $delete ( ` /api/me/progress/ ${ this . libraryItemId } ` )
. then ( ( ) => {
console . log ( 'Progress reset complete' )
this . $toast . success ( ` Your progress was reset ` )
2022-04-09 20:29:59 -05:00
this . $store . commit ( 'user/removeMediaProgress' , progressId )
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 ) {
if ( libraryItem . id === this . libraryItemId ) {
console . log ( 'Item Updated' )
this . libraryItem = libraryItem
}
} ,
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
}
2022-04-03 17:07:26 -05:00
if ( ! this . numTracks ) {
2022-04-02 19:43:43 -05:00
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
var localFolder = selectedLocalFolder
if ( ! localFolder ) {
2022-04-03 14:24:17 -05:00
var localFolders = ( await this . $db . getLocalFolders ( ) ) || [ ]
2022-04-02 19:43:43 -05:00
console . log ( 'Local folders loaded' , localFolders . length )
var foldersWithMediaType = localFolders . filter ( ( lf ) => {
console . log ( 'Checking local folder' , lf . mediaType )
return lf . mediaType == this . mediaType
} )
console . log ( 'Folders with media type' , this . mediaType , foldersWithMediaType . length )
if ( ! foldersWithMediaType . length ) {
// No local folders or no local folders with this media type
localFolder = await this . selectFolder ( )
} else if ( foldersWithMediaType . length == 1 ) {
console . log ( 'Only 1 local folder with this media type - auto select it' )
localFolder = foldersWithMediaType [ 0 ]
} else {
console . log ( 'Multiple folders with media type' )
this . showSelectLocalFolder = true
return
}
if ( ! localFolder ) {
return this . $toast . error ( 'Invalid download folder' )
}
}
console . log ( 'Local folder' , JSON . stringify ( localFolder ) )
var startDownloadMessage = ` Start download for " ${ this . title } " with ${ this . numTracks } audio track ${ this . numTracks == 1 ? '' : 's' } to folder ${ localFolder . name } ? `
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 ) {
2022-04-24 22:02:22 -04:00
var isFinished = ! this . userIsFinished
2022-04-30 15:35:20 -05:00
var payload = await this . $db . updateLocalMediaProgressFinished ( { localLibraryItemId : this . localLibraryItemId , isFinished } )
2022-04-24 22:02:22 -04:00
console . log ( 'toggleFinished payload' , JSON . stringify ( payload ) )
if ( ! payload || payload . error ) {
var errorMsg = payload ? payload . error : 'Unknown error'
this . $toast . error ( errorMsg )
} else {
var localMediaProgress = payload . localMediaProgress
console . log ( 'toggleFinished localMediaProgress' , JSON . stringify ( localMediaProgress ) )
if ( localMediaProgress ) {
this . $store . commit ( 'globals/updateLocalMediaProgress' , localMediaProgress )
}
var lmp = this . $store . getters [ 'globals/getLocalMediaProgressById' ] ( this . libraryItemId )
console . log ( 'toggleFinished Check LMP' , this . libraryItemId , JSON . stringify ( lmp ) )
var serverUpdated = payload . server
if ( serverUpdated ) {
this . $toast . success ( ` Local & Server Item marked as ${ isFinished ? 'Finished' : 'Not Finished' } ` )
} else {
this . $toast . success ( ` Local Item marked as ${ isFinished ? 'Finished' : 'Not Finished' } ` )
}
}
this . isProcessingReadUpdate = false
} else {
var updatePayload = {
isFinished : ! this . userIsFinished
}
this . $axios
. $patch ( ` /api/me/progress/ ${ this . libraryItemId } ` , updatePayload )
. then ( ( ) => {
this . isProcessingReadUpdate = false
this . $toast . success ( ` Item marked as ${ updatePayload . isFinished ? 'Finished' : 'Not Finished' } ` )
} )
. catch ( ( error ) => {
console . error ( 'Failed' , error )
this . isProcessingReadUpdate = false
this . $toast . error ( ` Failed to mark as ${ updatePayload . isFinished ? 'Finished' : 'Not Finished' } ` )
} )
}
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
} ,
windowResized ( ) {
this . windowWidth = window . innerWidth
2022-04-24 22:02:22 -04:00
}
2022-03-23 17:59:14 -05:00
} ,
mounted ( ) {
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 )
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 )
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 ) ;
}
2022-12-08 00:28:28 -05:00
< / style >