no1b4me's picture
Upload 5037 files
95f4e64 verified
const Router = require('router')
const qs = require('querystring')
const cors = require('cors')
function getRouter({ manifest , get }) {
const router = new Router()
// CORS is mandatory for the addon protocol
router.use(cors())
// Serve the manifest
const manifestBuf = JSON.stringify(manifest)
function manifestHandler(req, res) {
const { config } = req.params
let manifestRespBuf = manifestBuf
if (config && manifest.behaviorHints && (manifest.behaviorHints.configurationRequired || manifest.behaviorHints.configurable)) {
const manifestClone = JSON.parse(manifestBuf)
// we remove configurationRequired so the addon is installable after configuration
delete manifestClone.behaviorHints.configurationRequired
// we remove configuration page for installed addon too (could be added later to the router)
delete manifestClone.behaviorHints.configurable
manifestRespBuf = JSON.stringify(manifestClone)
}
res.setHeader('Content-Type', 'application/json; charset=utf-8')
res.end(manifestRespBuf)
}
const hasConfig = (manifest.config || []).length
if (hasConfig && !(manifest.behaviorHints || {}).configurable) {
console.warn('manifest.config is set but manifest.behaviorHints.configurable is disabled, the "Configure" button will not show in the Stremio apps')
}
const configPrefix = hasConfig ? '/:config?' : ''
// having config prifix always set to '/:config?' won't resault in a problem for non configurable addons,
// since now the order is restricted by resources.
router.get(`${configPrefix}/manifest.json`, manifestHandler)
// using the same methode used in builder.js to extract resources from manifest
const handlersInManifest = []
if (manifest.catalogs.length > 0) handlersInManifest.push('catalog')
manifest.resources.forEach((r) => handlersInManifest.push(r.name || r))
// converting the resources array to a regular expression
const ResourcesRegex = handlersInManifest && handlersInManifest.length ? '(' + handlersInManifest.join('|') + ')' : ''
// Handle all resources
router.get(`${configPrefix}/:resource${ResourcesRegex}/:type/:id/:extra?.json`, function(req, res, next) {
const { resource, type, id } = req.params
let { config } = req.params
// we get `extra` from `req.url` because `req.params.extra` decodes the characters
// and breaks dividing querystring parameters with `&`, in case `&` is one of the
// encoded characters of a parameter value
const extra = req.params.extra ? qs.parse(req.url.split('/').pop().slice(0, -5)) : {}
if ((config || '').length) {
try {
config = JSON.parse(config)
} catch(e) {
config = false
}
}
res.setHeader('Content-Type', 'application/json; charset=utf-8')
get(resource, type, id, extra, config, req)
.then(resp => {
let cacheHeaders = {
cacheMaxAge: 'max-age',
staleRevalidate: 'stale-while-revalidate',
staleError: 'stale-if-error'
}
const cacheControl = Object.keys(cacheHeaders).map(prop => {
const cacheProp = cacheHeaders[prop]
const cacheValue = resp[prop]
if (!Number.isInteger(cacheValue)) return false
if (cacheValue > 365 * 24 * 60 * 60)
console.warn(`${prop} set to more then 1 year, be advised that cache times are in seconds, not milliseconds.`)
return cacheProp + '=' + cacheValue
}).filter(val => !!val).join(', ')
if (cacheControl)
res.setHeader('Cache-Control', `${cacheControl}, public`)
if (resp.redirect) {
res.redirect(307, resp.redirect)
return
}
res.setHeader('Content-Type', 'application/json; charset=utf-8')
res.end(JSON.stringify(resp))
})
.catch(err => {
if (err.noHandler) {
if (next) next()
else {
res.writeHead(404)
res.end(JSON.stringify({ err: 'not found' }))
}
} else {
console.error(err)
res.writeHead(500)
res.end(JSON.stringify({ err: 'handler error' }))
}
})
})
return router
}
module.exports = getRouter