Add flixhq shows

This commit is contained in:
2023-09-27 22:49:22 -05:00
parent 2799708992
commit 3c292baf26
8 changed files with 129 additions and 34 deletions

View File

@@ -183,7 +183,7 @@ async function runScraper(providers: ProviderControls, source: MetaOutput, optio
id: source.id,
});
spinnies.succeed('scrape', { text: 'Done!' });
console.log(result);
console.log(JSON.stringify(result, null, 2));
} catch (error) {
let message = 'Unknown error';
if (error instanceof Error) {
@@ -208,7 +208,7 @@ async function runScraper(providers: ProviderControls, source: MetaOutput, optio
id: source.id,
});
spinnies.succeed('scrape', { text: 'Done!' });
console.log(result);
console.log(JSON.stringify(result, null, 2));
} catch (error) {
let message = 'Unknown error';
if (error instanceof Error) {

View File

@@ -15,10 +15,27 @@ export const flixhqScraper = makeSourcerer({
const id = await getFlixhqId(ctx, ctx.media);
if (!id) throw new NotFoundError('no search results match');
const sources = await getFlixhqSources(ctx, id);
const sources = await getFlixhqSources(ctx, ctx.media, id);
const upcloudStream = sources.find((v) => v.embed.toLowerCase() === 'upcloud');
if (!upcloudStream) throw new NotFoundError('upcloud stream not found for flixhq');
return {
embeds: [
{
embedId: upcloudScraper.id,
url: await getFlixhqSourceDetails(ctx, upcloudStream.episodeId),
},
],
};
},
async scrapeShow(ctx) {
const id = await getFlixhqId(ctx, ctx.media);
if (!id) throw new NotFoundError('no search results match');
const sources = await getFlixhqSources(ctx, ctx.media, id);
const upcloudStream = sources.find((v) => v.embed.toLowerCase() === 'server upcloud');
if (!upcloudStream) throw new NotFoundError('upcloud stream not found for flixhq');
return {
embeds: [
{

View File

@@ -1,16 +1,68 @@
import { load } from 'cheerio';
import { MovieMedia, ShowMedia } from '@/main/media';
import { flixHqBase } from '@/providers/sources/flixhq/common';
import { ScrapeContext } from '@/utils/context';
import { NotFoundError } from '@/utils/errors';
export async function getFlixhqSources(ctx: ScrapeContext, id: string) {
const type = id.split('/')[0];
export async function getFlixhqSources(ctx: ScrapeContext, media: MovieMedia | ShowMedia, id: string) {
const episodeParts = id.split('-');
const episodeId = episodeParts[episodeParts.length - 1];
const data = await ctx.proxiedFetcher<string>(`/ajax/${type}/episodes/${episodeId}`, {
if (media.type === 'show') {
const seasonsListData = await ctx.proxiedFetcher<string>(`/ajax/season/list/${episodeId}`, {
baseUrl: flixHqBase,
});
const seasonsDoc = load(seasonsListData);
const season = seasonsDoc('.dropdown-item')
.toArray()
.find((el) => seasonsDoc(el).text() === `Season ${media.season.number}`)?.attribs['data-id'];
if (!season) throw new NotFoundError('season not found');
const seasonData = await ctx.proxiedFetcher<string>(`/ajax/season/episodes/${season}`, {
baseUrl: flixHqBase,
});
const seasonDoc = load(seasonData);
const episode = seasonDoc('.nav-item > a')
.toArray()
.map((el) => {
return {
id: seasonDoc(el).attr('data-id'),
title: seasonDoc(el).attr('title'),
};
})
.find((e) => e.title?.startsWith(`Eps ${media.episode.number}`))?.id;
if (!episode) throw new NotFoundError('episode not found');
const data = await ctx.proxiedFetcher<string>(`/ajax/episode/servers/${episode}`, {
baseUrl: flixHqBase,
});
const doc = load(data);
const sourceLinks = doc('.nav-item > a')
.toArray()
.map((el) => {
const query = doc(el);
const embedTitle = query.attr('title');
const linkId = query.attr('data-id');
if (!embedTitle || !linkId) throw new Error('invalid sources');
return {
embed: embedTitle,
episodeId: linkId,
};
});
return sourceLinks;
}
const data = await ctx.proxiedFetcher<string>(`/ajax/movie/episodes/${episodeId}`, {
baseUrl: flixHqBase,
});
const doc = load(data);
const sourceLinks = doc('.nav-item > a')
.toArray()

View File

@@ -1,11 +1,11 @@
import { load } from 'cheerio';
import { MovieMedia } from '@/main/media';
import { MovieMedia, ShowMedia } from '@/main/media';
import { flixHqBase } from '@/providers/sources/flixhq/common';
import { compareMedia } from '@/utils/compare';
import { ScrapeContext } from '@/utils/context';
export async function getFlixhqId(ctx: ScrapeContext, media: MovieMedia): Promise<string | null> {
export async function getFlixhqId(ctx: ScrapeContext, media: MovieMedia | ShowMedia): Promise<string | null> {
const searchResults = await ctx.proxiedFetcher<string>(`/search/${media.title.replaceAll(/[^a-z0-9A-Z]/g, '-')}`, {
baseUrl: flixHqBase,
});

View File

@@ -1,12 +1,11 @@
import CryptoJS from 'crypto-js';
import { customAlphabet } from 'nanoid';
import randomBytes from 'randombytes';
import type { ScrapeContext } from '@/utils/context';
import { apiUrls, appId, appKey, key } from './common';
import { encrypt, getVerify } from './crypto';
const nanoid = customAlphabet('0123456789abcdef', 32);
const expiry = () => Math.floor(Date.now() / 1000 + 60 * 60 * 12);
export const sendRequest = async (ctx: ScrapeContext, data: object, altApi = false) => {
@@ -40,7 +39,7 @@ export const sendRequest = async (ctx: ScrapeContext, data: object, altApi = fal
formatted.append('platform', 'android');
formatted.append('version', '129');
formatted.append('medium', 'Website');
formatted.append('token', nanoid());
formatted.append('token', randomBytes(16).toString('hex'));
const requestUrl = altApi ? apiUrls[1] : apiUrls[0];

View File

@@ -12,8 +12,14 @@ export function compareTitle(a: string, b: string): boolean {
return normalizeTitle(a) === normalizeTitle(b);
}
export function compareMedia(media: CommonMedia, title: string, releaseYear?: number): boolean {
export function compareMedia(media: CommonMedia, title: string, releaseYear?: number, compareYear?: boolean): boolean {
// if no year is provided, count as if its the correct year
const isSameYear = releaseYear === undefined ? true : media.releaseYear === releaseYear;
let isSameYear: boolean;
if (!compareYear) {
isSameYear = true;
} else {
isSameYear = releaseYear === undefined ? true : media.releaseYear === releaseYear;
}
return compareTitle(media.title, title) && isSameYear;
}