Add TheMovieDB Button & Large Image (#395)

* Add TheMovieDB Button & Large Image

* A lil formatting
This commit is contained in:
SerStars 2025-09-16 00:44:13 +02:00 • committed by GitHub
parent 3b6d8696f7
commit 9c47e13a15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -19,6 +19,11 @@ interface ActivityAssets {
small_text?: string;
}
interface ActivityButton {
label: string;
url: string;
}
interface Activity {
state: string;
details?: string;
@ -26,6 +31,7 @@ interface Activity {
start?: number;
};
assets?: ActivityAssets;
buttons?: Array<string>;
name: string;
application_id: string;
metadata?: {
@ -50,8 +56,6 @@ interface MediaData {
position?: number;
}
const settings = definePluginSettings({
serverUrl: {
description: "Jellyfin server URL (e.g., https://jellyfin.example.com)",
@ -78,6 +82,11 @@ const settings = definePluginSettings({
description: "Custom Rich Presence name (only used if 'Custom' is selected).\nOptions: {name}, {series}, {season}, {episode}, {artist}, {album}, {year}",
type: OptionType.STRING,
},
showTMDBButton: {
description: "Show TheMovieDB button in Rich Presence",
type: OptionType.BOOLEAN,
default: true,
},
overrideRichPresenceType: {
description: "Override the rich presence type",
type: OptionType.SELECT,
@ -123,6 +132,27 @@ function setActivity(activity: Activity | null) {
});
}
async function fetchTmdbData(query: string) {
try {
const res = await fetch(`https://api.vmohammad.dev/tmdb/search/multi?q=${encodeURIComponent(query)}`);
if (!res.ok) throw `${res.status} ${res.statusText}`;
const data = await res.json();
if (data.results && data.results.length > 0) {
const topResult = data.results[0];
return {
url: `https://www.themoviedb.org/${topResult.media_type}/${topResult.id}`,
posterPath: topResult.poster_path
? `https://image.tmdb.org/t/p/original${topResult.poster_path}`
: null
};
}
return null;
} catch (e) {
console.error("Failed to fetch TMDb data:", e);
return null;
}
}
export default definePlugin({
name: "JellyfinRichPresence",
description: "Rich presence for Jellyfin media server",
@ -274,12 +304,26 @@ export default definePlugin({
break;
}
const largeImage = mediaData.imageUrl;
let tmdbData: { url: string; posterPath?: string | null } | null = null;
if (settings.store.showTMDBButton) {
tmdbData = await fetchTmdbData(mediaData.seriesName || mediaData.name);
}
const assets: ActivityAssets = {
large_image: largeImage ? await getApplicationAsset(largeImage) : await getApplicationAsset("jellyfin"),
large_text: mediaData.album || mediaData.seriesName || undefined,
large_image: tmdbData?.posterPath ? await getApplicationAsset(tmdbData.posterPath) : mediaData.imageUrl ? await getApplicationAsset(mediaData.imageUrl) : undefined,
large_text: mediaData.seriesName || mediaData.album || undefined,
};
const buttons: ActivityButton[] = [];
if (settings.store.showTMDBButton) {
const result = await fetchTmdbData(mediaData.seriesName || mediaData.name);
if (result?.url) tmdbData = { url: result.url };
buttons.push({
label: "View on TheMovieDB",
url: `${tmdbData?.url}`
});
}
const getDetails = () => {
if (mediaData.type === "Episode" && mediaData.seriesName) {
return mediaData.seriesName;
@ -291,7 +335,7 @@ export default definePlugin({
if (mediaData.type === "Episode" && mediaData.seriesName) {
const season = mediaData.seasonNumber ? `S${mediaData.seasonNumber}` : "";
const episode = mediaData.episodeNumber ? `E${mediaData.episodeNumber}` : "";
return `${mediaData.name} ${season} - ${episode}`.trim();
return `${mediaData.name} (${season} - ${episode})`.trim();
}
return mediaData.artist || (mediaData.year ? `(${mediaData.year})` : undefined);
};
@ -309,8 +353,12 @@ export default definePlugin({
assets,
timestamps,
buttons: buttons.length ? buttons.map(v => v.label) : undefined,
metadata: {
button_urls: buttons.map(v => v.url),
},
type: richPresenceType,
flags: 1,
flags: 1
};
}
});