2022-03-27 22:37:04 +02:00
< template >
< modals -modal v-model ="show" name="podcast-episodes-modal" :width="1200" :height="'unset'" :processing ="processing" >
< template # outer >
< div class = "absolute top-0 left-0 p-5 w-2/3 overflow-hidden" >
2023-02-11 22:02:56 +01:00
< p class = "text-3xl text-white truncate" > { { title } } < / p >
2022-03-27 22:37:04 +02:00
< / div >
< / template >
< div ref = "wrapper" id = "podcast-wrapper" class = "p-4 w-full text-sm py-2 rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden" >
2023-02-21 20:30:42 +01:00
< div v-if ="episodes.length" class="w-full py-3 mx-auto flex" >
2023-02-19 21:07:32 +01:00
< form @submit.prevent ="submit" class = "flex flex-grow" >
2023-02-21 20:30:42 +01:00
< ui -text -input v -model = " search " @input ="inputUpdate" type = "search" :placeholder ="$strings.PlaceholderSearchEpisode" class = "flex-grow mr-2 text-sm md:text-base" / >
2023-02-19 21:07:32 +01:00
< / form >
< / div >
2022-03-27 22:37:04 +02:00
< div ref = "episodeContainer" id = "episodes-scroll" class = "w-full overflow-x-hidden overflow-y-auto" >
< div
2023-02-19 21:07:32 +01:00
v - for = "(episode, index) in episodesList"
2022-03-27 22:37:04 +02:00
: key = "index"
class = "relative"
2023-03-21 23:59:37 +01:00
: class = "itemEpisodeMap[episode.enclosure.url?.split('?')[0]] ? 'bg-primary bg-opacity-40' : selectedEpisodes[String(index)] ? 'cursor-pointer bg-success bg-opacity-10' : index % 2 == 0 ? 'cursor-pointer bg-primary bg-opacity-25 hover:bg-opacity-40' : 'cursor-pointer bg-primary bg-opacity-5 hover:bg-opacity-25'"
2022-08-28 15:48:41 +02:00
@ click = "toggleSelectEpisode(index, episode)"
2022-03-27 22:37:04 +02:00
>
< div class = "absolute top-0 left-0 h-full flex items-center p-2" >
2023-03-21 23:59:37 +01:00
< span v-if ="itemEpisodeMap[episode.enclosure.url?.split('?')[0]]" class="material-icons text-success text-xl" > download_done < / span >
2022-08-28 15:48:41 +02:00
< ui -checkbox v -else v -model = " selectedEpisodes [ String ( index ) ] " small checkbox -bg = " primary " border -color = " gray -600 " / >
2022-03-27 22:37:04 +02:00
< / div >
< div class = "px-8 py-2" >
2023-02-27 03:56:07 +01:00
< div class = "flex items-center font-semibold text-gray-200" >
< div v-if ="episode.season || episode.episode" > # < / div >
< div v-if ="episode.season" > {{ episode.season }} x < / div >
< div v-if ="episode.episode" > {{ episode.episode }} < / div >
< / div >
< div class = "flex items-center mb-1" >
< div class = "break-words" > { { episode . title } } < / div >
< widgets -podcast -type -indicator :type ="episode.episodeType" / >
< / div >
2022-03-27 22:37:04 +02:00
< p v-if ="episode.subtitle" class="break-words mb-1 text-sm text-gray-300 episode-subtitle" > {{ episode.subtitle }} < / p >
< p class = "text-xs text-gray-300" > Published { { episode . publishedAt ? $dateDistanceFromNow ( episode . publishedAt ) : 'Unknown' } } < / p >
< / div >
< / div >
< / div >
< div class = "flex justify-end pt-4" >
2022-08-28 15:48:41 +02:00
< ui -checkbox v -if = " ! allDownloaded " v -model = " selectAll " @input ="toggleSelectAll" label = "Select all episodes" small checkbox -bg = " primary " border -color = " gray -600 " class = "mx-8" / >
< ui -btn v-if ="!allDownloaded" :disabled="!episodesSelected.length" @click="submit" > {{ buttonText }} < / ui -btn >
< p v -else class = "text-success text-base px-2 py-4" > All episodes are downloaded < / p >
2022-03-27 22:37:04 +02:00
< / div >
< / div >
< / m o d a l s - m o d a l >
< / template >
< script >
export default {
props : {
value : Boolean ,
libraryItem : {
type : Object ,
default : ( ) => { }
} ,
episodes : {
type : Array ,
default : ( ) => [ ]
}
} ,
data ( ) {
return {
processing : false ,
2022-08-28 15:48:41 +02:00
selectedEpisodes : { } ,
2023-02-19 21:07:32 +01:00
selectAll : false ,
search : null ,
searchTimeout : null ,
2023-03-21 23:59:37 +01:00
searchText : null
2022-03-27 22:37:04 +02:00
}
} ,
2022-04-10 18:01:50 +02:00
watch : {
show : {
immediate : true ,
handler ( newVal ) {
if ( newVal ) this . init ( )
}
}
} ,
2022-03-27 22:37:04 +02:00
computed : {
show : {
get ( ) {
return this . value
} ,
set ( val ) {
this . $emit ( 'input' , val )
}
} ,
title ( ) {
if ( ! this . libraryItem ) return ''
return this . libraryItem . media . metadata . title || 'Unknown'
} ,
2022-04-09 11:44:31 +02:00
allDownloaded ( ) {
2023-03-21 23:59:37 +01:00
return ! this . episodes . some ( ( episode ) => ! this . itemEpisodeMap [ episode . enclosure . url ? . split ( '?' ) [ 0 ] ] )
2022-04-09 11:44:31 +02:00
} ,
2022-03-27 22:37:04 +02:00
episodesSelected ( ) {
return Object . keys ( this . selectedEpisodes ) . filter ( ( key ) => ! ! this . selectedEpisodes [ key ] )
} ,
buttonText ( ) {
if ( ! this . episodesSelected . length ) return 'No Episodes Selected'
return ` Download ${ this . episodesSelected . length } Episode ${ this . episodesSelected . length > 1 ? 's' : '' } `
} ,
itemEpisodes ( ) {
if ( ! this . libraryItem ) return [ ]
return this . libraryItem . media . episodes || [ ]
} ,
itemEpisodeMap ( ) {
var map = { }
this . itemEpisodes . forEach ( ( item ) => {
2023-03-21 23:59:37 +01:00
if ( item . enclosure ) map [ item . enclosure . url . split ( '?' ) [ 0 ] ] = true
2022-03-27 22:37:04 +02:00
} )
return map
2023-02-19 21:07:32 +01:00
} ,
episodesList ( ) {
return this . episodes . filter ( ( episode ) => {
if ( ! this . searchText ) return true
2023-03-21 23:59:37 +01:00
return ( episode . title && episode . title . toLowerCase ( ) . includes ( this . searchText ) ) || ( episode . subtitle && episode . subtitle . toLowerCase ( ) . includes ( this . searchText ) )
2023-02-19 21:07:32 +01:00
} )
2022-03-27 22:37:04 +02:00
}
} ,
methods : {
2023-02-19 21:07:32 +01:00
inputUpdate ( ) {
clearTimeout ( this . searchTimeout )
this . searchTimeout = setTimeout ( ( ) => {
if ( ! this . search || ! this . search . trim ( ) ) {
this . searchText = ''
return
}
this . searchText = this . search . toLowerCase ( ) . trim ( )
} , 500 )
} ,
2022-08-28 15:48:41 +02:00
toggleSelectAll ( val ) {
for ( let i = 0 ; i < this . episodes . length ; i ++ ) {
const episode = this . episodes [ i ]
2023-03-21 23:59:37 +01:00
if ( this . itemEpisodeMap [ episode . enclosure . url ? . split ( '?' ) [ 0 ] ] ) this . selectedEpisodes [ String ( i ) ] = false
2022-08-28 15:48:41 +02:00
else this . $set ( this . selectedEpisodes , String ( i ) , val )
}
} ,
checkSetIsSelectedAll ( ) {
for ( let i = 0 ; i < this . episodes . length ; i ++ ) {
const episode = this . episodes [ i ]
2023-03-21 23:59:37 +01:00
if ( ! this . itemEpisodeMap [ episode . enclosure . url ? . split ( '?' ) [ 0 ] ] && ! this . selectedEpisodes [ String ( i ) ] ) {
2022-08-28 15:48:41 +02:00
this . selectAll = false
return
}
}
this . selectAll = true
2022-03-27 22:37:04 +02:00
} ,
2022-08-28 15:48:41 +02:00
toggleSelectEpisode ( index , episode ) {
2023-03-21 23:59:37 +01:00
if ( this . itemEpisodeMap [ episode . enclosure . url ? . split ( '?' ) [ 0 ] ] ) return
2022-08-28 15:48:41 +02:00
this . $set ( this . selectedEpisodes , String ( index ) , ! this . selectedEpisodes [ String ( index ) ] )
this . checkSetIsSelectedAll ( )
2022-08-28 14:22:51 +02:00
} ,
2022-03-27 22:37:04 +02:00
submit ( ) {
var episodesToDownload = [ ]
if ( this . episodesSelected . length ) {
episodesToDownload = this . episodesSelected . map ( ( episodeIndex ) => this . episodes [ Number ( episodeIndex ) ] )
}
2022-04-24 02:41:06 +02:00
var payloadSize = JSON . stringify ( episodesToDownload ) . length
var sizeInMb = payloadSize / 1024 / 1024
var sizeInMbPretty = sizeInMb . toFixed ( 2 ) + 'MB'
console . log ( 'Request size' , sizeInMb )
if ( sizeInMb > 4.99 ) {
return this . $toast . error ( ` Request is too large ( ${ sizeInMbPretty } ) should be < 5Mb ` )
}
2022-03-27 22:37:04 +02:00
this . processing = true
this . $axios
. $post ( ` /api/podcasts/ ${ this . libraryItem . id } /download-episodes ` , episodesToDownload )
. then ( ( ) => {
this . processing = false
this . $toast . success ( 'Started downloading episodes' )
this . show = false
} )
. catch ( ( error ) => {
var errorMsg = error . response && error . response . data ? error . response . data : 'Failed to download episodes'
console . error ( 'Failed to download episodes' , error )
this . processing = false
this . $toast . error ( errorMsg )
2022-08-28 15:48:41 +02:00
this . selectedEpisodes = { }
this . selectAll = false
2022-03-27 22:37:04 +02:00
} )
2022-04-10 18:01:50 +02:00
} ,
init ( ) {
2022-08-28 15:48:41 +02:00
this . episodes . sort ( ( a , b ) => ( a . publishedAt < b . publishedAt ? 1 : - 1 ) )
this . selectAll = false
this . selectedEpisodes = { }
2022-03-27 22:37:04 +02:00
}
} ,
mounted ( ) { }
}
< / script >
< style scoped >
# podcast - wrapper {
min - height : 400 px ;
max - height : 80 vh ;
}
# episodes - scroll {
max - height : calc ( 80 vh - 200 px ) ;
}
2022-08-28 05:40:02 +02:00
< / style >