Add: Episodes view after opening a session

pull/16/head
Juraj Nyíri 4 years ago
parent 1e21d74e35
commit 7c91d91318

@ -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% - 32px);
left: 0;
padding: 16px;
}
.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% - 32px);
left: 0; left: 0;
padding: 16px; padding: 16px;
display: none;
} }
.ratingDetail { .ratingDetail {
background: #ffffff24; background: #ffffff24;
@ -19143,9 +19154,20 @@ style.textContent = css `
margin-top: 5px; margin-top: 5px;
transition: 0.5s; transition: 0.5s;
} }
.episodeTitleElem {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
position: relative;
font-weight: bold;
margin-top: 5px;
transition: 0.5s;
}
.seasonEpisodesCount { .seasonEpisodesCount {
transition: 0.5s; transition: 0.5s;
} }
.episodeNumber {
}
.titleElem { .titleElem {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@ -19159,6 +19181,19 @@ style.textContent = css `
margin-bottom: 15px; margin-bottom: 15px;
transition: 0.5s; transition: 0.5s;
} }
.episodeContainer {
position: relative;
float: left;
margin-right: 16px;
margin-bottom: 15px;
transition: 0.5s;
}
.episodeElem {
background-repeat: no-repeat;
background-size: contain;
border-radius: 5px;
transition: 0.5s;
}
.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,37 +19453,41 @@ class PlexMeetsHomeAssistant extends HTMLElement {
}, 100); }, 100);
}; };
this.minimizeSeasons = () => { this.minimizeSeasons = () => {
if (this.seasonsElem) { return new Promise((resolve, reject) => {
lodash.forEach(this.seasonsElem.childNodes, child => { this.seasonsElemHidden = false;
const seasonElem = child.children[0]; if (this.seasonsElem) {
const seasonTitleElem = child.children[1]; lodash.forEach(this.seasonsElem.childNodes, child => {
const seasonEpisodesCount = child.children[2]; const seasonElem = child.children[0];
seasonElem.style.display = 'block'; const seasonTitleElem = child.children[1];
const moveElem = (elem) => { const seasonEpisodesCount = child.children[2];
const seasonElemLocal = elem; seasonElem.style.display = 'block';
seasonElemLocal.style.marginTop = '0'; const moveElem = (elem) => {
seasonElemLocal.style.width = `${CSS_STYLE.width}px`; const seasonElemLocal = elem;
seasonElemLocal.style.height = `${CSS_STYLE.height - 3}px`; seasonElemLocal.style.marginTop = '0';
seasonElemLocal.style.zIndex = '3'; seasonElemLocal.style.width = `${CSS_STYLE.width}px`;
seasonElemLocal.style.marginLeft = `0px`; seasonElemLocal.style.height = `${CSS_STYLE.height - 3}px`;
seasonElemLocal.dataset.clicked = 'false'; seasonElemLocal.style.zIndex = '3';
seasonTitleElem.style.display = 'block'; seasonElemLocal.style.marginLeft = `0px`;
seasonEpisodesCount.style.display = 'block'; seasonElemLocal.dataset.clicked = 'false';
setTimeout(() => { seasonTitleElem.style.display = 'block';
seasonTitleElem.style.color = 'rgba(255,255,255,1)'; seasonEpisodesCount.style.display = 'block';
seasonEpisodesCount.style.color = 'rgba(255,255,255,1)'; setTimeout(() => {
}, 500); seasonTitleElem.style.color = 'rgba(255,255,255,1)';
}; seasonEpisodesCount.style.color = 'rgba(255,255,255,1)';
if (seasonElem.dataset.clicked === 'true') { }, 500);
moveElem(seasonElem); };
} if (seasonElem.dataset.clicked === 'true') {
else {
setTimeout(() => {
moveElem(seasonElem); moveElem(seasonElem);
}, 100); }
} else {
}); setTimeout(() => {
} moveElem(seasonElem);
resolve();
}, 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,54 +19651,143 @@ 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 => {
event.stopPropagation(); (async () => {
if (this.activeMovieElem) { event.stopPropagation();
if (seasonElem.dataset.clicked === 'false') { if (this.activeMovieElem) {
seasonElem.dataset.clicked = 'true'; if (seasonElem.dataset.clicked === 'false') {
this.activeMovieElem.style.top = `${top - 1000}px`; seasonElem.dataset.clicked = 'true';
this.scrollDownInactiveSeasons(); this.activeMovieElem.style.top = `${top - 1000}px`;
seasonElem.style.marginTop = `${-CSS_STYLE.expandedHeight - 16}px`; this.scrollDownInactiveSeasons();
seasonElem.style.width = `${CSS_STYLE.expandedWidth}px`; seasonElem.style.marginTop = `${-CSS_STYLE.expandedHeight - 16}px`;
seasonElem.style.height = `${CSS_STYLE.expandedHeight - 6}px`; seasonElem.style.width = `${CSS_STYLE.expandedWidth}px`;
seasonElem.style.zIndex = '3'; seasonElem.style.height = `${CSS_STYLE.expandedHeight - 6}px`;
seasonElem.style.marginLeft = `-${getOffset(seasonElem).left - getOffset(this.activeMovieElem).left}px`; seasonElem.style.zIndex = '3';
seasonTitleElem.style.color = 'rgba(255,255,255,0)'; seasonElem.style.marginLeft = `-${getOffset(seasonElem).left -
seasonEpisodesCount.style.color = 'rgba(255,255,255,0)'; getOffset(this.activeMovieElem).left}px`;
if (this.detailElem) { seasonTitleElem.style.color = 'rgba(255,255,255,0)';
this.detailElem.children[1].innerHTML = seasonData.title; seasonEpisodesCount.style.color = 'rgba(255,255,255,0)';
if (this.detailElem) {
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 { console.log('A');
this.minimizeSeasons(); await this.minimizeSeasons();
this.activeMovieElem.style.top = `16px`; console.log('B');
if (this.detailElem && this.detailElem.children[1]) { this.hideEpisodes();
const { year } = this.detailElem.children[1].dataset; this.activeMovieElem.style.top = `${top + 16}px`;
if (year) { if (this.detailElem && this.detailElem.children[1]) {
this.detailElem.children[1].innerHTML = year; const { year } = this.detailElem.children[1].dataset;
if (year) {
this.detailElem.children[1].innerHTML = year;
}
} }
} }
} }
} })();
}); });
this.seasonsElem.append(seasonContainer); this.seasonsElem.append(seasonContainer);
setTimeout(() => {
this.seasonElemFreshlyLoaded = false;
}, 700);
} }
}); });
setTimeout(() => {
this.seasonElemFreshlyLoaded = false;
}, 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();
const contentbg = this.getElementsByClassName('contentbg');
if (requiredBodyHeight > contentbg[0].scrollHeight) {
contentbg[0].style.height = `${requiredBodyHeight}px`;
}
} }
}, 200); }, 200);
} }
}; };
this.resizeBackground = () => {
if (this.seasonsElem && this.episodesElem) {
const contentbg = this.getElementsByClassName('contentbg');
if (this.contentBGHeight === 0) {
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%';
}
}
};
this.showBackground = () => { this.showBackground = () => {
const contentbg = this.getElementsByClassName('contentbg'); const contentbg = this.getElementsByClassName('contentbg');
contentbg[0].style.zIndex = '2'; contentbg[0].style.zIndex = '2';

@ -2,7 +2,9 @@ const CSS_STYLE = {
width: 138, width: 138,
height: 203, height: 203,
expandedWidth: 220, expandedWidth: 220,
expandedHeight: 324 expandedHeight: 324,
episodeWidth: 300,
episodeHeight: 169
}; };
const LOREM_IPSUM = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec semper risus vitae aliquet interdum. Nulla facilisi. Pellentesque viverra sagittis lorem eget aliquet. Cras vehicula, purus vel consectetur mattis, ipsum arcu ullamcorper mi, id viverra purus ex eu dolor. Integer vehicula lacinia sem convallis iaculis. Nulla fermentum erat interdum, efficitur felis in, mollis neque. Vivamus luctus metus eget nisl pellentesque, placerat elementum magna eleifend. const LOREM_IPSUM = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec semper risus vitae aliquet interdum. Nulla facilisi. Pellentesque viverra sagittis lorem eget aliquet. Cras vehicula, purus vel consectetur mattis, ipsum arcu ullamcorper mi, id viverra purus ex eu dolor. Integer vehicula lacinia sem convallis iaculis. Nulla fermentum erat interdum, efficitur felis in, mollis neque. Vivamus luctus metus eget nisl pellentesque, placerat elementum magna eleifend.

@ -15,12 +15,21 @@ style.textContent = css`
background: orange; background: orange;
} }
.seasons { .seasons {
z-index: 5;
position: absolute;
top: ${CSS_STYLE.expandedHeight + 16}px;
width: calc(100% - 32px);
left: 0;
padding: 16px;
}
.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% - 32px);
left: 0; left: 0;
padding: 16px; padding: 16px;
display: none;
} }
.ratingDetail { .ratingDetail {
background: #ffffff24; background: #ffffff24;
@ -146,9 +155,20 @@ style.textContent = css`
margin-top: 5px; margin-top: 5px;
transition: 0.5s; transition: 0.5s;
} }
.episodeTitleElem {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
position: relative;
font-weight: bold;
margin-top: 5px;
transition: 0.5s;
}
.seasonEpisodesCount { .seasonEpisodesCount {
transition: 0.5s; transition: 0.5s;
} }
.episodeNumber {
}
.titleElem { .titleElem {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@ -162,6 +182,19 @@ style.textContent = css`
margin-bottom: 15px; margin-bottom: 15px;
transition: 0.5s; transition: 0.5s;
} }
.episodeContainer {
position: relative;
float: left;
margin-right: 16px;
margin-bottom: 15px;
transition: 0.5s;
}
.episodeElem {
background-repeat: no-repeat;
background-size: contain;
border-radius: 5px;
transition: 0.5s;
}
.seasonElem { .seasonElem {
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: contain; background-size: contain;

@ -23,10 +23,18 @@ class PlexMeetsHomeAssistant extends HTMLElement {
seasonElemFreshlyLoaded = false; seasonElemFreshlyLoaded = false;
episodesElemFreshlyLoaded = false;
detailElem: HTMLElement | undefined; detailElem: HTMLElement | undefined;
seasonsElem: HTMLElement | undefined; seasonsElem: HTMLElement | undefined;
seasonsElemHidden = true;
episodesElem: HTMLElement | undefined;
episodesElemHidden = true;
data: Record<string, any> = {}; data: Record<string, any> = {};
config: Record<string, any> = {}; config: Record<string, any> = {};
@ -47,6 +55,8 @@ class PlexMeetsHomeAssistant extends HTMLElement {
hassObj: HomeAssistant | undefined; hassObj: HomeAssistant | undefined;
contentBGHeight = 0;
set hass(hass: HomeAssistant) { set hass(hass: HomeAssistant) {
this.hassObj = hass; this.hassObj = hass;
if (this.plex) { if (this.plex) {
@ -120,6 +130,8 @@ class PlexMeetsHomeAssistant extends HTMLElement {
} }
if (renderNeeded) { if (renderNeeded) {
this.renderPage(); this.renderPage();
const contentbg = this.getElementsByClassName('contentbg');
this.contentBGHeight = (contentbg[0] as HTMLElement).scrollHeight;
} }
} }
}, 100); }, 100);
@ -174,6 +186,14 @@ class PlexMeetsHomeAssistant extends HTMLElement {
}); });
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', () => {
@ -218,39 +238,43 @@ class PlexMeetsHomeAssistant extends HTMLElement {
}, 100); }, 100);
}; };
minimizeSeasons = (): void => { minimizeSeasons = (): Promise<void> => {
if (this.seasonsElem) { return new Promise((resolve, reject) => {
_.forEach(this.seasonsElem.childNodes, child => { this.seasonsElemHidden = false;
const seasonElem = (child as HTMLElement).children[0] as HTMLElement; if (this.seasonsElem) {
const seasonTitleElem = (child as HTMLElement).children[1] as HTMLElement; _.forEach(this.seasonsElem.childNodes, child => {
const seasonEpisodesCount = (child as HTMLElement).children[2] as HTMLElement; const seasonElem = (child as HTMLElement).children[0] as HTMLElement;
seasonElem.style.display = 'block'; const seasonTitleElem = (child as HTMLElement).children[1] as HTMLElement;
const seasonEpisodesCount = (child as HTMLElement).children[2] as HTMLElement;
const moveElem = (elem: HTMLElement): void => { seasonElem.style.display = 'block';
const seasonElemLocal = elem;
seasonElemLocal.style.marginTop = '0'; const moveElem = (elem: HTMLElement): void => {
seasonElemLocal.style.width = `${CSS_STYLE.width}px`; const seasonElemLocal = elem;
seasonElemLocal.style.height = `${CSS_STYLE.height - 3}px`; seasonElemLocal.style.marginTop = '0';
seasonElemLocal.style.zIndex = '3'; seasonElemLocal.style.width = `${CSS_STYLE.width}px`;
seasonElemLocal.style.marginLeft = `0px`; seasonElemLocal.style.height = `${CSS_STYLE.height - 3}px`;
seasonElemLocal.dataset.clicked = 'false'; seasonElemLocal.style.zIndex = '3';
seasonTitleElem.style.display = 'block'; seasonElemLocal.style.marginLeft = `0px`;
seasonEpisodesCount.style.display = 'block'; seasonElemLocal.dataset.clicked = 'false';
setTimeout(() => { seasonTitleElem.style.display = 'block';
seasonTitleElem.style.color = 'rgba(255,255,255,1)'; seasonEpisodesCount.style.display = 'block';
seasonEpisodesCount.style.color = 'rgba(255,255,255,1)'; setTimeout(() => {
}, 500); seasonTitleElem.style.color = 'rgba(255,255,255,1)';
}; seasonEpisodesCount.style.color = 'rgba(255,255,255,1)';
}, 500);
if (seasonElem.dataset.clicked === 'true') { };
moveElem(seasonElem);
} else { if (seasonElem.dataset.clicked === 'true') {
setTimeout(() => {
moveElem(seasonElem); moveElem(seasonElem);
}, 100); } else {
} setTimeout(() => {
}); moveElem(seasonElem);
} resolve();
}, 100);
}
});
}
});
}; };
minimizeAll = (): void => { minimizeAll = (): void => {
@ -269,11 +293,13 @@ class PlexMeetsHomeAssistant extends HTMLElement {
} }
} }
this.hideSeasons(); this.hideSeasons();
this.hideEpisodes();
this.hideDetails(); this.hideDetails();
}; };
hideSeasons = (): void => { hideSeasons = (): void => {
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`;
@ -281,9 +307,26 @@ 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);
}
};
hideEpisodes = (): void => {
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] as HTMLElement).style.height = '100%'; this.resizeBackground();
console.log('BBB');
} }
}, 700); }, 700);
} }
@ -291,6 +334,7 @@ class PlexMeetsHomeAssistant extends HTMLElement {
scrollDownInactiveSeasons = (): void => { scrollDownInactiveSeasons = (): void => {
if (this.seasonsElem) { if (this.seasonsElem) {
this.seasonsElemHidden = true;
_.forEach(this.seasonsElem.childNodes, child => { _.forEach(this.seasonsElem.childNodes, child => {
const seasonElem = (child as HTMLElement).children[0] as HTMLElement; const seasonElem = (child as HTMLElement).children[0] as HTMLElement;
const seasonTitleElem = (child as HTMLElement).children[1] as HTMLElement; const seasonTitleElem = (child as HTMLElement).children[1] as HTMLElement;
@ -375,6 +419,7 @@ class PlexMeetsHomeAssistant extends HTMLElement {
_.forEach(seasonsData, seasonData => { _.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`;
@ -414,64 +459,164 @@ class PlexMeetsHomeAssistant extends HTMLElement {
seasonContainer.append(seasonEpisodesCount); seasonContainer.append(seasonEpisodesCount);
seasonContainer.addEventListener('click', event => { seasonContainer.addEventListener('click', event => {
event.stopPropagation(); (async (): Promise<void> => {
if (this.activeMovieElem) { event.stopPropagation();
if (seasonElem.dataset.clicked === 'false') { if (this.activeMovieElem) {
seasonElem.dataset.clicked = 'true'; if (seasonElem.dataset.clicked === 'false') {
this.activeMovieElem.style.top = `${top - 1000}px`; seasonElem.dataset.clicked = 'true';
this.activeMovieElem.style.top = `${top - 1000}px`;
this.scrollDownInactiveSeasons(); this.scrollDownInactiveSeasons();
seasonElem.style.marginTop = `${-CSS_STYLE.expandedHeight - 16}px`; seasonElem.style.marginTop = `${-CSS_STYLE.expandedHeight - 16}px`;
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] as HTMLElement).innerHTML = seasonData.title; (this.detailElem.children[1] as HTMLElement).innerHTML = seasonData.title;
} }
} else { (async (): Promise<void> => {
this.minimizeSeasons(); if (seasonData.leafCount > 0 && this.plex) {
this.activeMovieElem.style.top = `16px`; this.episodesElemFreshlyLoaded = true;
if (this.detailElem && (this.detailElem.children[1] as HTMLElement)) { const episodesData = await this.plex.getLibraryData(seasonData.key.split('/')[3]);
const { year } = (this.detailElem.children[1] as HTMLElement).dataset; if (this.episodesElem) {
if (year) { this.episodesElemHidden = false;
(this.detailElem.children[1] as HTMLElement).innerHTML = year; this.episodesElem.style.display = 'block';
this.episodesElem.innerHTML = '';
this.episodesElem.style.transition = `0s`;
this.episodesElem.style.top = `${top + 2000}px`;
_.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 {
console.log('A');
await this.minimizeSeasons();
console.log('B');
this.hideEpisodes();
this.activeMovieElem.style.top = `${top + 16}px`;
if (this.detailElem && (this.detailElem.children[1] as HTMLElement)) {
const { year } = (this.detailElem.children[1] as HTMLElement).dataset;
if (year) {
(this.detailElem.children[1] as HTMLElement).innerHTML = year;
}
} }
} }
} }
} })();
}); });
this.seasonsElem.append(seasonContainer); this.seasonsElem.append(seasonContainer);
setTimeout(() => {
this.seasonElemFreshlyLoaded = false;
}, 700);
} }
}); });
setTimeout(() => {
this.seasonElemFreshlyLoaded = false;
}, 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 = this.resizeBackground();
parseInt(this.seasonsElem.style.top.replace('px', ''), 10) + this.seasonsElem.scrollHeight;
const contentbg = this.getElementsByClassName('contentbg');
if (requiredBodyHeight > (contentbg[0] as HTMLElement).scrollHeight) {
(contentbg[0] as HTMLElement).style.height = `${requiredBodyHeight}px`;
}
} }
}, 200); }, 200);
} }
}; };
resizeBackground = (): void => {
if (this.seasonsElem && this.episodesElem) {
const contentbg = this.getElementsByClassName('contentbg');
if (this.contentBGHeight === 0) {
this.contentBGHeight = (contentbg[0] as HTMLElement).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] as HTMLElement).style.height = `${requiredSeasonBodyHeight}px`;
} else if (requiredEpisodeBodyHeight > this.contentBGHeight && !this.episodesElemHidden) {
console.log('2');
(contentbg[0] as HTMLElement).style.height = `${requiredEpisodeBodyHeight}px`;
} else {
console.log('3');
(contentbg[0] as HTMLElement).style.height = '100%';
}
}
};
showBackground = (): void => { showBackground = (): void => {
const contentbg = this.getElementsByClassName('contentbg'); const contentbg = this.getElementsByClassName('contentbg');
(contentbg[0] as HTMLElement).style.zIndex = '2'; (contentbg[0] as HTMLElement).style.zIndex = '2';

Loading…
Cancel
Save