feat: add RgShows
This commit is contained in:
parent
4bec9e556f
commit
dcad7db29c
16 changed files with 237 additions and 3 deletions
20
src/extractor/RgShows.test.ts
Normal file
20
src/extractor/RgShows.test.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import winston from 'winston';
|
||||
import { createTestContext } from '../test';
|
||||
import { FetcherMock } from '../utils';
|
||||
import { ExtractorRegistry } from './ExtractorRegistry';
|
||||
import { RgShows } from './RgShows';
|
||||
|
||||
const logger = winston.createLogger({ transports: [new winston.transports.Console({ level: 'nope' })] });
|
||||
const extractorRegistry = new ExtractorRegistry(logger, [new RgShows(new FetcherMock(`${__dirname}/__fixtures__/RgShows`))]);
|
||||
|
||||
const ctx = createTestContext();
|
||||
|
||||
describe('RgShows', () => {
|
||||
test('handle one battle after another', async () => {
|
||||
expect(await extractorRegistry.handle(ctx, new URL('https://api.rgshows.ru/main/movie/1054867'))).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('handle stranger things s05e01', async () => {
|
||||
expect(await extractorRegistry.handle(ctx, new URL('https://api.rgshows.ru/main/tv/66732/5/1'))).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
45
src/extractor/RgShows.ts
Normal file
45
src/extractor/RgShows.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { guessHeightFromPlaylist } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
interface RgShowsApiData {
|
||||
stream: {
|
||||
url: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class RgShows extends Extractor {
|
||||
public readonly id = 'rgshows';
|
||||
|
||||
public readonly label = 'RgShows';
|
||||
|
||||
public override readonly ttl: number = 10800000; // 3h
|
||||
|
||||
public supports(_ctx: Context, url: URL): boolean {
|
||||
return null !== url.host.match(/rgshows/);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
const nonSubDomainUrl = new URL(url);
|
||||
nonSubDomainUrl.hostname = nonSubDomainUrl.hostname.split('.').slice(-2).join('.');
|
||||
const headers = { 'Referer': `${nonSubDomainUrl.origin}/`, 'Origin': nonSubDomainUrl.origin, 'User-Agent': 'Mozilla' };
|
||||
|
||||
const data = await this.fetcher.json(ctx, url, { headers, noProxy: true }) as RgShowsApiData;
|
||||
|
||||
const playlistUrl = new URL(data.stream.url);
|
||||
|
||||
return [
|
||||
{
|
||||
url: playlistUrl,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
height: await guessHeightFromPlaylist(ctx, this.fetcher, playlistUrl, url, { headers, noProxy: true }),
|
||||
},
|
||||
requestHeaders: headers,
|
||||
},
|
||||
];
|
||||
};
|
||||
}
|
||||
1
src/extractor/__fixtures__/RgShows/https:api.rgshows.rumainmovie1054867
generated
Normal file
1
src/extractor/__fixtures__/RgShows/https:api.rgshows.rumainmovie1054867
generated
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"stream":{"url":"https://i-arch-400.lethe399key.com/stream2/i-arch-400/01df0d24fc785e08a44241ed17dc9aef/MJTMsp1RshGTygnMNRUR2N2MSlnWXZEdMNDZzQWe5MDZzMmdZJTO1R2RWVHZDljekhkSsl1VwYnWtx2cihVT2pFVNlnT6FVNPR1a04kMJlnTUJkaO1WWzklaNFTTHV1daRUW04ERFhnWUFVP:1767971011:193.233.230.8:338a99d2e898667664ed62657ac0b65a05ed7308fe98419b3a65225ee36a7ae1/index.m3u8"}}
|
||||
1
src/extractor/__fixtures__/RgShows/https:api.rgshows.rumaintv6673251
generated
Normal file
1
src/extractor/__fixtures__/RgShows/https:api.rgshows.rumaintv6673251
generated
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"stream":{"url":"https://i-cdn-0.lethe399key.com/stream2/i-cdn-0/01df0d24fc785e08a44241ed17dc9aef/MJTMsp1RshGTygnMNRUR2N2MSlnWXZEdMNDZzQWe5MDZzMmdZJTO1R2RWVHZDljekhkSsl1VwYnWtx2cihVT290VZBjTH1kMORVR390RFRTT6lFMPRUS18EVNhnWUtWMapWQ5l1VRJjTHlUP:1767971582:193.233.230.8:3e079e35a7d560d1b37aa2a38f4b3e6cf2d6449ab480651c4c3557eda220addd/index.m3u8"}}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#EXTM3U
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=400000,RESOLUTION=640x358
|
||||
./360/index.m3u8
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=858x482
|
||||
./480/index.m3u8
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=2000000,RESOLUTION=1280x720
|
||||
./720/index.m3u8
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1920x1080
|
||||
./1080/index.m3u8
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#EXTM3U
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=400000,RESOLUTION=640x358
|
||||
./360/index.m3u8
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=858x482
|
||||
./480/index.m3u8
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=2000000,RESOLUTION=1280x720
|
||||
./720/index.m3u8
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1920x1080
|
||||
./1080/index.m3u8
|
||||
43
src/extractor/__snapshots__/RgShows.test.ts.snap
Normal file
43
src/extractor/__snapshots__/RgShows.test.ts.snap
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`RgShows handle one battle after another 1`] = `
|
||||
[
|
||||
{
|
||||
"format": "hls",
|
||||
"label": "RgShows",
|
||||
"meta": {
|
||||
"countryCodes": [],
|
||||
"extractorId": "rgshows",
|
||||
"height": 1080,
|
||||
},
|
||||
"requestHeaders": {
|
||||
"Origin": "https://rgshows.ru",
|
||||
"Referer": "https://rgshows.ru/",
|
||||
"User-Agent": "Mozilla",
|
||||
},
|
||||
"ttl": 10800000,
|
||||
"url": "https://i-arch-400.lethe399key.com/stream2/i-arch-400/01df0d24fc785e08a44241ed17dc9aef/MJTMsp1RshGTygnMNRUR2N2MSlnWXZEdMNDZzQWe5MDZzMmdZJTO1R2RWVHZDljekhkSsl1VwYnWtx2cihVT2pFVNlnT6FVNPR1a04kMJlnTUJkaO1WWzklaNFTTHV1daRUW04ERFhnWUFVP:1767971011:193.233.230.8:338a99d2e898667664ed62657ac0b65a05ed7308fe98419b3a65225ee36a7ae1/index.m3u8",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`RgShows handle stranger things s05e01 1`] = `
|
||||
[
|
||||
{
|
||||
"format": "hls",
|
||||
"label": "RgShows",
|
||||
"meta": {
|
||||
"countryCodes": [],
|
||||
"extractorId": "rgshows",
|
||||
"height": 1080,
|
||||
},
|
||||
"requestHeaders": {
|
||||
"Origin": "https://rgshows.ru",
|
||||
"Referer": "https://rgshows.ru/",
|
||||
"User-Agent": "Mozilla",
|
||||
},
|
||||
"ttl": 10800000,
|
||||
"url": "https://i-cdn-0.lethe399key.com/stream2/i-cdn-0/01df0d24fc785e08a44241ed17dc9aef/MJTMsp1RshGTygnMNRUR2N2MSlnWXZEdMNDZzQWe5MDZzMmdZJTO1R2RWVHZDljekhkSsl1VwYnWtx2cihVT290VZBjTH1kMORVR390RFRTT6lFMPRUS18EVNhnWUtWMapWQ5l1VRJjTHlUP:1767971582:193.233.230.8:3e079e35a7d560d1b37aa2a38f4b3e6cf2d6449ab480651c4c3557eda220addd/index.m3u8",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
|
@ -11,6 +11,7 @@ import { HubCloud } from './HubCloud';
|
|||
import { KinoGer } from './KinoGer';
|
||||
import { LuluStream } from './LuluStream';
|
||||
import { Mixdrop } from './Mixdrop';
|
||||
import { RgShows } from './RgShows';
|
||||
import { SaveFiles } from './SaveFiles';
|
||||
import { StreamEmbed } from './StreamEmbed';
|
||||
import { Streamtape } from './Streamtape';
|
||||
|
|
@ -38,6 +39,7 @@ export const createExtractors = (fetcher: Fetcher): Extractor[] => {
|
|||
new KinoGer(fetcher),
|
||||
new LuluStream(fetcher),
|
||||
new Mixdrop(fetcher),
|
||||
new RgShows(fetcher),
|
||||
new SaveFiles(fetcher),
|
||||
new StreamEmbed(fetcher),
|
||||
new Streamtape(fetcher),
|
||||
|
|
|
|||
23
src/source/RgShows.test.ts
Normal file
23
src/source/RgShows.test.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { createTestContext } from '../test';
|
||||
import { FetcherMock, TmdbId } from '../utils';
|
||||
import { RgShows } from './RgShows';
|
||||
|
||||
const ctx = createTestContext();
|
||||
|
||||
describe('RgShows', () => {
|
||||
let source: RgShows;
|
||||
|
||||
beforeEach(() => {
|
||||
source = new RgShows(new FetcherMock(`${__dirname}/__fixtures__/RgShows`));
|
||||
});
|
||||
|
||||
test('handle stranger things s05e01', async () => {
|
||||
const streams = await source.handle(ctx, 'series', new TmdbId(66732, 5, 1));
|
||||
expect(streams).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('handle one battle after another', async () => {
|
||||
const streams = await source.handle(ctx, 'movie', new TmdbId(1054867, undefined, undefined));
|
||||
expect(streams).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
42
src/source/RgShows.ts
Normal file
42
src/source/RgShows.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { ContentType } from 'stremio-addon-sdk';
|
||||
import { Context, CountryCode } from '../types';
|
||||
import { Fetcher, getTmdbId, getTmdbNameAndYear, Id } from '../utils';
|
||||
import { Source, SourceResult } from './Source';
|
||||
|
||||
export class RgShows extends Source {
|
||||
public readonly id = 'rgshows';
|
||||
|
||||
public readonly label = 'RgShows';
|
||||
|
||||
public readonly contentTypes: ContentType[] = ['movie', 'series'];
|
||||
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.en];
|
||||
|
||||
public readonly baseUrl = 'https://rgshows.ru';
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
public constructor(fetcher: Fetcher) {
|
||||
super();
|
||||
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public async handleInternal(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const tmdbId = await getTmdbId(ctx, this.fetcher, id);
|
||||
const [name, year] = await getTmdbNameAndYear(ctx, this.fetcher, tmdbId);
|
||||
|
||||
let title: string = name;
|
||||
if (tmdbId.season) {
|
||||
title += ` ${tmdbId.formatSeasonAndEpisode()}`;
|
||||
} else {
|
||||
title += ` (${year})`;
|
||||
}
|
||||
|
||||
const url = tmdbId.season
|
||||
? new URL(`https://api.rgshows.ru/main/tv/${tmdbId.id}/${tmdbId.season}/${tmdbId.episode}`, this.baseUrl)
|
||||
: new URL(`https://api.rgshows.ru/main/movie/${tmdbId.id}`, this.baseUrl);
|
||||
|
||||
return [{ url, meta: { countryCodes: [CountryCode.multi], title } }];
|
||||
};
|
||||
}
|
||||
1
src/source/__fixtures__/RgShows/https:api.themoviedb.org3movie1054867
generated
Normal file
1
src/source/__fixtures__/RgShows/https:api.themoviedb.org3movie1054867
generated
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"adult":false,"backdrop_path":"/zpEWFNqoN8Qg1SzMMHmaGyOBTdW.jpg","belongs_to_collection":null,"budget":175000000,"genres":[{"id":53,"name":"Thriller"},{"id":80,"name":"Crime"},{"id":28,"name":"Action"}],"homepage":"https://www.onebattleafteranothermovie.com","id":1054867,"imdb_id":"tt30144839","origin_country":["US"],"original_language":"en","original_title":"One Battle After Another","overview":"Washed-up revolutionary Bob exists in a state of stoned paranoia, surviving off-grid with his spirited, self-reliant daughter, Willa. When his evil nemesis resurfaces after 16 years and she goes missing, the former radical scrambles to find her, father and daughter both battling the consequences of his past.","popularity":88.9734,"poster_path":"/r4uXvqCeco0KmO0CjlhXuTEFuSE.jpg","production_companies":[{"id":174,"logo_path":"/ingPVoHnINIrFR7WHmYux1f5pES.png","name":"Warner Bros. Pictures","origin_country":"US"},{"id":178,"logo_path":null,"name":"Ghoulardi Film Company","origin_country":"US"},{"id":216687,"logo_path":"/kKVYqekveOvLK1IgqdJojLjQvtu.png","name":"Domain Entertainment","origin_country":"US"}],"production_countries":[{"iso_3166_1":"US","name":"United States of America"}],"release_date":"2025-09-23","revenue":205168736,"runtime":162,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"},{"english_name":"French","iso_639_1":"fr","name":"Français"},{"english_name":"Spanish","iso_639_1":"es","name":"Español"},{"english_name":"Telugu","iso_639_1":"te","name":"తెలుగు"}],"status":"Released","tagline":"Some search for battle, others are born into it...","title":"One Battle After Another","video":false,"vote_average":7.462,"vote_count":2171}
|
||||
1
src/source/__fixtures__/RgShows/https:api.themoviedb.org3tv66732
generated
Normal file
1
src/source/__fixtures__/RgShows/https:api.themoviedb.org3tv66732
generated
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"adult":false,"backdrop_path":"/8zbAoryWbtH0DKdev8abFAjdufy.jpg","created_by":[{"id":1179422,"credit_id":"57599b039251410a99001cce","name":"Ross Duffer","original_name":"Ross Duffer","gender":2,"profile_path":"/kN1HdFViQkcJOQlNcvvFJIx9Uju.jpg"},{"id":1179419,"credit_id":"57599b0e925141378a002c87","name":"Matt Duffer","original_name":"Matt Duffer","gender":2,"profile_path":"/kXO5CnSxC0znMAICGxnPeuGP73U.jpg"}],"episode_run_time":[],"first_air_date":"2016-07-15","genres":[{"id":10765,"name":"Sci-Fi & Fantasy"},{"id":9648,"name":"Mystery"},{"id":10759,"name":"Action & Adventure"}],"homepage":"https://www.netflix.com/title/80057281","id":66732,"in_production":false,"languages":["en"],"last_air_date":"2025-12-31","last_episode_to_air":{"id":5607051,"name":"Chapter Eight: The Rightside Up","overview":"As Vecna prepares to destroy the world as we know it, the party must put everything on the line to defeat him once and for all.","vote_average":7.113,"vote_count":80,"air_date":"2025-12-31","episode_number":8,"episode_type":"finale","production_code":"","runtime":129,"season_number":5,"show_id":66732,"still_path":"/kP23RWbUWM6vGhT9PxFyP5VT3y4.jpg"},"name":"Stranger Things","next_episode_to_air":null,"networks":[{"id":213,"logo_path":"/wwemzKWzjKYJFfCeiB57q3r4Bcm.png","name":"Netflix","origin_country":""}],"number_of_episodes":42,"number_of_seasons":5,"origin_country":["US"],"original_language":"en","original_name":"Stranger Things","overview":"When a young boy vanishes, a small town uncovers a mystery involving secret experiments, terrifying supernatural forces, and one strange little girl.","popularity":1622.2589,"poster_path":"/uOOtwVbSr4QDjAGIifLDwpb2Pdl.jpg","production_companies":[{"id":2575,"logo_path":"/9YJrHYlcfHtwtulkFMAies3aFEl.png","name":"21 Laps Entertainment","origin_country":"US"},{"id":170090,"logo_path":null,"name":"Monkey Massacre Productions","origin_country":"US"},{"id":184664,"logo_path":"/4qv40ryAKUzvwptbv13eXUAl1Wm.png","name":"Upside Down Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"US","name":"United States of America"}],"seasons":[{"air_date":"2016-07-15","episode_count":8,"id":77680,"name":"Season 1","overview":"Strange things are afoot in Hawkins, Indiana, where a young boy's sudden disappearance unearths a young girl with otherworldly powers.","poster_path":"/hb4KmdA4F1XMnf0vVjevPKKBEjV.jpg","season_number":1,"vote_average":8.4},{"air_date":"2017-10-27","episode_count":9,"id":83248,"name":"Stranger Things 2","overview":"It's been nearly a year since Will's strange disappearance. But life's hardly back to normal in Hawkins. Not even close.","poster_path":"/74nFJmiapxKuUBXRbSu6VqGGcuo.jpg","season_number":2,"vote_average":8.2},{"air_date":"2019-07-04","episode_count":8,"id":115216,"name":"Stranger Things 3","overview":"Budding romance. A brand-new mall. And rabid rats running toward danger. It's the summer of 1985 in Hawkins ... and one summer can change everything.","poster_path":"/sDms9g40ZBhjMIfX9YqqaqId8sK.jpg","season_number":3,"vote_average":8.1},{"air_date":"2022-05-27","episode_count":9,"id":163313,"name":"Stranger Things 4","overview":"Darkness returns to Hawkins just in time for spring break, igniting fresh terror, disturbing memories — and an ominous new threat.","poster_path":"/zvGTZYDCoMSMIBkXExxRxLYimqN.jpg","season_number":4,"vote_average":8.5},{"air_date":"2025-11-26","episode_count":8,"id":402292,"name":"Stranger Things 5","overview":"The fall of 1987. Hawkins is scarred by rifts. Vecna has vanished and the government has placed the town under military quarantine, forcing Eleven back into hiding. To end this nightmare, they'll need everyone together, one last time.","poster_path":"/AaLrOh33YLkK1WLEB8Uml7FL8fm.jpg","season_number":5,"vote_average":7.5}],"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"}],"status":"Ended","tagline":"One last adventure.","type":"Scripted","vote_average":8.591,"vote_count":19952}
|
||||
29
src/source/__snapshots__/RgShows.test.ts.snap
Normal file
29
src/source/__snapshots__/RgShows.test.ts.snap
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`RgShows handle one battle after another 1`] = `
|
||||
[
|
||||
{
|
||||
"meta": {
|
||||
"countryCodes": [
|
||||
"multi",
|
||||
],
|
||||
"title": "One Battle After Another (2025)",
|
||||
},
|
||||
"url": "https://api.rgshows.ru/main/movie/1054867",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`RgShows handle stranger things s05e01 1`] = `
|
||||
[
|
||||
{
|
||||
"meta": {
|
||||
"countryCodes": [
|
||||
"multi",
|
||||
],
|
||||
"title": "Stranger Things S05E01",
|
||||
},
|
||||
"url": "https://api.rgshows.ru/main/tv/66732/5/1",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
|
@ -13,6 +13,7 @@ import { MegaKino } from './MegaKino';
|
|||
import { MeineCloud } from './MeineCloud';
|
||||
import { MostraGuarda } from './MostraGuarda';
|
||||
import { Movix } from './Movix';
|
||||
import { RgShows } from './RgShows';
|
||||
import { Source } from './Source';
|
||||
import { StreamKiste } from './StreamKiste';
|
||||
import { VerHdLink } from './VerHdLink';
|
||||
|
|
@ -26,6 +27,7 @@ export const createSources = (fetcher: Fetcher): Source[] => {
|
|||
return [
|
||||
// multi
|
||||
new FourKHDHub(fetcher),
|
||||
new RgShows(fetcher),
|
||||
new VixSrc(fetcher),
|
||||
// AL
|
||||
new Kokoshka(fetcher),
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ type ProxyConfig = Pick<AxiosRequestConfig, 'httpAgent' | 'httpsAgent' | 'proxy'
|
|||
|
||||
export type CustomRequestConfig = AxiosRequestConfig & {
|
||||
minCacheTtl?: number;
|
||||
noProxy?: boolean;
|
||||
noProxyHeaders?: boolean;
|
||||
queueLimit?: number;
|
||||
queueTimeout?: number;
|
||||
|
|
@ -122,7 +123,7 @@ export class Fetcher {
|
|||
}
|
||||
|
||||
protected async fetchWithTimeout(ctx: Context, url: URL, requestConfig?: CustomRequestConfig, tryCount = 0): Promise<AxiosResponse> {
|
||||
const proxyUrl = this.getProxyForUrl(ctx, url);
|
||||
const proxyUrl = requestConfig?.noProxy ? null : this.getProxyForUrl(ctx, url);
|
||||
|
||||
let message = `Fetch ${requestConfig?.method ?? 'GET'} ${url}`;
|
||||
/* istanbul ignore if */
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@ exports[`buildManifest default manifest 1`] = `
|
|||
"title": "German 🇩🇪 (Einschalten, KinoGer, MegaKino, MeineCloud, StreamKiste)",
|
||||
"type": "checkbox",
|
||||
},
|
||||
{
|
||||
"key": "en",
|
||||
"title": "English 🇺🇸 (RgShows)",
|
||||
"type": "checkbox",
|
||||
},
|
||||
{
|
||||
"key": "es",
|
||||
"title": "Castilian Spanish 🇪🇸 (CineHDPlus, Cuevana, HomeCine, VerHdLink)",
|
||||
|
|
@ -74,9 +79,9 @@ exports[`buildManifest default manifest 1`] = `
|
|||
],
|
||||
"description": "Provides HTTP URLs from streaming websites. Configure add-on for additional languages. Add MediaFlow proxy for more URLs.
|
||||
|
||||
Supported languages: Albanian, German, Castilian Spanish, French, Hindi, Italian, Latin American Spanish
|
||||
Supported languages: Albanian, German, English, Castilian Spanish, French, Hindi, Italian, Latin American Spanish
|
||||
|
||||
Supported sources: 4KHDHub, VixSrc, Kokoshka, CineHDPlus, Cuevana, HomeCine, VerHdLink, Einschalten, KinoGer, MegaKino, MeineCloud, StreamKiste, Frembed, FrenchCloud, Movix, Eurostreaming, MostraGuarda
|
||||
Supported sources: 4KHDHub, RgShows, VixSrc, Kokoshka, CineHDPlus, Cuevana, HomeCine, VerHdLink, Einschalten, KinoGer, MegaKino, MeineCloud, StreamKiste, Frembed, FrenchCloud, Movix, Eurostreaming, MostraGuarda
|
||||
|
||||
Supported extractors: ",
|
||||
"id": "webstreamr",
|
||||
|
|
|
|||
Loading…
Reference in a new issue