feat: add IIntroProvider for Wholphin/cinema-mode compatibility
All checks were successful
Publish Release / release (push) Successful in 1m34s

Registers TrailerIntroProvider as IIntroProvider. Queries fake-movie
items in the output folder and returns their local trailer extras
(LocalTrailers) as IntroInfo — mirroring jellyfin-plugin-cinemamode's
proven pattern so Wholphin plays the actual trailer, not the 3-second
black placeholder.

Recursion guard: items whose path starts with the output folder are
excluded from intro injection, so Wholphin's getIntros call on the
intro item itself returns empty. Server-scoped query bypasses library
visibility restrictions so hidden trailer libraries still work.

Adds TrailersPerMovie config option (default 1, 0 = disabled).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Martin
2026-06-09 13:03:34 -04:00
parent 3868876401
commit e84a897c27
6 changed files with 121 additions and 7 deletions

View File

@@ -217,6 +217,26 @@
</div>
</fieldset>
<!-- Cinema Mode Integration -->
<fieldset class="verticalSection verticalSection-extrabottompadding">
<legend><h3 class="sectionTitle">Cinema Mode Integration</h3></legend>
<p class="fieldDescription">
When enabled, this plugin registers as an <strong>IIntroProvider</strong> and
injects downloaded trailers before movies — compatible with Jellyfin's built-in
cinema mode support and clients like Wholphin.
The output folder must be added as a Jellyfin <strong>Movies</strong> library
and scanned before trailers appear.
</p>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="trailers-per-movie">Trailers per movie</label>
<input type="number" id="trailers-per-movie" is="emby-input" min="0" max="10" />
<div class="fieldDescription">
Number of trailers to play before each movie. Set to 0 to disable.
Default: 1.
</div>
</div>
</fieldset>
<!-- Advanced -->
<fieldset class="verticalSection verticalSection-extrabottompadding">
<legend><h3 class="sectionTitle">Advanced</h3></legend>
@@ -264,6 +284,7 @@
document.getElementById('lang-' + code).checked = langs.length === 0 || langs.indexOf(code) !== -1;
});
document.getElementById('max-total-trailers').value = config.MaxTotalTrailers ?? 50;
document.getElementById('trailers-per-movie').value = config.TrailersPerMovie ?? 1;
Dashboard.hideLoadingMsg();
});
});
@@ -291,6 +312,7 @@
// If all are checked treat it as "no preference" (empty string)
config.AllowedLanguages = checkedLangs.length === allLangCodes.length ? '' : checkedLangs.join(',');
config.MaxTotalTrailers = parseInt(document.getElementById('max-total-trailers').value, 10) || 50;
config.TrailersPerMovie = parseInt(document.getElementById('trailers-per-movie').value, 10) || 0;
ApiClient.updatePluginConfiguration(pluginId, config)
.then(Dashboard.processPluginConfigurationUpdateResult);
});