166 lines
5 KiB
TypeScript
166 lines
5 KiB
TypeScript
|
|
import { useContext, useEffect, useState } from "react";
|
||
|
|
import { Button, Modal, Form, Spinner } from "react-bootstrap";
|
||
|
|
import { AddTorrentResponse, AddTorrentOptions } from "../api-types";
|
||
|
|
import { AppContext, APIContext } from "../context";
|
||
|
|
import { ErrorComponent } from "./ErrorComponent";
|
||
|
|
import { formatBytes } from "../helper/formatBytes";
|
||
|
|
import { Error } from "../rqbit-web";
|
||
|
|
|
||
|
|
export const FileSelectionModal = (props: {
|
||
|
|
onHide: () => void;
|
||
|
|
listTorrentResponse: AddTorrentResponse | null;
|
||
|
|
listTorrentError: Error | null;
|
||
|
|
listTorrentLoading: boolean;
|
||
|
|
data: string | File;
|
||
|
|
}) => {
|
||
|
|
let {
|
||
|
|
onHide,
|
||
|
|
listTorrentResponse,
|
||
|
|
listTorrentError,
|
||
|
|
listTorrentLoading,
|
||
|
|
data,
|
||
|
|
} = props;
|
||
|
|
|
||
|
|
const [selectedFiles, setSelectedFiles] = useState<number[]>([]);
|
||
|
|
const [uploading, setUploading] = useState(false);
|
||
|
|
const [uploadError, setUploadError] = useState<Error | null>(null);
|
||
|
|
const [unpopularTorrent, setUnpopularTorrent] = useState(false);
|
||
|
|
const [outputFolder, setOutputFolder] = useState<string>("");
|
||
|
|
const ctx = useContext(AppContext);
|
||
|
|
const API = useContext(APIContext);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
console.log(listTorrentResponse);
|
||
|
|
setSelectedFiles(
|
||
|
|
listTorrentResponse
|
||
|
|
? listTorrentResponse.details.files.map((_, id) => id)
|
||
|
|
: []
|
||
|
|
);
|
||
|
|
setOutputFolder(listTorrentResponse?.output_folder || "");
|
||
|
|
}, [listTorrentResponse]);
|
||
|
|
|
||
|
|
const clear = () => {
|
||
|
|
onHide();
|
||
|
|
setSelectedFiles([]);
|
||
|
|
setUploadError(null);
|
||
|
|
setUploading(false);
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleToggleFile = (toggledId: number) => {
|
||
|
|
if (selectedFiles.includes(toggledId)) {
|
||
|
|
setSelectedFiles(selectedFiles.filter((i) => i !== toggledId));
|
||
|
|
} else {
|
||
|
|
setSelectedFiles([...selectedFiles, toggledId]);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleUpload = async () => {
|
||
|
|
if (!listTorrentResponse) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
setUploading(true);
|
||
|
|
let initialPeers = listTorrentResponse.seen_peers
|
||
|
|
? listTorrentResponse.seen_peers.slice(0, 32)
|
||
|
|
: null;
|
||
|
|
let opts: AddTorrentOptions = {
|
||
|
|
overwrite: true,
|
||
|
|
only_files: selectedFiles,
|
||
|
|
initial_peers: initialPeers,
|
||
|
|
output_folder: outputFolder,
|
||
|
|
};
|
||
|
|
if (unpopularTorrent) {
|
||
|
|
opts.peer_opts = {
|
||
|
|
connect_timeout: 20,
|
||
|
|
read_write_timeout: 60,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
API.uploadTorrent(data, opts)
|
||
|
|
.then(
|
||
|
|
() => {
|
||
|
|
onHide();
|
||
|
|
ctx.refreshTorrents();
|
||
|
|
},
|
||
|
|
(e) => {
|
||
|
|
setUploadError({ text: "Error starting torrent", details: e });
|
||
|
|
}
|
||
|
|
)
|
||
|
|
.finally(() => setUploading(false));
|
||
|
|
};
|
||
|
|
|
||
|
|
const getBody = () => {
|
||
|
|
if (listTorrentLoading) {
|
||
|
|
return <Spinner />;
|
||
|
|
} else if (listTorrentError) {
|
||
|
|
return <ErrorComponent error={listTorrentError}></ErrorComponent>;
|
||
|
|
} else if (listTorrentResponse) {
|
||
|
|
return (
|
||
|
|
<Form>
|
||
|
|
<fieldset className="mb-4">
|
||
|
|
<legend>Pick the files to download</legend>
|
||
|
|
{listTorrentResponse.details.files.map((file, index) => (
|
||
|
|
<Form.Group key={index} controlId={`check-${index}`}>
|
||
|
|
<Form.Check
|
||
|
|
type="checkbox"
|
||
|
|
label={`${file.name} (${formatBytes(file.length)})`}
|
||
|
|
checked={selectedFiles.includes(index)}
|
||
|
|
onChange={() => handleToggleFile(index)}
|
||
|
|
></Form.Check>
|
||
|
|
</Form.Group>
|
||
|
|
))}
|
||
|
|
</fieldset>
|
||
|
|
<fieldset>
|
||
|
|
<legend>Options</legend>
|
||
|
|
<Form.Group controlId="output-folder" className="mb-3">
|
||
|
|
<Form.Label>Output folder</Form.Label>
|
||
|
|
<Form.Control
|
||
|
|
type="text"
|
||
|
|
value={outputFolder}
|
||
|
|
onChange={(e) => setOutputFolder(e.target.value)}
|
||
|
|
/>
|
||
|
|
</Form.Group>
|
||
|
|
<Form.Group controlId="unpopular-torrent" className="mb-3">
|
||
|
|
<Form.Check
|
||
|
|
type="checkbox"
|
||
|
|
label="Increase timeouts"
|
||
|
|
checked={unpopularTorrent}
|
||
|
|
onChange={() => setUnpopularTorrent(!unpopularTorrent)}
|
||
|
|
></Form.Check>
|
||
|
|
<small id="emailHelp" className="form-text text-muted">
|
||
|
|
This might be useful for unpopular torrents with few peers. It
|
||
|
|
will slow down fast torrents though.
|
||
|
|
</small>
|
||
|
|
</Form.Group>
|
||
|
|
</fieldset>
|
||
|
|
</Form>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Modal show onHide={clear} size="lg">
|
||
|
|
<Modal.Header closeButton>
|
||
|
|
<Modal.Title>Add torrent</Modal.Title>
|
||
|
|
</Modal.Header>
|
||
|
|
<Modal.Body>
|
||
|
|
{getBody()}
|
||
|
|
<ErrorComponent error={uploadError} />
|
||
|
|
</Modal.Body>
|
||
|
|
<Modal.Footer>
|
||
|
|
{uploading && <Spinner />}
|
||
|
|
<Button
|
||
|
|
variant="primary"
|
||
|
|
onClick={handleUpload}
|
||
|
|
disabled={
|
||
|
|
listTorrentLoading || uploading || selectedFiles.length == 0
|
||
|
|
}
|
||
|
|
>
|
||
|
|
OK
|
||
|
|
</Button>
|
||
|
|
<Button variant="secondary" onClick={clear}>
|
||
|
|
Cancel
|
||
|
|
</Button>
|
||
|
|
</Modal.Footer>
|
||
|
|
</Modal>
|
||
|
|
);
|
||
|
|
};
|