Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[UI] Add and improve trackers tab
Browse files Browse the repository at this point in the history
First, added trackers tab to the WebUI.
Second, now we can view all the trackers and view each:
 * status
 * peers count
 * additional message
Third, moved the private torrent info to the details tab.

closes: https://dev.deluge-torrent.org/ticket/1015
DjLegolas committed Sep 28, 2024
1 parent 0ca8f4d commit 99dd3c2
Showing 11 changed files with 509 additions and 222 deletions.
7 changes: 5 additions & 2 deletions deluge/common.py
Original file line number Diff line number Diff line change
@@ -721,14 +721,17 @@ def parse_human_size(size):
raise InvalidSize(msg % (size, tokens))


def anchorify_urls(text: str) -> str:
def anchorify_urls(text: str, as_hyperlink: bool = True) -> str:
"""
Wrap all occurrences of text URLs with HTML
"""
url_pattern = r'((htt)|(ft)|(ud))ps?://\S+'
html_href_pattern = r'<a href="\g<0>">\g<0></a>'
markup_pattern = r'<span foreground="dodger blue" underline="single">\g<0></span>'

return re.sub(url_pattern, html_href_pattern, text)
return re.sub(
url_pattern, html_href_pattern if as_hyperlink else markup_pattern, text
)


def is_url(url):
3 changes: 2 additions & 1 deletion deluge/ui/gtk3/details_tab.py
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@
import deluge.component as component
from deluge.common import anchorify_urls, decode_bytes, fdate, fsize

from .tab_data_funcs import fdate_or_dash, fpieces_num_size
from .tab_data_funcs import fdate_or_dash, fpieces_num_size, fyes_no
from .torrentdetails import Tab

log = logging.getLogger(__name__)
@@ -34,6 +34,7 @@ def __init__(self):
self.add_tab_widget(
'summary_pieces', fpieces_num_size, ('num_pieces', 'piece_length')
)
self.add_tab_widget('summary_private', fyes_no, ('private',))

