From 18bde24b3a21bd2c3df793a76fd072e476febf0f Mon Sep 17 00:00:00 2001 From: cloud <62519659+lem6ns@users.noreply.github.com> Date: Sun, 11 Jun 2023 11:29:55 -0600 Subject: [PATCH 1/4] feat(provider): Remote Stream --- src/backend/index.ts | 1 + src/backend/providers/remotestream.ts | 49 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/backend/providers/remotestream.ts diff --git a/src/backend/index.ts b/src/backend/index.ts index eb0ad897..d62f557b 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/remotestream"; // embeds import "./embeds/streamm4u"; diff --git a/src/backend/providers/remotestream.ts b/src/backend/providers/remotestream.ts new file mode 100644 index 00000000..cf19f826 --- /dev/null +++ b/src/backend/providers/remotestream.ts @@ -0,0 +1,49 @@ +import { mwFetch } from "@/backend/helpers/fetch"; +import { registerProvider } from "@/backend/helpers/register"; +import { MWStreamQuality, MWStreamType } from "@/backend/helpers/streams"; +import { MWMediaType } from "@/backend/metadata/types"; + +const remotestreamBase = `https://fsa.remotestre.am`; + +registerProvider({ + id: "remotestream", + displayName: "Remote Stream", + disabled: false, + rank: 50, + 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" : "Shows"; + let playlistLink = `${remotestreamBase}/${type}/${media.tmdbId}`; + + if (media.meta.type === MWMediaType.SERIES) { + const seasonNumber = media.meta.seasonData.number; + const episodeNumber = media.meta.seasonData.episodes.find( + (e) => e.id === episode + )?.number; + + playlistLink += `/${seasonNumber}/${episodeNumber}.m3u8`; + } else { + playlistLink += `/${media.tmdbId}.m3u8`; + } + + const streamRes = await mwFetch(playlistLink); + if (streamRes.type !== "application/x-mpegurl") + throw new Error("No watchable item found"); + progress(90); + return { + embeds: [], + stream: { + streamUrl: playlistLink, + quality: MWStreamQuality.QUNKNOWN, + type: MWStreamType.HLS, + captions: [], + }, + }; + }, +}); From 893a385f0043a989cbb39ab1772737294c49ca9b Mon Sep 17 00:00:00 2001 From: cloud <62519659+lem6ns@users.noreply.github.com> Date: Sun, 11 Jun 2023 11:34:57 -0600 Subject: [PATCH 2/4] fix(remotestream): additional path for tv --- src/backend/providers/remotestream.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/providers/remotestream.ts b/src/backend/providers/remotestream.ts index cf19f826..8439d2c1 100644 --- a/src/backend/providers/remotestream.ts +++ b/src/backend/providers/remotestream.ts @@ -27,7 +27,7 @@ registerProvider({ (e) => e.id === episode )?.number; - playlistLink += `/${seasonNumber}/${episodeNumber}.m3u8`; + playlistLink += `/${seasonNumber}/${episodeNumber}/${episodeNumber}.m3u8`; } else { playlistLink += `/${media.tmdbId}.m3u8`; } From ef782974fe20115e2993e482f1a7a48f8087b287 Mon Sep 17 00:00:00 2001 From: cloud <62519659+lem6ns@users.noreply.github.com> Date: Sun, 11 Jun 2023 11:36:05 -0600 Subject: [PATCH 3/4] fix(remotestream): Duplicate rank number --- src/backend/providers/remotestream.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/providers/remotestream.ts b/src/backend/providers/remotestream.ts index 8439d2c1..02c0f199 100644 --- a/src/backend/providers/remotestream.ts +++ b/src/backend/providers/remotestream.ts @@ -9,7 +9,7 @@ registerProvider({ id: "remotestream", displayName: "Remote Stream", disabled: false, - rank: 50, + rank: 55, type: [MWMediaType.MOVIE, MWMediaType.SERIES], async scrape({ media, episode, progress }) { From 1a613287f8453672c83d9adb0fdbbb77d0f7772b Mon Sep 17 00:00:00 2001 From: cloud <62519659+lem6ns@users.noreply.github.com> Date: Sun, 11 Jun 2023 10:44:51 -0600 Subject: [PATCH 4/4] feat(provider): streamflix --- src/backend/index.ts | 1 + src/backend/providers/streamflix.ts | 70 +++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/backend/providers/streamflix.ts diff --git a/src/backend/index.ts b/src/backend/index.ts index eb0ad897..447c2165 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"; // embeds import "./embeds/streamm4u"; 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, + })), + }, + }; + }, +});