tmdb-js/sections/types/search.js

/**@module tmdb-js/sections/types */

// TMDb utilities
const tmdbUtils = require('../../../utils/tmdb_utils');
const sections = tmdbUtils.sections;

const Section = require('../section').Section;

/**
 * A class that represents the search section in TMDb.
 */
exports.SearchSection = class extends Section {

    /**
     * Initializes this object.
     * @param {string} apiKey A TMDb API key.
     * @param {string} language The natural language of search queries. The default is "en-US".
     */
    constructor(apiKey, language = "en-US") {
        super(sections.SEARCH, undefined, apiKey, language);
    }

    /**
     * Gets data from a company search in TMDb.
     *
     * @param {string} searchTerm The search term (query).
     * @param {Number} startPage
     * The first search result page to return data from. The default is 1.
     * @param {Number} pageCount
     * The number of search result pages to return data from. The default is 1.
     *
     * @returns {Promise<*>} A Promise of JSON data with search results of companies.
     */
    async searchCompaniesAsync(searchTerm, startPage = 1, pageCount = 1) {
        let companiesChild = this.createChild(searchType.COMPANIES);
        return await searchPagesAsync(
            companiesChild.toString(),
            searchTerm,
            this._apiKey,
            startPage,
            pageCount,
            false,
            this._language);
    }

    /**
     * Gets data from a collection search in TMDb.
     *
     * @param {string} searchTerm The search term (query).
     * @param {Number} startPage
     * The first search result page to return data from. The default is 1.
     * @param {Number} pageCount
     * The number of search result pages to return data from. The default is 1.
     *
     * @returns {Promise<*>} A Promise of JSON data with search results of collections.
     */
    async searchCollectionsAsync(searchTerm, startPage = 1, pageCount = 1) {
        let collectionsChild = this.createChild(searchType.COLLECTIONS);
        return await searchPagesAsync(
            collectionsChild.toString(),
            searchTerm,
            this._apiKey,
            startPage,
            pageCount,
            false,
            this._language);
    }

    /**
     * Gets data from a keyword search in TMDb.
     *
     * @param {string} searchTerm The search term (query).
     * @param {Number} startPage
     * The first search result page to return data from. The default is 1.
     * @param {Number} pageCount
     * The number of search result pages to return data from. The default is 1.
     *
     * @returns {Promise<*>} A Promise of JSON data with search results of keywords.
     */
    async searchKeywordsAsync(searchTerm, startPage = 1, pageCount = 1) {
        let keywordsChild = this.createChild(searchType.KEYWORDS);
        return await searchPagesAsync(
            keywordsChild.toString(),
            searchTerm,
            this._apiKey,
            startPage,
            pageCount,
            false,
            this._language);
    }

    /**
     * Gets data from a movie search in TMDb.
     *
     * @param {string} searchTerm The search term (query).
     * @param {Number} startPage
     * The first search result page to return data from. The default is 1.
     * @param {Number} pageCount
     * The number of search result pages to return data from. The default is 1.
     * @param {Boolean} includeAdult
     * true if adult content will be included. The default is true.
     * @param {string} region The region.
     * @param {Number} year The year.
     * @param {Number} primaryReleaseYear The primary release year.
     *
     * @returns {Promise<*>} A Promise of JSON data with search results of movies.
     */
    async searchMoviesAsync(searchTerm,
                            startPage = 1,
                            pageCount = 1,
                            includeAdult = true,
                            region = undefined,
                            year = undefined,
                            primaryReleaseYear = undefined) {

        // Additional optional query info
        let additionalInfo = {
            "region": region,
            "year": year,
            "primary_release_year": primaryReleaseYear
        };

        let moviesChild = this.createChild(searchType.MOVIES);

        return await searchPagesAsync(
            moviesChild.toString(),
            searchTerm,
            this._apiKey,
            startPage,
            pageCount,
            includeAdult,
            this._language,
            additionalInfo);
    }

    /**
     * Gets data from a multi search in TMDb.
     *
     * @param {string} searchTerm The search term (query).
     * @param {Number} startPage
     * The first search result page to return data from. The default is 1.
     * @param {Number} pageCount
     * The number of search result pages to return data from. The default is 1.
     * @param {Boolean} includeAdult
     * true if adult content will be included. The default is true.
     *
     * @returns {Promise<*>} A Promise of JSON data with multi-search results.
     */
    async multiSearchAsync(searchTerm, startPage = 1, pageCount = 1, includeAdult = true) {

        let multiChild = this.createChild(searchType.MULTI);

        return await searchPagesAsync(
            multiChild.toString(),
            searchTerm,
            this._apiKey,
            startPage,
            pageCount,
            includeAdult,
            this._language);
    }

    /**
     * Gets data from a people search in TMDb.
     *
     * @param {string} searchTerm The search term (query).
     * @param {Number} startPage
     * The first search result page to return data from. The default is 1.
     * @param {Number} pageCount
     * The number of search result pages to return data from. The default is 1.
     * @param {Boolean} includeAdult
     * true if adult content will be included. The default is true.
     * @param {string} region The region.
     *
     * @returns {Promise<*>} A Promise of JSON data with search results of people.
     */
    async searchPeopleAsync(searchTerm,
                            startPage = 1,
                            pageCount = 1,
                            includeAdult = true,
                            region = undefined) {

        // Additional optional query info
        let additionalInfo = {"region": region};

        let peopleChild = this.createChild(searchType.PEOPLE);

        return await searchPagesAsync(
            peopleChild.toString(),
            searchTerm,
            this._apiKey,
            startPage,
            pageCount,
            includeAdult,
            this._language,
            additionalInfo);
    }

    /**
     * Gets data from a TV show search in TMDb.
     *
     * @param {string} searchTerm The search term (query).
     * @param {Number} startPage
     * The first search result page to return data from. The default is 1.
     * @param {Number} pageCount
     * The number of search result pages to return data from. The default is 1.
     * @param {Boolean} includeAdult
     * true if adult content will be included. The default is true.
     * @param {Number} firstAirDateYear The first air date year.
     *
     * @returns {Promise<*>} A Promise of JSON data with search results of TV shows.
     */
    async searchTvShowsAsync(searchTerm,
                             startPage = 1,
                             pageCount = 1,
                             includeAdult = true,
                             firstAirDateYear = undefined) {

        // Additional optional query info
        let additionalInfo = {"first_air_date_year": firstAirDateYear};

        let tvShowChild = this.createChild(searchType.TV_SHOWS);

        return await searchPagesAsync(
            tvShowChild.toString(),
            searchTerm,
            this._apiKey,
            startPage,
            pageCount,
            includeAdult,
            this._language,
            additionalInfo);
    }
}

