update
parent
be3da0a45d
commit
b55af04082
|
@ -15,6 +15,7 @@
|
||||||
"@types/node": "^16.11.25",
|
"@types/node": "^16.11.25",
|
||||||
"@types/react": "^17.0.39",
|
"@types/react": "^17.0.39",
|
||||||
"@types/react-dom": "^17.0.11",
|
"@types/react-dom": "^17.0.11",
|
||||||
|
"filesize": "^8.0.7",
|
||||||
"mtproton": "6.0.0",
|
"mtproton": "6.0.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
|
|
@ -1,7 +1,19 @@
|
||||||
import style from "./style.module.css";
|
import style from "./style.module.css";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Close } from "@mui/icons-material";
|
import { Close } from "@mui/icons-material";
|
||||||
import { IconButton } from "@mui/material";
|
import {
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
IconButton,
|
||||||
|
} from "@mui/material";
|
||||||
|
import fileSize from "filesize";
|
||||||
|
import SendIcon from "@mui/icons-material/Send";
|
||||||
|
import { inputFile, sendFile, uploadBigFile } from "../../telegram/telegram";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { addFileOfStorage } from "../../store/fileList";
|
||||||
|
|
||||||
enum Status {
|
enum Status {
|
||||||
normal,
|
normal,
|
||||||
|
@ -18,6 +30,11 @@ export function HomeButton(props: Props) {
|
||||||
let [status, setStatus] = useState(Status.normal);
|
let [status, setStatus] = useState(Status.normal);
|
||||||
let [boxStyle, setBoxStyle] = useState([style.box]);
|
let [boxStyle, setBoxStyle] = useState([style.box]);
|
||||||
let [isReceive, setIsReceive] = useState(false);
|
let [isReceive, setIsReceive] = useState(false);
|
||||||
|
let [waitedFileList, setWaitedFileList] = useState<any[]>([]);
|
||||||
|
let [uploadRatio, setUploadRatio] = useState(0);
|
||||||
|
let [isFinish, setIsFinish] = useState(false);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
let onNormal = () => {
|
let onNormal = () => {
|
||||||
setStatus(Status.normal);
|
setStatus(Status.normal);
|
||||||
};
|
};
|
||||||
|
@ -42,6 +59,43 @@ export function HomeButton(props: Props) {
|
||||||
}
|
}
|
||||||
}, [status]);
|
}, [status]);
|
||||||
|
|
||||||
|
let addFileInput = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
let OnChangeFileInput = (e: any) => {
|
||||||
|
setWaitedFileList(e.target.files);
|
||||||
|
};
|
||||||
|
|
||||||
|
let handleFileUpload = () => {
|
||||||
|
setUploadRatio(1);
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function (event) {
|
||||||
|
if (event.target && event.target.result) {
|
||||||
|
let bytes = event.target.result;
|
||||||
|
uploadBigFile(bytes as ArrayBuffer, setUploadRatio)
|
||||||
|
.then((file) => {
|
||||||
|
console.log("uploadFile ret:", file);
|
||||||
|
sendFile(
|
||||||
|
// @ts-ignore
|
||||||
|
inputFile(file.file_id, file.total_part, waitedFileList[0].name),
|
||||||
|
waitedFileList[0].type
|
||||||
|
).then((result) => {
|
||||||
|
console.log("sendFile ret:", result);
|
||||||
|
result.updates[1].message.media.document.file_name =
|
||||||
|
waitedFileList[0].name;
|
||||||
|
dispatch(
|
||||||
|
addFileOfStorage(result.updates[1].message.media.document)
|
||||||
|
);
|
||||||
|
setIsFinish(true);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("uploadFile error:", error);
|
||||||
|
alert(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsArrayBuffer(waitedFileList[0]);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className={boxStyle.join(" ")}>
|
<div className={boxStyle.join(" ")}>
|
||||||
{!isReceive ? (
|
{!isReceive ? (
|
||||||
|
@ -51,8 +105,15 @@ export function HomeButton(props: Props) {
|
||||||
className={style.addFile}
|
className={style.addFile}
|
||||||
onMouseEnter={onAddFile}
|
onMouseEnter={onAddFile}
|
||||||
onMouseLeave={onNormal}
|
onMouseLeave={onNormal}
|
||||||
|
onClick={() => addFileInput.current?.click()}
|
||||||
>
|
>
|
||||||
添加文件
|
添加文件
|
||||||
|
<input
|
||||||
|
ref={addFileInput}
|
||||||
|
type="file"
|
||||||
|
style={{ display: "none" }}
|
||||||
|
onChange={OnChangeFileInput}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className={style.receive}
|
className={style.receive}
|
||||||
|
@ -87,6 +148,44 @@ export function HomeButton(props: Props) {
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<Dialog open={waitedFileList.length !== 0}>
|
||||||
|
<DialogTitle>文件上传</DialogTitle>
|
||||||
|
<DialogContent sx={{ minWidth: 300 }}>
|
||||||
|
是否上传文件?
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
文件名: {waitedFileList.length > 0 ? waitedFileList[0].name : ""}
|
||||||
|
<br />
|
||||||
|
文件大小:{" "}
|
||||||
|
{waitedFileList.length > 0 ? fileSize(waitedFileList[0].size) : ""}
|
||||||
|
<br />
|
||||||
|
{uploadRatio !== 0 && <>正在上传: {uploadRatio}%</>}
|
||||||
|
<br />
|
||||||
|
{isFinish && <>上传完成</>}
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
onClick={() => {
|
||||||
|
setWaitedFileList([]);
|
||||||
|
setUploadRatio(0);
|
||||||
|
setIsFinish(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
{uploadRatio === 0 && (
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleFileUpload}
|
||||||
|
endIcon={<SendIcon />}
|
||||||
|
>
|
||||||
|
上传
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import reportWebVitals from "./reportWebVitals";
|
import reportWebVitals from "./reportWebVitals";
|
||||||
|
@ -6,6 +8,33 @@ import { BrowserRouter, Routes, Route } from "react-router-dom";
|
||||||
import Home from "./pages/home";
|
import Home from "./pages/home";
|
||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import store from "./store";
|
import store from "./store";
|
||||||
|
import { updateOfStorage } from "./store/fileList";
|
||||||
|
|
||||||
|
store.dispatch(updateOfStorage());
|
||||||
|
|
||||||
|
Date.prototype.Format = function (fmt) {
|
||||||
|
var o = {
|
||||||
|
"M+": this.getMonth() + 1, //月份
|
||||||
|
"d+": this.getDate(), //日
|
||||||
|
"h+": this.getHours(), //小时
|
||||||
|
"m+": this.getMinutes(), //分
|
||||||
|
"s+": this.getSeconds(), //秒
|
||||||
|
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
|
||||||
|
S: this.getMilliseconds(), //毫秒
|
||||||
|
};
|
||||||
|
if (/(y+)/.test(fmt))
|
||||||
|
fmt = fmt.replace(
|
||||||
|
RegExp.$1,
|
||||||
|
(this.getFullYear() + "").substr(4 - RegExp.$1.length)
|
||||||
|
);
|
||||||
|
for (var k in o)
|
||||||
|
if (new RegExp("(" + k + ")").test(fmt))
|
||||||
|
fmt = fmt.replace(
|
||||||
|
RegExp.$1,
|
||||||
|
RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
|
||||||
|
);
|
||||||
|
return fmt;
|
||||||
|
};
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
|
|
|
@ -15,6 +15,9 @@ import {
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
|
import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
|
||||||
|
import { useSelectorFileList } from "../../store/fileList";
|
||||||
|
import fileSize from "filesize";
|
||||||
|
import { downloadFile } from "../../telegram/telegram";
|
||||||
|
|
||||||
enum ContentType {
|
enum ContentType {
|
||||||
File,
|
File,
|
||||||
|
@ -56,14 +59,34 @@ function Login() {
|
||||||
|
|
||||||
function File() {
|
function File() {
|
||||||
let [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
let [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||||
|
let [waitDownloadFile, setWaitDownloadFile] = useState(null);
|
||||||
|
let fileList = useSelectorFileList();
|
||||||
|
|
||||||
const open = Boolean(anchorEl);
|
const open = Boolean(anchorEl);
|
||||||
|
|
||||||
let handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
let handleClick = (index: number) => {
|
||||||
|
return (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
console.log("index", index);
|
||||||
|
setWaitDownloadFile(fileList[index]);
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorEl(event.currentTarget);
|
||||||
};
|
};
|
||||||
|
};
|
||||||
let handleClose = () => {
|
let handleClose = () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let Download = () => {
|
||||||
|
// @ts-ignore
|
||||||
|
console.log("waitDownloadFile", waitDownloadFile?.file_name);
|
||||||
|
downloadFile(waitDownloadFile)
|
||||||
|
.then((res) => {
|
||||||
|
console.log("res", res);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log("download error:", error);
|
||||||
|
alert(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -74,7 +97,7 @@ function File() {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Paper sx={{ padding: "100px", width: "100%" }}>
|
<Paper sx={{ padding: "100px", width: "100%" }}>
|
||||||
<TableContainer sx={{ backgroundColor: "#f2f2f2" }}>
|
<TableContainer sx={{ backgroundColor: "#f2f2f2", height: 500 }}>
|
||||||
<Table aria-label={"文件列表"}>
|
<Table aria-label={"文件列表"}>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
@ -84,19 +107,33 @@ function File() {
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow>
|
{fileList.map((item: any, index: number) => {
|
||||||
|
return (
|
||||||
|
<TableRow key={item.id} sx={{ cursor: "pointer" }}>
|
||||||
<TableCell sx={{ position: "relative" }}>
|
<TableCell sx={{ position: "relative" }}>
|
||||||
xxx
|
{item.attributes[0].file_name}
|
||||||
<IconButton
|
<IconButton
|
||||||
sx={{ position: "absolute", right: 20 }}
|
sx={{
|
||||||
onClick={handleClick}
|
position: "absolute",
|
||||||
|
right: 20,
|
||||||
|
top: "50%",
|
||||||
|
transform: "translate(-50%,-50%)",
|
||||||
|
}}
|
||||||
|
onClick={handleClick(index)}
|
||||||
>
|
>
|
||||||
<MoreHorizIcon />
|
<MoreHorizIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>2020-01-01 12:12:12</TableCell>
|
<TableCell>
|
||||||
<TableCell>128MB</TableCell>
|
{
|
||||||
|
// @ts-ignore
|
||||||
|
new Date(item.date * 1000).Format("yyyy-MM-dd hh:mm:ss")
|
||||||
|
}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{fileSize(item.size)}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
|
@ -107,7 +144,7 @@ function File() {
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
<MenuItem onClick={handleClose}>下载</MenuItem>
|
<MenuItem onClick={Download}>下载</MenuItem>
|
||||||
<MenuItem onClick={handleClose}>分享</MenuItem>
|
<MenuItem onClick={handleClose}>分享</MenuItem>
|
||||||
<Divider />
|
<Divider />
|
||||||
<MenuItem onClick={handleClose}>重命名</MenuItem>
|
<MenuItem onClick={handleClose}>重命名</MenuItem>
|
||||||
|
|
|
@ -9,11 +9,19 @@ function getLocalStorage() {
|
||||||
},
|
},
|
||||||
|
|
||||||
setObject(key: string, value: any) {
|
setObject(key: string, value: any) {
|
||||||
|
console.log("setObject", key, value);
|
||||||
return window.localStorage.setItem(key, JSON.stringify(value));
|
return window.localStorage.setItem(key, JSON.stringify(value));
|
||||||
},
|
},
|
||||||
|
|
||||||
getObject(key: string) {
|
getObject(key: string, defaultValue?: any) {
|
||||||
return JSON.parse(window.localStorage.getItem(key)?.toString() || "{}");
|
let value = window.localStorage.getItem(key);
|
||||||
|
if (value) {
|
||||||
|
return JSON.parse(value);
|
||||||
|
}
|
||||||
|
if (defaultValue) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
import { configureStore } from "@reduxjs/toolkit";
|
import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
|
||||||
import userReducer from "./store/user";
|
import userReducer from "./store/user";
|
||||||
|
import fileListReducer from "./store/fileList";
|
||||||
|
|
||||||
export default configureStore({
|
export default configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
user: userReducer,
|
user: userReducer,
|
||||||
|
fileList: fileListReducer,
|
||||||
},
|
},
|
||||||
|
middleware: getDefaultMiddleware({
|
||||||
|
serializableCheck: false,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,18 +4,16 @@ import storage from "../storage";
|
||||||
|
|
||||||
const FileList = createSlice({
|
const FileList = createSlice({
|
||||||
name: "fileList",
|
name: "fileList",
|
||||||
initialState: {
|
initialState: [] as any[],
|
||||||
fileList: [],
|
|
||||||
},
|
|
||||||
reducers: {
|
reducers: {
|
||||||
updateOfStorage: (state) => {
|
updateOfStorage: (state) => {
|
||||||
state.fileList = storage().getObject("fileList");
|
state = storage().getObject("fileList", []);
|
||||||
|
return state;
|
||||||
},
|
},
|
||||||
|
|
||||||
addFileOfStorage: (state, action) => {
|
addFileOfStorage: (state, action) => {
|
||||||
// @ts-ignore
|
state.push(action.payload);
|
||||||
state.fileList.push(action.payload);
|
storage().setObject("fileList", state);
|
||||||
storage().setObject("fileList", state.fileList);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -24,6 +22,6 @@ export function useSelectorFileList() {
|
||||||
return useSelector((state: any) => state.fileList);
|
return useSelector((state: any) => state.fileList);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { updateOfStorage } = FileList.actions;
|
export const { updateOfStorage, addFileOfStorage } = FileList.actions;
|
||||||
|
|
||||||
export default FileList.reducer;
|
export default FileList.reducer;
|
||||||
|
|
|
@ -16,7 +16,7 @@ class TelegramHelper {
|
||||||
this.client = new Client({
|
this.client = new Client({
|
||||||
api_id: appID,
|
api_id: appID,
|
||||||
api_hash: appHash,
|
api_hash: appHash,
|
||||||
test: true,
|
test: false,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let createTransport = function (dc: any, crypto: any) {
|
let createTransport = function (dc: any, crypto: any) {
|
||||||
|
@ -86,7 +86,8 @@ class TelegramHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadBigFile(
|
async function uploadBigFile(
|
||||||
bytes: ArrayBuffer
|
bytes: ArrayBuffer,
|
||||||
|
callback?: (ratio: number) => void
|
||||||
): Promise<{ file_id: number; total_part: number }> {
|
): Promise<{ file_id: number; total_part: number }> {
|
||||||
let file_id = rand_id();
|
let file_id = rand_id();
|
||||||
console.log("file_id", file_id);
|
console.log("file_id", file_id);
|
||||||
|
@ -109,10 +110,8 @@ async function uploadBigFile(
|
||||||
file_total_parts: file_total_parts,
|
file_total_parts: file_total_parts,
|
||||||
bytes: tempBytes,
|
bytes: tempBytes,
|
||||||
});
|
});
|
||||||
if (finished) {
|
if (callback) {
|
||||||
console.log("finished");
|
callback(((i + 1) / file_total_parts) * 100);
|
||||||
} else {
|
|
||||||
console.log("not finished");
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
|
@ -157,7 +156,7 @@ function sendFile(inputFile: any, type: string) {
|
||||||
|
|
||||||
async function downloadFile(fileDocument: any) {
|
async function downloadFile(fileDocument: any) {
|
||||||
let partSize = 1024 * 1024;
|
let partSize = 1024 * 1024;
|
||||||
const file_total_parts = Math.ceil(fileDocument.document.size / partSize);
|
const file_total_parts = Math.ceil(fileDocument.size / partSize);
|
||||||
|
|
||||||
let results = [];
|
let results = [];
|
||||||
for (let i = 0; i < file_total_parts; i++) {
|
for (let i = 0; i < file_total_parts; i++) {
|
||||||
|
@ -165,9 +164,9 @@ async function downloadFile(fileDocument: any) {
|
||||||
let result = await Telegram.call("upload.getFile", {
|
let result = await Telegram.call("upload.getFile", {
|
||||||
location: {
|
location: {
|
||||||
_: "inputDocumentFileLocation",
|
_: "inputDocumentFileLocation",
|
||||||
id: fileDocument.document.id,
|
id: fileDocument.id,
|
||||||
access_hash: fileDocument.document.access_hash,
|
access_hash: fileDocument.access_hash,
|
||||||
file_reference: fileDocument.document.file_reference,
|
file_reference: fileDocument.file_reference,
|
||||||
thumb_size: "",
|
thumb_size: "",
|
||||||
},
|
},
|
||||||
limit: partSize,
|
limit: partSize,
|
||||||
|
@ -181,7 +180,7 @@ async function downloadFile(fileDocument: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("messages.getDocument:", results);
|
console.log("messages.getDocument:", results);
|
||||||
let bytes = new Uint8Array(fileDocument.document.size);
|
let bytes = new Uint8Array(fileDocument.size);
|
||||||
for (let i = 0; i < results.length; i++) {
|
for (let i = 0; i < results.length; i++) {
|
||||||
for (let j = 0; j < results[i].bytes.length; j++) {
|
for (let j = 0; j < results[i].bytes.length; j++) {
|
||||||
bytes[i * partSize + j] = results[i].bytes[j];
|
bytes[i * partSize + j] = results[i].bytes[j];
|
||||||
|
@ -190,12 +189,12 @@ async function downloadFile(fileDocument: any) {
|
||||||
let downloadBytes = bytes;
|
let downloadBytes = bytes;
|
||||||
console.log("downloadBytes", downloadBytes);
|
console.log("downloadBytes", downloadBytes);
|
||||||
let blob = new Blob([downloadBytes], {
|
let blob = new Blob([downloadBytes], {
|
||||||
type: fileDocument.document.mime_type,
|
type: fileDocument.mime_type,
|
||||||
});
|
});
|
||||||
let url = window.URL.createObjectURL(blob);
|
let url = window.URL.createObjectURL(blob);
|
||||||
let a = document.createElement("a");
|
let a = document.createElement("a");
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = fileDocument.document.attributes[0].file_name;
|
a.download = fileDocument.file_name;
|
||||||
a.click();
|
a.click();
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4440,7 +4440,7 @@ filelist@^1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
minimatch "^3.0.4"
|
minimatch "^3.0.4"
|
||||||
|
|
||||||
filesize@^8.0.6:
|
filesize@^8.0.6, filesize@^8.0.7:
|
||||||
version "8.0.7"
|
version "8.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8"
|
resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8"
|
||||||
integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==
|
integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==
|
||||||
|
|
Loading…
Reference in New Issue