477 lines
36 KiB
HTML
477 lines
36 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
|
<title>Jellyfin Spotlight v2.3.2</title>
|
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap');
|
|
body { margin: 0; padding: 0; overflow: hidden; }
|
|
.slide { position: relative; width: 100vw; height: 100vh; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);}
|
|
.slide:focus { outline: 2px solid #fff; }
|
|
.backdrop { position: absolute; top: 3.15em; left: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 30%; z-index: 1; transition: width 0.5s ease, filter 0.8s ease, scale 2s ease; transform-origin: top; animation: none;}
|
|
.logo { position: relative; transform: translateX(-50%) translateY(-50%); top: 56%; left: 14.5%; z-index: 3; text-shadow: -2px 2px 4px rgba(0, 0, 0, 0.5); filter: drop-shadow(1px 1px 1px); pointer-events: none; transition: transform 0.3s ease, max-height 0.3s ease, max-width 0.3s ease;}
|
|
.heading { position: absolute; top: 0; left: 0; width: 100%; height: 2.3em; background-color: transparent; font-family: "Titillium Web", sans-serif; color: #D3D3D3; font-size: 22px; display: flex; align-items: center; justify-content: flex-start; z-index: 2; padding: 10px; padding-left: 0px; box-sizing: border-box; text-shadow: 1px 1px 4px rgba(0, 0, 0, 1); }
|
|
.next-button { position: absolute; top: 0.4em; right: 0.25em; font-size: 1.5em; color: #D3D3D3; cursor: pointer; z-index: 10; font-family: "Titillium Web", sans-serif; font-size: 1.35em; text-shadow: 1px 1px 4px rgba(0, 0, 0, 1);}
|
|
.skip-button {font-size: 1.62em; top: 0.5em; opacity: 0.5; transition: opacity 0.3s ease, background 0.3s ease; padding-left: 0.15em; padding-right: 0.15em; padding-top: 0.1em; border-radius: 50%; box-sizing: border-box; font-style: normal; font-weight: 400; letter-spacing: normal; line-height: 1; text-transform: none; word-wrap: normal; direction: inherit; white-space: nowrap; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; -moz-osx-font-smoothing: grayscale; -webkit-font-feature-settings: "liga"; font-feature-settings: "liga";}
|
|
.skip-button:hover {background: #ffffff70; opacity: 1;}
|
|
.video-container { position: absolute; right: 0; top: 50px; width: 0; height: calc(100% - 50px); overflow: hidden; z-index: 2; transition: width 0.5s ease; z-index: 6; border-top-right-radius: 0.5em; border-bottom-right-radius: 0.5em; transform-origin: right;}
|
|
.video-player { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 7; }
|
|
.clickable-overlay { position: absolute; top: 50px; left: 0; width: 100%; height: calc(100%); z-index: 2; pointer-events: none; background: transparent; transition: background 0.8s ease, backdrop-filter 0.8s ease;}
|
|
.clickable-overlay::before { content: ''; position: absolute; top: 25%; left: 0; width: 100%; height: 75%; background: linear-gradient(0deg, rgb(0% 0% 0%) 0%, rgba(0, 0, 0, 0.99) 6.25%, rgba(0, 0, 0, 0.96) 12.5%, rgba(0, 0, 0, 0.92) 18.75%, rgba(0, 0, 0, 0.86) 25%, rgba(0, 0, 0, 0.78) 31.25%, rgba(0, 0, 0, 0.69) 37.5%, rgba(0, 0, 0, 0.6) 43.75%, rgba(0, 0, 0, 0.5) 50%, rgba(0, 0, 0, 0.4) 56.25%, rgba(0, 0, 0, 0.31) 62.5%, rgba(0, 0, 0, 0.22) 68.75%, rgba(0, 0, 0, 0.14) 75%, rgba(0, 0, 0, 0.08) 81.25%, rgba(0, 0, 0, 0.04) 87.5%, rgba(0, 0, 0, 0.01) 93.75%, rgba(0, 0, 0, 0) 100% ); opacity: 0.15; transition: opacity 0.3s ease; z-index: 1;}
|
|
.clickable-overlay::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(180deg, rgb(0% 0% 0% / 0.9) 0%, rgb(0% 0% 0% / 0.6952285766601562) 6.25%, rgb(0% 0% 0% / 0.5275634765625) 12.5%, rgb(0% 0% 0% / 0.39222564697265627) 18.75%, rgb(0% 0% 0% / 0.284765625) 25%, rgb(0% 0% 0% / 0.20106353759765627) 31.25%, rgb(0% 0% 0% / 0.1373291015625) 37.5%, rgb(0% 0% 0% / 0.09010162353515627) 43.75%, rgb(0% 0% 0% / 0.05625000000000002) 50%, rgb(0% 0% 0% / 0.03297271728515627) 56.25%, rgb(0% 0% 0% / 0.017797851562500022) 62.5%, rgb(0% 0% 0% / 0.00858306884765625) 68.75%, rgb(0% 0% 0% / 0.003515625000000022) 75%, rgb(0% 0% 0% / 0.0011123657226562722) 81.25%, rgb(0% 0% 0% / 0.0002197265625000222) 87.5%, rgb(0% 0% 0% / 0.000013732910156272204) 93.75%, rgb(0% 0% 0% / 0) 100% ); opacity: 0.25; transition: opacity 0.3s ease, visibility 0.8s ease; z-index: 3; border-radius: 0.25em; }
|
|
.lorem-ipsum {position: relative; bottom: -44em; left: 59em; text-align: left; font-family: "Titillium Web", sans-serif; font-size: 92%; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1); opacity: 1; color: #fff; z-index: 4; box-sizing: border-box; background: transparent; max-width: fit-content; padding-left: 0.3em; padding-right: 0.3em; display: flex; flex-direction: row; max-height: 1.9em; padding-top: 0.15em; white-space: nowrap;}
|
|
.lorem-ipsum span { margin-right: 0.2em;}
|
|
.age-rating {position: absolute; top: 3.5em; left: 0em; text-align: left; font-family: "Titillium Web", sans-serif; font-size: 95%; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1); opacity: 1; color: #fff; z-index: 4; box-sizing: border-box; background: transparent; max-width: fit-content; padding-left: 0.3em; padding-right: 0.3em; display: flex; flex-direction: row; max-height: 1.9em; padding-top: 0.15em; white-space: nowrap;}
|
|
.plot { position: absolute; bottom: 0; left: -0.25em; right: 0; color: #fff; font-family: "Titillium Web", sans-serif; font-size: 0.9em; font-weight: 500; background: transparent; padding: 10px; z-index: 7; box-sizing: border-box; padding-bottom: 3px; padding-top: 0.5em; line-height: 1.2em; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1); display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; border-bottom-left-radius: 0.45em; transition: opacity 0.1s ease, max-height 0.8s ease; opacity: 0; max-width: 31%; opacity: 1; -webkit-line-clamp: 3; max-height: 7.8em;}
|
|
.genres { position: relative; bottom: -44.1em; color: #fff; z-index: 2; font-family: "Titillium Web", sans-serif; font-size: 0.79em; opacity: 1; transition: opacity 0.3s ease; max-width: 39em; overflow: hidden; height: 1.95em; padding-top: 0.25em; line-height: 2em; white-space: nowrap;}
|
|
.premiere-year {position: absolute; top: 5.75em; left: 0.5em; font-size: 0.9em; font-family: "Titillium Web", sans-serif; color: #fff; z-index: 3; opacity: 0; transition: opacity 0.3s; text-align: center; width: 3.5em;}
|
|
.additional-info {position: absolute; top: 7.3em; left: 31em; font-size: 0.9em; font-family: "Titillium Web", sans-serif; color: #fff; z-index: 3; opacity: 1; transition: opacity 0.3s; text-align: right; width: 5em;}
|
|
.community-rating {position: absolute; top: 5.75em; right: 69.5%; font-size: 0.9em; font-family: "Titillium Web", sans-serif; color: #fff; z-index: 3; opacity: 1; transition: opacity 0.3s; text-align: center; width: 3.6em; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1);}
|
|
.critic-rating {position: absolute; top: 5.75em; right: 73%; font-size: 0.9em; font-family: "Titillium Web", sans-serif; color: #fff; z-index: 3; opacity: 1; transition: opacity 0.3s; text-align: center; width: 3.9em; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1);}
|
|
@keyframes objectPositionAnimation { 0% { object-position: center 30%; } 40% { object-position: center 80%; } 80% { object-position: center 20%; } 100% { object-position: center 30%; }}
|
|
.star-icon { color: gold; font-size: 0.9em; padding-right: 0.2em; margin-left: -0.1em;}
|
|
@media (max-width: 1000px) { .age-rating {position: absolute; top: 3em; left: 0em; font-size: 0.7em;} .lorem-ipsum {font-size: 0.7em; transform: translateX(50%); right: 50vw !important; padding-left: 0; padding-right: 1.5em;} .lorem-ipsum span {background:transparent !important; border: none !important;}.logo { transform: translateX(-50%) translateY(-50%); top: 10.5em; left: 50% !important; max-width: 70%; max-height: 45%; transform-origin: 50% 50%;} .plot {display: none; opacity: 1 !important; font-size: 90%; bottom: 0.5em; -webkit-line-clamp: 2; max-height: 3.3em; overflow: hidden; width: 100% !important; max-width: 100%; line-height: 1.45em;} .lorem-ipsum::before { opacity:0; padding-bottom: 0.25em; } .clickable-overlay { background: linear-gradient(0deg, rgb(0% 0% 0%) 0%, rgb(0% 0% 0% / 0.9990234375) 6.25%, rgba(0, 0, 0, 0.99) 12.5%, rgba(0, 0, 0, 0.97) 18.75%, rgba(0, 0, 0, 0.94) 25%, rgba(0, 0, 0, 0.88) 31.25%, rgba(0, 0, 0, 0.79) 37.5%, rgba(0, 0, 0, 0.67) 43.75%, rgba(0, 0, 0, 0.5) 50%, rgba(0, 0, 0, 0.33) 56.25%, rgba(0, 0, 0, 0.21) 62.5%, rgba(0, 0, 0, 0.12) 68.75%, rgba(0, 0, 0, 0.06) 75%, rgba(0, 0, 0, 0.03) 81.25%, rgba(0, 0, 0, 0.01) 87.5%, rgba(0, 0, 0, 0) 93.75%, rgba(0, 0, 0, 0) 100% ); opacity: 0.8;} .backdrop {left: 0% !important; width: 100% !important; top: 2.95em;} .lorem-ipsum .full-content { opacity: 1; max-width: 100%;} .lorem-ipsum::before { opacity:1; backdrop-filter: blur(2px); transform: translateX(0);} .clickable-overlay::before { opacity: 0.98; backdrop-filter: blur(0px);} .slide:hover .clickable-overlay::before { opacity: 0.98;} .skip-button {opacity: 1 !important; font-size: 0.9em; top: 1.1em; color: #fff;} .genres {bottom: 4em; left: unset !important; overflow: hidden; max-width: 100vw !important; white-space: nowrap; left: 0; z-index: 8; color: #fff; font-size: 0.7em;} .genres span {background: transparent !important; border: none !important;} .additional-info {left: 18.5%; top: 5em; text-align: right;} .community-rating {left: 86vw !important; top: 19.45em !important; text-align: left; z-index: 8; font-size: 0.85em !important;} .critic-rating {font-size: 0.85em !important; left: 70vw !important; top: 19.45em !important; z-index: 8;} .additional-info {left: 18.5%; top: 5em; text-align: left;} .heading {z-index: 0;} .heading::before {display: none;} .video-container {max-width: 0 !important;} .watch-trailer-button {position: absolute; border: none; border-radius: 5px; padding: 0.5em 1em; padding-right: 1.5em; font-family: "Titillium Web", sans-serif; cursor: pointer; z-index: 10; transition: background-color 0.3s ease; align-items: center; justify-content: center; display: flex !important; top: unset !important; bottom: 0.4em; font-size: 0.7em !important; background: #fff9 !important; color: #000e !important; font-weight: 600; transform: translateX(-100%) !important; left: 47% !important;} .slide { box-shadow: none;} .text-container::before { display: none !important;} .buttons-container {top: unset !important; display: flex; position: absolute; bottom: 0.6em; left: 0em !important; width: 100vw; z-index: 10;} .details-button { background: #fff9 !important; color: 000e !important; position: absolute; border: none; border-radius: 5px; padding: 0.5em 1.5em; font-family: "Titillium Web", sans-serif; cursor: pointer; z-index: 10; transition: background-color 0.3s ease; align-items: center; justify-content: center; bottom: -0.4em; font-size: 0.7em !important; background: #fff9; color: #000e; font-weight: 600; transform: translateX(100%) !important; right: 47%; display: flex; padding-right: 2em;} .details-button:hover { background-color: #fffc;} .watch-trailer-button:hover { background-color: #fffc !important;} .details-button:hover { background-color: #fffc !important;} .fas {padding: 0.5em;}}
|
|
@media (max-width:1000px) and (orientation:portrait) {.back-button {right:58vw;} .skip-button {right: 0em; top: 0.25em !important;} .genres {right: 50vw; position: absolute; max-width: 95vw !important; overflow:hidden; top: unset; transform: translateX(50%); bottom: 6.5em;} .lorem-ipsum {position: absolute; left: unset; bottom: 4.25em;}}
|
|
@media (max-width:1000px) and (orientation:landscape) {.community-rating {left:89vw !important;} .critic-rating {left:76vw !important;} .back-button {right:70vw;} .skip-button {right: 0em; top: 0.25em !important;} .genres {position: absolute; bottom: 6.5em; top: unset; transform: translateX(50%); right: 50vw;} .lorem-ipsum {position: absolute; left: unset; bottom: 4.25em;}}
|
|
@media (min-width: 1001px) { .material-icons {font-size: 2em;}.details-button { color: white; background: #101010e3; font-size: 1.75em; padding: 0.25em; padding-left: 0.5em; padding-right: 0.75em; transition: background-color 0.3s ease; cursor: pointer; border-radius: 0.5em;} .lorem-ipsum { bottom: -47em; left: 59em; font-size: 1.1em; transform: translateX(-100%); transition: left 0.5s;} clickable-overlay {pointer-events: none;} .logo {max-height: 23em; position: absolute; top: 29em; transition: transform 0.1s ease, max-height 0.3s ease; max-width: 47em; left: 34em; transform: translateX(-50%) translateY(-50%); transition: left 0.5s, max-width 0.5s;} @media screen and (max-width:1400px){ .logo {max-width: 37em; left: 30em;} .lorem-ipsum {left: 55em;}} .watch-trailer-button {display: none;} .backdrop {filter: brightness(95%) contrast(105%) saturate(105%); left: 0%; width: 100%; transition: width 0.5s ease, filter 0.8s ease, transform 2s ease; filter: brightness(95%) contrast(105%) saturate(105%);} .slide {margin-top: -3.15em; height: 100vh;} .skip-button {top: 17.5em; right: 0.5em; font-size: 2em;} .video-container {top: 9em; height: 18.62em; right: 4em; border-radius: 0em; transform-origin: 100% 0; transition: transform 0.5s ease; transition-delay: 1s;} .plot {position: relative; bottom: -33.5em; left: 4em; font-size: 1.25em; max-width: 49em !important; width: 49em !important; -webkit-line-clamp: 3;} .genres {z-index: 3; bottom: unset; top: 10.5em; left: 5.1em; font-size: 1.1em; max-width: 74em;} .age-rating {font-size: 1.3em !important; position: absolute; left: 4em; top: 6.2em; white-space: nowrap;} .community-rating {top: 44em; left: 50em; font-size: 1.2em;} .critic-rating {top: 44em; left: 43em; font-size: 1.2em;} .heading::before {content: ''; position: absolute; top: 2.27em; left: 0; width: 100%; background: linear-gradient(0deg, rgb(0% 0% 0%) 0%, rgb(0% 0% 0% / 0.9903926402016152) 6.25%, rgb(0% 0% 0% / 0.9619397662556434) 12.5%, rgb(0% 0% 0% / 0.9157348061512727) 18.75%, rgb(0% 0% 0% / 0.8535533905932737) 25%, rgb(0% 0% 0% / 0.7777851165098011) 31.25%, rgb(0% 0% 0% / 0.6913417161825449) 37.5%, rgb(0% 0% 0% / 0.5975451610080642) 43.75%, rgb(0% 0% 0% / 0.5) 50%, rgb(0% 0% 0% / 0.4024548389919359) 56.25%, rgb(0% 0% 0% / 0.3086582838174552) 62.5%, rgb(0% 0% 0% / 0.22221488349019902) 68.75%, rgb(0% 0% 0% / 0.14644660940672627) 75%, rgb(0% 0% 0% / 0.08426519384872733) 81.25%, rgb(0% 0% 0% / 0.03806023374435663) 87.5%, rgb(0% 0% 0% / 0.009607359798384785) 93.75%, rgb(0% 0% 0% / 0) 100% ); height: 100vh; z-index:6; opacity: 1; bottom: 0;} .skip-button { position: absolute; top: 0.4em; right: 0.25em; font-size: 1.5em; color: #D3D3D3; cursor: pointer; z-index: 10; font-family: "Titillium Web", sans-serif; font-size: 1.35em; text-shadow: 1px 1px 4px rgba(0, 0, 0, 1);}}
|
|
@media (max-width: 500px) { .community-rating {left: 0em; top: 5.6em;} .critic-rating {left: 0em; top: 7.6em;} .additional-info {left: 18.5%; top: 5em; text-align: right;} .heading::before {display: none;} .logo {max-width: 60%; max-height: 35%; left: 50% !important;}}
|
|
.age-rating { font-weight: 600; font-size: 1.1em;} .additional-info {display: none;}
|
|
.age-rating span.gb-u, .age-rating span.u { background-color: #078c6d; color: white; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1);}
|
|
.age-rating span.gb-pg, .age-rating span.pg { background-color: #d7a203; color: white; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1);}
|
|
.age-rating span.gb-12a, .age-rating span.\31 2A { background-color: #ee7600; color: white; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1);}
|
|
.age-rating span.gb-12, .age-rating span.\31 2, .age-rating span.gb-15, .age-rating span.\31 2 { background-color: #e19887; color: #e2002d; border: 0.09em solid white !important; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1);}
|
|
.age-rating span.pg-13 { background-color: #157c0d; color: white; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1);}
|
|
.age-rating span.tv-y7, .age-rating span.tv-13, .age-rating span.tv-14, .age-rating span.\31 6, .age-rating span.tv-ma, .age-rating span.tv-y, .age-rating span.tv-g, .age-rating span.tv-pg { background-color: #157c0d; color: white; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1);}
|
|
.age-rating span.nc-17, .age-rating span.gb-18, .age-rating span.\31 8, .age-rating span.r { background-color: #c10f1f; color: white; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1);}
|
|
.age-rating span.au-g, .age-rating span.nz-g, .age-rating span.eu-pg, .age-rating span.ca-g, .age-rating span.jp-g, .age-rating span.de-0 { background-color: #078c6d; color: white; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1); }
|
|
.age-rating span.au-pg, .age-rating span.nz-pg, .age-rating span.eu-12, .age-rating span.ca-pg, .age-rating span.jp-pg12, .age-rating span.de-6 { background-color: #d7a203; color: white; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1); }
|
|
.age-rating span.au-m, .age-rating span.nz-m, .age-rating span.eu-16, .age-rating span.ca-14a, .age-rating span.jp-r15, .age-rating span.de-12 { background-color: #07b1e0; color: white; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1); }
|
|
.age-rating span.au-ma15, .age-rating span.nz-r15, .age-rating span.eu-18, .age-rating span.ca-18a, .age-rating span.jp-r18, .age-rating span.de-16 { background-color: #fc9712; color: white; border: 0.09em solid white !important; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1); }
|
|
.age-rating span.au-r18, .age-rating span.nz-r18, .age-rating span.ca-r, .age-rating span.jp-r18+, .age-rating span.de-18 { background-color: #c10f1f; color: white; text-shadow: 1px 1px 1px rgba(0, 0, 0, 1); }
|
|
.video-container {overflow: visible;}
|
|
.watch-trailer-button { }
|
|
.watch-trailer-button .fa-play { margin-right: 0.5em;}
|
|
.slide { opacity: 1; transition: opacity 0.31s ease-in-out, font-size 1s ease; }
|
|
.fade-in { opacity: 0; visibility: hidden; transition: opacity 0.31s ease-in-out;}
|
|
.fade-in-active { opacity: 1; visibility: visible;}
|
|
.fade-out { opacity: 0;}
|
|
.backdrop { transition: opacity 0.3s ease-in-out, width 0.5s ease, transform 1.5s ease, filter 1s ease;}
|
|
#video-overlay { position: fixed; top: 13vh; left: 0vw; width: 100%; height: 140vh; background-color: rgb(0, 0, 0); z-index: 1000; display: flex; background-size: cover; padding: 6vh; padding-top: 10vh; margin-top: -10vh;}
|
|
#video-overlay-content { position: relative; width: 90%; max-width: 100%; height: 60%; background-color: #000;}
|
|
#close-overlay { position: absolute; top: -1em; right: 0em; font-size: 1.5em; color: #7b7b7b; cursor: pointer;}
|
|
#countdown-bar-container { display: none; position: absolute; left: 0%; bottom: 0; width: 110%; height: 0.15em !important; background-color: rgba(0,0,0,0); z-index: 10;}
|
|
#countdown-bar { height: 100%; width: 0%; background-color: #ffffff; opacity: 0.5; transition: width 0.1s linear; border-radius: 1em;}
|
|
.video-player { mask-image: linear-gradient(45deg, rgb(0% 0% 0% / 0) 0%, rgb(0% 0% 0% / 0.1) 25%, rgb(0% 0% 0% / 0.7) 50%, rgb(0% 0% 0% / 1) 100% ); -webkit-mask-image: linear-gradient(45deg, rgb(0% 0% 0% / 0) 0%, rgb(0% 0% 0% / 0.1) 25%, rgb(0% 0% 0% / 0.7) 50%, rgb(0% 0% 0% / 1) 100% ); transition: mask-image 5s ease, -webkit-mask-image 5s ease; }
|
|
.video-container:hover { mask-image: none; -webkit-mask-image: none; transform:scale(1.335); transition-delay: 0s;}
|
|
.video-container:hover .video-player { mask-image: none; -webkit-mask-image: none;}
|
|
.skip-button {font-size: 2em; top: 50vh; position: absolute; z-index: 20; cursor: pointer; opacity: 0.5; transition: opacity 0.3s ease;} .skip-button:hover {opacity: 1;}
|
|
.buttons-container {display: flex; position: absolute; top: 53.6em; left: 8em; z-index: 10;}
|
|
.details-button:hover { background-color: #444;}
|
|
@media (min-width: 2000px) { .slide {font-size: 0.85vw;} .backdrop {top: 2em;}}
|
|
@media (min-width: 3000px) { .slide {.backdrop {top: 0em;} .slide {margin-top: -4vh;}}
|
|
@media screen and (min-aspect-ratio: 21/9) { .slide {font-size: 1.6vh; }}
|
|
.watch-trailer-button { position: absolute; border: none; border-radius: 5px; padding: 0.5em 1.5em; font-size: 0.9em; font-family: "Titillium Web", sans-serif; cursor: pointer; z-index: 10; transition: background-color 0.3s ease; align-items: center; justify-content: center; padding-right: 2em;}
|
|
.material-symbols-outlined { vertical-align: middle; font-size: 0.85em; opacity: 0.75; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="slides-container"></div>
|
|
<div id="video-overlay" style="display: none;">
|
|
<div id="video-overlay-content">
|
|
<span id="close-overlay" class="fas fa-times"></span>
|
|
<iframe id="trailer-video" width="100%" height="100%" frameborder="0" allowfullscreen></iframe>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
let title = 'Spotlight', moviesSeriesBoth = 3, shuffleInterval = 15000, plotMaxLength = 350, token = 'YOURAPIKEYHERE', useTrailers = true;
|
|
let isChangingSlide = false, player = null, slideChangeTimeout = null, isHomePageActive = false;
|
|
let currentLocation = window.top.location.href;
|
|
let movieList = [], currentMovieIndex = 0;
|
|
|
|
const createElem = (tag, className, textContent, src, alt) => {
|
|
const elem = document.createElement(tag);
|
|
if (className) elem.className = className;
|
|
if (textContent) elem.textContent = textContent;
|
|
if (src) elem.src = src;
|
|
if (alt) elem.alt = alt;
|
|
return elem;
|
|
};
|
|
|
|
// Check for screen size below 1000px
|
|
function isMobile() {
|
|
return window.innerWidth <= 1000;
|
|
}
|
|
|
|
const truncateText = (text, maxLength) => text.length > maxLength ? text.substr(0, maxLength) + '...' : text;
|
|
|
|
const cleanup = () => {
|
|
if (player) { player.destroy(); player = null; }
|
|
clearTimeout(slideChangeTimeout);
|
|
const container = document.getElementById('slides-container');
|
|
if (container) container.innerHTML = '';
|
|
};
|
|
|
|
const createSlideElement = (movie, hasVideo = false) => {
|
|
cleanup();
|
|
const container = document.getElementById('slides-container');
|
|
const slide = createElem('div', 'slide');
|
|
['backdrop', 'logo'].forEach(type => slide.appendChild(createElem('img', type, null, `/Items/${movie.Id}/Images/${type.charAt(0).toUpperCase() + type.slice(1)}${type === 'backdrop' ? '/0' : ''}`, type)));
|
|
slide.appendChild(createElem('div', 'heading', title));
|
|
|
|
const textContainer = createElem('div', 'text-container');
|
|
const premiereYear = movie.PremiereDate ? new Date(movie.PremiereDate).getFullYear() : 'Unknown';
|
|
const additionalInfo = movie.Type === 'Series' ?
|
|
(movie.ChildCount ? `${movie.ChildCount} Season${movie.ChildCount > 1 ? 's' : ''}` : 'Unknown Seasons') :
|
|
(movie.RunTimeTicks ? `${Math.round(movie.RunTimeTicks / 600000000)} min` : 'Unknown Runtime');
|
|
|
|
let loremText = `
|
|
<span style="border: 1px solid #fff8; background: #101010e3; border-radius: 0.5em; padding-left: 0.5em; padding-right: 0.5em; padding-top: 0.05em; padding-bottom: 0.05em; margin-left: 1em;">${additionalInfo}</span>
|
|
<span style="border: 1px solid #fff8; background: #101010e3; border-radius: 0.5em; padding-left: 0.5em; padding-right: 0.5em; padding-top: 0.05em; padding-bottom: 0.05em; margin-left: 1em;">${premiereYear}</span> `;
|
|
|
|
if (movie.CommunityRating) {
|
|
loremText += `<span style="border: 1px solid #fff8; background: #101010e3; border-radius: 0.5em; padding-left: 0.5em; padding-right: 0.5em; padding-top: 0.05em; padding-bottom: 0.05em; margin-left: 1em;">
|
|
<i class="star-icon fas fa-star"></i> ${movie.CommunityRating.toFixed(1)}
|
|
</span> `;
|
|
}
|
|
if (movie.CriticRating) {
|
|
loremText += `<span style="border: 1px solid #fff8; background: #101010e3; border-radius: 0.5em; padding-left: 0.5em; padding-right: 0.5em; padding-top: 0.05em; padding-bottom: 0.05em; margin-left: 1em;">
|
|
<img src="https://i.imgur.com/rMvyQMt.png" alt="Rotten Tomatoes" style="width: 1.05em; height: 1.25em; font-size: 0.9em; padding-right: 0.1em; margin-left: -0.1em; vertical-align: middle;">
|
|
${movie.CriticRating}%</span>`;
|
|
}
|
|
|
|
// Age Rating
|
|
|
|
const ageRating = movie.OfficialRating ? movie.OfficialRating : 'NR';
|
|
const ratingClass = ageRating.toLowerCase().replace(/ /g, '-');
|
|
|
|
const ageRatingDiv = createElem('div', 'age-rating');
|
|
const ageRatingSpan = createElem('span', ratingClass, ageRating);
|
|
ageRatingSpan.style.cssText = 'border: 0.09em solid currentColor; border-radius: .1em; padding: 0.2em; display: inline-block; text-align: center; line-height: 0.8em;';
|
|
ageRatingDiv.appendChild(ageRatingSpan);
|
|
slide.appendChild(ageRatingDiv);
|
|
|
|
// Genres Section
|
|
const genresDiv = createElem('div', 'genres');
|
|
if (movie.Genres && movie.Genres.length > 0) {
|
|
movie.Genres.forEach(genre => {
|
|
const genreElem = createElem('span', 'genre-item');
|
|
genreElem.textContent = genre;
|
|
genreElem.style.backgroundColor = '#101010e3';
|
|
genreElem.style.paddingLeft = '0.5em';
|
|
genreElem.style.paddingRight = '0.5em';
|
|
genreElem.style.paddingTop = '0.1em';
|
|
genreElem.style.paddingBottom = '0.1em';
|
|
genreElem.style.color = 'white';
|
|
genreElem.style.borderRadius = '0em';
|
|
genreElem.style.marginRight = '1em';
|
|
genreElem.style.border = '1px solid #fff8';
|
|
genreElem.style.borderRadius = '0.5em';
|
|
genresDiv.appendChild(genreElem);
|
|
});
|
|
} else {
|
|
genresDiv.textContent = 'Genres: N/A';
|
|
}
|
|
slide.appendChild(genresDiv);
|
|
|
|
const loremDiv = createElem('div', 'lorem-ipsum');
|
|
loremDiv.innerHTML = loremText;
|
|
textContainer.appendChild(loremDiv);
|
|
textContainer.appendChild(createElem('div', 'plot', truncateText(movie.Overview, plotMaxLength)));
|
|
slide.appendChild(textContainer);
|
|
|
|
// Create Details buttons
|
|
const buttonsContainer = createElem('div', 'buttons-container');
|
|
|
|
// Details Button
|
|
const detailsButton = createElem('button', 'details-button');
|
|
const playIcon = createElem('i', 'fas fa-play');
|
|
detailsButton.appendChild(playIcon);
|
|
detailsButton.appendChild(document.createTextNode(' Play'));
|
|
detailsButton.onclick = (e) => {
|
|
e.stopPropagation();
|
|
window.top.location.href = `/#!/details?id=${movie.Id}`; // Navigate to details page
|
|
};
|
|
|
|
// Append buttons to the container
|
|
buttonsContainer.appendChild(detailsButton);
|
|
slide.appendChild(buttonsContainer);
|
|
|
|
const backButton = createElem('div', 'back-button');
|
|
const backIcon = createElem('i', 'material-icons');
|
|
backIcon.textContent = 'chevron_left';
|
|
const skipButton = createElem('div', 'skip-button');
|
|
const skipIcon = createElem('i', 'material-icons');
|
|
skipIcon.textContent = 'chevron_right';
|
|
|
|
backButton.appendChild(backIcon);
|
|
skipButton.appendChild(skipIcon);
|
|
|
|
skipIcon.onclick = (e) => { e.stopPropagation(); fetchRandomMovie(); };
|
|
slide.appendChild(backButton);
|
|
slide.appendChild(skipButton);
|
|
|
|
const overlay = createElem('div', 'clickable-overlay');
|
|
overlay.onclick = () => window.top.location.href = `/#!/details?id=${movie.Id}`;
|
|
slide.appendChild(overlay);
|
|
|
|
if (hasVideo && movie.RemoteTrailers && movie.RemoteTrailers.length > 0) {
|
|
const trailerUrl = movie.RemoteTrailers[0].Url;
|
|
const watchTrailerButton = createElem('button', 'watch-trailer-button');
|
|
const playIcon = document.createElement('i');
|
|
playIcon.className = 'fas fa-film';
|
|
watchTrailerButton.appendChild(playIcon);
|
|
watchTrailerButton.appendChild(document.createTextNode(' Trailer'));
|
|
|
|
watchTrailerButton.onclick = (e) => {
|
|
e.stopPropagation();
|
|
if (isMobile()) {
|
|
// Show the video in an overlay for mobile
|
|
showVideoOverlay(trailerUrl);
|
|
} else {
|
|
// Open the trailer in a new tab for desktop
|
|
window.open(trailerUrl, '_blank');
|
|
}
|
|
};
|
|
|
|
slide.appendChild(watchTrailerButton);
|
|
}
|
|
|
|
if (useTrailers && hasVideo && movie.RemoteTrailers?.length > 0) {
|
|
const videoId = new URL(movie.RemoteTrailers[0].Url).searchParams.get('v');
|
|
const videoContainer = createElem('div', 'video-container');
|
|
const videoElement = createElem('div', 'video-player');
|
|
videoContainer.appendChild(videoElement);
|
|
slide.appendChild(videoContainer);
|
|
|
|
player = new YT.Player(videoElement, {
|
|
height: '100%', width: '100%', videoId,
|
|
events: {
|
|
'onReady': event => {
|
|
event.target.playVideo();
|
|
['backdrop', 'plot', 'lorem-ipsum'].forEach(cls => {
|
|
const element = document.querySelector(`.${cls}`);
|
|
if (element) element.style.width = '100%';
|
|
});
|
|
videoContainer.style.width = '27.6vw';
|
|
},
|
|
'onStateChange': event => { if (event.data === YT.PlayerState.ENDED) setTimeout(fetchRandomMovie, 100); },
|
|
'onError': () => {
|
|
console.error(`YouTube prevented playback of '${movie.Name}'`);
|
|
if (player) { player.destroy(); player = null; }
|
|
['backdrop', 'plot', 'lorem-ipsum'].forEach(cls => {
|
|
const element = document.querySelector(`.${cls}`);
|
|
if (element) element.style.width = '100%';
|
|
});
|
|
videoContainer.style.width = '0';
|
|
startSlideChangeTimer();
|
|
}
|
|
}
|
|
});
|
|
} else startSlideChangeTimer();
|
|
|
|
container.innerHTML = '';
|
|
container.appendChild(slide);
|
|
};
|
|
|
|
function addSwipeListeners(slide) {
|
|
let startX, startY, distX, distY;
|
|
const threshold = 50;
|
|
const restraint = 100;
|
|
|
|
slide.addEventListener('touchstart', e => {
|
|
const touch = e.touches[0];
|
|
startX = touch.clientX;
|
|
startY = touch.clientY;
|
|
});
|
|
|
|
slide.addEventListener('touchmove', e => {
|
|
const touch = e.touches[0];
|
|
distX = touch.clientX - startX;
|
|
distY = touch.clientY - startY;
|
|
});
|
|
|
|
slide.addEventListener('touchend', () => {
|
|
if (Math.abs(distX) > threshold && Math.abs(distY) < restraint) {
|
|
if (distX > 0) {
|
|
console.log('Swipe Right');
|
|
} else {
|
|
console.log('Swipe Left');
|
|
fetchRandomMovie();
|
|
}
|
|
}
|
|
distX = distY = 0;
|
|
});
|
|
}
|
|
|
|
// Show the video overlay
|
|
function showVideoOverlay(trailerUrl) {
|
|
const videoOverlay = document.getElementById('video-overlay');
|
|
const videoFrame = document.getElementById('trailer-video');
|
|
const closeOverlay = document.getElementById('close-overlay');
|
|
|
|
// Extract video ID from trailer URL
|
|
const videoId = new URL(trailerUrl).searchParams.get('v');
|
|
const embedUrl = `https://www.youtube.com/embed/${videoId}?autoplay=1`;
|
|
|
|
// Set iframe's source to trailer URL
|
|
videoFrame.src = embedUrl;
|
|
|
|
// Show the overlay
|
|
videoOverlay.style.display = 'block';
|
|
|
|
// Pause the slide timer when the video overlay is open
|
|
clearSlideChangeTimeout();
|
|
|
|
// Close the overlay when the X is clicked
|
|
closeOverlay.onclick = () => {
|
|
videoOverlay.style.display = 'none';
|
|
videoFrame.src = ''; // Stop the video
|
|
};
|
|
|
|
// Close the overlay when clicking outside content
|
|
window.onclick = (event) => {
|
|
if (event.target === videoOverlay) {
|
|
videoOverlay.style.display = 'none';
|
|
videoFrame.src = '';
|
|
}
|
|
};
|
|
}
|
|
|
|
// Close video overlay and restart slide timer
|
|
function closeVideoOverlay() {
|
|
const videoOverlay = document.getElementById('video-overlay');
|
|
const videoFrame = document.getElementById('trailer-video');
|
|
|
|
// Hide overlay
|
|
videoOverlay.style.display = 'none';
|
|
|
|
// Reset the iframe source
|
|
videoFrame.src = '';
|
|
|
|
// Restart slide change timer when video overlay is closed
|
|
startSlideChangeTimer();
|
|
}
|
|
|
|
function clearSlideChangeTimeout() {
|
|
if (slideChangeTimeout) {
|
|
clearTimeout(slideChangeTimeout);
|
|
slideChangeTimeout = null;
|
|
}
|
|
}
|
|
|
|
const startSlideChangeTimer = () => { clearTimeout(slideChangeTimeout); slideChangeTimeout = setTimeout(fetchRandomMovie, shuffleInterval); };
|
|
|
|
const checkBackdropAndLogo = movie => {
|
|
Promise.all(['/Images/Backdrop/0', '/Images/Logo'].map(url =>
|
|
fetch(`/Items/${movie.Id}${url}`, { method: 'HEAD' }).then(response => response.ok)
|
|
)).then(([backdropExists, logoExists]) =>
|
|
backdropExists && logoExists ? createSlideElement(movie, true) : fetchRandomMovie()
|
|
).catch(() => fetchRandomMovie());
|
|
};
|
|
|
|
const readCustomList = () =>
|
|
fetch('list.txt?' + new Date().getTime())
|
|
.then(response => response.ok ? response.text() : null)
|
|
.then(text => {
|
|
if (!text) return null;
|
|
const lines = text.split('\n').filter(Boolean);
|
|
title = lines.shift() || title;
|
|
return lines.map(line => line.trim().substring(0, 32));
|
|
})
|
|
.catch(() => null);
|
|
|
|
const fetchRandomMovie = () => {
|
|
if (isChangingSlide) return;
|
|
isChangingSlide = true;
|
|
if (movieList.length === 0) {
|
|
readCustomList().then(list => {
|
|
if (list) { movieList = list; currentMovieIndex = 0; }
|
|
fetchNextMovie();
|
|
});
|
|
} else fetchNextMovie();
|
|
};
|
|
|
|
const fetchNextMovie = () => {
|
|
const fetchCurrentUserId = () =>
|
|
fetch('/Sessions', {
|
|
headers: { 'Authorization': `MediaBrowser Client="Jellyfin Web", Device="YourDeviceName", DeviceId="YourDeviceId", Version="YourClientVersion", Token="${token}"` }
|
|
})
|
|
.then(response => response.json())
|
|
.then(sessions => {
|
|
const currentSession = sessions.find(session => session.UserId);
|
|
return currentSession ? currentSession.UserId : null;
|
|
})
|
|
.catch(() => null);
|
|
|
|
fetchCurrentUserId().then(currentUserId => {
|
|
if (!currentUserId) {
|
|
console.error('Could not retrieve the current user ID.');
|
|
return;
|
|
}
|
|
|
|
const headers = { 'Authorization': `MediaBrowser Client="Jellyfin Web", Device="YourDeviceName", DeviceId="YourDeviceId", Version="YourClientVersion", Token="${token}"` };
|
|
|
|
if (movieList.length > 0) {
|
|
if (currentMovieIndex >= movieList.length) currentMovieIndex = 0;
|
|
const movieId = movieList[currentMovieIndex];
|
|
currentMovieIndex++;
|
|
|
|
fetch(`/Users/${currentUserId}/Items/${movieId}?Fields=Overview,RemoteTrailers,PremiereDate,RunTimeTicks,ChildCount,Genres`, { headers })
|
|
.then(response => response.json())
|
|
.then(checkBackdropAndLogo)
|
|
.catch(() => startSlideChangeTimer())
|
|
.finally(() => { isChangingSlide = false; });
|
|
} else {
|
|
const itemTypes = moviesSeriesBoth === 1 ? 'Movie' : (moviesSeriesBoth === 2 ? 'Series' : 'Movie,Series');
|
|
fetch(`/Users/${currentUserId}/Items?IncludeItemTypes=${itemTypes}&Recursive=true&Limit=1&SortBy=random&Fields=Id,Overview,RemoteTrailers,PremiereDate,RunTimeTicks,ChildCount,Genres`, { headers })
|
|
.then(response => response.json())
|
|
.then(data => { if (data.Items[0]) checkBackdropAndLogo(data.Items[0]); })
|
|
.catch(() => startSlideChangeTimer())
|
|
.finally(() => { isChangingSlide = false; });
|
|
}
|
|
});
|
|
};
|
|
|
|
const checkNavigation = () => {
|
|
const newLocation = window.top.location.href;
|
|
if (newLocation !== currentLocation) {
|
|
currentLocation = newLocation;
|
|
const isHomePage = url => url.includes('/home') || url.endsWith('/web/') || url.endsWith('/web/index.html');
|
|
if (isHomePage(newLocation)) {
|
|
if (!isHomePageActive) {
|
|
console.log("Returning to homepage, reactivating slideshow");
|
|
isHomePageActive = true;
|
|
cleanup();
|
|
fetchRandomMovie();
|
|
}
|
|
} else if (isHomePageActive) {
|
|
console.log("Leaving homepage, cleaning up slideshow");
|
|
isHomePageActive = false;
|
|
cleanup();
|
|
}
|
|
}
|
|
};
|
|
|
|
setInterval(checkNavigation, 100);
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
if (window.innerWidth < 1001) useTrailers = false;
|
|
const isHomePage = url => url.includes('/home') || url.endsWith('/web/') || url.endsWith('/web/index.html');
|
|
if (isHomePage(window.top.location.href)) {
|
|
isHomePageActive = true;
|
|
readCustomList().then(list => {
|
|
if (list) { movieList = list; currentMovieIndex = 0; }
|
|
fetchRandomMovie();
|
|
});
|
|
}
|
|
});
|
|
|
|
window.addEventListener('unload', cleanup);
|
|
window.addEventListener('popstate', checkNavigation);
|
|
</script>
|
|
<script src="https://www.youtube.com/iframe_api"></script>
|
|
</body>
|
|
</html>
|