diff --git a/src/Jellyfin.Plugin.MediaBar/Controllers/MediaBarController.cs b/src/Jellyfin.Plugin.MediaBar/Controllers/MediaBarController.cs
index 38db0f9..e12eac0 100644
--- a/src/Jellyfin.Plugin.MediaBar/Controllers/MediaBarController.cs
+++ b/src/Jellyfin.Plugin.MediaBar/Controllers/MediaBarController.cs
@@ -53,5 +53,16 @@ namespace Jellyfin.Plugin.MediaBar.Controllers
return Content(regex, "text/html");
}
+
+ [HttpPost("Patch/MainJellyfinBundle")]
+ public ActionResult PatchMainBundle([FromBody] PatchRequestPayload payload)
+ {
+ string replacementText =
+ "window.PlaybackManager=this.playbackManager;console.log(\"PlaybackManager is now globally available:\",window.PlaybackManager);";
+
+ string regex = Regex.Replace(payload.Contents!, @"(this\.playbackManager=e,)", $"$1{replacementText}");
+
+ return Content(regex, "text/html");
+ }
}
}
\ No newline at end of file
diff --git a/src/Jellyfin.Plugin.MediaBar/Inject/slideshowpure.css b/src/Jellyfin.Plugin.MediaBar/Inject/slideshowpure.css
index 4afc598..e3b74dd 100644
--- a/src/Jellyfin.Plugin.MediaBar/Inject/slideshowpure.css
+++ b/src/Jellyfin.Plugin.MediaBar/Inject/slideshowpure.css
@@ -1,774 +1,687 @@
-@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");
+@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");
@media only screen and (min-width: 767px) {
- div[data-role="page"].page {
- overflow-y: scroll;
- scrollbar-width: none;
- -ms-overflow-style: none;
- }
+ div[data-role="page"].page {
+ overflow-y: scroll;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+ }
- div[data-role="page"].page::-webkit-scrollbar {
- display: none;
- }
+ div[data-role="page"].page::-webkit-scrollbar {
+ display: none;
+ }
- .backdrop,
- .slide {
- position: absolute;
- }
+ .backdrop,
+ .slide {
+ position: absolute;
+ }
- .featured-content,
- .plot-container {
- font-family: "Titillium Web", sans-serif;
- left: 0;
- }
+ .featured-content,
+ .plot-container {
+ font-family: "Titillium Web", sans-serif;
+ left: 0;
+ }
- .plot,
- body {
- overflow: hidden;
- }
+ .plot,
+ body {
+ overflow: hidden;
+ }
- .arrow {
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
- font-size: 24px;
- cursor: pointer;
- color: white;
- z-index: 3;
- display: flex;
- justify-content: center;
- align-items: center;
- }
+ .arrow {
+ position: absolute;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 24px;
+ cursor: pointer;
+ color: white;
+ z-index: 3;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
- .arrow::before {
- content: "";
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 40px;
- height: 40px;
- background-color: rgba(12, 110, 162, 0.7);
- border-radius: 50%;
- z-index: -1;
- }
+ .arrow::before {
+ content: "";
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 40px;
+ height: 40px;
+ background-color: rgba(12, 110, 162, 0.7);
+ border-radius: 50%;
+ z-index: -1;
+ }
- .left-arrow {
- left: 10px;
- }
+ .left-arrow {
+ left: 20px;
+ }
- .right-arrow {
- right: 10px;
- }
+ .right-arrow {
+ right: 20px;
+ }
- .dots-container {
- position: absolute;
- bottom: 5%;
- left: 0;
- right: 0;
- z-index: 2;
- display: flex;
- justify-content: center;
- align-items: center;
- width: 100vw;
- height: 22px;
- background-color: #ffffff00;
- gap: 2vw;
- }
+ .dots-container {
+ position: absolute;
+ bottom: 5%;
+ left: 0;
+ right: 0;
+ z-index: 2;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100vw;
+ height: 22px;
+ background-color: #ffffff00;
+ gap: 2vw;
+ }
- .dot {
- width: 15vw;
- height: 4px;
- background-color: #cecece;
- border-radius: 2px;
- cursor: pointer;
- transition: background-color 0.3s;
- }
+ .dot {
+ width: 15vw;
+ height: 4px;
+ background-color: #cecece;
+ border-radius: 2px;
+ cursor: pointer;
+ transition: background-color 0.3s;
+ }
- .dot.active {
- background-color: rgba(12, 110, 162, 0.7) !important;
- }
+ .dot.active {
+ background-color: rgba(12, 110, 162, 0.7) !important;
+ }
- body {
- margin: 0;
- padding: 0;
- }
+ body {
+ margin: 0;
+ padding: 0;
+ }
- .fade-in {
- opacity: 1 !important;
- }
+ .fade-in {
+ opacity: 1 !important;
+ }
- .fade-out {
- opacity: 0 !important;
- }
+ .fade-out {
+ opacity: 0 !important;
+ }
- #slides-container {
- position: relative;
- width: 100vw;
- height: 750px;
- overflow: hidden;
- margin: 0 auto;
- border-radius: 7px;
- top: -5em;
- }
+ #slides-container {
+ position: relative;
+ width: 92vw;
+ height: 650px;
+ overflow: hidden;
+ margin: 0 auto;
+ border-radius: 15px;
+ }
- .slide {
- transition: opacity 0.5s ease-in-out;
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- display: block;
- }
+ .slide {
+ transition: opacity 0.5s ease-in-out;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ display: block;
+ }
- .slide.active {
- opacity: 1;
- display: block;
- }
+ .slide.active {
+ opacity: 1;
+ display: block;
+ }
- .slide:focus {
- outline: #fff solid 2px;
- }
+ .slide:focus {
+ outline: #fff solid 2px;
+ }
- .backdrop-container {
- position: relative;
- top: -40%;
- right: -35%;
- width: 70%;
- height: 100%;
- }
+ .backdrop-container {
+ position: relative;
+ top: -40%;
+ right: -35%;
+ width: 70%;
+ height: 100%;
+ }
- .backdrop {
- right: 0;
- width: 100%;
- height: 100%;
- object-fit: cover;
- object-position: center 20%;
- border-radius: 5px;
- z-index: 1;
- mask-image: linear-gradient(
- to top,
- rgba(0, 0, 0, 0) 10%,
- rgba(0, 0, 0, 0.5) 15%,
- rgba(0, 0, 0, 1) 30%
- );
- -webkit-mask-image: linear-gradient(
- to top,
- rgba(0, 0, 0, 0) 10%,
- rgba(0, 0, 0, 0.5) 15%,
- rgba(0, 0, 0, 1) 30%
- );
- }
+ .backdrop {
+ right: 0;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ object-position: center 20%;
+ border-radius: 5px;
+ z-index: 1;
+ mask-image: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0) 10%,
+ rgba(0, 0, 0, 0.5) 15%,
+ rgba(0, 0, 0, 1) 30%
+ );
+ -webkit-mask-image: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0) 10%,
+ rgba(0, 0, 0, 0.5) 15%,
+ rgba(0, 0, 0, 1) 30%
+ );
+ }
- .backdrop-overlay {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.6);
- border-radius: 5px;
- z-index: 2;
- mask-image: linear-gradient(
- to top,
- rgba(0, 0, 0, 0) 10%,
- rgba(0, 0, 0, 0.5) 15%,
- rgba(0, 0, 0, 1) 30%
- );
- -webkit-mask-image: linear-gradient(
- to top,
- rgba(0, 0, 0, 0) 10%,
- rgba(0, 0, 0, 0.5) 15%,
- rgba(0, 0, 0, 1) 30%
- );
- }
+ .backdrop-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.6);
+ border-radius: 5px;
+ z-index: 2;
+ mask-image: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0) 10%,
+ rgba(0, 0, 0, 0.5) 15%,
+ rgba(0, 0, 0, 1) 30%
+ );
+ -webkit-mask-image: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0) 10%,
+ rgba(0, 0, 0, 0.5) 15%,
+ rgba(0, 0, 0, 1) 30%
+ );
+ }
- .logo-container {
- width: 45%;
- height: 40%;
- position: relative;
- display: flex;
- justify-content: left;
- align-items: left;
- }
+ .logo-container {
+ width: 45%;
+ height: 40%;
+ position: relative;
+ display: flex;
+ justify-content: left;
+ align-items: left;
+ }
- .logo {
- position: relative;
- max-height: 100%;
- max-width: 100%;
- height: auto;
- width: auto;
- object-fit: contain;
- z-index: 3;
- top: 5em;
- left: 8em;
- }
+ .logo {
+ position: relative;
+ max-height: 100%;
+ max-width: 100%;
+ height: auto;
+ width: auto;
+ object-fit: contain;
+ z-index: 3;
+ top: 5em;
+ left: 8em;
+ }
- .featured-content {
- position: absolute;
- top: 0;
- width: 100%;
- height: 50px;
- background-color: transparent;
- color: #d3d3d3;
- font-size: 22px;
- display: none;
- align-items: center;
- justify-content: flex-start;
- z-index: 2;
- }
+ .featured-content {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ height: 50px;
+ background-color: transparent;
+ color: #d3d3d3;
+ font-size: 22px;
+ display: none;
+ align-items: center;
+ justify-content: flex-start;
+ z-index: 2;
+ }
- .plot-container {
- position: absolute;
- bottom: 0;
- color: #fff;
- width: 50%;
- height: 60%;
- font-size: 15px;
- padding: 10px 0 25px 15px;
- border-radius: 5px;
- z-index: 3;
- box-sizing: border-box;
- display: flex;
- align-items: center;
- justify-content: center;
- text-align: justify;
- }
+ .plot-container {
+ position: absolute;
+ bottom: 0;
+ color: #fff;
+ width: 90%;
+ height: 60%;
+ font-size: 15px;
+ padding: 10px 0 25px 15px;
+ border-radius: 5px;
+ z-index: 3;
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-align: justify;
+ }
- .plot {
- display: -webkit-box;
- line-clamp: 4;
- -webkit-line-clamp: 4;
- -webkit-box-orient: vertical;
- left: 7.9em;
- position: absolute;
- top: 190px;
- }
+ .plot {
+ display: -webkit-box;
+ line-clamp: 4;
+ -webkit-line-clamp: 4;
+ -webkit-box-orient: vertical;
+ left: 7.9em;
+ position: absolute;
+ top: 190px;
+ }
- .gradient-overlay {
- position: absolute;
- top: 0;
- left: 0;
- width: 70%;
- height: 100%;
- background: linear-gradient(to right, #000 49%, rgba(0, 0, 0, 0) 70%);
- z-index: 2;
- mask-image: linear-gradient(
- to top,
- rgba(0, 0, 0, 0) 8%,
- rgba(0, 0, 0, 0.5) 10%,
- rgba(0, 0, 0, 1) 12%
- );
- -webkit-mask-image: linear-gradient(
- to top,
- rgba(0, 0, 0, 0) 8%,
- rgba(0, 0, 0, 0.5) 10%,
- rgba(0, 0, 0, 1) 12%
- );
- }
- .genre {
- position: absolute;
- top: calc(50% + 75px);
- left: 8.4em;
- text-align: center;
- color: #fff;
- font-family: "Titillium Web", sans-serif;
- font-size: 14px;
- z-index: 4;
- }
- .info-container {
- position: absolute;
- top: calc(50% + 0px);
- display: flex;
- align-items: center;
- justify-content: center;
- left: 2em !important;
- color: #fff;
- z-index: 4;
- }
- .rating-value {
- font-family: "Titillium Web", sans-serif;
- display: flex;
- align-items: center;
- margin: 0 6em;
- z-index: 5;
- position: relative;
- top: 1.5em;
- }
- .runTime {
- font-family: "Titillium Web", sans-serif;
- font-weight: 500;
- display: flex;
- align-items: center;
- margin: 0 8px;
- margin-right: -3px;
- }
- .rating-value img {
- margin-right: 6px;
- }
- .tomato-rating {
- display: flex;
- align-items: center;
- margin-left: 0;
- }
- .tomato-rating img {
- margin-left: 5px;
- }
- .age-rating {
- display: flex;
- align-items: center;
- margin-left: 5px;
- margin-right: 5px;
- border-radius: 5px;
- background: rgb(255 255 255 / 0.8);
- color: #000;
- border: none;
- font-weight: 600;
- white-space: nowrap;
- padding: 0 0.6em;
- }
- .date {
- font-family: "Titillium Web", sans-serif;
- font-weight: 500;
- display: flex;
- align-items: center;
- margin-right: 5px;
- margin-left: 2px;
- }
- .separator-icon {
- margin-left: 5px;
- margin-right: 5px;
- font-size: 10px;
- color: aquamarine;
- }
- .play-button {
- position: absolute;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 10px 20px;
- color: #fff;
- background-color: rgba(255, 255, 255, 0);
- border: none;
- border-radius: 50px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 300;
- transition: background-color 0.3s;
- z-index: 4;
- top: calc(50% + 190px);
- left: 6.8em;
- }
+ .gradient-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 70%;
+ height: 100%;
+ background: linear-gradient(to right, #000 49%, rgba(0, 0, 0, 0) 70%);
+ z-index: 2;
+ mask-image: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0) 8%,
+ rgba(0, 0, 0, 0.5) 10%,
+ rgba(0, 0, 0, 1) 12%
+ );
+ -webkit-mask-image: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0) 8%,
+ rgba(0, 0, 0, 0.5) 10%,
+ rgba(0, 0, 0, 1) 12%
+ );
+ }
+ .genre {
+ position: absolute;
+ top: calc(50% + 75px);
+ left: 8.4em;
+ text-align: center;
+ color: #fff;
+ font-family: "Titillium Web", sans-serif;
+ font-size: 14px;
+ z-index: 4;
+ }
+ .info-container {
+ position: absolute;
+ top: calc(50% + 0px);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ left: 2em !important;
+ color: #fff;
+ z-index: 4;
+ }
+ .rating-value {
+ font-family: "Titillium Web", sans-serif;
+ display: flex;
+ align-items: center;
+ margin: 0 6em;
+ z-index: 5;
+ position: relative;
+ top: 1.5em;
+ }
+ .runTime {
+ font-family: "Titillium Web", sans-serif;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ margin: 0 8px;
+ margin-right: -3px;
+ }
+ .rating-value img {
+ margin-right: 6px;
+ }
+ .tomato-rating {
+ display: flex;
+ align-items: center;
+ margin-left: 0;
+ }
+ .tomato-rating img {
+ margin-left: 5px;
+ }
+ .age-rating {
+ display: flex;
+ align-items: center;
+ margin-left: 5px;
+ margin-right: 5px;
+ border-radius: 5px;
+ background: rgb(255 255 255 / 0.8);
+ color: #000;
+ border: none;
+ font-weight: 600;
+ white-space: nowrap;
+ padding: 0 0.6em;
+ }
+ .date {
+ font-family: "Titillium Web", sans-serif;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ margin-right: 5px;
+ margin-left: 2px;
+ }
+ .separator-icon {
+ margin-left: 5px;
+ margin-right: 5px;
+ font-size: 10px;
+ color: aquamarine;
+ }
+ .button-container {
+ position: absolute;
+ top: calc(50% + 190px); /* Same as the previous button positions */
+ left: 7.5em;
+ display: flex;
+ gap: 2em; /* Space between buttons */
+ z-index: 5; /* Ensures it's above other elements */
+ }
+ .play-button,
+ .detail-button {
+ display: inline-flex; /* Ensures icon and text are on the same line */
+ align-items: center;
+ justify-content: center;
+ padding: 8px 16px; /* Slightly reduced padding for thinner buttons */
+ border: solid 2px;
+ border-radius: 25px; /* Sleeker look */
+ font-size: 14px;
+ white-space: nowrap; /* Prevents text wrapping */
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-weight: bold;
+ gap: 6px; /* Adds space between icon and text */
+ -webkit-tap-highlight-color: transparent;
+ }
- .play-icon {
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 20px;
- width: 30px;
- height: 30px;
- background-color: rgba(
- 12,
- 110,
- 162,
- 0.7
- );
- border: 3px solid rgba(12, 110, 162, 1);
- border-radius: 50%;
- }
+ .play-button {
+ background-color: #ffffff;
+ color: #000;
+ }
- .play-text {
- font-family: "Titillium Web", sans-serif;
- margin-left: 10px;
- font-size: 14px;
- color: #fff;
- }
- .detail-button {
- position: absolute;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 10px 20px;
- color: #fff;
- background-color: rgba(255, 255, 255, 0);
- border: none;
- border-radius: 50px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 300;
- transition: background-color 0.3s;
- z-index: 4;
- top: calc(50% + 190px);
- left: 15.8em;
- }
+ .detail-button {
+ background-color: rgba(255, 255, 255, 0);
+ color: #fff;
+ }
- .detail-icon {
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 20px;
- width: 30px;
- height: 30px;
- background-color: rgba(
- 12,
- 110,
- 162,
- 0.7
- );
- border: 3px solid rgba(12, 110, 162, 1);
- border-radius: 50%;
- }
+ .play-button:hover,
+ .detail-button:hover {
+ opacity: 0.8;
+ }
- .detail-text {
- font-family: "Titillium Web", sans-serif;
- margin-left: 10px;
- font-size: 14px;
- color: #fff;
- }
+ .play-icon,
+ .detail-icon {
+ font-size: 18px; /* Ensures icons are aligned with text */
+ display: flex;
+ align-items: center;
+ }
}
-
@media only screen and (max-width: 767px) {
- .backdrop,
- .slide {
- position: absolute;
- }
+ .backdrop,
+ .slide {
+ position: absolute;
+ }
- .arrow {
- position: absolute;
- bottom: 25px;
- font-size: 24px;
- cursor: pointer;
- color: rgba(255, 255, 255, 0.6);
- z-index: 4;
- -webkit-tap-highlight-color: transparent;
- }
+ .arrow {
+ position: absolute;
+ bottom: 25px;
+ font-size: 24px;
+ cursor: pointer;
+ color: rgba(255, 255, 255, 0.6);
+ z-index: 4;
+ -webkit-tap-highlight-color: transparent;
+ }
- .left-arrow {
- left: 10px;
- }
+ .left-arrow {
+ left: 10px;
+ }
- .right-arrow {
- right: 10px;
- }
+ .right-arrow {
+ right: 10px;
+ }
- .featured-content,
- .plot-container {
- font-family: "Titillium Web", sans-serif;
- left: 0;
- }
+ .featured-content,
+ .plot-container {
+ font-family: "Titillium Web", sans-serif;
+ left: 0;
+ }
- .plot,
- body {
- overflow: hidden;
- }
+ .plot,
+ body {
+ overflow: hidden;
+ }
- body {
- margin: 0;
- padding: 0;
- }
+ body {
+ margin: 0;
+ padding: 0;
+ }
- .fade-in {
- opacity: 1 !important;
- }
+ .fade-in {
+ opacity: 1 !important;
+ }
- .fade-out {
- opacity: 0 !important;
- }
+ .fade-out {
+ opacity: 0 !important;
+ }
- .dots-container {
- position: absolute;
- bottom: 11%;
- left: 50%;
- transform: translateX(-50%) scale(0.6);
- z-index: 2;
- display: flex;
- gap: 5px;
- background-color: #ffffff00;
- border-radius: 50px;
- justify-content: center;
- align-items: center;
- width: 140px;
- height: 22px;
- transition: opacity 0.5s ease-in-out;
- }
+ .dots-container {
+ position: absolute;
+ bottom: 11%;
+ left: 50%;
+ transform: translateX(-50%) scale(0.6);
+ z-index: 2;
+ display: flex;
+ gap: 5px;
+ background-color: #ffffff00;
+ border-radius: 50px;
+ justify-content: center;
+ align-items: center;
+ width: 140px;
+ height: 22px;
+ transition: opacity 0.5s ease-in-out;
+ }
- .dot {
- display: inline-block;
- width: 9px;
- height: 9px;
- margin: 0 5px;
- background-color: #cecece;
- border-radius: 50%;
- transition: background-color 0.3s;
- }
+ .dot {
+ display: inline-block;
+ width: 9px;
+ height: 9px;
+ margin: 0 5px;
+ background-color: #cecece;
+ border-radius: 50%;
+ transition: background-color 0.3s;
+ }
- .dot.active {
- width: 32px;
- height: 12px;
- background-color: rgba(12, 110, 162, 0.7);
- border-radius: 10px;
- }
+ .dot.active {
+ width: 32px;
+ height: 12px;
+ background-color: rgba(12, 110, 162, 0.7);
+ border-radius: 10px;
+ }
- #slides-container {
- position: relative;
- width: 92vw;
- height: 650px;
- overflow: hidden;
- margin: 0 auto;
- border-radius: 10px;
- }
+ #slides-container {
+ position: relative;
+ width: 92vw;
+ height: 650px;
+ overflow: hidden;
+ margin: 0 auto;
+ border-radius: 10px;
+ }
- .slide {
- transition: opacity 0.5s ease-in-out;
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- display: block;
- }
+ .slide {
+ transition: opacity 0.5s ease-in-out;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ display: block;
+ }
- .slide.active {
- opacity: 1;
- display: block;
- }
+ .slide.active {
+ opacity: 1;
+ display: block;
+ }
- .slide:focus {
- outline: #fff solid 2px;
- }
- .logo {
- position: absolute;
- bottom: 28%;
- left: 50%;
- transform: translateX(-50%);
- max-height: 60%;
- max-width: 80%;
- width: auto;
- z-index: 3;
- }
+ .slide:focus {
+ outline: #fff solid 2px;
+ }
+ .logo {
+ position: absolute;
+ bottom: 28%;
+ left: 50%;
+ transform: translateX(-50%);
+ max-height: 60%;
+ max-width: 80%;
+ width: auto;
+ z-index: 3;
+ }
- .backdrop {
- position: absolute;
- top: 45px;
- left: 0;
- width: 100%;
- height: calc(100% - 50px);
- object-fit: cover;
- object-position: center 20%;
- z-index: 1;
- border-radius: 13px;
- mask-image: linear-gradient(
- to top,
- rgba(0, 0, 0, 0) 10%,
- rgba(0, 0, 0, 0.5) 15%,
- rgba(0, 0, 0, 1) 30%
- );
- -webkit-mask-image: linear-gradient(
- to top,
- rgba(0, 0, 0, 0) 10%,
- rgba(0, 0, 0, 0.5) 15%,
- rgba(0, 0, 0, 1) 30%
- );
- }
+ .backdrop {
+ position: absolute;
+ top: 45px;
+ left: 0;
+ width: 100%;
+ height: calc(100% - 50px);
+ object-fit: cover;
+ object-position: center 20%;
+ z-index: 1;
+ border-radius: 13px;
+ mask-image: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0) 10%,
+ rgba(0, 0, 0, 0.5) 15%,
+ rgba(0, 0, 0, 1) 30%
+ );
+ -webkit-mask-image: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0) 10%,
+ rgba(0, 0, 0, 0.5) 15%,
+ rgba(0, 0, 0, 1) 30%
+ );
+ }
- .gradient-overlay {
- position: absolute;
- top: 45px;
- left: 0;
- width: 100%;
- height: calc(100% - 50px);
- background: rgba(0, 0, 0, 0.55);
- z-index: 2;
- border-radius: 13px;
- pointer-events: none;
- mask-image: linear-gradient(
- to top,
- rgba(0, 0, 0, 0) 10%,
- rgba(0, 0, 0, 0.5) 15%,
- rgba(0, 0, 0, 1) 30%
- );
- -webkit-mask-image: linear-gradient(
- to top,
- rgba(0, 0, 0, 0) 10%,
- rgba(0, 0, 0, 0.5) 15%,
- rgba(0, 0, 0, 1) 30%
- );
- }
+ .gradient-overlay {
+ position: absolute;
+ top: 45px;
+ left: 0;
+ width: 100%;
+ height: calc(100% - 50px);
+ background: rgba(0, 0, 0, 0.55);
+ z-index: 2;
+ border-radius: 13px;
+ pointer-events: none;
+ mask-image: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0) 10%,
+ rgba(0, 0, 0, 0.5) 15%,
+ rgba(0, 0, 0, 1) 30%
+ );
+ -webkit-mask-image: linear-gradient(
+ to top,
+ rgba(0, 0, 0, 0) 10%,
+ rgba(0, 0, 0, 0.5) 15%,
+ rgba(0, 0, 0, 1) 30%
+ );
+ }
- .genre {
- position: absolute;
- bottom: 16%;
- left: 50%;
- transform: translateX(-50%);
- text-align: center;
- color: #fff;
- width: 90%;
- max-width: 100%;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- font-family: "Titillium Web", sans-serif;
- font-size: 1.1em;
- font-weight: 500;
- z-index: 4;
- box-sizing: border-box;
- }
- .info-container {
- position: absolute;
- display: flex;
- align-items: center;
- justify-content: center;
- bottom: 20%;
- left: 50%;
- transform: translateX(-50%);
- font-size: 1.1em;
- color: #fff;
- z-index: 5;
- width: 100%;
- }
- .rating-value {
- font-family: "Titillium Web", sans-serif;
- font-weight: 500;
- display: flex;
- align-items: center;
- }
- .date {
- font-family: "Titillium Web", sans-serif;
- font-weight: 500;
- display: flex;
- align-items: center;
- margin-left: 2px;
- }
- .tomato-rating {
- display: flex;
- align-items: center;
- }
- .tomato-logo {
- margin-right: 3px;
- }
- .critic-logo {
- margin-left: 3px;
- }
- .imdb-logo {
- margin-right: 3px;
- }
- .age-rating {
- display: flex;
- align-items: center;
- border-radius: 5px;
- background: rgb(255 255 255 / 0.8);
- color: #000;
- border: none;
- font-weight: 600;
- white-space: nowrap;
- padding: 0 0.4em;
- }
- .separator-icon {
- margin-left: 5px;
- margin-right: 5px;
- font-size: 1px;
- color: aquamarine;
- }
- .featured-content,
- .plot {
- display: none;
- }
+ .genre {
+ position: absolute;
+ bottom: 16%;
+ left: 50%;
+ transform: translateX(-50%);
+ text-align: center;
+ color: #fff;
+ width: 90%;
+ max-width: 100%;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-family: "Titillium Web", sans-serif;
+ font-size: 1.1em;
+ font-weight: 500;
+ z-index: 4;
+ box-sizing: border-box;
+ }
+ .info-container {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ bottom: 20%;
+ left: 50%;
+ transform: translateX(-50%);
+ font-size: 1.1em;
+ color: #fff;
+ z-index: 5;
+ width: 100%;
+ }
+ .rating-value {
+ font-family: "Titillium Web", sans-serif;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ }
+ .date {
+ font-family: "Titillium Web", sans-serif;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ margin-left: 2px;
+ }
+ .tomato-rating {
+ display: flex;
+ align-items: center;
+ }
+ .tomato-logo {
+ margin-right: 3px;
+ }
+ .critic-logo {
+ margin-left: 3px;
+ }
+ .imdb-logo {
+ margin-right: 3px;
+ }
+ .age-rating {
+ display: flex;
+ align-items: center;
+ border-radius: 5px;
+ background: rgb(255 255 255 / 0.8);
+ color: #000;
+ border: none;
+ font-weight: 600;
+ white-space: nowrap;
+ padding: 0 0.4em;
+ }
+ .separator-icon {
+ margin-left: 5px;
+ margin-right: 5px;
+ font-size: 1px;
+ color: aquamarine;
+ }
+ .featured-content,
+ .plot {
+ display: none;
+ }
- .play-button {
- position: absolute;
- display: flex;
- align-items: center;
- justify-content: flex-start;
- padding: 10px 20px;
- color: #fff;
- background-color: rgba(255, 255, 255, 0);
- border: none;
- border-radius: 50px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 300;
- transition: background-color 0.3s;
- z-index: 4;
- bottom: 20px;
- left: 50%;
- transform: translateX(-110%) scale(1.2);
- outline: none;
- -webkit-tap-highlight-color: transparent;
- }
+ .button-container {
+ position: absolute;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ gap: 15px; /* Adjust spacing between buttons */
+ z-index: 4;
+ }
- .play-icon {
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 20px;
- width: 20px;
- height: 20px;
- background-color: rgba(
- 12,
- 110,
- 162,
- 0.7
- );
- border: 1.5px solid rgba(12, 110, 162, 1);
- border-radius: 50%;
- outline: none;
- -webkit-tap-highlight-color: transparent;
- }
+ .play-button,
+ .detail-button {
+ display: inline-flex; /* Ensures icon and text are on the same line */
+ align-items: center;
+ justify-content: center;
+ padding: 8px 16px; /* Slightly reduced padding for thinner buttons */
+ border: none;
+ border-radius: 20px; /* Sleeker look */
+ font-size: 14px;
+ white-space: nowrap; /* Prevents text wrapping */
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-weight: bold;
+ gap: 6px; /* Adds space between icon and text */
+ -webkit-tap-highlight-color: transparent;
+ }
- .play-text {
- display: block;
- font-family: "Titillium Web", sans-serif;
- margin-left: 5px;
- font-size: 14px;
- color: #fff;
- }
- .detail-button {
- position: absolute;
- display: flex;
- align-items: center;
- justify-content: flex-start;
- padding: 10px 20px;
- color: #fff;
- background-color: rgba(255, 255, 255, 0);
- border: none;
- border-radius: 50px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 300;
- transition: background-color 0.3s;
- z-index: 4;
- bottom: 20px;
- left: 50%;
- transform: translateX(10%) scale(1.2);
- outline: none;
- -webkit-tap-highlight-color: transparent;
- }
+ .play-button {
+ background-color: #ffffff;
+ color: #000;
+ }
- .detail-icon {
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 20px;
- width: 20px;
- height: 20px;
- background-color: rgba(
- 12,
- 110,
- 162,
- 0.7
- );
- border: 1.5px solid rgba(12, 110, 162, 1);
- border-radius: 50%;
- outline: none;
- -webkit-tap-highlight-color: transparent;
- }
+ .detail-button {
+ background-color: rgba(255, 255, 255, 0.2);
+ color: #fff;
+ }
- .detail-text {
- display: block;
- font-family: "Titillium Web", sans-serif;
- margin-left: 5px;
- color: #fff;
- }
-}
+ .play-button:hover,
+ .detail-button:hover {
+ opacity: 0.8;
+ }
+
+ .play-icon,
+ .detail-icon {
+ font-size: 18px; /* Ensures icons are aligned with text */
+ display: flex;
+ align-items: center;
+ }
+}
\ No newline at end of file
diff --git a/src/Jellyfin.Plugin.MediaBar/Inject/slideshowpure.js b/src/Jellyfin.Plugin.MediaBar/Inject/slideshowpure.js
index 548c8de..27dc4e0 100644
--- a/src/Jellyfin.Plugin.MediaBar/Inject/slideshowpure.js
+++ b/src/Jellyfin.Plugin.MediaBar/Inject/slideshowpure.js
@@ -1,487 +1,485 @@
-const slidesInit = () => {
- const shuffleInterval = 8000;
- let isTransitioning = false;
- const listFileName = `${window.location.origin}/web/avatars/list.txt`;
- const jsonCredentials = sessionStorage.getItem("json-credentials");
- let userId = null;
- let token = null;
- //const deviceId = localStorage.getItem("_deviceId2");
- //console.log(deviceId);
- if (jsonCredentials) {
- const credentials = JSON.parse(jsonCredentials);
- userId = credentials.Servers[0].UserId;
- token = credentials.Servers[0].AccessToken;
- }
- const shuffleArray = (array) => array.sort(() => Math.random() - 0.5);
- const truncateText = (element, maxLength) => {
- let text = element.innerText;
- if (text.length > maxLength)
- element.innerText = text.substring(0, maxLength) + "...";
- };
- const createSlideElement = (item, title) => {
- const itemId = item.Id;
- const plot = item.Overview || "No overview available";
- const rating = item.CommunityRating;
- const tomato = item.CriticRating;
- const runtime = item.RunTimeTicks;
- const genre = item.Genres;
- const youtube = item.RemoteTrailers;
- const age = item.OfficialRating;
- const date = item.PremiereDate;
- const season = item.ChildCount;
- function createSeparator() {
- const separatorHtml =
- '';
- const tempDiv = document.createElement("div");
- tempDiv.innerHTML = separatorHtml;
- return tempDiv.firstChild;
+const slidesInit = () => {
+ const shuffleInterval = 8000;
+ let isTransitioning = false;
+ const listFileName = `${window.location.origin}/web/avatars/list.txt`;
+ const jsonCredentials = sessionStorage.getItem("json-credentials");
+ let userId = null;
+ let token = null;
+ //const deviceId = localStorage.getItem("_deviceId2");
+ //console.log(deviceId);
+ if (jsonCredentials) {
+ const credentials = JSON.parse(jsonCredentials);
+ userId = credentials.Servers[0].UserId;
+ token = credentials.Servers[0].AccessToken;
}
- const slide = document.createElement("a");
- slide.className = "slide";
- slide.target = "_top";
- slide.rel = "noreferrer";
- slide.tabIndex = 0;
- slide.style.display = "none";
- const backdrop = document.createElement("img");
- backdrop.className = "backdrop";
- backdrop.src = `${window.location.origin}/Items/${itemId}/Images/Backdrop/0`;
- backdrop.alt = "Backdrop";
- const backdropOverlay = document.createElement("div");
- backdropOverlay.className = "backdrop-overlay";
- const backdropContainer = document.createElement("div");
- backdropContainer.className = "backdrop-container";
- backdropContainer.appendChild(backdrop);
- backdropContainer.appendChild(backdropOverlay);
- const logo = document.createElement("img");
- logo.className = "logo";
- logo.src = `${window.location.origin}/Items/${itemId}/Images/Logo`;
- logo.alt = "Logo";
- const logoContainer = document.createElement("div");
- logoContainer.className = "logo-container";
- logoContainer.appendChild(logo);
- const featuredContent = document.createElement("div");
- featuredContent.className = "featured-content";
- featuredContent.textContent = title;
- const plotElement = document.createElement("div");
- plotElement.className = "plot";
- plotElement.textContent = plot;
- truncateText(plotElement, 360);
- const plotContainer = document.createElement("div");
- plotContainer.className = "plot-container";
- plotContainer.appendChild(plotElement);
- const gradientOverlay = document.createElement("div");
- gradientOverlay.className = "gradient-overlay";
- const runTimeElement = document.createElement("div");
- runTimeElement.className = "runTime";
- if (season === undefined) {
- const milliseconds = runtime / 10000;
- const currentTime = new Date();
- const endTime = new Date(currentTime.getTime() + milliseconds);
- const options = { hour: "2-digit", minute: "2-digit", hour12: !0 };
- const formattedEndTime = endTime.toLocaleTimeString([], options);
- runTimeElement.textContent = `Ends at ${formattedEndTime}`;
- } else {
- runTimeElement.textContent = `${season} Season${season > 1 ? "s" : ""}`;
- }
- const ratingTest = document.createElement("div");
- ratingTest.className = "rating-value";
- const imdbLogo = document.createElement("img");
- imdbLogo.className = "imdb-logo";
- imdbLogo.src =
- "https://upload.wikimedia.org/wikipedia/commons/6/69/IMDB_Logo_2016.svg";
- imdbLogo.alt = "IMDb Logo";
- imdbLogo.style.width = "30px";
- imdbLogo.style.height = "30px";
- ratingTest.appendChild(imdbLogo);
- if (typeof rating === "number") {
- const formattedRating = rating.toFixed(1);
- ratingTest.innerHTML += `${formattedRating} ⭐`;
- } else {
- console.error("Rating is undefined or not a number:", rating);
- ratingTest.innerHTML += `N/A ⭐`;
- }
- ratingTest.appendChild(createSeparator());
- const tomatoRatingDiv = document.createElement("div");
- tomatoRatingDiv.className = "tomato-rating";
- const criticRating = item.CriticRating;
- const tomatoLogo = document.createElement("img");
- tomatoLogo.className = "tomato-logo";
- const criticLogo = document.createElement("img");
- criticLogo.className = "critic-logo";
- tomatoLogo.src =
- "https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Rotten_Tomatoes_positive_audience.svg/1920px-Rotten_Tomatoes_positive_audience.svg.png";
- let valueElement;
- if (typeof criticRating === "number") {
- valueElement = document.createTextNode(`${criticRating}% `);
- } else {
- valueElement = document.createTextNode(`N/A `);
- }
- if (criticRating === undefined || criticRating <= 59) {
- criticLogo.src =
- "https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Rotten_Tomatoes_rotten.svg/1024px-Rotten_Tomatoes_rotten.svg.png";
- criticLogo.alt = "Rotten Tomato";
- } else {
- criticLogo.src = "https://i.imgur.com/iMfwDk7.png";
- criticLogo.alt = "Fresh Tomato";
- }
- tomatoLogo.style.width = "15px";
- tomatoLogo.style.height = "17px";
- criticLogo.style.width = "15px";
- criticLogo.style.height = "15px";
- tomatoRatingDiv.appendChild(tomatoLogo);
- tomatoRatingDiv.appendChild(valueElement);
- tomatoRatingDiv.appendChild(criticLogo);
- tomatoRatingDiv.appendChild(createSeparator());
- const ageRatingDiv = document.createElement("div");
- ageRatingDiv.className = "age-rating";
- if (item.OfficialRating) {
- ageRatingDiv.innerHTML = `${item.OfficialRating}`;
- } else {
- ageRatingDiv.innerHTML = `N/A`;
- }
- const calender = "📅";
- const premiereDate = document.createElement("div");
- premiereDate.className = "date";
- const year = date ? new Date(date).getFullYear() : "N/A";
- premiereDate.textContent = isNaN(year) ? "N/A" : year;
- ratingTest.appendChild(tomatoRatingDiv);
- ratingTest.appendChild(document.createTextNode(calender));
- ratingTest.appendChild(premiereDate);
- ratingTest.appendChild(createSeparator());
- ratingTest.appendChild(ageRatingDiv);
- ratingTest.appendChild(createSeparator());
- ratingTest.appendChild(runTimeElement);
- const genresArray = item.Genres;
- function parseGenres(genresArray) {
- if (genresArray && genresArray.length > 0) {
- return genresArray.slice(0, 3).join(" 🔹 ");
- } else {
- return "No Genre Available";
- }
- }
- const genreElement = document.createElement("div");
- genreElement.className = "genre";
- genreElement.innerHTML = parseGenres(genresArray);
- const infoContainer = document.createElement("div");
- infoContainer.className = "info-container";
- infoContainer.appendChild(ratingTest);
- // Create a container for the buttons
-const buttonContainer = document.createElement("div");
-buttonContainer.className = "button-container"; // Add a class for styling
+ const shuffleArray = (array) => array.sort(() => Math.random() - 0.5);
+ const truncateText = (element, maxLength) => {
+ let text = element.innerText;
+ if (text.length > maxLength)
+ element.innerText = text.substring(0, maxLength) + "...";
+ };
+ const createSlideElement = (item, title) => {
+ const itemId = item.Id;
+ const plot = item.Overview || "No overview available";
+ const rating = item.CommunityRating;
+ const tomato = item.CriticRating;
+ const runtime = item.RunTimeTicks;
+ const genre = item.Genres;
+ const youtube = item.RemoteTrailers;
+ const age = item.OfficialRating;
+ const date = item.PremiereDate;
+ const season = item.ChildCount;
+ function createSeparator() {
+ const separatorHtml =
+ '';
+ const tempDiv = document.createElement("div");
+ tempDiv.innerHTML = separatorHtml;
+ return tempDiv.firstChild;
+ }
+ const slide = document.createElement("a");
+ slide.className = "slide";
+ slide.target = "_top";
+ slide.rel = "noreferrer";
+ slide.tabIndex = 0;
+ slide.style.display = "none";
+ const backdrop = document.createElement("img");
+ backdrop.className = "backdrop";
+ backdrop.src = `${window.location.origin}/Items/${itemId}/Images/Backdrop/0`;
+ backdrop.alt = "Backdrop";
+ const backdropOverlay = document.createElement("div");
+ backdropOverlay.className = "backdrop-overlay";
+ const backdropContainer = document.createElement("div");
+ backdropContainer.className = "backdrop-container";
+ backdropContainer.appendChild(backdrop);
+ backdropContainer.appendChild(backdropOverlay);
+ const logo = document.createElement("img");
+ logo.className = "logo";
+ logo.src = `${window.location.origin}/Items/${itemId}/Images/Logo`;
+ logo.alt = "Logo";
+ const logoContainer = document.createElement("div");
+ logoContainer.className = "logo-container";
+ logoContainer.appendChild(logo);
+ const featuredContent = document.createElement("div");
+ featuredContent.className = "featured-content";
+ featuredContent.textContent = title;
+ const plotElement = document.createElement("div");
+ plotElement.className = "plot";
+ plotElement.textContent = plot;
+ truncateText(plotElement, 360);
+ const plotContainer = document.createElement("div");
+ plotContainer.className = "plot-container";
+ plotContainer.appendChild(plotElement);
+ const gradientOverlay = document.createElement("div");
+ gradientOverlay.className = "gradient-overlay";
+ const runTimeElement = document.createElement("div");
+ runTimeElement.className = "runTime";
+ if (season === undefined) {
+ const milliseconds = runtime / 10000;
+ const currentTime = new Date();
+ const endTime = new Date(currentTime.getTime() + milliseconds);
+ const options = { hour: "2-digit", minute: "2-digit", hour12: !0 };
+ const formattedEndTime = endTime.toLocaleTimeString([], options);
+ runTimeElement.textContent = `Ends at ${formattedEndTime}`;
+ } else {
+ runTimeElement.textContent = `${season} Season${season > 1 ? "s" : ""}`;
+ }
+ const ratingTest = document.createElement("div");
+ ratingTest.className = "rating-value";
+ const imdbLogo = document.createElement("img");
+ imdbLogo.className = "imdb-logo";
+ imdbLogo.src =
+ "https://upload.wikimedia.org/wikipedia/commons/6/69/IMDB_Logo_2016.svg";
+ imdbLogo.alt = "IMDb Logo";
+ imdbLogo.style.width = "30px";
+ imdbLogo.style.height = "30px";
+ ratingTest.appendChild(imdbLogo);
+ if (typeof rating === "number") {
+ const formattedRating = rating.toFixed(1);
+ ratingTest.innerHTML += `${formattedRating} ⭐`;
+ } else {
+ console.error("Rating is undefined or not a number:", rating);
+ ratingTest.innerHTML += `N/A ⭐`;
+ }
+ ratingTest.appendChild(createSeparator());
+ const tomatoRatingDiv = document.createElement("div");
+ tomatoRatingDiv.className = "tomato-rating";
+ const criticRating = item.CriticRating;
+ const tomatoLogo = document.createElement("img");
+ tomatoLogo.className = "tomato-logo";
+ const criticLogo = document.createElement("img");
+ criticLogo.className = "critic-logo";
+ tomatoLogo.src =
+ "https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Rotten_Tomatoes_positive_audience.svg/1920px-Rotten_Tomatoes_positive_audience.svg.png";
+ let valueElement;
+ if (typeof criticRating === "number") {
+ valueElement = document.createTextNode(`${criticRating}% `);
+ } else {
+ valueElement = document.createTextNode(`N/A `);
+ }
+ if (criticRating === undefined || criticRating <= 59) {
+ criticLogo.src =
+ "https://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Rotten_Tomatoes_rotten.svg/1024px-Rotten_Tomatoes_rotten.svg.png";
+ criticLogo.alt = "Rotten Tomato";
+ } else {
+ criticLogo.src = "https://i.imgur.com/iMfwDk7.png";
+ criticLogo.alt = "Fresh Tomato";
+ }
+ tomatoLogo.style.width = "15px";
+ tomatoLogo.style.height = "17px";
+ criticLogo.style.width = "15px";
+ criticLogo.style.height = "15px";
+ tomatoRatingDiv.appendChild(tomatoLogo);
+ tomatoRatingDiv.appendChild(valueElement);
+ tomatoRatingDiv.appendChild(criticLogo);
+ tomatoRatingDiv.appendChild(createSeparator());
+ const ageRatingDiv = document.createElement("div");
+ ageRatingDiv.className = "age-rating";
+ if (item.OfficialRating) {
+ ageRatingDiv.innerHTML = `${item.OfficialRating}`;
+ } else {
+ ageRatingDiv.innerHTML = `N/A`;
+ }
+ const calender = "📅";
+ const premiereDate = document.createElement("div");
+ premiereDate.className = "date";
+ const year = date ? new Date(date).getFullYear() : "N/A";
+ premiereDate.textContent = isNaN(year) ? "N/A" : year;
+ ratingTest.appendChild(tomatoRatingDiv);
+ ratingTest.appendChild(document.createTextNode(calender));
+ ratingTest.appendChild(premiereDate);
+ ratingTest.appendChild(createSeparator());
+ ratingTest.appendChild(ageRatingDiv);
+ ratingTest.appendChild(createSeparator());
+ ratingTest.appendChild(runTimeElement);
+ const genresArray = item.Genres;
+ function parseGenres(genresArray) {
+ if (genresArray && genresArray.length > 0) {
+ return genresArray.slice(0, 3).join(" 🔹 ");
+ } else {
+ return "No Genre Available";
+ }
+ }
+ const genreElement = document.createElement("div");
+ genreElement.className = "genre";
+ genreElement.innerHTML = parseGenres(genresArray);
+ const infoContainer = document.createElement("div");
+ infoContainer.className = "info-container";
+ infoContainer.appendChild(ratingTest);
+ // Create a container for the buttons
+ const buttonContainer = document.createElement("div");
+ buttonContainer.className = "button-container"; // Add a class for styling
-// Create the Play button
-const playButton = document.createElement("button");
-playButton.className = "play-button";
-playButton.innerHTML = `
+ // Create the Play button
+ const playButton = document.createElement("button");
+ playButton.className = "play-button";
+ playButton.innerHTML = `
- Play Now
+ Play
`;
-playButton.onclick = async () => {
- if (!window.ApiClient) {
- console.error("Jellyfin API client is not available.");
- return;
- }
- const apiClient = window.ApiClient;
- const userId = apiClient.getCurrentUserId();
- if (!userId) {
- console.error("User not found.");
- return;
- }
- try {
- const sessions = await apiClient.getJSON(apiClient.serverAddress() + "/Sessions");
- if (!sessions.length) {
- console.error("No active Jellyfin sessions found.");
- return;
- }
+ playButton.onclick = async () => {
+ if (!window.PlaybackManager) {
+ console.error("PlaybackManager is not available.");
+ return;
+ }
- // Find the session matching the current user
- const userSession = sessions.find(session => session.UserId === userId);
- if (!userSession) {
- console.error("No active session found for the current user.");
- return;
- }
+ if (!window.ApiClient) {
+ console.error("Jellyfin API client is not available.");
+ return;
+ }
- const sessionId = userSession.Id;
- const playbackUrl = `${apiClient.serverAddress()}/Sessions/${sessionId}/Playing?StartPositionTicks=0&PlayCommand=PlayNow&StartIndex=0&ItemIds=${itemId}&api_key=${token}`;
+ const apiClient = window.ApiClient;
+ const userId = apiClient.getCurrentUserId();
- const response = await fetch(playbackUrl, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Authorization: `DeviceId="unique-device-id", Token="${token}"`,
- },
- });
+ if (!userId) {
+ console.error("User not found.");
+ return;
+ }
- if (response.status === 204) {
- console.log("Playback started successfully.");
- } else {
- const errorData = await response.json();
- console.error("Failed to start playback:", errorData);
- }
- } catch (error) {
- console.error("Error fetching sessions:", error);
- }
-};
+ try {
+ // Fetch the media item details
+ const item = await apiClient.getItem(userId, itemId);
+ if (!item) {
+ console.error("Media item not found.");
+ return;
+ }
-// Create the Details button
-const detailButton = document.createElement("button");
-detailButton.className = "detail-button";
-detailButton.innerHTML = `
+ // Initiate playback using PlaybackManager
+ window.PlaybackManager.play({
+ items: [item],
+ startPositionTicks: 0, // Start from beginning
+ isMuted: false,
+ isPaused: false,
+ })
+ .then(() => {
+ console.log("Playback started successfully.");
+ })
+ .catch((error) => {
+ console.error("Failed to start playback:", error);
+ });
+ } catch (error) {
+ console.error("Error starting playback:", error);
+ }
+ };
+
+ // Create the Details button
+ const detailButton = document.createElement("button");
+ detailButton.className = "detail-button";
+ detailButton.innerHTML = `
- More Info
+ Info
`;
-detailButton.onclick = () => {
- window.top.location.href = `/#!/details?id=${itemId}`;
-};
+ detailButton.onclick = () => {
+ window.top.location.href = `/#!/details?id=${itemId}`;
+ };
-// Append buttons to the button container
-buttonContainer.appendChild(playButton);
-buttonContainer.appendChild(detailButton);
+ // Append buttons to the button container
+ buttonContainer.appendChild(playButton);
+ buttonContainer.appendChild(detailButton);
-// Append all elements to the slide
-slide.append(
- logoContainer,
- backdropContainer,
- gradientOverlay,
- featuredContent,
- plotContainer,
- infoContainer,
- genreElement,
- buttonContainer // Add button container instead of individual buttons
-);
+ // Append all elements to the slide
+ slide.append(
+ logoContainer,
+ backdropContainer,
+ gradientOverlay,
+ featuredContent,
+ plotContainer,
+ infoContainer,
+ genreElement,
+ buttonContainer
+ );
-return slide;
- };
- const createSlideForItem = async (item, title) => {
- const container = document.getElementById("slides-container");
- const itemId = item.Id;
- const backdropUrl = `${window.location.origin}/Items/${itemId}/Images/Backdrop/0`;
- const logoUrl = `${window.location.origin}/Items/${itemId}/Images/Logo`;
- const [backdropExists, logoExists] = await Promise.all([
- fetch(backdropUrl, { method: "HEAD" }).then((res) => res.ok),
- fetch(logoUrl, { method: "HEAD" }).then((res) => res.ok),
- ]);
- if (backdropExists && logoExists) {
- const slideElement = createSlideElement(item, title);
- container.appendChild(slideElement);
- console.log(`Added slide for item ${itemId}`);
- if (container.children.length === 1) {
- showSlide(0);
- }
- } else {
- console.warn(`Skipping item ${itemId}: Missing backdrop or logo.`);
- }
- };
- const fetchItemDetails = async (itemId) => {
- const response = await fetch(
- `${window.location.origin}/Users/${userId}/Items/${itemId}`,
- {
- headers: {
- Authorization: `MediaBrowser Client="Jellyfin Web", Device="YourDeviceName", DeviceId="YourDeviceId", Version="YourClientVersion", Token="${token}"`,
- },
- }
- );
- const item = await response.json();
- console.log("Item Title:", item.Name);
- return item;
- };
- const fetchItemIdsFromList = async () => {
- try {
- const response = await fetch(listFileName);
- if (!response.ok) {
- throw new Error("Failed to fetch list.txt");
- }
- const text = await response.text();
- return text
- .split("\n")
- .map((id) => id.trim())
- .filter((id) => id);
- } catch (error) {
- console.error("Error fetching list.txt:", error);
- return [];
- }
- };
- const fetchItemsFromServer = async () => {
- try {
- const response = await fetch(
- `${window.location.origin}/Users/${userId}/Items?IncludeItemTypes=Movie,Series&Recursive=true&hasOverview=true&imageTypes=Logo,Backdrop&isPlayed=False&Limit=150`,
- {
- headers: {
- Authorization: `MediaBrowser Client="Jellyfin Web", Device="YourDeviceName", DeviceId="YourDeviceId", Version="YourClientVersion", Token="${token}"`,
- },
- }
- );
- const data = await response.json();
- const items = data.Items;
- const movies = items.filter((item) => item.Type === "Movie");
- const tvShows = items.filter((item) => item.Type === "Series");
- const shuffledMovies = shuffleArray(movies);
- const shuffledTvShows = shuffleArray(tvShows);
- const selectedMovies = shuffledMovies.slice(0, 15);
- const selectedTvShows = shuffledTvShows.slice(0, 15);
- const allItems = [];
- const maxLength = Math.max(selectedMovies.length, selectedTvShows.length);
- for (let i = 0; i < maxLength; i++) {
- if (i < selectedMovies.length) allItems.push(selectedMovies[i]);
- if (i < selectedTvShows.length) allItems.push(selectedTvShows[i]);
- }
- return allItems;
- } catch (error) {
- console.error("Error fetching items:", error);
- return [];
- }
- };
- const createSlidesForItems = async (items) => {
- await Promise.all(
- items.map((item) =>
- createSlideForItem(item, item.Type === "Movie" ? "Movie" : "TV Show")
- )
- );
- };
- const createPaginationDots = () => {
- const dotsContainer = document.createElement("div");
- dotsContainer.className = "dots-container";
- for (let i = 0; i < 5; i++) {
- const dot = document.createElement("span");
- dot.className = "dot";
- dotsContainer.appendChild(dot);
- }
- const container = document.getElementById("slides-container");
- container.appendChild(dotsContainer);
- };
- const showSlide = (index) => {
- const slides = document.querySelectorAll(".slide");
- const dots = document.querySelectorAll(".dot");
- slides.forEach((slide, i) => {
- if (i === index) {
- slide.style.display = "block";
- slide.offsetHeight;
- slide.style.opacity = "1";
- slide.classList.add("active");
- } else {
- slide.style.opacity = "0";
- slide.classList.remove("active");
- setTimeout(() => {
- slide.style.display = "none";
- }, 500);
- }
- });
- dots.forEach((dot, i) => {
- dot.classList.toggle("active", i === index % 5);
- });
- };
- const initializeSlideshow = () => {
- const slides = document.querySelectorAll(".slide");
- createPaginationDots();
- const container = document.getElementById("slides-container");
- let currentSlideIndex = 0;
- let focusedSlide = null;
- let containerFocused = !1;
- const updateCurrentSlide = (index) => {
- if (isTransitioning) return;
- isTransitioning = true;
- currentSlideIndex = (index + slides.length) % slides.length;
- showSlide(currentSlideIndex);
- setTimeout(() => {
- isTransitioning = false;
- }, 500);
+ return slide;
};
- const openActiveSlide = () => {
- if (focusedSlide) {
- window.location.href = focusedSlide.href;
- }
- };
- if (slides.length > 0) {
- showSlide(currentSlideIndex);
- container.style.display = "block";
- setTimeout(() => {
- setInterval(() => {
- updateCurrentSlide(currentSlideIndex + 1);
- }, shuffleInterval);
- }, 8000);
- }
- slides.forEach((slide) => {
- slide.addEventListener(
- "focus",
- () => {
- focusedSlide = slide;
- container.classList.remove("disable-interaction");
- },
- !0
- );
- slide.addEventListener(
- "blur",
- () => {
- if (focusedSlide === slide) {
- focusedSlide = null;
- }
- },
- !0
- );
- });
- document.addEventListener("keydown", (event) => {
- if (containerFocused) {
- switch (event.keyCode) {
- case 37:
- updateCurrentSlide(currentSlideIndex - 1);
- break;
- case 39:
- updateCurrentSlide(currentSlideIndex + 1);
- break;
- case 13:
- case 32:
- openActiveSlide();
- break;
+ const createSlideForItem = async (item, title) => {
+ const container = document.getElementById("slides-container");
+ const itemId = item.Id;
+ const backdropUrl = `${window.location.origin}/Items/${itemId}/Images/Backdrop/0`;
+ const logoUrl = `${window.location.origin}/Items/${itemId}/Images/Logo`;
+ const [backdropExists, logoExists] = await Promise.all([
+ fetch(backdropUrl, { method: "HEAD" }).then((res) => res.ok),
+ fetch(logoUrl, { method: "HEAD" }).then((res) => res.ok),
+ ]);
+ if (backdropExists && logoExists) {
+ const slideElement = createSlideElement(item, title);
+ container.appendChild(slideElement);
+ console.log(`Added slide for item ${itemId}`);
+ if (container.children.length === 1) {
+ showSlide(0);
+ }
+ } else {
+ console.warn(`Skipping item ${itemId}: Missing backdrop or logo.`);
}
- }
- });
- const leftArrow = document.createElement("div");
- const rightArrow = document.createElement("div");
- leftArrow.classList.add("arrow", "left-arrow");
- rightArrow.classList.add("arrow", "right-arrow");
- leftArrow.innerHTML = '';
- rightArrow.innerHTML = '';
- container.appendChild(leftArrow);
- container.appendChild(rightArrow);
- leftArrow.addEventListener("click", () =>
- updateCurrentSlide(currentSlideIndex - 1)
- );
- rightArrow.addEventListener("click", () =>
- updateCurrentSlide(currentSlideIndex + 1)
- );
- container.addEventListener("focus", () => {
- containerFocused = !0;
- });
- container.addEventListener("blur", () => {
- containerFocused = !1;
- });
- };
- const initializeSlides = async () => {
- const itemIds = await fetchItemIdsFromList();
- let items;
- if (itemIds.length > 0) {
- const itemPromises = itemIds.map((id) => fetchItemDetails(id));
- items = await Promise.all(itemPromises);
- } else {
- const allItems = await fetchItemsFromServer();
- const itemPromises = allItems.map((item) => fetchItemDetails(item.Id));
- items = await Promise.all(itemPromises);
- }
- items = shuffleArray(items);
- await createSlidesForItems(items);
- initializeSlideshow();
- };
- initializeSlides();
+ };
+ const fetchItemDetails = async (itemId) => {
+ const response = await fetch(
+ `${window.location.origin}/Users/${userId}/Items/${itemId}`,
+ {
+ headers: {
+ Authorization: `MediaBrowser Client="Jellyfin Web", Device="YourDeviceName", DeviceId="YourDeviceId", Version="YourClientVersion", Token="${token}"`,
+ },
+ }
+ );
+ const item = await response.json();
+ console.log("Item Title:", item.Name);
+ return item;
+ };
+ const fetchItemIdsFromList = async () => {
+ try {
+ const response = await fetch(listFileName);
+ if (!response.ok) {
+ throw new Error("Failed to fetch list.txt");
+ }
+ const text = await response.text();
+ return text
+ .split("\n")
+ .map((id) => id.trim())
+ .filter((id) => id);
+ } catch (error) {
+ console.error("Error fetching list.txt:", error);
+ return [];
+ }
+ };
+ const fetchItemsFromServer = async () => {
+ try {
+ const response = await fetch(
+ `${window.location.origin}/Users/${userId}/Items?IncludeItemTypes=Movie,Series&Recursive=true&hasOverview=true&imageTypes=Logo,Backdrop&isPlayed=False&Limit=150`,
+ {
+ headers: {
+ Authorization: `MediaBrowser Client="Jellyfin Web", Device="YourDeviceName", DeviceId="YourDeviceId", Version="YourClientVersion", Token="${token}"`,
+ },
+ }
+ );
+ const data = await response.json();
+ const items = data.Items;
+ const movies = items.filter((item) => item.Type === "Movie");
+ const tvShows = items.filter((item) => item.Type === "Series");
+ const shuffledMovies = shuffleArray(movies);
+ const shuffledTvShows = shuffleArray(tvShows);
+ const selectedMovies = shuffledMovies.slice(0, 15);
+ const selectedTvShows = shuffledTvShows.slice(0, 15);
+ const allItems = [];
+ const maxLength = Math.max(selectedMovies.length, selectedTvShows.length);
+ for (let i = 0; i < maxLength; i++) {
+ if (i < selectedMovies.length) allItems.push(selectedMovies[i]);
+ if (i < selectedTvShows.length) allItems.push(selectedTvShows[i]);
+ }
+ return allItems;
+ } catch (error) {
+ console.error("Error fetching items:", error);
+ return [];
+ }
+ };
+ const createSlidesForItems = async (items) => {
+ await Promise.all(
+ items.map((item) =>
+ createSlideForItem(item, item.Type === "Movie" ? "Movie" : "TV Show")
+ )
+ );
+ };
+ const createPaginationDots = () => {
+ const dotsContainer = document.createElement("div");
+ dotsContainer.className = "dots-container";
+ for (let i = 0; i < 5; i++) {
+ const dot = document.createElement("span");
+ dot.className = "dot";
+ dotsContainer.appendChild(dot);
+ }
+ const container = document.getElementById("slides-container");
+ container.appendChild(dotsContainer);
+ };
+ const showSlide = (index) => {
+ const slides = document.querySelectorAll(".slide");
+ const dots = document.querySelectorAll(".dot");
+ slides.forEach((slide, i) => {
+ if (i === index) {
+ slide.style.display = "block";
+ slide.offsetHeight;
+ slide.style.opacity = "1";
+ slide.classList.add("active");
+ } else {
+ slide.style.opacity = "0";
+ slide.classList.remove("active");
+ setTimeout(() => {
+ slide.style.display = "none";
+ }, 500);
+ }
+ });
+ dots.forEach((dot, i) => {
+ dot.classList.toggle("active", i === index % 5);
+ });
+ };
+ const initializeSlideshow = () => {
+ const slides = document.querySelectorAll(".slide");
+ createPaginationDots();
+ const container = document.getElementById("slides-container");
+ let currentSlideIndex = 0;
+ let focusedSlide = null;
+ let containerFocused = !1;
+ const updateCurrentSlide = (index) => {
+ if (isTransitioning) return;
+ isTransitioning = true;
+ currentSlideIndex = (index + slides.length) % slides.length;
+ showSlide(currentSlideIndex);
+ setTimeout(() => {
+ isTransitioning = false;
+ }, 500);
+ };
+ const openActiveSlide = () => {
+ if (focusedSlide) {
+ window.location.href = focusedSlide.href;
+ }
+ };
+ if (slides.length > 0) {
+ showSlide(currentSlideIndex);
+ container.style.display = "block";
+ setTimeout(() => {
+ setInterval(() => {
+ updateCurrentSlide(currentSlideIndex + 1);
+ }, shuffleInterval);
+ }, 8000);
+ }
+ slides.forEach((slide) => {
+ slide.addEventListener(
+ "focus",
+ () => {
+ focusedSlide = slide;
+ container.classList.remove("disable-interaction");
+ },
+ !0
+ );
+ slide.addEventListener(
+ "blur",
+ () => {
+ if (focusedSlide === slide) {
+ focusedSlide = null;
+ }
+ },
+ !0
+ );
+ });
+ document.addEventListener("keydown", (event) => {
+ if (containerFocused) {
+ switch (event.keyCode) {
+ case 37:
+ updateCurrentSlide(currentSlideIndex - 1);
+ break;
+ case 39:
+ updateCurrentSlide(currentSlideIndex + 1);
+ break;
+ case 13:
+ case 32:
+ openActiveSlide();
+ break;
+ }
+ }
+ });
+ const leftArrow = document.createElement("div");
+ const rightArrow = document.createElement("div");
+ leftArrow.classList.add("arrow", "left-arrow");
+ rightArrow.classList.add("arrow", "right-arrow");
+ leftArrow.innerHTML = '';
+ rightArrow.innerHTML = '';
+ container.appendChild(leftArrow);
+ container.appendChild(rightArrow);
+ leftArrow.addEventListener("click", () =>
+ updateCurrentSlide(currentSlideIndex - 1)
+ );
+ rightArrow.addEventListener("click", () =>
+ updateCurrentSlide(currentSlideIndex + 1)
+ );
+ container.addEventListener("focus", () => {
+ containerFocused = !0;
+ });
+ container.addEventListener("blur", () => {
+ containerFocused = !1;
+ });
+ };
+ const initializeSlides = async () => {
+ const itemIds = await fetchItemIdsFromList();
+ let items;
+ if (itemIds.length > 0) {
+ const itemPromises = itemIds.map((id) => fetchItemDetails(id));
+ items = await Promise.all(itemPromises);
+ } else {
+ const allItems = await fetchItemsFromServer();
+ const itemPromises = allItems.map((item) => fetchItemDetails(item.Id));
+ items = await Promise.all(itemPromises);
+ }
+ items = shuffleArray(items);
+ await createSlidesForItems(items);
+ initializeSlideshow();
+ };
+ initializeSlides();
};
document.addEventListener("DOMContentLoaded", () => {
- document.body.addEventListener("click", (event) => {
- const homeButton = event.target.matches(
- ".headerHomeButton, .css-17c09up, .mainDrawer-scrollContainer > a:nth-child(2)"
- );
- if (homeButton) {
- event.preventDefault();
- window.location.href = "/web/index.html#/home.html";
- setTimeout(handleHomeNavigation, 300);
- }
- });
-});
+ document.body.addEventListener("click", (event) => {
+ const homeButton = event.target.matches(
+ ".headerHomeButton, .css-17c09up, .mainDrawer-scrollContainer > a:nth-child(2)"
+ );
+ if (homeButton) {
+ event.preventDefault();
+ window.location.href = "/web/index.html#/home.html";
+ setTimeout(handleHomeNavigation, 300);
+ }
+ });
+});
\ No newline at end of file
diff --git a/src/Jellyfin.Plugin.MediaBar/Services/StartupService.cs b/src/Jellyfin.Plugin.MediaBar/Services/StartupService.cs
index 4f45027..ced7f3e 100644
--- a/src/Jellyfin.Plugin.MediaBar/Services/StartupService.cs
+++ b/src/Jellyfin.Plugin.MediaBar/Services/StartupService.cs
@@ -48,6 +48,14 @@ namespace Jellyfin.Plugin.MediaBar.Services
payloads.Add(payload);
}
+ {
+ JObject payload = new JObject();
+ payload.Add("id", "3d171ef1-a198-48ac-9a60-f6aa98e5fd6d");
+ payload.Add("fileNamePattern", "main.jellyfin.bundle.js");
+ payload.Add("tranformationEndpoint", "/MediaBar/Patch/MainJellyfinBundle");
+
+ payloads.Add(payload);
+ }
string? publishedServerUrl = m_serverApplicationHost.GetType()
.GetProperty("PublishedServerUrl", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(m_serverApplicationHost) as string;