301 lines
10 KiB
Python
301 lines
10 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
|
|
#
|
|
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
|
|
# the additional special exception to link portions of this program with the OpenSSL library.
|
|
# See LICENSE for more details.
|
|
#
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
import logging
|
|
import os.path
|
|
|
|
from gi.repository import Gtk
|
|
from twisted.internet import defer
|
|
|
|
import deluge.component as component
|
|
from deluge.common import is_url, resource_filename
|
|
from deluge.configmanager import ConfigManager
|
|
from deluge.ui.client import client
|
|
|
|
from .common import get_deluge_icon
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def last_tier_trackers_from_liststore(trackers_liststore):
|
|
"""Create a list of tracker from existing liststore and find last tier number.
|
|
|
|
Args:
|
|
tracker_liststore (Gtk.ListStore): A Gtk.ListStore with [tier (int), tracker (str)] rows.
|
|
|
|
Returns:
|
|
tuple(int, list): A tuple containing last tier number and list of trackers.
|
|
|
|
"""
|
|
|
|
last_tier = 0
|
|
trackers_from_liststore = []
|
|
for tier, tracker in trackers_liststore:
|
|
trackers_from_liststore.append(tracker)
|
|
if tier >= last_tier:
|
|
last_tier = tier + 1
|
|
|
|
return last_tier, trackers_from_liststore
|
|
|
|
|
|
def trackers_tiers_from_text(text_str=''):
|
|
"""Create a list of trackers from text.
|
|
|
|
Any duplicate trackers are removed.
|
|
|
|
Args:
|
|
text_input (str): A block of text with tracker separated by newlines.
|
|
|
|
Returns:
|
|
list: The list of trackers.
|
|
|
|
Notes:
|
|
Trackers should be separated by newlines and empty line denotes start of new tier.
|
|
|
|
"""
|
|
|
|
trackers = {}
|
|
tier = 0
|
|
|
|
lines = text_str.strip().split('\n')
|
|
for line in lines:
|
|
if not line:
|
|
tier += 1
|
|
continue
|
|
line = line.replace('\\', '/') # Fix any mistyped urls.
|
|
if is_url(line) and line not in trackers:
|
|
trackers[line] = tier
|
|
|
|
return trackers
|
|
|
|
|
|
class EditTrackersDialog(object):
|
|
def __init__(self, torrent_id, parent=None):
|
|
self.torrent_id = torrent_id
|
|
self.builder = Gtk.Builder()
|
|
self.gtkui_config = ConfigManager('gtk3ui.conf')
|
|
|
|
# Main dialog
|
|
self.builder.add_from_file(
|
|
resource_filename(__package__, os.path.join('glade', 'edit_trackers.ui'))
|
|
)
|
|
# add tracker dialog
|
|
self.builder.add_from_file(
|
|
resource_filename(
|
|
__package__, os.path.join('glade', 'edit_trackers.add.ui')
|
|
)
|
|
)
|
|
# edit tracker dialog
|
|
self.builder.add_from_file(
|
|
resource_filename(
|
|
__package__, os.path.join('glade', 'edit_trackers.edit.ui')
|
|
)
|
|
)
|
|
|
|
self.dialog = self.builder.get_object('edit_trackers_dialog')
|
|
self.treeview = self.builder.get_object('tracker_treeview')
|
|
self.add_tracker_dialog = self.builder.get_object('add_tracker_dialog')
|
|
self.add_tracker_dialog.set_transient_for(self.dialog)
|
|
self.edit_tracker_entry = self.builder.get_object('edit_tracker_entry')
|
|
self.edit_tracker_entry.set_transient_for(self.dialog)
|
|
self.dialog.set_icon(get_deluge_icon())
|
|
|
|
self.load_edit_trackers_dialog_state()
|
|
|
|
if parent is not None:
|
|
self.dialog.set_transient_for(parent)
|
|
|
|
# Connect the signals
|
|
self.builder.connect_signals(self)
|
|
|
|
# Create a liststore for tier, url
|
|
self.liststore = Gtk.ListStore(int, str)
|
|
|
|
# Create the columns
|
|
self.treeview.append_column(
|
|
Gtk.TreeViewColumn(_('Tier'), Gtk.CellRendererText(), text=0)
|
|
)
|
|
self.treeview.append_column(
|
|
Gtk.TreeViewColumn(_('Tracker'), Gtk.CellRendererText(), text=1)
|
|
)
|
|
|
|
self.treeview.set_model(self.liststore)
|
|
self.liststore.set_sort_column_id(0, Gtk.SortType.ASCENDING)
|
|
|
|
self.dialog.connect('delete-event', self._on_delete_event)
|
|
self.dialog.connect('response', self._on_response)
|
|
|
|
def run(self):
|
|
# Make sure we have a torrent_id.. if not just return
|
|
if self.torrent_id is None:
|
|
return
|
|
|
|
# Get the trackers for this torrent
|
|
session = component.get('SessionProxy')
|
|
session.get_torrent_status(self.torrent_id, ['trackers']).addCallback(
|
|
self._on_get_torrent_status
|
|
)
|
|
client.force_call()
|
|
|
|
self.deferred = defer.Deferred()
|
|
return self.deferred
|
|
|
|
def __del__(self):
|
|
del self.gtkui_config
|
|
|
|
def load_edit_trackers_dialog_state(self):
|
|
w = self.gtkui_config['edit_trackers_dialog_width']
|
|
h = self.gtkui_config['edit_trackers_dialog_height']
|
|
if w is not None and h is not None:
|
|
self.dialog.resize(w, h)
|
|
|
|
def on_edit_trackers_dialog_configure_event(self, widget, event):
|
|
self.gtkui_config['edit_trackers_dialog_width'] = event.width
|
|
self.gtkui_config['edit_trackers_dialog_height'] = event.height
|
|
|
|
def _on_delete_event(self, widget, event):
|
|
self.deferred.callback(Gtk.ResponseType.DELETE_EVENT)
|
|
self.dialog.destroy()
|
|
|
|
def _on_response(self, widget, response):
|
|
if response == 1:
|
|
self.trackers = []
|
|
|
|
def each(model, path, _iter, data):
|
|
tracker = {}
|
|
tracker['tier'] = model.get_value(_iter, 0)
|
|
tracker['url'] = model.get_value(_iter, 1)
|
|
self.trackers.append(tracker)
|
|
|
|
self.liststore.foreach(each, None)
|
|
if self.old_trackers != self.trackers:
|
|
# Set the torrens trackers
|
|
client.core.set_torrent_trackers(self.torrent_id, self.trackers)
|
|
self.deferred.callback(Gtk.ResponseType.OK)
|
|
else:
|
|
self.deferred.callback(Gtk.ResponseType.CANCEL)
|
|
else:
|
|
self.deferred.callback(Gtk.ResponseType.CANCEL)
|
|
self.dialog.destroy()
|
|
|
|
def _on_get_torrent_status(self, status):
|
|
"""Display trackers dialog"""
|
|
self.old_trackers = list(status['trackers'])
|
|
for tracker in self.old_trackers:
|
|
self.add_tracker(tracker['tier'], tracker['url'])
|
|
self.treeview.set_cursor((0))
|
|
self.dialog.show()
|
|
|
|
def add_tracker(self, tier, url):
|
|
"""Adds a tracker to the list"""
|
|
self.liststore.append([tier, url])
|
|
|
|
def get_selected(self):
|
|
"""Returns the selected tracker"""
|
|
return self.treeview.get_selection().get_selected()[1]
|
|
|
|
def on_button_add_clicked(self, widget):
|
|
log.debug('on_button_add_clicked')
|
|
# Show the add tracker dialog
|
|
self.add_tracker_dialog.show()
|
|
self.builder.get_object('textview_trackers').grab_focus()
|
|
|
|
def on_button_remove_clicked(self, widget):
|
|
log.debug('on_button_remove_clicked')
|
|
selected = self.get_selected()
|
|
if selected is not None:
|
|
self.liststore.remove(selected)
|
|
|
|
def on_button_edit_clicked(self, widget):
|
|
"""edits an existing tracker"""
|
|
log.debug('on_button_edit_clicked')
|
|
selected = self.get_selected()
|
|
if selected:
|
|
tracker = self.liststore.get_value(selected, 1)
|
|
self.builder.get_object('entry_edit_tracker').set_text(tracker)
|
|
self.edit_tracker_entry.show()
|
|
self.edit_tracker_entry.grab_focus()
|
|
self.dialog.set_sensitive(False)
|
|
|
|
def on_button_edit_cancel_clicked(self, widget):
|
|
log.debug('on_button_edit_cancel_clicked')
|
|
self.dialog.set_sensitive(True)
|
|
self.edit_tracker_entry.hide()
|
|
|
|
def on_button_edit_ok_clicked(self, widget):
|
|
log.debug('on_button_edit_ok_clicked')
|
|
selected = self.get_selected()
|
|
tracker = self.builder.get_object('entry_edit_tracker').get_text()
|
|
self.liststore.set_value(selected, 1, tracker)
|
|
self.dialog.set_sensitive(True)
|
|
self.edit_tracker_entry.hide()
|
|
|
|
def on_button_up_clicked(self, widget):
|
|
log.debug('on_button_up_clicked')
|
|
selected = self.get_selected()
|
|
num_rows = self.liststore.iter_n_children(None)
|
|
if selected is not None and num_rows > 1:
|
|
tier = self.liststore.get_value(selected, 0)
|
|
if tier <= 0:
|
|
return
|
|
new_tier = tier - 1
|
|
# Now change the tier for this tracker
|
|
self.liststore.set_value(selected, 0, new_tier)
|
|
|
|
def on_button_down_clicked(self, widget):
|
|
log.debug('on_button_down_clicked')
|
|
selected = self.get_selected()
|
|
num_rows = self.liststore.iter_n_children(None)
|
|
if selected is not None and num_rows > 1:
|
|
tier = self.liststore.get_value(selected, 0)
|
|
new_tier = tier + 1
|
|
# Now change the tier for this tracker
|
|
self.liststore.set_value(selected, 0, new_tier)
|
|
|
|
def on_button_add_ok_clicked(self, widget):
|
|
log.debug('on_button_add_ok_clicked')
|
|
|
|
# Create a list of trackers from the textview widget
|
|
textview_buf = self.builder.get_object('textview_trackers').get_buffer()
|
|
trackers_text = textview_buf.get_text(
|
|
*textview_buf.get_bounds(), include_hidden_chars=False
|
|
)
|
|
|
|
for tracker in trackers_tiers_from_text(trackers_text):
|
|
# Figure out what tier number to use.. it's going to be the highest+1
|
|
# Also check for duplicates
|
|
# Check if there are any entries
|
|
duplicate = False
|
|
highest_tier = -1
|
|
for row in self.liststore:
|
|
tier = row[0]
|
|
if tier > highest_tier:
|
|
highest_tier = tier
|
|
if tracker == row[1]:
|
|
duplicate = True
|
|
break
|
|
|
|
# If not a duplicate, then add it to the list
|
|
if not duplicate:
|
|
# Add the tracker to the list
|
|
self.add_tracker(highest_tier + 1, tracker)
|
|
|
|
# Clear the entry widget and hide the dialog
|
|
textview_buf.set_text('')
|
|
self.add_tracker_dialog.hide()
|
|
|
|
def on_button_add_cancel_clicked(self, widget):
|
|
log.debug('on_button_add_cancel_clicked')
|
|
# Clear the entry widget and hide the dialog
|
|
b = Gtk.TextBuffer()
|
|
self.builder.get_object('textview_trackers').set_buffer(b)
|
|
self.add_tracker_dialog.hide()
|