Skip to content

Commit 1a14806

Browse files
authored
Adding plugin files
New plugin uploaded
1 parent 7340f35 commit 1a14806

3 files changed

Lines changed: 155 additions & 0 deletions

File tree

plugins/tmdb-backdrop/manifest

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
id: tmdb-backdrop
2+
name: TMDB Backdrops
3+
metadata:
4+
description: Check for TMDB URL, grab a backdrop, and display backdrop as background image
5+
version: 0.1
6+
date: "2026-02-11 00:00:00"
7+
requires: []
8+
source_repository: https://lurking987.github.io/stash-plugins/main/index.yml
9+
files:
10+
- tmdb-backdrop.yml
11+
- tmdb_ui.js
12+
- README.md
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: tmdb-backdrop
2+
description: Check for TMDB URL and display random backdrop as background image
3+
version: 0.1
4+
ui:
5+
javascript:
6+
- tmdb_ui.js
7+
csp:
8+
connect-src:
9+
- https://api.themoviedb.org
10+
settings:
11+
tmdbapikey:
12+
displayName: TMDB API Key
13+
type: STRING

plugins/tmdb-backdrop/tmdb_ui.js

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
(function () {
2+
'use strict';
3+
let apiKey = null;
4+
5+
async function waitForElement(selector) {
6+
return new Promise(resolve => {
7+
const intervalId = setInterval(() => {
8+
const element = document.querySelector(selector);
9+
if (element) { clearInterval(intervalId); resolve(element); }
10+
}, 100);
11+
});
12+
}
13+
14+
async function getSettings() {
15+
try {
16+
const query = `{ configuration { plugins } }`;
17+
const res = await fetch('/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query }) });
18+
const result = await res.json();
19+
const plugins = result.data?.configuration?.plugins || {};
20+
apiKey = plugins['tmdb-backdrop']?.tmdbapikey || plugins['tmdb-backdrop']?.TmdbApiKey;
21+
} catch (e) { console.error("TMDB Plugin: Settings failed", e); }
22+
}
23+
24+
const updateBackdrop = async (tmdbUrl) => {
25+
if (!apiKey) await getSettings();
26+
if (!apiKey) return console.error("TMDB Plugin: No API Key found in settings.");
27+
28+
const idMatch = tmdbUrl.match(/(movie|tv|collection)\/(\d+)/);
29+
if (!idMatch) return;
30+
const [_, type, tmdbId] = idMatch;
31+
32+
try {
33+
const response = await fetch(`https://api.themoviedb.org/3/${type}/${tmdbId}/images?api_key=${apiKey}`);
34+
const data = await response.json();
35+
36+
if (data.backdrops && data.backdrops.length > 0) {
37+
const randomIdx = Math.floor(Math.random() * data.backdrops.length);
38+
const filePath = data.backdrops[randomIdx].file_path;
39+
const imageUrl = `https://image.tmdb.org/t/p/original${filePath}`;
40+
41+
let styleBlock = document.getElementById('tmdb-dynamic-style');
42+
if (!styleBlock) {
43+
styleBlock = document.createElement('style');
44+
styleBlock.id = 'tmdb-dynamic-style';
45+
document.head.appendChild(styleBlock);
46+
}
47+
48+
// Target #group-page for the image and .detail-header for transparency
49+
styleBlock.innerHTML = `
50+
#group-page {
51+
background-image: linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.6)), url("${imageUrl}") !important;
52+
background-size: cover !important;
53+
background-attachment: fixed !important;
54+
background-position: center !important;
55+
min-height: 100vh;
56+
}
57+
#group-page .background-image-container {
58+
display: none !important;
59+
}
60+
/* Clear the header background to reveal the TMDB image */
61+
#group-page .detail-header {
62+
background-color: transparent !important;
63+
border-bottom: none !important; /* Optional: removes the bottom border line */
64+
}
65+
#group-page .filtered-list-toolbar {
66+
background-color: transparent !important;
67+
}
68+
#group-page .card {
69+
background-color: transparent !important;
70+
box-shadow: none !important;
71+
}
72+
#group-page .detail-body nav {
73+
border-bottom: solid 0px;
74+
}
75+
`;
76+
console.log("TMDB Plugin: Backdrop applied:", imageUrl);
77+
}
78+
} catch (e) { console.error("TMDB Plugin API Error:", e); }
79+
};
80+
81+
async function updateDOM() {
82+
const match = window.location.pathname.match(/\/groups\/(\d+)/);
83+
if (!match) return;
84+
85+
const id = match[1];
86+
// Wait for the specific ID shown in your HTML snippet
87+
await waitForElement('#group-page');
88+
89+
const gRes = await fetch('/graphql', {
90+
method: 'POST',
91+
headers: { 'Content-Type': 'application/json' },
92+
body: JSON.stringify({
93+
query: `query FindGroup($id: ID!) { findGroup(id: $id) { urls } }`,
94+
variables: { id: id }
95+
})
96+
});
97+
const gData = await gRes.json();
98+
const urls = gData.data?.findGroup?.urls || [];
99+
const tmdbUrl = urls.find(u => u.toLowerCase().includes('themoviedb.org'));
100+
101+
if (tmdbUrl) {
102+
updateBackdrop(tmdbUrl);
103+
} else {
104+
const styleBlock = document.getElementById('tmdb-dynamic-style');
105+
if (styleBlock) styleBlock.remove();
106+
}
107+
}
108+
109+
const handlePathChange = () => {
110+
if (window.location.pathname.match(/\/groups\/\d+/)) {
111+
updateDOM();
112+
}
113+
};
114+
115+
// MutationObserver to catch Stash's internal navigation
116+
const observeUrlChange = () => {
117+
let oldHref = document.location.href;
118+
const body = document.querySelector("body");
119+
const observer = new MutationObserver(() => {
120+
if (oldHref !== document.location.href) {
121+
oldHref = document.location.href;
122+
handlePathChange();
123+
}
124+
});
125+
observer.observe(body, { childList: true, subtree: true });
126+
};
127+
128+
handlePathChange();
129+
observeUrlChange();
130+
})();

0 commit comments

Comments
 (0)