From cd2f45da928e505e5c36e775091a123a8607b353 Mon Sep 17 00:00:00 2001 From: Marcos Pinto Date: Sun, 28 Oct 2007 01:35:27 +0000 Subject: [PATCH] sync webui 112 and translate --- plugins/WebUi/__init__.py | 59 ++--- plugins/WebUi/dbus_interface.py | 58 +++- plugins/WebUi/deluge_webserver.py | 151 +++++------ plugins/WebUi/revno | 2 +- plugins/WebUi/run_webserver | 4 +- .../WebUi/scripts/add_torrent_to_deluge_webui | 10 + .../static/images/tango/system-log-out.png | Bin 0 -> 799 bytes plugins/WebUi/static_handler.py | 136 ++++++++++ plugins/WebUi/templates/deluge/about.html | 5 +- plugins/WebUi/templates/deluge/config.html | 10 + plugins/WebUi/templates/deluge/index.html | 4 +- .../WebUi/templates/deluge/part_button.html | 10 +- .../WebUi/templates/deluge/part_stats.html | 30 +++ .../WebUi/templates/deluge/torrent_info.html | 5 +- plugins/WebUi/templates/example/footer.html | 3 + plugins/WebUi/templates/example/header.html | 12 + plugins/WebUi/templates/example/index.html | 42 +++ plugins/WebUi/version | 2 +- plugins/WebUi/webserver_common.py | 109 +++++++- plugins/WebUi/webserver_framework.py | 247 ++++++++---------- po/POTFILES.in | 5 +- po/deluge.pot | 238 ++++++++++++++--- 22 files changed, 810 insertions(+), 332 deletions(-) create mode 100755 plugins/WebUi/scripts/add_torrent_to_deluge_webui create mode 100644 plugins/WebUi/static/images/tango/system-log-out.png create mode 100644 plugins/WebUi/static_handler.py create mode 100644 plugins/WebUi/templates/deluge/config.html create mode 100644 plugins/WebUi/templates/deluge/part_stats.html create mode 100644 plugins/WebUi/templates/example/footer.html create mode 100644 plugins/WebUi/templates/example/header.html create mode 100644 plugins/WebUi/templates/example/index.html diff --git a/plugins/WebUi/__init__.py b/plugins/WebUi/__init__.py index b6346c535..497fe5f0b 100644 --- a/plugins/WebUi/__init__.py +++ b/plugins/WebUi/__init__.py @@ -29,7 +29,7 @@ # this exception statement from your version. If you delete this exception plugin_name = _("Web User Interface") -plugin_author = _("Martijn Voncken") +plugin_author = "Martijn Voncken" plugin_version = "rev." plugin_description = _("""A Web based User Interface @@ -41,7 +41,7 @@ There is support for multiple templates, but just one is included. Other contributors: *somedude : template enhancements. - +*markybob : stability : synced with his changes in deluge-svn. """) import deluge.common @@ -80,9 +80,10 @@ class plugin_WebUi(object): self.web_server = None if not deluge.common.windows_check(): import commands - status = commands.getstatusoutput('ps x |grep -v grep |grep run_webserver') + status = commands.getstatusoutput( + 'ps x |grep -v grep |grep run_webserver') if status[0] == 0: - os.kill(status[1].split()[0], 9) + os.kill(int(status[1].split()[0]), 9) time.sleep(1) #safe time to wait for kill to finish. self.config_file = deluge.common.CONFIG_DIR + "/webui.conf" self.config = deluge.pref.Preferences(self.config_file, False) @@ -95,9 +96,6 @@ class plugin_WebUi(object): if not self.config.get('port'): #ugly way to detect new config file. #set default values: self.config.set("port", 8112) - #future->use deluge-core setting for download_dir (if it is set) - self.config.set("download_dir", os.path.expanduser("~")) - self.config.set("torrent_dir", os.path.expanduser("~")) self.config.set("button_style", 2) self.config.set("auto_refresh", False) self.config.set("auto_refresh_secs", 4) @@ -112,11 +110,9 @@ class plugin_WebUi(object): self.config.set("cache_templates", True) if deluge.common.windows_check(): - if self.config.get("run_in_thread") == None: - self.config.set("run_in_thread", True) + self.config.set("run_in_thread", True) else: - if self.config.get("run_in_thread") == None: - self.config.set("run_in_thread", False) + self.config.set("run_in_thread", False) self.dbus_manager = get_dbus_manager(deluge_core, deluge_interface, self.config, self.config_file) @@ -141,8 +137,8 @@ class plugin_WebUi(object): self.kill_server() if self.config.get("run_in_thread"): - print 'start Webui(inside gtk)..' - webserver_common.init() #reload changed config. + print 'Start Webui(inside gtk)..' + webserver_common.init_gtk_05() #reload changed config. from deluge_webserver import WebServer #only import in threaded mode @@ -150,11 +146,9 @@ class plugin_WebUi(object): self.web_server.start_gtk() else: - print 'start Webui(in process)..' - path = os.path.dirname(__file__) - server_bin = path + '/run_webserver' - port = str(self.config.get('port')) - self.proc = Popen((server_bin, port),cwd=path) + print 'Start Webui(in process)..' + server_bin = os.path.dirname(__file__) + '/run_webserver' + self.proc = Popen((server_bin,'env=0.5')) def kill_server(self): if self.web_server: @@ -187,7 +181,8 @@ class ConfigDialog(gtk.Dialog): template_path = os.path.join(os.path.dirname(__file__), 'templates') self.templates = [dirname for dirname in os.listdir(template_path) - if os.path.isdir(os.path.join(template_path, dirname))] + if os.path.isdir(os.path.join(template_path, dirname)) + and not dirname.startswith('.')] self.port = self.add_widget(_('Port Number'), gtk.SpinButton()) self.pwd1 = self.add_widget(_('New Password'), gtk.Entry()) @@ -195,16 +190,11 @@ class ConfigDialog(gtk.Dialog): self.template = self.add_widget(_('Template'), gtk.combo_box_new_text()) self.button_style = self.add_widget(_('Button Style'), gtk.combo_box_new_text()) - self.download_dir = self.add_widget(_('Download Directory'), - gtk.FileChooserButton(_('Download Directory'))) - self.torrent_dir = self.add_widget(_('Torrent Directory'), - gtk.FileChooserButton(_('Torrent Directory'))) self.cache_templates = self.add_widget(_('Cache Templates'), gtk.CheckButton()) - self.run_in_thread = self.add_widget(_('Run inside GTK'), gtk.CheckButton()) + #self.share_downloads = self.add_widget(_('Share Download Directory'), + # gtk.CheckButton()) - self.download_dir.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) - self.torrent_dir.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) self.port.set_range(80, 65536) self.port.set_increments(1, 10) self.pwd1.set_visibility(False) @@ -218,23 +208,16 @@ class ConfigDialog(gtk.Dialog): for item in [_('Text and image'), _('Image Only'), _('Text Only')]: self.button_style.append_text(item) - if not self.config.get("button_style"): + if self.config.get("button_style") == None: self.config.set("button_style", 2) self.port.set_value(int(self.config.get("port"))) self.template.set_active( self.templates.index(self.config.get("template"))) self.button_style.set_active(self.config.get("button_style")) + #self.share_downloads.set_active( + # bool(self.config.get("share_downloads"))) - self.torrent_dir.set_filename(self.config.get("torrent_dir")) - self.download_dir.set_filename(self.config.get("download_dir")) - - if deluge.common.windows_check(): - self.run_in_thread.set_active(True) - self.run_in_thread.set_sensitive(False) - else: - self.run_in_thread.set_active(False) - self.run_in_thread.set_sensitive(False) self.cache_templates.set_active(self.config.get("cache_templates")) self.vbox.pack_start(self.vb, True, True, 0) @@ -270,9 +253,7 @@ class ConfigDialog(gtk.Dialog): self.config.set("port", int(self.port.get_value())) self.config.set("template", self.template.get_active_text()) self.config.set("button_style", self.button_style.get_active()) - self.config.set("torrent_dir", self.torrent_dir.get_filename()) - self.config.set("download_dir",self.download_dir.get_filename()) self.config.set("cache_templates", self.cache_templates.get_active()) - self.config.set("run_in_thread", self.run_in_thread.get_active()) + #self.config.set("share_downloads", self.share_downloads.get_active()) self.config.save(self.plugin.config_file) self.plugin.start_server() #restarts server diff --git a/plugins/WebUi/dbus_interface.py b/plugins/WebUi/dbus_interface.py index 67fe2fa68..b253b821e 100644 --- a/plugins/WebUi/dbus_interface.py +++ b/plugins/WebUi/dbus_interface.py @@ -68,7 +68,7 @@ class DbusManager(dbus.service.Object): @dbus.service.method(dbus_interface=dbus_interface, in_signature="",out_signature="as") - def get_torrent_state(self): + def get_session_state(self): """Returns a list of torrent_ids in the session. same as 0.6, but returns type "as" instead of a pickle """ @@ -129,18 +129,20 @@ class DbusManager(dbus.service.Object): return status_subset @dbus.service.method(dbus_interface=dbus_interface, - in_signature="s",out_signature="") - def pause_torrent(self, torrent_id): + in_signature="as",out_signature="") + def pause_torrent(self, torrents): """same as 0.6 interface""" - torrent_id = int(torrent_id) - self.core.set_user_pause(torrent_id,True) + for torrent_id in torrents: + torrent_id = int(torrent_id) + self.core.set_user_pause(torrent_id,True) @dbus.service.method(dbus_interface=dbus_interface, - in_signature="s", out_signature="") - def resume_torrent(self, torrent_id): + in_signature="as", out_signature="") + def resume_torrent(self, torrents): """same as 0.6 interface""" - torrent_id = int(torrent_id) - self.core.set_user_pause(torrent_id,False) + for torrent_id in torrents: + torrent_id = int(torrent_id) + self.core.set_user_pause(torrent_id,False) @dbus.service.method(dbus_interface=dbus_interface, in_signature="sbb", out_signature="") @@ -157,7 +159,6 @@ class DbusManager(dbus.service.Object): @dbus.service.method(dbus_interface=dbus_interface, in_signature="s", out_signature="b") def add_torrent_url(self, url): - """not available in deluge 0.6 interface""" filename = fetch_url(url) self._add_torrent(filename) return True @@ -182,8 +183,8 @@ class DbusManager(dbus.service.Object): #name = fillename without directory name = name.replace('\\','/') name = 'deluge_' + str(random.random()) + '_' + name.split('/')[-1] + filename = os.path.join(self.core.config.get("default_download_path"), name) - filename = os.path.join(self.config.get("torrent_dir"),name) filecontent = base64.b64decode(filecontent_b64) f = open(filename,"wb") #no with statement, that's py 2.5+ f.write(filecontent) @@ -192,11 +193,42 @@ class DbusManager(dbus.service.Object): self._add_torrent(filename) return True + + @dbus.service.method(dbus_interface=dbus_interface, + in_signature="", out_signature="a{sv}") + def get_config(self): + return self.core.config.mapping + + @dbus.service.method(dbus_interface=dbus_interface, + in_signature="s", out_signature="v") + def get_config_value(self,key): + return self.core.config.mapping[pythonize(key)] #ugly! + + @dbus.service.method(dbus_interface=dbus_interface, + in_signature="a{sv}", out_signature="") + def set_config(self, config): + """Set the config with values from dictionary""" + config = deluge.common.pythonize(config) + # Load all the values into the configuration + for key in self.core.config.keys(): + self.core.config[key] = config[key] + self.core.apply_prefs() + + @dbus.service.method(dbus_interface=dbus_interface, + in_signature="", out_signature="v") + def get_download_rate(self): + return self.core.get_state()['download_rate'] + + @dbus.service.method(dbus_interface=dbus_interface, + in_signature="", out_signature="v") + def get_upload_rate(self): + return self.core.get_state()['upload_rate'] + + #internal def _add_torrent(self, filename): - #dbus types break pickle, again..... filename = unicode(filename) - target = self.config.get("download_dir") + target = self.core.config.get("default_download_path") torrent_id = self.core.add_torrent(filename, target, self.interface.config.get("use_compact_storage")) diff --git a/plugins/WebUi/deluge_webserver.py b/plugins/WebUi/deluge_webserver.py index a39200683..4c989dccb 100644 --- a/plugins/WebUi/deluge_webserver.py +++ b/plugins/WebUi/deluge_webserver.py @@ -31,67 +31,15 @@ # this exception statement from your version. If you delete this exception # statement from all source files in the program, then also delete it here. - -from webserver_common import TORRENT_KEYS, STATE_MESSAGES import webserver_common as ws from webserver_framework import * - import webpy022 as web from webpy022.http import seeother, url -from webpy022.utils import Storage -from md5 import md5 import base64 -from deluge.common import fsize from operator import attrgetter - -#utils: -def check_pwd(pwd): - m = md5() - m.update(ws.config.get('pwd_salt')) - m.update(pwd) - return (m.digest() == ws.config.get('pwd_md5')) - -def get_torrent_status(torrent_id): - """ - helper method. - enhance ws.proxy.get_torrent_status with some extra data - """ - status = ws.proxy.get_torrent_status(torrent_id,TORRENT_KEYS) - status["id"] = torrent_id - - #for naming the status-images - status["calc_state_str"] = "downloading" - if status["paused"]: - status["calc_state_str"] = "inactive" - elif status["is_seed"]: - status["calc_state_str"] = "seeding" - - #action for torrent_pause - if status["calc_state_str"] == "inactive": - status["action"] = "start" - else: - status["action"] = "stop" - - if status["paused"]: - status["message"] = _("Paused %s%%") % status['progress'] - else: - status["message"] = "%s %i%%" % (STATE_MESSAGES[status["state"]] - , status['progress']) - - #add some pre-calculated values - status.update({ - "calc_total_downloaded" : (fsize(status["total_done"]) - + " (" + fsize(status["total_download"]) + ")"), - "calc_total_uploaded": (fsize(status['uploaded_memory'] - + status["total_payload_upload"]) + " (" - + fsize(status["total_upload"]) + ")"), - }) - - return Storage(status) #Storage for easy templating. - -#/utils +import os #routing: urls = ( @@ -107,15 +55,21 @@ urls = ( "/resume_all(.*)", "resume_all", "/refresh/set(.*)", "refresh_set", "/refresh/(.*)", "refresh", + "/config(.*)","config", "/home(.*)", "home", "/about(.*)", "about", + "/logout(.*)", "logout", #default-pages - "/", "login", - "", "login", + "/", "home", + "", "home", #remote-api: - "/remote/torrent/add(.*)", "remote_torrent_add" -) + "/remote/torrent/add(.*)", "remote_torrent_add", + #static: + "/static/(.*)","static", + "/template/static/(.*)","template_static", + #"/downloads/(.*)","downloads" disabled until it can handle large downloads. +) #/routing #pages: @@ -133,15 +87,10 @@ class login: start_session() do_redirect() elif vars.redir: - seeother(url('/login',error=1,redir=vars.redir)) + seeother(url('/login',error=1, redir=vars.redir)) else: seeother('/login?error=1') -class home: - @check_session - def GET(self, name): - do_redirect() - class index: "page containing the torrent list." @auto_refreshed @@ -150,7 +99,7 @@ class index: vars = web.input(sort=None, order=None) status_rows = [get_torrent_status(torrent_id) - for torrent_id in ws.proxy.get_torrent_state()] + for torrent_id in ws.proxy.get_session_state()] #sorting: if vars.sort: @@ -164,21 +113,19 @@ class index: return ws.render.index(status_rows) class torrent_info: - "torrent details" @auto_refreshed @deluge_page def GET(self, torrent_id): return ws.render.torrent_info(get_torrent_status(torrent_id)) class torrent_pause: - "start/stop a torrent" @check_session def POST(self, name): vars = web.input(stop = None, start = None, redir = None) if vars.stop: - ws.proxy.pause_torrent(vars.stop) + ws.proxy.pause_torrent([vars.stop]) elif vars.start: - ws.proxy.resume_torrent(vars.start) + ws.proxy.resume_torrent([vars.start]) do_redirect() @@ -194,7 +141,7 @@ class torrent_add: if vars.url and vars.torrent.filename: error_page(_("Choose an url or a torrent, not both.")) if vars.url: - ws.proxy.add_torrent_url(vars.url) + ws.proxy.add_torrent_url(vars.url ) do_redirect() elif vars.torrent.filename: data = vars.torrent.file.read() @@ -227,8 +174,7 @@ class torrent_delete: return ws.render.torrent_delete(get_torrent_status(torrent_id)) @check_session - def POST(self, name): - torrent_id = name + def POST(self, torrent_id): vars = web.input(data_also = None, torrent_also = None) data_also = bool(vars.data_also) torrent_also = bool(vars.torrent_also) @@ -238,30 +184,26 @@ class torrent_delete: class torrent_queue_up: @check_session - def POST(self, name): - torrent_id = name + def POST(self, torrent_id): ws.proxy.queue_up(torrent_id) do_redirect() class torrent_queue_down: @check_session - def POST(self, name): - torrent_id = name + def POST(self, torrent_id): ws.proxy.queue_down(torrent_id) do_redirect() class pause_all: @check_session def POST(self, name): - for torrent_id in ws.proxy.get_torrent_state(): - ws.proxy.pause_torrent(torrent_id) + ws.proxy.pause_torrent(ws.proxy.get_session_state()) do_redirect() class resume_all: @check_session def POST(self, name): - for torrent_id in ws.proxy.get_torrent_state(): - ws.proxy.resume_torrent(torrent_id) + ws.proxy.resume_torrent(ws.proxy.get_session_state()) do_redirect() class refresh: @@ -287,13 +229,61 @@ class refresh_set: else: error_page(_('refresh must be > 0')) +class config: + """core config + TODO:good validation. + """ + cfg_form = web.form.Form( + web.form.Dropdown('max_download', ws.SPEED_VALUES, + description=_('Download Speed Limit'), + post='%s Kib/sec' % ws.proxy.get_config_value('max_download_speed') + ) + ,web.form.Dropdown('max_upload', ws.SPEED_VALUES, + description=_('Upload Speed Limit'), + post='%s Kib/sec' % ws.proxy.get_config_value('max_upload_speed') + ) + ) + + @deluge_page + def GET(self, name): + return ws.render.config(self.cfg_form()) + + def POST(self, name): + vars = web.input(max_download=None, max_upload=None) + + #self.config.set("max_download_speed", float(str_bwdown)) + raise NotImplementedError('todo') + +class home: + @check_session + def GET(self, name): + do_redirect() + class about: @deluge_page_noauth def GET(self, name): return ws.render.about() -#/pages +class logout: + def POST(self, name): + end_session() + seeother('/login') +class static(static_handler): + base_dir = os.path.join(os.path.dirname(__file__),'static') + +class template_static(static_handler): + def get_base_dir(self): + return os.path.join(os.path.dirname(__file__), + 'templates/%s/static' % ws.config.get('template')) + +class downloads(static_handler): + def GET(self, name): + self.base_dir = ws.proxy.get_config_value('default_download_path') + if not ws.config.get('share_downloads'): + raise Exception('Access to downloads is forbidden.') + return static_handler.GET(self, name) +#/pages def WebServer(): return create_webserver(urls, globals()) @@ -307,4 +297,3 @@ def run(): if __name__ == "__main__": run() - diff --git a/plugins/WebUi/revno b/plugins/WebUi/revno index 84df3526d..194b81caa 100644 --- a/plugins/WebUi/revno +++ b/plugins/WebUi/revno @@ -1 +1 @@ -87 +112 diff --git a/plugins/WebUi/run_webserver b/plugins/WebUi/run_webserver index 9ac32c4ff..b8e9b47f5 100755 --- a/plugins/WebUi/run_webserver +++ b/plugins/WebUi/run_webserver @@ -1,3 +1,3 @@ #!/usr/bin/env python -from deluge_webserver import * -web.run(urls, globals()) \ No newline at end of file +import deluge_webserver +deluge_webserver.run() diff --git a/plugins/WebUi/scripts/add_torrent_to_deluge_webui b/plugins/WebUi/scripts/add_torrent_to_deluge_webui new file mode 100755 index 000000000..740857ccb --- /dev/null +++ b/plugins/WebUi/scripts/add_torrent_to_deluge_webui @@ -0,0 +1,10 @@ +#!/bin/bash + +pwd=deluge +url=http://localhost:8112 + +for arg in "$@" +do + curl -F torrent=@"$arg" -F pwd=$pwd $url/remote/torrent/add +done + diff --git a/plugins/WebUi/static/images/tango/system-log-out.png b/plugins/WebUi/static/images/tango/system-log-out.png new file mode 100644 index 0000000000000000000000000000000000000000..0010931e2c2c35eda774f972dad5f305ff7b6766 GIT binary patch literal 799 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7Sc;uILpV4%IBGajIv5xj zI14-?iy0VruY)k7lg8`{1_lPn64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xh zq!<{O=6Jd|hFJ8LPWI0b@f0~$zkb!O-Bp{Kt2^X+6keT6)PLma*eY;wbw(+i%xz?v6}mCrR@>P|Movt zR83!B7jHXHM&?evk>@1Ax&Wo7_rGr(Na|q}+@y1q?c4dy>F4Gfcuwm1^8S|d&KR{W zC8=JvvuTqp`aCaB;TAu)c#2bYa}ZZU+MOqFb{Zc(kjX5-!ssY4L4`AO)}^ei1?LuS zWpmK%HGGz=pOO0_@+R|yaE6~X^9*=SJ}qiVysN25giEVp_f)Q% zcVzT@PrfRh!qz0bIw4qOzE0SD_L@5z7-idZ^mHx+b^Xi|oimy5 z;P+({+Z4BN&p9Ysw=ibq1Q)^j-u}<;pQz|}>3`g{YhGPqLeI;Lq@<<;zj%1%A74K` zJ>uH_+1Hl}-HI}^lS}^e!{GO#75}?A<~|kw_jF5VgC8WTh+3zME?6NuxVBM z&E4fQ=l*us`i(E)9z(@E_qAcFkueFMulZKY>o3-Q_G)uO&8;)Jd;jcNJN^6n>@#Q1 z=t%z9SO4nOR&C|2QKEv0Z!X?2fBmP_@;OJ-1Ac|S^7giWV<$5#O=VzUVDNPHb6Mw< G&;$TI!e>bU literal 0 HcmV?d00001 diff --git a/plugins/WebUi/static_handler.py b/plugins/WebUi/static_handler.py new file mode 100644 index 000000000..d5b706cca --- /dev/null +++ b/plugins/WebUi/static_handler.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python +#(c) Martijn Voncken, mvoncken@gmail.com +#Same Licence as web.py 0.22 ->Public Domain +# +""" +static fileserving for web.py +without the need for wsgi wrapper magic. +""" +import webpy022 as web +from webpy022.http import seeother, url + +import posixpath +import urlparse +import urllib +import mimetypes +import os +import datetime +import cgi +from StringIO import StringIO +mimetypes.init() # try to read system mime.types + +class static_handler: + """ + mostly c&p from SimpleHttpServer + serves relative from start location + """ + base_dir = './' + extensions_map = mimetypes.types_map + + def get_base_dir(self): + #override this if you have a config that changes the base dir at runtime + #deluge on windows :( + return self.base_dir + + def GET(self, path): + path = self.translate_path(path) + if os.path.isdir(path): + if not path.endswith('/'): + path += "/" + return self.list_directory(path) + + ctype = self.guess_type(path) + + try: + f = open(path, 'rb') + except IOError: + raise Exception('file not found:%s' % path) + #web.header("404", "File not found") + #return + web.header("Content-type", ctype) + fs = os.fstat(f.fileno()) + web.header("Content-Length", str(fs[6])) + web.lastmodified(datetime.datetime.fromtimestamp(fs.st_mtime)) + print f.read() + + def translate_path(self, path): + """Translate a /-separated PATH to the local filename syntax. + + Components that mean special things to the local file system + (e.g. drive or directory names) are ignored. (XXX They should + probably be diagnosed.) + + """ + # abandon query parameters + path = urlparse.urlparse(path)[2] + path = posixpath.normpath(urllib.unquote(path)) + words = path.split('/') + words = filter(None, words) + path = self.get_base_dir() + for word in words: + drive, word = os.path.splitdrive(word) + head, word = os.path.split(word) + if word in (os.curdir, os.pardir): continue + path = os.path.join(path, word) + return path + + def guess_type(self, path): + base, ext = posixpath.splitext(path) + if ext in self.extensions_map: + return self.extensions_map[ext] + ext = ext.lower() + if ext in self.extensions_map: + return self.extensions_map[ext] + else: + return 'application/octet-stream' + + + def list_directory(self, path): + """Helper to produce a directory listing (absent index.html). + + Return value is either a file object, or None (indicating an + error). In either case, the headers are sent, making the + interface the same as for send_head(). + #TODO ->use web.py +template! + """ + try: + list = os.listdir(path) + except os.error: + web.header('404', "No permission to list directory") + return None + list.sort(key=lambda a: a.lower()) + f = StringIO() + displaypath = cgi.escape(urllib.unquote(path)) + f.write("Directory listing for %s\n" % displaypath) + f.write("

