flixhq scraping improved

This commit is contained in:
frost768 2023-03-12 13:57:01 +03:00
parent 9bba47575a
commit 051c1ba709
3 changed files with 89 additions and 25 deletions

View File

@ -10,9 +10,11 @@ export enum MWCaptionType {
export enum MWStreamQuality {
Q360P = "360p",
Q540P = "540p",
Q480P = "480p",
Q720P = "720p",
Q1080P = "1080p",
QAUTO = "auto",
QUNKNOWN = "unknown",
}

View File

@ -1,7 +1,11 @@
import { compareTitle } from "@/utils/titleMatch";
import { proxiedFetch } from "../helpers/fetch";
import { registerProvider } from "../helpers/register";
import { MWStreamQuality, MWStreamType } from "../helpers/streams";
import {
MWCaptionType,
MWStreamQuality,
MWStreamType,
} from "../helpers/streams";
import { MWMediaType } from "../metadata/types";
// const flixHqBase = "https://api.consumet.org/movies/flixhq";
@ -9,13 +13,52 @@ import { MWMediaType } from "../metadata/types";
// SEE ISSUE: https://github.com/consumet/api.consumet.org/issues/326
const flixHqBase = "https://c.delusionz.xyz/movies/flixhq";
interface FLIXMediaBase {
id: number;
title: string;
url: string;
image: string;
}
interface FLIXTVSerie extends FLIXMediaBase {
type: "TV Series";
seasons: number;
}
interface FLIXMovie extends FLIXMediaBase {
type: "Movie";
releaseDate: number;
}
function castSubtitles({ url, lang }: { url: string; lang: string }) {
return {
url,
langIso: lang,
type:
url.substring(url.length - 3) === "vtt"
? MWCaptionType.VTT
: MWCaptionType.SRT,
};
}
const qualityMap: Record<string, MWStreamQuality> = {
"360": MWStreamQuality.Q360P,
"540": MWStreamQuality.Q540P,
"480": MWStreamQuality.Q480P,
"720": MWStreamQuality.Q720P,
"1080": MWStreamQuality.Q1080P,
};
registerProvider({
id: "flixhq",
displayName: "FlixHQ",
rank: 100,
type: [MWMediaType.MOVIE],
type: [MWMediaType.MOVIE, MWMediaType.SERIES],
async scrape({ media, progress }) {
if (!this.type.includes(media.meta.type)) {
throw new Error("Unsupported type");
}
// search for relevant item
const searchResults = await proxiedFetch<any>(
`/${encodeURIComponent(media.meta.title)}`,
@ -23,11 +66,22 @@ registerProvider({
baseURL: flixHqBase,
}
);
const foundItem = searchResults.results.find((v: any) => {
return (
compareTitle(v.title, media.meta.title) &&
v.releaseDate === media.meta.year
);
const foundItem = searchResults.results.find((v: FLIXMediaBase) => {
if (media.meta.type === MWMediaType.MOVIE) {
const movie = v as FLIXMovie;
return (
compareTitle(movie.title, media.meta.title) &&
movie.releaseDate === Number(media.meta.year)
);
}
const serie = v as FLIXTVSerie;
if (media.meta.seasons) {
return (
compareTitle(serie.title, media.meta.title) &&
serie.seasons === Number(media.meta.seasons.length)
);
}
return compareTitle(serie.title, media.meta.title);
});
if (!foundItem) throw new Error("No watchable item found");
const flixId = foundItem.id;
@ -51,18 +105,23 @@ registerProvider({
},
});
if (!watchInfo.sources) {
throw new Error("No watchable item found");
}
// get best quality source
const source = watchInfo.sources.reduce((p: any, c: any) =>
c.quality > p.quality ? c : p
);
// comes sorted by quality in descending order
const source = watchInfo.sources[0];
return {
embeds: [],
stream: {
streamUrl: source.url,
quality: MWStreamQuality.QUNKNOWN,
quality: qualityMap[source.quality],
type: source.isM3U8 ? MWStreamType.HLS : MWStreamType.MP4,
captions: [],
captions: watchInfo.subtitles
.filter(
(x: { url: string; lang: string }) => !x.lang.includes("(maybe)")
)
.map(castSubtitles),
},
};
},

View File

@ -9,13 +9,13 @@ import { MWMediaType } from "../metadata/types";
const netfilmBase = "https://net-film.vercel.app";
const qualityMap = {
"360": MWStreamQuality.Q360P,
"480": MWStreamQuality.Q480P,
"720": MWStreamQuality.Q720P,
"1080": MWStreamQuality.Q1080P,
const qualityMap: Record<number, MWStreamQuality> = {
360: MWStreamQuality.Q360P,
540: MWStreamQuality.Q540P,
480: MWStreamQuality.Q480P,
720: MWStreamQuality.Q720P,
1080: MWStreamQuality.Q1080P,
};
type QualityInMap = keyof typeof qualityMap;
registerProvider({
id: "netfilm",
@ -24,6 +24,9 @@ registerProvider({
type: [MWMediaType.MOVIE, MWMediaType.SERIES],
async scrape({ media, episode, progress }) {
if (!this.type.includes(media.meta.type)) {
throw new Error("Unsupported type");
}
// search for relevant item
const searchResponse = await proxiedFetch<any>(
`/api/search?keyword=${encodeURIComponent(media.meta.title)}`,
@ -54,8 +57,8 @@ registerProvider({
const data = watchInfo.data;
// get best quality source
const source = data.qualities.reduce((p: any, c: any) =>
c.quality > p.quality ? c : p
const source: { url: string; quality: number } = data.qualities.reduce(
(p: any, c: any) => (c.quality > p.quality ? c : p)
);
const mappedCaptions = data.subtitles.map((sub: Record<string, any>) => ({
@ -71,7 +74,7 @@ registerProvider({
streamUrl: source.url
.replace("akm-cdn", "aws-cdn")
.replace("gg-cdn", "aws-cdn"),
quality: qualityMap[source.quality as QualityInMap],
quality: qualityMap[source.quality],
type: MWStreamType.HLS,
captions: mappedCaptions,
},
@ -124,8 +127,8 @@ registerProvider({
const data = episodeStream.data;
// get best quality source
const source = data.qualities.reduce((p: any, c: any) =>
c.quality > p.quality ? c : p
const source: { url: string; quality: number } = data.qualities.reduce(
(p: any, c: any) => (c.quality > p.quality ? c : p)
);
const mappedCaptions = data.subtitles.map((sub: Record<string, any>) => ({
@ -141,7 +144,7 @@ registerProvider({
streamUrl: source.url
.replace("akm-cdn", "aws-cdn")
.replace("gg-cdn", "aws-cdn"),
quality: qualityMap[source.quality as QualityInMap],
quality: qualityMap[source.quality],
type: MWStreamType.HLS,
captions: mappedCaptions,
},