mirror of
https://github.com/IAmParadox27/jellyfin-plugin-media-bar.git
synced 2026-11-09 08:34:16 +01:00
Merge pull request #113 from MrRussLuther/prefer-main-trailer
Pick the main trailer instead of RemoteTrailers[0]
This commit is contained in:
1 file changed
+83
-9
+83
-9
@@ -22,6 +22,20 @@ const CONFIG = {
|
||||
fadeTransitionDuration: 500,
|
||||
slideAnimationEnabled: true,
|
||||
enableTrailers: true,
|
||||
// Name fragments identifying alternate cuts of a trailer: accessibility
|
||||
// variants and social crops. Matched case insensitively against the
|
||||
// RemoteTrailers entry name. These are demoted within their tier, so an
|
||||
// alternate cut loses to an ordinary entry of the same tier but still
|
||||
// beats lower tier promo clips, and an item whose only trailer is an
|
||||
// alternate cut still plays something.
|
||||
trailerAlternateCutTerms: [
|
||||
"sign language",
|
||||
"asl trailer",
|
||||
"audio description",
|
||||
"audio described",
|
||||
"described audio",
|
||||
"vertical",
|
||||
],
|
||||
youtubeApiLoadTimeoutMs: 8000,
|
||||
};
|
||||
|
||||
@@ -1198,6 +1212,73 @@ const SlideCreator = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Picks the YouTube video id of the most appropriate trailer for an item.
|
||||
*
|
||||
* RemoteTrailers arrives in metadata provider order, which is not preference
|
||||
* order. The first entry is frequently a promo clip, a teaser or an
|
||||
* accessibility variant rather than the main trailer, and it is not
|
||||
* guaranteed to be a YouTube link at all. Entries are ranked by name, with
|
||||
* provider order breaking ties, and any entry that does not yield a video id
|
||||
* is skipped instead of losing the trailer for that slide. Alternate cuts
|
||||
* are demoted within their tier: they lose to an ordinary entry of the same
|
||||
* tier but still beat lower tier promo clips.
|
||||
*
|
||||
* @param {Array} remoteTrailers - RemoteTrailers array from the item
|
||||
* @returns {string|null} YouTube video id, or null if no entry is usable
|
||||
*/
|
||||
selectTrailerVideoId(remoteTrailers) {
|
||||
if (!Array.isArray(remoteTrailers) || remoteTrailers.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rankName = (name) => {
|
||||
const text = (name || "").toLowerCase();
|
||||
const isAlternateCut = CONFIG.trailerAlternateCutTerms.some((term) =>
|
||||
text.includes(term),
|
||||
);
|
||||
|
||||
let rank;
|
||||
if (text.includes("official trailer")) rank = 5;
|
||||
else if (text.includes("final trailer") || text.includes("main trailer"))
|
||||
rank = 4;
|
||||
else if (text.includes("trailer")) rank = 3;
|
||||
else if (text.includes("teaser")) rank = 2;
|
||||
else rank = 1;
|
||||
|
||||
return isAlternateCut ? rank - 0.5 : rank;
|
||||
};
|
||||
|
||||
let best = null;
|
||||
|
||||
for (const trailer of remoteTrailers) {
|
||||
let videoId = null;
|
||||
try {
|
||||
const urlObj = new URL(trailer.Url);
|
||||
const host = urlObj.hostname.replace(/^www\./, "");
|
||||
if (host === "youtu.be") {
|
||||
videoId = urlObj.pathname.split("/")[1] || null;
|
||||
} else if (
|
||||
(host === "youtube.com" || host === "m.youtube.com") &&
|
||||
urlObj.pathname.startsWith("/embed/")
|
||||
) {
|
||||
videoId = urlObj.pathname.split("/")[2] || null;
|
||||
} else {
|
||||
videoId = urlObj.searchParams.get("v");
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (!videoId) continue;
|
||||
|
||||
const rank = rankName(trailer.Name);
|
||||
if (!best || rank > best.rank) {
|
||||
best = { videoId, rank };
|
||||
}
|
||||
}
|
||||
|
||||
return best ? best.videoId : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a slide element for an item
|
||||
* @param {Object} item - Item data
|
||||
@@ -1221,15 +1302,8 @@ const SlideCreator = {
|
||||
let videoId = null;
|
||||
let trailerContainer = null;
|
||||
|
||||
if (
|
||||
CONFIG.enableTrailers &&
|
||||
item.RemoteTrailers &&
|
||||
item.RemoteTrailers.length > 0
|
||||
) {
|
||||
try {
|
||||
const urlObj = new URL(item.RemoteTrailers[0].Url);
|
||||
videoId = urlObj.searchParams.get("v");
|
||||
} catch (e) {}
|
||||
if (CONFIG.enableTrailers) {
|
||||
videoId = this.selectTrailerVideoId(item.RemoteTrailers);
|
||||
|
||||
if (videoId) {
|
||||
trailerContainer = SlideUtils.createElement("div", {
|
||||
|
||||
Reference in new issue
Block a user