/**@module utils */
const open = require('open');
const httpUtils = require('./http_utils');
const httpMethod = httpUtils.httpMethod;
const baseUrlValue = "https://api.themoviedb.org/3/";
/**
* The TMDb API base URL.
*/
exports.baseUrl = baseUrlValue;
/**
* Gets data as a JSON object.
* @function
* @param {string} urlPath The URL path from where data will be retrieved (excluding the TMDb API base URL.).
* @param {Object} urlParameters The parameters of the URL.
* @returns {Promise<*>} A Promise of JSON data.
*/
exports.getDataAsync = async function (urlPath, urlParameters = {}) {
// Create the url, based on this function's parameters
let url = exports.buildUrl(urlPath, urlParameters);
return await httpUtils.parseHttpRequest(url, httpMethod.GET, JSON.parse, httpUtils.jsonContentType);
};
/**
* Builds the URL with the passed path and parameters.
* @param {string} urlPath The URL path from where data will be retrieved (excluding the TMDb API base URL.).
* @param {Object} parameters The parameters of the URL.
*/
exports.buildUrl = function (urlPath, parameters = {}) {
let url = baseUrlValue + urlPath;
// Apply URL parameters
if (Object.keys(parameters).length > 0) {
url += "?";
for (const key in parameters) {
if (Object.hasOwnProperty.call(parameters, key)
&& parameters[key] !== undefined
&& parameters[key] != null) {
let uriParameter = encodeURI(parameters[key]);
url += `${key}=${uriParameter}&`;
}
}
// Remove last parameter separator
url = url.substr(0, url.length - 1);
}
return url;
};
/**
* Gets a request token from TMDb.
* @param {string} apiKey The API key to TMDb.
* @returns {Promise<string>} A Promise of a request token string.
*/
exports.getRequestTokenAsync = async function (apiKey) {
// GET a request token
let requestTokenUrl = baseUrlValue + "authentication/token/new?api_key=" + apiKey;
let tokenRequestResult =
await httpUtils.parseHttpRequest(requestTokenUrl, httpMethod.GET, JSON.parse);
return tokenRequestResult["request_token"];
}
/**
* Creates a session with login at TMDb.
* @param {string} apiKey The API key to TMDb.
* @param {string} username The username to use to create a session.
* @param {string} password The password to use to create a session.
* @returns {Promise<string>} A Promise of a session ID string (undefined if the operation is not successful).
*/
exports.createLoginSessionAsync = async function (apiKey, username, password) {
let requestToken = await this.getRequestTokenAsync(apiKey);
// Approve request token
let authUrl = baseUrlValue + "authentication/token/validate_with_login?api_key=" + apiKey;
let authResponse = await httpUtils.parseHttpRequest(
authUrl,
httpMethod.POST,
JSON.parse,
httpUtils.jsonContentType,
JSON.stringify({
"username": username,
"password": password,
"request_token": requestToken
}));
if (!authResponse || !authResponse["success"]) {
// Log in and approval of request token was unsuccessful
return undefined;
}
return await getSessionIdAsync(apiKey, requestToken);
}
/**
* Creates a session at TMDb.
* @param {string} apiKey The API key to TMDb.
* @param {string} permissionApp
* The name of the web browser app to use when the
* end-user has to approve the request token.
* @returns {Promise<string>} A Promise of a session ID string (undefined if the operation is not successful).
*/
exports.createSessionAsync = async function (apiKey, permissionApp = undefined) {
let connectionOptions = permissionApp ? {wait: true, app: permissionApp} : {wait: true};
// Get request token and let the user approve it
let requestToken = await this.getRequestTokenAsync(apiKey);
await open('https://www.themoviedb.org/authenticate/' + requestToken, connectionOptions);
return await getSessionIdAsync(apiKey, requestToken);
}
/**
* Gets a session ID based on the approved request token and API key.
* @param apiKey The TMDb API key.
* @param requestToken The approved request token.
* @returns {Promise<string>} A Promise of a session ID string (undefined if the operation is not successful).
*/
getSessionIdAsync = async function(apiKey, requestToken) {
// Create a session
let sessionUrl = baseUrlValue + "authentication/session/new?api_key=" + apiKey + "&request_token=" + requestToken;
let sessionResponse = await httpUtils.parseHttpRequest(
sessionUrl,
httpMethod.GET,
JSON.parse,
httpUtils.jsonContentType);
if (!sessionResponse || !sessionResponse["success"]) {
return undefined;
}
// Return true if the session creation was successful
return sessionResponse["session_id"];
}
/**
* Creates a guest session at TMDb and returns the session ID.
* @param {string} apiKey The TMDb API key.
* @returns {Promise<string>} A Promise of a guest session ID.
*/
exports.createGuestSessionAsync = async (apiKey) => {
let sessionUrl = baseUrlValue + "authentication/guest_session/new?api_key=" + apiKey;
let sessionResponse = await httpUtils.parseHttpRequest(sessionUrl, httpMethod.GET, JSON.parse);
if (!sessionResponse || !sessionResponse["success"]) {
return undefined;
}
return sessionResponse["guest_session_id"];
}
/**
* Deletes (log outs of) a session.
* @param {string} apiKey The TMDb API key.
* @param {string} sessionId The ID of the session to delete.
* @returns {Promise<boolean>} A Promise of a boolean value,
* which will be true if the deletion is successful.
*/
exports.deleteSessionAsync = async (apiKey, sessionId) => {
let sessionUrl = baseUrlValue + "authentication/session?api_key=" + apiKey;
let sessionResponse = await httpUtils.parseHttpRequest(
sessionUrl,
httpMethod.DELETE,
JSON.parse,
httpUtils.jsonContentType,
JSON.stringify({"session_id": sessionId}));
return sessionResponse["success"];
}
/**
* Posts to TMDb.
* @param {string} urlPath The URL path from where data will be posted (excluding the TMDb API base URL.).
* @param {Object} urlParameters The parameters of the URL.
* @param {Object} requestBody The request body object.
* @returns {Promise<boolean>} A Promise of a boolean value, which will be true if the rating is successful.
*/
exports.postAsync = async function (urlPath, urlParameters, requestBody = null) {
let url = exports.buildUrl(urlPath, urlParameters);
// Wait for a response
return await httpUtils.parseHttpRequest(
url,
httpMethod.POST,
JSON.parse,
httpUtils.jsonContentType,
requestBody ? JSON.stringify(requestBody) : null);
};
/**
* Deletes at the passed url.
* @param {string} urlPath The URL path from where data will deleted (excluding the TMDb API base URL.).
* @param {Object} urlParameters The parameters of the URL.
* @returns {Promise<boolean>} A Promise of a boolean value, which will be true if the deletion is successful.
*/
exports.deleteAsync = async function (urlPath, urlParameters) {
let url = exports.buildUrl(urlPath, urlParameters);
// Wait for a response
let response = await httpUtils.parseHttpRequest(
url,
httpMethod.DELETE,
JSON.parse,
httpUtils.jsonContentType);
if (response && response["status_code"] === 11) {
// TODO [david98hall, 2021-08-30]: Remove this if-statement when this API ticket is fixed: https://trello.com/c/slruAstb
// List is deleted but the response is that there is an internal error in TMDb
return true;
}
return response && response["status_code"] === 13;
};
/**
* The different external sources supported in TMDb.
*/
exports.externalSources = Object.freeze({
IMDB_ID: 'imdb_id',
FREEBASE_MID: 'freebase_mid',
FREEBASE_ID: 'freebase_id',
TVDB_ID: 'tvdb_id',
TVRAGE_ID: 'tvrage_id',
FACEBOOK_ID: 'facebook_id',
TWITTER_ID: 'twitter_id',
INSTAGRAM_ID: 'instagram_id'
});
/**
* The different time window types available at TMDb.
*/
exports.timeWindows = Object.freeze({
DAY: 'day',
WEEK: 'week'
});
/**
* The different media types available at TMDb.
*/
exports.mediaTypes = Object.freeze({
ALL: 'all',
MOVIE: 'movie',
TV: 'tv',
PERSON: 'person',
});
/**
* The different types of sections available at TMDb.
*/
exports.sections = Object.freeze({
ACCOUNT: 'account',
CERTIFICATION: 'certification',
COLLECTION: 'collection',
COMPANY: 'company',
CONFIGURATION: 'configuration',
CREDIT: 'credit',
DISCOVER: 'discover',
EPISODES: 'episodes',
FIND: 'find',
GENRE: 'genre',
GUEST_SESSION: 'guest_session',
KEYWORD: 'keyword',
LIST: 'list',
MOVIE: 'movie',
NETWORK: 'network',
PERSON: 'person',
PROVIDERS: 'providers',
REVIEW: 'review',
SEARCH: 'search',
TRENDING: 'trending',
TV_SHOW: 'tv',
TV_SHOW_EPISODE: 'episode',
TV_SHOW_EPISODE_GROUP: 'episode_group',
TV_SHOW_SEASON: 'season',
WATCH: 'watch',
});
/**
* The different types of data available at TMDb.
*/
exports.dataTypes = Object.freeze({
ACCOUNT_STATES: 'account_states',
AGGREGATE_CREDITS: 'aggregate_credits',
AIRING_TODAY: 'airing_today',
ALTERNATIVE_NAMES: 'alternative_names',
ALTERNATIVE_TITLES: 'alternative_titles',
CHANGES: 'changes',
COMBINED_CREDITS: 'combined_credits',
CONTENT_RATINGS: 'content_ratings',
COUNTRIES: 'countries',
CREDITS: 'credits',
EPISODE: "episode",
EPISODE_GROUPS: 'episode_groups',
EXTERNAL_IDS: 'external_ids',
FAVORITE: 'favorite',
IMAGES: 'images',
ITEM_STATUS: 'item_status',
JOBS: 'jobs',
KEYWORDS: 'keywords',
LANGUAGES: 'languages',
LATEST: 'latest',
LISTS: 'lists',
MOVIES: 'movies',
MOVIE_CREDITS: 'movie_credits',
NOW_PLAYING: 'now_playing',
ON_THE_AIR: 'on_the_air',
POPULAR: 'popular',
PRIMARY_TRANSLATIONS: 'primary_translations',
RATED: 'rated',
RECOMMENDATIONS: 'recommendations',
REGIONS: 'regions',
RELEASE_DATES: 'release_dates',
REVIEWS: 'reviews',
SCREENED_THEATRICALLY: "screened_theatrically",
SEASON: 'season',
SIMILAR: 'similar',
SIMILAR_MOVIES: 'similar_movies',
SIMILAR_TV_SHOWS: "similar_tv_shows",
TAGGED_IMAGES: 'tagged_images',
TIMEZONES: 'timezones',
TOP_RATED: 'top_rated',
TRANSLATIONS: 'translations',
TV_AIRING_TODAY: 'tv_airing_today',
TV_CREDITS: 'tv_credits',
TV_ON_THE_AIR: 'tv_on_the_air',
UPCOMING: 'upcoming',
VIDEOS: 'videos',
WATCHLIST: 'watchlist'
});
/**
* The different types of actions available at TMDb.
*/
exports.actionTypes = Object.freeze({
RATING: "rating",
ADD_ITEM: "add_item",
REMOVE_ITEM: "remove_item",
CLEAR: "clear"
});
/**
* The different types of sorting available at TMDb.
*/
exports.sortingTypes = Object.freeze({
CREATED_AT_ASC: 'created_at.asc',
CREATED_AT_DESC: 'created_at.desc',
VOTE_AVERAGE_ASC: 'vote_average.asc',
VOTE_AVERAGE_DESC: 'vote_average.desc',
FIRST_AIR_DATE_ASC: 'first_air_date.asc',
FIRST_AIR_DATE_DESC: 'first_air_date.desc',
POPULARITY_ASC: 'popularity.asc',
POPULARITY_DESC: 'popularity.desc',
VOTE_COUNT_ASC: 'vote_count.asc',
VOTE_COUNT_DESC: 'vote_count.desc',
ORIGINAL_TITLE_ASC: 'original_title.asc',
ORIGINAL_TITLE_DESC: 'original_title.desc',
RELEASE_DATE_ASC: 'release_date.asc',
RELEASE_DATE_DESC: 'release_date.desc',
REVENUE_ASC: 'revenue.asc',
REVENUE_DESC: 'revenue.desc',
PRIMARY_RELEASE_DATE_ASC: 'primary_release_date.asc',
PRIMARY_RELEASE_DATE_DESC: 'primary_release_date.desc',
});