import config from "./config"; import { IList, IMediaCredits, IPersonCredits } from "./interfaces/IList"; const { ELASTIC_URL, ELASTIC_INDEX } = config; let { SEASONED_URL } = config; if (!SEASONED_URL) SEASONED_URL = window.location.origin; // - - - TMDB - - - /** * Fetches tmdb movie by id. Can optionally include cast credits in result object. * @param {number} id * @returns {object} Tmdb response */ const getMovie = ( id, { checkExistance, credits, releaseDates }: { checkExistance: boolean; credits: boolean; releaseDates?: boolean } ) => { const url = new URL("/api/v2/movie", SEASONED_URL); url.pathname = `${url.pathname}/${id.toString()}`; if (checkExistance) { url.searchParams.append("check_existance", "true"); } if (credits) { url.searchParams.append("credits", "true"); } if (releaseDates) { url.searchParams.append("release_dates", "true"); } return fetch(url.href) .then(resp => resp.json()) .catch(error => { console.error(`api error getting movie: ${id}`); // eslint-disable-line no-console throw error; }); }; /** * Fetches tmdb show by id. Can optionally include cast credits in result object. * @param {number} id * @param {boolean} [credits=false] Include credits * @returns {object} Tmdb response */ const getShow = ( id, { checkExistance, credits, releaseDates }: { checkExistance: boolean; credits: boolean; releaseDates?: boolean } ) => { const url = new URL("/api/v2/show", SEASONED_URL); url.pathname = `${url.pathname}/${id.toString()}`; if (checkExistance) { url.searchParams.append("check_existance", "true"); } if (credits) { url.searchParams.append("credits", "true"); } if (releaseDates) { url.searchParams.append("release_dates", "true"); } return fetch(url.href) .then(resp => resp.json()) .catch(error => { console.error(`api error getting show: ${id}`); // eslint-disable-line no-console throw error; }); }; /** * Fetches tmdb person by id. Can optionally include cast credits in result object. * @param {number} id * @param {boolean} [credits=false] Include credits * @returns {object} Tmdb response */ const getPerson = (id, credits = false) => { const url = new URL("/api/v2/person", SEASONED_URL); url.pathname = `${url.pathname}/${id.toString()}`; if (credits) { url.searchParams.append("credits", "true"); } return fetch(url.href) .then(resp => resp.json()) .catch(error => { console.error(`api error getting person: ${id}`); // eslint-disable-line no-console throw error; }); }; /** * Fetches tmdb movie credits by id. * @param {number} id * @returns {object} Tmdb response */ const getMovieCredits = (id: number): Promise => { const url = new URL("/api/v2/movie", SEASONED_URL); url.pathname = `${url.pathname}/${id.toString()}/credits`; return fetch(url.href) .then(resp => resp.json()) .catch(error => { console.error(`api error getting movie: ${id}`); // eslint-disable-line no-console throw error; }); }; /** * Fetches tmdb show credits by id. * @param {number} id * @returns {object} Tmdb response */ const getShowCredits = (id: number): Promise => { const url = new URL("/api/v2/show", SEASONED_URL); url.pathname = `${url.pathname}/${id.toString()}/credits`; return fetch(url.href) .then(resp => resp.json()) .catch(error => { console.error(`api error getting show: ${id}`); // eslint-disable-line no-console throw error; }); }; /** * Fetches tmdb person credits by id. * @param {number} id * @returns {object} Tmdb response */ const getPersonCredits = (id: number): Promise => { const url = new URL("/api/v2/person", SEASONED_URL); url.pathname = `${url.pathname}/${id.toString()}/credits`; return fetch(url.href) .then(resp => resp.json()) .catch(error => { console.error(`api error getting person: ${id}`); // eslint-disable-line no-console throw error; }); }; /** * Fetches tmdb list by name. * @param {string} name List the fetch * @param {number} [page=1] * @returns {object} Tmdb list response */ const getTmdbMovieListByName = (name: string, page = 1): Promise => { const url = new URL(`/api/v2/movie/${name}`, SEASONED_URL); url.searchParams.append("page", page.toString()); return fetch(url.href).then(resp => resp.json()); // .catch(error => { console.error(`api error getting list: ${name}, page: ${page}`); throw error }) // eslint-disable-line no-console }; /** * Fetches requested items. * @param {number} [page=1] * @returns {object} Request response */ const getRequests = (page = 1) => { const url = new URL("/api/v2/request", SEASONED_URL); url.searchParams.append("page", page.toString()); return fetch(url.href).then(resp => resp.json()); // .catch(error => { console.error(`api error getting list: ${name}, page: ${page}`); throw error }) // eslint-disable-line no-console }; const getUserRequests = (page = 1) => { const url = new URL("/api/v1/user/requests", SEASONED_URL); url.searchParams.append("page", page.toString()); return fetch(url.href).then(resp => resp.json()); }; /** * Fetches tmdb movies and shows by query. * @param {string} query * @param {number} [page=1] * @returns {object} Tmdb response */ const searchTmdb = (query, page = 1, adult = false, mediaType = null) => { const url = new URL("/api/v2/search", SEASONED_URL); if (mediaType != null && ["movie", "show", "person"].includes(mediaType)) { url.pathname += `/${mediaType}`; } url.searchParams.append("query", query); url.searchParams.append("page", page.toString()); url.searchParams.append("adult", adult.toString()); return fetch(url.href) .then(resp => resp.json()) .catch(error => { console.error(`api error searching: ${query}, page: ${page}`); // eslint-disable-line no-console throw error; }); }; // - - - Torrents - - - /** * Search for torrents by query * @param {string} query * @param {boolean} credits Include credits * @returns {object} Torrent response */ const searchTorrents = query => { const url = new URL("/api/v1/pirate/search", SEASONED_URL); url.searchParams.append("query", query); return fetch(url.href) .then(resp => resp.json()) .catch(error => { console.error(`api error searching torrents: ${query}`); // eslint-disable-line no-console throw error; }); }; /** * Add magnet to download queue. * @param {string} magnet Magnet link * @param {boolean} name Name of torrent * @param {boolean} tmdbId * @returns {object} Success/Failure response */ const addMagnet = (magnet: string, name: string, tmdbId: number | null) => { const url = new URL("/api/v1/pirate/add", SEASONED_URL); const options = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ magnet, name, tmdb_id: tmdbId }) }; return fetch(url.href, options) .then(resp => resp.json()) .catch(error => { console.error(`api error adding magnet: ${name} ${error}`); // eslint-disable-line no-console throw error; }); }; // - - - Plex/Request - - - /** * Request a movie or show from id. If authorization token is included the user will be linked * to the requested item. * @param {number} id Movie or show id * @param {string} type Movie or show type * @returns {object} Success/Failure response */ const request = (id, type) => { const url = new URL("/api/v2/request", SEASONED_URL); const options = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id, type }) }; return fetch(url.href, options) .then(resp => resp.json()) .catch(error => { console.error(`api error requesting: ${id}, type: ${type}`); // eslint-disable-line no-console throw error; }); }; /** * Check request status by tmdb id and type * @param {number} tmdb id * @param {string} type * @returns {object} Success/Failure response */ const getRequestStatus = (id, type = undefined) => { const url = new URL("/api/v2/request", SEASONED_URL); url.pathname = `${url.pathname}/${id.toString()}`; url.searchParams.append("type", type); return fetch(url.href) .then(resp => { const { status } = resp; if (status === 200) return true; const errorMessage = `api error getting request status for id ${id} and type ${type}`; // eslint-disable-next-line no-console console.error(errorMessage); return false; }) .catch(err => Promise.reject(err)); }; const watchLink = (title, year) => { const url = new URL("/api/v1/plex/watch-link", SEASONED_URL); url.searchParams.append("title", title); url.searchParams.append("year", year); return fetch(url.href) .then(resp => resp.json()) .then(response => response.link); }; const movieImages = id => { const url = new URL(`v2/movie/${id}/images`, SEASONED_URL); return fetch(url.href).then(resp => resp.json()); }; // - - - Seasoned user endpoints - - - const register = (username, password) => { const url = new URL("/api/v1/user", SEASONED_URL); const options = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username, password }) }; return fetch(url.href, options) .then(resp => resp.json()) .catch(error => { const errorMessage = "Unexpected error occured before receiving response. Error:"; // eslint-disable-next-line no-console console.error(errorMessage, error); // TODO log to sentry the issue here throw error; }); }; const login = (username, password, throwError = false) => { const url = new URL("/api/v1/user/login", SEASONED_URL); const options = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username, password }) }; return fetch(url.href, options).then(resp => { if (resp.status === 200) return resp.json(); if (throwError) throw resp; console.error("Error occured when trying to sign in.\nError:", resp); // eslint-disable-line no-console return Promise.reject(resp); }); }; const logout = (throwError = false) => { const url = new URL("/api/v1/user/logout", SEASONED_URL); const options = { method: "POST" }; return fetch(url.href, options).then(resp => { if (resp.status === 200) return resp.json(); if (throwError) throw resp; console.error("Error occured when trying to log out.\nError:", resp); // eslint-disable-line no-console return Promise.reject(resp); }); }; const getSettings = () => { const url = new URL("/api/v1/user/settings", SEASONED_URL); return fetch(url.href) .then(resp => resp.json()) .catch(error => { console.log("api error getting user settings"); // eslint-disable-line no-console throw error; }); }; const updateSettings = settings => { const url = new URL("/api/v1/user/settings", SEASONED_URL); const options = { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(settings) }; return fetch(url.href, options) .then(resp => resp.json()) .catch(error => { console.log("api error updating user settings"); // eslint-disable-line no-console throw error; }); }; // - - - Authenticate with plex - - - const linkPlexAccount = (username, password) => { const url = new URL("/api/v1/user/link_plex", SEASONED_URL); const body = { username, password }; const options = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }; return fetch(url.href, options) .then(resp => resp.json()) .catch(error => { console.error(`api error linking plex account: ${username}`); // eslint-disable-line no-console throw error; }); }; const unlinkPlexAccount = () => { const url = new URL("/api/v1/user/unlink_plex", SEASONED_URL); const options = { method: "POST", headers: { "Content-Type": "application/json" } }; return fetch(url.href, options) .then(resp => resp.json()) .catch(error => { console.error(`api error unlinking your plex account`); // eslint-disable-line no-console throw error; }); }; // - - - User graphs - - - const fetchGraphData = (urlPath, days, chartType) => { const url = new URL(`/api/v1/user/${urlPath}`, SEASONED_URL); url.searchParams.append("days", days); url.searchParams.append("y_axis", chartType); return fetch(url.href).then(resp => { if (!resp.ok) { console.log("DAMN WE FAILED!", resp); // eslint-disable-line no-console throw Error(resp.statusText); } return resp.json(); }); }; // - - - Random emoji - - - const getEmoji = () => { const url = new URL("/api/v1/emoji", SEASONED_URL); return fetch(url.href) .then(resp => resp.json()) .catch(error => { console.log("api error getting emoji"); // eslint-disable-line no-console throw error; }); }; // - - - ELASTIC SEARCH - - - // This elastic index contains titles mapped to ids. Lightning search // used for autocomplete /** * Search elastic indexes movies and shows by query. Doc includes Tmdb daily export of Movies and * Tv Shows. See tmdb docs for more info: https://developers.themoviedb.org/3/getting-started/daily-file-exports * @param {string} query * @returns {object} List of movies and shows matching query */ const elasticSearchMoviesAndShows = (query, count = 22) => { const url = new URL(`${ELASTIC_INDEX}/_search`, ELASTIC_URL); const body = { sort: [{ popularity: { order: "desc" } }, "_score"], query: { bool: { should: [ { match_phrase_prefix: { original_name: query } }, { match_phrase_prefix: { original_title: query } } ] } }, size: count }; const options = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }; return fetch(url.href, options) .then(resp => resp.json()) .catch(error => { console.log(`api error searching elasticsearch: ${query}`); // eslint-disable-line no-console throw error; }); }; export { getMovie, getShow, getPerson, getMovieCredits, getShowCredits, getPersonCredits, getTmdbMovieListByName, searchTmdb, getUserRequests, getRequests, searchTorrents, addMagnet, request, watchLink, movieImages, getRequestStatus, linkPlexAccount, unlinkPlexAccount, register, login, logout, getSettings, updateSettings, fetchGraphData, getEmoji, elasticSearchMoviesAndShows };