pieces tab update - micah

This commit is contained in:
Marcos Pinto 2007-08-03 17:59:32 +00:00
parent ba53e0268f
commit 0585d0930e
6 changed files with 266 additions and 52 deletions

View File

@ -18,7 +18,7 @@
plugin_name = _("Torrent Pieces")
plugin_author = "Micah Bucy"
plugin_version = "0.1"
plugin_version = "0.2"
plugin_description = _("""
Adds a pieces tab which gives piece by piece progress for a torrent.
Each piece is represented by a small progress bar.
@ -33,7 +33,11 @@ of blocks finished as well as the peer speed for that piece.
When the plugin initializes, such as when enabling the plugin or
when a different torrent is selected, the cpu will spike. This is normal,
as initialization must get information on every piece from libtorrent,
and the cpu will normalize once all of the information is retrieved.""")
and the cpu will normalize once all of the information is retrieved.
This plugin supports multifile torrents. If a file is skipped, it does not
show up in the pieces tab.
""")
def deluge_init(deluge_path):
global path
@ -80,12 +84,14 @@ class TorrentPieces:
break
def update(self):
update_files_removed = self.manager.update_files_removed
unique_id = self.parent.get_selected_torrent()
# If no torrents added or more than one torrent selected
if unique_id is None:
#if no torrents added or more than one torrent selected
self.tab_pieces.clear_pieces_store()
return
if unique_id != self.tab_pieces.unique_id:
if unique_id != self.tab_pieces.unique_id or unique_id in update_files_removed.keys():
#if different torrent was selected or file priorities were changed.
self.manager.disconnect_event(self.manager.constants['EVENT_PIECE_FINISHED'], self.tab_pieces.handle_event)
self.manager.disconnect_event(self.manager.constants['EVENT_BLOCK_FINISHED'], self.tab_pieces.handle_event)
self.manager.disconnect_event(self.manager.constants['EVENT_BLOCK_DOWNLOADING'], self.tab_pieces.handle_event)

View File

@ -1,11 +1,11 @@
from itertools import izip
import gtk
import math
class PiecesManager(object):
def __init__(self, viewport, manager):
self.viewport = viewport
self.table = None
self.vbox = None
self.manager = manager
self.progress = []
self.tooltips = []
@ -17,6 +17,8 @@ class PiecesManager(object):
self.unique_id = -1
self.peer_speed = []
self.piece_info = []
self.first_indexes = []
self.last_indexes = []
def set_unique_id(self, unique_id):
self.unique_id = unique_id
@ -24,59 +26,219 @@ class PiecesManager(object):
def clear_pieces_store(self):
self.unique_id = -1
self.rows = 0
if not self.table is None:
self.table.destroy()
self.table = None
if not self.vbox is None:
self.vbox.destroy()
self.vbox = None
self.peer_speed = []
self.eventboxes = []
self.progress = []
self.piece_info = []
self.tooltips = []
self.first_indexes = []
self.last_indexes = []
def prepare_pieces_store(self):
self.table = gtk.Table()
self.viewport.add(self.table)
self.vbox = gtk.VBox()
self.viewport.add(self.vbox)
all_files = self.manager.get_torrent_file_info(self.unique_id)
file_priorities = self.manager.get_priorities(self.unique_id)
state = self.manager.get_torrent_state(self.unique_id)
num_pieces = state["num_pieces"]
self.rows = int(math.ceil(num_pieces/self.columns))
self.table.resize(self.rows, self.columns)
self.table.set_size_request((self.columns+1)*self.piece_width, (self.rows+1)*self.piece_height)
for index in xrange(num_pieces):
prev_file_index = -1
file_index = 0
next_file_index = 1
for file, priority in izip(all_files, file_priorities):
if file_index == 0:
file_piece_range = self.manager.get_file_piece_range(self.unique_id,\
file_index, file['size'])
self.first_indexes.append(file_piece_range['first_index'])
self.last_indexes.append(file_piece_range['last_index'])
if priority > 0:
#if file is being downloaded build the file pieces information
temp_prev_priority = 1
label = gtk.Label()
label.set_alignment(0,0)
label.set_text(file['path'])
self.vbox.pack_start(label, expand=False)
table = gtk.Table()
self.rows = int(math.ceil((self.last_indexes[file_index]-self.first_indexes[file_index])/self.columns)+1)
self.vbox.pack_start(table, expand=False)
table.resize(self.rows, self.columns)
table.set_size_request((self.columns+1)*self.piece_width, (self.rows+1)*self.piece_height)
if self.last_indexes[file_index] != self.first_indexes[file_index]:
#if there is more than one piece
if self.first_indexes[file_index] == 0\
or self.first_indexes[file_index] != self.last_indexes[prev_file_index]:
#if first piece is not a shared piece
temp_range = self.last_indexes[file_index]-self.first_indexes[file_index]
diff = 0
else:
#if first piece is shared
temp_prev_priority = file_priorities[prev_file_index]
if temp_prev_priority > 0:
#if last file was not skipped, skip the first piece
diff = 1
temp_range = self.last_indexes[file_index]-(self.first_indexes[file_index]+1)
#otherwise keep the first piece
else:
diff = 0
temp_range = self.last_indexes[file_index]-self.first_indexes[file_index]
#last piece handled outside of loop, skip it from range
for index in xrange(temp_range):
main_index = diff+self.first_indexes[file_index]+index
if temp_prev_priority > 0:
#normal behavior
self.piece_info.append({'blocks_total':0, 'blocks_finished':0, 'blocks_requested':0})
self.progress.append(gtk.ProgressBar())
self.tooltips.append(gtk.Tooltips())
self.eventboxes.append(gtk.EventBox())
self.peer_speed.append("unknown")
self.progress[index].set_size_request(self.piece_width, self.piece_height)
else:
#if first piece is shared with a skipped file
self.piece_info[main_index] = {'blocks_total':0, 'blocks_finished':0, 'blocks_requested':0}
self.progress[main_index] = gtk.ProgressBar()
self.tooltips[main_index] = gtk.Tooltips()
self.eventboxes[main_index] = gtk.EventBox()
self.peer_speed[main_index] = "unknown"
temp_prev_priority = 1
self.progress[main_index].set_size_request(self.piece_width, self.piece_height)
row = index/self.columns
column = index%self.columns
self.table.attach(self.eventboxes[index], column, column+1, row, row+1,
table.attach(self.eventboxes[main_index], column, column+1, row, row+1,
xoptions=0, yoptions=0, xpadding=0, ypadding=0)
self.eventboxes[index].add(self.progress[index])
if self.manager.has_piece(self.unique_id, index):
self.progress[index].set_fraction(1)
self.tooltips[index].set_tip(self.eventboxes[index], _("Piece finished"))
self.eventboxes[main_index].add(self.progress[main_index])
if self.manager.has_piece(self.unique_id, main_index):
#if piece is already finished
self.progress[main_index].set_fraction(1)
self.tooltips[main_index].set_tip(self.eventboxes[main_index], _("Piece finished"))
else:
self.tooltips[index].set_tip(self.eventboxes[index], _("Piece not started"))
#if piece is not already finished
self.tooltips[main_index].set_tip(self.eventboxes[main_index], _("Piece not started"))
self.piece_info.append({'blocks_total':0, 'blocks_finished':0, 'blocks_requested':0})
self.progress.append(gtk.ProgressBar())
self.tooltips.append(gtk.Tooltips())
self.eventboxes.append(gtk.EventBox())
self.peer_speed.append("unknown")
index = index+1
only_one_piece = False
else:
#if file only has one piece
index = 0
only_one_piece = True
main_index = self.last_indexes[file_index]
# do the following even if file has only one piece
# and the piece does not need created
if next_file_index < len(all_files):
#if there is another file
file_piece_range = self.manager.get_file_piece_range(self.unique_id,\
next_file_index, all_files[next_file_index]['size'])
self.first_indexes.append(file_piece_range['first_index'])
self.last_indexes.append(file_piece_range['last_index'])
if file_index > 0 and not self.piece_info[main_index] is None and only_one_piece:
#if file has only one piece and it is shared destroy the table
table.destroy()
if file_index == 0 or self.piece_info[main_index] is None or not only_one_piece:
# piece could be shared if file has only one piece and it's not the first file
# only create it if it does not exist
if only_one_piece:
#if piece is shared with a skipped file
self.piece_info[main_index] = {'blocks_total':0, 'blocks_finished':0, 'blocks_requested':0}
self.progress[main_index] = gtk.ProgressBar()
self.tooltips[main_index] = gtk.Tooltips()
self.eventboxes[main_index] = gtk.EventBox()
self.peer_speed[main_index] = "unknown"
self.progress[main_index].set_size_request(self.piece_width, self.piece_height)
if next_file_index < len(all_files):
# if there is another file
if file_priorities[next_file_index]==0\
or self.last_indexes[file_index] != self.first_indexes[next_file_index]:
#if next file is skipped or there is no shared piece, keep last piece
row=index/self.columns
column=index%self.columns
table.attach(self.eventboxes[main_index], column, column+1, row, row+1,
xoptions=0, yoptions=0, xpadding=0, ypadding=0)
self.eventboxes[main_index].add(self.progress[main_index])
if file_priorities[next_file_index]>0\
and self.last_indexes[file_index] == self.first_indexes[next_file_index]:
#if next file is not skipped and there is a shared piece, do not keep last piece
if only_one_piece:
#only piece in file is shared, destroy table for file
table.destroy()
label = gtk.Label()
label.set_alignment(0,0)
label.set_text(_("Piece shared with next file(s)"))
self.vbox.pack_start(label, expand=False)
temp_table = gtk.Table()
temp_table.resize(1,2)
temp_table.set_size_request(self.piece_width, 2*self.piece_height)
temp_table.attach(self.eventboxes[main_index], 0, 1, 0, 1,
xoptions=0, yoptions=0, xpadding=0, ypadding=0)
self.eventboxes[main_index].add(self.progress[main_index])
self.vbox.pack_start(temp_table, expand=False)
else:
#if there is no other file
row=index/self.columns
column=index%self.columns
table.attach(self.eventboxes[main_index], column, column+1, row, row+1,
xoptions=0, yoptions=0, xpadding=0, ypadding=0)
self.eventboxes[main_index].add(self.progress[main_index])
if self.manager.has_piece(self.unique_id, main_index):
#if the last piece is already finished
self.progress[main_index].set_fraction(1)
self.tooltips[main_index].set_tip(self.eventboxes[main_index], _("Piece finished"))
else:
#if the last piece is not already finished
self.tooltips[main_index].set_tip(self.eventboxes[main_index], _("Piece not started"))
else:
#if file is not being downloaded skip the file pieces
if self.first_indexes[file_index] == 0 or self.first_indexes[file_index] != self.last_indexes[prev_file_index]:
#if first piece is not shared
temp_range = 1+self.last_indexes[file_index]-self.first_indexes[file_index]
else:
#if first piece is shared
temp_range = self.last_indexes[file_index]-self.first_indexes[file_index]
for index in xrange(temp_range):
self.piece_info.append(None)
self.progress.append(None)
self.eventboxes.append(None)
self.tooltips.append(None)
self.peer_speed.append(None)
if next_file_index < len(all_files):
#if there is another file
file_piece_range = self.manager.get_file_piece_range(self.unique_id,\
next_file_index, all_files[next_file_index]['size'])
self.first_indexes.append(file_piece_range['first_index'])
self.last_indexes.append(file_piece_range['last_index'])
if self.last_indexes[next_file_index] >= num_pieces:
self.last_indexes[next_file_index] = num_pieces-1
file_index += 1
next_file_index += 1
prev_file_index += 1
#get currently downloading piece information
all_piece_info = self.manager.get_all_piece_info(self.unique_id)
for piece_index in all_piece_info:
index = piece_index['piece_index']
if not self.piece_info[index] is None:
temp_piece_info = {'blocks_total':piece_index['blocks_total'], \
'blocks_finished':piece_index['blocks_finished']}
self.piece_info[piece_index['piece_index']] = temp_piece_info
self.piece_info[index] = temp_piece_info
blocks_total = str(temp_piece_info['blocks_total'])
info_string = str(temp_piece_info['blocks_finished']) + "/" + blocks_total + " " + _("blocks finished") + "\n" \
+ _("peer speed: unknown")
if self.progress[index].get_fraction() == 0:
self.progress[index].set_fraction(0.5)
self.tooltips[index].set_tip(self.eventboxes[index], info_string)
self.table.show_all()
self.vbox.show_all()
def handle_event(self, event):
#protect against pieces trying to display after file priority changed
#or different torrent selected
if event['unique_ID'] == self.unique_id\
and not self.piece_info[event['piece_index']] is None:
if event['event_type'] is self.manager.constants['EVENT_PIECE_FINISHED']:
if event['unique_ID'] == self.unique_id:
self.update_pieces_store(event['piece_index'], piece_finished=True)
elif event['event_type'] is self.manager.constants['EVENT_BLOCK_DOWNLOADING']:
if event['unique_ID'] == self.unique_id:
index = event['piece_index']
if self.piece_info[index]['blocks_total'] == 0:
self.piece_info[index] = self.manager.get_piece_info(self.unique_id, index)
@ -92,7 +254,6 @@ class PiecesManager(object):
self.peer_speed[index] = peer_speed_msg
self.update_pieces_store(index)
else:
if event['unique_ID'] == self.unique_id:
index = event['piece_index']
if self.piece_info[index]['blocks_total'] == 0:
self.piece_info[index] = self.manager.get_piece_info(self.unique_id, index)

View File

@ -246,6 +246,9 @@ class Manager:
# unique_ids removed by core
self.removed_unique_ids = {}
# unique_ids with files just removed by user
self.update_files_removed = {}
PREF_FUNCTIONS["enable_dht"] = self.set_DHT
# Unpickle the state, or create a new one
@ -318,6 +321,12 @@ class Manager:
# Get the value from the preferences object
return self.config.get(key)
# Get file piece range
def get_file_piece_range(self, unique_id,\
file_index, file_size):
return deluge_core.get_file_piece_range(unique_id,\
file_index, file_size)
# Check if piece is finished
def has_piece(self, unique_id, piece_index):
return deluge_core.has_piece(unique_id, piece_index)
@ -638,12 +647,17 @@ class Manager:
return ret
# Priorities functions
def prioritize_files(self, unique_ID, priorities):
def clear_update_files_removed(self):
self.update_files_removed = {}
def prioritize_files(self, unique_ID, priorities, update_files_removed=False):
assert(len(priorities) == \
self.get_core_torrent_state(unique_ID)['num_files'])
self.unique_IDs[unique_ID].priorities = priorities[:]
deluge_core.prioritize_files(unique_ID, priorities)
if update_files_removed:
self.update_files_removed[unique_ID] = 1
if self.get_pref('prioritize_first_last_pieces'):
self.prioritize_first_last_pieces(unique_ID)
@ -866,12 +880,14 @@ class Manager:
pass
else:
import random
ports = [random.randrange(49152, 65535), random.randrange(49152, 65535)]
randrange = lambda: random.randrange(49152, 65535)
ports = [randrange(), randrange()]
ports.sort()
deluge_core.set_listen_on(ports)
else:
import random
ports = [random.randrange(49152, 65535), random.randrange(49152, 65535)]
randrange = lambda: random.randrange(49152, 65535)
ports = [randrange(), randrange()]
ports.sort()
deluge_core.set_listen_on(ports)
else:

View File

@ -1261,6 +1261,26 @@ static PyObject *torrent_get_file_info(PyObject *self, PyObject *args)
return ret;
};
static PyObject *torrent_get_file_piece_range(PyObject *self, PyObject *args)
{
python_long unique_ID;
int file_index, file_size;
if (!PyArg_ParseTuple(args, "iii", &unique_ID, &file_index, &file_size))
return NULL;
long index = get_index_from_unique_ID(unique_ID);
if (PyErr_Occurred())
return NULL;
torrent_info const &info = M_torrents->at(index).handle.get_torrent_info();
peer_request first_index = info.map_file(file_index, 0, 1);
peer_request last_index = info.map_file(file_index, file_size-1, 1);
return Py_BuildValue(
"{s:i,s:i}",
"first_index", first_index.piece,
"last_index", last_index.piece
);
};
/*static PyObject *torrent_get_unique_IDs(PyObject *self, PyObject *args)
{
PyObject *ret = PyTuple_New(M_torrents.size());
@ -1878,6 +1898,7 @@ static PyMethodDef deluge_core_methods[] =
{"has_piece", torrent_has_piece, METH_VARARGS, "."},
{"get_piece_info", torrent_get_piece_info, METH_VARARGS, "."},
{"get_all_piece_info", torrent_get_all_piece_info, METH_VARARGS, "."},
{"get_file_piece_range", torrent_get_file_piece_range, METH_VARARGS, "."},
{NULL}
};

View File

@ -865,6 +865,9 @@ class DelugeGTK:
#Update any active plugins
self.plugins.update_active_plugins()
#Plugins have updated info, so clear it
self.manager.clear_update_files_removed()
# only update gui if it's needed
if self.update_interface:
# Put the generated message into the statusbar
@ -944,7 +947,6 @@ class DelugeGTK:
# Update tool buttons below based on the first selected torrent's state
path = torrent_selection.get_selected_rows()[1][0]
unique_id = self.torrent_model.get_value(self.torrent_model.get_iter(path), 0)
return True
def update_statusbar_and_tray(self):

View File

@ -190,8 +190,16 @@ class FilesTabManager(FilesBaseManager):
# From UI to core
def update_priorities(self):
file_priorities = [x[2] for x in self.file_store]
self.manager.prioritize_files(self.file_unique_id, file_priorities)
prev_file_priorities = self.manager.get_priorities(self.file_unique_id)
file_priorities = []
update = False
for x, priority in izip(self.file_store, prev_file_priorities):
file_priorities.append(x[2])
if x[2] > 0 and priority == 0:
update = True
if x[2] == 0:
update = True
self.manager.prioritize_files(self.file_unique_id, file_priorities, update_files_removed=update)
class FilesDialogManager(FilesBaseManager):
def __init__(self, dumped_torrent):