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