mirror of
https://github.com/knightcrawler-stremio/knightcrawler.git
synced 2024-12-20 03:29:51 +00:00
[addon] adds custom landing page for addon configuration
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
const { addonBuilder } = require('stremio-addon-sdk');
|
||||
const titleParser = require('parse-torrent-title');
|
||||
const { manifest } = require('./lib/manifest');
|
||||
const { toStreamInfo } = require('./lib/streamInfo');
|
||||
const { cacheWrapStream } = require('./lib/cache');
|
||||
const repository = require('./lib/repository');
|
||||
@@ -9,19 +10,7 @@ const CACHE_MAX_AGE_EMPTY = 30 * 60; // 30 minutes
|
||||
const STALE_REVALIDATE_AGE = 4 * 60 * 60; // 4 hours
|
||||
const STALE_ERROR_AGE = 7 * 24 * 60 * 60; // 7 days
|
||||
|
||||
const builder = new addonBuilder({
|
||||
id: 'com.stremio.torrentio.addon',
|
||||
version: '1.0.0',
|
||||
name: 'Torrentio',
|
||||
description: 'Provides torrent stream from scraped torrent providers. '
|
||||
+ 'Currently supports ThePirateBay, 1337x, RARBG, KickassTorrents, HorribleSubs.',
|
||||
catalogs: [],
|
||||
resources: ['stream'],
|
||||
types: ['movie', 'series'],
|
||||
idPrefixes: ['tt', 'kitsu'],
|
||||
background: `https://i.imgur.com/t8wVwcg.jpg`,
|
||||
logo: `https://i.imgur.com/GwxAcDV.png`,
|
||||
});
|
||||
const builder = new addonBuilder(manifest());
|
||||
|
||||
builder.defineStreamHandler((args) => {
|
||||
if (!args.id.match(/tt\d+/i) && !args.id.match(/kitsu:\d+/i)) {
|
||||
|
||||
16
addon/lib/configuration.js
Normal file
16
addon/lib/configuration.js
Normal file
@@ -0,0 +1,16 @@
|
||||
function parseConfiguration(configuration) {
|
||||
const configValues = configuration.split('|')
|
||||
.reduce((map, next) => {
|
||||
const parameterParts = next.split('=');
|
||||
if (parameterParts.length === 2) {
|
||||
map[parameterParts[0].toLowerCase()] = parameterParts[1];
|
||||
}
|
||||
return map;
|
||||
}, {});
|
||||
if (configValues.providers) {
|
||||
configValues.providers = configValues.providers.split(',').map(provider => provider.toLowerCase());
|
||||
}
|
||||
return configValues;
|
||||
}
|
||||
|
||||
module.exports = parseConfiguration;
|
||||
268
addon/lib/landingTemplate.js
Normal file
268
addon/lib/landingTemplate.js
Normal file
@@ -0,0 +1,268 @@
|
||||
const STYLESHEET = `
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%
|
||||
}
|
||||
|
||||
html {
|
||||
background-size: auto 100%;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
background: rgba(0, 0, 0, 0.60);
|
||||
font-family: 'Open Sans', Arial, sans-serif;
|
||||
color: white;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 4.5vh;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2.2vh;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 2.2vh;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
p,
|
||||
label {
|
||||
margin: 0;
|
||||
text-shadow: 0 0 1vh rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.75vh;
|
||||
}
|
||||
|
||||
ul {
|
||||
font-size: 1.75vh;
|
||||
margin: 0;
|
||||
margin-top: 1vh;
|
||||
padding-left: 3vh;
|
||||
}
|
||||
|
||||
a {
|
||||
color: white
|
||||
}
|
||||
|
||||
a.install-link {
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
button {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
color: white;
|
||||
background: #8A5AAB;
|
||||
padding: 1.2vh 3.5vh;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
font-family: 'Open Sans', Arial, sans-serif;
|
||||
font-size: 2.2vh;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
box-shadow: 0 0.5vh 1vh rgba(0, 0, 0, 0.2);
|
||||
transition: box-shadow 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
button:active {
|
||||
box-shadow: 0 0 0 0.5vh white inset;
|
||||
}
|
||||
|
||||
#addon {
|
||||
width: 40vh;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 14vh;
|
||||
width: 14vh;
|
||||
margin: auto;
|
||||
margin-bottom: 3vh;
|
||||
}
|
||||
|
||||
.logo img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.name, .version {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.name {
|
||||
line-height: 5vh;
|
||||
}
|
||||
|
||||
.version {
|
||||
position: absolute;
|
||||
line-height: 5vh;
|
||||
margin-left: 1vh;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.contact {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 4vh;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.contact a {
|
||||
font-size: 1.4vh;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.separator {
|
||||
margin-bottom: 4vh;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 2.2vh;
|
||||
font-weight: 600;
|
||||
padding: 0;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.btn-group, .multiselect-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.multiselect-container {
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.input, .btn {
|
||||
height: 3.5vh;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
padding: 6px 12px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
outline: 0;
|
||||
color: #333;
|
||||
box-shadow: 0 0.5vh 1vh rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
`;
|
||||
const { Providers } = require('./manifest');
|
||||
|
||||
function landingTemplate(manifest, providers = [], realDebridApiKey = '') {
|
||||
console.log(providers);
|
||||
console.log(realDebridApiKey);
|
||||
const background = manifest.background || 'https://dl.strem.io/addon-background.jpg';
|
||||
const logo = manifest.logo || 'https://dl.strem.io/addon-logo.png';
|
||||
const contactHTML = manifest.contactEmail ?
|
||||
`<div class="contact">
|
||||
<p>Contact ${manifest.name} creator:</p>
|
||||
<a href="mailto:${manifest.contactEmail}">${manifest.contactEmail}</a>
|
||||
</div>` : '';
|
||||
const providersHTML = Providers
|
||||
.map(provider => `<option value="${provider.toLowerCase()}">${provider}</option>`)
|
||||
.join('\n');
|
||||
const stylizedTypes = manifest.types
|
||||
.map(t => t[0].toUpperCase() + t.slice(1) + (t !== 'series' ? 's' : ''));
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html style="background-image: url(${background});">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>${manifest.name} - Stremio Addon</title>
|
||||
<link rel="shortcut icon" href="${logo}" type="image/x-icon">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,700&display=swap" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
||||
<script src="https://davidstutz.de/bootstrap-multiselect/docs/js/bootstrap-3.3.2.min.js"></script>
|
||||
<link href="https://davidstutz.de/bootstrap-multiselect/docs/css/bootstrap-3.3.2.min.css" rel="stylesheet"/>
|
||||
<script src="https://davidstutz.de/bootstrap-multiselect/dist/js/bootstrap-multiselect.js"></script>
|
||||
<link href="https://davidstutz.de/bootstrap-multiselect/dist/css/bootstrap-multiselect.css" rel="stylesheet"/>
|
||||
<style>${STYLESHEET}</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="addon">
|
||||
<div class="logo">
|
||||
<img src="${logo}">
|
||||
</div>
|
||||
<h1 class="name">${manifest.name}</h1>
|
||||
<h2 class="version">${manifest.version || '0.0.0'}</h2>
|
||||
<h2 class="description">${manifest.description || ''}</h2>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<h3 class="gives">This addon has more :</h3>
|
||||
<ul>
|
||||
${stylizedTypes.map(t => `<li>${t}</li>`).join('')}
|
||||
</ul>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<label class="label" for="iProviders">Providers:</label>
|
||||
<select id="iProviders" class="input" name="providers[]" multiple="multiple">
|
||||
${providersHTML}
|
||||
</select>
|
||||
|
||||
<label class="label" for="iRealDebrid">RealDebrid API Key:</label>
|
||||
<input type="text" id="iRealDebrid" onchange="generateInstallLink()" class="input">
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<a id="installLink" class="install-link" href="#">
|
||||
<button name="Install">INSTALL</button>
|
||||
</a>
|
||||
${contactHTML}
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('#iProviders').multiselect({
|
||||
nonSelectedText: 'All providers',
|
||||
onChange: () => generateInstallLink()
|
||||
});
|
||||
$('#iProviders').multiselect('select', [${providers.map(provider => '"' + provider + '"')}]);
|
||||
$('#iRealDebrid').val("${realDebridApiKey}");
|
||||
generateInstallLink();
|
||||
});
|
||||
|
||||
function generateInstallLink() {
|
||||
const providersValue = $('#iProviders').val().join(',');
|
||||
const realDebridValue = $('#iRealDebrid').val();
|
||||
const providers = providersValue && providersValue.length ? 'providers=' + providersValue : '';
|
||||
const realDebrid = realDebridValue && realDebridValue.length ? 'realrebrid='+realDebridValue : '';
|
||||
const configurationValue = [providers, realDebrid].filter(value => value.length).join('|');
|
||||
const configuration = configurationValue && configurationValue.length ? '/' + configurationValue : '';
|
||||
installLink.href = 'stremio://' + window.location.host + configuration + '/manifest.json';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>`
|
||||
}
|
||||
|
||||
module.exports = landingTemplate;
|
||||
33
addon/lib/manifest.js
Normal file
33
addon/lib/manifest.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const Providers = [
|
||||
'ThePirateBay',
|
||||
'RARBG',
|
||||
'1337x',
|
||||
'KickassTorrents',
|
||||
'HorribleSubs'
|
||||
];
|
||||
|
||||
function manifest(providers, realDebridApiKey) {
|
||||
const providersList = Array.isArray(providers) && providers.map(provider => getProvider(provider)) || Providers;
|
||||
const providersDesc = providers && providers.length ? 'Enabled providers -' : 'Currently supports';
|
||||
const realDebridDesc = realDebridApiKey ? ' and RealdDebrid enabled' : '';
|
||||
return {
|
||||
id: 'com.stremio.torrentio.addon',
|
||||
version: '0.0.1-beta',
|
||||
name: 'Torrentio',
|
||||
description: '[BETA] Provides torrent streams from scraped torrent providers.'
|
||||
+ ` ${providersDesc} ${providersList.join(', ')}${realDebridDesc}.`
|
||||
+ ' To configure visit www.torrentio.now.sh',
|
||||
catalogs: [],
|
||||
resources: ['stream'],
|
||||
types: ['movie', 'series'],
|
||||
idPrefixes: ['tt', 'kitsu'],
|
||||
background: `https://i.ibb.co/VtSfFP9/t8wVwcg.jpg`,
|
||||
logo: `https://i.ibb.co/w4BnkC9/GwxAcDV.png`,
|
||||
}
|
||||
}
|
||||
|
||||
function getProvider(configProvider) {
|
||||
return Providers.find(provider => provider.toLowerCase() === configProvider);
|
||||
}
|
||||
|
||||
module.exports = { manifest, Providers };
|
||||
4
addon/package-lock.json
generated
4
addon/package-lock.json
generated
@@ -1363,8 +1363,8 @@
|
||||
}
|
||||
},
|
||||
"parse-torrent-title": {
|
||||
"version": "git://github.com/TheBeastLT/parse-torrent-title.git#90c60ab3edab3a40843160ba1bdf4995c4b5cc56",
|
||||
"from": "git://github.com/TheBeastLT/parse-torrent-title.git#master",
|
||||
"version": "git://github.com/TheBeastLT/parse-torrent-title.git#7c00602bc1c405f5574758eeabb72b133fea81d5",
|
||||
"from": "git://github.com/TheBeastLT/parse-torrent-title.git#7c00602bc1c405f5574758eeabb72b133fea81d5",
|
||||
"requires": {
|
||||
"moment": "^2.24.0"
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"cache-manager": "^2.9.0",
|
||||
"cache-manager-mongodb": "^0.2.1",
|
||||
"express-rate-limit": "^5.1.1",
|
||||
"parse-torrent-title": "git://github.com/TheBeastLT/parse-torrent-title.git#master",
|
||||
"parse-torrent-title": "git://github.com/TheBeastLT/parse-torrent-title.git#7c00602bc1c405f5574758eeabb72b133fea81d5",
|
||||
"pg": "^7.8.2",
|
||||
"pg-hstore": "^2.3.2",
|
||||
"sequelize": "^4.43.0",
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
const rateLimit = require('express-rate-limit');
|
||||
const { getRouter } = require('stremio-addon-sdk');
|
||||
const landingTemplate = require('stremio-addon-sdk/src/landingTemplate');
|
||||
const addonInterface = require('./addon');
|
||||
const { manifest } = require('./lib/manifest');
|
||||
const parseConfiguration = require('./lib/configuration');
|
||||
const landingTemplate = require('./lib/landingTemplate');
|
||||
const router = getRouter(addonInterface);
|
||||
|
||||
const limiter = rateLimit({
|
||||
@@ -13,11 +15,26 @@ const limiter = rateLimit({
|
||||
router.use(limiter);
|
||||
|
||||
router.get('/', (_, res) => {
|
||||
const landingHTML = landingTemplate(addonInterface.manifest);
|
||||
const landingHTML = landingTemplate(manifest());
|
||||
res.setHeader('content-type', 'text/html');
|
||||
res.end(landingHTML);
|
||||
});
|
||||
|
||||
router.get('/:configuration', (req, res) => {
|
||||
const configValues = parseConfiguration(req.params.configuration);
|
||||
console.log(configValues);
|
||||
const landingHTML = landingTemplate(manifest(), configValues.providers, configValues.realdebrid);
|
||||
res.setHeader('content-type', 'text/html');
|
||||
res.end(landingHTML);
|
||||
});
|
||||
|
||||
router.get('/:configuration/manifest.json', (req, res) => {
|
||||
const configValues = parseConfiguration(req.params.configuration);
|
||||
const manifestBuf = JSON.stringify(manifest(configValues.providers, configValues.realdebrid));
|
||||
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
||||
res.end(manifestBuf)
|
||||
});
|
||||
|
||||
module.exports = function (req, res) {
|
||||
router(req, res, function () {
|
||||
res.statusCode = 404;
|
||||
|
||||
Reference in New Issue
Block a user