File size: 5,949 Bytes
ed2e9a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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}`);
});