Spaces:
Paused
Paused
Upload 9 files
Browse files- episodes.js +90 -46
- main.js +53 -70
- manifest.json +1 -1
- package-lock.json +0 -0
- package.json +27 -22
- rama_series.js +31 -34
- streams.js +71 -58
episodes.js
CHANGED
|
@@ -1,55 +1,95 @@
|
|
| 1 |
-
import axios from 'axios';
|
| 2 |
import cloudscraper from 'cloudscraper';
|
| 3 |
import * as cheerio from 'cheerio';
|
| 4 |
-
import { getStream, getEpisodes } from './streams.js';
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
// Lista di User-Agent
|
| 7 |
const userAgents = [
|
| 8 |
-
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
| 9 |
-
'Mozilla/5.0 (Windows NT 10.0;
|
| 10 |
-
'Mozilla/5.0 (Macintosh; Intel Mac OS X
|
|
|
|
| 11 |
];
|
| 12 |
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
'Accept-Language': 'en-US,en;q=0.9'
|
| 20 |
-
};
|
| 21 |
}
|
| 22 |
|
| 23 |
-
|
| 24 |
-
const
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
//
|
| 29 |
-
|
|
|
|
| 30 |
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
}
|
|
|
|
|
|
|
| 42 |
}
|
| 43 |
|
|
|
|
| 44 |
async function getMeta(id) {
|
| 45 |
const meta = { id, type: 'series', name: '', poster: '', episodes: [] };
|
| 46 |
-
const cleanId = id.replace(/,/g, '
|
| 47 |
const baseId = cleanId.replace(/-\d{4}$/, '');
|
| 48 |
const seriesLink = `https://ramaorientalfansub.tv/drama/${baseId}/`;
|
| 49 |
-
|
| 50 |
if (metaCache.has(id)) {
|
| 51 |
-
|
| 52 |
-
return { meta: metaCache.get(id) }; // Restituisci direttamente i metadati dalla cache
|
| 53 |
}
|
| 54 |
|
| 55 |
try {
|
|
@@ -60,28 +100,32 @@ async function getMeta(id) {
|
|
| 60 |
}
|
| 61 |
|
| 62 |
const $ = cheerio.load(data);
|
| 63 |
-
// Carica i metadati (name, poster, description)
|
| 64 |
meta.name = $('a.text-accent').text().trim();
|
| 65 |
meta.poster = $('img.wp-post-image').attr('src');
|
| 66 |
-
let description = $('div.font-light > div:nth-child(1)').text().trim();
|
| 67 |
-
// Aggiungi il tag alla descrizione se presente
|
| 68 |
if (meta.extra && meta.extra.tag) {
|
| 69 |
description += ` [${meta.extra.tag.toUpperCase()}]`;
|
| 70 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
-
meta.description = description; // Assegna la descrizione modificata a meta.description
|
| 73 |
-
// Carica gli episodi
|
| 74 |
-
meta.episodes = await getEpisodes(seriesLink, $); // Passa l'oggetto cheerio
|
| 75 |
-
console.log('Episodi trovati:', meta.episodes);
|
| 76 |
-
// Salva i metadati nella cache (CON gli episodi)
|
| 77 |
metaCache.set(id, meta);
|
| 78 |
-
console.log(`Metadati salvati nella cache per ${id}`);
|
| 79 |
} catch (error) {
|
| 80 |
console.error('Errore nel caricamento dei dettagli della serie:', error);
|
| 81 |
}
|
| 82 |
|
| 83 |
-
console.log('Meta finale:', meta);
|
| 84 |
return { meta };
|
| 85 |
}
|
| 86 |
|
| 87 |
-
|
|
|
|
|
|
|
|
|
| 1 |
import cloudscraper from 'cloudscraper';
|
| 2 |
import * as cheerio from 'cheerio';
|
| 3 |
+
import { getStream, getEpisodes } from './streams.js';
|
| 4 |
+
|
| 5 |
+
const DEBUG_MODE = process.env.DEBUG === 'true';
|
| 6 |
+
const CLOUDFLARE_RETRIES = process.env.CLOUDFLARE_RETRIES || 3;
|
| 7 |
+
const META_CACHE_TTL = 3600000; // 1 ora
|
| 8 |
|
|
|
|
| 9 |
const userAgents = [
|
| 10 |
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36',
|
| 11 |
+
'Mozilla/5.0 (Windows NT 10.0; rv:125.0) Gecko/20100101 Firefox/125.0',
|
| 12 |
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15',
|
| 13 |
+
'Mozilla/5.0 (Linux; Android 14; SM-S928U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.140 Mobile Safari/537.36'
|
| 14 |
];
|
| 15 |
|
| 16 |
+
const metaCache = new Map();
|
| 17 |
+
|
| 18 |
+
function debugLog(message) {
|
| 19 |
+
if (DEBUG_MODE) {
|
| 20 |
+
console.log(`[EPISODES][${new Date().toISOString()}] ${message}`);
|
| 21 |
+
}
|
|
|
|
|
|
|
| 22 |
}
|
| 23 |
|
| 24 |
+
async function fetchWithCloudscraper(url, retries = 2) {
|
| 25 |
+
const userAgents = [
|
| 26 |
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36',
|
| 27 |
+
'Mozilla/5.0 (Windows NT 10.0; rv:125.0) Gecko/20100101 Firefox/125.0',
|
| 28 |
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15',
|
| 29 |
+
'Mozilla/5.0 (Linux; Android 14; SM-S928U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.140 Mobile Safari/537.36',
|
| 30 |
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/123.0.6312.122'
|
| 31 |
+
];
|
| 32 |
|
| 33 |
+
function getRandomHeaders() {
|
| 34 |
+
return {
|
| 35 |
+
'User-Agent': userAgents[Math.floor(Math.random() * userAgents.length)],
|
| 36 |
+
'Referer': 'https://ramaorientalfansub.tv',
|
| 37 |
+
'Accept-Language': 'en-US,en;q=0.9',
|
| 38 |
+
'Upgrade-Insecure-Requests': '1',
|
| 39 |
+
'Cache-Control': 'no-cache',
|
| 40 |
+
'Pragma': 'no-cache',
|
| 41 |
+
'Connection': 'keep-alive'
|
| 42 |
+
};
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
for (let i = 0; i < retries; i++) {
|
| 46 |
+
try {
|
| 47 |
+
console.log(`[${i + 1}/${retries}] Tentativo di scraping: ${url}`);
|
| 48 |
+
const response = await cloudscraper.get({
|
| 49 |
+
uri: url,
|
| 50 |
+
headers: getRandomHeaders(),
|
| 51 |
+
followAllRedirects: true,
|
| 52 |
+
maxRedirects: 5,
|
| 53 |
+
timeout: 30000,
|
| 54 |
+
resolveWithFullResponse: true // Aggiungi questa opzione
|
| 55 |
+
});
|
| 56 |
+
|
| 57 |
+
if (response.statusCode === 404) {
|
| 58 |
+
console.warn(`[${i + 1}/${retries}] Errore 404 per ${url}. Interrompo i tentativi.`);
|
| 59 |
+
return null; // Interrompi immediatamente se l'episodio non esiste
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
if (response && response.statusCode >= 200 && response.statusCode < 300) {
|
| 63 |
+
console.log(`[${i + 1}/${retries}] Scraping riuscito: ${url}`);
|
| 64 |
+
return response.body; // Restituisci il corpo della risposta
|
| 65 |
+
} else {
|
| 66 |
+
console.warn(`[${i + 1}/${retries}] Errore ${response.statusCode} per ${url}. Riprovo...`);
|
| 67 |
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
| 68 |
+
}
|
| 69 |
+
} catch (error) {
|
| 70 |
+
console.error(`[${i + 1}/${retries}] Errore Cloudscraper per ${url}: ${error.message}`);
|
| 71 |
+
if (error.message.includes('Cloudflare')) {
|
| 72 |
+
console.warn(`[${i + 1}/${retries}] Rilevato Cloudflare. Attendo 15 secondi...`);
|
| 73 |
+
await new Promise(resolve => setTimeout(resolve, 15000));
|
| 74 |
+
} else {
|
| 75 |
+
console.warn(`[${i + 1}/${retries}] Errore generico. Attendo 5 secondi...`);
|
| 76 |
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
}
|
| 80 |
+
console.error(`[FETCH_FAILED] Impossibile recuperare ${url} dopo ${retries} tentativi.`);
|
| 81 |
+
return null;
|
| 82 |
}
|
| 83 |
|
| 84 |
+
|
| 85 |
async function getMeta(id) {
|
| 86 |
const meta = { id, type: 'series', name: '', poster: '', episodes: [] };
|
| 87 |
+
const cleanId = id.replace(/,/g, '-').toLowerCase();
|
| 88 |
const baseId = cleanId.replace(/-\d{4}$/, '');
|
| 89 |
const seriesLink = `https://ramaorientalfansub.tv/drama/${baseId}/`;
|
| 90 |
+
|
| 91 |
if (metaCache.has(id)) {
|
| 92 |
+
return { meta: metaCache.get(id) };
|
|
|
|
| 93 |
}
|
| 94 |
|
| 95 |
try {
|
|
|
|
| 100 |
}
|
| 101 |
|
| 102 |
const $ = cheerio.load(data);
|
|
|
|
| 103 |
meta.name = $('a.text-accent').text().trim();
|
| 104 |
meta.poster = $('img.wp-post-image').attr('src');
|
| 105 |
+
let description = $('div.font-light > div:nth-child(1)').text().trim();
|
|
|
|
| 106 |
if (meta.extra && meta.extra.tag) {
|
| 107 |
description += ` [${meta.extra.tag.toUpperCase()}]`;
|
| 108 |
}
|
| 109 |
+
meta.description = description;
|
| 110 |
+
|
| 111 |
+
// Recupera gli episodi
|
| 112 |
+
meta.episodes = await getEpisodes(seriesLink, $);
|
| 113 |
+
|
| 114 |
+
// Aggiungi i link degli episodi alla descrizione
|
| 115 |
+
if (meta.episodes && meta.episodes.length > 0) {
|
| 116 |
+
description += "\n\nEpisodi:\n";
|
| 117 |
+
meta.episodes.forEach(episode => {
|
| 118 |
+
description += `- ${episode.title}: ${episode.streams[0].url}\n`;
|
| 119 |
+
});
|
| 120 |
+
}
|
| 121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
metaCache.set(id, meta);
|
|
|
|
| 123 |
} catch (error) {
|
| 124 |
console.error('Errore nel caricamento dei dettagli della serie:', error);
|
| 125 |
}
|
| 126 |
|
|
|
|
| 127 |
return { meta };
|
| 128 |
}
|
| 129 |
|
| 130 |
+
|
| 131 |
+
export { getMeta };
|
main.js
CHANGED
|
@@ -4,106 +4,89 @@ import filmsCatalog from './rama_films.js';
|
|
| 4 |
import { getMeta } from './episodes.js';
|
| 5 |
|
| 6 |
const { addonBuilder, serveHTTP } = pkg;
|
|
|
|
| 7 |
|
| 8 |
const manifest = {
|
| 9 |
"id": "community.ramaorientalfansub",
|
| 10 |
-
"version": "1.0.
|
| 11 |
-
"name": "Rama Oriental Fansub",
|
| 12 |
-
"description": "Addon
|
| 13 |
"catalogs": [
|
| 14 |
{
|
| 15 |
"type": "series",
|
| 16 |
"id": "rama_series",
|
| 17 |
-
"name": "Serie Coreane",
|
| 18 |
"extra": [{ "name": "skip" }]
|
| 19 |
},
|
| 20 |
{
|
| 21 |
"type": "movie",
|
| 22 |
"id": "rama_films",
|
| 23 |
-
"name": "Film Coreani",
|
| 24 |
"extra": [{ "name": "skip" }]
|
| 25 |
}
|
| 26 |
],
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
};
|
| 32 |
|
| 33 |
const builder = new addonBuilder(manifest);
|
| 34 |
const metaCache = new Map();
|
| 35 |
|
| 36 |
-
builder.defineStreamHandler(async ({ type, id }) => {
|
| 37 |
-
if (type !== "series") {
|
| 38 |
-
return Promise.resolve({ streams: [] });
|
| 39 |
-
}
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
|
|
|
| 43 |
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
const metaResult = await getMeta(id);
|
| 50 |
-
meta = metaResult.meta;
|
| 51 |
-
metaCache.set(id, meta);
|
| 52 |
-
} catch (error) {
|
| 53 |
-
console.error(`Errore nel caricamento dei metadati per ${id}:`, error);
|
| 54 |
-
return Promise.resolve({ streams: [] });
|
| 55 |
}
|
| 56 |
-
}
|
| 57 |
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
}
|
| 62 |
-
|
| 63 |
-
const streams = meta.episodes.flatMap(ep =>
|
| 64 |
-
ep.streams.map(stream => ({
|
| 65 |
-
title: `${ep.title} - ${stream.title}`,
|
| 66 |
-
url: stream.url,
|
| 67 |
-
type: "video/mp4",
|
| 68 |
-
behaviorHints: {
|
| 69 |
-
bingeGroup: id,
|
| 70 |
-
notWebReady: false
|
| 71 |
-
}
|
| 72 |
-
}))
|
| 73 |
-
);
|
| 74 |
-
|
| 75 |
-
return Promise.resolve({ streams });
|
| 76 |
});
|
| 77 |
|
| 78 |
builder.defineCatalogHandler(async (args) => {
|
|
|
|
| 79 |
if (args.type === 'series' && args.id === 'rama_series') {
|
| 80 |
-
|
| 81 |
} else if (args.type === 'movie' && args.id === 'rama_films') {
|
| 82 |
-
|
| 83 |
}
|
| 84 |
-
}
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
if (
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
console.error(`Errore nel caricamento dei metadati per ${args.id}:`, error);
|
| 99 |
-
return { meta: null };
|
| 100 |
-
}
|
| 101 |
}
|
| 102 |
-
|
| 103 |
return { meta: { ...meta, extra: meta.extra } };
|
| 104 |
-
});
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
serveHTTP(builder.getInterface(), { port: 7000 });
|
| 109 |
-
console.log(`Addon server is running at http://localhost:7000/manifest.json`);
|
|
|
|
| 4 |
import { getMeta } from './episodes.js';
|
| 5 |
|
| 6 |
const { addonBuilder, serveHTTP } = pkg;
|
| 7 |
+
const META_CACHE_TTL = 3600000; // 1 ora
|
| 8 |
|
| 9 |
const manifest = {
|
| 10 |
"id": "community.ramaorientalfansub",
|
| 11 |
+
"version": "1.0.6",
|
| 12 |
+
"name": "Rama Oriental Fansub+",
|
| 13 |
+
"description": "Addon migliorato con scraper avanzato",
|
| 14 |
"catalogs": [
|
| 15 |
{
|
| 16 |
"type": "series",
|
| 17 |
"id": "rama_series",
|
| 18 |
+
"name": "Serie Coreane+",
|
| 19 |
"extra": [{ "name": "skip" }]
|
| 20 |
},
|
| 21 |
{
|
| 22 |
"type": "movie",
|
| 23 |
"id": "rama_films",
|
| 24 |
+
"name": "Film Coreani+",
|
| 25 |
"extra": [{ "name": "skip" }]
|
| 26 |
}
|
| 27 |
],
|
| 28 |
+
"resources": ["catalog", "meta", "stream"],
|
| 29 |
+
"types": ["series", "movie"],
|
| 30 |
+
"logo": "https://ramaorientalfansub.tv/wp-content/uploads/2023/10/cropped-Logo-1.png",
|
| 31 |
+
"background": "https://ramaorientalfansub.tv/wp-content/uploads/2023/10/2860055-e1696595653601.jpg"
|
| 32 |
};
|
| 33 |
|
| 34 |
const builder = new addonBuilder(manifest);
|
| 35 |
const metaCache = new Map();
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
+
builder.defineStreamHandler(async ({ type, id }) => {
|
| 39 |
+
try {
|
| 40 |
+
if (type !== "series") return { streams: [] };
|
| 41 |
|
| 42 |
+
let meta = metaCache.get(id);
|
| 43 |
+
if (!meta || Date.now() - meta.timestamp > META_CACHE_TTL) {
|
| 44 |
+
const result = await getMeta(id);
|
| 45 |
+
meta = result.meta;
|
| 46 |
+
metaCache.set(id, { ...meta, timestamp: Date.now() });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
}
|
|
|
|
| 48 |
|
| 49 |
+
return {
|
| 50 |
+
streams: meta.episodes?.flatMap(ep =>
|
| 51 |
+
ep.streams.map(stream => ({
|
| 52 |
+
title: `${ep.title} - ${stream.title}`,
|
| 53 |
+
url: stream.url,
|
| 54 |
+
type: "video/mp4",
|
| 55 |
+
behaviorHints: { bingeGroup: id }
|
| 56 |
+
}))
|
| 57 |
+
) || []
|
| 58 |
+
};
|
| 59 |
+
} catch (error) {
|
| 60 |
+
console.error(`Handler Error: ${error.message}`);
|
| 61 |
+
return { streams: [] };
|
| 62 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
});
|
| 64 |
|
| 65 |
builder.defineCatalogHandler(async (args) => {
|
| 66 |
+
console.log("Catalog Handler chiamato con:", args); // Aggiungi questo log
|
| 67 |
if (args.type === 'series' && args.id === 'rama_series') {
|
| 68 |
+
return seriesCatalog(args);
|
| 69 |
} else if (args.type === 'movie' && args.id === 'rama_films') {
|
| 70 |
+
return filmsCatalog(args);
|
| 71 |
}
|
| 72 |
+
return { metas: [] }; // Aggiungi un return di default
|
| 73 |
+
});
|
| 74 |
+
|
| 75 |
+
builder.defineMetaHandler(async (args) => {
|
| 76 |
+
let meta = metaCache.get(args.id);
|
| 77 |
+
if (!meta) {
|
| 78 |
+
try {
|
| 79 |
+
const metaResult = await getMeta(args.id);
|
| 80 |
+
meta = metaResult.meta;
|
| 81 |
+
metaCache.set(args.id, meta);
|
| 82 |
+
} catch (error) {
|
| 83 |
+
console.error(`Errore nel caricamento dei metadati per ${args.id}:`, error);
|
| 84 |
+
return { meta: null };
|
| 85 |
+
}
|
|
|
|
|
|
|
|
|
|
| 86 |
}
|
| 87 |
+
|
| 88 |
return { meta: { ...meta, extra: meta.extra } };
|
| 89 |
+
});
|
| 90 |
+
|
| 91 |
+
serveHTTP(builder.getInterface(), { port: 7000 });
|
| 92 |
+
console.log(`Addon server is running at http://localhost:7000/manifest.json`);
|
|
|
|
|
|
manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"id": "community.ramaorientalfansub",
|
| 3 |
-
"version": "1.0.
|
| 4 |
"name": "Rama Oriental Fansub",
|
| 5 |
"description": "Addon per visualizzare serie e film coreani dal sito Rama Oriental Fansub",
|
| 6 |
"catalogs": [
|
|
|
|
| 1 |
{
|
| 2 |
"id": "community.ramaorientalfansub",
|
| 3 |
+
"version": "1.0.6",
|
| 4 |
"name": "Rama Oriental Fansub",
|
| 5 |
"description": "Addon per visualizzare serie e film coreani dal sito Rama Oriental Fansub",
|
| 6 |
"catalogs": [
|
package-lock.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
package.json
CHANGED
|
@@ -1,23 +1,28 @@
|
|
| 1 |
{
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
"
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{
|
| 2 |
+
"name": "stremio-rama-addon",
|
| 3 |
+
"version": "1.0.6",
|
| 4 |
+
"main": "main.js",
|
| 5 |
+
"type": "module",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"start": "node main.js",
|
| 8 |
+
"postinstall": "npx npm-force-resolutions"
|
| 9 |
+
},
|
| 10 |
+
"dependencies": {
|
| 11 |
+
"axios": "^1.6.2",
|
| 12 |
+
"cheerio": "^1.0.0",
|
| 13 |
+
"cloudscraper": "^4.1.4",
|
| 14 |
+
"stremio-addon-sdk": "^1.6.10",
|
| 15 |
+
"uuid": "^9.0.1"
|
| 16 |
+
},
|
| 17 |
+
"resolutions": {
|
| 18 |
+
"har-validator": "5.1.5",
|
| 19 |
+
"request": "2.88.2",
|
| 20 |
+
"tough-cookie": "^4.1.3"
|
| 21 |
+
},
|
| 22 |
+
"overrides": {
|
| 23 |
+
"cloudscraper": {
|
| 24 |
+
"request": "2.88.2",
|
| 25 |
+
"request-promise": "4.2.6"
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
}
|
rama_series.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
| 1 |
import cloudscraper from 'cloudscraper';
|
| 2 |
import * as cheerio from 'cheerio';
|
| 3 |
|
|
|
|
| 4 |
const userAgents = [
|
| 5 |
-
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
| 6 |
-
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:
|
| 7 |
-
'Mozilla/5.0 (Macintosh; Intel Mac OS X
|
| 8 |
];
|
| 9 |
|
| 10 |
function getRandomHeaders() {
|
| 11 |
-
const userAgent = userAgents[Math.floor(Math.random() * userAgents.length)];
|
| 12 |
return {
|
| 13 |
-
'User-Agent':
|
| 14 |
'Referer': 'https://ramaorientalfansub.tv/paese/corea-del-sud/',
|
| 15 |
'Accept-Language': 'en-US,en;q=0.9'
|
| 16 |
};
|
|
@@ -20,7 +20,10 @@ async function fetchWithCloudscraper(url) {
|
|
| 20 |
try {
|
| 21 |
const data = await cloudscraper.get({
|
| 22 |
uri: url,
|
| 23 |
-
headers: getRandomHeaders()
|
|
|
|
|
|
|
|
|
|
| 24 |
});
|
| 25 |
return data;
|
| 26 |
} catch (error) {
|
|
@@ -41,17 +44,14 @@ async function getCatalog(skip = 0) {
|
|
| 41 |
|
| 42 |
while (catalog.length < itemsToLoad && pageNumber <= MAX_PAGES) {
|
| 43 |
const pageUrl = `${BASE_URL}page/${pageNumber}/`;
|
| 44 |
-
console.log(`Richiedendo pagina: ${pageNumber}`);
|
| 45 |
-
|
| 46 |
let data;
|
|
|
|
| 47 |
if (catalogCache.has(pageUrl)) {
|
| 48 |
-
console.log(`Caricamento pagina ${pageNumber} dalla cache.`);
|
| 49 |
data = catalogCache.get(pageUrl);
|
| 50 |
} else {
|
| 51 |
try {
|
| 52 |
data = await fetchWithCloudscraper(pageUrl);
|
| 53 |
if (!data) {
|
| 54 |
-
console.warn(`Nessun dato ricevuto per ${pageUrl}`);
|
| 55 |
pageNumber++;
|
| 56 |
continue;
|
| 57 |
}
|
|
@@ -68,7 +68,7 @@ async function getCatalog(skip = 0) {
|
|
| 68 |
|
| 69 |
$('div.w-full.bg-gradient-to-t.from-primary').each((index, element) => {
|
| 70 |
if (catalog.length >= itemsToLoad) {
|
| 71 |
-
return false;
|
| 72 |
}
|
| 73 |
|
| 74 |
const titleElement = $(element).find('a.text-sm.line-clamp-2.font-medium.leading-snug.lg\\:leading-normal');
|
|
@@ -85,38 +85,35 @@ async function getCatalog(skip = 0) {
|
|
| 85 |
extraTag = 'simulcast';
|
| 86 |
}
|
| 87 |
|
| 88 |
-
if (
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
meta.extra = { tag: extraTag };
|
| 103 |
-
}
|
| 104 |
-
|
| 105 |
-
catalog.push(meta);
|
| 106 |
-
foundItemsOnPage++;
|
| 107 |
}
|
|
|
|
|
|
|
|
|
|
| 108 |
}
|
| 109 |
});
|
| 110 |
|
| 111 |
-
console.log(`Pagina ${pageNumber}: trovati ${foundItemsOnPage} elementi.`);
|
| 112 |
pageNumber++;
|
| 113 |
}
|
| 114 |
|
| 115 |
-
console.log(`Totale elementi raccolti: ${catalog.length}`);
|
| 116 |
return catalog;
|
| 117 |
}
|
| 118 |
|
| 119 |
export default async function (args) {
|
| 120 |
const skip = args.extra?.skip || 0;
|
| 121 |
-
|
| 122 |
-
};
|
|
|
|
|
|
| 1 |
import cloudscraper from 'cloudscraper';
|
| 2 |
import * as cheerio from 'cheerio';
|
| 3 |
|
| 4 |
+
|
| 5 |
const userAgents = [
|
| 6 |
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
|
| 7 |
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0',
|
| 8 |
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15'
|
| 9 |
];
|
| 10 |
|
| 11 |
function getRandomHeaders() {
|
|
|
|
| 12 |
return {
|
| 13 |
+
'User-Agent': userAgents[Math.floor(Math.random() * userAgents.length)],
|
| 14 |
'Referer': 'https://ramaorientalfansub.tv/paese/corea-del-sud/',
|
| 15 |
'Accept-Language': 'en-US,en;q=0.9'
|
| 16 |
};
|
|
|
|
| 20 |
try {
|
| 21 |
const data = await cloudscraper.get({
|
| 22 |
uri: url,
|
| 23 |
+
headers: getRandomHeaders(),
|
| 24 |
+
followAllRedirects: true,
|
| 25 |
+
maxRedirects: 5,
|
| 26 |
+
timeout: 30000,
|
| 27 |
});
|
| 28 |
return data;
|
| 29 |
} catch (error) {
|
|
|
|
| 44 |
|
| 45 |
while (catalog.length < itemsToLoad && pageNumber <= MAX_PAGES) {
|
| 46 |
const pageUrl = `${BASE_URL}page/${pageNumber}/`;
|
|
|
|
|
|
|
| 47 |
let data;
|
| 48 |
+
|
| 49 |
if (catalogCache.has(pageUrl)) {
|
|
|
|
| 50 |
data = catalogCache.get(pageUrl);
|
| 51 |
} else {
|
| 52 |
try {
|
| 53 |
data = await fetchWithCloudscraper(pageUrl);
|
| 54 |
if (!data) {
|
|
|
|
| 55 |
pageNumber++;
|
| 56 |
continue;
|
| 57 |
}
|
|
|
|
| 68 |
|
| 69 |
$('div.w-full.bg-gradient-to-t.from-primary').each((index, element) => {
|
| 70 |
if (catalog.length >= itemsToLoad) {
|
| 71 |
+
return false;
|
| 72 |
}
|
| 73 |
|
| 74 |
const titleElement = $(element).find('a.text-sm.line-clamp-2.font-medium.leading-snug.lg\\:leading-normal');
|
|
|
|
| 85 |
extraTag = 'simulcast';
|
| 86 |
}
|
| 87 |
|
| 88 |
+
if (title && link) {
|
| 89 |
+
const formattedTitle = title.replace(/\s+/g, '-').toLowerCase().replace(/[()]/g, '');
|
| 90 |
+
const meta = {
|
| 91 |
+
id: formattedTitle,
|
| 92 |
+
type: 'series',
|
| 93 |
+
name: title,
|
| 94 |
+
poster,
|
| 95 |
+
description: title,
|
| 96 |
+
imdbRating: "N/A",
|
| 97 |
+
released: 2024,
|
| 98 |
+
};
|
| 99 |
+
|
| 100 |
+
if (extraTag) {
|
| 101 |
+
meta.extra = { tag: extraTag };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
}
|
| 103 |
+
|
| 104 |
+
catalog.push(meta);
|
| 105 |
+
foundItemsOnPage++;
|
| 106 |
}
|
| 107 |
});
|
| 108 |
|
|
|
|
| 109 |
pageNumber++;
|
| 110 |
}
|
| 111 |
|
|
|
|
| 112 |
return catalog;
|
| 113 |
}
|
| 114 |
|
| 115 |
export default async function (args) {
|
| 116 |
const skip = args.extra?.skip || 0;
|
| 117 |
+
const metas = await getCatalog(skip);
|
| 118 |
+
return { metas };
|
| 119 |
+
};
|
streams.js
CHANGED
|
@@ -1,42 +1,74 @@
|
|
| 1 |
import cloudscraper from 'cloudscraper';
|
| 2 |
import * as cheerio from 'cheerio';
|
| 3 |
|
| 4 |
-
// Lista di User-Agent
|
| 5 |
const userAgents = [
|
| 6 |
-
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
| 7 |
-
'Mozilla/5.0 (Windows NT 10.0;
|
| 8 |
-
'Mozilla/5.0 (Macintosh; Intel Mac OS X
|
|
|
|
| 9 |
];
|
| 10 |
|
| 11 |
-
//
|
| 12 |
-
function
|
| 13 |
-
const
|
| 14 |
-
|
| 15 |
-
'
|
| 16 |
-
'
|
| 17 |
-
'
|
| 18 |
-
|
| 19 |
-
|
| 20 |
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
return null;
|
| 32 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
}
|
| 34 |
|
| 35 |
-
/**
|
| 36 |
-
* Recupera il link dello stream per un episodio specifico.
|
| 37 |
-
* @param {string} episodeLink - URL della pagina dell'episodio.
|
| 38 |
-
* @returns {string|null} - URL dello stream o null se non trovato.
|
| 39 |
-
*/
|
| 40 |
async function getStream(episodeLink) {
|
| 41 |
let iframeSrc = null;
|
| 42 |
try {
|
|
@@ -50,7 +82,6 @@ async function getStream(episodeLink) {
|
|
| 50 |
iframeSrc = $('iframe').attr('src');
|
| 51 |
if (iframeSrc) {
|
| 52 |
iframeSrc = encodeURI(iframeSrc);
|
| 53 |
-
console.log(`Stream trovato: ${decodeURI(iframeSrc)}`);
|
| 54 |
if (iframeSrc.startsWith('https://server1.streamingrof.online/02-DRAMACOREANI')) {
|
| 55 |
return iframeSrc;
|
| 56 |
} else {
|
|
@@ -62,30 +93,20 @@ async function getStream(episodeLink) {
|
|
| 62 |
return null;
|
| 63 |
}
|
| 64 |
} catch (err) {
|
| 65 |
-
console.log(`Analizzando stream per: ${episodeLink}`);
|
| 66 |
-
console.log('Iframe trovato:', iframeSrc);
|
| 67 |
console.error(`Errore durante il recupero dello stream per ${episodeLink}:`, err);
|
| 68 |
return null;
|
| 69 |
}
|
| 70 |
}
|
| 71 |
|
| 72 |
-
/**
|
| 73 |
-
* Recupera la lista degli episodi e i rispettivi stream per una serie.
|
| 74 |
-
* @param {string} seriesLink - URL della pagina della serie.
|
| 75 |
-
* @param {CheerioStatic} $ - Oggetto Cheerio caricato con la pagina della serie.
|
| 76 |
-
* @returns {Array} - Lista di episodi con titolo, thumbnail e link allo stream.
|
| 77 |
-
*/
|
| 78 |
async function getEpisodes(seriesLink, $) {
|
| 79 |
try {
|
| 80 |
const episodes = [];
|
| 81 |
const baseEpisodeUrl = seriesLink.replace('/drama/', '/watch/');
|
| 82 |
-
console.log('Chiamata a getEpisodes con URL:', seriesLink);
|
| 83 |
let seriesId = seriesLink.split('/').filter(Boolean).pop();
|
| 84 |
-
|
| 85 |
-
seriesId = seriesId.replace(/
|
| 86 |
-
|
| 87 |
let seriesYear = null;
|
| 88 |
-
// Estrai l'anno dalla pagina della serie (se presente)
|
| 89 |
try {
|
| 90 |
const titleText = $('title').text();
|
| 91 |
const yearMatch = titleText.match(/\b(19|20)\d{2}\b/);
|
|
@@ -96,23 +117,19 @@ async function getEpisodes(seriesLink, $) {
|
|
| 96 |
console.error('Errore durante il recupero dell\'anno della serie:', error);
|
| 97 |
}
|
| 98 |
|
| 99 |
-
console.log('Anno serie:', seriesYear);
|
| 100 |
-
// Invece di cercare il numero massimo di episodi, proviamo semplicemente a caricarli in sequenza
|
| 101 |
let episodeNumber = 1;
|
| 102 |
while (true) {
|
| 103 |
const episodeId = seriesYear ? `${seriesId}-${seriesYear}` : seriesId;
|
| 104 |
const episodeLink = `https://ramaorientalfansub.tv/watch/${episodeId}-episodio-${episodeNumber}/`;
|
| 105 |
-
console.log(`URL dell'episodio generato: ${episodeLink}`);
|
| 106 |
try {
|
| 107 |
const stream = await getStream(episodeLink);
|
| 108 |
if (!stream) {
|
| 109 |
-
console.
|
| 110 |
-
break; // Interrompi il ciclo
|
| 111 |
}
|
| 112 |
-
|
| 113 |
episodes.push({
|
| 114 |
id: `episodio-${episodeNumber}`,
|
| 115 |
-
title: `${episodeNumber}`,
|
| 116 |
thumbnail: 'div.swiper-slide:nth-child(1) > a:nth-child(1) > div:nth-child(1)',
|
| 117 |
streams: [{
|
| 118 |
title: `Episodio ${episodeNumber}`,
|
|
@@ -120,17 +137,13 @@ async function getEpisodes(seriesLink, $) {
|
|
| 120 |
type: "video/mp4"
|
| 121 |
}]
|
| 122 |
});
|
| 123 |
-
//
|
| 124 |
-
await new Promise(resolve => setTimeout(resolve, 1000)); // Aspetta 1 secondo
|
| 125 |
} catch (error) {
|
| 126 |
-
console.error(`Errore durante il recupero dello stream per ${episodeLink}:`,
|
| 127 |
-
break; // Interrompi il ciclo anche in caso di errore
|
| 128 |
}
|
| 129 |
-
|
| 130 |
episodeNumber++;
|
| 131 |
}
|
| 132 |
-
|
| 133 |
-
console.log('Episodi trovati:', JSON.stringify(episodes, null, 2));
|
| 134 |
return episodes;
|
| 135 |
} catch (err) {
|
| 136 |
console.error('Errore durante il recupero degli episodi:', err);
|
|
@@ -138,4 +151,4 @@ async function getEpisodes(seriesLink, $) {
|
|
| 138 |
}
|
| 139 |
}
|
| 140 |
|
| 141 |
-
export { getEpisodes, getStream };
|
|
|
|
| 1 |
import cloudscraper from 'cloudscraper';
|
| 2 |
import * as cheerio from 'cheerio';
|
| 3 |
|
|
|
|
| 4 |
const userAgents = [
|
| 5 |
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36',
|
| 6 |
+
'Mozilla/5.0 (Windows NT 10.0; rv:125.0) Gecko/20100101 Firefox/125.0',
|
| 7 |
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15',
|
| 8 |
+
'Mozilla/5.0 (Linux; Android 14; SM-S928U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.140 Mobile Safari/537.36'
|
| 9 |
];
|
| 10 |
|
| 11 |
+
// Modifica fetchWithCloudscraper per accettare l'URL come parametro
|
| 12 |
+
async function fetchWithCloudscraper(url, retries = 2) {
|
| 13 |
+
const userAgents = [
|
| 14 |
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36',
|
| 15 |
+
'Mozilla/5.0 (Windows NT 10.0; rv:125.0) Gecko/20100101 Firefox/125.0',
|
| 16 |
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15',
|
| 17 |
+
'Mozilla/5.0 (Linux; Android 14; SM-S928U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.140 Mobile Safari/537.36',
|
| 18 |
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/123.0.6312.122'
|
| 19 |
+
];
|
| 20 |
|
| 21 |
+
function getRandomHeaders() {
|
| 22 |
+
return {
|
| 23 |
+
'User-Agent': userAgents[Math.floor(Math.random() * userAgents.length)],
|
| 24 |
+
'Referer': 'https://ramaorientalfansub.tv',
|
| 25 |
+
'Accept-Language': 'en-US,en;q=0.9',
|
| 26 |
+
'Upgrade-Insecure-Requests': '1',
|
| 27 |
+
'Cache-Control': 'no-cache',
|
| 28 |
+
'Pragma': 'no-cache',
|
| 29 |
+
'Connection': 'keep-alive'
|
| 30 |
+
};
|
|
|
|
| 31 |
}
|
| 32 |
+
|
| 33 |
+
for (let i = 0; i < retries; i++) {
|
| 34 |
+
try {
|
| 35 |
+
console.log(`[${i + 1}/${retries}] Tentativo di scraping: ${url}`);
|
| 36 |
+
const response = await cloudscraper.get({
|
| 37 |
+
uri: url,
|
| 38 |
+
headers: getRandomHeaders(),
|
| 39 |
+
followAllRedirects: true,
|
| 40 |
+
maxRedirects: 5,
|
| 41 |
+
timeout: 30000,
|
| 42 |
+
resolveWithFullResponse: true // Aggiungi questa opzione
|
| 43 |
+
});
|
| 44 |
+
|
| 45 |
+
if (response.statusCode === 404) {
|
| 46 |
+
console.warn(`[${i + 1}/${retries}] Errore 404 per ${url}. Interrompo i tentativi.`);
|
| 47 |
+
return null; // Interrompi immediatamente se l'episodio non esiste
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
if (response && response.statusCode >= 200 && response.statusCode < 300) {
|
| 51 |
+
console.log(`[${i + 1}/${retries}] Scraping riuscito: ${url}`);
|
| 52 |
+
return response.body; // Restituisci il corpo della risposta
|
| 53 |
+
} else {
|
| 54 |
+
console.warn(`[${i + 1}/${retries}] Errore ${response.statusCode} per ${url}. Riprovo...`);
|
| 55 |
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
| 56 |
+
}
|
| 57 |
+
} catch (error) {
|
| 58 |
+
console.error(`[${i + 1}/${retries}] Errore Cloudscraper per ${url}: ${error.message}`);
|
| 59 |
+
if (error.message.includes('Cloudflare')) {
|
| 60 |
+
console.warn(`[${i + 1}/${retries}] Rilevato Cloudflare. Attendo 15 secondi...`);
|
| 61 |
+
await new Promise(resolve => setTimeout(resolve, 15000));
|
| 62 |
+
} else {
|
| 63 |
+
console.warn(`[${i + 1}/${retries}] Errore generico. Attendo 5 secondi...`);
|
| 64 |
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
console.error(`[FETCH_FAILED] Impossibile recuperare ${url} dopo ${retries} tentativi.`);
|
| 69 |
+
return null;
|
| 70 |
}
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
async function getStream(episodeLink) {
|
| 73 |
let iframeSrc = null;
|
| 74 |
try {
|
|
|
|
| 82 |
iframeSrc = $('iframe').attr('src');
|
| 83 |
if (iframeSrc) {
|
| 84 |
iframeSrc = encodeURI(iframeSrc);
|
|
|
|
| 85 |
if (iframeSrc.startsWith('https://server1.streamingrof.online/02-DRAMACOREANI')) {
|
| 86 |
return iframeSrc;
|
| 87 |
} else {
|
|
|
|
| 93 |
return null;
|
| 94 |
}
|
| 95 |
} catch (err) {
|
|
|
|
|
|
|
| 96 |
console.error(`Errore durante il recupero dello stream per ${episodeLink}:`, err);
|
| 97 |
return null;
|
| 98 |
}
|
| 99 |
}
|
| 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
async function getEpisodes(seriesLink, $) {
|
| 102 |
try {
|
| 103 |
const episodes = [];
|
| 104 |
const baseEpisodeUrl = seriesLink.replace('/drama/', '/watch/');
|
|
|
|
| 105 |
let seriesId = seriesLink.split('/').filter(Boolean).pop();
|
| 106 |
+
seriesId = seriesId.replace(/,/g, '-').toLowerCase();
|
| 107 |
+
seriesId = seriesId.replace(/--+/g, '-');
|
| 108 |
+
|
| 109 |
let seriesYear = null;
|
|
|
|
| 110 |
try {
|
| 111 |
const titleText = $('title').text();
|
| 112 |
const yearMatch = titleText.match(/\b(19|20)\d{2}\b/);
|
|
|
|
| 117 |
console.error('Errore durante il recupero dell\'anno della serie:', error);
|
| 118 |
}
|
| 119 |
|
|
|
|
|
|
|
| 120 |
let episodeNumber = 1;
|
| 121 |
while (true) {
|
| 122 |
const episodeId = seriesYear ? `${seriesId}-${seriesYear}` : seriesId;
|
| 123 |
const episodeLink = `https://ramaorientalfansub.tv/watch/${episodeId}-episodio-${episodeNumber}/`;
|
|
|
|
| 124 |
try {
|
| 125 |
const stream = await getStream(episodeLink);
|
| 126 |
if (!stream) {
|
| 127 |
+
console.warn(`Nessuno stream trovato per ${episodeLink}. Interrompo.`);
|
| 128 |
+
break; // Interrompi il ciclo while
|
| 129 |
}
|
|
|
|
| 130 |
episodes.push({
|
| 131 |
id: `episodio-${episodeNumber}`,
|
| 132 |
+
title: `Episodio ${episodeNumber}`,
|
| 133 |
thumbnail: 'div.swiper-slide:nth-child(1) > a:nth-child(1) > div:nth-child(1)',
|
| 134 |
streams: [{
|
| 135 |
title: `Episodio ${episodeNumber}`,
|
|
|
|
| 137 |
type: "video/mp4"
|
| 138 |
}]
|
| 139 |
});
|
| 140 |
+
// await new Promise(resolve => setTimeout(resolve, 1000)); // Rimuovi questo delay
|
|
|
|
| 141 |
} catch (error) {
|
| 142 |
+
console.error(`Errore durante il recupero dello stream per ${episodeLink}:`, error);
|
| 143 |
+
break; // Interrompi il ciclo while anche in caso di errore
|
| 144 |
}
|
|
|
|
| 145 |
episodeNumber++;
|
| 146 |
}
|
|
|
|
|
|
|
| 147 |
return episodes;
|
| 148 |
} catch (err) {
|
| 149 |
console.error('Errore durante il recupero degli episodi:', err);
|
|
|
|
| 151 |
}
|
| 152 |
}
|
| 153 |
|
| 154 |
+
export { getEpisodes, getStream };
|