From 8dfb7fa8d0f49d61f94badf70bb6941618602846 Mon Sep 17 00:00:00 2001 From: HFO4 <912394456@qq.com> Date: Sat, 8 Feb 2020 15:37:20 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A6=BB=E7=BA=BF=E4=B8=8B=E8=BD=BD=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- src/App.js | 7 + src/component/{ => Download}/Download.js | 128 +---- src/component/Download/DownloadingCard.js | 560 ++++++++++++++++++++++ src/component/FileManager/ContextMenu.js | 5 +- src/component/FileManager/Modals.js | 80 +--- src/component/Navbar/Navbar.js | 4 +- src/middleware/Api.js | 5 +- src/pages/download.app.js | 2 +- src/untils/index.js | 6 +- yarn.lock | 12 + 11 files changed, 620 insertions(+), 192 deletions(-) rename src/component/{ => Download}/Download.js (69%) create mode 100644 src/component/Download/DownloadingCard.js diff --git a/package.json b/package.json index 7b87056..b19b45a 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "react-router": "^5.1.2", "react-router-dom": "^5.1.2", "react-scripts": "3.2.0", - "redux": "^4.0.4" + "redux": "^4.0.4", + "timeago-react": "^3.0.0" }, "scripts": { "start": "react-scripts start", diff --git a/src/App.js b/src/App.js index 566e010..b111b1e 100644 --- a/src/App.js +++ b/src/App.js @@ -16,6 +16,7 @@ import PageLoading from "./component/Placeholder/PageLoading.js" import TextViewer from "./component/Viewer/Text"; import DocViewer from "./component/Viewer/Doc"; import SharePreload from "./component/Share/SharePreload"; +import Download from "./component/Download/Download"; // Lazy loads const LoginForm = React.lazy(() => import("./component/Login/LoginForm")); @@ -93,6 +94,12 @@ export default function App() { + + }> + + + + }> diff --git a/src/component/Download.js b/src/component/Download/Download.js similarity index 69% rename from src/component/Download.js rename to src/component/Download/Download.js index a54805a..9e482a0 100644 --- a/src/component/Download.js +++ b/src/component/Download/Download.js @@ -17,11 +17,11 @@ import { WindowRestore, Android } from "mdi-material-ui"; -import { toggleSnackbar } from "../actions/index"; +import { toggleSnackbar } from "../../actions"; import axios from "axios"; -import { sizeToString } from "../untils/index"; -import { mediaType } from "../config"; - +import { sizeToString } from "../../untils"; +import { mediaType } from "../../config"; +import API, { baseURL } from "../../middleware/Api"; import { withStyles, Card, @@ -31,13 +31,9 @@ import { Button, IconButton } from "@material-ui/core"; +import DownloadingCard from "./DownloadingCard"; const styles = theme => ({ - card: { - marginTop: "20px", - display: "flex", - justifyContent: "space-between" - }, actions: { display: "flex" }, @@ -67,28 +63,6 @@ const styles = theme => ({ gird: { marginTop: "30px" }, - iconContainer: { - width: "90px", - height: "90px", - padding: "29px", - marginTop: "6px", - paddingLeft: "35px", - [theme.breakpoints.down("md")]: { - display: "none" - } - }, - content: { - width: "100%", - minWidth: 0 - }, - contentSide: { - minWidth: 0, - paddingTop: "24px", - paddingRight: "28px", - [theme.breakpoints.down("md")]: { - display: "none" - } - }, iconImgBig: { color: "#d32f2f", fontSize: "30px" @@ -204,7 +178,7 @@ const getIcon = (classes, name) => { return iconBig; }; -class DownloadCompoment extends Component { +class DownloadComponent extends Component { page = 0; state = { @@ -222,21 +196,20 @@ class DownloadCompoment extends Component { this.setState({ loading: true }); - axios - .get("/RemoteDownload/FlushUser") + API.get("/aria2/downloading") .then(response => { - axios.post("/RemoteDownload/ListDownloading").then(response => { - this.setState({ - downloading: response.data, - loading: false - }); + this.setState({ + downloading: response.data, + loading: false }); }) .catch(error => { - this.props.toggleSnackbar("top", "right", "加载失败", "error"); - this.setState({ - loading: false - }); + this.props.toggleSnackbar( + "top", + "right", + error.message, + "error" + ); }); }; @@ -316,70 +289,9 @@ class DownloadCompoment extends Component { - {this.state.downloading.map(value => { - value.percent = !value.hasOwnProperty("completedLength") - ? 0 - : value.completedLength / value.totalLength; - return ( - -
- {getIcon(classes, value.fileName)} -
- - - {value.fileName} - - - - {value.hasOwnProperty( - "completedLength" - ) && ( - - {(value.percent * 100).toFixed(2)}% - -{" "} - {value.completedLength === "0" - ? "0Bytes" - : sizeToString( - value.completedLength - )} - / - {value.totalLength === "0" - ? "0Bytes" - : sizeToString( - value.totalLength - )}{" "} - -{" "} - {value.downloadSpeed === "0" - ? "0B/s" - : sizeToString( - value.downloadSpeed - ) + "/s"} - - )} - {!value.hasOwnProperty( - "completedLength" - ) && - } - - - this.cancelDownload(value.id)} - > - - - - -
- ); - })} + {this.state.downloading.map((value, k) => ( + + ))} ({ + root: { + display: "block", + padding: theme.spacing(0) + } +}))(MuiExpansionPanelDetails); + +const useStyles = makeStyles(theme => ({ + card: { + marginTop: "20px", + justifyContent: "space-between" + }, + iconContainer: { + width: "90px", + height: "96px", + padding: " 35px 29px 29px 29px", + paddingLeft: "35px", + [theme.breakpoints.down("sm")]: { + display: "none" + } + }, + content: { + width: "100%", + minWidth: 0, + [theme.breakpoints.up("sm")]: { + borderInlineStart: "1px " + theme.palette.divider + " solid" + } + }, + contentSide: { + minWidth: 0, + paddingTop: "24px", + paddingRight: "28px", + [theme.breakpoints.down("sm")]: { + display: "none" + } + }, + iconBig: { + fontSize: "30px" + }, + iconMultiple:{ + fontSize: "30px", + color:"#607D8B", + }, + progress: { + marginTop: 8, + marginBottom: 4 + }, + expand: { + transition: ".15s transform ease-in-out" + }, + expanded: { + transform: "rotate(180deg)" + }, + subFileName: { + display: "flex" + }, + subFileIcon: { + marginRight: "20px" + }, + scroll: { + overflowY: "auto" + }, + action:{ + padding:theme.spacing(2), + textAlign:"right", + }, + actionButton:{ + marginLeft: theme.spacing(1), + }, + info:{ + padding:theme.spacing(2), + }, + infoTitle:{ + fontWeight:700, + }, + infoValue:{ + color:theme.palette.text.secondary, + }, + bitmap:{ + width: "100%", + height: "50px", + backgroundColor:theme.palette.background.default, + } +})); + +export default function DownloadingCard(props) { + let canvasRef = React.createRef(); + const classes = useStyles(); + const theme = useTheme(); + + const [expanded, setExpanded] = React.useState(""); + const [task, setTask] = React.useState(props.task); + const [loading, setLoading] = React.useState(false); + + const handleChange = panel => (event, newExpanded) => { + setExpanded(newExpanded ? panel : false); + }; + + const dispatch = useDispatch(); + const ToggleSnackbar = useCallback( + (vertical, horizontal, msg, color) => + dispatch(toggleSnackbar(vertical, horizontal, msg, color)), + [dispatch] + ); + + useEffect(()=>{ + setTask(props.task); + },[props.task]); + + useEffect(()=>{ + if (task.info.bitfield===""){ + return + } + let result = ""; + task.info.bitfield.match(/.{1,2}/g).forEach(str => { + result += hex2bin(str); + }); + const canvas = canvasRef.current; + const context = canvas.getContext('2d'); + context.clearRect(0, 0, canvas.width, canvas.height); + context.strokeStyle = theme.palette.primary.main; + for (let i = 0;i { + if (total == 0) { + return 0; + } + return (completed / total) * 100; + }; + + const deleteFile = (index)=>{ + setLoading(true); + let current = activeFiles(); + let newIndex = []; + let newFiles = []; + current.map((v)=>{ + + if (v.index !== index && v.selected){ + newIndex.push(parseInt(v.index)); + newFiles.push({ + ...v, + selected:"true", + }); + }else{ + newFiles.push({ + ...v, + selected:"false", + }); + } + }); + API.put("/aria2/select/"+task.info.gid,{ + indexes:newIndex, + }) + .then(response => { + setTask({ + ...task, + info:{ + ...task.info, + files:newFiles, + } + }); + ToggleSnackbar( + "top", + "right", + "文件已删除", + "success" + ); + }) + .catch(error => { + ToggleSnackbar( + "top", + "right", + error.message, + "error" + ); + }).finally(()=>{ + setLoading(false); + }); + + }; + + const getDownloadName = useCallback(() => { + if (task.info.bittorrent.info.name !== "") { + return task.info.bittorrent.info.name; + } + return task.name === "." ? "[未知]" : task.name; + }, [task]); + + const activeFiles = useCallback(() => { + return task.info.files.filter((v)=> v.selected==="true"); + }, [task.info.files]); + + const getIcon = useCallback(() => { + if (task.info.bittorrent.mode === "multi") { + return ( + + + + ) + } else { + return ( + + ); + } + }, [task, classes]); + + return ( + + + +
{getIcon()}
+ + + + + {getDownloadName()} + + + + + + {task.total > 0 && ( + + {getPercent( + task.downloaded, + task.total + ).toFixed(2)} + % -{" "} + {task.downloaded === 0 + ? "0Bytes" + : sizeToString(task.downloaded)} + / + {task.total === 0 + ? "0Bytes" + : sizeToString(task.total)}{" "} + -{" "} + {task.speed === "0" + ? "0B/s" + : sizeToString(task.speed) + "/s"} + + )} + {task.total === 0 && - } + + + + + + + +
+ + +
+ + + {activeFiles().map((value, key) => { + return ( + + + + + {value.path} + + + + + {" "} + {sizeToString(value.length)} + + + + + {getPercent( + value.completedLength, + value.length + ).toFixed(2)} + % + + + + + deleteFile(value.index)} disabled={loading} size={"small"}> + + + + + + ); + })} + +
+ +
+
+ + +
+ +
+ {task.info.bitfield !==""&&} + + + + + 更新于: + + + + + + + + 上传大小: + + + {sizeToString(task.info.uploadLength)} + + + + + 上传速度: + + + {sizeToString(task.info.uploadLength)} / s + + + {task.info.bittorrent.mode !== ""&& + <> + + InfoHash: + + + {task.info.infoHash} + + + + + 做种者: + + + {task.info.numSeeders} + + + + + 做种中: + + + {task.info.seeder === "true"?"是":"否"} + + + + } + + + 分片大小: + + + {sizeToString(task.info.pieceLength)} + + + + + 分片数量: + + + {task.info.numPieces} + + + + +
+
+
+
+ ); +} diff --git a/src/component/FileManager/ContextMenu.js b/src/component/FileManager/ContextMenu.js index d14628a..0484567 100644 --- a/src/component/FileManager/ContextMenu.js +++ b/src/component/FileManager/ContextMenu.js @@ -411,9 +411,8 @@ class ContextMenuCompoment extends Component { {!this.props.isMultiple && isHomePage && - user.group.allowTorrentDownload && - this.props.withFile && - isTorrent(this.props.selected[0].name) && ( + user.group.allowRemoteDownload && + this.props.withFile&& ( this.props.openTorrentDownloadDialog() diff --git a/src/component/FileManager/Modals.js b/src/component/FileManager/Modals.js index 506d031..c110f7e 100644 --- a/src/component/FileManager/Modals.js +++ b/src/component/FileManager/Modals.js @@ -10,7 +10,6 @@ import { openLoadingDialog } from "../../actions/index"; import PathSelector from "./PathSelector"; -import axios from "axios"; import API, { baseURL } from "../../middleware/Api"; import { withStyles, @@ -22,9 +21,6 @@ import { DialogTitle, DialogContentText, CircularProgress, - Checkbox, - FormControl, - FormControlLabel } from "@material-ui/core"; import Loading from "../Modals/Loading"; import CopyDialog from "../Modals/Copy"; @@ -35,6 +31,7 @@ import PurchaseShareDialog from "../Modals/PurchaseShare"; import Auth from "../../middleware/Auth"; import DecompressDialog from "../Modals/Decompress"; import CompressDialog from "../Modals/Compress"; +import {filePath} from "../../untils"; const styles = theme => ({ wrapper: { @@ -283,48 +280,6 @@ class ModalsCompoment extends Component { }); }; - submitShare = e => { - e.preventDefault(); - this.props.setModalsLoading(true); - axios - .post("/File/Share", { - action: "share", - item: - this.props.selected[0].path === "/" - ? this.props.selected[0].path + - this.props.selected[0].name - : this.props.selected[0].path + - "/" + - this.props.selected[0].name, - shareType: this.state.secretShare ? "private" : "public", - pwd: this.state.sharePwd - }) - .then(response => { - if (response.data.result !== "") { - this.setState({ - shareUrl: response.data.result - }); - } else { - this.props.toggleSnackbar( - "top", - "right", - response.data.result.error, - "warning" - ); - } - this.props.setModalsLoading(false); - }) - .catch(error => { - this.props.toggleSnackbar( - "top", - "right", - error.message, - "error" - ); - this.props.setModalsLoading(false); - }); - }; - submitRemove = e => { e.preventDefault(); this.props.setModalsLoading(true); @@ -575,14 +530,11 @@ class ModalsCompoment extends Component { submitTorrentDownload = e => { e.preventDefault(); this.props.setModalsLoading(true); - axios - .post("/RemoteDownload/AddTorrent", { - action: "torrentDownload", - id: this.props.selected[0].id, - savePath: this.state.selectedPath + API + .post("/aria2/torrent" + filePath(this.props.selected[0]), { + dst: this.state.selectedPath === "//" ? "/" : this.state.selectedPath }) .then(response => { - if (response.data.result.success) { this.props.toggleSnackbar( "top", "right", @@ -590,14 +542,6 @@ class ModalsCompoment extends Component { "success" ); this.onClose(); - } else { - this.props.toggleSnackbar( - "top", - "right", - response.data.result.error, - "warning" - ); - } this.props.setModalsLoading(false); }) .catch(error => { @@ -614,14 +558,12 @@ class ModalsCompoment extends Component { submitDownload = e => { e.preventDefault(); this.props.setModalsLoading(true); - axios - .post("/RemoteDownload/addUrl", { - action: "remoteDownload", + API + .post("/aria2/url", { url: this.state.downloadURL, - path: this.state.selectedPath + dst: this.state.selectedPath === "//" ? "/" : this.state.selectedPath }) .then(response => { - if (response.data.result.success) { this.props.toggleSnackbar( "top", "right", @@ -629,14 +571,6 @@ class ModalsCompoment extends Component { "success" ); this.onClose(); - } else { - this.props.toggleSnackbar( - "top", - "right", - response.data.result.error, - "warning" - ); - } this.props.setModalsLoading(false); }) .catch(error => { diff --git a/src/component/Navbar/Navbar.js b/src/component/Navbar/Navbar.js index 2d23007..738afee 100644 --- a/src/component/Navbar/Navbar.js +++ b/src/component/Navbar/Navbar.js @@ -528,9 +528,7 @@ class NavbarCompoment extends Component { - (window.location.href = "/Home/Download") - } + onClick={() => (this.props.history.push("/aria2?"))} > diff --git a/src/middleware/Api.js b/src/middleware/Api.js index 879a1cd..1c93b54 100644 --- a/src/middleware/Api.js +++ b/src/middleware/Api.js @@ -13,9 +13,10 @@ const instance = axios.create({ crossDomain: true }); -function AppError(message,code) { +function AppError(message,code,error) { this.code = code; this.message = message || '未知错误'; + this.message += error?(" "+error) : ""; this.stack = (new Error()).stack; } AppError.prototype = Object.create(Error.prototype); @@ -35,7 +36,7 @@ instance.interceptors.response.use( Auth.signout(); window.location.href = "#/Login"; } - throw new AppError(response.rawData.msg,response.rawData.code); + throw new AppError(response.rawData.msg,response.rawData.code,response.rawData.error); } return response; }, diff --git a/src/pages/download.app.js b/src/pages/download.app.js index ac1136e..4dbd4b1 100644 --- a/src/pages/download.app.js +++ b/src/pages/download.app.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import Navbar from "../component/Navbar/Navbar.js" import AlertBar from "../component/Snackbar" import { createMuiTheme } from '@material-ui/core/styles'; -import Download from '../component/Download' +import Download from '../component/Download/Download' import { CssBaseline, withStyles, MuiThemeProvider } from '@material-ui/core'; const theme = createMuiTheme(window.colorTheme); const styles = theme => ({ diff --git a/src/untils/index.js b/src/untils/index.js index c1f119f..8d4d155 100644 --- a/src/untils/index.js +++ b/src/untils/index.js @@ -1,5 +1,5 @@ export const sizeToString = bytes => { - if (bytes === 0) return "0 B"; + if (bytes === 0 || bytes==="0") return "0 B"; var k = 1024; var sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; var i = Math.floor(Math.log(bytes) / Math.log(k)); @@ -131,3 +131,7 @@ export function filePath(file) { ? file.path + file.name : file.path + "/" + file.name; } + +export function hex2bin(hex){ + return (parseInt(hex, 16).toString(2)).padStart(8, '0'); +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index a5abdcc..c543edf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10022,6 +10022,18 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow== +timeago-react@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/timeago-react/-/timeago-react-3.0.0.tgz#777665f768ae0517e71be137fc6287c4d0a6a788" + integrity sha512-dO7dBjuRqUSoyt7kLc6UJLvfN5F0JbC2qTqIsjpRFaMXu9bK9PKuWQ3/XD/kPZWGVtwpNimKDpQC3Q2ok8MMSA== + dependencies: + timeago.js "^4.0.0" + +timeago.js@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/timeago.js/-/timeago.js-4.0.2.tgz#724e8c8833e3490676c7bb0a75f5daf20e558028" + integrity sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w== + timers-browserify@^2.0.4: version "2.0.11" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f"