This commit is contained in:
YouROK
2021-05-17 14:55:57 +03:00
parent 29f13fd482
commit e578628886
40 changed files with 1319 additions and 656 deletions

View File

@@ -6,22 +6,56 @@ import DialogTitle from '@material-ui/core/DialogTitle'
import DialogContent from '@material-ui/core/DialogContent'
import { cacheHost } from '../utils/Hosts'
const style = {
cache: {
paddingLeft: "6px",
paddingRight: "2px",
lineHeight: "11px",
},
piece: {
width: "12px",
height: "12px",
backgroundColor: "#eef2f4",
border: "1px solid #eef2f4",
display: "inline-block",
marginRight: "1px",
},
pieceComplete: {
backgroundColor: "#3fb57a",
borderColor: "#3fb57a",
},
pieceLoading: {
backgroundColor: "#00d0d0",
borderColor: "#00d0d0",
},
readerRange: {
borderColor: "#9a9aff !important",
},
pieceReader: {
borderColor: "#000000 !important",
},
pieceProgress: {
position: "relative",
zIndex: "1",
backgroundColor: "#009090",
left: "-1px",
top: "-1px",
width: "12px",
},
}
export default function DialogCacheInfo(props) {
const [hash] = React.useState(props.hash)
const [cache, setCache] = React.useState({})
const timerID = useRef(-1)
const canvasRef = useRef(null)
const dialogRef = useRef(null)
const [pMap, setPMap] = React.useState([])
useEffect(() => {
const canvas = canvasRef.current
const context = canvas.getContext('2d')
if (hash)
timerID.current = setInterval(() => {
getCache(hash, (cache) => {
setCache(cache);
redraw(cache, canvas, context, dialogRef)
setCache(cache)
})
}, 100)
else clearInterval(timerID.current)
@@ -31,6 +65,39 @@ export default function DialogCacheInfo(props) {
}
}, [hash, props.open])
useEffect(()=>{
if (cache && cache.PiecesCount && cache.Pieces){
var map = [];
for (let i = 0; i < cache.PiecesCount; i++) {
var reader = 0
var cls = "piece"
var prc = 0
if (cache.Pieces[i]) {
if (cache.Pieces[i].Completed && cache.Pieces[i].Size >= cache.Pieces[i].Length)
cls += " piece-complete"
else
cls += " piece-loading"
prc = (cache.Pieces[i].Size / cache.Pieces[i].Length * 100).toFixed(2)
}
cache.Readers.forEach((r, k) => {
if (i >= r.Start && i <= r.End && i !== r.Reader)
cls += " reader-range"
if (i === r.Reader) {
cls += " piece-reader"
}
})
map.push({
prc: prc,
class: cls,
info: i,
reader: reader,
})
}
setPMap(map)
}
},[cache.Pieces])
return (
<div>
<DialogTitle id="form-dialog-title">
@@ -51,110 +118,52 @@ export default function DialogCacheInfo(props) {
<br />
<b>Download speed </b> {cache.Torrent && cache.Torrent.download_speed ? humanizeSize(cache.Torrent.download_speed) + '/sec' : ''}
<br />
<b>Upload speed </b> {cache.Torrent && cache.Torrent.upload_speed ? humanizeSize(cache.Torrent.upload_speed) + '/sec' : ''}
<br />
<b>Status </b> {cache.Torrent && cache.Torrent.stat_string && cache.Torrent.stat_string}
</Typography>
</DialogTitle>
<DialogContent ref={dialogRef}>
<canvas ref={canvasRef} />
<DialogContent>
<div className="cache">
{pMap.map((itm) => <span className={itm.class} title={itm.info}>{itm.prc>0 && itm.prc<100 && (<div className="piece-progress" style={{height: itm.prc/100*12+"px"}}></div>)}</span>)}
</div>
</DialogContent>
</div>
)
}
const pieceSize = 12;
const colors = {
0: "#eef2f4", // empty piece
1: "#00d0d0", // donwloading
2: "#009090", // donwloading fill color
3: "#3fb57a", // downloaded
4: "#9a9aff", // reader range color
5: "#000000", // reader current position
}
const map = new Map();
const savedCanvas = document.createElement("canvas");
savedCanvas.ctx = savedCanvas.getContext("2d");
function redraw(cache, canvas, ctx, dialogRef) {
if (!cache || !cache.PiecesCount || !dialogRef.current) return;
if(dialogRef.current.offsetWidth !== canvas.width + 50 || cache.PiecesCount !== map.size) {
canvas.width = dialogRef.current.offsetWidth - 50;
renderPieces(canvas, ctx, cache.PiecesCount);
}
ctx.drawImage(savedCanvas, 0, 0);
if (cache.Pieces) {
Object.values(cache.Pieces).forEach(piece => {
const cords = map.get(piece.Id);
function getCacheMap(cache) {
if (!cache || !cache.PiecesCount) return ''
var html = ''
for (let i = 0; i < cache.PiecesCount; i++) {
html += "<span class='piece"
let info = i
var prcDiv = ""
if (cache.Pieces && cache.Pieces[i]) {
let prc = (cache.Pieces[i].Size/cache.Pieces[i].Length*100).toFixed(2)
let piece = cache.Pieces[i]
if (piece.Completed && piece.Size >= piece.Length) {
ctx.fillStyle = colors[3];
ctx.beginPath();
ctx.rect(cords.x, cords.y, pieceSize, pieceSize);
ctx.fill();
} else {
ctx.fillStyle = colors[1];
ctx.beginPath();
ctx.rect(cords.x, cords.y, pieceSize, pieceSize);
ctx.fill();
const percent = piece.Size / piece.Length
fillPiece(ctx, piece.Id, percent)
html += ' piece-complete'
info += ' 100%'
}else {
html += ' piece-loading'
info += ' ' + prc + '%'
prcDiv = "<div class='piece-progress' style='height: "+prc+"%;'></div>"
}
}
cache.Readers.forEach((r,k)=> {
if (i >= r.Start && i <= r.End && i !== r.Reader)
html += ' reader-range'
if (i === r.Reader) {
html += ' piece-reader'
info += ' reader'
}
})
html += "' title='" + info + "'>"
html += prcDiv
html += "</span>"
}
cache.Readers.forEach(r => setReader(ctx, r.Start, r.Reader, r.End ))
}
function renderPieces(canvas, ctx, count) {
const horizont = ~~(canvas.width / (pieceSize + 1));
canvas.height = ~~(count / horizont) * (pieceSize + 1) + pieceSize + 1;
const vertical = ~~(canvas.height / pieceSize);
ctx.fillStyle = colors[0];
map.clear();
for(let y = 0; y < vertical; y++) {
for(let x = 0; x < horizont; x++) {
if(map.size >= count) break;
map.set(map.size, { x: (pieceSize + 1) * x, y: (pieceSize + 1) * y});
ctx.beginPath();
ctx.rect((pieceSize + 1) * x, (pieceSize + 1) * y, pieceSize, pieceSize);
ctx.fill();
}
}
savedCanvas.width = canvas.width;
savedCanvas.height = canvas.height;
savedCanvas.ctx.drawImage(canvas, 0, 0);
}
function fillPiece(ctx, piece, percent) {
let cords = map.get(piece);
let offest = pieceSize * percent;
if(offest < 1) return; //if less than one pixel a spot remains under a piece
ctx.fillStyle = colors[2];
ctx.beginPath();
ctx.rect(cords.x, cords.y + (pieceSize - offest), pieceSize, offest);
ctx.fill();
}
function setReader(ctx, start, reader, end) {
ctx.strokeStyle = colors[4];
for (let i = start; i <= end; i++) {
cords = map.get(i)
ctx.beginPath();
ctx.rect(cords.x + 0.5, cords.y + 0.5, pieceSize - 1, pieceSize - 1);
ctx.stroke();
}
let cords = map.get(reader);
ctx.strokeStyle = colors[5];
ctx.beginPath();
ctx.rect(cords.x + 0.5, cords.y + 0.5, pieceSize - 1, pieceSize - 1);
ctx.stroke();
return html
}
function getCache(hash, callback) {
@@ -181,4 +190,22 @@ function getCache(hash, callback) {
console.error(e)
callback({})
}
}
}
/*
{
"Hash": "41e36c8de915d80db83fc134bee4e7e2d292657e",
"Capacity": 209715200,
"Filled": 2914808,
"PiecesLength": 4194304,
"PiecesCount": 2065,
"DownloadSpeed": 32770.860273455524,
"Pieces": {
"2064": {
"Id": 2064,
"Length": 2914808,
"Size": 162296,
"Completed": false
}
}
}
*/

View File

@@ -19,7 +19,7 @@ const style = {
poster: {
display: 'flex',
flexDirection: 'row',
borderRadius:'5px',
borderRadius: '5px',
},
}

View File

@@ -79,6 +79,8 @@ export default function SettingsDialog() {
sets[event.target.id] = Number(event.target.value)
} else if (event.target.type === 'checkbox') {
sets[event.target.id] = Boolean(event.target.checked)
} else if (event.target.type === 'url') {
sets[event.target.id] = event.target.value
}
setSets(sets)
}
@@ -138,6 +140,10 @@ export default function SettingsDialog() {
<TextField onChange={inputForm} margin="dense" id="ConnectionsLimit" label="Connections limit" value={settings.ConnectionsLimit} type="number" fullWidth />
<TextField onChange={inputForm} margin="dense" id="DhtConnectionLimit" label="Dht connection limit" value={settings.DhtConnectionLimit} type="number" fullWidth />
<TextField onChange={inputForm} margin="dense" id="PeersListenPort" label="Peers listen port" value={settings.PeersListenPort} type="number" fullWidth />
<br />
<FormControlLabel control={<Switch checked={settings.UseDisk} onChange={inputForm} id="UseDisk" color="primary" />} label="Use disk" />
<br />
<TextField onChange={inputForm} margin="dense" id="TorrentsSavePath" label="Torrents save path" value={settings.TorrentsSavePath} type="url" fullWidth />
</>
)}
</DialogContent>