Spaces:
Paused
Paused
| const express = require("express"); | |
| const path = require("path"); // Import path module for path handling | |
| const app = express(); | |
| const config = require('./config'); | |
| const MANIFEST = require('./manifest'); | |
| const { getManifest, getCatalog, getMeta, getUserData } = require("./addon"); | |
| const { createXtreamModule } = require("./xtream-module"); | |
| const NodeCache = require("node-cache"); | |
| const myCache = new NodeCache({ stdTTL: 200 }); | |
| // Middleware to allow CORS and set response headers | |
| var respond = function (res, data) { | |
| res.setHeader('Access-Control-Allow-Origin', '*'); | |
| res.setHeader('Access-Control-Allow-Headers', '*'); | |
| res.setHeader('Content-Type', 'application/json'); | |
| res.send(data); | |
| }; | |
| // Serve static files from the 'assets' directory | |
| app.use('/assets', express.static(path.join(__dirname, 'assets'))); | |
| app.engine('html', require('ejs').renderFile); | |
| app.set('views', path.join(__dirname, 'views')); | |
| app.get("/", function (req, res) { | |
| res.redirect("/configure"); | |
| }); | |
| app.get("/:userConf?/configure", function (req, res) { | |
| const newManifest = { ...{ MANIFEST } }; | |
| res.render('configure.html', newManifest); | |
| }); | |
| app.get('/manifest.json', function (req, res) { | |
| const newManifest = { ...MANIFEST }; | |
| newManifest.behaviorHints.configurationRequired = true; | |
| respond(res, newManifest); | |
| }); | |
| app.get('/:userConf/manifest.json', async function (req, res) { | |
| let newManifest = { ...MANIFEST }; | |
| if (!((req || {}).params || {}).userConf) { | |
| newManifest.behaviorHints.configurationRequired = true; | |
| respond(res, newManifest); | |
| } else { | |
| try { | |
| if (myCache.has(`manifest-${req.params.userConf}`)) { | |
| respond(res, myCache.get(`manifest-${req.params.userConf}`)); | |
| } else { | |
| newManifest = await getManifest(req.params.userConf); | |
| if (newManifest && newManifest.id) { | |
| myCache.set(`manifest-${req.params.userConf}`, newManifest); | |
| } | |
| respond(res, newManifest); | |
| } | |
| } catch (error) { | |
| console.log(error); | |
| respond(res, { error: error }); | |
| } | |
| } | |
| }); | |
| app.get('/:userConf/catalog/:type/:id/:extra?.json', async function (req, res) { | |
| let { userConf, type, id, extra } = req.params; | |
| let extraObj; | |
| if (extra) { | |
| try { | |
| extraObj = JSON.parse('{"' + decodeURI(extra.replace(/&/g, '","').replace(/=/g, '":"')) + '"}'); | |
| } catch (error) { | |
| console.log(error); | |
| return respond(res, { metas: [] }); | |
| } | |
| } | |
| if (extraObj && extraObj.genre && extraObj.genre.includes("+")) { | |
| extraObj.genre = extraObj.genre.replace(/\+/g, ' '); | |
| } | |
| let metas = []; | |
| try { | |
| if (myCache.has(`catalog-${userConf}-${type}-${id}-${extra}`)) { | |
| respond(res, myCache.get(`catalog-${userConf}-${type}-${id}-${extra}`)); | |
| } else { | |
| metas = await getCatalog(userConf, type, extraObj.genre); | |
| if (metas.length > 0) { | |
| myCache.set(`catalog-${userConf}-${type}-${id}-${extra}`, { metas: metas }); | |
| } | |
| respond(res, { metas: metas }); | |
| } | |
| } catch (error) { | |
| console.log(error); | |
| respond(res, { metas: [] }); | |
| } | |
| }); | |
| app.get('/:userConf/meta/:type/:id.json', async function (req, res) { | |
| let { userConf, type, id } = req.params; | |
| try { | |
| if (myCache.has(`meta-${userConf}-${type}-${id}`)) { | |
| respond(res, myCache.get(`meta-${userConf}-${type}-${id}`)); | |
| } else { | |
| const meta = await getMeta(userConf, type, id); | |
| if (meta && meta.id) { | |
| myCache.set(`meta-${userConf}-${type}-${id}`, { meta: meta }); | |
| } | |
| respond(res, { meta: meta }); | |
| } | |
| } catch (error) { | |
| console.log(error); | |
| respond(res, { error }); | |
| } | |
| }); | |
| app.get('/:userConf/stream/:type/:id.json', async function (req, res) { | |
| let { userConf, type, id } = req.params; | |
| const obj = getUserData(userConf); | |
| if (id.startsWith('tt')) { | |
| // Handle IMDb IDs using the Xtream module | |
| const xtreamModule = createXtreamModule(obj.baseURL, obj.username, obj.password); | |
| try { | |
| const xtreamResponse = await xtreamModule(id); | |
| if (xtreamResponse && xtreamResponse.contentUrl) { | |
| console.log('Stream URL for IMDb ID:', xtreamResponse.contentUrl); | |
| respond(res, { streams: [{ url: xtreamResponse.contentUrl, name: xtreamResponse.title }] }); | |
| } else { | |
| console.log('No stream found for IMDb ID:', id); | |
| respond(res, { streams: [] }); | |
| } | |
| } catch (error) { | |
| console.error('Xtream module error:', error); | |
| respond(res, { streams: [] }); | |
| } | |
| } else { | |
| // Existing logic for non-IMDb IDs | |
| let extension = "mp4"; | |
| const streamID = id.split(":")[1]; | |
| let stream = []; | |
| if (type === "tv") { | |
| type = "live"; | |
| extension = "ts"; | |
| const url = `${obj.baseURL}/${type}/${obj.username}/${obj.password}/${streamID}.${extension}`; | |
| console.log('Stream URL for TV:', url); | |
| stream = [{ | |
| url: url, | |
| name: "Watch Now", | |
| behaviorHints: { | |
| notWebReady: true | |
| } | |
| }]; | |
| } else { | |
| const url = `${obj.baseURL}/${type}/${obj.username}/${obj.password}/${streamID}.${extension}`; | |
| console.log('Stream URL for VOD:', url); | |
| stream = [{ | |
| url: url, | |
| name: "Watch Now" | |
| }]; | |
| } | |
| respond(res, { streams: stream }); | |
| } | |
| }); | |
| // Listen for incoming requests | |
| // Listen for incoming requests | |
| if (module.parent) { | |
| module.exports = app; | |
| } else { | |
| // Bind to 0.0.0.0 and use the configured port | |
| app.listen(config.port, '0.0.0.0', function () { | |
| console.log(`Server started: ${config.addon}`); | |
| console.log(`Listening on: ${config.local} (${config.port})`); | |
| }); | |
| } | |