/**
 * All different search types on TMDb.
 */
const searchType = {
    COMPANIES: 'company',
    COLLECTIONS: 'collection',
    KEYWORDS: 'keyword',
    MOVIES: 'movie',
    MULTI: 'multi',
    PEOPLE: 'person',
    TV_SHOWS: 'tv'
}

/**
 * Gets search data from TMDb as a JSON object.
 *
 * @param {string} url The url.
 * @param {string} searchTerm The search term (query).
 * @param {string} apiKey The API key to the TMDb API.
 * @param {Number} startPage
 * The first search result page to return data from.
 * @param {Number} pageCount
 * The number of search result pages to return data from.
 * @param {Boolean} includeAdult true if adult content will be included.
 * @param {string} language
 * The language of the search results. Default value is "en-US".
 * @param {Object} additionalInfo
 * Additional info to add to the search query.
 *
 * @returns {Promise<*>} A Promise of JSON data with search results.
 */
async function searchPagesAsync(url, searchTerm, apiKey, startPage,
                                pageCount, includeAdult = true, language = "en-US", additionalInfo = {}) {

    // Throw an error if the page related parameters are invalid
    if (startPage < 1 || pageCount < 1) {
        throw "startPage and pageCount have to be larger or equal to 1.";
    }

    // Search the first page in order to get the total number of pages.
    // Used to interrupt when there are no pages left to search.
    let firstPage = await searchPageAsync(url,
        searchTerm,
        apiKey,
        startPage,
        includeAdult,
        language,
        additionalInfo);

    // The page count is 1, no more pages should thus be searched
    if (pageCount === 1)
        return [firstPage];

    // Update the page count, in case it exceeds the total number of pages
    pageCount = Math.min(pageCount, firstPage["total_pages"] - startPage);

    // Create one search promise per page
    let promises = [];
    for (let index = 1; index <= pageCount; index++) {
        let page = startPage + index;
        let promise = searchPageAsync(url,
            searchTerm,
            apiKey,
            page,
            includeAdult,
            language,
            additionalInfo);
        promises.push(promise);
    }

    // Add the rest of the resulting pages to the first one
    return await Promise
        .all(promises)
        .then(restOfPages => [firstPage, ...restOfPages]);
}

/**
 * Gets search data from TMDb as a JSON object.
 * @param {string} url The url path.
 * @param {string} searchTerm The search term (query).
 * @param {string} apiKey The API key to the TMDb API.
 * @param {Number} page The search result page to return data from.
 * @param {Boolean} includeAdult true if adult content will be included.
 * @param {string} language
 * The language of the search results. Default value is "en-US".
 * @param {Object} additionalInfo
 * Additional info to add to the search query.
 *
 * @returns {Promise<*>} A Promise of JSON data of the specified page.
 */
async function searchPageAsync(url,
                               searchTerm,
                               apiKey,
                               page = 1,
                               includeAdult = true,
                               language = "en-US",
                               additionalInfo = {}) {

    let parameters = {
        "api_key": apiKey,
        "language": language,
        "query": searchTerm,
        "page": page,
        "include_adult": includeAdult,
        ...additionalInfo
    };

    return await tmdbUtils.getDataAsync(url, parameters);
}