mirror of
https://github.com/knightcrawler-stremio/knightcrawler.git
synced 2024-12-20 03:29:51 +00:00
add video size filter to configuration options, closes #131
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
const { DebridOptions } = require('../moch/options');
|
const { DebridOptions } = require('../moch/options');
|
||||||
const { QualityFilter, Providers } = require('./filter');
|
const { QualityFilter, Providers, SizeFilter } = require('./filter');
|
||||||
const { LanguageOptions } = require('./languages');
|
const { LanguageOptions } = require('./languages');
|
||||||
|
|
||||||
const PRE_CONFIGURATIONS = {
|
const PRE_CONFIGURATIONS = {
|
||||||
@@ -26,7 +26,8 @@ const PRE_CONFIGURATIONS = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const keysToSplit = [Providers.key, LanguageOptions.key, QualityFilter.key, DebridOptions.key];
|
const keysToSplit = [Providers.key, LanguageOptions.key, QualityFilter.key, SizeFilter.key, DebridOptions.key];
|
||||||
|
const keyToUppercase = [SizeFilter.key];
|
||||||
|
|
||||||
function parseConfiguration(configuration) {
|
function parseConfiguration(configuration) {
|
||||||
if (PRE_CONFIGURATIONS[configuration]) {
|
if (PRE_CONFIGURATIONS[configuration]) {
|
||||||
@@ -42,7 +43,8 @@ function parseConfiguration(configuration) {
|
|||||||
}, {});
|
}, {});
|
||||||
keysToSplit
|
keysToSplit
|
||||||
.filter(key => configValues[key])
|
.filter(key => configValues[key])
|
||||||
.filter(key => configValues[key] = configValues[key].split(',').map(provider => provider.toLowerCase()))
|
.forEach(key => configValues[key] = configValues[key].split(',')
|
||||||
|
.map(value => keyToUppercase.includes(key) ? value.toUpperCase() : value.toLowerCase()))
|
||||||
return configValues;
|
return configValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
const { extractProvider, parseSize, extractSize } = require("./titleHelper");
|
||||||
|
const { Type } = require("./types");
|
||||||
const Providers = {
|
const Providers = {
|
||||||
key: 'providers',
|
key: 'providers',
|
||||||
options: [
|
options: [
|
||||||
@@ -87,7 +89,7 @@ const QualityFilter = {
|
|||||||
key: 'brremux',
|
key: 'brremux',
|
||||||
label: 'BluRay REMUX',
|
label: 'BluRay REMUX',
|
||||||
test(quality, bingeGroup) {
|
test(quality, bingeGroup) {
|
||||||
return bingeGroup && bingeGroup.includes(this.label);
|
return bingeGroup?.includes(this.label);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -95,7 +97,7 @@ const QualityFilter = {
|
|||||||
label: 'HDR/HDR10+/Dolby Vision',
|
label: 'HDR/HDR10+/Dolby Vision',
|
||||||
items: ['HDR', 'HDR10+', 'DV'],
|
items: ['HDR', 'HDR10+', 'DV'],
|
||||||
test(quality) {
|
test(quality) {
|
||||||
const hdrProfiles = quality && quality.split(' ').slice(1).join() || '';
|
const hdrProfiles = quality?.split(' ')?.slice(1)?.join() || '';
|
||||||
return this.items.some(hdrType => hdrProfiles.includes(hdrType));
|
return this.items.some(hdrType => hdrProfiles.includes(hdrType));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -103,7 +105,7 @@ const QualityFilter = {
|
|||||||
key: 'dolbyvision',
|
key: 'dolbyvision',
|
||||||
label: 'Dolby Vision',
|
label: 'Dolby Vision',
|
||||||
test(quality) {
|
test(quality) {
|
||||||
const hdrProfiles = quality && quality.split(' ').slice(1).join() || '';
|
const hdrProfiles = quality?.split(' ')?.slice(1)?.join() || '';
|
||||||
return hdrProfiles === 'DV';
|
return hdrProfiles === 'DV';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -173,20 +175,26 @@ const QualityFilter = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
const SizeFilter = {
|
||||||
|
key: 'sizefilter'
|
||||||
|
}
|
||||||
const defaultProviderKeys = Providers.options.map(provider => provider.key);
|
const defaultProviderKeys = Providers.options.map(provider => provider.key);
|
||||||
|
|
||||||
function applyFilters(streams, config) {
|
function applyFilters(streams, config) {
|
||||||
return filterByQuality(filterByProvider(streams, config), config);
|
return [
|
||||||
|
filterByProvider,
|
||||||
|
filterByQuality,
|
||||||
|
filterBySize
|
||||||
|
].reduce((filteredStreams, filter) => filter(filteredStreams, config), streams);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterByProvider(streams, config) {
|
function filterByProvider(streams, config) {
|
||||||
const providers = config.providers || defaultProviderKeys;
|
const providers = config.providers || defaultProviderKeys;
|
||||||
if (!providers || !providers.length) {
|
if (!providers?.length) {
|
||||||
return streams;
|
return streams;
|
||||||
}
|
}
|
||||||
return streams.filter(stream => {
|
return streams.filter(stream => {
|
||||||
const match = stream.title.match(/⚙.* ([^ \n]+)/);
|
const provider = extractProvider(stream.title)
|
||||||
const provider = match && match[1].toLowerCase();
|
|
||||||
return providers.includes(provider);
|
return providers.includes(provider);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -204,6 +212,19 @@ function filterByQuality(streams, config) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filterBySize(streams, config) {
|
||||||
|
const sizeFilters = config[SizeFilter.key];
|
||||||
|
if (!sizeFilters?.length) {
|
||||||
|
return streams;
|
||||||
|
}
|
||||||
|
const sizeLimit = parseSize(config.type === Type.MOVIE ? sizeFilters.shift() : sizeFilters.pop());
|
||||||
|
return streams.filter(stream => {
|
||||||
|
const size = extractSize(stream.title)
|
||||||
|
return size <= sizeLimit;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = applyFilters;
|
module.exports = applyFilters;
|
||||||
module.exports.Providers = Providers;
|
module.exports.Providers = Providers;
|
||||||
module.exports.QualityFilter = QualityFilter;
|
module.exports.QualityFilter = QualityFilter;
|
||||||
|
module.exports.SizeFilter = SizeFilter;
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ a.install-link {
|
|||||||
const { Providers } = require('./filter');
|
const { Providers } = require('./filter');
|
||||||
const { SortOptions } = require('./sort');
|
const { SortOptions } = require('./sort');
|
||||||
const { LanguageOptions } = require('./languages');
|
const { LanguageOptions } = require('./languages');
|
||||||
const { QualityFilter } = require('./filter');
|
const { QualityFilter, SizeFilter } = require('./filter');
|
||||||
const { DebridOptions } = require('../moch/options');
|
const { DebridOptions } = require('../moch/options');
|
||||||
const { MochOptions } = require('../moch/moch');
|
const { MochOptions } = require('../moch/moch');
|
||||||
const { PreConfigurations } = require('../lib/configuration');
|
const { PreConfigurations } = require('../lib/configuration');
|
||||||
@@ -197,6 +197,7 @@ function landingTemplate(manifest, config = {}) {
|
|||||||
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] || [];
|
||||||
|
const sizeFilter = (config[SizeFilter.key] || []).join(',');
|
||||||
const limit = config.limit || '';
|
const limit = config.limit || '';
|
||||||
|
|
||||||
const debridProvider = Object.keys(MochOptions).find(mochKey => config[mochKey]);
|
const debridProvider = Object.keys(MochOptions).find(mochKey => config[mochKey]);
|
||||||
@@ -295,6 +296,10 @@ function landingTemplate(manifest, config = {}) {
|
|||||||
<label class="label" id="iLimitLabel" for="iLimit">Max results per quality:</label>
|
<label class="label" id="iLimitLabel" for="iLimit">Max results per quality:</label>
|
||||||
<input type="text" inputmode="numeric" pattern="[0-9]*" id="iLimit" onchange="generateInstallLink()" class="input" placeholder="All results">
|
<input type="text" inputmode="numeric" pattern="[0-9]*" id="iLimit" onchange="generateInstallLink()" class="input" placeholder="All results">
|
||||||
|
|
||||||
|
<label class="label" id="iSizeFilterLabel" for="iSizeFilter">Video size limit:</label>
|
||||||
|
<input type="text" pattern="([0-9.]*(?:MB|GB),?)+" id="iSizeFilter" onchange="generateInstallLink()" class="input" placeholder="No limit" title="Returned videos cannot exceed this size, use comma to have different size for movies and series. Examples: 5GB ; 800MB ; 10GB,2GB">
|
||||||
|
|
||||||
|
|
||||||
<label class="label" for="iDebridProviders">Debrid provider:</label>
|
<label class="label" for="iDebridProviders">Debrid provider:</label>
|
||||||
<select id="iDebridProviders" class="input" onchange="debridProvidersChange()">
|
<select id="iDebridProviders" class="input" onchange="debridProvidersChange()">
|
||||||
<option value="none" selected>None</option>
|
<option value="none" selected>None</option>
|
||||||
@@ -396,6 +401,7 @@ function landingTemplate(manifest, config = {}) {
|
|||||||
$('#iPutioToken').val("${putioToken}");
|
$('#iPutioToken').val("${putioToken}");
|
||||||
$('#iSort').val("${sort}");
|
$('#iSort').val("${sort}");
|
||||||
$('#iLimit').val("${limit}");
|
$('#iLimit').val("${limit}");
|
||||||
|
$('#iSizeFilter').val("${sizeFilter}");
|
||||||
generateInstallLink();
|
generateInstallLink();
|
||||||
debridProvidersChange();
|
debridProvidersChange();
|
||||||
});
|
});
|
||||||
@@ -427,6 +433,7 @@ function landingTemplate(manifest, config = {}) {
|
|||||||
const sortValue = $('#iSort').val() || '';
|
const sortValue = $('#iSort').val() || '';
|
||||||
const languagesValue = $('#iLanguages').val().join(',') || [];
|
const languagesValue = $('#iLanguages').val().join(',') || [];
|
||||||
const limitValue = $('#iLimit').val() || '';
|
const limitValue = $('#iLimit').val() || '';
|
||||||
|
const sizeFilterValue = $('#iSizeFilter').val() || '';
|
||||||
|
|
||||||
const debridOptionsValue = $('#iDebridOptions').val().join(',') || '';
|
const debridOptionsValue = $('#iDebridOptions').val().join(',') || '';
|
||||||
const realDebridValue = $('#iRealDebrid').val() || '';
|
const realDebridValue = $('#iRealDebrid').val() || '';
|
||||||
@@ -443,6 +450,7 @@ function landingTemplate(manifest, config = {}) {
|
|||||||
const sort = sortValue !== '${SortOptions.options.qualitySeeders.key}' && sortValue;
|
const sort = sortValue !== '${SortOptions.options.qualitySeeders.key}' && sortValue;
|
||||||
const languages = languagesValue.length && languagesValue;
|
const languages = languagesValue.length && languagesValue;
|
||||||
const limit = /^[1-9][0-9]{0,2}$/.test(limitValue) && limitValue;
|
const limit = /^[1-9][0-9]{0,2}$/.test(limitValue) && limitValue;
|
||||||
|
const sizeFilter = sizeFilterValue.length && sizeFilterValue;
|
||||||
|
|
||||||
const debridOptions = debridOptionsValue.length && debridOptionsValue.trim();
|
const debridOptions = debridOptionsValue.length && debridOptionsValue.trim();
|
||||||
const realDebrid = realDebridValue.length && realDebridValue.trim();
|
const realDebrid = realDebridValue.length && realDebridValue.trim();
|
||||||
@@ -461,6 +469,7 @@ function landingTemplate(manifest, config = {}) {
|
|||||||
['${LanguageOptions.key}', languages],
|
['${LanguageOptions.key}', languages],
|
||||||
['${QualityFilter.key}', qualityFilters],
|
['${QualityFilter.key}', qualityFilters],
|
||||||
['limit', limit],
|
['limit', limit],
|
||||||
|
['${SizeFilter.key}', sizeFilter],
|
||||||
['${DebridOptions.key}', debridOptions],
|
['${DebridOptions.key}', debridOptions],
|
||||||
['${MochOptions.realdebrid.key}', realDebrid],
|
['${MochOptions.realdebrid.key}', realDebrid],
|
||||||
['${MochOptions.premiumize.key}', premiumize],
|
['${MochOptions.premiumize.key}', premiumize],
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const { QualityFilter } = require('./filter');
|
|||||||
const { containsLanguage, LanguageOptions } = require('./languages');
|
const { containsLanguage, LanguageOptions } = require('./languages');
|
||||||
const { Type } = require("./types");
|
const { Type } = require("./types");
|
||||||
const { hasMochConfigured } = require("../moch/moch");
|
const { hasMochConfigured } = require("../moch/moch");
|
||||||
|
const { extractSeeders, extractSize } = require("./titleHelper");
|
||||||
|
|
||||||
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');
|
||||||
@@ -34,7 +35,7 @@ const SortOptions = {
|
|||||||
|
|
||||||
function sortStreams(streams, config, type) {
|
function sortStreams(streams, config, type) {
|
||||||
const languages = config[LanguageOptions.key];
|
const languages = config[LanguageOptions.key];
|
||||||
if (languages && 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
|
||||||
const streamsWithLanguage = streams.filter(stream => containsLanguage(stream, languages));
|
const streamsWithLanguage = streams.filter(stream => containsLanguage(stream, languages));
|
||||||
const streamsNoLanguage = streams.filter(stream => !streamsWithLanguage.includes(stream));
|
const streamsNoLanguage = streams.filter(stream => !streamsWithLanguage.includes(stream));
|
||||||
@@ -44,7 +45,7 @@ function sortStreams(streams, config, type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _sortStreams(streams, config, type) {
|
function _sortStreams(streams, config, type) {
|
||||||
const sort = config.sort && config.sort.toLowerCase() || undefined;
|
const sort = config?.sort?.toLowerCase() || undefined;
|
||||||
const limit = /^[1-9][0-9]*$/.test(config.limit) && parseInt(config.limit) || undefined;
|
const limit = /^[1-9][0-9]*$/.test(config.limit) && parseInt(config.limit) || undefined;
|
||||||
const sortedStreams = sortBySeeders(streams, config, type);
|
const sortedStreams = sortBySeeders(streams, config, type);
|
||||||
if (sort === SortOptions.options.seeders.key) {
|
if (sort === SortOptions.options.seeders.key) {
|
||||||
@@ -93,8 +94,8 @@ function sortByVideoQuality(streams, nestedSort, limit) {
|
|||||||
}, {});
|
}, {});
|
||||||
const sortedQualities = Object.keys(qualityMap)
|
const sortedQualities = Object.keys(qualityMap)
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const aResolution = a && a.match(/\d+p/) && parseInt(a, 10);
|
const aResolution = a?.match(/\d+p/) && parseInt(a, 10);
|
||||||
const bResolution = b && b.match(/\d+p/) && parseInt(b, 10);
|
const bResolution = b?.match(/\d+p/) && parseInt(b, 10);
|
||||||
if (aResolution && bResolution) {
|
if (aResolution && bResolution) {
|
||||||
return bResolution - aResolution; // higher resolution first;
|
return bResolution - aResolution; // higher resolution first;
|
||||||
} else if (aResolution) {
|
} else if (aResolution) {
|
||||||
@@ -111,7 +112,7 @@ function sortByVideoQuality(streams, nestedSort, limit) {
|
|||||||
|
|
||||||
function extractQuality(title) {
|
function extractQuality(title) {
|
||||||
const qualityDesc = title.split('\n')[1];
|
const qualityDesc = title.split('\n')[1];
|
||||||
const resolutionMatch = qualityDesc && qualityDesc.match(/\d+p/);
|
const resolutionMatch = qualityDesc?.match(/\d+p/);
|
||||||
if (resolutionMatch) {
|
if (resolutionMatch) {
|
||||||
return resolutionMatch[0];
|
return resolutionMatch[0];
|
||||||
} else if (/8k/i.test(qualityDesc)) {
|
} else if (/8k/i.test(qualityDesc)) {
|
||||||
@@ -126,32 +127,5 @@ function extractQuality(title) {
|
|||||||
return qualityDesc;
|
return qualityDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractSeeders(title) {
|
|
||||||
const seedersMatch = title.match(/👤 (\d+)/);
|
|
||||||
return seedersMatch && parseInt(seedersMatch[1]) || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractSize(title) {
|
|
||||||
const seedersMatch = title.match(/💾 ([\d.]+ \w+)/);
|
|
||||||
return seedersMatch && parseSize(seedersMatch[1]) || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseSize(sizeText) {
|
|
||||||
if (!sizeText) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
let scale = 1;
|
|
||||||
if (sizeText.includes('TB')) {
|
|
||||||
scale = 1024 * 1024 * 1024 * 1024
|
|
||||||
} else if (sizeText.includes('GB')) {
|
|
||||||
scale = 1024 * 1024 * 1024
|
|
||||||
} else if (sizeText.includes('MB')) {
|
|
||||||
scale = 1024 * 1024;
|
|
||||||
} else if (sizeText.includes('kB')) {
|
|
||||||
scale = 1024;
|
|
||||||
}
|
|
||||||
return Math.floor(parseFloat(sizeText.replace(/,/g, '')) * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = sortStreams;
|
module.exports = sortStreams;
|
||||||
module.exports.SortOptions = SortOptions;
|
module.exports.SortOptions = SortOptions;
|
||||||
33
addon/lib/titleHelper.js
Normal file
33
addon/lib/titleHelper.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
function extractSeeders(title) {
|
||||||
|
const seedersMatch = title.match(/👤 (\d+)/);
|
||||||
|
return seedersMatch && parseInt(seedersMatch[1]) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractSize(title) {
|
||||||
|
const seedersMatch = title.match(/💾 ([\d.]+ \w+)/);
|
||||||
|
return seedersMatch && parseSize(seedersMatch[1]) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractProvider(title) {
|
||||||
|
const match = title.match(/⚙.* ([^ \n]+)/);
|
||||||
|
return match?.[1]?.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseSize(sizeText) {
|
||||||
|
if (!sizeText) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let scale = 1;
|
||||||
|
if (sizeText.includes('TB')) {
|
||||||
|
scale = 1024 * 1024 * 1024 * 1024
|
||||||
|
} else if (sizeText.includes('GB')) {
|
||||||
|
scale = 1024 * 1024 * 1024
|
||||||
|
} else if (sizeText.includes('MB')) {
|
||||||
|
scale = 1024 * 1024;
|
||||||
|
} else if (sizeText.includes('kB')) {
|
||||||
|
scale = 1024;
|
||||||
|
}
|
||||||
|
return Math.floor(parseFloat(sizeText.replace(/,/g, '')) * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { extractSeeders, extractSize, extractProvider, parseSize }
|
||||||
@@ -39,7 +39,7 @@ router.get('/:configuration/:resource/:type/:id/:extra?.json', (req, res, next)
|
|||||||
const extra = req.params.extra ? qs.parse(req.url.split('/').pop().slice(0, -5)) : {}
|
const extra = req.params.extra ? qs.parse(req.url.split('/').pop().slice(0, -5)) : {}
|
||||||
const ip = requestIp.getClientIp(req);
|
const ip = requestIp.getClientIp(req);
|
||||||
const host = `${req.protocol}://${req.headers.host}`;
|
const host = `${req.protocol}://${req.headers.host}`;
|
||||||
const configValues = { ...extra, ...parseConfiguration(configuration), ip, host };
|
const configValues = { ...extra, ...parseConfiguration(configuration), id, type, ip, host };
|
||||||
addonInterface.get(resource, type, id, configValues)
|
addonInterface.get(resource, type, id, configValues)
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
const cacheHeaders = {
|
const cacheHeaders = {
|
||||||
|
|||||||
Reference in New Issue
Block a user