feat(downloading): ability to choose files which you wanna download
This commit is contained in:
parent
3326bc2505
commit
0b329b8328
@ -7,6 +7,7 @@ import Subheader from 'material-ui/Subheader';
|
|||||||
import {Tabs, Tab} from 'material-ui/Tabs';
|
import {Tabs, Tab} from 'material-ui/Tabs';
|
||||||
import ActionInfo from 'material-ui/svg-icons/action/info';
|
import ActionInfo from 'material-ui/svg-icons/action/info';
|
||||||
import RaisedButton from 'material-ui/RaisedButton';
|
import RaisedButton from 'material-ui/RaisedButton';
|
||||||
|
import Toggle from 'material-ui/Toggle';
|
||||||
|
|
||||||
import FileFolder from 'material-ui/svg-icons/file/folder';
|
import FileFolder from 'material-ui/svg-icons/file/folder';
|
||||||
import NoImage from './images/no-image-icon.png'
|
import NoImage from './images/no-image-icon.png'
|
||||||
@ -42,11 +43,21 @@ let buildFilesTree = (filesList) => {
|
|||||||
filesList.forEach((file) => {
|
filesList.forEach((file) => {
|
||||||
let pathTree = file.path.split('/');
|
let pathTree = file.path.split('/');
|
||||||
let currentItem = rootTree;
|
let currentItem = rootTree;
|
||||||
pathTree.forEach((pathItem) => {
|
pathTree.forEach((pathItem, index) => {
|
||||||
if(!(pathItem in currentItem))
|
if(!(pathItem in currentItem))
|
||||||
{
|
{
|
||||||
currentItem[pathItem] = {
|
// крайний индекс, значит это объект файла, объединяем объекты
|
||||||
__sizeBT: 0
|
if(index === pathTree.length - 1)
|
||||||
|
{
|
||||||
|
file.__sizeBT = 0
|
||||||
|
file.__fileBT = true
|
||||||
|
currentItem[pathItem] = file
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentItem[pathItem] = {
|
||||||
|
__sizeBT: 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentItem = currentItem[pathItem]
|
currentItem = currentItem[pathItem]
|
||||||
@ -57,22 +68,59 @@ let buildFilesTree = (filesList) => {
|
|||||||
return rootTree;
|
return rootTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
const treeToTorrentFiles = (tree) => {
|
const treeToTorrentFiles = (tree, torrent, toggles) => {
|
||||||
|
// toggles for button disable/enable torrent/directory in torrent client
|
||||||
|
if(toggles)
|
||||||
|
{
|
||||||
|
if(tree.__fileBT && typeof tree.downloadIndex !== 'undefined')
|
||||||
|
{
|
||||||
|
toggles.push({
|
||||||
|
downloadIndex: tree.downloadIndex,
|
||||||
|
selected: typeof tree.downloadSelected === 'undefined' || tree.downloadSelected
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is already file, return
|
||||||
|
if(tree.__fileBT)
|
||||||
|
return
|
||||||
|
|
||||||
let arr = [];
|
let arr = [];
|
||||||
for(let file in tree)
|
for(let file in tree)
|
||||||
{
|
{
|
||||||
if(file == '__sizeBT')
|
if(file == '__sizeBT')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
const newToggles = []
|
||||||
|
|
||||||
arr.push(<ListItem
|
arr.push(<ListItem
|
||||||
key={file}
|
key={file}
|
||||||
primaryText={file}
|
primaryText={file}
|
||||||
secondaryText={formatBytes(tree[file].__sizeBT)}
|
secondaryText={formatBytes(tree[file].__sizeBT)}
|
||||||
nestedItems={treeToTorrentFiles(tree[file])}
|
nestedItems={treeToTorrentFiles(tree[file], torrent, newToggles)}
|
||||||
primaryTogglesNestedList={true}
|
primaryTogglesNestedList={true}
|
||||||
innerDivStyle={{wordBreak: 'break-word'}}
|
innerDivStyle={{wordBreak: 'break-word'}}
|
||||||
leftIcon={tree[file] && Object.keys(tree[file]).length > 1 ? <FileFolder /> : contentIcon(fileTypeDetect({path: file}))}
|
leftIcon={!tree[file].__fileBT ? <FileFolder /> : contentIcon(fileTypeDetect({path: file}))}
|
||||||
|
rightToggle={
|
||||||
|
newToggles.length > 0
|
||||||
|
&&
|
||||||
|
<Toggle
|
||||||
|
toggled={newToggles.every( ({selected}) => selected )}
|
||||||
|
onToggle={(e, checked) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
let toggleValues = {}
|
||||||
|
newToggles.forEach(({downloadIndex}) => toggleValues[downloadIndex] = checked)
|
||||||
|
window.torrentSocket.emit('downloadSelectFiles', torrent, toggleValues)
|
||||||
|
}}
|
||||||
|
/>}
|
||||||
/>);
|
/>);
|
||||||
|
|
||||||
|
if(toggles)
|
||||||
|
{
|
||||||
|
for(const newToggle of newToggles)
|
||||||
|
toggles.push(newToggle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
@ -87,7 +135,7 @@ const TorrentFiles = (props) => {
|
|||||||
?
|
?
|
||||||
<div className='w100p'>
|
<div className='w100p'>
|
||||||
<Subheader inset={true}>{__('Content of the torrent')}:</Subheader>
|
<Subheader inset={true}>{__('Content of the torrent')}:</Subheader>
|
||||||
{treeToTorrentFiles(tree)}
|
{treeToTorrentFiles(tree, {hash: props.torrent.hash})}
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div className='column center'>
|
<div className='column center'>
|
||||||
@ -206,7 +254,7 @@ export default class TorrentPage extends Page {
|
|||||||
// Получаем более новую статистику пира
|
// Получаем более новую статистику пира
|
||||||
if((Date.now() / 1000) - this.torrent.trackersChecked > 10 * 60) {
|
if((Date.now() / 1000) - this.torrent.trackersChecked > 10 * 60) {
|
||||||
window.torrentSocket.emit('checkTrackers', this.torrent.hash);
|
window.torrentSocket.emit('checkTrackers', this.torrent.hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, () => {
|
}, () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -221,11 +269,20 @@ export default class TorrentPage extends Page {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
super.componentDidMount();
|
super.componentDidMount();
|
||||||
|
|
||||||
this.filesUpdated = (hash) => {
|
this.filesUpdated = (hash, filesList) => {
|
||||||
if(this.props.hash != hash)
|
if(this.props.hash != hash)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.getTorrentInfo();
|
if(filesList)
|
||||||
|
{
|
||||||
|
if(this.torrent)
|
||||||
|
{
|
||||||
|
this.torrent.filesList = filesList
|
||||||
|
this.forceUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.getTorrentInfo();
|
||||||
}
|
}
|
||||||
window.torrentSocket.on('filesReady', this.filesUpdated);
|
window.torrentSocket.on('filesReady', this.filesUpdated);
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ module.exports = async ({
|
|||||||
removeOnDone: download.removeOnDone,
|
removeOnDone: download.removeOnDone,
|
||||||
paused: torrent.paused || torrent._paused
|
paused: torrent.paused || torrent._paused
|
||||||
}
|
}
|
||||||
|
torrent.filesList = download.files.length > 0 ? downloadFilesList(download) : torrent.filesList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +82,14 @@ module.exports = async ({
|
|||||||
Fn(...rest, (data) => callback(mergeTorrentsWithDownloads(data, copy)))
|
Fn(...rest, (data) => callback(mergeTorrentsWithDownloads(data, copy)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const downloadFilesList = (torrent) => torrent.files.map((file, index) => ({
|
||||||
|
path: file.path.replace(/\\/g, '/'),
|
||||||
|
size: file.length,
|
||||||
|
downloadIndex: index,
|
||||||
|
downloadSelected: file.selected
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
recive('recentTorrents', function(callback)
|
recive('recentTorrents', function(callback)
|
||||||
{
|
{
|
||||||
if(typeof callback != 'function')
|
if(typeof callback != 'function')
|
||||||
@ -692,6 +701,7 @@ module.exports = async ({
|
|||||||
delete torrent._paused
|
delete torrent._paused
|
||||||
torrent._pause()
|
torrent._pause()
|
||||||
}
|
}
|
||||||
|
send('filesReady', torrent.infoHash, downloadFilesList(torrent))
|
||||||
})
|
})
|
||||||
|
|
||||||
torrent.on('done', () => {
|
torrent.on('done', () => {
|
||||||
@ -762,6 +772,49 @@ module.exports = async ({
|
|||||||
return _destroy.call(torrent, ...args)
|
return _destroy.call(torrent, ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
torrent.selectFiles = (selection) => {
|
||||||
|
if(Array.isArray(selection))
|
||||||
|
{
|
||||||
|
if(selection.length !== torrent.files.length)
|
||||||
|
{
|
||||||
|
logTE('downloader', 'selection map not full', torrent.files.length, selection.length)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for(let i = 0; i < selection.length; i++)
|
||||||
|
{
|
||||||
|
torrent.files[i].selected = !!selection[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(let fileId in selection)
|
||||||
|
{
|
||||||
|
fileId = parseInt(fileId)
|
||||||
|
if(fileId >= torrent.files.length)
|
||||||
|
{
|
||||||
|
logTE('downloader', 'selection map wrong', selection)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
torrent.files[fileId].selected = !!selection[fileId]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
torrent.updateFilesSelection()
|
||||||
|
}
|
||||||
|
|
||||||
|
torrent.updateFilesSelection = () => {
|
||||||
|
torrent.deselect(0, torrent.pieces.length - 1, false)
|
||||||
|
|
||||||
|
for(const file of torrent.files)
|
||||||
|
{
|
||||||
|
const {selected} = file
|
||||||
|
if(typeof selected === 'undefined' || selected)
|
||||||
|
file.select()
|
||||||
|
else
|
||||||
|
file.deselect()
|
||||||
|
}
|
||||||
|
logT('downloader', 'selection updated')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(callback)
|
if(callback)
|
||||||
callback(true)
|
callback(true)
|
||||||
@ -834,6 +887,31 @@ module.exports = async ({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
recive('downloadSelectFiles', ({hash}, files, callback) =>
|
||||||
|
{
|
||||||
|
logT('downloader', 'call update selection', hash, files.length)
|
||||||
|
const id = torrentClientHashMap[hash]
|
||||||
|
if(!id)
|
||||||
|
{
|
||||||
|
logT('downloader', 'cant find torrent for selection', hash)
|
||||||
|
if(callback)
|
||||||
|
callback(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const torrent = torrentClient.get(id)
|
||||||
|
if(!torrent) {
|
||||||
|
logT('downloader', 'no torrent for selection founded')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
torrent.selectFiles(files)
|
||||||
|
send('filesReady', torrent.infoHash, downloadFilesList(torrent))
|
||||||
|
|
||||||
|
if(callback)
|
||||||
|
callback(true)
|
||||||
|
})
|
||||||
|
|
||||||
recive('downloads', (callback) =>
|
recive('downloads', (callback) =>
|
||||||
{
|
{
|
||||||
callback(torrentClient.torrents.map(torrent => ({
|
callback(torrentClient.torrents.map(torrent => ({
|
||||||
|
@ -10,7 +10,8 @@ torrentClient.saveSession = (sessionFile) => {
|
|||||||
torrent: torrent.torrentObject,
|
torrent: torrent.torrentObject,
|
||||||
|
|
||||||
removeOnDone: torrent.removeOnDone,
|
removeOnDone: torrent.removeOnDone,
|
||||||
paused: torrent.paused || torrent._paused
|
paused: torrent.paused || torrent._paused,
|
||||||
|
selection: torrent.files.map(file => typeof file.selected === 'undefined' || file.selected)
|
||||||
}))
|
}))
|
||||||
}, null, 4), 'utf8');
|
}, null, 4), 'utf8');
|
||||||
}
|
}
|
||||||
@ -34,7 +35,7 @@ torrentClient.loadSession = (sessionFile) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const {torrents} = obj
|
const {torrents} = obj
|
||||||
torrents.forEach(({torrent, infoHash, path, removeOnDone, paused}) => {
|
torrents.forEach(({torrent, infoHash, path, removeOnDone, paused, selection}) => {
|
||||||
if(!torrent || !infoHash || !path)
|
if(!torrent || !infoHash || !path)
|
||||||
{
|
{
|
||||||
logT('downloader', 'no info for starting download this torrent')
|
logT('downloader', 'no info for starting download this torrent')
|
||||||
@ -51,6 +52,13 @@ torrentClient.loadSession = (sessionFile) => {
|
|||||||
{
|
{
|
||||||
download._paused = true
|
download._paused = true
|
||||||
}
|
}
|
||||||
|
if(selection)
|
||||||
|
{
|
||||||
|
download.on('metadata', () => {
|
||||||
|
logT('downloader', 'load torrent selection from session')
|
||||||
|
download.selectFiles(selection)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user