mirror of
https://github.com/p-stream/providers.git
synced 2026-01-11 20:10:33 +00:00
add 1stream
This commit is contained in:
parent
e05d259b02
commit
045e3d4e59
4 changed files with 403 additions and 0 deletions
|
|
@ -19,6 +19,17 @@ import { mp4hydraScraper } from '@/providers/sources/mp4hydra';
|
|||
import { tugaflixScraper } from '@/providers/sources/tugaflix';
|
||||
import { vidsrcsuScraper } from '@/providers/sources/vidsrcsu';
|
||||
|
||||
import {
|
||||
oneServerAnimepaheEmbed,
|
||||
oneServerAnizoneEmbed,
|
||||
oneServerAutoembedEmbed,
|
||||
oneServerFlixhqEmbed,
|
||||
oneServerFoxstreamEmbed,
|
||||
oneServerGokuEmbed,
|
||||
oneServerHianimeEmbed,
|
||||
oneServerPrimeboxEmbed,
|
||||
oneServerVidsrcsuEmbed,
|
||||
} from './embeds/1server';
|
||||
import {
|
||||
autoembedBengaliScraper,
|
||||
autoembedEnglishScraper,
|
||||
|
|
@ -66,6 +77,7 @@ import {
|
|||
xprimePrimenetEmbed,
|
||||
xprimeStreamboxEmbed,
|
||||
} from './embeds/xprime';
|
||||
import { oneServerScraper } from './sources/1server';
|
||||
import { EightStreamScraper } from './sources/8stream';
|
||||
import { coitusScraper } from './sources/coitus';
|
||||
import { ConsumetScraper } from './sources/consumet';
|
||||
|
|
@ -115,6 +127,7 @@ export function gatherAllSources(): Array<Sourcerer> {
|
|||
xprimeScraper,
|
||||
ConsumetScraper,
|
||||
hianimeScraper,
|
||||
oneServerScraper,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -173,5 +186,14 @@ export function gatherAllEmbeds(): Array<Embed> {
|
|||
hianimeHd2DubEmbed,
|
||||
hianimeHd1SubEmbed,
|
||||
hianimeHd2SubEmbed,
|
||||
oneServerAutoembedEmbed,
|
||||
oneServerVidsrcsuEmbed,
|
||||
oneServerPrimeboxEmbed,
|
||||
oneServerFoxstreamEmbed,
|
||||
oneServerFlixhqEmbed,
|
||||
oneServerGokuEmbed,
|
||||
oneServerHianimeEmbed,
|
||||
oneServerAnimepaheEmbed,
|
||||
oneServerAnizoneEmbed,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
295
src/providers/embeds/1server.ts
Normal file
295
src/providers/embeds/1server.ts
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
/* eslint-disable no-console */
|
||||
import { flags } from '@/entrypoint/utils/targets';
|
||||
import { EmbedOutput, makeEmbed } from '@/providers/base';
|
||||
import { NotFoundError } from '@/utils/errors';
|
||||
|
||||
const baseUrl = 'https://flix.1anime.app';
|
||||
|
||||
const languageMap: Record<string, string> = {
|
||||
'chinese - hong kong': 'zh',
|
||||
'chinese - traditional': 'zh',
|
||||
czech: 'cs',
|
||||
danish: 'da',
|
||||
dutch: 'nl',
|
||||
english: 'en',
|
||||
'english - sdh': 'en',
|
||||
finnish: 'fi',
|
||||
french: 'fr',
|
||||
german: 'de',
|
||||
greek: 'el',
|
||||
hungarian: 'hu',
|
||||
italian: 'it',
|
||||
korean: 'ko',
|
||||
norwegian: 'no',
|
||||
polish: 'pl',
|
||||
portuguese: 'pt',
|
||||
'portuguese - brazilian': 'pt',
|
||||
romanian: 'ro',
|
||||
'spanish - european': 'es',
|
||||
'spanish - latin american': 'es',
|
||||
swedish: 'sv',
|
||||
turkish: 'tr',
|
||||
اَلْعَرَبِيَّةُ: 'ar',
|
||||
বাংলা: 'bn',
|
||||
filipino: 'tl',
|
||||
indonesia: 'id',
|
||||
اردو: 'ur',
|
||||
};
|
||||
|
||||
function createProxyUrl(originalUrl: string, referer?: string): string {
|
||||
const encodedUrl = encodeURIComponent(originalUrl);
|
||||
const encodedHeaders = encodeURIComponent(
|
||||
JSON.stringify({
|
||||
referer,
|
||||
}),
|
||||
);
|
||||
|
||||
return `https://proxy.fifthwit.net/m3u8-proxy?url=${encodedUrl}&headers=${encodedHeaders}`;
|
||||
}
|
||||
|
||||
function processProxiedURL(url: string): string {
|
||||
// Handle orbitproxy URLs
|
||||
if (url.includes('orbitproxy')) {
|
||||
try {
|
||||
const urlParts = url.split(/orbitproxy\.[^/]+\//);
|
||||
if (urlParts.length >= 2) {
|
||||
const encryptedPart = urlParts[1].split('.m3u8')[0];
|
||||
try {
|
||||
const decodedData =
|
||||
typeof window !== 'undefined'
|
||||
? atob(encryptedPart)
|
||||
: Buffer.from(encryptedPart, 'base64').toString('utf-8');
|
||||
|
||||
const jsonData = JSON.parse(decodedData);
|
||||
const originalUrl = jsonData.u;
|
||||
const referer = jsonData.r || '';
|
||||
|
||||
return createProxyUrl(originalUrl, referer);
|
||||
} catch (jsonError) {
|
||||
console.error('Error decoding/parsing orbitproxy data:', jsonError);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing orbitproxy URL:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle other proxied URLs
|
||||
if (url.includes('/m3u8-proxy?url=')) {
|
||||
return url.replace(/https:\/\/[^/]+\/m3u8-proxy/, 'https://proxy.fifthwit.net/m3u8-proxy');
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
function isOnionflixerUrl(url: string): boolean {
|
||||
return url.includes('onionflixer');
|
||||
}
|
||||
|
||||
function processSubtitles(subtitles: any[] | undefined): any[] {
|
||||
const captions = [];
|
||||
|
||||
if (subtitles && Array.isArray(subtitles)) {
|
||||
for (const sub of subtitles) {
|
||||
const url = sub.url || sub.file;
|
||||
const lang = sub.lang || sub.label || 'unknown';
|
||||
|
||||
if (url) {
|
||||
captions.push({
|
||||
type: sub.type || 'vtt',
|
||||
url,
|
||||
language: languageMap[lang.toLowerCase()] || lang.toLowerCase() || 'unknown',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return captions;
|
||||
}
|
||||
|
||||
function processApiResponse(response: any, ctx: any): EmbedOutput {
|
||||
if (!response) {
|
||||
throw new NotFoundError('No response received');
|
||||
}
|
||||
|
||||
if (response.error) {
|
||||
throw new NotFoundError(`${response.error}${response.hint ? ` - ${response.hint}` : ''}`);
|
||||
}
|
||||
|
||||
// Handle array responses (multiple provider options)
|
||||
if (Array.isArray(response)) {
|
||||
for (const item of response) {
|
||||
// Handle format with headers and sources array
|
||||
if (item.headers && item.sources && Array.isArray(item.sources)) {
|
||||
const bestSource = item.sources.find((s: any) => s.isM3U8);
|
||||
if (bestSource && bestSource.url) {
|
||||
const playlistUrl = processProxiedURL(bestSource.url);
|
||||
const captions = processSubtitles(item.subtitles);
|
||||
|
||||
return {
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'hls',
|
||||
playlist: playlistUrl,
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Handle format with source.provider and source.files
|
||||
if (item.source && item.source.files && Array.isArray(item.source.files)) {
|
||||
const bestFile = item.source.files.find((f: any) => f.type === 'hls' || f.file.includes('.m3u8'));
|
||||
if (bestFile && bestFile.file) {
|
||||
const playlistUrl = processProxiedURL(bestFile.file);
|
||||
const captions = processSubtitles(item.source.subtitles);
|
||||
|
||||
return {
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'hls',
|
||||
playlist: playlistUrl,
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle original format with sources object
|
||||
const sourcesObj = response.sources;
|
||||
if (sourcesObj) {
|
||||
let bestSource = null;
|
||||
|
||||
// Look through all providers in the sources object
|
||||
for (const provider in sourcesObj) {
|
||||
if (Object.prototype.hasOwnProperty.call(sourcesObj, provider)) {
|
||||
const providerSources = sourcesObj[provider];
|
||||
if (providerSources && providerSources.length > 0) {
|
||||
// Find the highest quality non-onionflixer source
|
||||
for (const source of providerSources) {
|
||||
if (source.url && source.isM3U8 && !isOnionflixerUrl(source.url)) {
|
||||
bestSource = source;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If we found a good source, no need to check other providers
|
||||
if (bestSource) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no non-onionflixer source was found, use the first available one
|
||||
if (!bestSource) {
|
||||
for (const provider in sourcesObj) {
|
||||
if (Object.prototype.hasOwnProperty.call(sourcesObj, provider)) {
|
||||
const providerSources = sourcesObj[provider];
|
||||
if (providerSources && providerSources.length > 0) {
|
||||
bestSource = providerSources[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestSource && bestSource.url) {
|
||||
const playlistUrl = processProxiedURL(bestSource.url);
|
||||
const captions = processSubtitles(response.subtitles);
|
||||
|
||||
ctx.progress(100);
|
||||
|
||||
return {
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'hls',
|
||||
playlist: createProxyUrl(playlistUrl, ctx.referer),
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundError('No valid stream URL found in response');
|
||||
}
|
||||
|
||||
/* MOVIE & TV PROVIDERS */
|
||||
const movieTvProviders = [
|
||||
{ id: 'autoembed', name: 'Autoembed', rank: 165 },
|
||||
{ id: 'vidsrcsu', name: 'vidsrc.su', rank: 164 },
|
||||
{ id: 'primebox', name: 'Primebox', rank: 162, disabled: true },
|
||||
{ id: 'foxstream', name: 'Foxstream', rank: 161, disabled: true },
|
||||
{ id: 'flixhq', name: 'FlixHQ', rank: 166 },
|
||||
{ id: 'goku', name: 'Goku', rank: 163, disabled: true },
|
||||
];
|
||||
|
||||
const createMovieTvEmbed = (provider: { id: string; name: string; rank: number; disabled?: boolean }) =>
|
||||
makeEmbed({
|
||||
id: `oneserver-${provider.id}`,
|
||||
name: provider.name,
|
||||
rank: provider.rank,
|
||||
disabled: provider.disabled,
|
||||
async scrape(ctx) {
|
||||
const query = JSON.parse(ctx.url);
|
||||
const apiUrl =
|
||||
query.type === 'movie'
|
||||
? `${baseUrl}/movie/${provider.id}/${query.tmdbId}`
|
||||
: `${baseUrl}/tv/${provider.id}/${query.tmdbId}/${query.season}/${query.episode}`;
|
||||
|
||||
try {
|
||||
const response = await ctx.fetcher(apiUrl);
|
||||
ctx.progress(50);
|
||||
return processApiResponse(response, ctx);
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) throw error;
|
||||
throw new NotFoundError(`Failed to fetch from ${provider.id}: ${error}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const [
|
||||
oneServerAutoembedEmbed,
|
||||
oneServerVidsrcsuEmbed,
|
||||
oneServerPrimeboxEmbed,
|
||||
oneServerFoxstreamEmbed,
|
||||
oneServerFlixhqEmbed,
|
||||
oneServerGokuEmbed,
|
||||
] = movieTvProviders.map(createMovieTvEmbed);
|
||||
|
||||
/* ANIME PROVIDERS */
|
||||
const animeProviders = [
|
||||
{ id: 'hianime', name: 'Hianime', rank: 269 },
|
||||
{ id: 'animepahe', name: 'Animepahe', rank: 268 },
|
||||
{ id: 'anizone', name: 'Anizone', rank: 267 },
|
||||
];
|
||||
|
||||
const createAnimeEmbed = (provider: { id: string; name: string; rank: number }) =>
|
||||
makeEmbed({
|
||||
id: `oneserver-${provider.id}`,
|
||||
name: provider.name,
|
||||
rank: provider.rank,
|
||||
async scrape(ctx) {
|
||||
const query = JSON.parse(ctx.url);
|
||||
const apiUrl = `${baseUrl}/anime/${provider.id}/${query.anilistId}${query.episode ? `/${query.episode}` : ''}`;
|
||||
|
||||
try {
|
||||
const response = await ctx.fetcher(apiUrl);
|
||||
return processApiResponse(response, ctx);
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) throw error;
|
||||
throw new NotFoundError(`Failed to fetch from ${provider.id}: ${error}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const [oneServerHianimeEmbed, oneServerAnimepaheEmbed, oneServerAnizoneEmbed] =
|
||||
animeProviders.map(createAnimeEmbed);
|
||||
66
src/providers/sources/1server.ts
Normal file
66
src/providers/sources/1server.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import { flags } from '@/entrypoint/utils/targets';
|
||||
import { SourcererOutput, makeSourcerer } from '@/providers/base';
|
||||
import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context';
|
||||
|
||||
async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise<SourcererOutput> {
|
||||
const query = {
|
||||
type: ctx.media.type,
|
||||
title: ctx.media.title,
|
||||
tmdbId: ctx.media.tmdbId.toString(),
|
||||
...(ctx.media.type === 'show' && {
|
||||
season: ctx.media.season.number,
|
||||
episode: ctx.media.episode.number,
|
||||
}),
|
||||
};
|
||||
|
||||
const embeds = [
|
||||
{
|
||||
embedId: 'oneserver-autoembed',
|
||||
url: JSON.stringify(query),
|
||||
},
|
||||
{
|
||||
embedId: 'oneserver-vidsrcsu',
|
||||
url: JSON.stringify(query),
|
||||
},
|
||||
{
|
||||
embedId: 'oneserver-primebox',
|
||||
url: JSON.stringify(query),
|
||||
},
|
||||
{
|
||||
embedId: 'oneserver-foxstream',
|
||||
url: JSON.stringify(query),
|
||||
},
|
||||
{
|
||||
embedId: 'oneserver-flixhq',
|
||||
url: JSON.stringify(query),
|
||||
},
|
||||
{
|
||||
embedId: 'oneserver-goku',
|
||||
url: JSON.stringify(query),
|
||||
},
|
||||
// {
|
||||
// embedId: 'oneserver-hianime',
|
||||
// url: JSON.stringify(query),
|
||||
// },
|
||||
// {
|
||||
// embedId: 'oneserver-animepahe',
|
||||
// url: JSON.stringify(query),
|
||||
// },
|
||||
// {
|
||||
// embedId: 'oneserver-anizone',
|
||||
// url: JSON.stringify(query),
|
||||
// },
|
||||
];
|
||||
|
||||
return { embeds };
|
||||
}
|
||||
|
||||
export const oneServerScraper = makeSourcerer({
|
||||
id: '1server',
|
||||
name: '1Server',
|
||||
rank: 165,
|
||||
disabled: false,
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
scrapeMovie: comboScraper,
|
||||
scrapeShow: comboScraper,
|
||||
});
|
||||
|
|
@ -1,5 +1,16 @@
|
|||
// import { alphaScraper, deltaScraper } from '@/providers/embeds/nsbx';
|
||||
// import { astraScraper, novaScraper, orionScraper } from '@/providers/embeds/whvx';
|
||||
import {
|
||||
oneServerAnimepaheEmbed,
|
||||
oneServerAnizoneEmbed,
|
||||
oneServerAutoembedEmbed,
|
||||
oneServerFlixhqEmbed,
|
||||
oneServerFoxstreamEmbed,
|
||||
oneServerGokuEmbed,
|
||||
oneServerHianimeEmbed,
|
||||
oneServerPrimeboxEmbed,
|
||||
oneServerVidsrcsuEmbed,
|
||||
} from '@/providers/embeds/1server';
|
||||
import {
|
||||
ConsumetStreamSBScraper,
|
||||
ConsumetStreamTapeScraper,
|
||||
|
|
@ -51,6 +62,15 @@ const SKIP_VALIDATION_CHECK_IDS = [
|
|||
hianimeHd1SubEmbed.id,
|
||||
hianimeHd2DubEmbed.id,
|
||||
hianimeHd2SubEmbed.id,
|
||||
oneServerAutoembedEmbed.id,
|
||||
oneServerVidsrcsuEmbed.id,
|
||||
oneServerPrimeboxEmbed.id,
|
||||
oneServerFoxstreamEmbed.id,
|
||||
oneServerFlixhqEmbed.id,
|
||||
oneServerGokuEmbed.id,
|
||||
oneServerHianimeEmbed.id,
|
||||
oneServerAnimepaheEmbed.id,
|
||||
oneServerAnizoneEmbed.id,
|
||||
];
|
||||
|
||||
export function isValidStream(stream: Stream | undefined): boolean {
|
||||
|
|
|
|||
Loading…
Reference in a new issue