Compare commits

..

14 Commits
3.2.2 ... 3.2.5

Author SHA1 Message Date
Jip Frijlink
47eba8caa4 Merge pull request #504 from movie-web/add-disallowed-ids
Add disallowed ids
2023-12-01 14:43:22 +01:00
Jip Fr
1dc957b56a Fix typo 2023-12-01 14:41:46 +01:00
Jip Fr
e653c72d87 Add comment 2023-12-01 14:41:25 +01:00
Jip Fr
c39d61cf53 Change text 2023-12-01 14:39:04 +01:00
Jip Fr
b14a73378f Bump version 2023-12-01 14:35:12 +01:00
Jip Fr
43d1e290fc Add DISALLOWED_IDS to conf 2023-12-01 14:34:52 +01:00
Jip Frijlink
1f6318360e Merge pull request #485 from movie-web/dev
Fix poster issue (into prod)
2023-11-09 15:53:54 +01:00
Jip Frijlink
791299dd43 Merge pull request #484 from movie-web/fix-posters
Fix poster issue
2023-11-09 15:50:22 +01:00
Jip Fr
2c92bbf94e Fix poster issue 2023-11-09 15:34:35 +01:00
mrjvs
e3569c7ed7 Merge pull request #479 from movie-web/dev
v3.2.3 - fixing upcloud
2023-11-07 21:14:16 +01:00
mrjvs
196a805d32 Merge branch 'master' into dev 2023-11-07 21:13:07 +01:00
William Oldham
94d6d7b37e Merge pull request #478 from movie-web/fix-upcloud
Fix upcloud
2023-11-07 20:10:22 +00:00
mrjvs
fde5f0c82e version bump 2023-11-07 21:07:39 +01:00
mrjvs
bb449d6dfb Fix upcloud 2023-11-07 21:04:43 +01:00
5 changed files with 90 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "movie-web",
"version": "3.2.2",
"version": "3.2.5",
"private": true,
"homepage": "https://movie-web.app",
"dependencies": {

View File

@@ -29,6 +29,32 @@ function isJSON(json: string) {
}
}
function extractKey(script: string): [number, number][] | null {
const startOfSwitch = script.lastIndexOf("switch");
const endOfCases = script.indexOf("partKeyStartPosition");
const switchBody = script.slice(startOfSwitch, endOfCases);
const nums: [number, number][] = [];
const matches = switchBody.matchAll(
/:[a-zA-Z0-9]+=([a-zA-Z0-9]+),[a-zA-Z0-9]+=([a-zA-Z0-9]+);/g
);
for (const match of matches) {
const innerNumbers: number[] = [];
for (const varMatch of [match[1], match[2]]) {
const regex = new RegExp(`${varMatch}=0x([a-zA-Z0-9]+)`, "g");
const varMatches = [...script.matchAll(regex)];
const lastMatch = varMatches[varMatches.length - 1];
if (!lastMatch) return null;
const number = parseInt(lastMatch[1], 16);
innerNumbers.push(number);
}
nums.push([innerNumbers[0], innerNumbers[1]]);
}
return nums;
}
registerEmbedScraper({
id: "upcloud",
displayName: "UpCloud",
@@ -54,23 +80,31 @@ registerEmbedScraper({
let sources: { file: string; type: string } | null = null;
if (!isJSON(streamRes.sources)) {
const decryptionKey = JSON.parse(
await proxiedFetch<string>(
`https://raw.githubusercontent.com/enimax-anime/key/e4/key.txt`
)
) as [number, number][];
const scriptJs = await proxiedFetch<string>(
`https://rabbitstream.net/js/player/prod/e4-player.min.js`,
{
responseType: "text" as any,
}
);
const decryptionKey = extractKey(scriptJs);
if (!decryptionKey) throw new Error("Key extraction failed");
let extractedKey = "";
const sourcesArray = streamRes.sources.split("");
for (const index of decryptionKey) {
for (let i: number = index[0]; i < index[1]; i += 1) {
extractedKey += streamRes.sources[i];
sourcesArray[i] = "";
}
}
let strippedSources = streamRes.sources;
let totalledOffset = 0;
decryptionKey.forEach(([a, b]) => {
const start = a + totalledOffset;
const end = start + b;
extractedKey += streamRes.sources.slice(start, end);
strippedSources = strippedSources.replace(
streamRes.sources.substring(start, end),
""
);
totalledOffset += b;
});
const decryptedStream = AES.decrypt(
sourcesArray.join(""),
strippedSources,
extractedKey
).toString(enc.Utf8);
const parsedStream = JSON.parse(decryptedStream)[0];

View File

@@ -51,7 +51,7 @@ function MediaCardContent({
>
<div
className={[
"relative mb-4 aspect-[2/3] w-full overflow-hidden rounded-xl bg-denim-500 bg-cover bg-center transition-[border-radius] duration-100",
"relative mb-4 w-full overflow-hidden rounded-xl bg-denim-500 bg-cover bg-center pb-[150%] transition-[border-radius] duration-100",
closable ? "" : "group-hover:rounded-lg",
].join(" ")}
style={{

View File

@@ -7,6 +7,7 @@ interface Config {
TMDB_READ_API_KEY: string;
CORS_PROXY_URL: string;
NORMAL_ROUTER: boolean;
DISALLOWED_IDS: string;
}
export interface RuntimeConfig {
@@ -16,6 +17,7 @@ export interface RuntimeConfig {
TMDB_READ_API_KEY: string;
NORMAL_ROUTER: boolean;
PROXY_URLS: string[];
DISALLOWED_IDS: string[];
}
const env: Record<keyof Config, undefined | string> = {
@@ -25,6 +27,7 @@ const env: Record<keyof Config, undefined | string> = {
DISCORD_LINK: undefined,
CORS_PROXY_URL: import.meta.env.VITE_CORS_PROXY_URL,
NORMAL_ROUTER: import.meta.env.VITE_NORMAL_ROUTER,
DISALLOWED_IDS: import.meta.env.VITE_DISALLOWED_IDS,
};
// loads from different locations, in order: environment (VITE_{KEY}), window (public/config.js)
@@ -61,5 +64,8 @@ export function conf(): RuntimeConfig {
.split(",")
.map((v) => v.trim()),
NORMAL_ROUTER: getKey("NORMAL_ROUTER", "false") === "true",
DISALLOWED_IDS: getKey("DISALLOWED_IDS", "")
.split(",")
.map((v) => v.trim()), // Should be comma-seperated and contain the media type and ID, formatted like so: movie-753342,movie-753342,movie-753342
};
}

View File

@@ -15,10 +15,12 @@ import {
} from "@/backend/metadata/types/mw";
import { IconPatch } from "@/components/buttons/IconPatch";
import { Icons } from "@/components/Icon";
import { ErrorMessage } from "@/components/layout/ErrorBoundary";
import { Loading } from "@/components/layout/Loading";
import { useGoBack } from "@/hooks/useGoBack";
import { useLoading } from "@/hooks/useLoading";
import { SelectedMediaData, useScrape } from "@/hooks/useScrape";
import { conf } from "@/setup/config";
import { useWatchedItem } from "@/state/watched";
import { MetaController } from "@/video/components/controllers/MetaController";
import { ProgressListenerController } from "@/video/components/controllers/ProgressListenerController";
@@ -53,6 +55,31 @@ function MediaViewLoading(props: { onGoBack(): void }) {
);
}
function MediaVIewNotAllowed(props: { onGoBack(): void }) {
const { t } = useTranslation();
return (
<div className="relative flex flex-1 items-center justify-center">
<Helmet>
<title>{t("videoPlayer.got")}</title>
</Helmet>
<div className="absolute inset-x-0 top-0 px-8 py-6">
<VideoPlayerHeader onClick={props.onGoBack} />
</div>
<div className="flex flex-col items-center">
<ErrorMessage
error={{
name: "Media not allowed",
description:
"this media is no longer available due to a takedown notice or copyright claim",
path: "",
}}
/>
</div>
</div>
);
}
interface MediaViewScrapingProps {
onStream(stream: MWStream): void;
onGoBack(): void;
@@ -240,6 +267,14 @@ export function MediaView() {
});
}, [exec, history, params]);
const disallowedEntries = conf().DISALLOWED_IDS.map((id) => id.split("-"));
if (
disallowedEntries.find(
(entry) => meta?.tmdbId === entry[1] && meta?.meta?.type === entry[0]
)
)
return <MediaVIewNotAllowed onGoBack={goBack} />;
if (loading) return <MediaViewLoading onGoBack={goBack} />;
if (error) return <MediaFetchErrorView />;
if (!meta || !selected)