Directory listing for %s

\n" % displaypath) + f.write("
\n
    \n") + for name in list: + fullname = os.path.join(path, name) + displayname = linkname = name + # Append / for directories or @ for symbolic links + if os.path.isdir(fullname): + displayname = name + "/" + linkname = name + "/" + if os.path.islink(fullname): + displayname = name + "@" + # Note: a link to a directory displays with @ and links with / + f.write('
  • %s\n' + % (urllib.quote(linkname), cgi.escape(displayname))) + f.write("
\n
\n") + length = f.tell() + f.seek(0) + + web.header("Content-type", "text/html") + web.header("Content-Length", str(length)) + print f.read() + + +if __name__ == '__main__': + #example: + class usr_static(static_handler): + base_dir = os.path.expanduser('~') + + urls = ('/relative/(.*)','static_handler', + '/(.*)','usr_static') + + web.run(urls,globals()) diff --git a/plugins/WebUi/templates/deluge/about.html b/plugins/WebUi/templates/deluge/about.html index 66430a8b8..c882c8fad 100644 --- a/plugins/WebUi/templates/deluge/about.html +++ b/plugins/WebUi/templates/deluge/about.html @@ -7,6 +7,7 @@ $:render.header(_('About'))
  • Deluge
  • WebUi forum Thread +
  • GPL v2
  • @@ -18,6 +19,7 @@ $:render.header(_('About'))
    • Martijn Voncken
    +

    Template

    • Martijn Voncken
    • @@ -27,6 +29,7 @@ $:render.header(_('About'))
      • Zach Tibbitts
      • Alon Zakai
      • +
      • Alon Zakai
      • Marcos Pinto
      • Andrew Resch
      • @@ -36,4 +39,4 @@ $:render.header(_('About')) *and all other authors/helpers/contributors I forgot to mention. -$:render.footer() \ No newline at end of file +$:render.footer() diff --git a/plugins/WebUi/templates/deluge/config.html b/plugins/WebUi/templates/deluge/config.html new file mode 100644 index 000000000..e2670d0ae --- /dev/null +++ b/plugins/WebUi/templates/deluge/config.html @@ -0,0 +1,10 @@ +$def with (form) +$:render.header(_('Config')) + +
        Not Implemented!
        +
        +$:form.render() + +
        + +$:render.footer() diff --git a/plugins/WebUi/templates/deluge/index.html b/plugins/WebUi/templates/deluge/index.html index 249c83b3a..fb502868b 100644 --- a/plugins/WebUi/templates/deluge/index.html +++ b/plugins/WebUi/templates/deluge/index.html @@ -51,8 +51,10 @@ $for torrent in torrent_list: $:render.part_button('GET', '/torrent/add', _('Add torrent'), 'tango/list-add.png') $:render.part_button('POST', '/pause_all', _('Pause all'), 'tango/media-playback-pause.png') $:render.part_button('POST', '/resume_all', _('Resume all'), 'tango/media-playback-start.png') +$:render.part_button('POST', '/logout', _('Logout'), 'tango/system-log-out.png') -$:render.part_refresh() +$:part_stats() $:render.footer() + diff --git a/plugins/WebUi/templates/deluge/part_button.html b/plugins/WebUi/templates/deluge/part_button.html index b2d15d541..8c420560f 100644 --- a/plugins/WebUi/templates/deluge/part_button.html +++ b/plugins/WebUi/templates/deluge/part_button.html @@ -2,21 +2,25 @@ $def with (method, url, title, image='')
        - $if (get_config('button_style') == 1): $if image: - $title + $else: + $if (get_config('button_style') == 2): + -
        diff --git a/plugins/WebUi/templates/deluge/part_stats.html b/plugins/WebUi/templates/deluge/part_stats.html new file mode 100644 index 000000000..4150a0f36 --- /dev/null +++ b/plugins/WebUi/templates/deluge/part_stats.html @@ -0,0 +1,30 @@ +$def with (stats) + + +
        + +$_('Auto refresh:') +$if getcookie('auto_refresh') == '1': + ($getcookie('auto_refresh_secs')) $_('seconds')   + $:render.part_button('GET', '/refresh/set', _('Set'), 'tango/preferences-system.png') + $:render.part_button('POST', '/refresh/off', _('Disable'), 'tango/process-stop.png') +$else: + $_('Off')   + $:render.part_button('POST', '/refresh/on', _('Enable'), 'tango/view-refresh.png') +$#end +
        + + + + diff --git a/plugins/WebUi/templates/deluge/torrent_info.html b/plugins/WebUi/templates/deluge/torrent_info.html index 39e25a51c..663d26c87 100644 --- a/plugins/WebUi/templates/deluge/torrent_info.html +++ b/plugins/WebUi/templates/deluge/torrent_info.html @@ -84,6 +84,7 @@ $:render.part_button('GET', '/torrent/delete/' + str(torrent.id), _('Remove'), '
        + + @@ -114,6 +117,6 @@ $:render.part_button('POST', '/torrent/queue/up/' + str(torrent.id), _('Queue Up $:render.part_button('POST', '/torrent/queue/down/' + str(torrent.id), _('Queue Down'), 'tango/down.png') -$:render.part_refresh() +$:part_stats() $:render.footer() diff --git a/plugins/WebUi/templates/example/footer.html b/plugins/WebUi/templates/example/footer.html new file mode 100644 index 000000000..11a09caf8 --- /dev/null +++ b/plugins/WebUi/templates/example/footer.html @@ -0,0 +1,3 @@ + + + diff --git a/plugins/WebUi/templates/example/header.html b/plugins/WebUi/templates/example/header.html new file mode 100644 index 000000000..6b0702f4a --- /dev/null +++ b/plugins/WebUi/templates/example/header.html @@ -0,0 +1,12 @@ +$def with (title) + + + Deluge(example) : $title + + + + + +[HOME] + +

        $title

        diff --git a/plugins/WebUi/templates/example/index.html b/plugins/WebUi/templates/example/index.html new file mode 100644 index 000000000..7c3ca4aab --- /dev/null +++ b/plugins/WebUi/templates/example/index.html @@ -0,0 +1,42 @@ +$def with (torrent_list) +$:render.header(_('Torrent list')) + +
        + + + $:(sort_head('calc_state_str', 'S')) + $:(sort_head('queue_pos', '#')) + $:(sort_head('name', _('Name'))) + $:(sort_head('progress', _('Progress'))) + +$#4-space indentation is mandatory for for-loops in templetor! +$for torrent in torrent_list: + + + + + + +
        + $torrent.queue_pos + $(crop(torrent.name, 40)) +
        +
        + $torrent.message +
        +
        +
        + +
        + +
        +$:render.part_button('GET', '/torrent/add', _('Add torrent'), 'tango/list-add.png') +$:render.part_button('POST', '/pause_all', _('Pause all'), 'tango/media-playback-pause.png') +$:render.part_button('POST', '/resume_all', _('Resume all'), 'tango/media-playback-start.png') +$:render.part_button('POST', '/logout', _('Logout'), 'tango/system-log-out.png') +
        + +$:render.footer() + diff --git a/plugins/WebUi/version b/plugins/WebUi/version index 448878e1e..004ed9c81 100644 --- a/plugins/WebUi/version +++ b/plugins/WebUi/version @@ -1,5 +1,5 @@ revision-id: mvoncken@gmail.com-20070930083408-sv8mo0mi1rbjnfvk date: 2007-10-23 15:10:08 +0200 build-date: 2007-10-23 15:34:50 +0200 -revno: 87 +revno: 112 branch-nick: WebUi diff --git a/plugins/WebUi/webserver_common.py b/plugins/WebUi/webserver_common.py index 2173f7712..dd932c681 100644 --- a/plugins/WebUi/webserver_common.py +++ b/plugins/WebUi/webserver_common.py @@ -29,40 +29,96 @@ # this exception statement from your version. If you delete this exception # statement from all source files in the program, then also delete it here. +""" +initializes config,render and proxy. +contains all hacks to support running in process0.5 ,run inside-gtk0.5 and + run in process0.6 +""" + import os import deluge -from deluge.common import INSTALL_PREFIX import random import pickle +import sys from webpy022 import template - random.seed() +path = os.path.dirname(__file__) -config_file = deluge.common.CONFIG_DIR + "/webui.conf" +try: + _('translate something') +except: + import gettext + gettext.install('~/') #no translations :( -#a bit hacky way of detecting i'm in the deluge gui or in a process :( -if not hasattr(deluge,'pref'): +try: + config_dir = deluge.common.CONFIG_DIR +except: + config_dir = os.path.expanduser("~/.config/deluge") + +config_file = os.path.join(config_dir,'webui.conf') +session_file = os.path.join(config_dir,'webui.sessions') + + +class subclassed_render(object): + """ + try to use the html template in configured dir. + not available : use template in /deluge/ + """ + def __init__(self, template_dirname, cache=False): + self.base_template = template.render( + os.path.join(path, 'templates/deluge/'), + cache=cache) + + self.sub_template = template.render( + os.path.join(path, 'templates/%s/' % template_dirname), + cache=cache) + + def __getattr__(self, attr): + if hasattr(self.sub_template, attr): + return getattr(self.sub_template, attr) + else: + return getattr(self.base_template, attr) + +def init_process(): + globals()['config'] = pickle.load(open(config_file)) + globals()['render'] = subclassed_render(config.get('template'), + config.get('cache_templates')) + +def init_06(): + import deluge.ui.client as proxy + proxy.set_core_uri('http://localhost:58846') #How to configure this? + + init_process() + globals()['proxy'] = proxy + +def init_05(): import dbus + init_process() bus = dbus.SessionBus() proxy = bus.get_object("org.deluge_torrent.dbusplugin" , "/org/deluge_torrent/DelugeDbusPlugin") - config = pickle.load(open(config_file)) - render = template.render('templates/%s/' % config.get('template'), - cache=config.get('cache_templates')) + globals()['proxy'] = proxy -def init(): +def init_gtk_05(): #appy possibly changed config-vars, only called in when runing inside gtk. - path = os.path.dirname(__file__) from dbus_interface import get_dbus_manager globals()['proxy'] = get_dbus_manager() globals()['config'] = deluge.pref.Preferences(config_file, False) - globals()['render'] = template.render(os.path.join(path, 'templates/%s/' % - config.get('template')), cache=config.get('cache_templates')) + globals()['render'] = subclassed_render(config.get('template'), + config.get('cache_templates')) +#hacks to determine environment, TODO: clean up. +if 'env=0.5' in sys.argv: + init_05() +elif not hasattr(deluge, 'common'): + init_06() +elif not hasattr(deluge,'pref'): + init_05() -REVNO = '0.56.stable.' + open(os.path.join(os.path.dirname(__file__),'revno')).read() +#constants +REVNO = open(os.path.join(os.path.dirname(__file__),'revno')).read() VERSION = open(os.path.join(os.path.dirname(__file__),'version')).read() TORRENT_KEYS = ['distributed_copies', 'download_payload_rate', @@ -82,3 +138,30 @@ STATE_MESSAGES = (_("Queued"), _("Finished"), _("Seeding"), _("Allocating")) + +SPEED_VALUES = [ + (-1, 'Unlimited'), + (5, '5.0 Kib/sec'), + (10, '10.0 Kib/sec'), + (15, '15.0 Kib/sec'), + (25, '25.0 Kib/sec'), + (30, '30.0 Kib/sec'), + (50, '50.0 Kib/sec'), + (80, '80.0 Kib/sec'), + (300, '300.0 Kib/sec'), + (500, '500.0 Kib/sec') + ] + +COOKIE_DEFAULTS = { + 'auto_refresh_secs':'10' +} + +try: + SESSIONS = pickle.load(open(session_file)) +except: + SESSIONS = [] + + + + + diff --git a/plugins/WebUi/webserver_framework.py b/plugins/WebUi/webserver_framework.py index b7254886b..37b8497b0 100644 --- a/plugins/WebUi/webserver_framework.py +++ b/plugins/WebUi/webserver_framework.py @@ -45,15 +45,21 @@ import webpy022 as web from webpy022.webapi import cookies, setcookie as w_setcookie from webpy022.http import seeother, url from webpy022 import template,changequery as self_url +from webpy022.utils import Storage +from static_handler import static_handler + +from deluge.common import fsize,fspeed import traceback import random from operator import attrgetter +import datetime +import pickle +from md5 import md5 from deluge import common -from webserver_common import REVNO, VERSION +from webserver_common import REVNO, VERSION, COOKIE_DEFAULTS import webserver_common as ws - from debugerror import deluge_debugerror #init: @@ -65,14 +71,22 @@ def setcookie(key, val): """add 30 days expires header for persistent cookies""" return w_setcookie(key, val , expires=2592000) -SESSIONS = [] #dumb sessions. +#really simple sessions, to bad i had to implement them myself. def start_session(): session_id = str(random.random()) - SESSIONS.append(session_id) + ws.SESSIONS.append(session_id) + if len(ws.SESSIONS) > 20: #save max 20 sessions? + ws.SESSIONS = ws.SESSIONS[-20:] + #not thread safe! , but a verry rare bug. + pickle.dump(ws.SESSIONS, open(ws.session_file,'wb')) setcookie("session_id", session_id) - if getcookie('auto_refresh_secs') == None: - setcookie('auto_refresh_secs','10') +def end_session(): + session_id = getcookie("session_id") + if session_id in ws.SESSIONS: + ws.SESSIONS.remove(session_id) + #not thread safe! , but a verry rare bug. + pickle.dump(ws.SESSIONS, open(ws.session_file,'wb')) def do_redirect(): """for redirects after a POST""" @@ -92,7 +106,6 @@ def error_page(error): print ws.render.error(error) def getcookie(key, default=None): - COOKIE_DEFAULTS = {'auto_refresh_secs':'10'} key = str(key).strip() ck = cookies() val = ck.get(key, default) @@ -120,9 +133,8 @@ def check_session(func): """ def deco(self, name): vars = web.input(redir_after_login=None) - ck = cookies() - if ck.has_key("session_id") and ck["session_id"] in SESSIONS: + if ck.has_key("session_id") and ck["session_id"] in ws.SESSIONS: return func(self, name) #ok, continue.. elif vars.redir_after_login: seeother(url("/login",redir=self_url())) @@ -154,6 +166,77 @@ def remote(func): print traceback.format_exc() return deco +#utils: +def check_pwd(pwd): + m = md5() + m.update(ws.config.get('pwd_salt')) + m.update(pwd) + return (m.digest() == ws.config.get('pwd_md5')) + +def get_stats(): + stats = Storage({ + 'download_rate':fspeed(ws.proxy.get_download_rate()), + 'upload_rate':fspeed(ws.proxy.get_upload_rate()), + 'max_download':ws.proxy.get_config_value('max_download_speed_bps'), + 'max_upload':ws.proxy.get_config_value('max_upload_speed_bps'), + }) + if stats.max_upload < 0: + stats.max_upload = _("Unlimited") + else: + stats.max_upload = fspeed(stats.max_upload) + + if stats.max_download < 0: + stats.max_download = _("Unlimited") + else: + stats.max_download = fspeed(stats.max_download) + + return stats + + +def get_torrent_status(torrent_id): + """ + helper method. + enhance ws.proxy.get_torrent_status with some extra data + """ + status = Storage(ws.proxy.get_torrent_status(torrent_id,ws.TORRENT_KEYS)) + + #add missing values for deluge 0.6: + for key in ws.TORRENT_KEYS: + if not key in status: + status[key] = 0 + + status["id"] = torrent_id + + #for naming the status-images + status["calc_state_str"] = "downloading" + if status["paused"]: + status["calc_state_str"] = "inactive" + elif status["is_seed"]: + status["calc_state_str"] = "seeding" + + #action for torrent_pause + if status["calc_state_str"] == "inactive": + status["action"] = "start" + else: + status["action"] = "stop" + + if status["paused"]: + status["message"] = _("Paused %s%%") % status['progress'] + else: + status["message"] = "%s %i%%" % (ws.STATE_MESSAGES[status["state"]] + , status['progress']) + + #add some pre-calculated values + status.update({ + "calc_total_downloaded" : (fsize(status["total_done"]) + + " (" + fsize(status["total_download"]) + ")"), + "calc_total_uploaded": (fsize(status['uploaded_memory'] + + status["total_payload_upload"]) + " (" + + fsize(status["total_upload"]) + ")"), + }) + return status +#/utils + #template-defs: def template_crop(text, end): if len(text) > end: @@ -176,12 +259,15 @@ def template_sort_head(id,name): return ws.render.sort_column_head(id, name, order, active_up, active_down) +def template_part_stats(): + return ws.render.part_stats(get_stats()) def get_config(var): return ws.config.get(var) template.Template.globals.update({ 'sort_head': template_sort_head, + 'part_stats':template_part_stats, 'crop': template_crop, '_': _ , #gettext/translations 'str': str, #because % in templetor is broken. @@ -198,145 +284,20 @@ template.Template.globals.update({ }) #/template-defs +def create_webserver(urls, methods): + from webpy022.request import webpyfunc + from webpy022 import webapi + from gtk_cherrypy_wsgiserver import CherryPyWSGIServer - -#------------------------------------------------------------------------------ -#Some copy and paste from web.py -#mostly caused by /static -#TODO : FIX THIS. -#static-files serving should be moved to the normal webserver! -from SimpleHTTPServer import SimpleHTTPRequestHandler -from BaseHTTPServer import BaseHTTPRequestHandler -from gtk_cherrypy_wsgiserver import CherryPyWSGIServer -from BaseHTTPServer import BaseHTTPRequestHandler - -from webpy022.request import webpyfunc -from webpy022 import webapi -import os - -import posixpath -import urllib -import urlparse - -class RelativeHandler(SimpleHTTPRequestHandler): - def translate_path(self, path): - """Translate a /-separated PATH to the local filename syntax. - - Components that mean special things to the local file system - (e.g. drive or directory names) are ignored. (XXX They should - probably be diagnosed.) - - """ - # abandon query parameters - path = urlparse.urlparse(path)[2] - path = posixpath.normpath(urllib.unquote(path)) - words = path.split('/') - words = filter(None, words) - path = os.path.dirname(__file__) - for word in words: - drive, word = os.path.splitdrive(word) - head, word = os.path.split(word) - if word in (os.curdir, os.pardir): continue - path = os.path.join(path, word) - return path - -class StaticApp(RelativeHandler): - """WSGI application for serving static files.""" - def __init__(self, environ, start_response): - self.headers = [] - self.environ = environ - self.start_response = start_response - - def send_response(self, status, msg=""): - self.status = str(status) + " " + msg - - def send_header(self, name, value): - self.headers.append((name, value)) - - def end_headers(self): - pass - - def log_message(*a): pass - - def __iter__(self): - environ = self.environ - - self.path = environ.get('PATH_INFO', '') - self.client_address = environ.get('REMOTE_ADDR','-'), \ - environ.get('REMOTE_PORT','-') - self.command = environ.get('REQUEST_METHOD', '-') - - from cStringIO import StringIO - self.wfile = StringIO() # for capturing error - - f = self.send_head() - self.start_response(self.status, self.headers) - - if f: - block_size = 16 * 1024 - while True: - buf = f.read(block_size) - if not buf: - break - yield buf - f.close() - else: - value = self.wfile.getvalue() - yield value - -class WSGIWrapper(BaseHTTPRequestHandler): - """WSGI wrapper for logging the status and serving static files.""" - def __init__(self, app): - self.app = app - self.format = '%s - - [%s] "%s %s %s" - %s' - - def __call__(self, environ, start_response): - def xstart_response(status, response_headers, *args): - write = start_response(status, response_headers, *args) - self.log(status, environ) - return write - - path = environ.get('PATH_INFO', '') - if path.startswith('/static/'): - return StaticApp(environ, xstart_response) - else: - return self.app(environ, xstart_response) - - def log(self, status, environ): - #mvoncken,no logging.. - return - - outfile = environ.get('wsgi.errors', web.debug) - req = environ.get('PATH_INFO', '_') - protocol = environ.get('ACTUAL_SERVER_PROTOCOL', '-') - method = environ.get('REQUEST_METHOD', '-') - host = "%s:%s" % (environ.get('REMOTE_ADDR','-'), - environ.get('REMOTE_PORT','-')) - - #@@ It is really bad to extend from - #@@ BaseHTTPRequestHandler just for this method - time = self.log_date_time_string() - - print >> outfile, self.format % (host, time, protocol, - method, req, status) - -def create_webserver(urls,methods): - func = webapi.wsgifunc(webpyfunc(urls,methods, False)) - server_address=("0.0.0.0",ws.config.get('port')) - - func = WSGIWrapper(func) + func = webapi.wsgifunc(webpyfunc(urls, methods, False)) + server_address=("0.0.0.0", int(ws.config.get('port'))) server = CherryPyWSGIServer(server_address, func, server_name="localhost") - - - print "(created) http://%s:%d/" % server_address - + print "http://%s:%d/" % server_address return server #------ __all__ = ['deluge_page_noauth', 'deluge_page', 'remote', 'auto_refreshed', 'check_session', 'do_redirect', 'error_page','start_session','getcookie' - ,'create_webserver','setcookie'] - - - + ,'setcookie','create_webserver','end_session', + 'get_torrent_status', 'check_pwd','static_handler'] diff --git a/po/POTFILES.in b/po/POTFILES.in index aebac4469..514678dba 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -54,4 +54,7 @@ plugins/WebSeed/__init__.py plugins/WebSeed/webseed.glade plugins/Scheduler/__init__.py plugins/Scheduler/plugin.py -plugins/WebUI/__init__.py +plugins/WebUi/__init__.py +plugins/WebUi/webserver_common.py +plugins/WebUi/deluge_webserver.py +plugins/WebUi/scripts/template_strings.py diff --git a/po/deluge.pot b/po/deluge.pot index c3e2d397c..c8c03f45d 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-10-25 21:56-0500\n" +"POT-Creation-Date: 2007-10-27 20:34-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -88,7 +88,7 @@ msgstr "" msgid "Torrent Info" msgstr "" -#: glade/delugegtk.glade:750 +#: glade/delugegtk.glade:750 plugins/WebUi/scripts/template_strings.py:8 msgid "Details" msgstr "" @@ -149,11 +149,13 @@ msgid "Status" msgstr "" #: glade/delugegtk.glade:965 src/interface.py:602 +#: plugins/WebUi/scripts/template_strings.py:19 msgid "Seeders" msgstr "" #: glade/delugegtk.glade:974 src/interface.py:605 #: plugins/TorrentPeers/__init__.py:72 +#: plugins/WebUi/scripts/template_strings.py:15 msgid "Peers" msgstr "" @@ -171,11 +173,11 @@ msgstr "" msgid "Time Remaining" msgstr "" -#: glade/delugegtk.glade:1010 +#: glade/delugegtk.glade:1010 plugins/WebUi/scripts/template_strings.py:4 msgid "Availability" msgstr "" -#: glade/delugegtk.glade:1019 +#: glade/delugegtk.glade:1019 plugins/WebUi/scripts/template_strings.py:21 msgid "Share Ratio" msgstr "" @@ -211,7 +213,7 @@ msgstr "" msgid "Remove Torrent" msgstr "" -#: glade/delugegtk.glade:1157 +#: glade/delugegtk.glade:1157 plugins/WebUi/scripts/template_strings.py:18 msgid "Remove" msgstr "" @@ -278,7 +280,7 @@ msgstr "" msgid "Delete downloaded files" msgstr "" -#: glade/dgtkpopups.glade:88 +#: glade/dgtkpopups.glade:88 plugins/WebUi/scripts/template_strings.py:6 msgid "Delete .torrent file" msgstr "" @@ -294,7 +296,7 @@ msgstr "" msgid "Clear Finished" msgstr "" -#: glade/dgtkpopups.glade:241 +#: glade/dgtkpopups.glade:241 plugins/WebUi/scripts/template_strings.py:22 msgid "Speed" msgstr "" @@ -542,6 +544,7 @@ msgid "Seeding" msgstr "" #: glade/preferences_dialog.glade:964 src/core.py:91 +#: plugins/WebUi/webserver_common.py:139 msgid "Seeding" msgstr "" @@ -646,6 +649,7 @@ msgstr "" #: glade/preferences_dialog.glade:1478 glade/preferences_dialog.glade:1672 #: glade/preferences_dialog.glade:1866 glade/preferences_dialog.glade:2060 +#: plugins/WebUi/scripts/template_strings.py:13 msgid "Password" msgstr "" @@ -1004,7 +1008,7 @@ msgstr "" msgid "Name" msgstr "" -#: src/interface.py:614 +#: src/interface.py:614 plugins/WebUi/scripts/template_strings.py:10 msgid "ETA" msgstr "" @@ -1088,31 +1092,32 @@ msgstr "" msgid "Are you sure that you want to remove all seeding torrents?" msgstr "" -#: src/core.py:85 +#: src/core.py:85 plugins/WebUi/webserver_common.py:133 msgid "Queued" msgstr "" -#: src/core.py:86 +#: src/core.py:86 plugins/WebUi/webserver_common.py:134 msgid "Checking" msgstr "" -#: src/core.py:87 +#: src/core.py:87 plugins/WebUi/webserver_common.py:135 msgid "Connecting" msgstr "" -#: src/core.py:88 +#: src/core.py:88 plugins/WebUi/webserver_common.py:136 msgid "Downloading Metadata" msgstr "" #: src/core.py:89 plugins/BlocklistImport/ui.py:117 +#: plugins/WebUi/webserver_common.py:137 msgid "Downloading" msgstr "" -#: src/core.py:90 +#: src/core.py:90 plugins/WebUi/webserver_common.py:138 msgid "Finished" msgstr "" -#: src/core.py:92 +#: src/core.py:92 plugins/WebUi/webserver_common.py:140 msgid "Allocating" msgstr "" @@ -1390,66 +1395,66 @@ msgstr "" msgid "Torrent Creator" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:103 +#: plugins/TorrentCreator/torrentcreator.glade:102 msgid "This torrent will be made from a single file" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:104 +#: plugins/TorrentCreator/torrentcreator.glade:103 msgid "File:" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:120 +#: plugins/TorrentCreator/torrentcreator.glade:119 msgid "This torrent will be made from a directory" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:121 +#: plugins/TorrentCreator/torrentcreator.glade:120 msgid "Folder:" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:138 +#: plugins/TorrentCreator/torrentcreator.glade:137 msgid "Source" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:184 +#: plugins/TorrentCreator/torrentcreator.glade:182 msgid "Save Torrent File As:" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:237 +#: plugins/TorrentCreator/torrentcreator.glade:235 msgid "Load this torrent into Deluge for seeding" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:238 +#: plugins/TorrentCreator/torrentcreator.glade:236 msgid "Add new torrent to queue" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:257 +#: plugins/TorrentCreator/torrentcreator.glade:255 msgid "Torrent File" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:305 +#: plugins/TorrentCreator/torrentcreator.glade:302 msgid "Trackers" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:352 +#: plugins/TorrentCreator/torrentcreator.glade:348 msgid "Comments" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:389 +#: plugins/TorrentCreator/torrentcreator.glade:384 msgid "Author" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:425 +#: plugins/TorrentCreator/torrentcreator.glade:423 msgid "Set Private Flag" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:441 -#: plugins/TorrentCreator/torrentcreator.glade:461 +#: plugins/TorrentCreator/torrentcreator.glade:436 +#: plugins/TorrentCreator/torrentcreator.glade:457 msgid "" "The smaller the piece sizes, the more efficient the transfers will be, but " "the actual \".torrent\" file will be larger" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:442 +#: plugins/TorrentCreator/torrentcreator.glade:437 msgid "" "32 KiB\n" "64 KiB\n" @@ -1457,13 +1462,14 @@ msgid "" "256 KiB\n" "512 KiB\n" "1024 KiB\n" +"2048 KiB\n" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:463 +#: plugins/TorrentCreator/torrentcreator.glade:459 msgid "Piece Size:" msgstr "" -#: plugins/TorrentCreator/torrentcreator.glade:477 +#: plugins/TorrentCreator/torrentcreator.glade:473 msgid "Advanced" msgstr "" @@ -2102,3 +2108,171 @@ msgid "" "When set to -1 (unlimited), the global limits in Deluge's preferences will " "be obeyed." msgstr "" + +#: plugins/WebUi/__init__.py:31 +msgid "Web User Interface" +msgstr "" + +#: plugins/WebUi/__init__.py:34 +msgid "" +"A Web based User Interface\n" +"\n" +"Firefox greasemonkey script: http://userscripts.org/scripts/show/12639\n" +"\n" +"Remotely add a file: \"curl -F torrent=@./test1.torrent -F pwd=deluge http://" +"localhost:8112/remote/torrent/add\"\n" +"\n" +"There is support for multiple templates, but just one is included.\n" +"\n" +"Other contributors:\n" +"*somedude : template enhancements.\n" +"*markybob : stability : synced with his changes in deluge-svn.\n" +msgstr "" + +#: plugins/WebUi/__init__.py:179 +msgid "WebUi Config" +msgstr "" + +#: plugins/WebUi/__init__.py:187 +msgid "Port Number" +msgstr "" + +#: plugins/WebUi/__init__.py:188 +msgid "New Password" +msgstr "" + +#: plugins/WebUi/__init__.py:189 +msgid "New Password(confirm)" +msgstr "" + +#: plugins/WebUi/__init__.py:190 +msgid "Template" +msgstr "" + +#: plugins/WebUi/__init__.py:191 +msgid "Button Style" +msgstr "" + +#: plugins/WebUi/__init__.py:193 +msgid "Cache Templates" +msgstr "" + +#: plugins/WebUi/__init__.py:209 +msgid "Text and image" +msgstr "" + +#: plugins/WebUi/__init__.py:209 +msgid "Image Only" +msgstr "" + +#: plugins/WebUi/__init__.py:209 +msgid "Text Only" +msgstr "" + +#: plugins/WebUi/__init__.py:243 +msgid "Confirmed Password <> New Password\n" +msgstr "" + +#: plugins/WebUi/webserver_common.py:48 +msgid "translate something" +msgstr "" + +#: plugins/WebUi/deluge_webserver.py:142 +msgid "Choose an url or a torrent, not both." +msgstr "" + +#: plugins/WebUi/deluge_webserver.py:153 +msgid "no data." +msgstr "" + +#: plugins/WebUi/deluge_webserver.py:230 +msgid "refresh must be > 0" +msgstr "" + +#: plugins/WebUi/deluge_webserver.py:238 +msgid "Download Speed Limit" +msgstr "" + +#: plugins/WebUi/deluge_webserver.py:242 +msgid "Upload Speed Limit" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:1 +msgid "# Of Files" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:2 +msgid "About" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:3 +msgid "Auto refresh:" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:5 +msgid "Debug:Data Dump" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:7 +msgid "Delete downloaded files." +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:9 +msgid "Downloaded" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:11 +msgid "Next Announce" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:12 +msgid "Off" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:14 +msgid "Password is invalid,try again" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:16 +msgid "Pieces" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:17 +msgid "Refresh page every:" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:20 +msgid "Set" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:23 +msgid "Submit" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:24 +msgid "Total Size" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:25 +msgid "Tracker" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:26 +msgid "Tracker Status" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:27 +msgid "Upload torrent" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:28 +msgid "Uploaded" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:29 +msgid "Url" +msgstr "" + +#: plugins/WebUi/scripts/template_strings.py:30 +msgid "seconds" +msgstr ""