mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-20 14:37:43 +01:00
commit
f7d51e6d8b
3 changed files with 88 additions and 26 deletions
|
@ -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",
|
||||||
|
|
|
@ -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) => {
|
||||||
return (
|
if (media.meta.type === MWMediaType.MOVIE) {
|
||||||
compareTitle(v.title, media.meta.title) &&
|
const movie = v as FLIXMovie;
|
||||||
v.releaseDate === media.meta.year
|
return (
|
||||||
);
|
compareTitle(movie.title, media.meta.title) &&
|
||||||
|
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),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue