webstreamr-github/src/extractor/Soaper.ts
WebStreamr 1b9ee36cfd
revert: "chore: remove Soaper 😭" 🎉
This reverts commit df60013e16.
2025-07-17 07:56:54 +00:00

67 lines
1.9 KiB
TypeScript

import { Context, CountryCode, Format, UrlResult } from '../types';
import { Fetcher, guessHeightFromPlaylist } from '../utils';
import { Extractor } from './Extractor';
interface SoaperInfoResponsePartial {
val: string;
val_bak: string;
}
export class Soaper extends Extractor {
public readonly id = 'soaper';
public readonly label = 'Soaper';
private readonly fetcher: Fetcher;
public constructor(fetcher: Fetcher) {
super();
this.fetcher = fetcher;
}
public supports(_ctx: Context, url: URL): boolean {
return null !== url.host.match(/soaper/) && null !== url.pathname.match(/^\/(episode|movie)_/);
}
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode, title: string | undefined): Promise<UrlResult[]> {
const movieOrEpisodeId = (url.pathname.match(/\/\w+_(\w+)/) as string[])[1] as string;
const form = new URLSearchParams();
form.append('pass', movieOrEpisodeId);
form.append('param', '');
form.append('extra', '');
form.append('e2', '');
form.append('server', '0');
const response = await this.fetcher.textPost(
ctx,
new URL(url.pathname.includes('episode') ? '/home/index/GetEInfoAjax' : '/home/index/GetMInfoAjax', url.origin),
form.toString(),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': url.origin,
},
},
);
const jsonResponse = JSON.parse(response) as SoaperInfoResponsePartial;
const m3u8Url = new URL(jsonResponse['val'], url.origin);
return [
{
url: m3u8Url,
format: Format.hls,
label: this.label,
sourceId: `${this.id}_${countryCode}`,
ttl: this.ttl,
meta: {
countryCodes: [countryCode],
height: await guessHeightFromPlaylist(ctx, this.fetcher, m3u8Url),
title: `${title}`,
},
},
];
};
}