sync webui 112 and translate

This commit is contained in:
Marcos Pinto 2007-10-28 01:35:27 +00:00
commit cd2f45da92
22 changed files with 810 additions and 332 deletions

View file

@ -29,7 +29,7 @@
# this exception statement from your version. If you delete this exception # this exception statement from your version. If you delete this exception
plugin_name = _("Web User Interface") plugin_name = _("Web User Interface")
plugin_author = _("Martijn Voncken") plugin_author = "Martijn Voncken"
plugin_version = "rev." plugin_version = "rev."
plugin_description = _("""A Web based User Interface plugin_description = _("""A Web based User Interface
@ -41,7 +41,7 @@ There is support for multiple templates, but just one is included.
Other contributors: Other contributors:
*somedude : template enhancements. *somedude : template enhancements.
*markybob : stability : synced with his changes in deluge-svn.
""") """)
import deluge.common import deluge.common
@ -80,9 +80,10 @@ class plugin_WebUi(object):
self.web_server = None self.web_server = None
if not deluge.common.windows_check(): if not deluge.common.windows_check():
import commands 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: 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. time.sleep(1) #safe time to wait for kill to finish.
self.config_file = deluge.common.CONFIG_DIR + "/webui.conf" self.config_file = deluge.common.CONFIG_DIR + "/webui.conf"
self.config = deluge.pref.Preferences(self.config_file, False) 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. if not self.config.get('port'): #ugly way to detect new config file.
#set default values: #set default values:
self.config.set("port", 8112) 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("button_style", 2)
self.config.set("auto_refresh", False) self.config.set("auto_refresh", False)
self.config.set("auto_refresh_secs", 4) self.config.set("auto_refresh_secs", 4)
@ -112,11 +110,9 @@ class plugin_WebUi(object):
self.config.set("cache_templates", True) self.config.set("cache_templates", True)
if deluge.common.windows_check(): 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: 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.dbus_manager = get_dbus_manager(deluge_core, deluge_interface,
self.config, self.config_file) self.config, self.config_file)
@ -141,8 +137,8 @@ class plugin_WebUi(object):
self.kill_server() self.kill_server()
if self.config.get("run_in_thread"): if self.config.get("run_in_thread"):
print 'start Webui(inside gtk)..' print 'Start Webui(inside gtk)..'
webserver_common.init() #reload changed config. webserver_common.init_gtk_05() #reload changed config.
from deluge_webserver import WebServer #only import in threaded mode from deluge_webserver import WebServer #only import in threaded mode
@ -150,11 +146,9 @@ class plugin_WebUi(object):
self.web_server.start_gtk() self.web_server.start_gtk()
else: else:
print 'start Webui(in process)..' print 'Start Webui(in process)..'
path = os.path.dirname(__file__) server_bin = os.path.dirname(__file__) + '/run_webserver'
server_bin = path + '/run_webserver' self.proc = Popen((server_bin,'env=0.5'))
port = str(self.config.get('port'))
self.proc = Popen((server_bin, port),cwd=path)
def kill_server(self): def kill_server(self):
if self.web_server: if self.web_server:
@ -187,7 +181,8 @@ class ConfigDialog(gtk.Dialog):
template_path = os.path.join(os.path.dirname(__file__), 'templates') template_path = os.path.join(os.path.dirname(__file__), 'templates')
self.templates = [dirname for dirname self.templates = [dirname for dirname
in os.listdir(template_path) 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.port = self.add_widget(_('Port Number'), gtk.SpinButton())
self.pwd1 = self.add_widget(_('New Password'), gtk.Entry()) 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.template = self.add_widget(_('Template'), gtk.combo_box_new_text())
self.button_style = self.add_widget(_('Button Style'), self.button_style = self.add_widget(_('Button Style'),
gtk.combo_box_new_text()) 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'), self.cache_templates = self.add_widget(_('Cache Templates'),
gtk.CheckButton()) 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_range(80, 65536)
self.port.set_increments(1, 10) self.port.set_increments(1, 10)
self.pwd1.set_visibility(False) self.pwd1.set_visibility(False)
@ -218,23 +208,16 @@ class ConfigDialog(gtk.Dialog):
for item in [_('Text and image'), _('Image Only'), _('Text Only')]: for item in [_('Text and image'), _('Image Only'), _('Text Only')]:
self.button_style.append_text(item) 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.config.set("button_style", 2)
self.port.set_value(int(self.config.get("port"))) self.port.set_value(int(self.config.get("port")))
self.template.set_active( self.template.set_active(
self.templates.index(self.config.get("template"))) self.templates.index(self.config.get("template")))
self.button_style.set_active(self.config.get("button_style")) 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.cache_templates.set_active(self.config.get("cache_templates"))
self.vbox.pack_start(self.vb, True, True, 0) 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("port", int(self.port.get_value()))
self.config.set("template", self.template.get_active_text()) self.config.set("template", self.template.get_active_text())
self.config.set("button_style", self.button_style.get_active()) 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("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.config.save(self.plugin.config_file)
self.plugin.start_server() #restarts server self.plugin.start_server() #restarts server

View file

@ -68,7 +68,7 @@ class DbusManager(dbus.service.Object):
@dbus.service.method(dbus_interface=dbus_interface, @dbus.service.method(dbus_interface=dbus_interface,
in_signature="",out_signature="as") in_signature="",out_signature="as")
def get_torrent_state(self): def get_session_state(self):
"""Returns a list of torrent_ids in the session. """Returns a list of torrent_ids in the session.
same as 0.6, but returns type "as" instead of a pickle same as 0.6, but returns type "as" instead of a pickle
""" """
@ -129,18 +129,20 @@ class DbusManager(dbus.service.Object):
return status_subset return status_subset
@dbus.service.method(dbus_interface=dbus_interface, @dbus.service.method(dbus_interface=dbus_interface,
in_signature="s",out_signature="") in_signature="as",out_signature="")
def pause_torrent(self, torrent_id): def pause_torrent(self, torrents):
"""same as 0.6 interface""" """same as 0.6 interface"""
torrent_id = int(torrent_id) for torrent_id in torrents:
self.core.set_user_pause(torrent_id,True) torrent_id = int(torrent_id)
self.core.set_user_pause(torrent_id,True)
@dbus.service.method(dbus_interface=dbus_interface, @dbus.service.method(dbus_interface=dbus_interface,
in_signature="s", out_signature="") in_signature="as", out_signature="")
def resume_torrent(self, torrent_id): def resume_torrent(self, torrents):
"""same as 0.6 interface""" """same as 0.6 interface"""
torrent_id = int(torrent_id) for torrent_id in torrents:
self.core.set_user_pause(torrent_id,False) torrent_id = int(torrent_id)
self.core.set_user_pause(torrent_id,False)
@dbus.service.method(dbus_interface=dbus_interface, @dbus.service.method(dbus_interface=dbus_interface,
in_signature="sbb", out_signature="") in_signature="sbb", out_signature="")
@ -157,7 +159,6 @@ class DbusManager(dbus.service.Object):
@dbus.service.method(dbus_interface=dbus_interface, @dbus.service.method(dbus_interface=dbus_interface,
in_signature="s", out_signature="b") in_signature="s", out_signature="b")
def add_torrent_url(self, url): def add_torrent_url(self, url):
"""not available in deluge 0.6 interface"""
filename = fetch_url(url) filename = fetch_url(url)
self._add_torrent(filename) self._add_torrent(filename)
return True return True
@ -182,8 +183,8 @@ class DbusManager(dbus.service.Object):
#name = fillename without directory #name = fillename without directory
name = name.replace('\\','/') name = name.replace('\\','/')
name = 'deluge_' + str(random.random()) + '_' + name.split('/')[-1] 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) filecontent = base64.b64decode(filecontent_b64)
f = open(filename,"wb") #no with statement, that's py 2.5+ f = open(filename,"wb") #no with statement, that's py 2.5+
f.write(filecontent) f.write(filecontent)
@ -192,11 +193,42 @@ class DbusManager(dbus.service.Object):
self._add_torrent(filename) self._add_torrent(filename)
return True 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 #internal
def _add_torrent(self, filename): def _add_torrent(self, filename):
#dbus types break pickle, again.....
filename = unicode(filename) 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, torrent_id = self.core.add_torrent(filename, target,
self.interface.config.get("use_compact_storage")) self.interface.config.get("use_compact_storage"))

View file

@ -31,67 +31,15 @@
# this exception statement from your version. If you delete this exception # this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here. # 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 import webserver_common as ws
from webserver_framework import * from webserver_framework import *
import webpy022 as web import webpy022 as web
from webpy022.http import seeother, url from webpy022.http import seeother, url
from webpy022.utils import Storage
from md5 import md5
import base64 import base64
from deluge.common import fsize
from operator import attrgetter from operator import attrgetter
import os
#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
#routing: #routing:
urls = ( urls = (
@ -107,15 +55,21 @@ urls = (
"/resume_all(.*)", "resume_all", "/resume_all(.*)", "resume_all",
"/refresh/set(.*)", "refresh_set", "/refresh/set(.*)", "refresh_set",
"/refresh/(.*)", "refresh", "/refresh/(.*)", "refresh",
"/config(.*)","config",
"/home(.*)", "home", "/home(.*)", "home",
"/about(.*)", "about", "/about(.*)", "about",
"/logout(.*)", "logout",
#default-pages #default-pages
"/", "login", "/", "home",
"", "login", "", "home",
#remote-api: #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 #/routing
#pages: #pages:
@ -133,15 +87,10 @@ class login:
start_session() start_session()
do_redirect() do_redirect()
elif vars.redir: elif vars.redir:
seeother(url('/login',error=1,redir=vars.redir)) seeother(url('/login',error=1, redir=vars.redir))
else: else:
seeother('/login?error=1') seeother('/login?error=1')
class home:
@check_session
def GET(self, name):
do_redirect()
class index: class index:
"page containing the torrent list." "page containing the torrent list."
@auto_refreshed @auto_refreshed
@ -150,7 +99,7 @@ class index:
vars = web.input(sort=None, order=None) vars = web.input(sort=None, order=None)
status_rows = [get_torrent_status(torrent_id) 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: #sorting:
if vars.sort: if vars.sort:
@ -164,21 +113,19 @@ class index:
return ws.render.index(status_rows) return ws.render.index(status_rows)
class torrent_info: class torrent_info:
"torrent details"
@auto_refreshed @auto_refreshed
@deluge_page @deluge_page
def GET(self, torrent_id): def GET(self, torrent_id):
return ws.render.torrent_info(get_torrent_status(torrent_id)) return ws.render.torrent_info(get_torrent_status(torrent_id))
class torrent_pause: class torrent_pause:
"start/stop a torrent"
@check_session @check_session
def POST(self, name): def POST(self, name):
vars = web.input(stop = None, start = None, redir = None) vars = web.input(stop = None, start = None, redir = None)
if vars.stop: if vars.stop:
ws.proxy.pause_torrent(vars.stop) ws.proxy.pause_torrent([vars.stop])
elif vars.start: elif vars.start:
ws.proxy.resume_torrent(vars.start) ws.proxy.resume_torrent([vars.start])
do_redirect() do_redirect()
@ -194,7 +141,7 @@ class torrent_add:
if vars.url and vars.torrent.filename: if vars.url and vars.torrent.filename:
error_page(_("Choose an url or a torrent, not both.")) error_page(_("Choose an url or a torrent, not both."))
if vars.url: if vars.url:
ws.proxy.add_torrent_url(vars.url) ws.proxy.add_torrent_url(vars.url )
do_redirect() do_redirect()
elif vars.torrent.filename: elif vars.torrent.filename:
data = vars.torrent.file.read() data = vars.torrent.file.read()
@ -227,8 +174,7 @@ class torrent_delete:
return ws.render.torrent_delete(get_torrent_status(torrent_id)) return ws.render.torrent_delete(get_torrent_status(torrent_id))
@check_session @check_session
def POST(self, name): def POST(self, torrent_id):
torrent_id = name
vars = web.input(data_also = None, torrent_also = None) vars = web.input(data_also = None, torrent_also = None)
data_also = bool(vars.data_also) data_also = bool(vars.data_also)
torrent_also = bool(vars.torrent_also) torrent_also = bool(vars.torrent_also)
@ -238,30 +184,26 @@ class torrent_delete:
class torrent_queue_up: class torrent_queue_up:
@check_session @check_session
def POST(self, name): def POST(self, torrent_id):
torrent_id = name
ws.proxy.queue_up(torrent_id) ws.proxy.queue_up(torrent_id)
do_redirect() do_redirect()
class torrent_queue_down: class torrent_queue_down:
@check_session @check_session
def POST(self, name): def POST(self, torrent_id):
torrent_id = name
ws.proxy.queue_down(torrent_id) ws.proxy.queue_down(torrent_id)
do_redirect() do_redirect()
class pause_all: class pause_all:
@check_session @check_session
def POST(self, name): def POST(self, name):
for torrent_id in ws.proxy.get_torrent_state(): ws.proxy.pause_torrent(ws.proxy.get_session_state())
ws.proxy.pause_torrent(torrent_id)
do_redirect() do_redirect()
class resume_all: class resume_all:
@check_session @check_session
def POST(self, name): def POST(self, name):
for torrent_id in ws.proxy.get_torrent_state(): ws.proxy.resume_torrent(ws.proxy.get_session_state())
ws.proxy.resume_torrent(torrent_id)
do_redirect() do_redirect()
class refresh: class refresh:
@ -287,13 +229,61 @@ class refresh_set:
else: else:
error_page(_('refresh must be > 0')) 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: class about:
@deluge_page_noauth @deluge_page_noauth
def GET(self, name): def GET(self, name):
return ws.render.about() 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(): def WebServer():
return create_webserver(urls, globals()) return create_webserver(urls, globals())
@ -307,4 +297,3 @@ def run():
if __name__ == "__main__": if __name__ == "__main__":
run() run()

View file

@ -1 +1 @@
87 112

View file

@ -1,3 +1,3 @@
#!/usr/bin/env python #!/usr/bin/env python
from deluge_webserver import * import deluge_webserver
web.run(urls, globals()) deluge_webserver.run()

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 799 B

View file

@ -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("<title>Directory listing for %s</title>\n" % displaypath)
f.write("<h2>Directory listing for %s</h2>\n" % displaypath)
f.write("<hr>\n<ul>\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('<li><a href="%s">%s</a>\n'
% (urllib.quote(linkname), cgi.escape(displayname)))
f.write("</ul>\n<hr>\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())

View file

@ -7,6 +7,7 @@ $:render.header(_('About'))
<li><a href="http://deluge-torrent.org">Deluge</a></li> <li><a href="http://deluge-torrent.org">Deluge</a></li>
<li><a href="http://forum.deluge-torrent.org/viewtopic.php?f=9&t=425"> <li><a href="http://forum.deluge-torrent.org/viewtopic.php?f=9&t=425">
WebUi forum Thread</a> WebUi forum Thread</a>
</li> </li>
<li><a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GPL v2 <li><a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GPL v2
</a></li> </a></li>
@ -18,6 +19,7 @@ $:render.header(_('About'))
<ul> <ul>
<li>Martijn Voncken</li> <li>Martijn Voncken</li>
</ul> </ul>
<h3>Template</h3> <h3>Template</h3>
<ul> <ul>
<li>Martijn Voncken</li> <li>Martijn Voncken</li>
@ -27,6 +29,7 @@ $:render.header(_('About'))
<ul> <ul>
<li>Zach Tibbitts</li> <li>Zach Tibbitts</li>
<li>Alon Zakai</li> <li>Alon Zakai</li>
<li>Alon Zakai</li> <li>Alon Zakai</li>
<li>Marcos Pinto</li> <li>Marcos Pinto</li>
<li>Andrew Resch</li> <li>Andrew Resch</li>
@ -36,4 +39,4 @@ $:render.header(_('About'))
*and all other authors/helpers/contributors I forgot to mention. *and all other authors/helpers/contributors I forgot to mention.
</div> </div>
$:render.footer() $:render.footer()

View file

@ -0,0 +1,10 @@
$def with (form)
$:render.header(_('Config'))
<div class="error">Not Implemented!</div>
<form method="POST">
$:form.render()
<input type="submit" value="$_('Apply')"/>
</form>
$:render.footer()

View file

@ -51,8 +51,10 @@ $for torrent in torrent_list:
$:render.part_button('GET', '/torrent/add', _('Add torrent'), 'tango/list-add.png') $: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', '/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', '/resume_all', _('Resume all'), 'tango/media-playback-start.png')
$:render.part_button('POST', '/logout', _('Logout'), 'tango/system-log-out.png')
</div> </div>
$:render.part_refresh() $:part_stats()
$:render.footer() $:render.footer()

View file

@ -2,21 +2,25 @@ $def with (method, url, title, image='')
<div class="deluge_button"> <div class="deluge_button">
<form method="$method" action="$url" class="deluge_button"> <form method="$method" action="$url" class="deluge_button">
<input type="hidden" name="redir" value="$self_url()"> <input type="hidden" name="redir" value="$self_url()">
<button type="submit" class="deluge_button">
$if (get_config('button_style') == 0): $if (get_config('button_style') == 0):
<button type="submit" class="deluge_button" alt="$title">
$title $title
$if image: $if image:
<image src="/static/images/$image" class="button" alt="$title"/> <image src="/static/images/$image" class="button" alt="$title"/>
</button>
$if (get_config('button_style') == 1): $if (get_config('button_style') == 1):
$if image: $if image:
<image src="/static/images/$image" class="button" alt="$title"/> <input type="image" image src="/static/images/$image" class="img_button" alt="$title"/>
$else: $else:
<button type="submit" class="deluge_button" alt="$title">
$title $title
</button>
$if (get_config('button_style') == 2): $if (get_config('button_style') == 2):
<button type="submit" class="deluge_button" alt="$title">
$title $title
</button>
</button>
</form> </form>
</div> </div>

View file

@ -0,0 +1,30 @@
$def with (stats)
<div class="panel" id='refresh_panel'>
$_('Auto refresh:')
$if getcookie('auto_refresh') == '1':
($getcookie('auto_refresh_secs')) $_('seconds') &nbsp;
$:render.part_button('GET', '/refresh/set', _('Set'), 'tango/preferences-system.png')
$:render.part_button('POST', '/refresh/off', _('Disable'), 'tango/process-stop.png')
$else:
$_('Off') &nbsp;
$:render.part_button('POST', '/refresh/on', _('Enable'), 'tango/view-refresh.png')
$#end
</div>
<div class="panel" id='refresh_panel'>
<a href='/config'>
$_('Down Speed') : $stats.download_rate ($stats.max_download)
$_('Up Speed') : $stats.upload_rate ($stats.max_upload)
</a>
(<a href='/about'>$_('About')</a>)
</div>

View file

@ -84,6 +84,7 @@ $:render.part_button('GET', '/torrent/delete/' + str(torrent.id), _('Remove'), '
<br> <br>
<!--
[<a onclick="javascript:toggle_dump()">$_('Debug:Data Dump')</a>] [<a onclick="javascript:toggle_dump()">$_('Debug:Data Dump')</a>]
<pre style="background-color:white;color:black;display:none" id="data_dump"> <pre style="background-color:white;color:black;display:none" id="data_dump">
@ -102,6 +103,8 @@ function toggle_dump(){
} }
} }
</script> </script>
-->
</div> </div>
@ -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_button('POST', '/torrent/queue/down/' + str(torrent.id), _('Queue Down'), 'tango/down.png')
</div> </div>
$:render.part_refresh() $:part_stats()
$:render.footer() $:render.footer()

View file

@ -0,0 +1,3 @@
</body>
</html>

View file

@ -0,0 +1,12 @@
$def with (title)
<html>
<head>
<title>Deluge(example) : $title</title>
<link rel="icon" href="/static/images/deluge_icon.gif" type="image/gif" />
<link rel="shortcut icon" href="/static/images/deluge_icon.gif" type="image/gif" />
</head>
<body>
<img src="/template/static/example.png">
<a href=/home>[HOME]</a>
<h1>$title</h1>

View file

@ -0,0 +1,42 @@
$def with (torrent_list)
$:render.header(_('Torrent list'))
<form action="/torrent/pause" method="POST">
<table class="torrent_list" border=1>
<tr>
$:(sort_head('calc_state_str', 'S'))
$:(sort_head('queue_pos', '#'))
$:(sort_head('name', _('Name')))
$:(sort_head('progress', _('Progress')))
</tr>
$#4-space indentation is mandatory for for-loops in templetor!
$for torrent in torrent_list:
<tr>
<td><input type="image"
src="/static/images/$(torrent.calc_state_str)16.png"
name="$torrent.action" value="$torrent.id">
</td>
<td>$torrent.queue_pos</td>
<td style="width:100px; overflow:hidden;white-space: nowrap">
<a href="/torrent/info/$torrent.id">$(crop(torrent.name, 40))</a></td>
<td class="progress_bar">
<div class="progress_bar_outer">
<div class="progress_bar" style="width:$(torrent.progress)%">
$torrent.message
</div>
</div>
</td>
</tr>
</table>
</form>
<div class="panel" bgcolor="5555AA">
$: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')
</div>
$:render.footer()

View file

@ -1,5 +1,5 @@
revision-id: mvoncken@gmail.com-20070930083408-sv8mo0mi1rbjnfvk revision-id: mvoncken@gmail.com-20070930083408-sv8mo0mi1rbjnfvk
date: 2007-10-23 15:10:08 +0200 date: 2007-10-23 15:10:08 +0200
build-date: 2007-10-23 15:34:50 +0200 build-date: 2007-10-23 15:34:50 +0200
revno: 87 revno: 112
branch-nick: WebUi branch-nick: WebUi

View file

@ -29,40 +29,96 @@
# this exception statement from your version. If you delete this exception # this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here. # 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 os
import deluge import deluge
from deluge.common import INSTALL_PREFIX
import random import random
import pickle import pickle
import sys
from webpy022 import template from webpy022 import template
random.seed() 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 :( try:
if not hasattr(deluge,'pref'): 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 import dbus
init_process()
bus = dbus.SessionBus() bus = dbus.SessionBus()
proxy = bus.get_object("org.deluge_torrent.dbusplugin" proxy = bus.get_object("org.deluge_torrent.dbusplugin"
, "/org/deluge_torrent/DelugeDbusPlugin") , "/org/deluge_torrent/DelugeDbusPlugin")
config = pickle.load(open(config_file)) globals()['proxy'] = proxy
render = template.render('templates/%s/' % config.get('template'),
cache=config.get('cache_templates'))
def init(): def init_gtk_05():
#appy possibly changed config-vars, only called in when runing inside gtk. #appy possibly changed config-vars, only called in when runing inside gtk.
path = os.path.dirname(__file__)
from dbus_interface import get_dbus_manager from dbus_interface import get_dbus_manager
globals()['proxy'] = get_dbus_manager() globals()['proxy'] = get_dbus_manager()
globals()['config'] = deluge.pref.Preferences(config_file, False) globals()['config'] = deluge.pref.Preferences(config_file, False)
globals()['render'] = template.render(os.path.join(path, 'templates/%s/' % globals()['render'] = subclassed_render(config.get('template'),
config.get('template')), cache=config.get('cache_templates')) 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() VERSION = open(os.path.join(os.path.dirname(__file__),'version')).read()
TORRENT_KEYS = ['distributed_copies', 'download_payload_rate', TORRENT_KEYS = ['distributed_copies', 'download_payload_rate',
@ -82,3 +138,30 @@ STATE_MESSAGES = (_("Queued"),
_("Finished"), _("Finished"),
_("Seeding"), _("Seeding"),
_("Allocating")) _("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 = []

View file

@ -45,15 +45,21 @@ import webpy022 as web
from webpy022.webapi import cookies, setcookie as w_setcookie from webpy022.webapi import cookies, setcookie as w_setcookie
from webpy022.http import seeother, url from webpy022.http import seeother, url
from webpy022 import template,changequery as self_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 traceback
import random import random
from operator import attrgetter from operator import attrgetter
import datetime
import pickle
from md5 import md5
from deluge import common from deluge import common
from webserver_common import REVNO, VERSION from webserver_common import REVNO, VERSION, COOKIE_DEFAULTS
import webserver_common as ws import webserver_common as ws
from debugerror import deluge_debugerror from debugerror import deluge_debugerror
#init: #init:
@ -65,14 +71,22 @@ def setcookie(key, val):
"""add 30 days expires header for persistent cookies""" """add 30 days expires header for persistent cookies"""
return w_setcookie(key, val , expires=2592000) return w_setcookie(key, val , expires=2592000)
SESSIONS = [] #dumb sessions. #really simple sessions, to bad i had to implement them myself.
def start_session(): def start_session():
session_id = str(random.random()) 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) setcookie("session_id", session_id)
if getcookie('auto_refresh_secs') == None: def end_session():
setcookie('auto_refresh_secs','10') 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(): def do_redirect():
"""for redirects after a POST""" """for redirects after a POST"""
@ -92,7 +106,6 @@ def error_page(error):
print ws.render.error(error) print ws.render.error(error)
def getcookie(key, default=None): def getcookie(key, default=None):
COOKIE_DEFAULTS = {'auto_refresh_secs':'10'}
key = str(key).strip() key = str(key).strip()
ck = cookies() ck = cookies()
val = ck.get(key, default) val = ck.get(key, default)
@ -120,9 +133,8 @@ def check_session(func):
""" """
def deco(self, name): def deco(self, name):
vars = web.input(redir_after_login=None) vars = web.input(redir_after_login=None)
ck = cookies() 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.. return func(self, name) #ok, continue..
elif vars.redir_after_login: elif vars.redir_after_login:
seeother(url("/login",redir=self_url())) seeother(url("/login",redir=self_url()))
@ -154,6 +166,77 @@ def remote(func):
print traceback.format_exc() print traceback.format_exc()
return deco 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: #template-defs:
def template_crop(text, end): def template_crop(text, end):
if len(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) 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): def get_config(var):
return ws.config.get(var) return ws.config.get(var)
template.Template.globals.update({ template.Template.globals.update({
'sort_head': template_sort_head, 'sort_head': template_sort_head,
'part_stats':template_part_stats,
'crop': template_crop, 'crop': template_crop,
'_': _ , #gettext/translations '_': _ , #gettext/translations
'str': str, #because % in templetor is broken. 'str': str, #because % in templetor is broken.
@ -198,145 +284,20 @@ template.Template.globals.update({
}) })
#/template-defs #/template-defs
def create_webserver(urls, methods):
from webpy022.request import webpyfunc
from webpy022 import webapi
from gtk_cherrypy_wsgiserver import CherryPyWSGIServer
func = webapi.wsgifunc(webpyfunc(urls, methods, False))
#------------------------------------------------------------------------------ server_address=("0.0.0.0", int(ws.config.get('port')))
#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)
server = CherryPyWSGIServer(server_address, func, server_name="localhost") server = CherryPyWSGIServer(server_address, func, server_name="localhost")
print "http://%s:%d/" % server_address
print "(created) http://%s:%d/" % server_address
return server return server
#------ #------
__all__ = ['deluge_page_noauth', 'deluge_page', 'remote', __all__ = ['deluge_page_noauth', 'deluge_page', 'remote',
'auto_refreshed', 'check_session', 'auto_refreshed', 'check_session',
'do_redirect', 'error_page','start_session','getcookie' 'do_redirect', 'error_page','start_session','getcookie'
,'create_webserver','setcookie'] ,'setcookie','create_webserver','end_session',
'get_torrent_status', 'check_pwd','static_handler']

View file

@ -54,4 +54,7 @@ plugins/WebSeed/__init__.py
plugins/WebSeed/webseed.glade plugins/WebSeed/webseed.glade
plugins/Scheduler/__init__.py plugins/Scheduler/__init__.py
plugins/Scheduler/plugin.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

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -88,7 +88,7 @@ msgstr ""
msgid "<b>Torrent Info</b>" msgid "<b>Torrent Info</b>"
msgstr "" msgstr ""
#: glade/delugegtk.glade:750 #: glade/delugegtk.glade:750 plugins/WebUi/scripts/template_strings.py:8
msgid "Details" msgid "Details"
msgstr "" msgstr ""
@ -149,11 +149,13 @@ msgid "Status"
msgstr "" msgstr ""
#: glade/delugegtk.glade:965 src/interface.py:602 #: glade/delugegtk.glade:965 src/interface.py:602
#: plugins/WebUi/scripts/template_strings.py:19
msgid "Seeders" msgid "Seeders"
msgstr "" msgstr ""
#: glade/delugegtk.glade:974 src/interface.py:605 #: glade/delugegtk.glade:974 src/interface.py:605
#: plugins/TorrentPeers/__init__.py:72 #: plugins/TorrentPeers/__init__.py:72
#: plugins/WebUi/scripts/template_strings.py:15
msgid "Peers" msgid "Peers"
msgstr "" msgstr ""
@ -171,11 +173,11 @@ msgstr ""
msgid "Time Remaining" msgid "Time Remaining"
msgstr "" msgstr ""
#: glade/delugegtk.glade:1010 #: glade/delugegtk.glade:1010 plugins/WebUi/scripts/template_strings.py:4
msgid "Availability" msgid "Availability"
msgstr "" msgstr ""
#: glade/delugegtk.glade:1019 #: glade/delugegtk.glade:1019 plugins/WebUi/scripts/template_strings.py:21
msgid "Share Ratio" msgid "Share Ratio"
msgstr "" msgstr ""
@ -211,7 +213,7 @@ msgstr ""
msgid "Remove Torrent" msgid "Remove Torrent"
msgstr "" msgstr ""
#: glade/delugegtk.glade:1157 #: glade/delugegtk.glade:1157 plugins/WebUi/scripts/template_strings.py:18
msgid "Remove" msgid "Remove"
msgstr "" msgstr ""
@ -278,7 +280,7 @@ msgstr ""
msgid "Delete downloaded files" msgid "Delete downloaded files"
msgstr "" msgstr ""
#: glade/dgtkpopups.glade:88 #: glade/dgtkpopups.glade:88 plugins/WebUi/scripts/template_strings.py:6
msgid "Delete .torrent file" msgid "Delete .torrent file"
msgstr "" msgstr ""
@ -294,7 +296,7 @@ msgstr ""
msgid "Clear Finished" msgid "Clear Finished"
msgstr "" msgstr ""
#: glade/dgtkpopups.glade:241 #: glade/dgtkpopups.glade:241 plugins/WebUi/scripts/template_strings.py:22
msgid "Speed" msgid "Speed"
msgstr "" msgstr ""
@ -542,6 +544,7 @@ msgid "<b>Seeding</b>"
msgstr "" msgstr ""
#: glade/preferences_dialog.glade:964 src/core.py:91 #: glade/preferences_dialog.glade:964 src/core.py:91
#: plugins/WebUi/webserver_common.py:139
msgid "Seeding" msgid "Seeding"
msgstr "" msgstr ""
@ -646,6 +649,7 @@ msgstr ""
#: glade/preferences_dialog.glade:1478 glade/preferences_dialog.glade:1672 #: glade/preferences_dialog.glade:1478 glade/preferences_dialog.glade:1672
#: glade/preferences_dialog.glade:1866 glade/preferences_dialog.glade:2060 #: glade/preferences_dialog.glade:1866 glade/preferences_dialog.glade:2060
#: plugins/WebUi/scripts/template_strings.py:13
msgid "Password" msgid "Password"
msgstr "" msgstr ""
@ -1004,7 +1008,7 @@ msgstr ""
msgid "Name" msgid "Name"
msgstr "" msgstr ""
#: src/interface.py:614 #: src/interface.py:614 plugins/WebUi/scripts/template_strings.py:10
msgid "ETA" msgid "ETA"
msgstr "" msgstr ""
@ -1088,31 +1092,32 @@ msgstr ""
msgid "Are you sure that you want to remove all seeding torrents?" msgid "Are you sure that you want to remove all seeding torrents?"
msgstr "" msgstr ""
#: src/core.py:85 #: src/core.py:85 plugins/WebUi/webserver_common.py:133
msgid "Queued" msgid "Queued"
msgstr "" msgstr ""
#: src/core.py:86 #: src/core.py:86 plugins/WebUi/webserver_common.py:134
msgid "Checking" msgid "Checking"
msgstr "" msgstr ""
#: src/core.py:87 #: src/core.py:87 plugins/WebUi/webserver_common.py:135
msgid "Connecting" msgid "Connecting"
msgstr "" msgstr ""
#: src/core.py:88 #: src/core.py:88 plugins/WebUi/webserver_common.py:136
msgid "Downloading Metadata" msgid "Downloading Metadata"
msgstr "" msgstr ""
#: src/core.py:89 plugins/BlocklistImport/ui.py:117 #: src/core.py:89 plugins/BlocklistImport/ui.py:117
#: plugins/WebUi/webserver_common.py:137
msgid "Downloading" msgid "Downloading"
msgstr "" msgstr ""
#: src/core.py:90 #: src/core.py:90 plugins/WebUi/webserver_common.py:138
msgid "Finished" msgid "Finished"
msgstr "" msgstr ""
#: src/core.py:92 #: src/core.py:92 plugins/WebUi/webserver_common.py:140
msgid "Allocating" msgid "Allocating"
msgstr "" msgstr ""
@ -1390,66 +1395,66 @@ msgstr ""
msgid "Torrent Creator" msgid "Torrent Creator"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:103 #: plugins/TorrentCreator/torrentcreator.glade:102
msgid "This torrent will be made from a single file" msgid "This torrent will be made from a single file"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:104 #: plugins/TorrentCreator/torrentcreator.glade:103
msgid "File:" msgid "File:"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:120 #: plugins/TorrentCreator/torrentcreator.glade:119
msgid "This torrent will be made from a directory" msgid "This torrent will be made from a directory"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:121 #: plugins/TorrentCreator/torrentcreator.glade:120
msgid "Folder:" msgid "Folder:"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:138 #: plugins/TorrentCreator/torrentcreator.glade:137
msgid "<b>Source</b>" msgid "<b>Source</b>"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:184 #: plugins/TorrentCreator/torrentcreator.glade:182
msgid "Save Torrent File As:" msgid "Save Torrent File As:"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:237 #: plugins/TorrentCreator/torrentcreator.glade:235
msgid "Load this torrent into Deluge for seeding" msgid "Load this torrent into Deluge for seeding"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:238 #: plugins/TorrentCreator/torrentcreator.glade:236
msgid "Add new torrent to queue" msgid "Add new torrent to queue"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:257 #: plugins/TorrentCreator/torrentcreator.glade:255
msgid "<b>Torrent File</b>" msgid "<b>Torrent File</b>"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:305 #: plugins/TorrentCreator/torrentcreator.glade:302
msgid "<b>Trackers</b>" msgid "<b>Trackers</b>"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:352 #: plugins/TorrentCreator/torrentcreator.glade:348
msgid "<b>Comments</b>" msgid "<b>Comments</b>"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:389 #: plugins/TorrentCreator/torrentcreator.glade:384
msgid "<b>Author</b>" msgid "<b>Author</b>"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:425 #: plugins/TorrentCreator/torrentcreator.glade:423
msgid "Set Private Flag" msgid "Set Private Flag"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:441 #: plugins/TorrentCreator/torrentcreator.glade:436
#: plugins/TorrentCreator/torrentcreator.glade:461 #: plugins/TorrentCreator/torrentcreator.glade:457
msgid "" msgid ""
"The smaller the piece sizes, the more efficient the transfers will be, but " "The smaller the piece sizes, the more efficient the transfers will be, but "
"the actual \".torrent\" file will be larger" "the actual \".torrent\" file will be larger"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:442 #: plugins/TorrentCreator/torrentcreator.glade:437
msgid "" msgid ""
"32 KiB\n" "32 KiB\n"
"64 KiB\n" "64 KiB\n"
@ -1457,13 +1462,14 @@ msgid ""
"256 KiB\n" "256 KiB\n"
"512 KiB\n" "512 KiB\n"
"1024 KiB\n" "1024 KiB\n"
"2048 KiB\n"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:463 #: plugins/TorrentCreator/torrentcreator.glade:459
msgid "Piece Size:" msgid "Piece Size:"
msgstr "" msgstr ""
#: plugins/TorrentCreator/torrentcreator.glade:477 #: plugins/TorrentCreator/torrentcreator.glade:473
msgid "<b>Advanced</b>" msgid "<b>Advanced</b>"
msgstr "" msgstr ""
@ -2102,3 +2108,171 @@ msgid ""
"When set to -1 (unlimited), the global limits in Deluge's preferences will " "When set to -1 (unlimited), the global limits in Deluge's preferences will "
"be obeyed." "be obeyed."
msgstr "" 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 ""