const { parse } = require('parse-torrent-title'); const { Type } = require('./types'); const MULTIPLE_FILES_SIZE = 4 * 1024 * 1024 * 1024; // 4 GB function parseSeriesVideos(torrent, videos) { const parsedTorrentName = parse(torrent.title); const hasMovies = parsedTorrentName.complete || !!torrent.title.match(/movies?(?:\W|$)/i); const parsedVideos = videos.map(video => parseSeriesVideo(video, parsedTorrentName)); return parsedVideos.map(video => ({ ...video, isMovie: isMovieVideo(video, parsedVideos, torrent.type, hasMovies) })); } function parseSeriesVideo(video, parsedTorrentName) { const videoInfo = parse(video.name); const hasSeason = Number.isInteger(videoInfo.season); // the episode may be in a folder containing season number if (!hasSeason && video.path.includes('/')) { const folders = video.path.split('/'); const pathInfo = parse(folders[folders.length - 2]); videoInfo.season = pathInfo.season; } if (!hasSeason && parsedTorrentName.season) { videoInfo.season = parsedTorrentName.season; } if (!hasSeason && videoInfo.seasons && videoInfo.seasons.length > 1) { // in case single file was interpreted as having multiple seasons videoInfo.season = videoInfo.seasons[0]; } if (!hasSeason && video.path.includes('/') && parsedTorrentName.seasons && parsedTorrentName.seasons.length > 1) { // russian season are usually named with 'series name-2` i.e. Улицы разбитых фонарей-6/22. Одиночный выстрел.mkv const folderPathSeasonMatch = video.path.match(/[\u0400-\u04ff]-(\d{1,2})(?=.*\/)/); videoInfo.season = folderPathSeasonMatch && parseInt(folderPathSeasonMatch[1], 10) || undefined; } // sometimes video file does not have correct date format as in torrent title if (!videoInfo.episodes && !videoInfo.date && parsedTorrentName.date) { videoInfo.date = parsedTorrentName.date; } // limit number of episodes in case of incorrect parsing if (videoInfo.episodes && videoInfo.episodes.length > 20) { videoInfo.episodes = [videoInfo.episodes[0]]; videoInfo.episode = videoInfo.episodes[0]; } // force episode to any found number if it was not parsed if (!videoInfo.episodes && !videoInfo.date) { const epMatcher = videoInfo.title.match( /(? 3 && otherVideos.filter(other => other.title === video.title && other.year === video.year) < 3; } function isPackTorrent(torrent) { if (torrent.pack) { return true; } const parsedInfo = parse(torrent.title); if (torrent.type === Type.MOVIE) { return parsedInfo.complete || typeof parsedInfo.year === 'string' || /movies/i.test(torrent.title); } const hasMultipleEpisodes = parsedInfo.complete || torrent.size > MULTIPLE_FILES_SIZE || (parsedInfo.seasons && parsedInfo.seasons.length > 1) || (parsedInfo.episodes && parsedInfo.episodes.length > 1) || (parsedInfo.seasons && !parsedInfo.episodes); const hasSingleEpisode = Number.isInteger(parsedInfo.episode) || (!parsedInfo.episodes && parsedInfo.date); return hasMultipleEpisodes && !hasSingleEpisode; } module.exports = { parseSeriesVideos, isPackTorrent }