mirror of
https://github.com/sussy-code/providers.git
synced 2026-08-20 14:06:48 +00:00
add webtor
This commit is contained in:
parent
7b7e019afb
commit
06a9ceb7a5
5 changed files with 195 additions and 0 deletions
|
|
@ -76,6 +76,7 @@ import { voeScraper } from './embeds/voe';
|
|||
import { warezcdnembedHlsScraper } from './embeds/warezcdn/hls';
|
||||
import { warezcdnembedMp4Scraper } from './embeds/warezcdn/mp4';
|
||||
import { warezPlayerScraper } from './embeds/warezcdn/warezplayer';
|
||||
import { webtor1080Scraper, webtor480Scraper, webtor4kScraper, webtor720Scraper } from './embeds/webtor';
|
||||
import { wootlyScraper } from './embeds/wootly';
|
||||
import { goojaraScraper } from './sources/goojara';
|
||||
import { hdRezkaScraper } from './sources/hdrezka';
|
||||
|
|
@ -88,6 +89,7 @@ import { smashyStreamScraper } from './sources/smashystream';
|
|||
import { soaperTvScraper } from './sources/soapertv';
|
||||
import { vidSrcToScraper } from './sources/vidsrcto';
|
||||
import { warezcdnScraper } from './sources/warezcdn';
|
||||
import { webtorScraper } from './sources/webtor';
|
||||
|
||||
export function gatherAllSources(): Array<Sourcerer> {
|
||||
// all sources are gathered here
|
||||
|
|
@ -124,6 +126,7 @@ export function gatherAllSources(): Array<Sourcerer> {
|
|||
vidsrcsuScraper,
|
||||
TASFScraper,
|
||||
mp4hydraScraper,
|
||||
webtorScraper,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -186,5 +189,9 @@ export function gatherAllEmbeds(): Array<Embed> {
|
|||
VidsrcsuServer9Scraper,
|
||||
VidsrcsuServer10Scraper,
|
||||
VidsrcsuServer11Scraper,
|
||||
webtor4kScraper,
|
||||
webtor1080Scraper,
|
||||
webtor720Scraper,
|
||||
webtor480Scraper,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
32
src/providers/embeds/webtor.ts
Normal file
32
src/providers/embeds/webtor.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { flags } from '@/entrypoint/utils/targets';
|
||||
import { makeEmbed } from '@/providers/base';
|
||||
|
||||
const providers = [
|
||||
{ id: 'webtor-1080', rank: 80 }, // 1080p should be a higher rank becuase it loads faster
|
||||
{ id: 'webtor-4k', rank: 79 },
|
||||
{ id: 'webtor-720', rank: 78 },
|
||||
{ id: 'webtor-480', rank: 77 },
|
||||
];
|
||||
|
||||
function embed(provider: { id: string; rank: number }) {
|
||||
return makeEmbed({
|
||||
id: provider.id,
|
||||
name: `Webtor ${provider.id.split('-')[1].toUpperCase()}`,
|
||||
rank: provider.rank,
|
||||
async scrape(ctx) {
|
||||
return {
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'hls',
|
||||
playlist: ctx.url,
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const [webtor4kScraper, webtor1080Scraper, webtor720Scraper, webtor480Scraper] = providers.map(embed);
|
||||
69
src/providers/sources/webtor/common.ts
Normal file
69
src/providers/sources/webtor/common.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import { Stream } from './types';
|
||||
|
||||
const trackers = [
|
||||
'udp://tracker.opentrackr.org:1337/announce',
|
||||
'udp://open.demonii.com:1337/announce',
|
||||
'udp://open.tracker.cl:1337/announce',
|
||||
'udp://open.stealth.si:80/announce',
|
||||
'udp://tracker.torrent.eu.org:451/announce',
|
||||
'udp://explodie.org:6969/announce',
|
||||
'udp://tracker.qu.ax:6969/announce',
|
||||
'udp://tracker.ololosh.space:6969/announce',
|
||||
'udp://tracker.dump.cl:6969/announce',
|
||||
'udp://tracker.dler.org:6969/announce',
|
||||
'udp://tracker.bittor.pw:1337/announce',
|
||||
'udp://tracker-udp.gbitt.info:80/announce',
|
||||
'udp://opentracker.io:6969/announce',
|
||||
'udp://open.free-tracker.ga:6969/announce',
|
||||
'udp://ns-1.x-fins.com:6969/announce',
|
||||
'udp://leet-tracker.moe:1337/announce',
|
||||
'udp://isk.richardsw.club:6969/announce',
|
||||
'udp://discord.heihachi.pw:6969/announce',
|
||||
'http://www.torrentsnipe.info:2701/announce',
|
||||
'http://www.genesis-sp.org:2710/announce',
|
||||
];
|
||||
|
||||
export function getMagnetUrl(infoHash: string, name: string): string {
|
||||
const encodedName = encodeURIComponent(name);
|
||||
const trackerParams = trackers.map((tracker) => `&tr=${encodeURIComponent(tracker)}`).join('');
|
||||
return `magnet:?xt=urn:btih:${infoHash}&dn=${encodedName}${trackerParams}`;
|
||||
}
|
||||
|
||||
export function constructProxyUrl(magnetUrl: string): string {
|
||||
const encodedMagnet = encodeURIComponent(magnetUrl);
|
||||
return `https://savingshub.online/api/fetchHls?magnet=${encodedMagnet}`;
|
||||
}
|
||||
|
||||
export function categorizeStreams(streams: Stream[]): Record<string, Stream[]> {
|
||||
const categories: Record<string, Stream[]> = {
|
||||
'4k': [],
|
||||
'1080p': [],
|
||||
'720p': [],
|
||||
'480p': [],
|
||||
};
|
||||
|
||||
streams.forEach((stream) => {
|
||||
const name = stream.name.toLowerCase();
|
||||
if (name.includes('4k')) {
|
||||
categories['4k'].push(stream);
|
||||
} else if (name.includes('1080p')) {
|
||||
categories['1080p'].push(stream);
|
||||
} else if (name.includes('720p')) {
|
||||
categories['720p'].push(stream);
|
||||
} else if (name.includes('480p')) {
|
||||
categories['480p'].push(stream);
|
||||
}
|
||||
});
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
export function getTopStreamsBySeeders(categoryStreams: Stream[], limit: number): Stream[] {
|
||||
return categoryStreams
|
||||
.sort((a, b) => {
|
||||
const seedersA = parseInt(a.title.match(/👤 (\d+) /)?.[1] || '0', 10);
|
||||
const seedersB = parseInt(b.title.match(/👤 (\d+) /)?.[1] || '0', 10);
|
||||
return seedersB - seedersA;
|
||||
})
|
||||
.slice(0, limit);
|
||||
}
|
||||
70
src/providers/sources/webtor/index.ts
Normal file
70
src/providers/sources/webtor/index.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import { flags } from '@/entrypoint/utils/targets';
|
||||
import { SourcererOutput, makeSourcerer } from '@/providers/base';
|
||||
import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context';
|
||||
|
||||
import { categorizeStreams, constructProxyUrl, getMagnetUrl, getTopStreamsBySeeders } from './common';
|
||||
import { Response } from './types';
|
||||
|
||||
async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise<SourcererOutput> {
|
||||
const search =
|
||||
ctx.media.type === 'movie'
|
||||
? `movie/${ctx.media.imdbId}.json`
|
||||
: `series/${ctx.media.imdbId}:${ctx.media.season.number}:${ctx.media.episode.number}.json`;
|
||||
|
||||
const response: Response = await ctx
|
||||
.fetcher(
|
||||
`https://torrentio.strem.fun/providers=yts,eztv,rarbg,1337x,thepiratebay,kickasstorrents,torrentgalaxy,magnetdl,horriblesubs,nyaasi,tokyotosho,anidex/stream/${search}`,
|
||||
)
|
||||
.then((res) => (typeof res === 'string' ? JSON.parse(res) : res));
|
||||
|
||||
ctx.progress(50);
|
||||
|
||||
const categories = categorizeStreams(response.streams);
|
||||
const embeds: { embedId: string; url: string }[] = [];
|
||||
|
||||
const qualityResults = await Promise.all(
|
||||
Object.entries(categories).map(async ([category, streams]) => {
|
||||
const [topStream] = getTopStreamsBySeeders(streams, 1);
|
||||
if (!topStream) return null;
|
||||
|
||||
try {
|
||||
const magnet = getMagnetUrl(topStream.infoHash, topStream.name);
|
||||
const apiUrl = constructProxyUrl(magnet);
|
||||
|
||||
const apiResponse = await ctx.fetcher(apiUrl);
|
||||
const responseData = typeof apiResponse === 'string' ? JSON.parse(apiResponse) : apiResponse;
|
||||
if (!responseData?.m3u8Link) throw new Error('No m3u8 link in response');
|
||||
|
||||
return {
|
||||
quality: category,
|
||||
url: responseData.m3u8Link,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch ${category}:`, error);
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
qualityResults.forEach((result) => {
|
||||
if (result?.url) {
|
||||
embeds.push({
|
||||
embedId: `webtor-${result.quality.replace('p', '')}`,
|
||||
url: result.url,
|
||||
});
|
||||
}
|
||||
});
|
||||
ctx.progress(90);
|
||||
|
||||
return { embeds };
|
||||
}
|
||||
|
||||
export const webtorScraper = makeSourcerer({
|
||||
id: 'webtor',
|
||||
name: 'Webtor',
|
||||
rank: 5,
|
||||
disabled: false,
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
scrapeMovie: comboScraper,
|
||||
scrapeShow: comboScraper,
|
||||
});
|
||||
17
src/providers/sources/webtor/types.ts
Normal file
17
src/providers/sources/webtor/types.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
export interface Stream {
|
||||
name: string;
|
||||
title: string;
|
||||
infoHash: string;
|
||||
fileIdx: number;
|
||||
behaviorHints: {
|
||||
bingeGroup: string;
|
||||
filename: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
streams: Stream[];
|
||||
cacheMaxAge: number;
|
||||
staleRevalidate: number;
|
||||
staleError: number;
|
||||
}
|
||||
Loading…
Reference in a new issue