From 051c1ba709fc5d53b86a5dfd8c423cd1b31cbdbb Mon Sep 17 00:00:00 2001 From: frost768 Date: Sun, 12 Mar 2023 13:57:01 +0300 Subject: [PATCH 1/3] flixhq scraping improved --- src/backend/helpers/streams.ts | 2 + src/backend/providers/flixhq.ts | 85 +++++++++++++++++++++++++++----- src/backend/providers/netfilm.ts | 27 +++++----- 3 files changed, 89 insertions(+), 25 deletions(-) diff --git a/src/backend/helpers/streams.ts b/src/backend/helpers/streams.ts index 92943d94..6f4e28cb 100644 --- a/src/backend/helpers/streams.ts +++ b/src/backend/helpers/streams.ts @@ -10,9 +10,11 @@ export enum MWCaptionType { export enum MWStreamQuality { Q360P = "360p", + Q540P = "540p", Q480P = "480p", Q720P = "720p", Q1080P = "1080p", + QAUTO = "auto", QUNKNOWN = "unknown", } diff --git a/src/backend/providers/flixhq.ts b/src/backend/providers/flixhq.ts index 95a09b7b..4c8a6cc5 100644 --- a/src/backend/providers/flixhq.ts +++ b/src/backend/providers/flixhq.ts @@ -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 = { + "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( `/${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), }, }; }, diff --git a/src/backend/providers/netfilm.ts b/src/backend/providers/netfilm.ts index 9b4faafa..23a8cf90 100644 --- a/src/backend/providers/netfilm.ts +++ b/src/backend/providers/netfilm.ts @@ -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 = { + 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( `/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) => ({ @@ -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) => ({ @@ -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, }, From f02256f9e03bb18655cfd221d3fe1fdf27e4abb3 Mon Sep 17 00:00:00 2001 From: frost768 Date: Mon, 13 Mar 2023 16:48:28 +0300 Subject: [PATCH 2/3] enum value added --- src/backend/providers/flixhq.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/backend/providers/flixhq.ts b/src/backend/providers/flixhq.ts index 4c8a6cc5..22c19030 100644 --- a/src/backend/providers/flixhq.ts +++ b/src/backend/providers/flixhq.ts @@ -22,12 +22,12 @@ interface FLIXMediaBase { interface FLIXTVSerie extends FLIXMediaBase { type: "TV Series"; - seasons: number; + seasons: number | null; } interface FLIXMovie extends FLIXMediaBase { type: "Movie"; - releaseDate: number; + releaseDate: string; } function castSubtitles({ url, lang }: { url: string; lang: string }) { @@ -42,6 +42,7 @@ function castSubtitles({ url, lang }: { url: string; lang: string }) { } const qualityMap: Record = { + auto: MWStreamQuality.QAUTO, "360": MWStreamQuality.Q360P, "540": MWStreamQuality.Q540P, "480": MWStreamQuality.Q480P, @@ -71,14 +72,14 @@ registerProvider({ const movie = v as FLIXMovie; return ( compareTitle(movie.title, media.meta.title) && - movie.releaseDate === Number(media.meta.year) + movie.releaseDate === media.meta.year ); } const serie = v as FLIXTVSerie; - if (media.meta.seasons) { + if (serie.seasons && media.meta.seasons) { return ( compareTitle(serie.title, media.meta.title) && - serie.seasons === Number(media.meta.seasons.length) + serie.seasons === media.meta.seasons.length ); } return compareTitle(serie.title, media.meta.title); @@ -94,7 +95,7 @@ registerProvider({ id: flixId, }, }); - + if (!mediaInfo.episodes) throw new Error("No watchable item found"); // get stream info from media progress(75); const watchInfo = await proxiedFetch("/watch", { @@ -105,9 +106,8 @@ registerProvider({ }, }); - if (!watchInfo.sources) { - throw new Error("No watchable item found"); - } + if (!watchInfo.sources) throw new Error("No watchable item found"); + // get best quality source // comes sorted by quality in descending order const source = watchInfo.sources[0]; From 3aa4365a5693b05b921aa58f985f92de637e505c Mon Sep 17 00:00:00 2001 From: frost768 Date: Mon, 13 Mar 2023 21:37:29 +0300 Subject: [PATCH 3/3] 'auto' quality removed --- src/backend/helpers/streams.ts | 1 - src/backend/providers/flixhq.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/backend/helpers/streams.ts b/src/backend/helpers/streams.ts index 6f4e28cb..d5985cfa 100644 --- a/src/backend/helpers/streams.ts +++ b/src/backend/helpers/streams.ts @@ -14,7 +14,6 @@ export enum MWStreamQuality { Q480P = "480p", Q720P = "720p", Q1080P = "1080p", - QAUTO = "auto", QUNKNOWN = "unknown", } diff --git a/src/backend/providers/flixhq.ts b/src/backend/providers/flixhq.ts index 22c19030..2232ca9d 100644 --- a/src/backend/providers/flixhq.ts +++ b/src/backend/providers/flixhq.ts @@ -42,7 +42,6 @@ function castSubtitles({ url, lang }: { url: string; lang: string }) { } const qualityMap: Record = { - auto: MWStreamQuality.QAUTO, "360": MWStreamQuality.Q360P, "540": MWStreamQuality.Q540P, "480": MWStreamQuality.Q480P,