From 69e9b079c6095ebbdd16150302ecd88f50645f00 Mon Sep 17 00:00:00 2001
From: knom
Date: Wed, 16 Jul 2025 20:40:50 +0200
Subject: [PATCH 1/2] Add trailer download functionality with TMDb and YouTube
integration
- Implemented trailer downloading logic in a new TrailerDownloader class.
- Added scheduled task for automatic trailer downloads.
- Added necessary dependencies for TMDb and YouTube downloading.
- Introduced new configuration options for TMDb API key and trailer download libraries.
- Updated HTML configuration to support new features.
- Updated README
---
.../Configuration/PluginConfiguration.cs | 9 +
.../Configuration/config.html | 150 ++++++++-
.../Jellyfin.Plugin.CinemaMode.csproj | 2 +
.../TrailerDownloader/MediaItem.cs | 19 ++
.../TrailerDownloader/TrailerDownloader.cs | 287 ++++++++++++++++++
.../TrailerDownloader/YoutubeDownloader.cs | 68 +++++
.../TrailerDownloaderScheduledTask.cs | 82 +++++
README.md | 63 +++-
8 files changed, 676 insertions(+), 4 deletions(-)
create mode 100644 Jellyfin.Plugin.CinemaMode/TrailerDownloader/MediaItem.cs
create mode 100644 Jellyfin.Plugin.CinemaMode/TrailerDownloader/TrailerDownloader.cs
create mode 100644 Jellyfin.Plugin.CinemaMode/TrailerDownloader/YoutubeDownloader.cs
create mode 100644 Jellyfin.Plugin.CinemaMode/TrailerDownloaderScheduledTask.cs
diff --git a/Jellyfin.Plugin.CinemaMode/Configuration/PluginConfiguration.cs b/Jellyfin.Plugin.CinemaMode/Configuration/PluginConfiguration.cs
index e5575bb..fdbecb7 100644
--- a/Jellyfin.Plugin.CinemaMode/Configuration/PluginConfiguration.cs
+++ b/Jellyfin.Plugin.CinemaMode/Configuration/PluginConfiguration.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using MediaBrowser.Model.Plugins;
@@ -75,6 +76,10 @@ public class PluginConfiguration : BasePluginConfiguration
public int NumberOfTrailers { get; set; }
public bool TrailerConsumeMode { get; set; }
+ public string TmdbApiKey { get; set; }
+
+ public string[] TrailerDownloadLibraries { get; set; }
+
public PluginConfiguration()
{
TrailerPreRollsLibrary = "-";
@@ -90,6 +95,10 @@ public PluginConfiguration()
NumberOfTrailers = 2;
EnforceRatingLimitTrailers = true;
TrailerConsumeMode = false;
+
+ TrailerDownloadLibraries = [];
+
+ TmdbApiKey = string.Empty;
}
}
}
diff --git a/Jellyfin.Plugin.CinemaMode/Configuration/config.html b/Jellyfin.Plugin.CinemaMode/Configuration/config.html
index a49bb72..9c7df2c 100644
--- a/Jellyfin.Plugin.CinemaMode/Configuration/config.html
+++ b/Jellyfin.Plugin.CinemaMode/Configuration/config.html
@@ -21,6 +21,11 @@
Cinema Mode
Playback settings. For more information, access the user guide via the above help button.
Pro-tip: Skip any pre-roll or trailer by pressing the next button in the player.
+
+ NEW: It is also possible to automatically download trailers from TMDb / Youtube on a daily
+ schedule as a task.
+ The trailers will be stored locally, alongside the movies as "xyz-trailer.mp4".
+
@@ -197,8 +202,49 @@
Seasonal Tag Definitions
-
-
+
+
+
+
+
@@ -469,6 +515,93 @@
Seasonal Tag Definitions
});
};
+ function initLibraryCheckboxes(selectedLibraries, selectAllID, libraryListID, prefix) {
+ var container = document.getElementById(libraryListID);
+ container.innerHTML = "";
+
+ // Check if "all libraries" should be selected
+ var selectedArray = selectedLibraries;
+ var includeAllLibraries = selectedArray.includes("*") && selectedArray.length === 1;
+
+ var selectAllCheckBox = document.getElementById(selectAllID);
+ selectAllCheckBox.checked = includeAllLibraries;
+
+ mediaFolders.then((folderArray) => {
+
+ // Add movie libraries as checkboxes
+ for (const folder of folderArray) {
+ if (folder.CollectionType == "movies") {
+ var listItem = document.createElement('div');
+ listItem.setAttribute("class", "listItem listItem-border");
+
+ var isSelected = selectedArray.includes(folder.ItemId);
+
+
+ // Create label
+ var label = document.createElement('label');
+
+ // Create checkbox input
+ var input = document.createElement('input');
+ input.setAttribute('is', 'emby-checkbox');
+ input.setAttribute('type', 'checkbox');
+ input.setAttribute('id', prefix + folder.ItemId);
+ input.setAttribute('name', prefix + folder.ItemId);
+ input.setAttribute('data-itemId', folder.ItemId);
+ if (isSelected) {
+ input.setAttribute('checked', 'true');
+ }
+
+ // Create span for label text
+ var span = document.createElement('span');
+ span.textContent = folder.Name;
+
+ // Assemble elements
+ label.appendChild(input);
+ label.appendChild(span);
+ listItem.appendChild(label);
+
+ container.appendChild(listItem);
+ }
+ }
+
+ // Add event listener for "Include All Libraries" checkbox
+ document.getElementById(selectAllID).addEventListener('change', function () {
+ var checkboxes = container.querySelectorAll('input[type="checkbox"]');
+ for (let checkbox of checkboxes) {
+ checkbox.checked = this.checked;
+ checkbox.disabled = this.checked;
+ }
+ });
+
+ // Run same logic right away: if "includeAll" is ticked, all other checkboxes should be checked and disabled
+ if (includeAllLibraries) {
+ var checkboxes = container.querySelectorAll('input[type="checkbox"]');
+ for (let checkbox of checkboxes) {
+ checkbox.checked = true;
+ checkbox.disabled = true;
+ }
+ }
+ });
+ }
+
+ function getSelectedLibrariesFromCheckboxes(selectAllID, libraryListID, prefix) {
+ var includeAllLibraries = document.getElementById(selectAllID).checked;
+ if (includeAllLibraries) {
+ return ["*"];
+ }
+
+ var container = document.getElementById(libraryListID);
+ var checkboxes = container.querySelectorAll('input[type="checkbox"]:checked');
+ var selected = [];
+
+ for (let checkbox of checkboxes) {
+ var id = checkbox.getAttribute("data-itemId");
+ selected.push(id);
+ }
+
+ return selected;
+ }
+
$('.cinemaModeConfigurationPage').on('pageshow', function () {
Dashboard.showLoadingMsg();
clearList('trailerPreRollLibrarySelect');
@@ -480,6 +613,7 @@