diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp index c52521d0a..636f7e530 100755 --- a/libtorrent/include/libtorrent/piece_picker.hpp +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -42,7 +42,6 @@ POSSIBILITY OF SUCH DAMAGE. #pragma warning(push, 1) #endif -#include #include #ifdef _MSC_VER @@ -90,10 +89,11 @@ namespace libtorrent struct block_info { - block_info(): num_downloads(0), state(state_none) {} + block_info(): peer(0), num_downloads(0), state(state_none) {} // the peer this block was requested or - // downloaded from - tcp::endpoint peer; + // downloaded from. This is a pointer to + // a policy::peer object + void* peer; // the number of times this block has been downloaded unsigned num_downloads:14; enum { state_none, state_requested, state_writing, state_finished }; @@ -185,12 +185,16 @@ namespace libtorrent // decides to download a piece, it must mark it as being downloaded // itself, by using the mark_as_downloading() member function. // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION! - // The last argument is the tcp::endpoint of the peer that we'll download - // from. + // The last argument is the policy::peer pointer for the peer that + // we'll download from. void pick_pieces(const std::vector& pieces , std::vector& interesting_blocks , int num_pieces, bool prefer_whole_pieces - , tcp::endpoint peer, piece_state_t speed) const; + , void* peer, piece_state_t speed) const; + + // clears the peer pointer in all downloading pieces with this + // peer pointer + void clear_peer(void* peer); // returns true if any client is currently downloading this // piece-block, or if it's queued for downloading by some client @@ -202,10 +206,10 @@ namespace libtorrent bool is_finished(piece_block block) const; // marks this piece-block as queued for downloading - void mark_as_downloading(piece_block block, tcp::endpoint const& peer + void mark_as_downloading(piece_block block, void* peer , piece_state_t s); - void mark_as_writing(piece_block block, tcp::endpoint const& peer); - void mark_as_finished(piece_block block, tcp::endpoint const& peer); + void mark_as_writing(piece_block block, void* peer); + void mark_as_finished(piece_block block, void* peer); // if a piece had a hash-failure, it must be restored and // made available for redownloading @@ -224,12 +228,12 @@ namespace libtorrent // the hash-check yet int unverified_blocks() const; - void get_downloaders(std::vector& d, int index) const; + void get_downloaders(std::vector& d, int index) const; std::vector const& get_download_queue() const { return m_downloads; } - boost::optional get_downloader(piece_block block) const; + void* get_downloader(piece_block block) const; // the number of filtered pieces we don't have int num_filtered() const { return m_num_filtered; } @@ -348,7 +352,7 @@ namespace libtorrent , std::vector& interesting_blocks , std::vector& backup_blocks , int num_blocks, bool prefer_whole_pieces - , tcp::endpoint peer, piece_state_t speed) const; + , void* peer, piece_state_t speed) const; downloading_piece& add_download_piece(); void erase_download_piece(std::vector::iterator i); diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index 1274c46fc..90a9c2c57 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -272,6 +272,16 @@ namespace libtorrent return i->second; } + peer_connection* connection_for(address const& a) + { + for (peer_iterator i = m_connections.begin() + , end(m_connections.end()); i != end; ++i) + { + if (i->first.address() == a) return i->second; + } + return 0; + } + // the number of peers that belong to this torrent int num_peers() const { return (int)m_connections.size(); } int num_seeds() const; diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 8a2ac0ae3..739378c85 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -397,15 +397,6 @@ namespace libtorrent try { (*i)->on_piece_pass(index); } catch (std::exception&) {} } #endif - - if (peer_info_struct()) - { - peer_info_struct()->on_parole = false; - int& trust_points = peer_info_struct()->trust_points; - trust_points++; - // TODO: make this limit user settable - if (trust_points > 20) trust_points = 20; - } } void peer_connection::received_invalid_data(int index) @@ -1185,7 +1176,7 @@ namespace libtorrent fs.async_write(p, data, bind(&peer_connection::on_disk_write_complete , self(), _1, _2, p, t)); - picker.mark_as_writing(block_finished, m_remote); + picker.mark_as_writing(block_finished, peer_info_struct()); if (request_peer && !request_peer->has_peer_choked() && !t->is_seed()) { @@ -1224,7 +1215,7 @@ namespace libtorrent assert(p.piece == j.piece); assert(p.start == j.offset); piece_block block_finished(p.piece, p.start / t->block_size()); - picker.mark_as_finished(block_finished, m_remote); + picker.mark_as_finished(block_finished, peer_info_struct()); if (!has_peer_choked() && !t->is_seed() && !m_torrent.expired()) { @@ -1336,7 +1327,7 @@ namespace libtorrent else if (speed == medium) state = piece_picker::medium; else state = piece_picker::slow; - t->picker().mark_as_downloading(block, m_remote, state); + t->picker().mark_as_downloading(block, peer_info_struct(), state); m_request_queue.push_back(block); } diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index bd568210f..a1afc6bc3 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -116,11 +116,10 @@ namespace libtorrent for (std::vector::const_iterator i = unfinished.begin(); i != unfinished.end(); ++i) { - tcp::endpoint peer; for (int j = 0; j < m_blocks_per_piece; ++j) { if (i->info[j].state == block_info::state_finished) - mark_as_finished(piece_block(i->index, j), peer); + mark_as_finished(piece_block(i->index, j), 0); } if (is_piece_finished(i->index)) { @@ -212,7 +211,7 @@ namespace libtorrent { ret.info[i].num_downloads = 0; ret.info[i].state = block_info::state_none; - ret.info[i].peer = tcp::endpoint(); + ret.info[i].peer = 0; } return ret; } @@ -1001,10 +1000,10 @@ namespace libtorrent // prefer_whole_pieces can be set if this peer should download // whole pieces rather than trying to download blocks from the // same piece as other peers. - // the endpoint is the address of the peer we're picking pieces - // from. This is used when downloading whole pieces, to only - // pick from the same piece the same peer is downloading from. - // state is supposed to be set to fast if the peer is downloading + // the void* is the pointer to the policy::peer of the peer we're + // picking pieces from. This is used when downloading whole pieces, + // to only pick from the same piece the same peer is downloading + // from. state is supposed to be set to fast if the peer is downloading // relatively fast, by some notion. Slow peers will prefer not // to pick blocks from the same pieces as fast peers, and vice // versa. Downloading pieces are marked as being fast, medium @@ -1012,7 +1011,7 @@ namespace libtorrent void piece_picker::pick_pieces(const std::vector& pieces , std::vector& interesting_blocks , int num_blocks, bool prefer_whole_pieces - , tcp::endpoint peer, piece_state_t speed) const + , void* peer, piece_state_t speed) const { TORRENT_PIECE_PICKER_INVARIANT_CHECK; assert(num_blocks > 0); @@ -1063,17 +1062,25 @@ namespace libtorrent + (std::min)(num_blocks, (int)backup_blocks.size())); } + void piece_picker::clear_peer(void* peer) + { + for (std::vector::iterator i = m_block_info.begin() + , end(m_block_info.end()); i != end; ++i) + if (i->peer == peer) i->peer = 0; + } + namespace { bool exclusively_requested_from(piece_picker::downloading_piece const& p - , int num_blocks_in_piece, tcp::endpoint peer) + , int num_blocks_in_piece, void* peer) { for (int j = 0; j < num_blocks_in_piece; ++j) { piece_picker::block_info const& info = p.info[j]; if (info.state != piece_picker::block_info::state_none && info.peer != peer - && info.peer != tcp::endpoint()) + && info.peer != 0 + && static_cast(info.peer)->connection) { return false; } @@ -1087,7 +1094,7 @@ namespace libtorrent , std::vector& interesting_blocks , std::vector& backup_blocks , int num_blocks, bool prefer_whole_pieces - , tcp::endpoint peer, piece_state_t speed) const + , void* peer, piece_state_t speed) const { // if we have less than 1% of the pieces, ignore speed priorities and just try // to finish any downloading piece @@ -1281,7 +1288,7 @@ namespace libtorrent void piece_picker::mark_as_downloading(piece_block block - , const tcp::endpoint& peer, piece_state_t state) + , void* peer, piece_state_t state) { TORRENT_PIECE_PICKER_INVARIANT_CHECK; @@ -1330,7 +1337,7 @@ namespace libtorrent *j = i->peer_count; } - void piece_picker::mark_as_writing(piece_block block, tcp::endpoint const& peer) + void piece_picker::mark_as_writing(piece_block block, void* peer) { TORRENT_PIECE_PICKER_INVARIANT_CHECK; @@ -1367,7 +1374,7 @@ namespace libtorrent = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); assert(i != m_downloads.end()); block_info& info = i->info[block.block_index]; - info.peer == peer; + info.peer = peer; assert(info.state == block_info::state_requested); if (info.state == block_info::state_requested) --i->requested; assert(i->requested >= 0); @@ -1384,7 +1391,7 @@ namespace libtorrent } } - void piece_picker::mark_as_finished(piece_block block, tcp::endpoint const& peer) + void piece_picker::mark_as_finished(piece_block block, void* peer) { assert(block.piece_index >= 0); assert(block.block_index >= 0); @@ -1397,7 +1404,7 @@ namespace libtorrent { TORRENT_PIECE_PICKER_INVARIANT_CHECK; - assert(peer == tcp::endpoint()); + assert(peer == 0); int prio = p.priority(m_sequenced_download_threshold); p.downloading = 1; if (prio > 0) move(prio, p.index); @@ -1424,7 +1431,7 @@ namespace libtorrent block_info& info = i->info[block.block_index]; info.peer = peer; assert(info.state == block_info::state_writing - || peer == tcp::endpoint()); + || peer == 0); if (info.state == block_info::state_writing) --i->writing; assert(i->writing >= 0); ++i->finished; @@ -1439,7 +1446,7 @@ namespace libtorrent } } - void piece_picker::get_downloaders(std::vector& d, int index) const + void piece_picker::get_downloaders(std::vector& d, int index) const { assert(index >= 0 && index <= (int)m_piece_map.size()); std::vector::const_iterator i @@ -1453,22 +1460,21 @@ namespace libtorrent } } - boost::optional piece_picker::get_downloader(piece_block block) const + void* piece_picker::get_downloader(piece_block block) const { std::vector::const_iterator i = std::find_if( m_downloads.begin() , m_downloads.end() , has_index(block.piece_index)); - if (i == m_downloads.end()) - return boost::optional(); + if (i == m_downloads.end()) return 0; assert(block.block_index >= 0); if (i->info[block.block_index].state == block_info::state_none) - return boost::optional(); + return 0; - return boost::optional(i->info[block.block_index].peer); + return i->info[block.block_index].peer; } void piece_picker::abort_download(piece_block block) @@ -1505,7 +1511,7 @@ namespace libtorrent --i->requested; // clear the downloader of this block - i->info[block.block_index].peer = tcp::endpoint(); + i->info[block.block_index].peer = 0; // if there are no other blocks in this piece // that's being downloaded, remove it from the list diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index eca5ba613..917694721 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -54,6 +54,11 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/invariant_check.hpp" #include "libtorrent/time.hpp" #include "libtorrent/aux_/session_impl.hpp" +#include "libtorrent/piece_picker.hpp" + +#ifndef NDEBUG +#include "libtorrent/bt_peer_connection.hpp" +#endif namespace libtorrent { @@ -189,6 +194,7 @@ namespace libtorrent { assert(!t.is_seed()); assert(!c.has_peer_choked()); + assert(c.peer_info_struct() != 0 || !dynamic_cast(&c)); int num_requests = c.desired_queue_size() - (int)c.download_queue().size() - (int)c.request_queue().size(); @@ -233,7 +239,7 @@ namespace libtorrent // for this peer. If we're downloading one piece in 20 seconds // then use this mode. p.pick_pieces(c.get_bitfield(), interesting_pieces - , num_requests, prefer_whole_pieces, c.remote(), state); + , num_requests, prefer_whole_pieces, c.peer_info_struct(), state); // this vector is filled with the interesting pieces // that some other peer is currently downloading @@ -680,6 +686,10 @@ namespace libtorrent if (m_torrent->is_paused()) return; + piece_picker* p = 0; + if (m_torrent->has_picker()) + p = &m_torrent->picker(); + ptime now = time_now(); // remove old disconnected peers from the list for (iterator i = m_peers.begin(); i != m_peers.end();) @@ -689,6 +699,7 @@ namespace libtorrent && i->connected != min_time() && now - i->connected > minutes(120)) { + if (p) p->clear_peer(&(*i)); m_peers.erase(i++); } else @@ -1393,17 +1404,21 @@ namespace libtorrent for (const_iterator i = m_peers.begin(); i != m_peers.end(); ++i) { + peer const& p = *i; if (!m_torrent->settings().allow_multiple_connections_per_ip) - assert(unique_test.find(i->ip.address()) == unique_test.end()); - unique_test.insert(i->ip.address()); + assert(unique_test.find(p.ip.address()) == unique_test.end()); + unique_test.insert(p.ip.address()); ++total_connections; - if (!i->connection) continue; - assert(i->connection->peer_info_struct() == 0 - || i->connection->peer_info_struct() == &*i); + if (!p.connection) continue; + if (!m_torrent->settings().allow_multiple_connections_per_ip) + assert(p.connection == m_torrent->connection_for(p.ip.address()) + || p.connection == m_torrent->connection_for(p.ip)); + assert(p.connection->peer_info_struct() == 0 + || p.connection->peer_info_struct() == &p); ++nonempty_connections; - if (!i->connection->is_disconnecting()) + if (!p.connection->is_disconnecting()) ++connected_peers; - if (!i->connection->is_choked()) ++actual_unchoked; + if (!p.connection->is_choked()) ++actual_unchoked; } // assert(actual_unchoked <= m_torrent->m_uploads_quota.given); assert(actual_unchoked == m_num_unchoked); @@ -1419,6 +1434,33 @@ namespace libtorrent ++num_torrent_peers; } + if (m_torrent->has_picker()) + { + piece_picker& p = m_torrent->picker(); + std::vector downloaders = p.get_download_queue(); + + std::set peer_set; + std::vector peers; + for (std::vector::iterator i = downloaders.begin() + , end(downloaders.end()); i != end; ++i) + { + p.get_downloaders(peers, i->index); + std::copy(peers.begin(), peers.end() + , std::insert_iterator >(peer_set, peer_set.begin())); + } + + for (std::set::iterator i = peer_set.begin() + , end(peer_set.end()); i != end; ++i) + { + policy::peer* p = static_cast(*i); + if (p == 0) continue; + std::list::const_iterator k = m_peers.begin(); + for (; k != m_peers.end(); ++k) + if (&(*k) == p) break; + assert(k != m_peers.end()); + } + } + // this invariant is a bit complicated. // the usual case should be that connected_peers // == num_torrent_peers. But when there's an incoming diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index d173f8943..788c45c57 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -914,13 +914,13 @@ namespace libtorrent // increase the total amount of failed bytes m_total_failed_bytes += m_torrent_file.piece_size(index); - std::vector downloaders; + std::vector downloaders; m_picker->get_downloaders(downloaders, index); // decrease the trust point of all peers that sent // parts of this piece. // first, build a set of all peers that participated - std::set peers; + std::set peers; std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin())); #ifndef TORRENT_DISABLE_EXTENSIONS @@ -931,19 +931,22 @@ namespace libtorrent } #endif - for (std::set::iterator i = peers.begin() + for (std::set::iterator i = peers.begin() , end(peers.end()); i != end; ++i) { - peer_iterator p = m_connections.find(*i); - if (p == m_connections.end()) continue; - peer_connection& peer = *p->second; - peer.received_invalid_data(index); + policy::peer* p = static_cast(*i); + if (p == 0) continue; +#ifndef NDEBUG + if (!settings().allow_multiple_connections_per_ip) + assert(p->connection == 0 || p->connection == connection_for(p->ip.address()) + || p->connection == connection_for(p->ip)); +#endif + if (p->connection) p->connection->received_invalid_data(index); // either, we have received too many failed hashes // or this was the only peer that sent us this piece. // TODO: make this a changable setting - if ((peer.peer_info_struct() - && peer.peer_info_struct()->trust_points <= -7) + if (p->trust_points <= -7 || peers.size() == 1) { // we don't trust this peer anymore @@ -951,31 +954,22 @@ namespace libtorrent if (m_ses.m_alerts.should_post(alert::info)) { m_ses.m_alerts.post_alert(peer_ban_alert( - p->first + p->ip , get_handle() , "banning peer because of too many corrupt pieces")); } // mark the peer as banned - policy::peer* peerinfo = p->second->peer_info_struct(); - if (peerinfo) - { - peerinfo->banned = true; - } - else - { - // it might be a web seed - if (web_peer_connection const* wpc - = dynamic_cast(p->second)) - { - remove_url_seed(wpc->url()); - } - } + p->banned = true; + if (p->connection) + { #if defined(TORRENT_VERBOSE_LOGGING) - (*p->second->m_logger) << "*** BANNING PEER 'too many corrupt pieces'\n"; + (*p->connection->m_logger) << "*** BANNING PEER [ " << p->ip + << " ] 'too many corrupt pieces'\n"; #endif - p->second->disconnect(); + p->connection->disconnect(); + } } } @@ -1028,12 +1022,12 @@ namespace libtorrent assert(index >= 0); assert(index < m_torrent_file.num_pieces()); - std::vector downloaders; + std::vector downloaders; m_picker->get_downloaders(downloaders, index); // increase the trust point of all peers that sent // parts of this piece. - std::set peers; + std::set peers; std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin())); if (!m_have_pieces[index]) @@ -1047,12 +1041,16 @@ namespace libtorrent for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) try { i->second->announce_piece(index); } catch (std::exception&) {} - for (std::set::iterator i = peers.begin() + for (std::set::iterator i = peers.begin() , end(peers.end()); i != end; ++i) { - peer_iterator p = m_connections.find(*i); - if (p == m_connections.end()) continue; - p->second->received_valid_data(index); + policy::peer* p = static_cast(*i); + if (p == 0) continue; + p->on_parole = false; + ++p->trust_points; + // TODO: make this limit user settable + if (p->trust_points > 20) p->trust_points = 20; + if (p->connection) p->connection->received_valid_data(index); } #ifndef TORRENT_DISABLE_EXTENSIONS @@ -1900,6 +1898,8 @@ namespace libtorrent if (pp) p->add_extension(pp); } #endif + assert(connection_for(p->remote()) == p); + assert(ci->second == p); m_policy->new_connection(*ci->second); } catch (std::exception& e) diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index c9ade14e9..4ebe4e904 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -773,7 +773,17 @@ namespace libtorrent pi.blocks_in_piece = p.blocks_in_piece(i->index); for (int j = 0; j < pi.blocks_in_piece; ++j) { - pi.blocks[j].peer = i->info[j].peer; + if (i->info[j].peer == 0) + pi.blocks[j].peer = tcp::endpoint(); + else + { + policy::peer* p = static_cast(i->info[j].peer); + if (p->connection) + pi.blocks[j].peer = p->connection->remote(); + else + pi.blocks[j].peer = p->ip; + } + pi.blocks[j].num_downloads = i->info[j].num_downloads; pi.blocks[j].state = i->info[j].state; } diff --git a/po/deluge.pot b/po/deluge.pot index 4b8d5883a..c01792b2c 100644 --- a/po/deluge.pot +++ b/po/deluge.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-06-27 18:52-0500\n" +"POT-Creation-Date: 2007-07-04 14:16-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -81,7 +81,7 @@ msgid "Details" msgstr "" #: glade/delugegtk.glade:659 glade/delugegtk.glade:897 -#: glade/dgtkpopups.glade:37 src/interface.py:443 +#: glade/dgtkpopups.glade:37 src/interface.py:448 msgid "Peers" msgstr "" @@ -133,26 +133,26 @@ msgstr "" msgid "Columns" msgstr "" -#: glade/delugegtk.glade:870 glade/dgtkpopups.glade:10 src/interface.py:440 -#: src/interface.py:629 +#: glade/delugegtk.glade:870 glade/dgtkpopups.glade:10 src/interface.py:445 +#: src/interface.py:634 msgid "Size" msgstr "" -#: glade/delugegtk.glade:879 glade/dgtkpopups.glade:19 src/interface.py:441 +#: glade/delugegtk.glade:879 glade/dgtkpopups.glade:19 src/interface.py:446 msgid "Status" msgstr "" -#: glade/delugegtk.glade:888 glade/dgtkpopups.glade:28 src/interface.py:442 +#: glade/delugegtk.glade:888 glade/dgtkpopups.glade:28 src/interface.py:447 msgid "Seeders" msgstr "" -#: glade/delugegtk.glade:906 src/interface.py:444 src/interface.py:627 -#: src/interface.py:880 src/interface.py:892 +#: glade/delugegtk.glade:906 src/interface.py:449 src/interface.py:632 +#: src/interface.py:884 src/interface.py:896 msgid "Download" msgstr "" -#: glade/delugegtk.glade:915 src/interface.py:445 src/interface.py:881 -#: src/interface.py:893 +#: glade/delugegtk.glade:915 src/interface.py:450 src/interface.py:885 +#: src/interface.py:897 msgid "Upload" msgstr "" @@ -288,230 +288,230 @@ msgstr "" msgid "Download Location" msgstr "" -#: glade/preferences_dialog.glade:133 +#: glade/preferences_dialog.glade:132 glade/preferences_dialog.glade:145 +msgid "" +"The number of active torrents that Deluge will run. Set to -1 for unlimited." +msgstr "" + +#: glade/preferences_dialog.glade:134 msgid "Maximum simultaneous active torrents:" msgstr "" -#: glade/preferences_dialog.glade:144 -msgid "" -"The number of active torrents that Deluge will run. Set to 0 for unlimited." -msgstr "" - -#: glade/preferences_dialog.glade:164 +#: glade/preferences_dialog.glade:165 msgid "Torrents" msgstr "" -#: glade/preferences_dialog.glade:193 +#: glade/preferences_dialog.glade:194 msgid "" "Compact allocation will only allocate as much storage as it needs to keep " "the pieces downloaded so far." msgstr "" -#: glade/preferences_dialog.glade:194 +#: glade/preferences_dialog.glade:195 msgid "Use compact storage allocation" msgstr "" -#: glade/preferences_dialog.glade:205 +#: glade/preferences_dialog.glade:206 msgid "Compact Allocation" msgstr "" -#: glade/preferences_dialog.glade:238 +#: glade/preferences_dialog.glade:239 msgid "Queue torrents to bottom when they begin seeding" msgstr "" -#: glade/preferences_dialog.glade:251 +#: glade/preferences_dialog.glade:252 msgid "Stop seeding torrents when their share ratio reaches:" msgstr "" -#: glade/preferences_dialog.glade:287 +#: glade/preferences_dialog.glade:288 msgid "Seeding" msgstr "" -#: glade/preferences_dialog.glade:323 +#: glade/preferences_dialog.glade:324 glade/preferences_dialog.glade:453 msgid "The maximum upload rate for all torrents. Set -1 for unlimited." msgstr "" -#: glade/preferences_dialog.glade:341 +#: glade/preferences_dialog.glade:342 glade/preferences_dialog.glade:433 msgid "The maximum download rate for all torrents. Set -1 for unlimited." msgstr "" -#: glade/preferences_dialog.glade:358 +#: glade/preferences_dialog.glade:359 glade/preferences_dialog.glade:413 msgid "The maximum number of upload slots. Set -1 for unlimited." msgstr "" -#: glade/preferences_dialog.glade:375 +#: glade/preferences_dialog.glade:376 glade/preferences_dialog.glade:395 msgid "The maximum number of connections allowed. Set -1 for unlimited." msgstr "" -#: glade/preferences_dialog.glade:395 +#: glade/preferences_dialog.glade:397 msgid "Maximum Connections:" msgstr "" -#: glade/preferences_dialog.glade:412 +#: glade/preferences_dialog.glade:415 msgid "Upload Slots:" msgstr "" -#: glade/preferences_dialog.glade:431 +#: glade/preferences_dialog.glade:435 msgid "Maximum Download Rate (KiB/s):" msgstr "" -#: glade/preferences_dialog.glade:450 +#: glade/preferences_dialog.glade:455 msgid "Maximum Upload Rate (KiB/s):" msgstr "" -#: glade/preferences_dialog.glade:467 +#: glade/preferences_dialog.glade:472 msgid "Bandwidth Usage" msgstr "" -#: glade/preferences_dialog.glade:494 +#: glade/preferences_dialog.glade:499 msgid "Downloads" msgstr "" -#: glade/preferences_dialog.glade:539 +#: glade/preferences_dialog.glade:544 msgid "" "Please Note - Changes to these settings will only be applied the next " "time Deluge is restarted." msgstr "" -#: glade/preferences_dialog.glade:582 +#: glade/preferences_dialog.glade:587 msgid "From:" msgstr "" -#: glade/preferences_dialog.glade:605 +#: glade/preferences_dialog.glade:610 msgid "To:" msgstr "" -#: glade/preferences_dialog.glade:630 +#: glade/preferences_dialog.glade:635 msgid "Active Port:" msgstr "" -#: glade/preferences_dialog.glade:643 +#: glade/preferences_dialog.glade:648 msgid "0000" msgstr "" -#: glade/preferences_dialog.glade:658 +#: glade/preferences_dialog.glade:663 msgid "Test Active Port" msgstr "" -#: glade/preferences_dialog.glade:680 +#: glade/preferences_dialog.glade:685 msgid "TCP Port" msgstr "" -#: glade/preferences_dialog.glade:712 +#: glade/preferences_dialog.glade:717 msgid "Distributed hash table may improve the amount of active connections." msgstr "" -#: glade/preferences_dialog.glade:713 +#: glade/preferences_dialog.glade:718 msgid "Enable Mainline DHT" msgstr "" -#: glade/preferences_dialog.glade:729 +#: glade/preferences_dialog.glade:734 msgid "DHT" msgstr "" -#: glade/preferences_dialog.glade:764 +#: glade/preferences_dialog.glade:769 msgid "Universal Plug and Play" msgstr "" -#: glade/preferences_dialog.glade:765 +#: glade/preferences_dialog.glade:770 msgid "UPnP" msgstr "" -#: glade/preferences_dialog.glade:779 +#: glade/preferences_dialog.glade:784 msgid "NAT Port Mapping Protocol" msgstr "" -#: glade/preferences_dialog.glade:780 +#: glade/preferences_dialog.glade:785 msgid "NAT-PMP" msgstr "" -#: glade/preferences_dialog.glade:795 +#: glade/preferences_dialog.glade:800 msgid "µTorrent Peer-Exchange" msgstr "" -#: glade/preferences_dialog.glade:796 +#: glade/preferences_dialog.glade:801 msgid "µTorrent-PeX" msgstr "" -#: glade/preferences_dialog.glade:814 +#: glade/preferences_dialog.glade:819 msgid "Network Extras" msgstr "" -#: glade/preferences_dialog.glade:855 +#: glade/preferences_dialog.glade:860 msgid "Inbound:" msgstr "" -#: glade/preferences_dialog.glade:864 glade/preferences_dialog.glade:886 +#: glade/preferences_dialog.glade:869 glade/preferences_dialog.glade:891 msgid "" "Disabled\n" "Enabled\n" "Forced" msgstr "" -#: glade/preferences_dialog.glade:877 +#: glade/preferences_dialog.glade:882 msgid "Outbound:" msgstr "" -#: glade/preferences_dialog.glade:904 +#: glade/preferences_dialog.glade:909 msgid "Prefer to encrypt the entire stream" msgstr "" -#: glade/preferences_dialog.glade:917 +#: glade/preferences_dialog.glade:922 msgid "Level:" msgstr "" -#: glade/preferences_dialog.glade:926 +#: glade/preferences_dialog.glade:931 msgid "" "Handshake\n" "Either\n" "Full Stream" msgstr "" -#: glade/preferences_dialog.glade:947 +#: glade/preferences_dialog.glade:952 msgid "Encryption" msgstr "" -#: glade/preferences_dialog.glade:980 +#: glade/preferences_dialog.glade:985 msgid "Affects regular bittorrent peers" msgstr "" -#: glade/preferences_dialog.glade:981 +#: glade/preferences_dialog.glade:986 msgid "Peer Proxy" msgstr "" -#: glade/preferences_dialog.glade:991 +#: glade/preferences_dialog.glade:996 msgid "" "Only affects HTTP tracker connections (UDP tracker connections are affected " "if the given proxy supports UDP, e.g. SOCKS5)." msgstr "" -#: glade/preferences_dialog.glade:992 +#: glade/preferences_dialog.glade:997 msgid "Tracker Proxy" msgstr "" -#: glade/preferences_dialog.glade:1005 +#: glade/preferences_dialog.glade:1010 msgid "" "Affects the DHT messages. Since they are sent over UDP, it only has any " "effect if the proxy supports UDP." msgstr "" -#: glade/preferences_dialog.glade:1006 +#: glade/preferences_dialog.glade:1011 msgid "DHT Proxy" msgstr "" -#: glade/preferences_dialog.glade:1032 +#: glade/preferences_dialog.glade:1037 msgid "Proxy type" msgstr "" -#: glade/preferences_dialog.glade:1039 +#: glade/preferences_dialog.glade:1044 msgid "Username" msgstr "" -#: glade/preferences_dialog.glade:1050 +#: glade/preferences_dialog.glade:1055 msgid "Password" msgstr "" -#: glade/preferences_dialog.glade:1061 +#: glade/preferences_dialog.glade:1066 msgid "" "None\n" "Socksv4\n" @@ -521,51 +521,51 @@ msgid "" "HTTP W/ Auth" msgstr "" -#: glade/preferences_dialog.glade:1104 +#: glade/preferences_dialog.glade:1109 msgid "Server" msgstr "" -#: glade/preferences_dialog.glade:1115 +#: glade/preferences_dialog.glade:1120 msgid "Port" msgstr "" -#: glade/preferences_dialog.glade:1159 +#: glade/preferences_dialog.glade:1164 msgid "Proxy" msgstr "" -#: glade/preferences_dialog.glade:1186 +#: glade/preferences_dialog.glade:1191 msgid "Network" msgstr "" -#: glade/preferences_dialog.glade:1227 +#: glade/preferences_dialog.glade:1232 msgid "Enable system tray icon" msgstr "" -#: glade/preferences_dialog.glade:1241 +#: glade/preferences_dialog.glade:1246 msgid "Minimize to tray on close" msgstr "" -#: glade/preferences_dialog.glade:1264 +#: glade/preferences_dialog.glade:1269 msgid "Password protect system tray" msgstr "" -#: glade/preferences_dialog.glade:1281 +#: glade/preferences_dialog.glade:1286 msgid "Password:" msgstr "" -#: glade/preferences_dialog.glade:1322 +#: glade/preferences_dialog.glade:1327 msgid "System Tray" msgstr "" -#: glade/preferences_dialog.glade:1353 +#: glade/preferences_dialog.glade:1358 msgid "GUI update interval (seconds)" msgstr "" -#: glade/preferences_dialog.glade:1381 +#: glade/preferences_dialog.glade:1386 msgid "Performance" msgstr "" -#: glade/preferences_dialog.glade:1409 +#: glade/preferences_dialog.glade:1414 msgid "Other" msgstr "" @@ -625,7 +625,7 @@ msgstr "" msgid "_Quit" msgstr "" -#: src/common.py:54 src/interface.py:417 +#: src/common.py:54 src/interface.py:422 msgid "Infinity" msgstr "" @@ -648,143 +648,153 @@ msgstr "" msgid "Error: no webbrowser found" msgstr "" -#: src/core.py:332 +#: src/core.py:119 +#, python-format +msgid "%d %d bytes needed" +msgstr "" + +#: src/core.py:335 msgid "File was not found" msgstr "" -#: src/interface.py:190 src/interface.py:193 src/interface.py:244 -#: src/interface.py:266 +#: src/interface.py:195 src/interface.py:198 src/interface.py:249 +#: src/interface.py:271 msgid "KiB/s" msgstr "" -#: src/interface.py:237 src/interface.py:248 src/interface.py:270 +#: src/interface.py:242 src/interface.py:253 src/interface.py:275 msgid "Other..." msgstr "" -#: src/interface.py:245 src/interface.py:267 src/interface.py:865 -#: src/interface.py:871 src/interface.py:875 +#: src/interface.py:250 src/interface.py:272 src/interface.py:869 +#: src/interface.py:875 src/interface.py:879 msgid "Unlimited" msgstr "" -#: src/interface.py:293 +#: src/interface.py:298 msgid "Deluge is locked" msgstr "" -#: src/interface.py:295 +#: src/interface.py:300 msgid "" "Deluge is password protected.\n" "To show the Deluge window, please enter your password" msgstr "" -#: src/interface.py:425 +#: src/interface.py:430 msgid "Unknown" msgstr "" -#: src/interface.py:439 +#: src/interface.py:444 msgid "Name" msgstr "" -#: src/interface.py:446 +#: src/interface.py:451 msgid "ETA" msgstr "" -#: src/interface.py:447 +#: src/interface.py:452 msgid "Ratio" msgstr "" -#: src/interface.py:522 src/interface.py:561 src/interface.py:943 +#: src/interface.py:527 src/interface.py:566 src/interface.py:968 msgid "Resume" msgstr "" -#: src/interface.py:525 src/interface.py:564 src/interface.py:946 +#: src/interface.py:530 src/interface.py:569 src/interface.py:971 msgid "Pause" msgstr "" -#: src/interface.py:551 +#: src/interface.py:556 msgid "Pause/Resume" msgstr "" -#: src/interface.py:599 +#: src/interface.py:604 msgid "IP Address" msgstr "" -#: src/interface.py:600 +#: src/interface.py:605 msgid "Client" msgstr "" -#: src/interface.py:601 +#: src/interface.py:606 msgid "Percent Complete" msgstr "" -#: src/interface.py:602 +#: src/interface.py:607 msgid "Download Rate" msgstr "" -#: src/interface.py:603 +#: src/interface.py:608 msgid "Upload Rate" msgstr "" -#: src/interface.py:628 +#: src/interface.py:633 msgid "Filename" msgstr "" -#: src/interface.py:630 +#: src/interface.py:635 msgid "Offset" msgstr "" -#: src/interface.py:631 +#: src/interface.py:636 msgid "Progress" msgstr "" -#: src/interface.py:851 +#: src/interface.py:752 +#, python-format +msgid "Paused %s" +msgstr "" + +#: src/interface.py:855 msgid "" "For some reason, the previous state could not be loaded, so a blank state " "has been loaded for you." msgstr "" -#: src/interface.py:853 +#: src/interface.py:857 msgid "Would you like to attempt to reload the previous session's downloads?" msgstr "" -#: src/interface.py:880 src/interface.py:892 +#: src/interface.py:884 src/interface.py:896 msgid "Connections" msgstr "" -#: src/interface.py:891 +#: src/interface.py:895 msgid "Deluge Bittorrent Client" msgstr "" -#: src/interface.py:1106 +#: src/interface.py:1131 msgid "" "An error occured while trying to add the torrent. It's possible your ." "torrent file is corrupted." msgstr "" -#: src/interface.py:1108 +#: src/interface.py:1133 msgid "The torrent you've added seems to already be in Deluge." msgstr "" -#: src/interface.py:1112 +#: src/interface.py:1137 msgid "There is not enough free disk space to complete your download." msgstr "" -#: src/interface.py:1113 +#: src/interface.py:1138 msgid "Space Needed:" msgstr "" -#: src/interface.py:1114 +#: src/interface.py:1139 msgid "Available Space:" msgstr "" -#: src/interface.py:1124 +#: src/interface.py:1149 msgid "Add torrent from URL" msgstr "" -#: src/interface.py:1128 +#: src/interface.py:1153 msgid "Enter the URL of the .torrent to download" msgstr "" -#: src/interface.py:1218 +#: src/interface.py:1244 msgid "Warning - all downloaded files for this torrent will be deleted!" msgstr "" @@ -812,6 +822,6 @@ msgstr "" msgid "All files" msgstr "" -#: src/dialogs.py:295 +#: src/dialogs.py:296 msgid "Choose a download directory" msgstr "" diff --git a/src/core.py b/src/core.py index 5396ebe49..8c8cc2625 100644 --- a/src/core.py +++ b/src/core.py @@ -74,16 +74,18 @@ PREF_FUNCTIONS = { "use_utpex" : deluge_core.use_utpex, } -STATE_MESSAGES = ( "Queued", - "Checking", - "Connecting", - "Downloading Metadata", - "Downloading", - "Finished", - "Seeding", - "Allocating" - ) +def N_(self): + return self +STATE_MESSAGES = ( N_("Queued"), + N_("Checking)"), + N_("Connecting"), + N_("Downloading Metadata"), + N_("Downloading"), + N_("Finished"), + N_("Seeding"), + N_("Allocating") + ) # Exceptions class DelugeError(Exception): @@ -114,7 +116,7 @@ class InsufficientFreeSpaceError(DelugeError): self.free_space = free_space self.needed_space = needed_space def __str__(self): - return "%d %d bytes needed"%(self.free_space, self.needed_space) + return _("%d %d bytes needed")%(self.free_space, self.needed_space) # A cached data item diff --git a/src/interface.py b/src/interface.py index 26fbca8e1..2c69c5ea9 100644 --- a/src/interface.py +++ b/src/interface.py @@ -749,10 +749,10 @@ class DelugeGTK: progress = torrent_state['progress'] progress = '%d%%'%int(progress * 100) if is_paused: - message = 'Paused %s'%progress + message = _("Paused %s")%progress else: try: - message = core.STATE_MESSAGES[state] + message = _(core.STATE_MESSAGES[state]) if state in (1, 3, 4, 7): message = '%s %s'%(message, progress) except IndexError: