Pasthis

Raw | New paste
Never expires.
import { Radarr } from 'Shared/Radarr';

/**
 * @description This script looks up a Movie from Radarr and retrieves its metadata
 * @help Performs a search on Radarr for a movie.
Stores the Metadata inside the variable 'MovieInfo'.
 * @author iBuSH
 * @revision 9
 * @param {string} URL Radarr root URL and port (e.g., http://radarr:1234)
 * @param {string} ApiKey API Key for Radarr
 * @param {bool} UseFolderName Whether to use the folder name instead of the file name for search<br>- Best option if your downlad library is the same as your media library.
 * @output Movie found
 * @output Movie not found
 */
function Script(URL, ApiKey, UseFolderName) {
    URL = (URL || Variables['Radarr.Url'] || Variables['Radarr.URI']).replace(/\/+$/g, '');
    ApiKey = ApiKey || Variables['Radarr.ApiKey'];
    const radarr = new Radarr(URL, ApiKey);
    const folderPath = Variables.folder.Orig.FullName;
    const fileNameNoExt = Variables.file.Orig.FileNameNoExtension;
    const searchPattern = UseFolderName ? getMovieFolderName(folderPath) : fileNameNoExt;

    Logger.ILog(`Radarr URL: ${URL}`);
    Logger.ILog(`Lookup Movie name: ${searchPattern}`);

    // Search for the movie in Radarr by path, queue, or download history
    let movie = (UseFolderName && searchMovieByPath(searchPattern, radarr)) ||
                searchInQueue(searchPattern, radarr) ||
                searchInGrabHistory(searchPattern, radarr) ||
                searchInDownloadHistory(searchPattern, radarr) ||
                parseMovie(searchPattern, radarr);

    if (!movie) {
        Logger.ILog(`No result found for: ${searchPattern}`);
        return 2; // Movie not found
    }

    updateMovieMetadata(movie);
    return 1; // Movie found
}

/**
 * @description Updates the movie metadata in the global variables based on the Radarr movie data
 * @param {Object} movie - Movie object returned from Radarr API
 */
function updateMovieMetadata(movie) {
    const isoLang = LanguageHelper.GetIso2Code(movie.originalLanguage.name);

    Object.assign(Variables, {
        'movie.Title': movie.title,
        'movie.Year': movie.year,
        'Radarr.movieId': movie.id,
        MovieInfo: movie,
        OriginalLanguage: isoLang,
        VideoMetadata: {
            Title: movie.title,
            Description: movie.overview,
            Year: movie.year,
            ReleaseDate: movie.firstAired,
            OriginalLanguage: isoLang,
            Genres: movie.genres
        }
    })

    Logger.ILog(`Detected Movie Title: ${movie.title}`);
    Logger.ILog(`Detected Movie Year: ${movie.year}`);
    Logger.ILog(`Detected Original Language: ${isoLang}`);
    Logger.ILog(`Detected Radarr movieId: ${movie.id}`);

    // Extract the url of the poster image
    const poster = movie.images?.find(image => image.coverType === 'poster');
    if (poster && poster.remoteUrl) {
        Variables["movie.PosterUrl"] = poster.remoteUrl;
        Flow.SetThumbnail(poster.remoteUrl); // Set the FileFlows Thumbnail
    } else {
        Logger.WLog("No poster image found.");
    }
}

/**
 * @description Extracts the folder name from the provided folder path
 * @param {string} folderPath - The full path of the folder
 * @returns {string} The folder name
 */
function getMovieFolderName(folderPath) {
    return System.IO.Path.GetFileName(folderPath);
}

/**
 * @description Searches for a movie by file or folder path in Radarr
 * @param {string} searchPattern - The search string to use (from the folder or file name)
 * @param {Object} radarr - Radarr API instance
 * @returns {Object|null} Movie object if found, or null if not found
 */
function searchMovieByPath(searchPattern, radarr) {
    Logger.ILog(`Searching by Movie path`);

    try {
        const movie = radarr.getMovieByPath(searchPattern);
        return movie || null;
    } catch (e) {
        Logger.ELog(`Error searching movie by path: ${e.message}`);
        return null;
    }
}

/**
 * @description Parse the movie name using Radarr parsing based on the search pattern.
 * @param {string} searchPattern - The search string (file or folder name)
 * @param {Object} radarr - Radarr API instance
 * @param {bool} fullOutput - Get full output or only the movie data
 * @returns {Object|null} Parsed movie object, or null if none.
 */
