@ -18760,7 +18760,9 @@ const CSS_STYLE = {
width : 138 ,
width : 138 ,
height : 203 ,
height : 203 ,
expandedWidth : 220 ,
expandedWidth : 220 ,
expandedHeight : 324
expandedHeight : 324 ,
episodeWidth : 300 ,
episodeHeight : 169
} ;
} ;
/ * *
/ * *
@ -19012,12 +19014,21 @@ style.textContent = css `
background : orange ;
background : orange ;
}
}
. seasons {
. seasons {
z - index : 5 ;
position : absolute ;
top : $ { CSS _STYLE . expandedHeight + 16 } px ;
width : calc ( 100 % - 32 px ) ;
left : 0 ;
padding : 16 px ;
}
. episodes {
z - index : 4 ;
z - index : 4 ;
position : absolute ;
position : absolute ;
top : $ { CSS _STYLE . expandedHeight + 16 } px ;
top : $ { CSS _STYLE . expandedHeight + 16 } px ;
width : 100 % ;
width : calc ( 100 % - 32 px ) ;
left : 0 ;
left : 0 ;
padding : 16 px ;
padding : 16 px ;
display : none ;
}
}
. ratingDetail {
. ratingDetail {
background : # ffffff24 ;
background : # ffffff24 ;
@ -19143,9 +19154,20 @@ style.textContent = css `
margin - top : 5 px ;
margin - top : 5 px ;
transition : 0.5 s ;
transition : 0.5 s ;
}
}
. episodeTitleElem {
text - overflow : ellipsis ;
white - space : nowrap ;
overflow : hidden ;
position : relative ;
font - weight : bold ;
margin - top : 5 px ;
transition : 0.5 s ;
}
. seasonEpisodesCount {
. seasonEpisodesCount {
transition : 0.5 s ;
transition : 0.5 s ;
}
}
. episodeNumber {
}
. titleElem {
. titleElem {
text - overflow : ellipsis ;
text - overflow : ellipsis ;
white - space : nowrap ;
white - space : nowrap ;
@ -19159,6 +19181,19 @@ style.textContent = css `
margin - bottom : 15 px ;
margin - bottom : 15 px ;
transition : 0.5 s ;
transition : 0.5 s ;
}
}
. episodeContainer {
position : relative ;
float : left ;
margin - right : 16 px ;
margin - bottom : 15 px ;
transition : 0.5 s ;
}
. episodeElem {
background - repeat : no - repeat ;
background - size : contain ;
border - radius : 5 px ;
transition : 0.5 s ;
}
. seasonElem {
. seasonElem {
background - repeat : no - repeat ;
background - repeat : no - repeat ;
background - size : contain ;
background - size : contain ;
@ -19259,6 +19294,9 @@ class PlexMeetsHomeAssistant extends HTMLElement {
this . movieElems = [ ] ;
this . movieElems = [ ] ;
this . activeMovieElemData = { } ;
this . activeMovieElemData = { } ;
this . seasonElemFreshlyLoaded = false ;
this . seasonElemFreshlyLoaded = false ;
this . episodesElemFreshlyLoaded = false ;
this . seasonsElemHidden = true ;
this . episodesElemHidden = true ;
this . data = { } ;
this . data = { } ;
this . config = { } ;
this . config = { } ;
this . requestTimeout = 3000 ;
this . requestTimeout = 3000 ;
@ -19267,6 +19305,7 @@ class PlexMeetsHomeAssistant extends HTMLElement {
this . playSupported = false ;
this . playSupported = false ;
this . error = '' ;
this . error = '' ;
this . previousPositions = [ ] ;
this . previousPositions = [ ] ;
this . contentBGHeight = 0 ;
this . loadInitialData = async ( ) => {
this . loadInitialData = async ( ) => {
this . loading = true ;
this . loading = true ;
this . renderPage ( ) ;
this . renderPage ( ) ;
@ -19318,6 +19357,8 @@ class PlexMeetsHomeAssistant extends HTMLElement {
}
}
if ( renderNeeded ) {
if ( renderNeeded ) {
this . renderPage ( ) ;
this . renderPage ( ) ;
const contentbg = this . getElementsByClassName ( 'contentbg' ) ;
this . contentBGHeight = contentbg [ 0 ] . scrollHeight ;
}
}
}
}
} , 100 ) ;
} , 100 ) ;
@ -19361,6 +19402,13 @@ class PlexMeetsHomeAssistant extends HTMLElement {
this . minimizeAll ( ) ;
this . minimizeAll ( ) ;
} ) ;
} ) ;
this . content . appendChild ( this . seasonsElem ) ;
this . content . appendChild ( this . seasonsElem ) ;
this . episodesElem = document . createElement ( 'div' ) ;
this . episodesElem . className = 'episodes' ;
this . episodesElem . addEventListener ( 'click' , ( ) => {
this . hideBackground ( ) ;
this . minimizeAll ( ) ;
} ) ;
this . content . appendChild ( this . episodesElem ) ;
// todo: figure out why timeout is needed here and do it properly
// todo: figure out why timeout is needed here and do it properly
setTimeout ( ( ) => {
setTimeout ( ( ) => {
contentbg . addEventListener ( 'click' , ( ) => {
contentbg . addEventListener ( 'click' , ( ) => {
@ -19405,6 +19453,8 @@ class PlexMeetsHomeAssistant extends HTMLElement {
} , 100 ) ;
} , 100 ) ;
} ;
} ;
this . minimizeSeasons = ( ) => {
this . minimizeSeasons = ( ) => {
return new Promise ( ( resolve , reject ) => {
this . seasonsElemHidden = false ;
if ( this . seasonsElem ) {
if ( this . seasonsElem ) {
lodash . forEach ( this . seasonsElem . childNodes , child => {
lodash . forEach ( this . seasonsElem . childNodes , child => {
const seasonElem = child . children [ 0 ] ;
const seasonElem = child . children [ 0 ] ;
@ -19432,10 +19482,12 @@ class PlexMeetsHomeAssistant extends HTMLElement {
else {
else {
setTimeout ( ( ) => {
setTimeout ( ( ) => {
moveElem ( seasonElem ) ;
moveElem ( seasonElem ) ;
resolve ( ) ;
} , 100 ) ;
} , 100 ) ;
}
}
} ) ;
} ) ;
}
}
} ) ;
} ;
} ;
this . minimizeAll = ( ) => {
this . minimizeAll = ( ) => {
this . activeMovieElem = undefined ;
this . activeMovieElem = undefined ;
@ -19453,10 +19505,12 @@ class PlexMeetsHomeAssistant extends HTMLElement {
}
}
}
}
this . hideSeasons ( ) ;
this . hideSeasons ( ) ;
this . hideEpisodes ( ) ;
this . hideDetails ( ) ;
this . hideDetails ( ) ;
} ;
} ;
this . hideSeasons = ( ) => {
this . hideSeasons = ( ) => {
if ( this . seasonsElem ) {
if ( this . seasonsElem ) {
this . seasonsElemHidden = true ;
const doc = document . documentElement ;
const doc = document . documentElement ;
const top = ( window . pageYOffset || doc . scrollTop ) - ( doc . clientTop || 0 ) ;
const top = ( window . pageYOffset || doc . scrollTop ) - ( doc . clientTop || 0 ) ;
this . seasonsElem . style . top = ` ${ top + 2000 } px ` ;
this . seasonsElem . style . top = ` ${ top + 2000 } px ` ;
@ -19464,15 +19518,32 @@ class PlexMeetsHomeAssistant extends HTMLElement {
if ( this . seasonsElem && ! this . seasonElemFreshlyLoaded ) {
if ( this . seasonsElem && ! this . seasonElemFreshlyLoaded ) {
this . seasonsElem . innerHTML = '' ;
this . seasonsElem . innerHTML = '' ;
this . seasonsElem . style . display = 'none' ;
this . seasonsElem . style . display = 'none' ;
this . resizeBackground ( ) ;
}
} , 700 ) ;
}
} ;
this . hideEpisodes = ( ) => {
if ( this . episodesElem ) {
this . episodesElemHidden = true ;
const doc = document . documentElement ;
const top = ( window . pageYOffset || doc . scrollTop ) - ( doc . clientTop || 0 ) ;
this . episodesElem . style . top = ` ${ top + 2000 } px ` ;
setTimeout ( ( ) => {
if ( this . episodesElem && ! this . episodesElemFreshlyLoaded ) {
this . episodesElem . innerHTML = '' ;
this . episodesElem . style . display = 'none' ;
// fix for a specific case when user scrolls outside of normal home assistant area for seasons look
// fix for a specific case when user scrolls outside of normal home assistant area for seasons look
const contentbg = this . getElementsByClassName ( 'contentbg' ) ;
console . log ( 'AAA' ) ;
contentbg [ 0 ] . style . height = '100%' ;
this . resizeBackground ( ) ;
console . log ( 'BBB' ) ;
}
}
} , 700 ) ;
} , 700 ) ;
}
}
} ;
} ;
this . scrollDownInactiveSeasons = ( ) => {
this . scrollDownInactiveSeasons = ( ) => {
if ( this . seasonsElem ) {
if ( this . seasonsElem ) {
this . seasonsElemHidden = true ;
lodash . forEach ( this . seasonsElem . childNodes , child => {
lodash . forEach ( this . seasonsElem . childNodes , child => {
const seasonElem = child . children [ 0 ] ;
const seasonElem = child . children [ 0 ] ;
const seasonTitleElem = child . children [ 1 ] ;
const seasonTitleElem = child . children [ 1 ] ;
@ -19547,6 +19618,7 @@ class PlexMeetsHomeAssistant extends HTMLElement {
}
}
lodash . forEach ( seasonsData , seasonData => {
lodash . forEach ( seasonsData , seasonData => {
if ( this . seasonsElem ) {
if ( this . seasonsElem ) {
this . seasonsElemHidden = false ;
const seasonContainer = document . createElement ( 'div' ) ;
const seasonContainer = document . createElement ( 'div' ) ;
seasonContainer . className = 'seasonContainer' ;
seasonContainer . className = 'seasonContainer' ;
seasonContainer . style . width = ` ${ CSS _STYLE . width } px ` ;
seasonContainer . style . width = ` ${ CSS _STYLE . width } px ` ;
@ -19579,6 +19651,7 @@ class PlexMeetsHomeAssistant extends HTMLElement {
seasonEpisodesCount . innerHTML = ` ${ escapeHtml ( seasonData . leafCount ) } episodes ` ;
seasonEpisodesCount . innerHTML = ` ${ escapeHtml ( seasonData . leafCount ) } episodes ` ;
seasonContainer . append ( seasonEpisodesCount ) ;
seasonContainer . append ( seasonEpisodesCount ) ;
seasonContainer . addEventListener ( 'click' , event => {
seasonContainer . addEventListener ( 'click' , event => {
( async ( ) => {
event . stopPropagation ( ) ;
event . stopPropagation ( ) ;
if ( this . activeMovieElem ) {
if ( this . activeMovieElem ) {
if ( seasonElem . dataset . clicked === 'false' ) {
if ( seasonElem . dataset . clicked === 'false' ) {
@ -19589,16 +19662,83 @@ class PlexMeetsHomeAssistant extends HTMLElement {
seasonElem . style . width = ` ${ CSS _STYLE . expandedWidth } px ` ;
seasonElem . style . width = ` ${ CSS _STYLE . expandedWidth } px ` ;
seasonElem . style . height = ` ${ CSS _STYLE . expandedHeight - 6 } px ` ;
seasonElem . style . height = ` ${ CSS _STYLE . expandedHeight - 6 } px ` ;
seasonElem . style . zIndex = '3' ;
seasonElem . style . zIndex = '3' ;
seasonElem . style . marginLeft = ` - ${ getOffset ( seasonElem ) . left - getOffset ( this . activeMovieElem ) . left } px ` ;
seasonElem . style . marginLeft = ` - ${ getOffset ( seasonElem ) . left -
getOffset ( this . activeMovieElem ) . left } px ` ;
seasonTitleElem . style . color = 'rgba(255,255,255,0)' ;
seasonTitleElem . style . color = 'rgba(255,255,255,0)' ;
seasonEpisodesCount . style . color = 'rgba(255,255,255,0)' ;
seasonEpisodesCount . style . color = 'rgba(255,255,255,0)' ;
if ( this . detailElem ) {
if ( this . detailElem ) {
this . detailElem . children [ 1 ] . innerHTML = seasonData . title ;
this . detailElem . children [ 1 ] . innerHTML = seasonData . title ;
}
}
( async ( ) => {
if ( seasonData . leafCount > 0 && this . plex ) {
this . episodesElemFreshlyLoaded = true ;
const episodesData = await this . plex . getLibraryData ( seasonData . key . split ( '/' ) [ 3 ] ) ;
if ( this . episodesElem ) {
this . episodesElemHidden = false ;
this . episodesElem . style . display = 'block' ;
this . episodesElem . innerHTML = '' ;
this . episodesElem . style . transition = ` 0s ` ;
this . episodesElem . style . top = ` ${ top + 2000 } px ` ;
lodash . forEach ( episodesData , episodeData => {
if ( this . episodesElem ) {
const episodeContainer = document . createElement ( 'div' ) ;
episodeContainer . className = 'episodeContainer' ;
episodeContainer . style . width = ` ${ CSS _STYLE . episodeWidth } px ` ;
const episodeThumbURL = ` ${ this . plexProtocol } :// ${ this . config . ip } : ${ this . config . port } /photo/:/transcode?width= ${ CSS _STYLE . episodeWidth } &height= ${ CSS _STYLE . episodeHeight } &minSize=1&upscale=1&url= ${ episodeData . thumb } &X-Plex-Token= ${ this . config . token } ` ;
const episodeElem = document . createElement ( 'div' ) ;
episodeElem . className = 'episodeElem' ;
episodeElem . style . width = ` ${ CSS _STYLE . episodeWidth } px ` ;
episodeElem . style . height = ` ${ CSS _STYLE . episodeHeight } px ` ;
episodeElem . style . backgroundImage = ` url(' ${ episodeThumbURL } ') ` ;
episodeElem . dataset . clicked = 'false' ;
const episodeInteractiveArea = document . createElement ( 'div' ) ;
episodeInteractiveArea . className = 'interactiveArea' ;
const episodePlayButton = document . createElement ( 'button' ) ;
episodePlayButton . name = 'playButton' ;
episodePlayButton . addEventListener ( 'click' , episodeEvent => {
episodeEvent . stopPropagation ( ) ;
if ( this . plex && this . playController ) {
this . playController . play ( episodeData . key . split ( '/' ) [ 3 ] ) ;
}
} ) ;
episodeInteractiveArea . append ( episodePlayButton ) ;
episodeElem . append ( episodeInteractiveArea ) ;
episodeContainer . append ( episodeElem ) ;
const episodeTitleElem = document . createElement ( 'div' ) ;
episodeTitleElem . className = 'episodeTitleElem' ;
episodeTitleElem . innerHTML = escapeHtml ( episodeData . title ) ;
episodeContainer . append ( episodeTitleElem ) ;
const episodeNumber = document . createElement ( 'div' ) ;
episodeNumber . className = 'episodeNumber' ;
episodeNumber . innerHTML = escapeHtml ( ` Episode ${ escapeHtml ( episodeData . index ) } ` ) ;
episodeContainer . append ( episodeNumber ) ;
episodeContainer . addEventListener ( 'click' , episodeEvent => {
episodeEvent . stopPropagation ( ) ;
console . log ( episodeData ) ;
} ) ;
this . episodesElem . append ( episodeContainer ) ;
}
} ) ;
setTimeout ( ( ) => {
if ( this . episodesElem ) {
this . episodesElem . style . transition = ` 0.7s ` ;
this . episodesElem . style . top = ` ${ top + CSS _STYLE . expandedHeight + 16 } px ` ;
this . resizeBackground ( ) ;
}
} , 200 ) ;
setTimeout ( ( ) => {
this . episodesElemFreshlyLoaded = false ;
} , 700 ) ;
}
}
} ) ( ) ;
}
}
else {
else {
this . minimizeSeasons ( ) ;
console . log ( 'A' ) ;
this . activeMovieElem . style . top = ` 16px ` ;
await this . minimizeSeasons ( ) ;
console . log ( 'B' ) ;
this . hideEpisodes ( ) ;
this . activeMovieElem . style . top = ` ${ top + 16 } px ` ;
if ( this . detailElem && this . detailElem . children [ 1 ] ) {
if ( this . detailElem && this . detailElem . children [ 1 ] ) {
const { year } = this . detailElem . children [ 1 ] . dataset ;
const { year } = this . detailElem . children [ 1 ] . dataset ;
if ( year ) {
if ( year ) {
@ -19607,24 +19747,45 @@ class PlexMeetsHomeAssistant extends HTMLElement {
}
}
}
}
}
}
} ) ( ) ;
} ) ;
} ) ;
this . seasonsElem . append ( seasonContainer ) ;
this . seasonsElem . append ( seasonContainer ) ;
}
} ) ;
setTimeout ( ( ) => {
setTimeout ( ( ) => {
this . seasonElemFreshlyLoaded = false ;
this . seasonElemFreshlyLoaded = false ;
} , 700 ) ;
} , 700 ) ;
}
} ) ;
setTimeout ( ( ) => {
setTimeout ( ( ) => {
if ( this . seasonsElem ) {
if ( this . seasonsElem ) {
this . seasonsElem . style . transition = ` 0.7s ` ;
this . seasonsElem . style . transition = ` 0.7s ` ;
this . seasonsElem . style . top = ` ${ top + CSS _STYLE . expandedHeight + 16 } px ` ;
this . seasonsElem . style . top = ` ${ top + CSS _STYLE . expandedHeight + 16 } px ` ;
const requiredBodyHeight = parseInt ( this . seasonsElem . style . top . replace ( 'px' , '' ) , 10 ) + this . seasonsElem . scrollHeight ;
this . resizeBackground ( ) ;
}
} , 200 ) ;
}
} ;
this . resizeBackground = ( ) => {
if ( this . seasonsElem && this . episodesElem ) {
const contentbg = this . getElementsByClassName ( 'contentbg' ) ;
const contentbg = this . getElementsByClassName ( 'contentbg' ) ;
if ( requiredBodyHeight > contentbg [ 0 ] . scrollHeight ) {
if ( this . contentBGHeight === 0 ) {
contentbg [ 0 ] . style . height = ` ${ requiredBodyHeight } px ` ;
this . contentBGHeight = contentbg [ 0 ] . scrollHeight ;
}
}
const requiredSeasonBodyHeight = parseInt ( this . seasonsElem . style . top . replace ( 'px' , '' ) , 10 ) + this . seasonsElem . scrollHeight ;
const requiredEpisodeBodyHeight = parseInt ( this . episodesElem . style . top . replace ( 'px' , '' ) , 10 ) + this . episodesElem . scrollHeight ;
console . log ( this . seasonsElemHidden ) ;
console . log ( this . episodesElemHidden ) ;
if ( requiredSeasonBodyHeight > this . contentBGHeight && ! this . seasonsElemHidden ) {
console . log ( '1' ) ;
contentbg [ 0 ] . style . height = ` ${ requiredSeasonBodyHeight } px ` ;
}
else if ( requiredEpisodeBodyHeight > this . contentBGHeight && ! this . episodesElemHidden ) {
console . log ( '2' ) ;
contentbg [ 0 ] . style . height = ` ${ requiredEpisodeBodyHeight } px ` ;
}
else {
console . log ( '3' ) ;
contentbg [ 0 ] . style . height = '100%' ;
}
}
} , 200 ) ;
}
}
} ;
} ;
this . showBackground = ( ) => {
this . showBackground = ( ) => {