feat(source): add XPrime
This commit is contained in:
parent
9854d3b5b6
commit
cfe38878d7
18 changed files with 276 additions and 1 deletions
29
src/extractor/XPrime.test.ts
Normal file
29
src/extractor/XPrime.test.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import winston from 'winston';
|
||||
import { createTestContext } from '../test';
|
||||
import { CountryCode } from '../types';
|
||||
import { FetcherMock } from '../utils';
|
||||
import { ExtractorRegistry } from './ExtractorRegistry';
|
||||
import { XPrime } from './XPrime';
|
||||
|
||||
const logger = winston.createLogger({ transports: [new winston.transports.Console({ level: 'nope' })] });
|
||||
const extractorRegistry = new ExtractorRegistry(logger, [new XPrime(new FetcherMock(`${__dirname}/__fixtures__/XPrime`))]);
|
||||
|
||||
const ctx = createTestContext();
|
||||
|
||||
describe('XPrime', () => {
|
||||
test('unknown backend is ignored', async () => {
|
||||
expect(await extractorRegistry.handle(ctx, new URL('https://backend.xprime.tv/unknown?name=Superman&year=2025'), CountryCode.en, 'Superman (2025)')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('primebox Superman', async () => {
|
||||
expect(await extractorRegistry.handle(ctx, new URL('https://backend.xprime.tv/primebox?name=Superman&year=2025'), CountryCode.en, 'Superman (2025)')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('primebox Alien: Earth', async () => {
|
||||
expect(await extractorRegistry.handle(ctx, new URL('https://backend.xprime.tv/primebox?name=Alien%3A%20Earth&year=2025&season=1&episode=1'), CountryCode.en, 'Alien: Earth')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('primebox not found', async () => {
|
||||
expect(await extractorRegistry.handle(ctx, new URL('https://backend.xprime.tv/primebox?name=Jurassic%20World%20Rebirth&year=2025'), CountryCode.en, 'Jurassic World Rebirth (2025)')).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
60
src/extractor/XPrime.ts
Normal file
60
src/extractor/XPrime.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { Context, CountryCode, Format, UrlResult } from '../types';
|
||||
import { Fetcher } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
interface XPrimePrimeboxResponsePartial {
|
||||
streams: Record<string, string>;
|
||||
}
|
||||
|
||||
export class XPrime extends Extractor {
|
||||
public readonly id = 'xprime';
|
||||
|
||||
public readonly label = 'XPrime';
|
||||
|
||||
public override readonly ttl: number = 10800000; // 3h
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
public constructor(fetcher: Fetcher) {
|
||||
super();
|
||||
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public supports(_ctx: Context, url: URL): boolean {
|
||||
return null !== url.host.match(/xprime/);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode, title: string | undefined): Promise<UrlResult[]> {
|
||||
const urlResults: UrlResult[] = [];
|
||||
|
||||
const referer = url.protocol + '//' + url.hostname.split('.').slice(-2).join('.'); // Strip subdomains
|
||||
|
||||
if (url.href.includes('primebox')) {
|
||||
const jsonResponse = JSON.parse(await this.fetcher.text(ctx, url)) as XPrimePrimeboxResponsePartial;
|
||||
|
||||
for (const [resolution, stream] of Object.entries(jsonResponse.streams)) {
|
||||
const url = new URL(stream);
|
||||
|
||||
urlResults.push({
|
||||
url,
|
||||
format: Format.mp4,
|
||||
label: `${this.label} Primebox`,
|
||||
sourceId: `${this.id}_${countryCode}_primebox`,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
countryCodes: [countryCode],
|
||||
bytes: parseInt((await this.fetcher.head(ctx, url, { headers: { Referer: referer }, minCacheTtl: this.ttl }))['content-length'] as string),
|
||||
height: parseInt(resolution),
|
||||
title: `${title}`,
|
||||
},
|
||||
requestHeaders: {
|
||||
Referer: referer,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return urlResults;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"accept-ranges":"bytes","access-control-allow-methods":"*","access-control-allow-origin":"https://xprime.tv","age":"189968","ali-swift-global-savetime":"1755063340","alt-svc":"h3=\":443\"; ma=86400","cache-control":"public, max-age=31536000, immutable","cdn-cache-control":"public, max-age=31536000, immutable","cf-cache-status":"MISS","cf-ray":"96f7f793caffd26c-FRA","connection":"close","content-disposition":"attachment;filename=Alien: Earth-S1E1-480P.mp4","content-length":"420170402","content-type":"video/mp4","date":"Fri, 15 Aug 2025 10:21:48 GMT","eagleid":"2ff617a417552533081123028e","etag":"\"C6A45A0457EDA758D7DF7576FF2FDB1C-12\"","last-modified":"Wed, 13 Aug 2025 05:30:23 GMT","nel":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}","report-to":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=iK6KXy00H4dsUV65PssAn7rKLgvq2C2cak5DPDyN0R%2BpG8MpU3RJIVMrmmf4Ux79jlRKXxBT3S%2Bjp210eZLTAkruPkqJBbm%2BRgrYNXnjwBaTOkkKhDwZC3Hdb6OKpX0sbnvb2YXyqsTpQ0786Z35AARB6RaQhms%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}","server":"cloudflare","server-timing":"cfL4;desc=\"?proto=TCP&rtt=0&min_rtt=0&rtt_var=0&sent=0&recv=0&lost=0&retrans=0&sent_bytes=0&recv_bytes=0&delivery_rate=0&cwnd=0&unsent_bytes=0&cid=2581445feac3607a&ts=721&x=0\"","timing-allow-origin":"*","vary":"Accept-Encoding","via":"ens-cache30.l2us4[160,160,206-0,M], ens-cache20.l2us4[161,0], ens-cache15.us22[0,0,200-0,H], ens-cache16.us22[5,0]","x-cache":"HIT TCP_HIT dirn:11:315619406 mlen:0","x-oss-cdn-auth":"success","x-oss-hash-crc64ecma":"16834050796546943518","x-oss-object-type":"Multipart","x-oss-request-id":"689C242CA5D3D93034286C85","x-oss-server-time":"8","x-oss-storage-class":"Standard","x-swift-cachetime":"31104000","x-swift-savetime":"Wed, 13 Aug 2025 05:35:40 GMT"}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"accept-ranges":"bytes","access-control-allow-methods":"*","access-control-allow-origin":"https://xprime.tv","age":"199101","ali-swift-global-savetime":"1755054206","alt-svc":"h3=\":443\"; ma=86400","cache-control":"public, max-age=31536000, immutable","cdn-cache-control":"public, max-age=31536000, immutable","cf-cache-status":"MISS","cf-ray":"96f7f7937a70d26c-FRA","connection":"close","content-disposition":"attachment;filename=Alien: Earth-S1E1-1080P.mp4","content-length":"871281904","content-type":"video/mp4","date":"Fri, 15 Aug 2025 10:21:47 GMT","eagleid":"a3b5fea017552533074354078e","etag":"\"A916E682B7AC6E06B851A8C778FECF87-51\"","last-modified":"Wed, 13 Aug 2025 03:03:24 GMT","nel":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}","report-to":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=4VKbB%2B%2BCwOuVnc8rJR1AXcYR6yksEpmK1RNI5BXUt0EZW5HhZwtdvOVk%2BOdtenwt492cI5myJvdekV2GKA78Pz17V%2FMTLSCnaBXkfFKttbLfmdXxKL51w6dBncXMmq3J1rvW%2BlDBLMxqtMlvN%2FXNMlkJdZXScSc%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}","server":"cloudflare","server-timing":"cfL4;desc=\"?proto=TCP&rtt=0&min_rtt=0&rtt_var=0&sent=0&recv=0&lost=0&retrans=0&sent_bytes=0&recv_bytes=0&delivery_rate=0&cwnd=0&unsent_bytes=0&cid=eb4294c1b3c9cfec&ts=40&x=0\"","timing-allow-origin":"*","vary":"Accept-Encoding","via":"ens-cache12.l2de3[19,19,206-0,M], ens-cache2.l2de3[386,0], ens-cache5.de10[0,0,200-0,H], ens-cache12.de10[3,0]","x-cache":"HIT TCP_MEM_HIT dirn:-2:-2 mlen:0","x-oss-cdn-auth":"success","x-oss-hash-crc64ecma":"11633186024771853813","x-oss-object-type":"Multipart","x-oss-request-id":"689C007E989F153439D3D9E1","x-oss-server-time":"16","x-oss-storage-class":"Standard","x-swift-cachetime":"31104000","x-swift-savetime":"Wed, 13 Aug 2025 03:03:26 GMT"}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"accept-ranges":"bytes","access-control-allow-methods":"*","access-control-allow-origin":"https://xprime.tv","age":"5442571","ali-swift-global-savetime":"1749810736","alt-svc":"h3=\":443\"; ma=86400","cache-control":"public, max-age=31536000, immutable","cdn-cache-control":"public, max-age=31536000, immutable","cf-cache-status":"MISS","cf-ray":"96f7f790ed31d26c-FRA","connection":"close","content-disposition":"attachment;filename=Superman.mp4","content-length":"896638128","content-type":"video/mp4","date":"Fri, 15 Aug 2025 10:21:47 GMT","eagleid":"a3b5fea317552533071221673e","etag":"\"E273E5E2EA0F4F351EE597E014D3EDEE-3\"","last-modified":"Thu, 01 Jun 2023 12:10:55 GMT","nel":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}","report-to":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=MPOgJvCX2NGVXvLVAkL9Do%2BXxQJB6Z2j1%2FaClvju88VXQvlO21PTiMZaPtnjIorRafTOREYJ9Y8892ZJkQ38oV5%2BNFcJSUfJQo8hY0Kv3rPPrNYWZBYMFGqgQhOxIk3dsBiowMrb22BRG6cgPv3UGjW4cCxuEoc%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}","server":"cloudflare","server-timing":"cfL4;desc=\"?proto=TCP&rtt=0&min_rtt=0&rtt_var=0&sent=0&recv=0&lost=0&retrans=0&sent_bytes=0&recv_bytes=0&delivery_rate=0&cwnd=0&unsent_bytes=0&cid=503c8ba5bfeda5bc&ts=125&x=0\"","timing-allow-origin":"*","vary":"Accept-Encoding","via":"ens-cache1.l2de3[0,0,206-0,H], ens-cache5.l2de3[1,0], ens-cache13.de10[0,0,200-0,H], ens-cache15.de10[4,0]","x-cache":"HIT TCP_MEM_HIT dirn:-2:-2 mlen:0","x-oss-cdn-auth":"success","x-oss-hash-crc64ecma":"4771098201880069728","x-oss-object-type":"Multipart","x-oss-qos-delay-time":"1426548","x-oss-request-id":"684BFE2F2547D43238F66A0F","x-oss-server-time":"4","x-oss-storage-class":"Standard","x-swift-cachetime":"30538308","x-swift-savetime":"Thu, 19 Jun 2025 23:40:28 GMT"}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"accept-ranges":"bytes","access-control-allow-methods":"*","access-control-allow-origin":"https://xprime.tv","age":"1163","ali-swift-global-savetime":"1749411183","alt-svc":"h3=\":443\"; ma=86400","cache-control":"public, max-age=31536000, immutable","cdn-cache-control":"public, max-age=31536000, immutable","cf-cache-status":"HIT","cf-ray":"96f7f7909ca9d26c-FRA","connection":"close","content-disposition":"attachment;filename=Superman.mp4","content-length":"401394599","content-type":"video/mp4","date":"Fri, 15 Aug 2025 10:21:47 GMT","eagleid":"a3b5fea617552521434468697e","etag":"\"0F8C23B2BD3CC7F6BA6379E8354B0F84\"","last-modified":"Thu, 17 Nov 2022 00:30:11 GMT","nel":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}","report-to":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=5FtQGStEmGWQDt5%2FJ9tfbv6%2FV8Zu7qy7b%2BnLU%2BdVqv7ojoP7bEtRJ%2BXY5xpTmWTFuzFVroRhqPLEb873RCU60Jhc7iZhZDhLPISYsqnek%2BDvftzT96Fv9Yk1tQQxDL2pm%2BpAlnZfAD8D4cW%2BEQ4ofLszBL1YaTs%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}","server":"cloudflare","server-timing":"cfL4;desc=\"?proto=TCP&rtt=0&min_rtt=0&rtt_var=0&sent=0&recv=0&lost=0&retrans=0&sent_bytes=0&recv_bytes=0&delivery_rate=0&cwnd=0&unsent_bytes=0&cid=2e26c3ffa922ad37&ts=31&x=0\"","timing-allow-origin":"*","vary":"Accept-Encoding","via":"ens-cache8.l2de3[0,0,206-0,H], ens-cache12.l2de3[3,0], ens-cache17.de10[0,0,200-0,H], ens-cache18.de10[7,0]","x-cache":"HIT TCP_MEM_HIT dirn:-2:-2 mlen:0","x-oss-cdn-auth":"success","x-oss-hash-crc64ecma":"4264950399079041808","x-oss-object-type":"Normal","x-oss-request-id":"6845E56FB7AA223534E03B81","x-oss-server-time":"27","x-oss-storage-class":"Standard","x-swift-cachetime":"30691545","x-swift-savetime":"Fri, 13 Jun 2025 14:07:18 GMT"}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
|||
{"available_qualities":[],"has_subtitles":false,"message":"No exact match found for Jurassic World Rebirth (2025)","status":"not_found","streams":{},"subtitles":[]}
|
||||
1
src/extractor/__fixtures__/XPrime/https:backend.xprime.tvprimeboxnameSupermanandyear2025
generated
Normal file
1
src/extractor/__fixtures__/XPrime/https:backend.xprime.tvprimeboxnameSupermanandyear2025
generated
Normal file
File diff suppressed because one or more lines are too long
87
src/extractor/__snapshots__/XPrime.test.ts.snap
Normal file
87
src/extractor/__snapshots__/XPrime.test.ts.snap
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`XPrime primebox Alien: Earth 1`] = `
|
||||
[
|
||||
{
|
||||
"format": "mp4",
|
||||
"label": "XPrime Primebox",
|
||||
"meta": {
|
||||
"bytes": 871281904,
|
||||
"countryCodes": [
|
||||
"en",
|
||||
],
|
||||
"height": 1080,
|
||||
"title": "Alien: Earth",
|
||||
},
|
||||
"requestHeaders": {
|
||||
"Referer": "https://xprime.tv",
|
||||
},
|
||||
"sourceId": "xprime_en_primebox",
|
||||
"ttl": 10800000,
|
||||
"url": "https://oca.flutch09.workers.dev/?v=cenBDs9Hbnv6PuXYzNUtVR2ZZ2YtmVtQIt6JqHB1dsbz2Y%2BXC9UwPurnE%2BQNk27Yr1WeYeLOOazAnSL8cU0DvVfg4pwKsjHKWIJICiVlvv9ndXII0bR7eaIi%2B11NbAj72pFFryHZjO6MkMKEJJnF4G%2BH1BXIO1ALds7J1A7gj2vc7DbUWL8kPxwH1rMw7NAys20M5s3PsbhgSrMpguZSBm8X&headers=%7B%22origin%22%3A%22https%3A%2F%2Fmoviebox.ng%22%2C%22referer%22%3A%22https%3A%2F%2Fmoviebox.ng%22%7D&safe",
|
||||
},
|
||||
{
|
||||
"format": "mp4",
|
||||
"label": "XPrime Primebox",
|
||||
"meta": {
|
||||
"bytes": 420170402,
|
||||
"countryCodes": [
|
||||
"en",
|
||||
],
|
||||
"height": 480,
|
||||
"title": "Alien: Earth",
|
||||
},
|
||||
"requestHeaders": {
|
||||
"Referer": "https://xprime.tv",
|
||||
},
|
||||
"sourceId": "xprime_en_primebox",
|
||||
"ttl": 10800000,
|
||||
"url": "https://oca.flutch09.workers.dev/?v=oS2n5QbXtpa%2BWXMpIIi0SqeqadEyYEAg6AmHvpTa3jzooh6zxINciUJrR%2B6b1xLZtxbnbAM3mrGGXOa5yckYkNSC%2BKGEFSdofXw298vq3ssHpI9LBN6XLvhtxnDfmub0QoMG%2Fkvgjhb8T%2FwiCHo9NeSX%2FetW6ANppW9jhZn0Hv3hsWdmES1jqj6nfIjQ1ur53htjr2vF7mZbZSsJ&headers=%7B%22origin%22%3A%22https%3A%2F%2Fmoviebox.ng%22%2C%22referer%22%3A%22https%3A%2F%2Fmoviebox.ng%22%7D&safe",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`XPrime primebox Superman 1`] = `
|
||||
[
|
||||
{
|
||||
"format": "mp4",
|
||||
"label": "XPrime Primebox",
|
||||
"meta": {
|
||||
"bytes": 401394599,
|
||||
"countryCodes": [
|
||||
"en",
|
||||
],
|
||||
"height": 480,
|
||||
"title": "Superman (2025)",
|
||||
},
|
||||
"requestHeaders": {
|
||||
"Referer": "https://xprime.tv",
|
||||
},
|
||||
"sourceId": "xprime_en_primebox",
|
||||
"ttl": 10800000,
|
||||
"url": "https://oca.flutch09.workers.dev/?v=3RVZDNxcKNs6%2BqcdL1bDCgq9Yp1iPYqb6a9yToLq66vlzu08R1Hz7jiKx4OBH6YzJBcK7skuiDGDwIpro78ReVjMLtMHCfa0fBo0aJ9RYULOUMkLrZxjzSTXvo5Jss1Jiss8e9Z8pFdlC1VqwAUm6G9mx0u41dFLJ0GTJrwCesPe4zflbL8I76WkWYKBMT2MwHvDTIO4r3V0nf8BsRswsNJZ&headers=%7B%22origin%22%3A%22https%3A%2F%2Fmoviebox.ng%22%2C%22referer%22%3A%22https%3A%2F%2Fmoviebox.ng%22%7D&safe",
|
||||
},
|
||||
{
|
||||
"format": "mp4",
|
||||
"label": "XPrime Primebox",
|
||||
"meta": {
|
||||
"bytes": 896638128,
|
||||
"countryCodes": [
|
||||
"en",
|
||||
],
|
||||
"height": 720,
|
||||
"title": "Superman (2025)",
|
||||
},
|
||||
"requestHeaders": {
|
||||
"Referer": "https://xprime.tv",
|
||||
},
|
||||
"sourceId": "xprime_en_primebox",
|
||||
"ttl": 10800000,
|
||||
"url": "https://oca.flutch09.workers.dev/?v=gUbhHOwpFIqajH6NnoH%2BYE9AWORUUogamkdYQedBfKi5eQtyniWtxmI1%2B5Swyl1ThC6vM0qHl53s0Q7j%2BDaWFhVRJQL%2BJRxbuOL1iCz1w5xVPLDU%2FTJ3zhf9EbULPGbbee14kdNYNc5%2FlF2sNe6RiUupsvhlj%2BjcgsT8uypX%2BudVyw1jVEUVogufPnc0lSrfoE98IZlOgdjBZKE3%2Fcw3erD2&headers=%7B%22origin%22%3A%22https%3A%2F%2Fmoviebox.ng%22%2C%22referer%22%3A%22https%3A%2F%2Fmoviebox.ng%22%7D&safe",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`XPrime primebox not found 1`] = `[]`;
|
||||
|
||||
exports[`XPrime unknown backend is ignored 1`] = `[]`;
|
||||
|
|
@ -14,6 +14,7 @@ import { SuperVideo } from './SuperVideo';
|
|||
import { Uqload } from './Uqload';
|
||||
import { VidSrc } from './VidSrc';
|
||||
import { VixSrc } from './VixSrc';
|
||||
import { XPrime } from './XPrime';
|
||||
|
||||
export * from './Extractor';
|
||||
export * from './ExtractorRegistry';
|
||||
|
|
@ -32,5 +33,6 @@ export const createExtractors = (fetcher: Fetcher): Extractor[] => [
|
|||
new Uqload(fetcher),
|
||||
new VidSrc(fetcher, ['in', 'pm', 'net', 'xyz', 'io', 'vc']), // https://vidsrc.domains/
|
||||
new VixSrc(fetcher),
|
||||
new XPrime(fetcher),
|
||||
new ExternalUrl(fetcher), // fallback extractor which must come last
|
||||
];
|
||||
|
|
|
|||
23
src/source/XPrime.test.ts
Normal file
23
src/source/XPrime.test.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { createTestContext } from '../test';
|
||||
import { FetcherMock, TmdbId } from '../utils';
|
||||
import { XPrime } from './XPrime';
|
||||
|
||||
const ctx = createTestContext();
|
||||
|
||||
describe('XPrime', () => {
|
||||
let handler: XPrime;
|
||||
|
||||
beforeEach(() => {
|
||||
handler = new XPrime(new FetcherMock(`${__dirname}/__fixtures__/XPrime`));
|
||||
});
|
||||
|
||||
test('handle alien: earth 1x1', async () => {
|
||||
const streams = await handler.handle(ctx, 'series', new TmdbId(157239, 1, 1));
|
||||
expect(streams).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('handle superman', async () => {
|
||||
const streams = await handler.handle(ctx, 'series', new TmdbId(1061474, undefined, undefined));
|
||||
expect(streams).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
42
src/source/XPrime.ts
Normal file
42
src/source/XPrime.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 './types';
|
||||
|
||||
export class XPrime implements Source {
|
||||
public readonly id = 'xprime';
|
||||
|
||||
public readonly label = 'XPrime';
|
||||
|
||||
public readonly contentTypes: ContentType[] = ['movie', 'series'];
|
||||
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.en];
|
||||
|
||||
public readonly baseUrl = 'https://backend.xprime.tv';
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public async handle(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);
|
||||
|
||||
if (tmdbId.season) {
|
||||
const title = `${name} ${tmdbId.season}x${tmdbId.episode}`;
|
||||
|
||||
const urlPrimebox = new URL(`/primebox?name=${encodeURIComponent(name)}&year=${year}&season=${tmdbId.season}&episode=${tmdbId.episode}`, this.baseUrl);
|
||||
|
||||
return [{ countryCode: CountryCode.en, title, url: urlPrimebox }];
|
||||
}
|
||||
|
||||
const title = `${name} (${year})`;
|
||||
|
||||
const urlPrimebox = new URL(`/primebox?name=${encodeURIComponent(name)}&year=${year}`, this.baseUrl);
|
||||
|
||||
return [{ countryCode: CountryCode.en, title, url: urlPrimebox }];
|
||||
};
|
||||
}
|
||||
1
src/source/__fixtures__/XPrime/https:api.themoviedb.org3movie1061474
generated
Normal file
1
src/source/__fixtures__/XPrime/https:api.themoviedb.org3movie1061474
generated
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"adult":false,"backdrop_path":"/eU7IfdWq8KQy0oNd4kKXS0QUR08.jpg","belongs_to_collection":null,"budget":225000000,"genres":[{"id":878,"name":"Science Fiction"},{"id":12,"name":"Adventure"},{"id":28,"name":"Action"}],"homepage":"https://www.superman.com","id":1061474,"imdb_id":"tt5950044","origin_country":["US"],"original_language":"en","original_title":"Superman","overview":"Superman, a journalist in Metropolis, embarks on a journey to reconcile his Kryptonian heritage with his human upbringing as Clark Kent.","popularity":168.8676,"poster_path":"/ombsmhYUqR4qqOLOxAyr5V8hbyv.jpg","production_companies":[{"id":184898,"logo_path":"/2Z2hiM1ERqFOWRxNxWoJZ8lTxhb.png","name":"DC Studios","origin_country":"US"},{"id":94218,"logo_path":"/kxuhS8wyKtVprOn5nckdHyNuSg1.png","name":"Troll Court Entertainment","origin_country":"US"},{"id":11565,"logo_path":"/odU3l6csuBmXUrzFm6araUgEUHQ.png","name":"The Safran 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-07-09","revenue":581086143,"runtime":130,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"}],"status":"Released","tagline":"Look up.","title":"Superman","video":false,"vote_average":7.7,"vote_count":1684}
|
||||
1
src/source/__fixtures__/XPrime/https:api.themoviedb.org3tv157239
generated
Normal file
1
src/source/__fixtures__/XPrime/https:api.themoviedb.org3tv157239
generated
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"adult":false,"backdrop_path":"/25g7mthXoJFcNZhAKz0evk17Bsx.jpg","created_by":[{"id":202816,"credit_id":"620bdfc73e01ea002b2f90b1","name":"Noah Hawley","original_name":"Noah Hawley","gender":2,"profile_path":"/pxVP1lywEBA9y8x5Xe3kM7m4ai3.jpg"}],"episode_run_time":[],"first_air_date":"2025-08-12","genres":[{"id":10765,"name":"Sci-Fi & Fantasy"},{"id":18,"name":"Drama"}],"homepage":"https://www.fxnetworks.com/shows/alien-earth","id":157239,"in_production":true,"languages":["en"],"last_air_date":"2025-08-12","last_episode_to_air":{"id":6231083,"name":"Mr. October","overview":"Tensions rise between rival corporations, a reunion takes place, and a secret is revealed.","vote_average":8.5,"vote_count":10,"air_date":"2025-08-12","episode_number":2,"episode_type":"standard","production_code":"XWYV1002","runtime":56,"season_number":1,"show_id":157239,"still_path":"/hZclNGZx4pjOx6MNdJfTZid113f.jpg"},"name":"Alien: Earth","next_episode_to_air":{"id":6231084,"name":"Metamorphosis","overview":"The team returns home with unexpected cargo. An unsettling experiment occurs, and a new talent is discovered.","vote_average":0.0,"vote_count":0,"air_date":"2025-08-19","episode_number":3,"episode_type":"standard","production_code":"","runtime":54,"season_number":1,"show_id":157239,"still_path":null},"networks":[{"id":88,"logo_path":"/aexGjtcs42DgRtZh7zOxayiry4J.png","name":"FX","origin_country":"US"},{"id":453,"logo_path":"/pqUTCleNUiTLAVlelGxUgWn1ELh.png","name":"Hulu","origin_country":"US"}],"number_of_episodes":8,"number_of_seasons":1,"origin_country":["US"],"original_language":"en","original_name":"Alien: Earth","overview":"When the mysterious deep space research vessel USCSS Maginot crash-lands on Earth, Wendy and a ragtag group of tactical soldiers make a fateful discovery that puts them face-to-face with the planet's greatest threat.","popularity":395.6075,"poster_path":"/yueXS3q8BtoWekcHOATFHicLl3e.jpg","production_companies":[{"id":15990,"logo_path":"/5cT4zwHA66uNAr2p3CcBDLddXu2.png","name":"FX Productions","origin_country":"US"},{"id":221347,"logo_path":"/6Ry6uNBaa0IbbSs1XYIgX5DkA9r.png","name":"Scott Free Productions","origin_country":"US"},{"id":20814,"logo_path":null,"name":"26 Keys Productions","origin_country":"US"}],"production_countries":[{"iso_3166_1":"US","name":"United States of America"}],"seasons":[{"air_date":null,"episode_count":2,"id":469846,"name":"Specials","overview":"","poster_path":null,"season_number":0,"vote_average":0.0},{"air_date":"2025-08-12","episode_count":8,"id":243129,"name":"Season 1","overview":"As members of the crash recovery crew search for survivors among the wreckage of a mysterious crashed space vessel, they encounter mysterious predatory life forms more terrifying than they could have ever imagined.With this new threat unlocked, the search crew must fight for survival and what they choose to do with this discovery could change planet Earth as they know it.","poster_path":"/dJ7lUdzZ98AlhZ38BpfG6jy3UDa.jpg","season_number":1,"vote_average":8.3}],"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"}],"status":"Returning Series","tagline":"We were safer in space.","type":"Scripted","vote_average":8.26,"vote_count":96}
|
||||
21
src/source/__snapshots__/XPrime.test.ts.snap
Normal file
21
src/source/__snapshots__/XPrime.test.ts.snap
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`XPrime handle alien: earth 1x1 1`] = `
|
||||
[
|
||||
{
|
||||
"countryCode": "en",
|
||||
"title": "Alien: Earth 1x1",
|
||||
"url": "https://backend.xprime.tv/primebox?name=Alien%3A%20Earth&year=2025&season=1&episode=1",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`XPrime handle superman 1`] = `
|
||||
[
|
||||
{
|
||||
"countryCode": "en",
|
||||
"title": "Superman (2025)",
|
||||
"url": "https://backend.xprime.tv/primebox?name=Superman&year=2025",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
|
@ -16,6 +16,7 @@ import { Source } from './types';
|
|||
import { VerHdLink } from './VerHdLink';
|
||||
import { VidSrc } from './VidSrc';
|
||||
import { VixSrc } from './VixSrc';
|
||||
import { XPrime } from './XPrime';
|
||||
|
||||
export * from './types';
|
||||
|
||||
|
|
@ -26,6 +27,7 @@ export const createSources = (fetcher: Fetcher): Source[] => [
|
|||
new PrimeWire(fetcher),
|
||||
new Soaper(fetcher),
|
||||
new VidSrc(fetcher),
|
||||
new XPrime(fetcher),
|
||||
// ES / MX
|
||||
new CineHDPlus(fetcher),
|
||||
new Cuevana(fetcher),
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ exports[`buildManifest default manifest 1`] = `
|
|||
},
|
||||
{
|
||||
"key": "en",
|
||||
"title": "English 🇺🇸 (PrimeWire, Soaper, VidSrc, VixSrc)",
|
||||
"title": "English 🇺🇸 (PrimeWire, Soaper, VidSrc, VixSrc, XPrime)",
|
||||
"type": "checkbox",
|
||||
},
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue