import React, { Component } from 'react'; import AdvancedSearch from './search-advanced-controls' import TorrentsStatistic from './torrent-statistic' import Tooltip from './tooltip' import TextField from 'material-ui/TextField'; import RaisedButton from 'material-ui/RaisedButton'; import RefreshIndicator from 'material-ui/RefreshIndicator'; import Checkbox from 'material-ui/Checkbox'; import Visibility from 'material-ui/svg-icons/action/visibility'; import VisibilityOff from 'material-ui/svg-icons/action/visibility-off'; import AddIcon from 'material-ui/svg-icons/content/add'; import RemoveIcon from 'material-ui/svg-icons/content/remove'; import _ from 'lodash' import singleton from './singleton'; class Search extends Component { constructor(props) { super(props) this.onSearchUpdate = () => {} this.state = { searchingIndicator: false, safeSearchText: __('safe search enabled'), safeSearchColor: 'rgb(0, 188, 212)', moreTorrentsIndicator: false, moreFilesIndicator: false, orderBy: null, orderDesc: false, advancedSearch: false, } this.searchLimit = 10 this.advanced = {} this.searchError = undefined; } search(oldSearch) { window.router('/search') this.setState({ searchingIndicator: true }); this.onSearchUpdate('indicator') this.searchTorrents = []; this.moreSearchTorrents = true; this.searchFiles = []; this.moreSearchFiles = true; this.currentSearch = this.searchValue; let queries = 2; let searchTorrentsParams = { limit: this.searchLimit, safeSearch: !this.notSafeSearch, orderBy: this.state.orderBy, orderDesc: this.state.orderDesc, }; if(this.state.advancedSearch && this.advanced) searchTorrentsParams = Object.assign(searchTorrentsParams, this.advanced); window.torrentSocket.emit('searchTorrent', oldSearch ? this.currentSearch : this.searchValue, searchTorrentsParams, window.customLoader((torrents) => { if(torrents) { this.searchTorrents = torrents; if(torrents.length != this.searchLimit) this.moreSearchTorrents = false; } else { this.moreSearchTorrents = false; } if(--queries == 0) { this.setState({ searchingIndicator: false }); } this.onSearchUpdate('torrents') })); let searchFilesParams = { limit: this.searchLimit, safeSearch: !this.notSafeSearch, orderBy: this.state.orderBy, orderDesc: this.state.orderDesc, }; if(this.state.advancedSearch && this.advanced) searchFilesParams = Object.assign(searchFilesParams, this.advanced); window.torrentSocket.emit('searchFiles', oldSearch ? this.currentSearch : this.searchValue, searchFilesParams, window.customLoader((torrents) => { if(torrents) { this.searchFiles = torrents; let files = 0; torrents.forEach((torrent) => { if(torrent.path && torrent.path.length > 0) files += torrent.path.length }); if(files != this.searchLimit) this.moreSearchFiles = false; } else { this.moreSearchFiles = false; } if(--queries == 0) { this.setState({ searchingIndicator: false }); } this.onSearchUpdate('files') })); } moreTorrents() { this.setState({moreTorrentsIndicator: true}); this.onSearchUpdate('indicator') window.torrentSocket.emit('searchTorrent', this.currentSearch, { index: this.searchTorrents.length, limit: this.searchLimit, safeSearch: !this.notSafeSearch, orderBy: this.state.orderBy, orderDesc: this.state.orderDesc, }, window.customLoader((torrents) => { if(torrents) { this.searchTorrents = this.searchTorrents.concat(torrents); if(torrents.length != this.searchLimit) this.moreSearchTorrents = false; this.setState({moreTorrentsIndicator: false}); this.onSearchUpdate('more torrents') } })); } calcTorrentsFiles(torrents) { let files = 0; torrents.forEach((torrent) => { if(torrent.path && torrent.path.length > 0) files += torrent.path.length }); return files } moreFiles() { let index = 0; this.searchFiles.forEach((torrent) => { if(torrent.path && torrent.path.length > 0) index += torrent.path.length; }); this.setState({moreFilesIndicator: true}); this.onSearchUpdate('indicator') window.torrentSocket.emit('searchFiles', this.currentSearch, { index: index, limit: this.searchLimit, safeSearch: !this.notSafeSearch, orderBy: this.state.orderBy, orderDesc: this.state.orderDesc, }, window.customLoader((torrents) => { if(torrents) { this.searchFiles = this.searchFiles.concat(torrents); if(this.calcTorrentsFiles(torrents) != this.searchLimit) this.moreSearchFiles = false; this.mergeFiles() this.setState({moreFilesIndicator: false}); this.onSearchUpdate('more files') } })); } mergeFiles() { for(let i = 0; i < this.searchFiles.length; i++) { for(let j = i + 1; j < this.searchFiles.length; j++) { if(this.searchFiles[i].hash != this.searchFiles[j].hash) continue if(!this.searchFiles[i].remove) { this.searchFiles[i].path = this.searchFiles[i].path.concat(this.searchFiles[j].path) } this.searchFiles[j].remove = true } } this.searchFiles = this.searchFiles.filter(torrent => !torrent.remove) } componentDidMount() { this.newStatisticFunc = (statistic) => { if(statistic) { this.stats = statistic; this.forceUpdate(); } }; window.torrentSocket.emit('statistic', window.customLoader(this.newStatisticFunc)); window.torrentSocket.on('newStatistic', this.newStatisticFunc); this.remoteSearchTorrent = (torrents) => { if(!torrents) return if(torrents.length === this.searchLimit) this.moreSearchTorrents = true; this.searchTorrents = _.unionBy(this.searchTorrents, torrents, 'hash') this.onSearchUpdate('remote torrents') } window.torrentSocket.on('remoteSearchTorrent', this.remoteSearchTorrent); this.remoteSearchFiles = (torrents) => { if(!torrents) return if(torrents.length > 0 && this.calcTorrentsFiles(torrents) === this.searchLimit) this.moreSearchFiles = true; this.searchFiles = _.unionBy(this.searchFiles, torrents, 'hash') this.mergeFiles() this.onSearchUpdate('remote files') } window.torrentSocket.on('remoteSearchFiles', this.remoteSearchFiles); } componentWillUnmount() { if(this.newStatisticFunc) window.torrentSocket.off('newStatistic', this.newStatisticFunc); if(this.remoteSearchTorrent) window.torrentSocket.off('remoteSearchTorrent', this.remoteSearchTorrent); if(this.remoteSearchFiles) window.torrentSocket.off('remoteSearchFiles', this.remoteSearchFiles); } setSafeSearch(ch) { this.notSafeSearch = ch; if(ch) { return {safeSearchText: __('safe search disabled'), safeSearchColor: '#EC407A'} } else { return {safeSearchText: __('safe search enabled'), safeSearchColor: 'rgb(0, 188, 212)'} } } render() { const style = { refresh: { display: 'inline-block', position: 'relative', }, }; return (
{ ((this.searchTorrents && this.searchTorrents.length > 0) || (this.searchFiles && this.searchFiles.length > 0)) &&
} iconStyle={{fill: '#27ce74'}} onCheck={() => { if(window.routerCurrent() !== '/search') window.router('/search') }} style={{paddingTop: '0.6em', paddingLeft: '0.2em'}} />
} { if (e.key === 'Enter') { this.search(); } }} onChange={e => { this.searchValue = e.target.value if(this.searchValue.length < 3 && this.searchValue.length > 0) this.searchError = __('too short string for search'); else this.searchError = undefined; this.forceUpdate() }} />
} uncheckedIcon={} iconStyle={{fill: this.state.safeSearchColor}} onCheck={(ev, ch) => { this.setState(this.setSafeSearch(ch)); }} style={{paddingBottom: '0.8em'}} />
} uncheckedIcon={} iconStyle={{fill: 'black'}} onCheck={(ev, ch) => { this.setState({advancedSearch: ch}); }} style={{paddingBottom: '0.8em'}} />
{ this.search() }} />
{ this.state.advancedSearch && { this.advanced = state; }} state={this.advanced} /> } { this.stats && } { this.state.searchingIndicator ?
: null }
); } } export default singleton(Search)