Merge pull request #199 from frost768/dev

flixhq scraping improved
This commit is contained in:
mrjvs 2023-03-13 19:41:17 +01:00 committed by GitHub
commit f7d51e6d8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 26 deletions

View File

@ -10,6 +10,7 @@ export enum MWCaptionType {
export enum MWStreamQuality { export enum MWStreamQuality {
Q360P = "360p", Q360P = "360p",
Q540P = "540p",
Q480P = "480p", Q480P = "480p",
Q720P = "720p", Q720P = "720p",
Q1080P = "1080p", Q1080P = "1080p",

View File

@ -1,7 +1,11 @@
import { compareTitle } from "@/utils/titleMatch"; import { compareTitle } from "@/utils/titleMatch";
import { proxiedFetch } from "../helpers/fetch"; import { proxiedFetch } from "../helpers/fetch";
import { registerProvider } from "../helpers/register"; import { registerProvider } from "../helpers/register";
import { MWStreamQuality, MWStreamType } from "../helpers/streams"; import {
MWCaptionType,
MWStreamQuality,
MWStreamType,
} from "../helpers/streams";
import { MWMediaType } from "../metadata/types"; import { MWMediaType } from "../metadata/types";
// const flixHqBase = "https://api.consumet.org/movies/flixhq"; // 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 // SEE ISSUE: https://github.com/consumet/api.consumet.org/issues/326
const flixHqBase = "https://c.delusionz.xyz/movies/flixhq"; 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 | null;
}
interface FLIXMovie extends FLIXMediaBase {
type: "Movie";
releaseDate: string;
}
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({ registerProvider({
id: "flixhq", id: "flixhq",
displayName: "FlixHQ", displayName: "FlixHQ",
rank: 100, rank: 100,
type: [MWMediaType.MOVIE], type: [MWMediaType.MOVIE, MWMediaType.SERIES],
async scrape({ media, progress }) { async scrape({ media, progress }) {
if (!this.type.includes(media.meta.type)) {
throw new Error("Unsupported type");
}
// search for relevant item // search for relevant item
const searchResults = await proxiedFetch<any>( const searchResults = await proxiedFetch<any>(
`/${encodeURIComponent(media.meta.title)}`, `/${encodeURIComponent(media.meta.title)}`,
@ -23,11 +66,22 @@ registerProvider({
baseURL: flixHqBase, baseURL: flixHqBase,
} }
); );
const foundItem = searchResults.results.find((v: any) => { const foundItem = searchResults.results.find((v: FLIXMediaBase) => {
if (media.meta.type === MWMediaType.MOVIE) {
const movie = v as FLIXMovie;
return ( return (
compareTitle(v.title, media.meta.title) && compareTitle(movie.title, media.meta.title) &&
v.releaseDate === media.meta.year movie.releaseDate === media.meta.year
); );
}
const serie = v as FLIXTVSerie;
if (serie.seasons && media.meta.seasons) {
return (
compareTitle(serie.title, media.meta.title) &&
serie.seasons === media.meta.seasons.length
);
}
return compareTitle(serie.title, media.meta.title);
}); });
if (!foundItem) throw new Error("No watchable item found"); if (!foundItem) throw new Error("No watchable item found");
const flixId = foundItem.id; const flixId = foundItem.id;
@ -40,7 +94,7 @@ registerProvider({
id: flixId, id: flixId,
}, },
}); });
if (!mediaInfo.episodes) throw new Error("No watchable item found");
// get stream info from media // get stream info from media
progress(75); progress(75);
const watchInfo = await proxiedFetch<any>("/watch", { const watchInfo = await proxiedFetch<any>("/watch", {
@ -51,18 +105,22 @@ registerProvider({
}, },
}); });
// get best quality source if (!watchInfo.sources) throw new Error("No watchable item found");
const source = watchInfo.sources.reduce((p: any, c: any) =>
c.quality > p.quality ? c : p
);
// get best quality source
// comes sorted by quality in descending order
const source = watchInfo.sources[0];
return { return {
embeds: [], embeds: [],
stream: { stream: {
streamUrl: source.url, streamUrl: source.url,
quality: MWStreamQuality.QUNKNOWN, quality: qualityMap[source.quality],
type: source.isM3U8 ? MWStreamType.HLS : MWStreamType.MP4, 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 netfilmBase = "https://net-film.vercel.app";
const qualityMap = { const qualityMap: Record<number, MWStreamQuality> = {
"360": MWStreamQuality.Q360P, 360: MWStreamQuality.Q360P,
"480": MWStreamQuality.Q480P, 540: MWStreamQuality.Q540P,
"720": MWStreamQuality.Q720P, 480: MWStreamQuality.Q480P,
"1080": MWStreamQuality.Q1080P, 720: MWStreamQuality.Q720P,
1080: MWStreamQuality.Q1080P,
}; };
type QualityInMap = keyof typeof qualityMap;
registerProvider({ registerProvider({
id: "netfilm", id: "netfilm",
@ -24,6 +24,9 @@ registerProvider({
type: [MWMediaType.MOVIE, MWMediaType.SERIES], type: [MWMediaType.MOVIE, MWMediaType.SERIES],
async scrape({ media, episode, progress }) { async scrape({ media, episode, progress }) {
if (!this.type.includes(media.meta.type)) {
throw new Error("Unsupported type");
}
// search for relevant item // search for relevant item
const searchResponse = await proxiedFetch<any>( const searchResponse = await proxiedFetch<any>(
`/api/search?keyword=${encodeURIComponent(media.meta.title)}`, `/api/search?keyword=${encodeURIComponent(media.meta.title)}`,
@ -54,8 +57,8 @@ registerProvider({
const data = watchInfo.data; const data = watchInfo.data;
// get best quality source // get best quality source
const source = data.qualities.reduce((p: any, c: any) => const source: { url: string; quality: number } = data.qualities.reduce(
c.quality > p.quality ? c : p (p: any, c: any) => (c.quality > p.quality ? c : p)
); );
const mappedCaptions = data.subtitles.map((sub: Record<string, any>) => ({ const mappedCaptions = data.subtitles.map((sub: Record<string, any>) => ({
@ -71,7 +74,7 @@ registerProvider({
streamUrl: source.url streamUrl: source.url
.replace("akm-cdn", "aws-cdn") .replace("akm-cdn", "aws-cdn")
.replace("gg-cdn", "aws-cdn"), .replace("gg-cdn", "aws-cdn"),
quality: qualityMap[source.quality as QualityInMap], quality: qualityMap[source.quality],
type: MWStreamType.HLS, type: MWStreamType.HLS,
captions: mappedCaptions, captions: mappedCaptions,
}, },
@ -124,8 +127,8 @@ registerProvider({
const data = episodeStream.data; const data = episodeStream.data;
// get best quality source // get best quality source
const source = data.qualities.reduce((p: any, c: any) => const source: { url: string; quality: number } = data.qualities.reduce(
c.quality > p.quality ? c : p (p: any, c: any) => (c.quality > p.quality ? c : p)
); );
const mappedCaptions = data.subtitles.map((sub: Record<string, any>) => ({ const mappedCaptions = data.subtitles.map((sub: Record<string, any>) => ({
@ -141,7 +144,7 @@ registerProvider({
streamUrl: source.url streamUrl: source.url
.replace("akm-cdn", "aws-cdn") .replace("akm-cdn", "aws-cdn")
.replace("gg-cdn", "aws-cdn"), .replace("gg-cdn", "aws-cdn"),
quality: qualityMap[source.quality as QualityInMap], quality: qualityMap[source.quality],
type: MWStreamType.HLS, type: MWStreamType.HLS,
captions: mappedCaptions, captions: mappedCaptions,
}, },