UNPKG

identify-media

Version:

Analyse file path and content to make search criteria for media APIs

157 lines (128 loc) 5.51 kB
import {findEpisode, findSeason, findSeasonEpisode, findYear} from "./analyseString"; import {setSpaces, stripEnd, stripParenthesis, stripSeasons, trimEnd} from "./cleanString"; const parseFilePath = (filePath: string): {fileName: string, dirNames: string[]} => { const parts = filePath.split(/[/\\]/); const fileName = parts[parts.length-1]; const dirNames = parts.slice(0, -1); return { fileName, dirNames } } const cleanUpName = (name: string): string => { return stripParenthesis(trimEnd(setSpaces(name))).trim(); } export interface AnalysedMovie { type: 'movie'; year?: number; name: string; } export const isAnalysedMovie = (analysed: AnalysedMedia): analysed is AnalysedMovie => { return (analysed as AnalysedMovie).type === 'movie'; } const analyseForMovie = (fileName: string, dirNames: string[]): AnalysedMovie | undefined => { const yearResult = findYear(fileName) || findYear(dirNames[dirNames.length - 1]); if (!!yearResult) { const name = cleanUpName(yearResult.restName || stripEnd(fileName)); return { type: 'movie', year: yearResult.year, name }; } return undefined; } export interface AnalysedTVShow { type: 'tv'; name: string; season?: number; episodes?: number[]; year?: number; } export const isAnalysedTVShow = (analysed: AnalysedMedia): analysed is AnalysedTVShow => { return (analysed as any).hasOwnProperty('type') && (analysed as AnalysedTVShow).type === 'tv'; } const searchYear = (fileName: string, dirNames: string[], episodeRestName?: string, seasonRestName?: string): {restName?: string, year: number} | undefined => { return findYear(episodeRestName || seasonRestName) || findYear(dirNames[dirNames.length-2]) || findYear(dirNames[dirNames.length-1]) || findYear(fileName); } interface RestName { restName?: string; } const guessName = (fileName: string, dirNames: string[], seResult?: RestName, yearResult?: RestName): string => { return cleanUpName( yearResult?.restName && trimEnd(stripSeasons(yearResult.restName)) || seResult?.restName || (!!yearResult ? dirNames[dirNames.length-3] || dirNames[dirNames.length-2] : dirNames[dirNames.length-2] || dirNames[dirNames.length-1]) || stripEnd(fileName) ); } const tvBySeasonEpisode = (fileName: string, dirNames: string[]): AnalysedTVShow | undefined => { const seasonEpisodeResult = findSeasonEpisode(fileName); if (!!seasonEpisodeResult) { const seasonResult = findSeason(dirNames[dirNames.length-1]); const season = seasonEpisodeResult.season || seasonResult?.season; const yearResult = searchYear(fileName, dirNames, seasonEpisodeResult.restName, seasonResult?.restName); const name = guessName(fileName, dirNames, seasonEpisodeResult.restName ? seasonEpisodeResult : seasonResult, yearResult); return { type: 'tv', name, season, episodes: seasonEpisodeResult.episodes, year: yearResult?.year, } } return undefined; } const tvBySeason = (fileName: string, dirNames: string[]): AnalysedTVShow | undefined => { const seasonResult = findSeason(dirNames[dirNames.length-1]); if (!!seasonResult) { const episodeResult = findEpisode(fileName, seasonResult.season); const yearResult = searchYear(fileName, dirNames, episodeResult?.restName, seasonResult.restName); const name = guessName( fileName, dirNames, episodeResult?.restName ? episodeResult : seasonResult, yearResult); return { type: 'tv', name, season: seasonResult.season, episodes: episodeResult?.episodes, year: yearResult?.year, }; } return undefined; } const analyseForTv = (fileName: string, dirNames: string[]): AnalysedTVShow | undefined => { return tvBySeasonEpisode(fileName, dirNames) || tvBySeason(fileName, dirNames); } export type AnalysedMedia = AnalysedMovie|AnalysedTVShow|string; export const analyseFilePath = (filePath: string): AnalysedMedia => { const {fileName, dirNames} = parseFilePath(filePath); return analyseForTv(fileName, dirNames) || analyseForMovie(fileName, dirNames) || cleanUpName(stripEnd(fileName)); } const extrasRegex = /\bextras?\b|\bfeaturettes?\b|\bbonus?\b|\btrailer?\b/i export const isExtras = (filePath: string): boolean => { const {dirNames, fileName} = parseFilePath(filePath); return dirNames.some((dirName) => extrasRegex.test(dirName)) || extrasRegex.test(fileName); } const samplesRegex = /^samples?$/i const sampleRegex = /\bsample\b/i export const isSample = (filePath: string): boolean => { const {fileName, dirNames} = parseFilePath(filePath); return sampleRegex.test(fileName) || dirNames.some((dirName) => samplesRegex.test(dirName)); } export const isSameRelease = (a: AnalysedMedia, b: AnalysedMedia): boolean => { if (typeof a === 'string' && typeof b === 'string') { return a.toLowerCase() === b.toLowerCase(); } if (isAnalysedMovie(a) && isAnalysedMovie(b)) { return a.name.toLowerCase() === b.name.toLowerCase() && a.year === b.year; } if (isAnalysedTVShow(a) && isAnalysedTVShow(b)) { return a.name.toLowerCase() === b.name.toLowerCase() && a.year === b.year; } return false; }