Add suports to personal lists #17

This commit is contained in:
mrcanelas
2024-10-31 19:24:48 -03:00
parent 14e09fd152
commit 2334c898dd
12 changed files with 306 additions and 251 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
{
"projectName": "tmdb-addon",
"lastCommit": "d6b45b1"
"lastCommit": "14e09fd"
}
+28 -2
View File
@@ -236,7 +236,7 @@
<img src="https://github.com/mrcanelas/tmdb-addon/raw/main/images/logo.png" alt="Logo" />
</div>
<h1 class="name">The Movie Database Addon</h1>
<h2 class="version">3.0.16</h2>
<h2 class="version">3.0.17</h2>
<h2 class="description">Metadata provided by TMDB.</h2>
<div class="separator"></div>
<h3 class="gives">This addon has more :</h3>
@@ -481,6 +481,10 @@
</select>
</form>
<div class="separator"></div>
<a id="tmdb-login" class="install-link" href="#">
<button>LOGIN WITH TMDB</button>
</a>
<div class="separator"></div>
<a id="installLink" class="install-link" href="#">
<button name="Install">INSTALL</button>
</a>
@@ -489,6 +493,17 @@
</div>
</div>
<script>
async function createSession() {
const response = await fetch('/request_token');
const requestToken = await response.text();
document.getElementById("tmdb-login").addEventListener("click", function () {
const tmdbAuthUrl = `https://www.themoviedb.org/authenticate/${requestToken}?redirect_to=${window.location.href}`;
window.location.href = tmdbAuthUrl;
});
}
createSession();
const arrayIMDB = [
"tt0016847",
"tt0049223",
@@ -556,8 +571,18 @@
installLink.onclick = () => {
return mainForm.reportValidity();
};
const updateLink = () => {
const updateLink = async () => {
const config = Object.fromEntries(new FormData(mainForm));
const urlParams = new URLSearchParams(window.location.search);
const requestToken = urlParams.get('request_token');
if (requestToken) {
const response = await fetch(`/session_id?request_token=${requestToken}`);
const sessionId = await response.text();
config.sessionId = sessionId
}
installLink.href =
"stremio://" +
window.location.host +
@@ -565,6 +590,7 @@
encodeURIComponent(JSON.stringify(config)) +
"/manifest.json";
};
mainForm.onchange = updateLink;
if (typeof updateLink === "function") updateLink();
+34 -5
View File
@@ -9,6 +9,8 @@ const { getTmdb } = require("./lib/getTmdb");
const { cacheWrapMeta } = require("./lib/getCache");
const { getTrending } = require("./lib/getTrending");
const { parseConfig, getRpdbPoster, checkIfExists } = require("./utils/parseProps");
const { getRequestToken, getSessionId } = require("./lib/getSession");
const { getFavorites, getWatchList } = require("./lib/getPersonalLists");
const getCacheHeaders = function (opts) {
opts = opts || {};
@@ -44,6 +46,17 @@ addon.get("/", async function (_, res) {
res.redirect("/configure");
});
addon.get("/request_token", async function (req, res) {
const requestToken = await getRequestToken()
respond(res, requestToken);
});
addon.get("/session_id", async function (req, res) {
const requestToken = req.query.request_token
const sessionId = await getSessionId(requestToken)
respond(res, sessionId);
});
addon.get("/:catalogChoices?/configure", async function (req, res) {
res.sendFile(path.join(__dirname + "/configure.html"));
});
@@ -66,6 +79,7 @@ addon.get("/:catalogChoices?/catalog/:type/:id/:extra?.json", async function (re
const language = config.language || DEFAULT_LANGUAGE;
const include_adult = config.include_adult || false
const rpdbkey = config.rpdbkey
const sessionId = config.sessionId
const { genre, skip, search } = req.params.extra
? Object.fromEntries(
new URLSearchParams(req.url.split("/").pop().split("?")[0].slice(0, -5)).entries()
@@ -74,11 +88,26 @@ addon.get("/:catalogChoices?/catalog/:type/:id/:extra?.json", async function (re
const page = Math.ceil(skip ? skip / 20 + 1 : undefined) || 1;
let metas = [];
try {
metas = search
? await getSearch(type, language, search, include_adult)
: id === "tmdb.trending"
? await getTrending(type, id, language, genre, page)
: await getCatalog(type, id, language, genre, page);
const args = [type, language, page];
if (search) {
metas = await getSearch(type, language, search, include_adult);
} else {
switch (id) {
case "tmdb.trending":
metas = await getTrending(...args, genre);
break;
case "tmdb.favorites":
metas = await getFavorites(...args, sessionId);
break;
case "tmdb.watchlist":
metas = await getWatchList(...args, sessionId);
break;
default:
metas = await getCatalog(...args, id, genre);
break;
}
}
} catch (e) {
res.status(404).send((e || {}).message || "Not found");
return;
+46 -56
View File
@@ -6,65 +6,55 @@ const { getLanguages } = require("./getLanguages");
const { getTrending } = require("./getTrending");
const { parseMedia } = require("../utils/parseProps");
async function getCatalog(type, id, language, genre, page) {
if (id === "tmdb.top" && !genre) {return await getTrending(type, id, language, "week", page)}
var parameters = {
language: language,
page: page,
};
const genre_id = await getGenreList(language, type);
async function getCatalog(type, language, page, id, genre) {
if (id === "tmdb.top" && !genre) return await getTrending(type, language, page, "week");
const genreList = await getGenreList(language, type);
const parameters = await buildParameters(type, language, page, id, genre, genreList);
const fetchFunction = type === "movie" ? moviedb.discoverMovie.bind(moviedb) : moviedb.discoverTv.bind(moviedb);
return fetchFunction(parameters)
.then((res) => ({
metas: res.results.map(el => parseMedia(el, type, genreList))
}))
.catch(console.error);
}
async function buildParameters(type, language, page, id, genre, genreList) {
const languages = await getLanguages();
if (type === "movie") {
if (id === "tmdb.top") {
let gen_name = ''
if (genre) {
gen_name = genre
? (genre_id.find((x) => x.name === genre) || {}).id || ''
: genre;
if (!gen_name) return Promise.reject(Error(`Could not find genre: ${genre}`))
const parameters = { language, page };
switch (id) {
case "tmdb.top":
parameters.with_genres = genre ? findGenreId(genre, genreList) : undefined;
if (type === "tv") {
parameters.watch_region = language.split('-')[1];
parameters.with_watch_monetization_types = "flatrate|free|ads|rent|buy";
}
parameters.with_genres = gen_name
} else if (id === "tmdb.year") {
parameters.primary_release_year = genre
} else if (id === "tmdb.language") {
parameters.with_original_language = languages
.find((lang) => lang.name === genre)
.iso_639_1.split("-")[0]
}
return await moviedb
.discoverMovie(parameters)
.then(async (res) => {
const metas = res.results.map(el => parseMedia(el, 'movie', genre_id));
return { metas };
})
.catch(console.error);
} else {
if (id === "tmdb.top") {
parameters.watch_region = language.split('-')[1]
parameters.with_watch_monetization_types = "flatrate|free|ads|rent|buy"
let gen_name = ''
if (genre) {
gen_name = genre
? (genre_id.find((x) => x.name === genre) || {}).id || ''
: genre;
if (!gen_name) return Promise.reject(Error(`Could not find genre: ${genre}`))
}
parameters.with_genres = gen_name
} else if (id === "tmdb.year") {
parameters.first_air_date_year = genre
} else if (id === "tmdb.language") {
parameters.with_original_language = languages
.find((lang) => lang.name === genre)
.iso_639_1.split("-")[0]
}
return await moviedb
.discoverTv(parameters)
.then(async (res) => {
const metas = res.results.map(el => parseMedia(el, 'tv', genre_id));
return { metas };
})
.catch(console.error);
break;
case "tmdb.year":
parameters[type === "movie" ? "primary_release_year" : "first_air_date_year"] = genre;
break;
case "tmdb.language":
parameters.with_original_language = findLanguageCode(genre, languages);
break;
default:
break;
}
return parameters;
}
function findGenreId(genre, genreList) {
const genreData = genreList.find((x) => x.name === genre);
if (!genreData) throw new Error(`Could not find genre: ${genre}`);
return genreData.id;
}
function findLanguageCode(genre, languages) {
const language = languages.find((lang) => lang.name === genre);
return language ? language.iso_639_1.split("-")[0] : "";
}
module.exports = { getCatalog };
+37 -106
View File
@@ -32,6 +32,7 @@ async function getManifest(config) {
const language = config.language || DEFAULT_LANGUAGE;
const usePrefix = config.use_tmdb_prefix === "true";
const provideImdbId = config.provide_imdbId === "true";
const sessionId = config.sessionId
const translatedCatalogs = loadTranslations(language);
const years = generateArrayOfYears(20);
const genres_movie = await getGenreList(language, "movie").then((genres) => genres.map((el) => el.name).sort());
@@ -40,6 +41,41 @@ async function getManifest(config) {
const filterLanguages = setOrderLanguage(language, languagesArray);
const descriptionSuffix = language && language !== DEFAULT_LANGUAGE ? ` with ${language} language.` : ".";
function createCatalog(id, type, nameKey, options, extraRequired = []) {
return {
id,
type,
name: `${usePrefix ? "TMDB - " : ""}${translatedCatalogs[nameKey]}`,
pageSize: 20,
extra: [
{ name: "genre", options, isRequired: extraRequired.includes("genre") },
{ name: "skip" },
...(extraRequired.includes("search") ? [{ name: "search" }] : [])
],
extraSupported: ["genre", "skip", ...(extraRequired.includes("search") ? ["search"] : [])],
...(extraRequired.length > 0 && { extraRequired })
};
}
const catalogs = [
createCatalog("tmdb.top", "movie", "popular", genres_movie, ["search"]),
createCatalog("tmdb.year", "movie", "year", years, ["genre"]),
createCatalog("tmdb.language", "movie", "language", filterLanguages, ["genre"]),
createCatalog("tmdb.trending", "movie", "trending", ["Day", "Week"], ["genre"]),
...(sessionId ? [
createCatalog("tmdb.favorites", "movie", "favorites"),
createCatalog("tmdb.watchlist", "movie", "watchlist")
] : []),
createCatalog("tmdb.top", "series", "popular", genres_series, ["search"]),
createCatalog("tmdb.year", "series", "year", years, ["genre"]),
createCatalog("tmdb.language", "series", "language", filterLanguages, ["genre"]),
createCatalog("tmdb.trending", "series", "trending", ["Day", "Week"], ["genre"]),
...(sessionId ? [
createCatalog("tmdb.favorites", "series", "favorites"),
createCatalog("tmdb.watchlist", "series", "watchlist")
] : [])
];
return {
id: package.name,
version: package.version,
@@ -55,112 +91,7 @@ async function getManifest(config) {
configurable: true,
configurationRequired: false,
},
catalogs: [
{
id: "tmdb.top",
type: "movie",
name: `${usePrefix ? "TMDB - " : ""}${translatedCatalogs.popular}`,
pageSize: 20,
extra: [
{ name: "genre", options: genres_movie },
{ name: "skip" },
{ name: "search" },
],
extraSupported: ["genre", "skip", "search"],
},
{
id: "tmdb.year",
type: "movie",
name: `${usePrefix ? "TMDB - " : ""}${translatedCatalogs.year}`,
pageSize: 20,
extra: [
{ name: "genre", options: years, isRequired: true },
{ name: "skip" },
],
extraSupported: ["genre", "skip"],
extraRequired: ["genre"],
},
{
id: "tmdb.language",
type: "movie",
name: `${usePrefix ? "TMDB - " : ""}${translatedCatalogs.language}`,
pageSize: 20,
extra: [
{
name: "genre",
options: filterLanguages,
isRequired: true,
},
{ name: "skip" },
],
extraSupported: ["genre", "skip"],
extraRequired: ["genre"],
},
{
id: "tmdb.trending",
type: "movie",
name: `${usePrefix ? "TMDB - " : ""}${translatedCatalogs.trending}`,
pageSize: 20,
extra: [
{ name: "genre", options: ["Day", "Week"], isRequired: true },
{ name: "skip" },
],
extraSupported: ["genre", "skip"],
extraRequired: ["genre"],
},
{
id: "tmdb.top",
type: "series",
name: `${usePrefix ? "TMDB - " : ""}${translatedCatalogs.popular}`,
pageSize: 20,
extra: [
{ name: "genre", options: genres_series },
{ name: "skip" },
{ name: "search" },
],
extraSupported: ["genre", "skip", "search"],
},
{
id: "tmdb.year",
type: "series",
name: `${usePrefix ? "TMDB - " : ""}${translatedCatalogs.year}`,
pageSize: 20,
extra: [
{ name: "genre", options: years, isRequired: true },
{ name: "skip" },
],
extraSupported: ["genre", "skip"],
extraRequired: ["genre"],
},
{
id: "tmdb.language",
type: "series",
name: `${usePrefix ? "TMDB - " : ""}${translatedCatalogs.language}`,
pageSize: 20,
extra: [
{
name: "genre",
options: filterLanguages,
isRequired: true,
},
{ name: "skip" },
],
extraSupported: ["genre", "skip"],
extraRequired: ["genre"],
},
{
id: "tmdb.trending",
type: "series",
name: `${usePrefix ? "TMDB - " : ""}${translatedCatalogs.trending}`,
pageSize: 20,
extra: [
{ name: "genre", options: ["Day", "Week"], isRequired: true },
{ name: "skip" },
],
extraSupported: ["genre", "skip"],
extraRequired: ["genre"],
}
],
catalogs,
};
}
+31
View File
@@ -0,0 +1,31 @@
require("dotenv").config();
const { MovieDb } = require("moviedb-promise");
const moviedb = new MovieDb(process.env.TMDB_API);
const { getGenreList } = require("./getGenreList");
const { parseMedia } = require("../utils/parseProps");
async function getFavorites(type, language, page, sessionId) {
moviedb.sessionId = sessionId
const genreList = await getGenreList(language, type);
const fetchFunction = type === "movie" ? moviedb.accountFavoriteMovies.bind(moviedb) : moviedb.accountFavoriteTv.bind(moviedb);
return fetchFunction({ language, page })
.then((res) => ({
metas: res.results.map(el => parseMedia(el, type, genreList))
}))
.catch(console.error);
}
async function getWatchList(type, language, page, sessionId) {
moviedb.sessionId = sessionId
const genreList = await getGenreList(language, type);
const fetchFunction = type === "movie" ? moviedb.accountMovieWatchlist.bind(moviedb) : moviedb.accountTvWatchlist.bind(moviedb);
return fetchFunction({ language, page })
.then((res) => ({
metas: res.results.map(el => parseMedia(el, type, genreList))
}))
.catch(console.error);
}
module.exports = { getFavorites, getWatchList }
+25
View File
@@ -0,0 +1,25 @@
require("dotenv").config();
const axios = require("axios")
const { MovieDb } = require("moviedb-promise");
const moviedb = new MovieDb(process.env.TMDB_API);
moviedb.sessionId = '051e2865c49c81d4c010d1506d9adaef033b2e65'
async function getRequestToken() {
return moviedb.requestToken()
.then(response => {
if (response.success) {
return response.request_token
}
})
}
async function getSessionId(requestToken) {
return axios.get(`https://api.themoviedb.org/3/authentication/session/new?api_key=${process.env.TMDB_API}&request_token=${requestToken}`)
.then(response => {
if (response.data.success) {
return response.data.session_id
}
})
}
module.exports = { getRequestToken, getSessionId }
+3 -3
View File
@@ -4,7 +4,7 @@ const moviedb = new MovieDb(process.env.TMDB_API);
const { getGenreList } = require("./getGenreList");
const { parseMedia } = require("../utils/parseProps");
async function getTrending(type, id, language, genre, page) {
async function getTrending(type, language, page, genre) {
const media_type = type === "series" ? "tv" : type
const parameters = {
media_type,
@@ -12,11 +12,11 @@ async function getTrending(type, id, language, genre, page) {
language,
page,
};
const genre_id = await getGenreList(language, type);
const genreList = await getGenreList(language, type);
return await moviedb
.trending(parameters)
.then(async (res) => {
const metas = res.results.map(el => parseMedia(el, media_type, genre_id));
const metas = res.results.map(el => parseMedia(el, type, genreList));
return { metas };
})
.catch(console.error);
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "tmdb-addon",
"version": "3.0.16",
"version": "3.0.17",
"lockfileVersion": 2,
"requires": true,
"packages": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "tmdb-addon",
"version": "3.0.16",
"version": "3.0.17",
"description": "Metadata provided by TMDB",
"main": "server.js",
"dependencies": {
+96 -73
View File
@@ -1,75 +1,98 @@
{
"en-US": {
"popular": "Popular",
"year": "Year",
"language": "Language",
"trending": "Trending"
},
"pt-BR": {
"popular": "Popular",
"year": "Ano",
"language": "Idioma",
"trending": "Tendências"
},
"es-ES": {
"popular": "Popular",
"year": "Año",
"language": "Idioma",
"trending": "Tendencias"
},
"fr-FR": {
"popular": "Populaire",
"year": "Année",
"language": "Langue",
"trending": "Tendances"
},
"de-DE": {
"popular": "Beliebt",
"year": "Jahr",
"language": "Sprache",
"trending": "Im Trend"
},
"it-IT": {
"popular": "Popolare",
"year": "Anno",
"language": "Lingua",
"trending": "Di tendenza"
},
"ru-RU": {
"popular": "Популярное",
"year": "Год",
"language": "Язык",
"trending": "Тренды"
},
"ja-JP": {
"popular": "人気",
"year": "年",
"language": "言語",
"trending": "トレンド"
},
"zh-CN": {
"popular": "热门",
"year": "年份",
"language": "语言",
"trending": "趋势"
},
"ko-KR": {
"popular": "인기",
"year": "년도",
"language": "언어",
"trending": "트렌드"
},
"hi-IN": {
"popular": "लोकप्रिय",
"year": "साल",
"language": "भाषा",
"trending": "प्रवृत्ति"
},
"ar-SA": {
"popular": "شائع",
"year": "السنة",
"language": "اللغة",
"trending": "الشائع"
}
"en-US": {
"popular": "Popular",
"year": "Year",
"language": "Language",
"trending": "Trending",
"favorites": "Favorites",
"watchlist": "Watchlist"
},
"pt-BR": {
"popular": "Popular",
"year": "Ano",
"language": "Idioma",
"trending": "Tendências",
"favorites": "Favoritos",
"watchlist": "Interesses"
},
"es-ES": {
"popular": "Popular",
"year": "Año",
"language": "Idioma",
"trending": "Tendencias",
"favorites": "Favoritos",
"watchlist": "Intereses"
},
"fr-FR": {
"popular": "Populaire",
"year": "Année",
"language": "Langue",
"trending": "Tendances",
"favorites": "Favoris",
"watchlist": "Intérêts"
},
"de-DE": {
"popular": "Beliebt",
"year": "Jahr",
"language": "Sprache",
"trending": "Im Trend",
"favorites": "Favoriten",
"watchlist": "Interessen"
},
"it-IT": {
"popular": "Popolare",
"year": "Anno",
"language": "Lingua",
"trending": "Di tendenza",
"favorites": "Preferiti",
"watchlist": "Interessi"
},
"ru-RU": {
"popular": "Популярное",
"year": "Год",
"language": "Язык",
"trending": "Тренды",
"favorites": "Избранное",
"watchlist": "Интересы"
},
"ja-JP": {
"popular": "人気",
"year": "年",
"language": "言語",
"trending": "トレンド",
"favorites": "お気に入り",
"watchlist": "興味"
},
"zh-CN": {
"popular": "热门",
"year": "年份",
"language": "语言",
"trending": "趋势",
"favorites": "收藏",
"watchlist": "兴趣"
},
"ko-KR": {
"popular": "인기",
"year": "년도",
"language": "언어",
"trending": "트렌드",
"favorites": "즐겨찾기",
"watchlist": "관심사"
},
"hi-IN": {
"popular": "लोकप्रिय",
"year": "साल",
"language": "भाषा",
"trending": "प्रवृत्ति",
"favorites": "पसंदीदा",
"watchlist": "रुचियाँ"
},
"ar-SA": {
"popular": "شائع",
"year": "السنة",
"language": "اللغة",
"trending": "الشائع",
"favorites": "المفضلة",
"watchlist": "الاهتمامات"
}
}
+3 -3
View File
@@ -172,9 +172,9 @@ async function parsePoster(type, id, poster, language, rpdbkey) {
return tmdbImage;
}
function parseMedia(el, type, genre_id = []) { // Definindo um valor padrão para genre_id
function parseMedia(el, type, genreList = []) {
const genres = Array.isArray(el.genre_ids)
? el.genre_ids.map(genre => genre_id.find((x) => x.id === genre)?.name || 'Unknown') // Usando optional chaining e valor padrão
? el.genre_ids.map(genre => genreList.find((x) => x.id === genre)?.name || 'Unknown')
: [];
return {
@@ -184,7 +184,7 @@ function parseMedia(el, type, genre_id = []) { // Definindo um valor padrão par
poster: `https://image.tmdb.org/t/p/w500${el.poster_path}`,
background: `https://image.tmdb.org/t/p/original${el.backdrop_path}`,
posterShape: "regular",
imdbRating: el.vote_average ? el.vote_average.toFixed(1) : 'N/A', // Verifica se existe vote_average
imdbRating: el.vote_average ? el.vote_average.toFixed(1) : 'N/A',
year: type === 'movie' ? (el.release_date ? el.release_date.substr(0, 4) : "") : (el.first_air_date ? el.first_air_date.substr(0, 4) : ""),
type: type === 'movie' ? type : 'series',
description: el.overview,