function parseMovie(searchPattern, radarr, fullOutput=false) {
    let endpoint = 'parse'
    let sp = null;

    Logger.ILog(`Trying to Parse Movie name using Radarr Parsing`);

    if (!searchPattern) {
        Logger.WLog('No pattern passed in to find movie');
        return null;
    } else {
        sp = searchPattern.toLowerCase();
    }

    try {
        const queryParams = buildQueryParams({ title: sp });
        const item = radarr.fetchJson(endpoint, queryParams);

        if (item?.movie?.title) {
            Logger.ILog(`Found Movie: ${item.movie.title}`);
            
            return fullOutput ? item : item.movie;
        }
        Logger.WLog(`The ${endpoint} endpoint did not recognise this title.`);
        return null;
    } catch (e) {
        Logger.ELog(`Error fetching Radarr ${endpoint} endpoint: ${e.message}`);
        return null;
    }
}

/**
 * @description Searches the Radarr queue for a movie based on the search pattern
 * @param {string} searchPattern - The search string (file or folder name)
 * @param {Object} radarr - Radarr API instance
 * @returns {Object|null} Movie object if found, or null if not found
 */
function searchInQueue(searchPattern, radarr) {
    Logger.ILog(`Searching in Queue`);

    return searchRadarrAPI('queue', searchPattern, radarr, (item, sp) => {
        return item.outputPath?.toLowerCase().includes(sp);
    });
}

/**
 * @description Searches the Radarr download history for a movie based on the search pattern
 * @param {string} searchPattern - The search string (file or folder name)
 * @param {Object} radarr - Radarr API instance
 * @returns {Object|null} Movie object if found, or null if not found
 */
function searchInDownloadHistory(searchPattern, radarr) {
    Logger.ILog(`Searching in Download History`);

    return searchRadarrAPI('history', searchPattern, radarr, (item, sp) => {
        return item.data?.droppedPath?.toLowerCase().includes(sp);
    }, { eventType: 3 });   // 3 == downloaded
}

/**
 * @description Searches the Radarr grabbed history for a movie based on the search pattern
 * @param {string} searchPattern - The search string (file or folder name)
 * @param {Object} radarr - Radarr API instance
 * @returns {Object|null} Movie object if found, or null if not found
 */
function searchInGrabHistory(searchPattern, radarr) {
    Logger.ILog(`Searching in Grab History`);

    return searchRadarrAPI('history', searchPattern, radarr, (item, sp) => {
        return item.sourceTitle?.toLowerCase().includes(sp);
    }, { eventType: 1 });   // 1 == grabbed
}

/**
 * @description Generic function to search Radarr API (queue or history) based on a search pattern
 * @param {string} endpoint - The Radarr API endpoint to search (queue or history)
 * @param {string} searchPattern - The search string (file or folder name)
 * @param {Object} radarr - Radarr API instance
 * @param {Function} matchFunction - A function that determines if an item matches the search pattern
 * @param {Object} [extraParams={}] - Additional query parameters for the API request
 * @returns {Object|null} Movie object if found, or null if not found
 */
function searchRadarrAPI(endpoint, searchPattern, radarr, matchFunction, extraParams = {}) {
    let page = 1;
    const pageSize = 1000;
    const includeMovie = 'true'
    let sp = null;

    if (!searchPattern) {
        Logger.WLog('No pattern passed in to find movie');
        return null;
    } else {
        sp = searchPattern.toLowerCase();
    }

    try {
        while (true) {
            const queryParams = buildQueryParams({ page, pageSize, includeMovie, ...extraParams });
            const json = radarr.fetchJson(endpoint, queryParams);
            const items = json.records;

            if (items.length === 0) {
                Logger.WLog(`Reached the end of ${endpoint} endpoint with no match.`);
                break;
            }

            const matchingItem = items.find(item => matchFunction(item, sp));
            if (matchingItem) {
                Logger.ILog(`Found Movie: ${matchingItem.movie.title}`);
                
                return matchingItem.movie;
            }

            if (endpoint === 'queue' || page === 10) {
                Logger.WLog(`Reached the end of ${endpoint} endpoint with no match.`);
                break;
            }

            page++;
        }
    } catch (e) {
        Logger.ELog(`Error fetching Radarr ${endpoint} endpoint: ${e.message}`);
        return null;
    }
}

/**
 * @description Constructs a query string from the given parameters
 * @param {Object} params - Key-value pairs to be converted into a query string
 * @returns {string} The constructed query string
 */
function buildQueryParams(params) {
    return Object.keys(params)
        .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
        .join('&');
}