showai / index.js
mikmc's picture
Update index.js
ed2e9a7 verified
const express = require('express');
const { addonBuilder, getRouter } = require('stremio-addon-sdk');
const cors = require('cors');
const fs = require('fs');
const path = require('path');
const manifest = {
id: 'hy.yourtvshows.org',
version: '1.0.0',
name: 'TV Club',
description: 'Stream TV series categorized by genre with search capability',
resources: ['catalog', 'stream', 'meta'],
types: ['series'],
idPrefixes: ['tt'],
catalogs: [
{
id: 'main-catalog',
type: 'series',
name: 'All Series',
extra: [
{ name: 'genre', options: [] },
{ name: 'search', isRequired: false }
]
}
]
};
const builder = new addonBuilder(manifest);
// Function to read JSON files
function readJSONFile(filename) {
const filePath = path.join(__dirname, filename);
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
}
// Load and parse series data files
const seriesDataFiles = fs.readdirSync(__dirname)
.filter(file => file.endsWith('_series_data.json'));
console.log("Found series data files:", seriesDataFiles);
// Store catalogs and metadata
const catalogs = [];
const metaData = {};
// Process each series data file dynamically
seriesDataFiles.forEach(filename => {
const data = readJSONFile(filename);
const catalogType = 'series'; // Assuming 'series' for all catalogs
// Add categories to genre options in manifest
Object.keys(data).forEach(category => {
if (!manifest.catalogs[0].extra[0].options.includes(category)) {
manifest.catalogs[0].extra[0].options.push(category);
}
});
// Process each category in the file
Object.entries(data).forEach(([category, seriesList]) => {
// Add series metadata for each series in the category
seriesList.forEach(series => {
const seriesMeta = {
id: series.id,
type: catalogType,
name: series.name,
genres: [category],
poster: series.poster || null
};
// Store metadata and catalog information
metaData[series.id] = {
...seriesMeta,
seasons: series.seasons.map(season => ({
season: season.season,
episodes: season.episodes.map(ep => ({
episode: ep.episode,
stream_url: ep.stream_url
}))
}))
};
catalogs.push({
category,
meta: seriesMeta
});
});
});
});
// Catalog handler to list series by genre and enable search
builder.defineCatalogHandler(({ type, extra }) => {
return new Promise((resolve) => {
if (type === 'series') {
const genre = extra.genre;
const searchQuery = extra.search ? extra.search.toLowerCase() : null;
let seriesCatalog = catalogs
.filter(catalog => !genre || catalog.category === genre) // Filter by genre if provided
.map(catalog => catalog.meta);
// Filter by search query if provided
if (searchQuery) {
seriesCatalog = seriesCatalog.filter(meta =>
meta.name.toLowerCase().includes(searchQuery)
);
}
resolve({ metas: seriesCatalog });
} else {
resolve({ metas: [] });
}
});
});
// Meta handler to get details of a specific series
builder.defineMetaHandler(({ id }) => {
return new Promise((resolve) => {
const seriesMeta = metaData[id];
if (seriesMeta) {
resolve({
meta: {
id: seriesMeta.id,
type: 'series',
name: seriesMeta.name,
poster: seriesMeta.poster,
genres: seriesMeta.genres,
seasons: seriesMeta.seasons.map(season => ({
number: season.season,
episodes: season.episodes.map(ep => ({
id: `${seriesMeta.id}:${season.season}:${ep.episode}`,
title: `Episode ${ep.episode}`,
season: season.season,
number: ep.episode
}))
}))
}
});
} else {
resolve({});
}
});
});
// Stream handler to fetch specific episode streams
builder.defineStreamHandler(({ type, id }) => {
return new Promise((resolve) => {
if (type === 'series') {
const [seriesId, seasonNumber, episodeNumber] = id.split(':');
const seriesMeta = metaData[seriesId];
if (seriesMeta) {
const season = seriesMeta.seasons.find(s => s.season == seasonNumber);
if (season) {
const episode = season.episodes.find(e => e.episode == episodeNumber);
if (episode) {
resolve({
streams: [{
title: `${seriesMeta.name} S${seasonNumber}E${episodeNumber}`,
url: episode.stream_url
}]
});
return;
}
}
}
}
resolve({ streams: [] });
});
});
const addonInterface = builder.getInterface();
const app = express();
app.use(cors());
app.use('/', getRouter(addonInterface));
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something went wrong!');
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`TV Club Stremio Addon running on port ${PORT}`);
});