def update(self):
# Get the first selected torrent
27 changes: 27 additions & 0 deletions deluge/ui/gtk3/glade/main_window.tabs.menu_trackers.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.0"/>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">list-add-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkMenu" id="menu_trackers_tab">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="edit_trackers_menuitem">
<property name="label" translatable="yes">_Edit Trackers</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Edit all trackers</property>
<property name="use_underline">True</property>
<property name="image">image1</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_menuitem_edit_trackers_activate" swapped="no"/>
</object>
</child>
</object>
</interface>
224 changes: 32 additions & 192 deletions deluge/ui/gtk3/glade/main_window.tabs.ui
Original file line number Diff line number Diff line change
@@ -583,6 +583,17 @@
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="summary_private">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_pieces">
<property name="visible">True</property>
@@ -801,6 +812,21 @@
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_private">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Private Torrent:</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="vseparator5">
<property name="visible">True</property>
@@ -809,8 +835,8 @@
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">2</property>
<property name="height">3</property>
<property name="top_attach">1</property>
<property name="height">4</property>
</packing>
</child>
<child>
@@ -843,12 +869,6 @@
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
@@ -1446,191 +1466,11 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkViewport" id="viewport4">
<object class="GtkTreeView" id="trackers_listview">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="top_padding">5</property>
<property name="bottom_padding">2</property>
<property name="left_padding">10</property>
<property name="right_padding">15</property>
<child>
<object class="GtkGrid" id="table2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">5</property>
<property name="column_spacing">10</property>
<child>
<object class="GtkLabel" id="label_tracker">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Current Tracker:</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="summary_tracker">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="summary_next_announce">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="summary_tracker_status">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="wrap">True</property>
<property name="wrap_mode">char</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="summary_tracker_total">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="summary_private">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="wrap_mode">char</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_tracker_total">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Total Trackers:</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_tracker_status">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Tracker Status:</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_next_announce">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Next Announce:</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_private">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Private Torrent:</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment_edit_trackers">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="top_padding">5</property>
<child>
<object class="GtkButton" id="button_edit_trackers">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_button_edit_trackers_clicked" swapped="no"/>
<child>
<object class="GtkLabel" id="label_edit_trackers">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Edit Trackers</property>
<property name="use_underline">True</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
<property name="can_focus">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeselection3"/>
</child>
</object>
</child>
1 change: 1 addition & 0 deletions deluge/ui/gtk3/mainwindow.py
Original file line number Diff line number Diff line change
@@ -101,6 +101,7 @@ def patched_connect_signals(*a, **k):
'main_window.tabs.ui',
'main_window.tabs.menu_file.ui',
'main_window.tabs.menu_peer.ui',
'main_window.tabs.menu_trackers.ui',
]
for filename in ui_filenames:
self.main_builder.add_from_file(
235 changes: 208 additions & 27 deletions deluge/ui/gtk3/trackers_tab.py
Original file line number Diff line number Diff line change
@@ -7,11 +7,23 @@
#

import logging
import webbrowser

from gi.repository.Gdk import EventType
from gi.repository.Gtk import (
CellRendererText,
ListStore,
SortType,
TreeView,
TreeViewColumn,
)

import deluge.component as component
from deluge.common import anchorify_urls, ftime
from deluge.common import anchorify_urls, is_url
from deluge.decorators import maybe_coroutine
from deluge.ui.client import client

from .tab_data_funcs import fcount, ftranslate, fyes_no
from .tab_data_funcs import ftranslate
from .torrentdetails import Tab

log = logging.getLogger(__name__)
@@ -21,49 +33,218 @@ class TrackersTab(Tab):
def __init__(self):
super().__init__('Trackers', 'trackers_tab', 'trackers_tab_label')

self.add_tab_widget('summary_next_announce', ftime, ('next_announce',))
self.add_tab_widget('summary_tracker', None, ('tracker_host',))
self.add_tab_widget('summary_tracker_status', ftranslate, ('tracker_status',))
self.add_tab_widget('summary_tracker_total', fcount, ('trackers',))
self.add_tab_widget('summary_private', fyes_no, ('private',))

self.trackers_menu = self.main_builder.get_object('menu_trackers_tab')
component.get('MainWindow').connect_signals(self)

self.listview: TreeView = self.main_builder.get_object('trackers_listview')
self.listview.props.has_tooltip = True
self.listview.connect('button-press-event', self._on_button_press_event)
self.listview.connect('row-activated', self._on_row_activated)
self.listview.props.activate_on_single_click = True

# url, status, peers, message
self.liststore = ListStore(str, str, int, str)

# key is url, item is row iter
self.trackers = {}

self._can_get_trackers_info = False

# self.treeview.append_column(
# Gtk.TreeViewColumn(_('Tier'), Gtk.CellRendererText(), text=0)
# )
column = TreeViewColumn(_('Tracker'))
render = CellRendererText()
column.pack_start(render, False)
column.add_attribute(render, 'text', 0)
column.set_clickable(True)
column.set_resizable(True)
column.set_expand(False)
column.set_min_width(150)
column.set_reorderable(True)
self.listview.append_column(column)

column = TreeViewColumn(_('Status'))
render = CellRendererText()
column.pack_start(render, False)
column.add_attribute(render, 'markup', 1)
column.set_clickable(True)
column.set_resizable(True)
column.set_expand(False)
column.set_min_width(50)
column.set_reorderable(True)
self.listview.append_column(column)

column = TreeViewColumn(_('Peers'))
render = CellRendererText()
column.pack_start(render, False)
column.add_attribute(render, 'text', 2)
column.set_clickable(True)
column.set_resizable(True)
column.set_expand(False)
column.set_min_width(50)
column.set_reorderable(True)
self.listview.append_column(column)

column = TreeViewColumn(_('Message'))
render = CellRendererText()
column.pack_start(render, False)
column.add_attribute(render, 'markup', 3)
column.set_clickable(True)
column.set_resizable(True)
column.set_expand(False)
column.set_min_width(100)
column.set_reorderable(True)
self.listview.append_column(column)

self.listview.set_model(self.liststore)
self.liststore.set_sort_column_id(0, SortType.ASCENDING)

self.torrent_id = None

def update(self):
if client.is_standalone():
self._can_get_trackers_info = True
else:
self._can_get_trackers_info = client.daemon_version_check_min('2.1.2')
self.do_update()

@maybe_coroutine
async def do_update(self):
# Get the first selected torrent
selected = component.get('TorrentView').get_selected_torrents()
torrent_id = component.get('TorrentView').get_selected_torrents()

# Only use the first torrent in the list or return if None selected
if selected:
selected = selected[0]
if torrent_id:
torrent_id = torrent_id[0]
else:
self.clear()
self.liststore.clear()
return

if torrent_id != self.torrent_id:
# We only want to do this if the torrent_id has changed
self.liststore.clear()
self.trackers = {}
self.torrent_id = torrent_id

session = component.get('SessionProxy')
session.get_torrent_status(selected, self.status_keys).addCallback(
self._on_get_torrent_status
)

def _on_get_torrent_status(self, status):
if not self._can_get_trackers_info:
tracker_keys = [
'tracker_host',
'tracker_status',
]
else:
tracker_keys = [
'trackers',
'trackers_status',
'trackers_peers',
]

status = await session.get_torrent_status(torrent_id, tracker_keys)
self._on_get_torrent_tracker_status(status)

def _on_get_torrent_tracker_status(self, status):
# Check to see if we got valid data from the core
if not status:
return

# Update all the tab label widgets
for widget in self.tab_widgets.values():
txt = self.widget_status_as_fstr(widget, status)
if widget.obj.get_text() != txt:
if 'tracker_status' in widget.status_keys:
widget.obj.set_markup(anchorify_urls(txt))
else:
widget.obj.set_text(txt)
if not self._can_get_trackers_info:
status['trackers'] = [{'url': status['tracker_host'], 'message': ''}]
status['trackers_status'] = {
status['tracker_host']: {
'status': status['tracker_status'],
'message': '',
}
}
status['trackers_peers'] = {}

new_trackers = set()
for tracker in status['trackers']:
new_trackers.add(tracker['url'])
tracker_url = tracker['url']
stacker_status_dict = status['trackers_status'].get(tracker_url, {})
tracker_status = ftranslate(stacker_status_dict.get('status', ''))
tracker_status = anchorify_urls(tracker_status, as_hyperlink=False)
tracker_status_message = ftranslate(stacker_status_dict.get('message', ''))
tracker_status_message = anchorify_urls(
tracker_status_message, as_hyperlink=False
)
tracker_peers = status['trackers_peers'].get(tracker_url, 0)
tracker_message = tracker.get('message', '')
if not tracker_message and tracker_status_message:
tracker_message = tracker_status_message
if tracker_url in self.trackers:
row = self.trackers[tracker_url]
if not self.liststore.iter_is_valid(row):
# This iter is invalid, delete it and continue to next iteration
del self.trackers[tracker_url]
continue
values = self.liststore.get(row, 1, 2, 3)
if tracker_status != values[0]:
self.liststore.set_value(row, 1, tracker_status)
if tracker_peers != values[1]:
self.liststore.set_value(row, 2, tracker_peers)
if tracker_message != values[2]:
self.liststore.set_value(row, 3, tracker_message)
else:
row = self.liststore.append(
[
tracker_url,
tracker_status,
tracker_peers,
tracker_message,
]
)

self.trackers[tracker_url] = row

# Now we need to remove any tracker that were not in status['trackers'] list
for tracker in set(self.trackers).difference(new_trackers):
self.liststore.remove(self.trackers[tracker])
del self.trackers[tracker]

def clear(self):
for widget in self.tab_widgets.values():
widget.obj.set_text('')
self.liststore.clear()

def _on_button_press_event(self, widget, event):
"""This is a callback for handling click events."""
log.debug('on_button_press_event')
if event.button == 3:
self.trackers_menu.popup(None, None, None, None, event.button, event.time)
return True
elif event.type == EventType.DOUBLE_BUTTON_PRESS:
self.on_menuitem_edit_trackers_activate(event.button)

def _on_row_activated(self, treeview, path, column):
"""THis is a callback for handling link click"""
log.debug('on_row_activated')
model = treeview.get_model()
tree_iter = model.get_iter(path)

# Get the index of the clicked column from the TreeViewColumn
clicked_column_index = self._get_column_index(column)
if clicked_column_index is None:
log.warning(f'column {column.get_title()} not selected')
return

# Retrieve the value from the correct column based on the clicked column
cell_value = model.get_value(tree_iter, clicked_column_index)

if '<span' in cell_value:
start_index = cell_value.index('>') + 1
end_index = cell_value[start_index:].index('<') + start_index
url = cell_value[start_index:end_index]
if is_url(url):
webbrowser.open_new(url)

def _get_column_index(self, column):
for index, col in enumerate(self.listview.get_columns()):
if col == column:
return index
return None

def on_button_edit_trackers_clicked(self, button):
def on_menuitem_edit_trackers_activate(self, button):
torrent_id = component.get('TorrentView').get_selected_torrent()
if torrent_id:
from .edittrackersdialog import EditTrackersDialog
12 changes: 12 additions & 0 deletions deluge/ui/web/js/deluge-all/Keys.js
Original file line number Diff line number Diff line change
@@ -94,6 +94,18 @@ Deluge.Keys = {
*/
Peers: ['peers'],

/**
* Keys used in the trackers tab of the statistics panel.
* <pre>['trackers', 'trackers_status', 'trackers_peers']</pre>
*/
Trackers: ['trackers', 'trackers_status', 'trackers_peers'],

/**
* Keys used in the trackers tab of the statistics panel for Deluge version <2.1.1.
* <pre>['tracker_host', 'tracker_status']</pre>
*/
TrackersRedundant: ['tracker_host', 'tracker_status'],

/**
* Keys used in the details tab of the statistics panel.
*/
7 changes: 7 additions & 0 deletions deluge/ui/web/js/deluge-all/UI.js
Original file line number Diff line number Diff line change
@@ -52,6 +52,7 @@ deluge.ui = {
deluge.sidebar = new Deluge.Sidebar();
deluge.statusbar = new Deluge.Statusbar();
deluge.toolbar = new Deluge.Toolbar();
deluge.server_version = '';

this.detailsPanel = new Ext.Panel({
id: 'detailsPanel',
@@ -223,6 +224,11 @@ deluge.ui = {
this.running = setTimeout(this.update, 2000);
this.update();
}
deluge.client.daemon.get_version({
success: function (server_version) {
deluge.server_version = server_version;
},
});
deluge.client.web.get_plugins({
success: this.onGotPlugins,
scope: this,
@@ -234,6 +240,7 @@ deluge.ui = {
* @private
*/
onDisconnect: function () {
deluge.server_version = '';
this.stop();
},

40 changes: 40 additions & 0 deletions deluge/ui/web/js/deluge-all/data/TrackerRecord.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Deluge.data.TrackerRecord.js
*
* Copyright (c) Damien Churchill 2009-2010 <damoxc@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.
*/
Ext.namespace('Deluge.data');

/**
* Deluge.data.Tracker record
*
* @author Damien Churchill <damoxc@gmail.com>
* @version 1.3
*
* @class Deluge.data.Tracker
* @extends Ext.data.Record
* @constructor
* @param {Object} data The tracker data
*/
Deluge.data.Tracker = Ext.data.Record.create([
{
name: 'tracker',
type: 'string',
},
{
name: 'status',
type: 'string',
},
{
name: 'peers',
type: 'int',
},
{
name: 'message',
type: 'string',
},
]);
1 change: 1 addition & 0 deletions deluge/ui/web/js/deluge-all/details/DetailsPanel.js
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ Deluge.details.DetailsPanel = Ext.extend(Ext.TabPanel, {
this.add(new Deluge.details.StatusTab());
this.add(new Deluge.details.DetailsTab());
this.add(new Deluge.details.FilesTab());
this.add(new Deluge.details.TrackersTab());
this.add(new Deluge.details.PeersTab());
this.add(new Deluge.details.OptionsTab());
},
174 changes: 174 additions & 0 deletions deluge/ui/web/js/deluge-all/details/TrackersTab.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/**
* Deluge.details.TrackersTab.js
*
* Copyright (c) Damien Churchill 2009-2010 <damoxc@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.
*/

(function () {
Deluge.details.TrackersTab = Ext.extend(Ext.grid.GridPanel, {
// fast way to figure out if we have a tracker already.
trackers: {},
can_get_trackers_info: false,

constructor: function (config) {
config = Ext.apply(
{
title: _('Trackers'),
cls: 'x-deluge-trackers',
store: new Ext.data.Store({
reader: new Ext.data.JsonReader(
{
idProperty: 'ip',
root: 'peers',
},
Deluge.data.Tracker
),
}),
columns: [
{
header: _('Tracker'),
width: 300,
sortable: true,
renderer: 'htmlEncode',
dataIndex: 'tracker',
},
{
header: _('Status'),
width: 150,
sortable: true,
renderer: 'htmlEncode',
dataIndex: 'status',
},
{
header: _('Peers'),
width: 100,
sortable: true,
renderer: 'htmlEncode',
dataIndex: 'peers',
},
{
header: _('Message'),
width: 100,
renderer: 'htmlEncode',
dataIndex: 'message',
},
],
stripeRows: true,
deferredRender: false,
autoScroll: true,
},
config
);
Deluge.details.TrackersTab.superclass.constructor.call(
this,
config
);
},

clear: function () {
this.getStore().removeAll();
this.trackers = {};
},

update: function (torrentId) {
this.can_get_trackers_info = deluge.server_version > '2.0.5';

var trackers_keys = this.can_get_trackers_info
? Deluge.Keys.Trackers
: Deluge.Keys.TrackersRedundant;

deluge.client.web.get_torrent_status(torrentId, trackers_keys, {
success: this.onTrackersRequestComplete,
scope: this,
});
},

onTrackersRequestComplete: function (status, options) {
if (!status) return;

var store = this.getStore();
var newTrackers = [];
var addresses = {};

if (!this.can_get_trackers_info) {
status['trackers'] = [
{
url: status['tracker_host'],
message: '',
},
];
var tracker_host = status['tracker_host'];
status['trackers_status'] = {
tracker_host: {
status: status['tracker_status'],
message: '',
},
};
status['trackers_peers'] = {};
}

// Go through the trackers updating and creating tracker records
Ext.each(
status.trackers,
function (tracker) {
var url = tracker.url;
var tracker_status =
url in status.trackers_status
? status.trackers_status[url]
: {};
var message = tracker.message ? tracker.message : '';
if (!message && 'message' in tracker_status) {
message = tracker_status['message'];
}
var tracker_data = {
tracker: url,
status:
'status' in tracker_status
? tracker_status['status']
: '',
peers:
url in status.trackers_peers
? status.trackers_peers[url]
: 0,
message: message,
};
if (this.trackers[tracker.url]) {
var record = store.getById(tracker.url);
record.beginEdit();
for (var k in tracker_data) {
if (record.get(k) != tracker_data[k]) {
record.set(k, tracker_data[k]);
}
}
record.endEdit();
} else {
this.trackers[tracker.url] = 1;
newTrackers.push(
new Deluge.data.Tracker(tracker_data, tracker.url)
);
}
addresses[tracker.url] = 1;
},
this
);
store.add(newTrackers);

// Remove any trackers that should not be left in the store.
store.each(function (record) {
if (!addresses[record.id] && !this.constantRows[record.id]) {
store.remove(record);
delete this.trackers[record.id];
}
}, this);
store.commitChanges();

var sortState = store.getSortState();
if (!sortState) return;
store.sort(sortState.field, sortState.direction);
},
});
})();

0 comments on commit 99dd3c2

Please sign in to comment.