Codebase list deluge / 3eb1918
Imported Upstream version 1.3.1 Cristian Greco 13 years ago
21 changed file(s) with 200 addition(s) and 137 deletion(s). Raw diff Collapse all Expand all
0 === Deluge 1.3.1 (31 October 2010) ===
1 ==== Core ====
2 * #1369: Fix non-ascii config folders not working in windows
3
4 ==== GtkUI ====
5 * #1365: Fix sidebar not updating show/hide trackers
6 * #1247: Fix hang on quit
7
8 ==== WebUI ====
9 * #1364: Fix preferences not saving when the web ui plugin is enabled in classic mode
10 * #1377: Fix bug when enabling plugins
11 * #1370: Fix issues with preferences
12 * #1312: Fix deluge-web using 100% CPU
13
014 === Deluge 1.3.0 (18 September 2010) ===
15 ==== Core ====
116 * Fix issue where the save_timer is cancelled when it's not active
217 * Fix unhandled exception when adding a torrent to the session
318 * Moved xdg import so it is not called on Windows, where it is unused. fixes #1343
419 * Fix key error after enabling a plugin that introduces a new status key
20 * Ignore global stop ratio related settings in logic, so per torrent ones are used.
21 * Ensure preferencesmanager only changes intended libtorrent session settings.
22 * Fix issue when adding torrents without a 'session'. This can happen when a plugin adds a torrent, like how the AutoAdd plugin works. The user that adds this torrent will be an empty string.
23 * Add TorrentFileCompleted event
24
25 ==== GtkUI ====
26 * Increase max piece size to 8 MiB in create torrent dialog (closes #1358)
27
28 ==== Scheduler ====
529 * Add max active downloading and seeding options to scheduler.
6 * Ignore global stop ratio related settings in logic, so per torrent ones are used.
730 * Fix scheduler so that it keeps current state, even after global settings change.
8 * Ensure preferencesmanager only changes intended libtorrent session settings.
9 * Fix issue when adding torrents without a 'session'. This can happen when
10 a plugin adds a torrent, like how the AutoAdd plugin works. The user that
11 adds this torrent will be an empty string.
12 * Add TorrentFileCompleted event
31
32 ==== AutoAdd ====
1333 * AutoAdd plugin can now recover when one of the watchfolders has an unhandled exception.
14 * Increase max piece size to 8 MiB in create torrent dialog (closes #1358)
1534 * Fix bug in AutoAdd plugin where watchdirs would not display in gtkui when first enabled.
1635 * Fix bugs with unicode torrents in AutoAdd plugin.
1736
1938 ==== Core ====
2039 * Fix tracker_icons failing on windows
2140 * Fix #1302 an uncaught exception in an state_changed event handler in SessionProxy was preventing the TorrentManager's stop method from properly saving all the resume data
22 * Fix issue with SessionProxy not updating the torrent status correctly when
23 get_torrent_status calls take place within the cache_expiry time
41 * Fix issue with SessionProxy not updating the torrent status correctly when get_torrent_status calls take place within the cache_expiry time
2442
2543 ==== ConsoleUI ====
2644 * #1307: Fix not being able to add torrents
66 * setuptools
77 * gettext
88 * pyxdg
9 * chardet
910 * geoip-database (optional)
1011
1112 * libtorrent >= 0.14, or build the included version
1415 * boost >= 1.34.1
1516 * openssl
1617 * zlib
17
18 === UIs ===
19 * chardet
2018
2119 === Gtk ===
2220 * python-notify (libnotify python wrapper)
4040 import subprocess
4141 import platform
4242 import sys
43 import chardet
4344
4445 try:
4546 import json
473474 sectors, bytes, free, total = map(long, win32file.GetDiskFreeSpace(path))
474475 return (free * sectors * bytes)
475476 else:
476 disk_data = os.statvfs(path)
477 disk_data = os.statvfs(path.encode("utf8"))
477478 block_size = disk_data.f_bsize
478479 return disk_data.f_bavail * block_size
479480
559560 string = string.replace(char, escape)
560561 return string
561562
563 def decode_string(s, encoding="utf8"):
564 """
565 Decodes a string and re-encodes it in utf8. If it cannot decode using
566 `:param:encoding` then it will try to detect the string encoding and
567 decode it.
568
569 :param s: string to decode
570 :type s: string
571 :keyword encoding: the encoding to use in the decoding
572 :type encoding: string
573
574 """
575
576 try:
577 s = s.decode(encoding).encode("utf8", "ignore")
578 except UnicodeDecodeError:
579 s = s.decode(chardet.detect(s)["encoding"], "ignore").encode("utf8", "ignore")
580 return s
581
582 def utf8_encoded(s):
583 """
584 Returns a utf8 encoded string of s
585
586 :param s: (unicode) string to (re-)encode
587 :type s: basestring
588 :returns: a utf8 encoded string of s
589 :rtype: str
590
591 """
592 if isinstance(s, str):
593 s = decode_string(s, locale.getpreferredencoding())
594 elif isinstance(s, unicode):
595 s = s.encode("utf8", "ignore")
596 return s
597
562598 class VersionSplit(object):
563599 """
564600 Used for comparing version numbers.
145145 self._save_timer = None
146146
147147 if defaults:
148 self.__config = dict(defaults)
148 for key, value in defaults.iteritems():
149 self.set_item(key, value)
149150
150151 # Load the config from file in the config_dir
151152 if config_dir:
186187 5
187188
188189 """
190 if isinstance(value, basestring):
191 value = deluge.common.utf8_encoded(value)
192
193
189194 if not self.__config.has_key(key):
190195 self.__config[key] = value
191196 log.debug("Setting '%s' to %s of %s", key, value, type(value))
199204
200205 if value is not None and oldtype != type(None) and oldtype != newtype:
201206 try:
202 value = oldtype(value)
207 if oldtype == unicode:
208 value = oldtype(value, "utf8")
209 else:
210 value = oldtype(value)
203211 except ValueError:
204212 log.warning("Type '%s' invalid for '%s'", newtype, key)
205213 raise
249257 5
250258
251259 """
252 return self.__config[key]
260 if isinstance(self.__config[key], str):
261 return self.__config[key].decode("utf8")
262 else:
263 return self.__config[key]
253264
254265 def register_change_callback(self, callback):
255266 """
399410 # The config has not changed so lets just return
400411 if self._save_timer and self._save_timer.active():
401412 self._save_timer.cancel()
402 return
413 return True
403414 except IOError, e:
404415 log.warning("Unable to open config file: %s because: %s", filename, e)
405416
195195 value = status[field]
196196 items[field][value] = items[field].get(value, 0) + 1
197197
198 items["tracker_host"]["All"] = len(torrent_ids)
199
200198 if "tracker_host" in items:
199 items["tracker_host"]["All"] = len(torrent_ids)
201200 items["tracker_host"]["Error"] = len(tracker_error_filter(torrent_ids, ("Error",)))
202201
203202 if "state" in tree_keys and not show_zero_hits:
178178 else:
179179 self.time_added = time.time()
180180
181 # Keep track if we're forcing a recheck of the torrent so that we can
182 # repause it after its done if necessary
183 self.forcing_recheck = False
184 self.forcing_recheck_paused = False
185
181186 log.debug("Torrent object created.")
182187
183188 ## Options methods ##
858863
859864 def force_recheck(self):
860865 """Forces a recheck of the torrents pieces"""
866 paused = self.handle.is_paused()
861867 try:
862868 self.handle.force_recheck()
863869 self.handle.resume()
864870 except Exception, e:
865871 log.debug("Unable to force recheck: %s", e)
866872 return False
873 self.forcing_recheck = True
874 self.forcing_recheck_paused = paused
867875 return True
868876
869877 def rename_files(self, filenames):
4646
4747 from deluge._libtorrent import lt
4848
49
5049 from deluge.event import *
5150 from deluge.error import *
52 import deluge.common
5351 import deluge.component as component
5452 from deluge.configmanager import ConfigManager, get_config_dir
5553 from deluge.core.torrent import Torrent
5654 from deluge.core.torrent import TorrentOptions
5755 import deluge.core.oldstateupgrader
58 from deluge.ui.common import utf8_encoded
56 from deluge.common import utf8_encoded
5957
6058 from deluge.log import LOG as log
6159
850848 torrent = self.torrents[str(alert.handle.info_hash())]
851849 except:
852850 return
853
851
852 # Check to see if we're forcing a recheck and set it back to paused
853 # if necessary
854 if torrent.forcing_recheck:
855 torrent.forcing_recheck = False
856 if torrent.forcing_recheck_paused:
857 torrent.handle.pause()
858
854859 # Set the torrent state
855860 torrent.update_state()
856861
8181 self.is_importing = False
8282 self.has_imported = False
8383 self.up_to_date = False
84 self.need_to_resume_session = False
8485 self.num_blocked = 0
8586 self.file_progress = 0.0
8687
9495
9596 update_now = False
9697 if self.config["load_on_start"]:
97 self.pause_transfers()
98 self.pause_session()
9899 if self.config["last_update"]:
99100 last_update = datetime.fromtimestamp(self.config["last_update"])
100101 check_period = timedelta(days=self.config["check_after_days"])
103104 else:
104105 d = self.import_list(deluge.configmanager.get_config_dir("blocklist.cache"))
105106 d.addCallbacks(self.on_import_complete, self.on_import_error)
106 d.addBoth(self.resume_transfers)
107 if self.need_to_resume_session:
108 d.addBoth(self.resume_session)
107109
108110 # This function is called every 'check_after_days' days, to download
109111 # and import a new list if needed.
149151 else:
150152 d = self.import_list(self.config["url"])
151153 d.addCallbacks(self.on_import_complete, self.on_import_error)
152 d.addBoth(self.resume_transfers)
154 if self.need_to_resume_session:
155 d.addBoth(self.resume_session)
153156
154157 return d
155158
417420 else:
418421 self.reader = create_reader(self.config["list_type"], self.config["list_compression"])
419422
420 def pause_transfers(self):
421 self.session_was_paused = self.core.session.is_paused()
422 if not self.session_was_paused:
423 def pause_session(self):
424 if not self.core.session.is_paused():
423425 self.core.session.pause()
424
425 def resume_transfers(self, result):
426 if not self.session_was_paused:
427 self.session_was_paused = True
428 self.core.session.resume()
426 self.need_to_resume_session = True
427 else:
428 self.need_to_resume_session = False
429
430 def resume_session(self, result):
431 self.core.session.resume()
432 self.need_to_resume_session = False
429433 return result
4141 import sys
4242 import urlparse
4343
44 import chardet
4544 import locale
4645
4746 try:
4948 except ImportError:
5049 from sha import sha
5150
52 from deluge import bencode, common
51 from deluge import bencode
52 from deluge.common import decode_string, path_join
5353 from deluge.log import LOG as log
5454 import deluge.configmanager
55
56 def decode_string(s, encoding="utf8"):
57 """
58 Decodes a string and re-encodes it in utf8. If it cannot decode using
59 `:param:encoding` then it will try to detect the string encoding and
60 decode it.
61
62 :param s: string to decode
63 :type s: string
64 :keyword encoding: the encoding to use in the decoding
65 :type encoding: string
66
67 """
68
69 try:
70 s = s.decode(encoding).encode("utf8", "ignore")
71 except UnicodeDecodeError:
72 s = s.decode(chardet.detect(s)["encoding"], "ignore").encode("utf8", "ignore")
73 return s
74
75 def utf8_encoded(s):
76 """
77 Returns a utf8 encoded string of s
78
79 :param s: (unicode) string to (re-)encode
80 :type s: basestring
81 :returns: a utf8 encoded string of s
82 :rtype: str
83
84 """
85 if isinstance(s, str):
86 s = decode_string(s, locale.getpreferredencoding())
87 elif isinstance(s, unicode):
88 s = s.encode("utf8", "ignore")
89 return s
9055
9156 class TorrentInfo(object):
9257 """
335300 """
336301 def walk(directory, parent_path):
337302 for path in directory["contents"].keys():
338 full_path = common.path_join(parent_path, path)
303 full_path = path_join(parent_path, path)
339304 if directory["contents"][path]["type"] == "dir":
340305 directory["contents"][path] = callback(full_path, directory["contents"][path]) or \
341306 directory["contents"][path]
121121 self.label_view.set_show_expanders(True)
122122 self.label_view.set_headers_visible(False)
123123 self.label_view.set_level_indentation(-35)
124
124 # Force the theme to use an expander-size of 15 so that we don't cut out
125 # entries due to our indentation hack.
126 gtk.rc_parse_string('style "treeview-style" { GtkTreeView::expander-size = 15 } class "GtkTreeView" style "treeview-style"')
127
125128 self.label_view.set_model(self.treestore)
126129 self.label_view.get_selection().connect("changed", self.on_selection_changed)
127130 self.create_model_filter()
4646
4747 # Initialize gettext
4848 try:
49 locale.setlocale(locale.LC_ALL, '')
4950 if hasattr(locale, "bindtextdomain"):
5051 locale.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n"))
5152 if hasattr(locale, "textdomain"):
151151 """Returns a reference to the main window glade object."""
152152 return self.main_glade
153153
154 def quit(self):
155 if client.is_classicmode():
156 gtk.main_quit()
157 else:
158 reactor.stop()
154 def quit(self, shutdown=False):
155 """
156 Quits the GtkUI
157
158 :param shutdown: whether or not to shutdown the daemon as well
159 :type shutdown: boolean
160 """
161 if shutdown:
162 client.daemon.shutdown()
163 reactor.stop()
159164
160165 def load_window_state(self):
161166 x = self.config["window_x_pos"]
252252
253253 def on_menuitem_quitdaemon_activate(self, data=None):
254254 log.debug("on_menuitem_quitdaemon_activate")
255 # Tell the core to shutdown
256 def on_shutdown(result):
257 self.window.quit()
258 client.daemon.shutdown().addCallback(on_shutdown)
255 self.window.quit(shutdown=True)
259256
260257 def on_menuitem_quit_activate(self, data=None):
261258 log.debug("on_menuitem_quit_activate")
322322 if self.config["lock_tray"] and not self.window.visible():
323323 self.unlock_tray()
324324
325 if self.config["classic_mode"]:
326 client.daemon.shutdown()
327
328325 self.window.quit()
329326
330327 def on_menuitem_quitdaemon_activate(self, menuitem):
332329 if self.config["lock_tray"] and not self.window.visible():
333330 self.unlock_tray()
334331
335 client.daemon.shutdown()
336 self.window.quit()
332 self.window.quit(shutdown=True)
337333
338334 def tray_setbwdown(self, widget, data=None):
339335 self.setbwlimit(widget, _("Set Maximum Download Speed"), "max_download_speed",
3030 </script>
3131 </head>
3232 <body>
33 <div style="background-image: url('${base}themes/default/tree/loading.gif');"></div>
33 <div style="background-image: url('${base}themes/images/default/tree/loading.gif');"></div>
3434
3535 <!-- Preload icon classes -->
3636 <div class="ext-mb-error"></div>
173173 this.stored[this.currentId][option] = value;
174174
175175 if (!this.isDirty(option)) {
176 this.fireEvent('changed', this.currentId, option, value, oldValue);
176 this.fireEvent('changed', option, value, oldValue);
177177 }
178178 }
179179 },
231231 },
232232
233233 onPluginEnabled: function(pluginName) {
234 var index = this.grid.getStore().find('plugin', pluginName);
234 var index = this.list.getStore().find('plugin', pluginName);
235235 if (index == -1) return;
236 var plugin = this.grid.getStore().getAt(index);
236 var plugin = this.list.getStore().getAt(index);
237237 plugin.set('enabled', true);
238238 plugin.commit();
239239 },
0 /*!
1 * Ext.ux.form.SpinnerField.js
2 *
3 * Copyright (c) Damien Churchill 2010 <damoxc@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, write to:
17 * The Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor
19 * Boston, MA 02110-1301, USA.
20 *
21 * In addition, as a special exception, the copyright holders give
22 * permission to link the code of portions of this program with the OpenSSL
23 * library.
24 * You must obey the GNU General Public License in all respects for all of
25 * the code used other than OpenSSL. If you modify file(s) with this
26 * exception, you may extend this exception to your version of the file(s),
27 * but you are not obligated to do so. If you do not wish to do so, delete
28 * this exception statement from your version. If you delete this exception
29 * statement from all source files in the program, then also delete it here.
30 */
31
32 Ext.override(Ext.ux.form.SpinnerField, {
33 onBlur: Ext.form.Field.prototype.onBlur
34 });
149149 return d
150150
151151 def disable(self):
152 client.disconnect()
152 if not client.is_classicmode():
153 client.disconnect()
153154
154155 def enable(self):
155156 if component.get("DelugeWeb").config["default_daemon"]:
380381
381382 # Create a deferred to and check again in 100ms
382383 d = Deferred()
383 reactor.callLater(0.5, self._get_events, listener_id, d)
384 reactor.callLater(0.1, self._get_events, listener_id, 0, d)
384385 return d
385386
386 def _get_events(self, listener_id, d):
387 def _get_events(self, listener_id, count, d):
387388 if listener_id in self.__queue:
388389 queue = self.__queue[listener_id]
389390 del self.__queue[listener_id]
390391 d.callback(queue)
391392 else:
392 reactor.callLater(0.1, self._get_events, listener_id, d)
393 # Prevent this loop going on indefinitely incase a client leaves
394 # the page or disconnects uncleanly.
395 if count >= 3000:
396 d.callback(None)
397 else:
398 reactor.callLater(0.1, self._get_events, listener_id, count + 1, d)
393399
394400 def remove_listener(self, listener_id, event):
395401 """
+0
-33
deluge_convert_conf.py less more
0 #!/usr/bin/env python
1
2 import os
3 import sys
4 import cPickle as pickle
5 if sys.version_info > (2, 6):
6 import json
7 else:
8 import simplejson as json
9
10 from deluge.common import get_default_config_dir
11
12 config_dir = get_default_config_dir()
13 files = []
14 for filename in os.listdir(config_dir):
15 filename = os.path.join(config_dir, filename)
16 if not os.path.isfile(filename):
17 continue
18 if filename.endswith(".log"):
19 continue
20
21 basename = os.path.basename(filename)
22 sys.stdout.write("Converting %s..." % (basename) + ' '*(20-len(basename)))
23 try:
24 config = json.load(open(filename, "r"))
25 pickle.dump(config, open(filename, "wb"))
26 print "\033[032mdone\033[0m"
27 except:
28 try:
29 pickle.load(open(filename, "rb"))
30 print "\033[032malready converted\033[0m"
31 except:
32 print "\033[031mfailed\033[1;m"
421421 'docs/man/deluge-console.1'])
422422 ]
423423
424 entry_points = {
425 "console_scripts": [
426 "deluge-console = deluge.ui.console:start",
427 "deluge-web = deluge.ui.web:start",
428 "deluged = deluge.main:start_daemon"
429 ],
430 "gui_scripts": [
431 "deluge = deluge.main:start_ui",
432 "deluge-gtk = deluge.ui.gtkui:start"
433 ]
434 }
435
436
437 if windows_check():
438 entry_points["console_scripts"].append("deluge-debug = deluge.main:start_ui")
439
424440 # Main setup
425441 setup(
426442 name = "deluge",
427 version = "1.3.0",
443 version = "1.3.1",
428444 fullname = "Deluge Bittorrent Client",
429445 description = "Bittorrent Client",
430446 author = "Andrew Resch, Damien Churchill",
468484 "ui/web/themes/images/*/*/*.png"
469485 ]},
470486 packages = find_packages(exclude=["plugins", "docs", "tests"]),
471 entry_points = """
472 [console_scripts]
473 deluge = deluge.main:start_ui
474 deluge-console = deluge.ui.console:start
475 deluge-gtk = deluge.ui.gtkui:start
476 deluge-web = deluge.ui.web:start
477 deluged = deluge.main:start_daemon
478 """,
487 entry_points = entry_points
479488 )