diff --git a/addon/addon.js b/addon/addon.js index ddfa3a1..9899e50 100644 --- a/addon/addon.js +++ b/addon/addon.js @@ -1,14 +1,14 @@ -const Bottleneck = require('bottleneck'); -const { addonBuilder } = require('stremio-addon-sdk'); -const { Type } = require('./lib/types'); -const { dummyManifest } = require('./lib/manifest'); -const { cacheWrapStream } = require('./lib/cache'); -const { toStreamInfo, applyStaticInfo } = require('./lib/streamInfo'); -const repository = require('./lib/repository'); -const applySorting = require('./lib/sort'); -const applyFilters = require('./lib/filter'); -const { applyMochs, getMochCatalog, getMochItemMeta } = require('./moch/moch'); -const StaticLinks = require("./moch/static"); +import Bottleneck from 'bottleneck'; +import { addonBuilder } from 'stremio-addon-sdk'; +import { Type } from './lib/types.js'; +import { dummyManifest } from './lib/manifest.js'; +import { cacheWrapStream } from './lib/cache.js'; +import { toStreamInfo, applyStaticInfo } from './lib/streamInfo.js'; +import * as repository from './lib/repository.js'; +import applySorting from './lib/sort.js'; +import applyFilters from './lib/filter.js'; +import { applyMochs, getMochCatalog, getMochItemMeta } from './moch/moch.js'; +import StaticLinks from './moch/static.js'; const CACHE_MAX_AGE = parseInt(process.env.CACHE_MAX_AGE) || 60 * 60; // 1 hour in seconds const CACHE_MAX_AGE_EMPTY = 60; // 60 seconds @@ -109,7 +109,7 @@ function enrichCacheParams(streams) { let cacheAge = CACHE_MAX_AGE; if (!streams.length) { cacheAge = CACHE_MAX_AGE_EMPTY; - } else if (streams.every(stream => stream?.url === StaticLinks.FAILED_ACCESS)) { + } else if (streams.every(stream => stream?.url?.endsWith(StaticLinks.FAILED_ACCESS))) { cacheAge = 0; } return { @@ -120,4 +120,4 @@ function enrichCacheParams(streams) { } } -module.exports = builder.getInterface(); +export default builder.getInterface(); diff --git a/addon/index.js b/addon/index.js index 928bff8..a68c628 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,8 +1,8 @@ -const express = require('express'); -const rateLimit = require("express-rate-limit"); -const requestIp = require("request-ip"); -const serverless = require('./serverless'); -const { initBestTrackers } = require('./lib/magnetHelper'); +import express from 'express'; +import rateLimit from 'express-rate-limit'; +import requestIp from 'request-ip'; +import serverless from './serverless.js'; +import { initBestTrackers } from './lib/magnetHelper.js'; const app = express(); app.enable('trust proxy'); diff --git a/addon/lib/cache.js b/addon/lib/cache.js index 5d8871b..710f50e 100644 --- a/addon/lib/cache.js +++ b/addon/lib/cache.js @@ -1,6 +1,6 @@ -const cacheManager = require('cache-manager'); -const mangodbStore = require('cache-manager-mongodb'); -const { isStaticUrl } = require('../moch/static') +import cacheManager from 'cache-manager'; +import mangodbStore from 'cache-manager-mongodb'; +import { isStaticUrl } from '../moch/static.js'; const GLOBAL_KEY_PREFIX = 'torrentio-addon'; const STREAM_KEY_PREFIX = `${GLOBAL_KEY_PREFIX}|stream`; @@ -60,19 +60,19 @@ function cacheWrap(cache, key, method, options) { return cache.wrap(key, method, options); } -function cacheWrapStream(id, method) { +export function cacheWrapStream(id, method) { return cacheWrap(remoteCache, `${STREAM_KEY_PREFIX}:${id}`, method, { ttl: (streams) => streams.length ? STREAM_TTL : STREAM_EMPTY_TTL }); } -function cacheWrapResolvedUrl(id, method) { +export function cacheWrapResolvedUrl(id, method) { return cacheWrap(memoryCache, `${RESOLVED_URL_KEY_PREFIX}:${id}`, method, { ttl: (url) => isStaticUrl(url) ? MESSAGE_VIDEO_URL_TTL : STREAM_TTL }); } -function cacheAvailabilityResults(results) { +export function cacheAvailabilityResults(results) { Object.keys(results) .forEach(infoHash => { const key = `${AVAILABILITY_KEY_PREFIX}:${infoHash}`; @@ -83,7 +83,7 @@ function cacheAvailabilityResults(results) { return results; } -function getCachedAvailabilityResults(infoHashes) { +export function getCachedAvailabilityResults(infoHashes) { const keys = infoHashes.map(infoHash => `${AVAILABILITY_KEY_PREFIX}:${infoHash}`) return new Promise(resolve => { memoryCache.mget(...keys, (error, result) => { @@ -101,6 +101,3 @@ function getCachedAvailabilityResults(infoHashes) { }) }); } - -module.exports = { cacheWrapStream, cacheWrapResolvedUrl, cacheAvailabilityResults, getCachedAvailabilityResults }; - diff --git a/addon/lib/configuration.js b/addon/lib/configuration.js index c9f741e..4b9204c 100644 --- a/addon/lib/configuration.js +++ b/addon/lib/configuration.js @@ -1,8 +1,8 @@ -const { DebridOptions } = require('../moch/options'); -const { QualityFilter, Providers, SizeFilter } = require('./filter'); -const { LanguageOptions } = require('./languages'); +import { DebridOptions } from '../moch/options.js'; +import { QualityFilter, Providers, SizeFilter } from './filter.js'; +import { LanguageOptions } from './languages.js'; -const PRE_CONFIGURATIONS = { +export const PreConfigurations = { lite: { config: liteConfig(), serialized: configValue(liteConfig()), @@ -29,9 +29,9 @@ const PRE_CONFIGURATIONS = { const keysToSplit = [Providers.key, LanguageOptions.key, QualityFilter.key, SizeFilter.key, DebridOptions.key]; const keyToUppercase = [SizeFilter.key]; -function parseConfiguration(configuration) { - if (PRE_CONFIGURATIONS[configuration]) { - return PRE_CONFIGURATIONS[configuration].config; +export function parseConfiguration(configuration) { + if (PreConfigurations[configuration]) { + return PreConfigurations[configuration].config; } const configValues = configuration.split('|') .reduce((map, next) => { @@ -73,11 +73,7 @@ function configValue(config) { .join('|'); } -function getManifestOverride(config) { - const preConfig = Object.values(PRE_CONFIGURATIONS).find(pre => pre.config === config); +export function getManifestOverride(config) { + const preConfig = Object.values(PreConfigurations).find(pre => pre.config === config); return preConfig ? preConfig.manifest : {}; -} - -module.exports.PreConfigurations = PRE_CONFIGURATIONS; -module.exports.parseConfiguration = parseConfiguration; -module.exports.getManifestOverride = getManifestOverride; \ No newline at end of file +} \ No newline at end of file diff --git a/addon/lib/extension.js b/addon/lib/extension.js index 57eb70c..abd1b72 100644 --- a/addon/lib/extension.js +++ b/addon/lib/extension.js @@ -50,25 +50,23 @@ const ARCHIVE_EXTENSIONS = [ "zip" ] -function isVideo(filename) { +export function isVideo(filename) { return isExtension(filename, VIDEO_EXTENSIONS); } -function isSubtitle(filename) { +export function isSubtitle(filename) { return isExtension(filename, SUBTITLE_EXTENSIONS); } -function isDisk(filename) { +export function isDisk(filename) { return isExtension(filename, DISK_EXTENSIONS); } -function isArchive(filename) { +export function isArchive(filename) { return isExtension(filename, ARCHIVE_EXTENSIONS); } -function isExtension(filename, extensions) { - const extensionMatch = filename && filename.match(/\.(\w{2,4})$/); +export function isExtension(filename, extensions) { + const extensionMatch = filename?.match(/\.(\w{2,4})$/); return extensionMatch && extensions.includes(extensionMatch[1].toLowerCase()); } - -module.exports = { isVideo, isSubtitle, isDisk, isArchive, isExtension } \ No newline at end of file diff --git a/addon/lib/filter.js b/addon/lib/filter.js index ec67fa9..2b60d8a 100644 --- a/addon/lib/filter.js +++ b/addon/lib/filter.js @@ -1,6 +1,6 @@ -const { extractProvider, parseSize, extractSize } = require("./titleHelper"); -const { Type } = require("./types"); -const Providers = { +import { extractProvider, parseSize, extractSize } from './titleHelper.js'; +import { Type } from './types.js'; +export const Providers = { key: 'providers', options: [ { @@ -82,7 +82,7 @@ const Providers = { }, ] }; -const QualityFilter = { +export const QualityFilter = { key: 'qualityfilter', options: [ { @@ -175,12 +175,12 @@ const QualityFilter = { } ] }; -const SizeFilter = { +export const SizeFilter = { key: 'sizefilter' } const defaultProviderKeys = Providers.options.map(provider => provider.key); -function applyFilters(streams, config) { +export default function applyFilters(streams, config) { return [ filterByProvider, filterByQuality, @@ -223,8 +223,3 @@ function filterBySize(streams, config) { return size <= sizeLimit; }) } - -module.exports = applyFilters; -module.exports.Providers = Providers; -module.exports.QualityFilter = QualityFilter; -module.exports.SizeFilter = SizeFilter; diff --git a/addon/lib/landingTemplate.js b/addon/lib/landingTemplate.js index 264bcdc..0e39d98 100644 --- a/addon/lib/landingTemplate.js +++ b/addon/lib/landingTemplate.js @@ -184,16 +184,15 @@ a.install-link { box-shadow: 0 0 0 2pt rgb(30, 144, 255, 0.7); } `; -const { Providers } = require('./filter'); -const { SortOptions } = require('./sort'); -const { LanguageOptions } = require('./languages'); -const { QualityFilter, SizeFilter } = require('./filter'); -const { DebridOptions } = require('../moch/options'); -const { MochOptions } = require('../moch/moch'); -const { PreConfigurations } = require('../lib/configuration'); +import { Providers, QualityFilter, SizeFilter } from './filter.js'; +import { SortOptions } from './sort.js'; +import { LanguageOptions } from './languages.js'; +import { DebridOptions } from '../moch/options.js'; +import { MochOptions } from '../moch/moch.js'; +import { PreConfigurations } from './configuration.js'; -function landingTemplate(manifest, config = {}) { - const providers = config.providers || Providers.options.map(provider => provider.key); +export default function landingTemplate(manifest, config = {}) { + const providers = config[Providers.key] || Providers.options.map(provider => provider.key); const sort = config[SortOptions.key] || SortOptions.options.qualitySeeders.key; const languages = config[LanguageOptions.key] || []; const qualityFilters = config[QualityFilter.key] || []; @@ -491,5 +490,3 @@ function landingTemplate(manifest, config = {}) { ` } - -module.exports = landingTemplate; \ No newline at end of file diff --git a/addon/lib/languages.js b/addon/lib/languages.js index 8076ca1..1b80ac4 100644 --- a/addon/lib/languages.js +++ b/addon/lib/languages.js @@ -47,7 +47,7 @@ const languageMapping = { 'thai': 'šŸ‡¹šŸ‡­' } -const LanguageOptions = { +export const LanguageOptions = { key: 'language', options: Object.keys(languageMapping).slice(5).map(lang => ({ key: lang, @@ -55,7 +55,7 @@ const LanguageOptions = { })) } -function mapLanguages(languages) { +export function mapLanguages(languages) { const mapped = languages .map(language => languageMapping[language]) .filter(language => language) @@ -66,13 +66,11 @@ function mapLanguages(languages) { return [...new Set([].concat(mapped).concat(unmapped))]; } -function containsLanguage(stream, languages) { +export function containsLanguage(stream, languages) { return languages.map(lang => languageMapping[lang]).some(lang => stream.title.includes(lang)); } -function languageFromCode(code) { +export function languageFromCode(code) { const entry = Object.entries(languageMapping).find(entry => entry[1] === code); - return entry && entry[0]; + return entry?.[0]; } - -module.exports = { mapLanguages, containsLanguage, languageFromCode, LanguageOptions } \ No newline at end of file diff --git a/addon/lib/magnetHelper.js b/addon/lib/magnetHelper.js index 7412356..50a43d9 100644 --- a/addon/lib/magnetHelper.js +++ b/addon/lib/magnetHelper.js @@ -1,8 +1,9 @@ -const axios = require('axios'); -const magnet = require('magnet-uri'); -const { getRandomUserAgent } = require('../lib/requestHelper'); -const { getTorrent } = require('../lib/repository'); -const { Type } = require('../lib/types'); +import axios from 'axios'; +import magnet from 'magnet-uri'; +import { getRandomUserAgent } from './requestHelper.js'; +import { getTorrent } from './repository.js'; +import { Type } from './types.js'; +import { extractProvider } from "./titleHelper.js"; const TRACKERS_URL = 'https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt'; const DEFAULT_TRACKERS = [ @@ -61,9 +62,9 @@ let BEST_TRACKERS = []; let ALL_ANIME_TRACKERS = []; let ALL_RUSSIAN_TRACKERS = []; -async function getMagnetLink(infoHash) { +export async function getMagnetLink(infoHash) { const torrent = await getTorrent(infoHash).catch(() => ({ infoHash })); - const torrentTrackers = torrent.trackers && torrent.trackers.split(','); + const torrentTrackers = torrent?.trackers?.split(','); const animeTrackers = torrent.type === Type.ANIME ? ALL_ANIME_TRACKERS : undefined; const providerTrackers = RUSSIAN_PROVIDERS.includes(torrent.provider) && ALL_RUSSIAN_TRACKERS; const trackers = unique([].concat(torrentTrackers).concat(animeTrackers).concat(providerTrackers)); @@ -73,7 +74,7 @@ async function getMagnetLink(infoHash) { : magnet.encode({ infoHash: infoHash }); } -async function initBestTrackers() { +export async function initBestTrackers() { BEST_TRACKERS = await getBestTrackers(); ALL_ANIME_TRACKERS = unique(BEST_TRACKERS.concat(DEFAULT_TRACKERS).concat(ANIME_TRACKERS)); ALL_RUSSIAN_TRACKERS = unique(BEST_TRACKERS.concat(DEFAULT_TRACKERS).concat(RUSSIAN_TRACKERS)); @@ -94,7 +95,7 @@ async function getBestTrackers(retry = 2) { }); } -function getSources(trackersInput, infoHash) { +export function getSources(trackersInput, infoHash) { if (!trackersInput) { return null; } @@ -102,9 +103,8 @@ function getSources(trackersInput, infoHash) { return trackers.map(tracker => `tracker:${tracker}`).concat(`dht:${infoHash}`); } -function enrichStreamSources(stream) { - const match = stream.title.match(/āš™.* ([^ \n]+)/); - const provider = match && match[1]; +export function enrichStreamSources(stream) { + const provider = extractProvider(stream.title); if (ANIME_PROVIDERS.includes(provider)) { const sources = getSources(ALL_ANIME_TRACKERS, stream.infoHash); return { ...stream, sources }; @@ -118,6 +118,4 @@ function enrichStreamSources(stream) { function unique(array) { return Array.from(new Set(array)); -} - -module.exports = { initBestTrackers, getMagnetLink, getSources, enrichStreamSources }; \ No newline at end of file +} \ No newline at end of file diff --git a/addon/lib/manifest.js b/addon/lib/manifest.js index 4d2cdd6..c933cb3 100644 --- a/addon/lib/manifest.js +++ b/addon/lib/manifest.js @@ -1,13 +1,13 @@ -const { MochOptions } = require('../moch/moch'); -const { Providers } = require('./filter'); -const { showDebridCatalog } = require('../moch/options'); -const { getManifestOverride } = require('./configuration'); -const { Type } = require('./types'); +import { MochOptions } from '../moch/moch.js'; +import { Providers } from './filter.js'; +import { showDebridCatalog } from '../moch/options.js'; +import { getManifestOverride } from './configuration.js'; +import { Type } from './types.js'; const DefaultProviders = Providers.options.map(provider => provider.key); const CatalogMochs = Object.values(MochOptions).filter(moch => moch.catalog); -function manifest(config = {}) { +export function manifest(config = {}) { const defaultManifest = { id: 'com.stremio.torrentio.addon', version: '0.0.13', @@ -27,7 +27,7 @@ function manifest(config = {}) { return Object.assign(defaultManifest, overrideManifest); } -function dummyManifest() { +export function dummyManifest() { const manifestDefault = manifest(); manifestDefault.catalogs = [{ id: 'dummy', type: Type.OTHER }]; manifestDefault.resources = ['stream', 'meta']; @@ -35,7 +35,7 @@ function dummyManifest() { } function getDescription(config) { - const providersList = config.providers || DefaultProviders; + const providersList = config[Providers.key] || DefaultProviders; const enabledProvidersDesc = Providers.options .map(provider => `${provider.label}${providersList.includes(provider.key) ? '(+)' : '(-)'}`) .join(', ') @@ -76,5 +76,3 @@ function getResources(config) { } return [streamResource]; } - -module.exports = { manifest, dummyManifest }; \ No newline at end of file diff --git a/addon/lib/promises.js b/addon/lib/promises.js index dc501f2..55094bb 100644 --- a/addon/lib/promises.js +++ b/addon/lib/promises.js @@ -1,14 +1,14 @@ /** * Delay promise */ -async function delay(duration) { +export async function delay(duration) { return new Promise((resolve) => setTimeout(resolve, duration)); } /** * Timeout promise after a set time in ms */ -async function timeout(timeoutMs, promise, message = 'Timed out') { +export async function timeout(timeoutMs, promise, message = 'Timed out') { return Promise.race([ promise, new Promise(function (resolve, reject) { @@ -18,5 +18,3 @@ async function timeout(timeoutMs, promise, message = 'Timed out') { }) ]); } - -module.exports = { delay, timeout }; \ No newline at end of file diff --git a/addon/lib/repository.js b/addon/lib/repository.js index 9325bd2..e6c3029 100644 --- a/addon/lib/repository.js +++ b/addon/lib/repository.js @@ -1,4 +1,4 @@ -const { Sequelize } = require('sequelize'); +import { Sequelize } from 'sequelize'; const Op = Sequelize.Op; const DATABASE_URI = process.env.DATABASE_URI; @@ -67,15 +67,15 @@ File.belongsTo(Torrent, { foreignKey: 'infoHash', constraints: false }); File.hasMany(Subtitle, { foreignKey: 'fileId', constraints: false }); Subtitle.belongsTo(File, { foreignKey: 'fileId', constraints: false }); -function getTorrent(infoHash) { +export function getTorrent(infoHash) { return Torrent.findOne({ where: { infoHash: infoHash } }); } -function getFiles(infoHashes) { +export function getFiles(infoHashes) { return File.findAll({ where: { infoHash: { [Op.in]: infoHashes} } }); } -function getImdbIdMovieEntries(imdbId) { +export function getImdbIdMovieEntries(imdbId) { return File.findAll({ where: { imdbId: { [Op.eq]: imdbId } @@ -88,7 +88,7 @@ function getImdbIdMovieEntries(imdbId) { }); } -function getImdbIdSeriesEntries(imdbId, season, episode) { +export function getImdbIdSeriesEntries(imdbId, season, episode) { return File.findAll({ where: { imdbId: { [Op.eq]: imdbId }, @@ -103,7 +103,7 @@ function getImdbIdSeriesEntries(imdbId, season, episode) { }); } -function getKitsuIdMovieEntries(kitsuId) { +export function getKitsuIdMovieEntries(kitsuId) { return File.findAll({ where: { kitsuId: { [Op.eq]: kitsuId } @@ -116,7 +116,7 @@ function getKitsuIdMovieEntries(kitsuId) { }); } -function getKitsuIdSeriesEntries(kitsuId, episode) { +export function getKitsuIdSeriesEntries(kitsuId, episode) { return File.findAll({ where: { kitsuId: { [Op.eq]: kitsuId }, @@ -129,12 +129,3 @@ function getKitsuIdSeriesEntries(kitsuId, episode) { ] }); } - -module.exports = { - getTorrent, - getFiles, - getImdbIdMovieEntries, - getImdbIdSeriesEntries, - getKitsuIdMovieEntries, - getKitsuIdSeriesEntries -}; \ No newline at end of file diff --git a/addon/lib/requestHelper.js b/addon/lib/requestHelper.js index 27e4fd2..7053ac4 100644 --- a/addon/lib/requestHelper.js +++ b/addon/lib/requestHelper.js @@ -1,8 +1,6 @@ -const UserAgent = require('user-agents'); +import UserAgent from 'user-agents'; const userAgent = new UserAgent(); -function getRandomUserAgent() { +export function getRandomUserAgent() { return userAgent.random().toString(); } - -module.exports = { getRandomUserAgent }; \ No newline at end of file diff --git a/addon/lib/sort.js b/addon/lib/sort.js index 3a46373..cd9de08 100644 --- a/addon/lib/sort.js +++ b/addon/lib/sort.js @@ -1,8 +1,8 @@ -const { QualityFilter } = require('./filter'); -const { containsLanguage, LanguageOptions } = require('./languages'); -const { Type } = require("./types"); -const { hasMochConfigured } = require("../moch/moch"); -const { extractSeeders, extractSize } = require("./titleHelper"); +import { QualityFilter } from './filter.js'; +import { containsLanguage, LanguageOptions } from './languages.js'; +import { Type } from './types.js'; +import { hasMochConfigured } from '../moch/moch.js'; +import { extractSeeders, extractSize } from './titleHelper.js'; const OTHER_QUALITIES = QualityFilter.options.find(option => option.key === 'other'); const CAM_QUALITIES = QualityFilter.options.find(option => option.key === 'cam'); @@ -11,7 +11,7 @@ const SEEDED_SEEDERS = 1; const MIN_HEALTHY_COUNT = 50; const MAX_UNHEALTHY_COUNT = 5; -const SortOptions = { +export const SortOptions = { key: 'sort', options: { qualitySeeders: { @@ -33,7 +33,7 @@ const SortOptions = { } } -function sortStreams(streams, config, type) { +export default function sortStreams(streams, config, type) { const languages = config[LanguageOptions.key]; if (languages?.length && languages[0] !== 'english') { // No need to filter english since it's hard to predict which entries are english @@ -126,6 +126,3 @@ function extractQuality(title) { } return qualityDesc; } - -module.exports = sortStreams; -module.exports.SortOptions = SortOptions; \ No newline at end of file diff --git a/addon/lib/streamInfo.js b/addon/lib/streamInfo.js index c485a1a..59436ac 100644 --- a/addon/lib/streamInfo.js +++ b/addon/lib/streamInfo.js @@ -1,15 +1,15 @@ -const titleParser = require('parse-torrent-title'); -const { Type } = require('./types'); -const { mapLanguages } = require('./languages'); -const { enrichStreamSources, getSources } = require('./magnetHelper'); -const { getSubtitles } = require("./subtitles"); +import titleParser from 'parse-torrent-title'; +import { Type } from './types.js'; +import { mapLanguages } from './languages.js'; +import { enrichStreamSources, getSources } from './magnetHelper.js'; +import { getSubtitles } from './subtitles.js'; const ADDON_NAME = 'Torrentio'; const SIZE_DELTA = 0.02; const UNKNOWN_SIZE = 300000000; const CAM_SOURCES = ['CAM', 'TeleSync', 'TeleCine', 'SCR']; -function toStreamInfo(record) { +export function toStreamInfo(record) { const torrentInfo = titleParser.parse(record.torrent.title); const fileInfo = titleParser.parse(record.title); const sameInfo = !Number.isInteger(record.fileIndex) @@ -105,7 +105,7 @@ function formatSize(size) { return Number((size / Math.pow(1024, i)).toFixed(2)) + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i]; } -function applyStaticInfo(streams) { +export function applyStaticInfo(streams) { return streams.map(stream => enrichStaticInfo(stream)); } @@ -148,5 +148,3 @@ function getBingeGroupParts(record, sameInfo, quality, torrentInfo, fileInfo) { function cleanOutputObject(object) { return Object.fromEntries(Object.entries(object).filter(([_, v]) => v != null)); } - -module.exports = { toStreamInfo, applyStaticInfo }; diff --git a/addon/lib/subtitles.js b/addon/lib/subtitles.js index dac87c5..10be676 100644 --- a/addon/lib/subtitles.js +++ b/addon/lib/subtitles.js @@ -1,7 +1,7 @@ -const { parse } = require('parse-torrent-title'); -const { isExtension } = require("./extension"); -const { Providers } = require("./filter"); -const { languageFromCode } = require("./languages"); +import { parse } from 'parse-torrent-title'; +import { isExtension } from './extension.js'; +import { Providers } from './filter.js'; +import { languageFromCode } from './languages.js'; const languageMapping = { 'english': 'eng', @@ -50,8 +50,8 @@ const languageMapping = { const ignoreSet = new Set(['dubbed', 'multi audio', 'multi subs', 'dual audio']); const allowedExtensions = ['srt', 'vtt', 'ass', 'ssa']; -function getSubtitles(record) { - if (!record.subtitles || !record.subtitles.length) { +export function getSubtitles(record) { + if (!record?.subtitles?.length) { return null; } return record.subtitles @@ -95,7 +95,5 @@ function getSingleLanguage(title) { function getFileNameLanguageCode(fileName) { const match = fileName.match(/(?:(?:^|[._ ])([A-Za-z][a-z]{1,2})|\[([a-z]{2,3})])\.\w{3,4}$/); - return match && match[1].toLowerCase(); + return match?.[1]?.toLowerCase(); } - -module.exports = { getSubtitles } \ No newline at end of file diff --git a/addon/lib/titleHelper.js b/addon/lib/titleHelper.js index 1376a29..49f52b8 100644 --- a/addon/lib/titleHelper.js +++ b/addon/lib/titleHelper.js @@ -1,19 +1,19 @@ -function extractSeeders(title) { +export function extractSeeders(title) { const seedersMatch = title.match(/šŸ‘¤ (\d+)/); return seedersMatch && parseInt(seedersMatch[1]) || 0; } -function extractSize(title) { +export function extractSize(title) { const seedersMatch = title.match(/šŸ’¾ ([\d.]+ \w+)/); return seedersMatch && parseSize(seedersMatch[1]) || 0; } -function extractProvider(title) { +export function extractProvider(title) { const match = title.match(/āš™.* ([^ \n]+)/); return match?.[1]?.toLowerCase(); } -function parseSize(sizeText) { +export function parseSize(sizeText) { if (!sizeText) { return 0; } @@ -29,5 +29,3 @@ function parseSize(sizeText) { } return Math.floor(parseFloat(sizeText.replace(/,/g, '')) * scale); } - -module.exports = { extractSeeders, extractSize, extractProvider, parseSize } \ No newline at end of file diff --git a/addon/lib/types.js b/addon/lib/types.js index 12be6bb..5d9b2ea 100644 --- a/addon/lib/types.js +++ b/addon/lib/types.js @@ -1,4 +1,4 @@ -exports.Type = { +export const Type = { MOVIE: 'movie', SERIES: 'series', ANIME: 'anime', diff --git a/addon/moch/alldebrid.js b/addon/moch/alldebrid.js index 0bf365d..b2bf52f 100644 --- a/addon/moch/alldebrid.js +++ b/addon/moch/alldebrid.js @@ -1,14 +1,14 @@ -const AllDebridClient = require('all-debrid-api'); -const { Type } = require('../lib/types'); -const { isVideo, isArchive } = require('../lib/extension'); -const StaticResponse = require('./static'); -const { getMagnetLink } = require('../lib/magnetHelper'); -const { BadTokenError, AccessDeniedError } = require('./mochHelper'); +import AllDebridClient from 'all-debrid-api'; +import { Type } from '../lib/types.js'; +import { isVideo, isArchive } from '../lib/extension.js'; +import StaticResponse from './static.js'; +import { getMagnetLink } from '../lib/magnetHelper.js'; +import { BadTokenError, AccessDeniedError } from './mochHelper.js'; const KEY = 'alldebrid'; const AGENT = 'torrentio'; -async function getCachedStreams(streams, apiKey) { +export async function getCachedStreams(streams, apiKey) { const options = await getDefaultOptions(); const AD = new AllDebridClient(apiKey, options); const hashes = streams.map(stream => stream.infoHash); @@ -23,7 +23,7 @@ async function getCachedStreams(streams, apiKey) { console.warn(`Failed AllDebrid cached [${hashes[0]}] torrent availability request:`, error); return undefined; }); - return available && available.data && available.data.magnets && streams + return available?.data?.magnets && streams .reduce((mochStreams, stream) => { const cachedEntry = available.data.magnets.find(magnet => stream.infoHash === magnet.hash.toLowerCase()); const streamTitleParts = stream.title.replace(/\nšŸ‘¤.*/s, '').split('\n'); @@ -32,13 +32,13 @@ async function getCachedStreams(streams, apiKey) { const encodedFileName = encodeURIComponent(fileName); mochStreams[stream.infoHash] = { url: `${apiKey}/${stream.infoHash}/${encodedFileName}/${fileIndex}`, - cached: cachedEntry && cachedEntry.instant + cached: cachedEntry?.instant } return mochStreams; }, {}) } -async function getCatalog(apiKey, offset = 0) { +export async function getCatalog(apiKey, offset = 0) { if (offset > 0) { return []; } @@ -55,7 +55,7 @@ async function getCatalog(apiKey, offset = 0) { }))); } -async function getItemMeta(itemId, apiKey) { +export async function getItemMeta(itemId, apiKey) { const options = await getDefaultOptions(); const AD = new AllDebridClient(apiKey, options); return AD.magnet.status(itemId) @@ -76,7 +76,7 @@ async function getItemMeta(itemId, apiKey) { })) } -async function resolve({ ip, apiKey, infoHash, cachedEntryInfo, fileIndex }) { +export async function resolve({ ip, apiKey, infoHash, cachedEntryInfo, fileIndex }) { console.log(`Unrestricting AllDebrid ${infoHash} [${fileIndex}]`); const options = await getDefaultOptions(ip); const AD = new AllDebridClient(apiKey, options); @@ -186,5 +186,3 @@ function errorExpiredSubscriptionError(error) { return ['AUTH_BAD_APIKEY', 'MUST_BE_PREMIUM', 'MAGNET_MUST_BE_PREMIUM', 'FREE_TRIAL_LIMIT_REACHED', 'AUTH_USER_BANNED'] .includes(error.code); } - -module.exports = { getCachedStreams, resolve, getCatalog, getItemMeta }; \ No newline at end of file diff --git a/addon/moch/debridlink.js b/addon/moch/debridlink.js index 3d632bb..ef5dbac 100644 --- a/addon/moch/debridlink.js +++ b/addon/moch/debridlink.js @@ -1,14 +1,13 @@ -const DebridLinkClient = require('debrid-link-api'); -const { Type } = require('../lib/types'); -const { isVideo, isArchive } = require('../lib/extension'); -const { delay } = require('../lib/promises'); -const StaticResponse = require('./static'); -const { getMagnetLink } = require('../lib/magnetHelper'); -const { chunkArray, BadTokenError } = require('./mochHelper'); +import DebridLinkClient from 'debrid-link-api'; +import { Type } from '../lib/types.js'; +import { isVideo, isArchive } from '../lib/extension.js'; +import StaticResponse from './static.js'; +import { getMagnetLink } from '../lib/magnetHelper.js'; +import { chunkArray, BadTokenError } from './mochHelper.js'; const KEY = 'debridlink'; -async function getCachedStreams(streams, apiKey) { +export async function getCachedStreams(streams, apiKey) { const options = await getDefaultOptions(); const DL = new DebridLinkClient(apiKey, options); const hashBatches = chunkArray(streams.map(stream => stream.infoHash), 50) @@ -34,7 +33,7 @@ async function getCachedStreams(streams, apiKey) { }, {}) } -async function getCatalog(apiKey, offset = 0) { +export async function getCatalog(apiKey, offset = 0) { if (offset > 0) { return []; } @@ -51,7 +50,7 @@ async function getCatalog(apiKey, offset = 0) { }))); } -async function getItemMeta(itemId, apiKey, ip) { +export async function getItemMeta(itemId, apiKey, ip) { const options = await getDefaultOptions(ip); const DL = new DebridLinkClient(apiKey, options); return DL.seedbox.list(itemId) @@ -72,7 +71,7 @@ async function getItemMeta(itemId, apiKey, ip) { })) } -async function resolve({ ip, apiKey, infoHash, fileIndex }) { +export async function resolve({ ip, apiKey, infoHash, fileIndex }) { console.log(`Unrestricting DebridLink ${infoHash} [${fileIndex}]`); const options = await getDefaultOptions(ip); const DL = new DebridLinkClient(apiKey, options); @@ -147,5 +146,3 @@ function statusReady(torrent) { function errorExpiredSubscriptionError(error) { return ['freeServerOverload', 'maxTorrent', 'maxLink', 'maxLinkHost', 'maxData', 'maxDataHost'].includes(error); } - -module.exports = { getCachedStreams, resolve, getCatalog, getItemMeta }; \ No newline at end of file diff --git a/addon/moch/moch.js b/addon/moch/moch.js index 31f013a..0a24728 100644 --- a/addon/moch/moch.js +++ b/addon/moch/moch.js @@ -1,21 +1,21 @@ -const namedQueue = require('named-queue'); -const options = require('./options'); -const realdebrid = require('./realdebrid'); -const premiumize = require('./premiumize'); -const alldebrid = require('./alldebrid'); -const debridlink = require('./debridlink'); -const offcloud = require('./offcloud'); -const putio = require('./putio'); -const StaticResponse = require('./static'); -const { cacheWrapResolvedUrl } = require('../lib/cache'); -const { timeout } = require('../lib/promises'); -const { BadTokenError, streamFilename, AccessDeniedError, enrichMeta } = require('./mochHelper'); -const { isStaticUrl } = require("./static"); +import namedQueue from 'named-queue'; +import * as options from './options.js'; +import * as realdebrid from './realdebrid.js'; +import * as premiumize from './premiumize.js'; +import * as alldebrid from './alldebrid.js'; +import * as debridlink from './debridlink.js'; +import * as offcloud from './offcloud.js'; +import * as putio from './putio.js'; +import StaticResponse from './static.js'; +import { cacheWrapResolvedUrl } from '../lib/cache.js'; +import { timeout } from '../lib/promises.js'; +import { BadTokenError, streamFilename, AccessDeniedError, enrichMeta } from './mochHelper.js'; +import { isStaticUrl } from './static.js'; const RESOLVE_TIMEOUT = 2 * 60 * 1000; // 2 minutes const MIN_API_KEY_SYMBOLS = 15; const TOKEN_BLACKLIST = []; -const MOCHS = { +export const MochOptions = { realdebrid: { key: 'realdebrid', instance: realdebrid, @@ -64,17 +64,17 @@ const unrestrictQueue = new namedQueue((task, callback) => task.method() .then(result => callback(false, result)) .catch((error => callback(error))), 20); -function hasMochConfigured(config) { - return Object.keys(MOCHS).find(moch => config?.[moch]) +export function hasMochConfigured(config) { + return Object.keys(MochOptions).find(moch => config?.[moch]) } -async function applyMochs(streams, config) { +export async function applyMochs(streams, config) { if (!streams?.length || !hasMochConfigured(config)) { return streams; } return Promise.all(Object.keys(config) - .filter(configKey => MOCHS[configKey]) - .map(configKey => MOCHS[configKey]) + .filter(configKey => MochOptions[configKey]) + .map(configKey => MochOptions[configKey]) .map(moch => { if (isInvalidToken(config[moch.key], moch.key)) { return { moch, error: BadTokenError }; @@ -91,8 +91,8 @@ async function applyMochs(streams, config) { .then(results => processMochResults(streams, config, results)); } -async function resolve(parameters) { - const moch = MOCHS[parameters.mochKey]; +export async function resolve(parameters) { + const moch = MochOptions[parameters.mochKey]; if (!moch) { return Promise.reject(new Error(`Not a valid moch provider: ${parameters.mochKey}`)); } @@ -112,8 +112,8 @@ async function resolve(parameters) { })); } -async function getMochCatalog(mochKey, config) { - const moch = MOCHS[mochKey]; +export async function getMochCatalog(mochKey, config) { + const moch = MochOptions[mochKey]; if (!moch) { return Promise.reject(new Error(`Not a valid moch provider: ${mochKey}`)); } @@ -123,8 +123,8 @@ async function getMochCatalog(mochKey, config) { return moch.instance.getCatalog(config[moch.key], config.skip, config.ip); } -async function getMochItemMeta(mochKey, itemId, config) { - const moch = MOCHS[mochKey]; +export async function getMochItemMeta(mochKey, itemId, config) { + const moch = MochOptions[mochKey]; if (!moch) { return Promise.reject(new Error(`Not a valid moch provider: ${mochKey}`)); } @@ -212,19 +212,17 @@ function blackListToken(token, mochKey) { function errorStreamResponse(mochKey, error, config) { if (error === BadTokenError) { return { - name: `Torrentio\n${MOCHS[mochKey].shortName} error`, - title: `Invalid ${MOCHS[mochKey].name} ApiKey/Token!`, + name: `Torrentio\n${MochOptions[mochKey].shortName} error`, + title: `Invalid ${MochOptions[mochKey].name} ApiKey/Token!`, url: `${config.host}/${StaticResponse.FAILED_ACCESS}` }; } if (error === AccessDeniedError) { return { - name: `Torrentio\n${MOCHS[mochKey].shortName} error`, - title: `Expired/invalid ${MOCHS[mochKey].name} subscription!`, + name: `Torrentio\n${MochOptions[mochKey].shortName} error`, + title: `Expired/invalid ${MochOptions[mochKey].name} subscription!`, url: `${config.host}/${StaticResponse.FAILED_ACCESS}` }; } return undefined; } - -module.exports = { applyMochs, getMochCatalog, getMochItemMeta, resolve, hasMochConfigured, MochOptions: MOCHS } diff --git a/addon/moch/mochHelper.js b/addon/moch/mochHelper.js index b99991a..8f75050 100644 --- a/addon/moch/mochHelper.js +++ b/addon/moch/mochHelper.js @@ -1,16 +1,16 @@ -const repository = require('../lib/repository') +import * as repository from '../lib/repository.js'; const METAHUB_URL = 'https://images.metahub.space' -const BadTokenError = { code: 'BAD_TOKEN' } -const AccessDeniedError = { code: 'ACCESS_DENIED' } +export const BadTokenError = { code: 'BAD_TOKEN' } +export const AccessDeniedError = { code: 'ACCESS_DENIED' } -function chunkArray(arr, size) { +export function chunkArray(arr, size) { return arr.length > size ? [arr.slice(0, size), ...chunkArray(arr.slice(size), size)] : [arr]; } -function streamFilename(stream) { +export function streamFilename(stream) { const titleParts = stream.title.replace(/\nšŸ‘¤.*/s, '').split('\n'); const filePath = titleParts.pop(); const filename = titleParts.length @@ -19,7 +19,7 @@ function streamFilename(stream) { return encodeURIComponent(filename) } -async function enrichMeta(itemMeta) { +export async function enrichMeta(itemMeta) { const infoHashes = [...new Set([itemMeta.infoHash] .concat(itemMeta.videos.map(video => video.infoHash)) .filter(infoHash => infoHash))]; @@ -33,7 +33,7 @@ async function enrichMeta(itemMeta) { background: commonImdbId && `${METAHUB_URL}/background/medium/${commonImdbId}/img`, videos: itemMeta.videos.map(video => { const file = files.find(file => video.title.includes(file.title)); - if (file && file.imdbId) { + if (file?.imdbId) { if (file.imdbSeason && file.imdbEpisode) { video.id = `${file.imdbId}:${file.imdbSeason}:${file.imdbEpisode}`; video.season = file.imdbSeason; @@ -54,5 +54,3 @@ async function enrichMeta(itemMeta) { function mostCommonValue(array) { return array.sort((a, b) => array.filter(v => v === a).length - array.filter(v => v === b).length).pop(); } - -module.exports = { chunkArray, streamFilename, enrichMeta, BadTokenError, AccessDeniedError } diff --git a/addon/moch/offcloud.js b/addon/moch/offcloud.js index cd857fb..0d32622 100644 --- a/addon/moch/offcloud.js +++ b/addon/moch/offcloud.js @@ -1,13 +1,13 @@ -const OffcloudClient = require('offcloud-api'); -const { Type } = require('../lib/types'); -const { isVideo } = require('../lib/extension'); -const StaticResponse = require('./static'); -const { getMagnetLink } = require('../lib/magnetHelper'); -const { chunkArray, BadTokenError } = require('./mochHelper'); +import OffcloudClient from 'offcloud-api'; +import { Type } from '../lib/types.js'; +import { isVideo } from '../lib/extension.js'; +import StaticResponse from './static.js'; +import { getMagnetLink } from '../lib/magnetHelper.js'; +import { chunkArray, BadTokenError } from './mochHelper.js'; const KEY = 'offcloud'; -async function getCachedStreams(streams, apiKey) { +export async function getCachedStreams(streams, apiKey) { const options = await getDefaultOptions(); const OC = new OffcloudClient(apiKey, options); const hashBatches = chunkArray(streams.map(stream => stream.infoHash), 100); @@ -36,7 +36,7 @@ async function getCachedStreams(streams, apiKey) { }, {}) } -async function getCatalog(apiKey, offset = 0) { +export async function getCatalog(apiKey, offset = 0) { if (offset > 0) { return []; } @@ -52,7 +52,7 @@ async function getCatalog(apiKey, offset = 0) { }))); } -async function getItemMeta(itemId, apiKey, ip) { +export async function getItemMeta(itemId, apiKey, ip) { const options = await getDefaultOptions(ip); const OC = new OffcloudClient(apiKey, options); const torrents = await OC.cloud.history(); @@ -74,7 +74,7 @@ async function getItemMeta(itemId, apiKey, ip) { })) } -async function resolve({ ip, apiKey, infoHash, cachedEntryInfo, fileIndex }) { +export async function resolve({ ip, apiKey, infoHash, cachedEntryInfo, fileIndex }) { console.log(`Unrestricting Offcloud ${infoHash} [${fileIndex}]`); const options = await getDefaultOptions(ip); const OC = new OffcloudClient(apiKey, options); @@ -152,5 +152,3 @@ function statusReady(torrent) { function errorExpiredSubscriptionError(error) { return error && (error.includes('not_available') || error.includes('NOAUTH')); } - -module.exports = { getCachedStreams, resolve, getCatalog, getItemMeta }; \ No newline at end of file diff --git a/addon/moch/options.js b/addon/moch/options.js index 80e9fc5..9b793fd 100644 --- a/addon/moch/options.js +++ b/addon/moch/options.js @@ -1,4 +1,4 @@ -const DebridOptions = { +export const DebridOptions = { key: 'debridoptions', options: { noDownloadLinks: { @@ -16,19 +16,14 @@ const DebridOptions = { } } -function excludeDownloadLinks(config) { - return config[DebridOptions.key] && config[DebridOptions.key] - .includes(DebridOptions.options.noDownloadLinks.key); +export function excludeDownloadLinks(config) { + return config[DebridOptions.key]?.includes(DebridOptions.options.noDownloadLinks.key); } -function includeTorrentLinks(config) { - return config[DebridOptions.key] && config[DebridOptions.key] - .includes(DebridOptions.options.torrentLinks.key); +export function includeTorrentLinks(config) { + return config[DebridOptions.key]?.includes(DebridOptions.options.torrentLinks.key); } -function showDebridCatalog(config) { - return !(config[DebridOptions.key] && config[DebridOptions.key] - .includes(DebridOptions.options.noCatalog.key)); +export function showDebridCatalog(config) { + return !config[DebridOptions.key]?.includes(DebridOptions.options.noCatalog.key); } - -module.exports = { DebridOptions, excludeDownloadLinks, showDebridCatalog, includeTorrentLinks } \ No newline at end of file diff --git a/addon/moch/premiumize.js b/addon/moch/premiumize.js index 0041eda..c18fa6b 100644 --- a/addon/moch/premiumize.js +++ b/addon/moch/premiumize.js @@ -1,14 +1,14 @@ -const PremiumizeClient = require('premiumize-api'); -const magnet = require('magnet-uri'); -const { Type } = require('../lib/types'); -const { isVideo, isArchive } = require('../lib/extension'); -const StaticResponse = require('./static'); -const { getMagnetLink } = require('../lib/magnetHelper'); -const { BadTokenError, chunkArray } = require('./mochHelper'); +import PremiumizeClient from 'premiumize-api'; +import magnet from 'magnet-uri'; +import { Type } from '../lib/types.js'; +import { isVideo, isArchive } from '../lib/extension.js'; +import StaticResponse from './static.js'; +import { getMagnetLink } from '../lib/magnetHelper.js'; +import { BadTokenError, chunkArray } from './mochHelper.js'; const KEY = 'premiumize'; -async function getCachedStreams(streams, apiKey) { +export async function getCachedStreams(streams, apiKey) { const options = await getDefaultOptions(); const PM = new PremiumizeClient(apiKey, options); return Promise.all(chunkArray(streams, 100) @@ -34,13 +34,13 @@ async function _getCachedStreams(PM, apiKey, streams) { const encodedFileName = encodeURIComponent(fileName); mochStreams[stream.infoHash] = { url: `${apiKey}/${stream.infoHash}/${encodedFileName}/${fileIndex}`, - cached: available && available.response[index] + cached: available?.response[index] }; return mochStreams; }, {})); } -async function getCatalog(apiKey, offset = 0) { +export async function getCatalog(apiKey, offset = 0) { if (offset > 0) { return []; } @@ -57,7 +57,7 @@ async function getCatalog(apiKey, offset = 0) { }))); } -async function getItemMeta(itemId, apiKey, ip) { +export async function getItemMeta(itemId, apiKey, ip) { const options = await getDefaultOptions(); const PM = new PremiumizeClient(apiKey, options); const rootFolder = await PM.folder.list(itemId, null); @@ -89,7 +89,7 @@ async function getFolderContents(PM, itemId, ip, folderPrefix = '') { .concat(otherContents))); } -async function resolve({ ip, isBrowser, apiKey, infoHash, cachedEntryInfo, fileIndex }) { +export async function resolve({ ip, isBrowser, apiKey, infoHash, cachedEntryInfo, fileIndex }) { console.log(`Unrestricting Premiumize ${infoHash} [${fileIndex}] for IP ${ip} from browser=${isBrowser}`); const options = await getDefaultOptions(); const PM = new PremiumizeClient(apiKey, options); @@ -120,7 +120,7 @@ async function _resolve(PM, infoHash, cachedEntryInfo, fileIndex, ip, isBrowser) async function _getCachedLink(PM, infoHash, encodedFileName, fileIndex, ip, isBrowser) { const cachedTorrent = await PM.transfer.directDownload(magnet.encode({ infoHash }), ip); - if (cachedTorrent && cachedTorrent.content && cachedTorrent.content.length) { + if (cachedTorrent?.content?.length) { const targetFileName = decodeURIComponent(encodedFileName); const videos = cachedTorrent.content.filter(file => isVideo(file.path)); const targetVideo = Number.isInteger(fileIndex) @@ -178,5 +178,3 @@ function statusReady(status) { async function getDefaultOptions(ip) { return { timeout: 30000 }; } - -module.exports = { getCachedStreams, resolve, getCatalog, getItemMeta }; \ No newline at end of file diff --git a/addon/moch/putio.js b/addon/moch/putio.js index 4a54082..7a20589 100644 --- a/addon/moch/putio.js +++ b/addon/moch/putio.js @@ -1,10 +1,10 @@ -const PutioAPI = require('@putdotio/api-client').default -const { isVideo } = require('../lib/extension'); -const { delay } = require('../lib/promises'); -const StaticResponse = require('./static'); -const { getMagnetLink } = require('../lib/magnetHelper'); +import PutioAPI from '@putdotio/api-client' +import { isVideo } from '../lib/extension.js'; +import { delay } from '../lib/promises.js'; +import StaticResponse from './static.js'; +import { getMagnetLink } from '../lib/magnetHelper.js'; -async function getCachedStreams(streams, apiKey) { +export async function getCachedStreams(streams, apiKey) { return streams .reduce((mochStreams, stream) => { const streamTitleParts = stream.title.replace(/\nšŸ‘¤.*/s, '').split('\n'); @@ -19,7 +19,7 @@ async function getCachedStreams(streams, apiKey) { }, {}); } -async function resolve({ ip, apiKey, infoHash, cachedEntryInfo, fileIndex }) { +export async function resolve({ ip, apiKey, infoHash, cachedEntryInfo, fileIndex }) { console.log(`Unrestricting Putio ${infoHash} [${fileIndex}]`); const clientId = apiKey.replace(/@.*/, ''); const token = apiKey.replace(/.*@/, ''); @@ -28,7 +28,7 @@ async function resolve({ ip, apiKey, infoHash, cachedEntryInfo, fileIndex }) { return _resolve(Putio, infoHash, cachedEntryInfo, fileIndex) .catch(error => { - if (error && error.data && error.data.status_code === 401) { + if (error?.data?.status_code === 401) { console.log(`Access denied to Putio ${infoHash} [${fileIndex}]`); return StaticResponse.FAILED_ACCESS; } @@ -90,7 +90,7 @@ async function _unrestrictLink(Putio, torrent, encodedFileName, fileIndex) { const publicToken = await _getPublicToken(Putio, targetVideo.id); const publicFile = await Putio.File.Public(publicToken).then(response => response.data.parent); - if (!publicFile.stream_url || !publicFile.stream_url.length) { + if (!publicFile?.stream_url?.length) { return Promise.reject(`No Putio links found for [${torrent.hash}] ${encodedFileName}`); } console.log(`Unrestricted Putio ${torrent.hash} [${fileIndex}] to ${publicFile.stream_url}`); @@ -155,5 +155,3 @@ function statusProcessing(status) { function statusReady(status) { return ['COMPLETED', 'SEEDING'].includes(status); } - -module.exports = { getCachedStreams, resolve }; \ No newline at end of file diff --git a/addon/moch/realdebrid.js b/addon/moch/realdebrid.js index 6fe7588..f8361a1 100644 --- a/addon/moch/realdebrid.js +++ b/addon/moch/realdebrid.js @@ -1,11 +1,11 @@ -const RealDebridClient = require('real-debrid-api'); -const { Type } = require('../lib/types'); -const { isVideo, isArchive } = require('../lib/extension'); -const { delay } = require('../lib/promises'); -const { cacheAvailabilityResults, getCachedAvailabilityResults } = require('../lib/cache'); -const StaticResponse = require('./static'); -const { getMagnetLink } = require('../lib/magnetHelper'); -const { chunkArray, BadTokenError, AccessDeniedError } = require('./mochHelper'); +import RealDebridClient from 'real-debrid-api'; +import { Type } from '../lib/types.js'; +import { isVideo, isArchive } from '../lib/extension.js'; +import { delay } from '../lib/promises.js'; +import { cacheAvailabilityResults, getCachedAvailabilityResults } from '../lib/cache.js'; +import StaticResponse from './static.js'; +import { getMagnetLink } from '../lib/magnetHelper.js'; +import { chunkArray, BadTokenError, AccessDeniedError } from './mochHelper.js'; const MIN_SIZE = 5 * 1024 * 1024; // 5 MB const CATALOG_MAX_PAGE = 1; @@ -14,7 +14,7 @@ const NON_BLACKLIST_ERRORS = ['ESOCKETTIMEDOUT', 'EAI_AGAIN', '504 Gateway Time- const KEY = 'realdebrid'; const DEBRID_DOWNLOADS = 'Downloads'; -async function getCachedStreams(streams, apiKey) { +export async function getCachedStreams(streams, apiKey) { const hashes = streams.map(stream => stream.infoHash); const available = await _getInstantAvailable(hashes, apiKey); return available && streams @@ -100,7 +100,7 @@ function _getCachedFileIds(fileIndex, cachedResults) { return cachedIds || []; } -async function getCatalog(apiKey, offset, ip) { +export async function getCatalog(apiKey, offset, ip) { if (offset > 0) { return []; } @@ -123,11 +123,10 @@ async function getCatalog(apiKey, offset, ip) { return [downloadsMeta].concat(torrentMetas) } -async function getItemMeta(itemId, apiKey, ip) { +export async function getItemMeta(itemId, apiKey, ip) { const options = await getDefaultOptions(ip); const RD = new RealDebridClient(apiKey, options); if (itemId === DEBRID_DOWNLOADS) { - // const allTorrents = await _getAllTorrents(RD).catch(() => []); const videos = await _getAllDownloads(RD) .then(downloads => downloads .map(download => ({ @@ -177,7 +176,7 @@ async function _getAllDownloads(RD, page = 1) { return RD.downloads.get(page - 1, page, CATALOG_PAGE_SIZE); } -async function resolve({ ip, isBrowser, apiKey, infoHash, cachedEntryInfo, fileIndex }) { +export async function resolve({ ip, isBrowser, apiKey, infoHash, cachedEntryInfo, fileIndex }) { console.log(`Unrestricting RealDebrid ${infoHash} [${fileIndex}]`); const options = await getDefaultOptions(ip); const RD = new RealDebridClient(apiKey, options); @@ -384,5 +383,3 @@ function infringingFile(error) { async function getDefaultOptions(ip) { return { ip, timeout: 30000 }; } - -module.exports = { getCachedStreams, resolve, getCatalog, getItemMeta }; diff --git a/addon/moch/static.js b/addon/moch/static.js index fc55088..4483e81 100644 --- a/addon/moch/static.js +++ b/addon/moch/static.js @@ -8,11 +8,9 @@ const staticVideoUrls = { FAILED_INFRINGEMENT: `videos/failed_infringement_v2.mp4` } -function isStaticUrl(url) { + +export function isStaticUrl(url) { return Object.values(staticVideoUrls).some(videoUrl => url?.endsWith(videoUrl)); } -module.exports = { - ...staticVideoUrls, - isStaticUrl -} \ No newline at end of file +export default staticVideoUrls \ No newline at end of file diff --git a/addon/package.json b/addon/package.json index 31e2121..a3e49b5 100644 --- a/addon/package.json +++ b/addon/package.json @@ -1,7 +1,8 @@ { "name": "stremio-torrentio", "version": "1.0.13", - "main": "addon.js", + "exports": "./index.js", + "type": "module", "scripts": { "start": "node index.js" }, diff --git a/addon/serverless.js b/addon/serverless.js index 01a2395..8398162 100644 --- a/addon/serverless.js +++ b/addon/serverless.js @@ -1,12 +1,12 @@ -const { getRouter } = require('stremio-addon-sdk'); -const requestIp = require('request-ip'); -const userAgentParser = require('ua-parser-js'); -const addonInterface = require('./addon'); -const qs = require('querystring') -const { manifest } = require('./lib/manifest'); -const { parseConfiguration, PreConfigurations } = require('./lib/configuration'); -const landingTemplate = require('./lib/landingTemplate'); -const moch = require('./moch/moch'); +import getRouter from 'stremio-addon-sdk/src/getRouter.js'; +import requestIp from 'request-ip'; +import userAgentParser from 'ua-parser-js'; +import addonInterface from './addon.js'; +import qs from 'querystring'; +import { manifest } from './lib/manifest.js'; +import { parseConfiguration, PreConfigurations } from './lib/configuration.js'; +import landingTemplate from './lib/landingTemplate.js'; +import * as moch from './moch/moch.js'; const router = getRouter({ ...addonInterface, manifest: manifest() }); @@ -95,7 +95,7 @@ router.get('/:moch/:apiKey/:infoHash/:cachedEntryInfo/:fileIndex/:filename?', (r }); }); -module.exports = function (req, res) { +export default function (req, res) { router(req, res, function () { res.statusCode = 404; res.end();