feat: add integration with MDBList for item and genre retrieval

This commit is contained in:
mrcanelas
2025-06-07 14:55:04 -03:00
parent f20df66b47
commit 15994210f1
3 changed files with 128 additions and 2 deletions
+11
View File
@@ -4,9 +4,20 @@ const moviedb = new MovieDb(process.env.TMDB_API);
const { getGenreList } = require("./getGenreList");
const { getLanguages } = require("./getLanguages");
const { parseMedia } = require("../utils/parseProps");
const { fetchMDBListItems, parseMDBListItems } = require("../utils/mdbList");
const CATALOG_TYPES = require("../static/catalog-types.json");
async function getCatalog(type, language, page, id, genre, config) {
const mdblistKey = config.mdblistkey
if (id.startsWith("mdblist.")) {
const listId = id.split(".")[1];
const results = await fetchMDBListItems(listId, mdblistKey, language, page);
const parseResults = parseMDBListItems(results, type, genre);
return parseResults
}
const genreList = await getGenreList(language, type);
const parameters = await buildParameters(type, language, page, id, genre, genreList, config);
+26 -2
View File
@@ -1,6 +1,7 @@
require("dotenv").config();
const { getGenreList } = require("./getGenreList");
const { getLanguages } = require("./getLanguages");
const { getGenresFromMDBList } = require("../utils/mdbList");
const packageJson = require("../../package.json");
const catalogsTranslations = require("../static/translations.json");
const CATALOG_TYPES = require("../static/catalog-types.json");
@@ -98,6 +99,23 @@ function getOptionsForCatalog(catalogDef, type, showInHome, { years, genres_movi
}
}
async function createMDBListCatalog(userCatalog, mdblistKey) {
const listId = userCatalog.id.split(".")[1];
const genres = await getGenresFromMDBList(listId, mdblistKey);
return {
id: userCatalog.id,
type: userCatalog.type,
name: userCatalog.name,
pageSize: 20,
extra: [
{ name: "genre", options: genres, isRequired: false },
{ name: "skip" },
],
showInHome: userCatalog.showInHome,
};
}
async function getManifest(config) {
const language = config.language || DEFAULT_LANGUAGE;
const tmdbPrefix = config.tmdbPrefix === "true";
@@ -124,16 +142,21 @@ async function getManifest(config) {
const languagesArray = await getLanguages();
const filterLanguages = setOrderLanguage(language, languagesArray);
const isMDBList = (id) => id.startsWith("mdblist.");
const options = { years, genres_movie, genres_series, filterLanguages };
let catalogs = userCatalogs
let catalogs = await Promise.all(userCatalogs
.filter(userCatalog => {
const catalogDef = getCatalogDefinition(userCatalog.id);
if (isMDBList(userCatalog.id)) return true;
if (!catalogDef) return false;
if (catalogDef.requiresAuth && !sessionId) return false;
return true;
})
.map(userCatalog => {
if (isMDBList(userCatalog.id)) {
return createMDBListCatalog(userCatalog, config.mdblistkey);
}
const catalogDef = getCatalogDefinition(userCatalog.id);
const catalogOptions = getOptionsForCatalog(catalogDef, userCatalog.type, userCatalog.showInHome, options);
@@ -146,7 +169,7 @@ async function getManifest(config) {
translatedCatalogs,
userCatalog.showInHome
);
});
}));
if (config.searchEnabled !== "false") {
const searchCatalogMovie = {
@@ -169,6 +192,7 @@ async function getManifest(config) {
const activeConfigs = [
`Language: ${language}`,
`TMDB Account: ${sessionId ? 'Connected' : 'Not Connected'}`,
`MDBList Integration: ${config.mdblistkey ? 'Connected' : 'Not Connected'}`,
`IMDb Integration: ${provideImdbId ? 'Enabled' : 'Disabled'}`,
`RPDB Integration: ${config.rpdbkey ? 'Enabled' : 'Disabled'}`,
`Search: ${config.searchEnabled !== "false" ? 'Enabled' : 'Disabled'}`,
+91
View File
@@ -0,0 +1,91 @@
const axios = require("axios");
const getPosterPath = (url) => url.split("/").pop();
async function fetchMDBListItems(listId, apiKey, language, page) {
const offset = (page * 20) - 20;
try {
const url = `https://api.mdblist.com/lists/${listId}/items?language=${'pt-BR'}&limit=20&offset=${offset}&apikey=${apiKey}&append_to_response=genre,poster`;
const response = await axios.get(url);
return [
...(response.data.movies || []),
...(response.data.shows || [])
];
} catch (err) {
console.error("Error retrieving MDBList items:", err.message, err);
return [];
}
}
async function getGenresFromMDBList(listId, apiKey) {
try {
const items = await fetchMDBListItems(listId, apiKey);
const genres = [
...new Set(
items.flatMap(item =>
(item.genre || []).map(g => {
if (!g || typeof g !== "string") return null;
return g.charAt(0).toUpperCase() + g.slice(1).toLowerCase();
})
).filter(Boolean)
)
].sort();
return genres;
} catch(err) {
console.error("ERROR in getGenresFromMDBList:", err);
return [];
}
}
function parseMDBListItems(items, type, genreFilter) {
const availableGenres = [
...new Set(
items.flatMap(item =>
(item.genre || [])
.map(g =>
typeof g === "string"
? g.charAt(0).toUpperCase() + g.slice(1).toLowerCase()
: null
)
.filter(Boolean)
)
)
].sort();
let filteredItems = items;
if (genreFilter) {
filteredItems = filteredItems.filter(item =>
Array.isArray(item.genre) &&
item.genre.some(
g =>
typeof g === "string" &&
g.toLowerCase() === genreFilter.toLowerCase()
)
);
}
const metas = filteredItems
.filter(item => {
if (type === "series") return item.mediatype === "show";
if (type === "movie") return item.mediatype === "movie";
return false;
})
.map(item => ({
id: item.id
? `tmdb:${item.id}`
: item.imdb_id
? `tt${item.imdb_id}`
: undefined,
name: item.title,
type,
poster: `https://image.tmdb.org/t/p/w500/${getPosterPath(item.poster)}`,
genre: item.genre,
year: item.release_year,
imdb_id: item.imdb_id
}))
.filter(meta => meta.id && meta.name && meta.poster);
return { metas, availableGenres };
}
module.exports = { fetchMDBListItems, getGenresFromMDBList, parseMDBListItems };