Render plugin data from static server
This commit is contained in:
parent
74c8920edf
commit
6a76bfac33
@ -2,24 +2,16 @@ import Head from "next/head";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import styles from "../styles/PluginData.module.css";
|
import styles from "../styles/PluginData.module.css";
|
||||||
import { Cell } from "./CellData";
|
import { formatBytes } from "../lib/plugins";
|
||||||
|
|
||||||
export interface Plugin {
|
export interface Plugin {
|
||||||
id: number;
|
hash: string;
|
||||||
name: string;
|
|
||||||
hash: bigint;
|
|
||||||
file_id: number;
|
|
||||||
mod_id: number;
|
|
||||||
version: number;
|
|
||||||
size: number;
|
size: number;
|
||||||
author?: string;
|
author?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
masters: string[];
|
masters: string[];
|
||||||
file_name: string;
|
file_name: string;
|
||||||
file_path: string;
|
cell_count: number;
|
||||||
updated_at: Date;
|
|
||||||
created_at: Date;
|
|
||||||
cells: Omit<Cell, "mods">[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -39,7 +31,7 @@ const PluginData: React.FC<Props> = ({ plugin, counts }) => {
|
|||||||
<meta
|
<meta
|
||||||
key="description"
|
key="description"
|
||||||
name="description"
|
name="description"
|
||||||
content={`Map of Skyrim showing ${plugin.cells.length} cell edits from the plugin: ${plugin.file_name}`}
|
content={`Map of Skyrim showing ${plugin.cell_count} cell edits from the plugin: ${plugin.file_name}`}
|
||||||
/>
|
/>
|
||||||
<meta
|
<meta
|
||||||
key="og:title"
|
key="og:title"
|
||||||
@ -49,7 +41,7 @@ const PluginData: React.FC<Props> = ({ plugin, counts }) => {
|
|||||||
<meta
|
<meta
|
||||||
key="og:description"
|
key="og:description"
|
||||||
property="og:description"
|
property="og:description"
|
||||||
content={`Map of Skyrim showing ${plugin.cells.length} cell edits from the plugin: ${plugin.file_name}`}
|
content={`Map of Skyrim showing ${plugin.cell_count} cell edits from the plugin: ${plugin.file_name}`}
|
||||||
/>
|
/>
|
||||||
<meta
|
<meta
|
||||||
key="twitter:title"
|
key="twitter:title"
|
||||||
@ -59,7 +51,7 @@ const PluginData: React.FC<Props> = ({ plugin, counts }) => {
|
|||||||
<meta
|
<meta
|
||||||
key="twitter:description"
|
key="twitter:description"
|
||||||
name="twitter:description"
|
name="twitter:description"
|
||||||
content={`Map of Skyrim showing ${plugin.cells.length} cell edits from the plugin: ${plugin.file_name}`}
|
content={`Map of Skyrim showing ${plugin.cell_count} cell edits from the plugin: ${plugin.file_name}`}
|
||||||
/>
|
/>
|
||||||
<meta
|
<meta
|
||||||
key="og:url"
|
key="og:url"
|
||||||
@ -80,9 +72,13 @@ const PluginData: React.FC<Props> = ({ plugin, counts }) => {
|
|||||||
{plugin.masters.join(", ")}
|
{plugin.masters.join(", ")}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div>
|
||||||
|
<strong>Size: </strong>
|
||||||
|
{formatBytes(plugin.size)}
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Cell edits: </strong>
|
<strong>Cell edits: </strong>
|
||||||
{plugin.cells.length}
|
{plugin.cell_count}
|
||||||
</div>
|
</div>
|
||||||
{plugin.description && (
|
{plugin.description && (
|
||||||
<div>
|
<div>
|
||||||
|
@ -2,8 +2,11 @@ import React from "react";
|
|||||||
import useSWRImmutable from "swr/immutable";
|
import useSWRImmutable from "swr/immutable";
|
||||||
|
|
||||||
import { useAppSelector } from "../lib/hooks";
|
import { useAppSelector } from "../lib/hooks";
|
||||||
|
import { PluginFile } from "../slices/plugins";
|
||||||
import { Mod } from "./ModData";
|
import { Mod } from "./ModData";
|
||||||
import PluginData from "./PluginData";
|
import { Cell } from "./CellData";
|
||||||
|
import CellModList from "./CellModList";
|
||||||
|
import PluginData, { Plugin as PluginProps } from "./PluginData";
|
||||||
import styles from "../styles/PluginData.module.css";
|
import styles from "../styles/PluginData.module.css";
|
||||||
|
|
||||||
export interface File {
|
export interface File {
|
||||||
@ -40,13 +43,19 @@ export interface Plugin {
|
|||||||
file_path: string;
|
file_path: string;
|
||||||
updated_at: Date;
|
updated_at: Date;
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
file: File;
|
}
|
||||||
mod: Omit<Mod, "cells">;
|
|
||||||
|
export interface PluginsByHashWithMods {
|
||||||
|
hash: number;
|
||||||
|
plugins: Plugin[];
|
||||||
|
files: File[];
|
||||||
|
mods: Mod[];
|
||||||
|
cells: Cell[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const NEXUS_MODS_URL = "https://www.nexusmods.com/skyrimspecialedition";
|
const NEXUS_MODS_URL = "https://www.nexusmods.com/skyrimspecialedition";
|
||||||
|
|
||||||
const jsonFetcher = async (url: string): Promise<Plugin | null> => {
|
const jsonFetcher = async (url: string): Promise<PluginsByHashWithMods | null> => {
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
@ -59,6 +68,20 @@ const jsonFetcher = async (url: string): Promise<Plugin | null> => {
|
|||||||
return res.json();
|
return res.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const buildPluginProps = (data?: PluginsByHashWithMods | null, plugin?: PluginFile): PluginProps => {
|
||||||
|
const dataPlugin = data && data.plugins.length > 0 && data.plugins[0];
|
||||||
|
return {
|
||||||
|
hash: (plugin && plugin.hash) || (dataPlugin && dataPlugin.hash.toString(36)) || "",
|
||||||
|
size: plugin?.size || (dataPlugin && dataPlugin.size) || 0,
|
||||||
|
author: plugin?.parsed?.header.author || (dataPlugin && dataPlugin.author) || undefined,
|
||||||
|
description: plugin?.parsed?.header.description || (dataPlugin && dataPlugin.description) || undefined,
|
||||||
|
masters: plugin?.parsed?.header.masters || (dataPlugin && dataPlugin.masters) || [],
|
||||||
|
file_name: plugin?.filename || (dataPlugin && dataPlugin.file_name) || "",
|
||||||
|
cell_count: plugin?.parsed?.cells.length || (data && data.cells.length) || 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
hash: string;
|
hash: string;
|
||||||
counts: Record<number, [number, number, number]> | null;
|
counts: Record<number, [number, number, number]> | null;
|
||||||
@ -86,27 +109,10 @@ const PluginDetail: React.FC<Props> = ({ hash, counts }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PluginData
|
<PluginData
|
||||||
plugin={
|
plugin={buildPluginProps(data, plugin)}
|
||||||
// TODO: merge into one common plugin object
|
counts={counts}
|
||||||
data || {
|
|
||||||
id: plugin!.id,
|
|
||||||
name: plugin!.name,
|
|
||||||
hash: plugin!.hash,
|
|
||||||
file_id: plugin!.file_id,
|
|
||||||
mod_id: plugin!.mod_id,
|
|
||||||
version: plugin!.version,
|
|
||||||
size: plugin!.size,
|
|
||||||
author: plugin!.author,
|
|
||||||
description: plugin!.description,
|
|
||||||
masters: plugin!.masters,
|
|
||||||
file_name: plugin!.filename,
|
|
||||||
file_path: plugin!.filepath,
|
|
||||||
updated_at: plugin!.updated_at,
|
|
||||||
created_at: plugin!.created_at,
|
|
||||||
cells: plugin!.cells,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
|
{data && <CellModList mods={data.mods} counts={counts} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -42,7 +42,7 @@ export class WorkerPool {
|
|||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const worker = new Worker();
|
const worker = new Worker();
|
||||||
worker.onmessage = (evt: {
|
worker.onmessage = (evt: {
|
||||||
data: string | PluginFile & { timeHashEnd: number };
|
data: string | PluginFile;
|
||||||
}) => {
|
}) => {
|
||||||
const { data } = evt;
|
const { data } = evt;
|
||||||
if (typeof data === "string" && data === "ready") {
|
if (typeof data === "string" && data === "ready") {
|
||||||
|
@ -43,3 +43,16 @@ export const parsePluginFiles = (pluginFiles: File[], workerPool: WorkerPool) =>
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From: https://stackoverflow.com/a/18650828
|
||||||
|
export const formatBytes = (bytes: number, decimals = 2): string => {
|
||||||
|
if (bytes === 0) return '0 Bytes';
|
||||||
|
|
||||||
|
const k = 1024;
|
||||||
|
const dm = decimals < 0 ? 0 : decimals;
|
||||||
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||||
|
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
|
||||||
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||||
|
}
|
@ -38,6 +38,7 @@ export interface PluginFile {
|
|||||||
hash: string;
|
hash: string;
|
||||||
parseError?: string;
|
parseError?: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
size: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PluginsState = {
|
export type PluginsState = {
|
||||||
|
@ -19,7 +19,7 @@ self.addEventListener("message", async (event: MessageEvent<{ skipParsing?: bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const hash = hash_plugin(contents).toString(36);
|
const hash = hash_plugin(contents).toString(36);
|
||||||
self.postMessage({ filename, lastModified, parsed, hash, parseError, enabled: parsed && !parseError, timeHashEnd: Date.now() });
|
self.postMessage({ filename, lastModified, parsed, hash, parseError, enabled: parsed && !parseError, size: contents.length });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
self.postMessage(error);
|
self.postMessage(error);
|
||||||
|
Loading…
Reference in New Issue
Block a user