diff --git a/src/backend/index.ts b/src/backend/index.ts index d62f557b..bc8d9d6c 100644 --- a/src/backend/index.ts +++ b/src/backend/index.ts @@ -9,6 +9,7 @@ import "./providers/m4ufree"; import "./providers/hdwatched"; import "./providers/2embed"; import "./providers/sflix"; +import "./providers/streamflix"; import "./providers/remotestream"; // embeds diff --git a/src/backend/providers/streamflix.ts b/src/backend/providers/streamflix.ts new file mode 100644 index 00000000..90dd4975 --- /dev/null +++ b/src/backend/providers/streamflix.ts @@ -0,0 +1,70 @@ +import { proxiedFetch } from "@/backend/helpers/fetch"; +import { registerProvider } from "@/backend/helpers/register"; +import { + MWCaptionType, + MWStreamQuality, + MWStreamType, +} from "@/backend/helpers/streams"; +import { MWMediaType } from "@/backend/metadata/types"; + +const streamflixBase = "https://us-west2-compute-proxied.streamflix.one"; + +const qualityMap: Record = { + 360: MWStreamQuality.Q360P, + 540: MWStreamQuality.Q540P, + 480: MWStreamQuality.Q480P, + 720: MWStreamQuality.Q720P, + 1080: MWStreamQuality.Q1080P, +}; + +registerProvider({ + id: "streamflix", + displayName: "StreamFlix", + disabled: false, + rank: 69, + type: [MWMediaType.MOVIE, MWMediaType.SERIES], + + async scrape({ media, episode, progress }) { + if (!this.type.includes(media.meta.type)) { + throw new Error("Unsupported type"); + } + + progress(30); + const type = media.meta.type === MWMediaType.MOVIE ? "movies" : "tv"; + let seasonNumber: number | undefined; + let episodeNumber: number | undefined; + + if (media.meta.type === MWMediaType.SERIES) { + // can't do type === "tv" here :( + seasonNumber = media.meta.seasonData.number; + episodeNumber = media.meta.seasonData.episodes.find( + (e: any) => e.id === episode + )?.number; + } + + const streamRes = await proxiedFetch(`/api/player/${type}`, { + baseURL: streamflixBase, + params: { + id: media.tmdbId, + s: seasonNumber, + e: episodeNumber, + }, + }); + if (!streamRes.headers.Referer) throw new Error("No watchable item found"); + progress(90); + return { + embeds: [], + stream: { + streamUrl: streamRes.sources[0].url, + quality: qualityMap[streamRes.sources[0].quality], + type: MWStreamType.HLS, + captions: streamRes.subtitles.map((s: Record) => ({ + needsProxy: true, + url: s.url, + type: MWCaptionType.VTT, + langIso: s.lang, + })), + }, + }; + }, +});