sync webui plugin with rev48
This commit is contained in:
parent
9a050065a9
commit
53e65e9554
|
@ -33,18 +33,24 @@
|
|||
plugin_name = "Web User interface"
|
||||
plugin_author = "Martijn Voncken"
|
||||
plugin_version = "rev."
|
||||
plugin_description = """A Web based User Interface (and dbus-ipc)
|
||||
beta test version, disclaimer, etc..
|
||||
"""
|
||||
plugin_description = "A Web based User Interface\n"
|
||||
|
||||
import deluge.common, deluge.pref
|
||||
import deluge.common
|
||||
import deluge.pref
|
||||
from deluge.dialogs import show_popup_warning
|
||||
from dbus_interface import DbusManager
|
||||
|
||||
import gtk
|
||||
import os
|
||||
|
||||
from subprocess import Popen
|
||||
from md5 import md5
|
||||
import random
|
||||
random.seed()
|
||||
|
||||
plugin_version += open(os.path.join(os.path.dirname(__file__),'revno')).read()
|
||||
plugin_description += (
|
||||
open(os.path.join(os.path.dirname(__file__),'version')).read())
|
||||
|
||||
|
||||
def deluge_init(deluge_path):
|
||||
global path
|
||||
|
@ -72,19 +78,24 @@ class plugin_WebUi:
|
|||
if not self.config.get('port'): #ugly way to detect new config file.
|
||||
#set default values:
|
||||
self.config.set("port", 8112)
|
||||
self.config.set("user", "deluge")
|
||||
self.config.set("pwd", "deluge")
|
||||
#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)
|
||||
self.config.set("template", "deluge")
|
||||
self.config.save(self.config_file)
|
||||
|
||||
if not self.config.get("pwd_salt"):
|
||||
self.config.set("pwd_salt", "invalid")
|
||||
self.config.set("pwd_md5", "invalid")
|
||||
|
||||
|
||||
self.dbusManager = DbusManager(deluge_core, deluge_interface
|
||||
, self.config, self.config_file)
|
||||
|
||||
print dir(self.dbusManager)
|
||||
self.start_server()
|
||||
|
||||
def unload(self):
|
||||
|
@ -135,9 +146,11 @@ class ConfigDialog(gtk.Dialog):
|
|||
if os.path.isdir(os.path.join(template_path, dirname))]
|
||||
|
||||
self.port = self.add_widget(_('Port Number'), gtk.SpinButton())
|
||||
self.user = self.add_widget(_('User'), gtk.Entry())
|
||||
self.pwd = self.add_widget(_('Password'), gtk.Entry())
|
||||
self.pwd1 = self.add_widget(_('New Password'), gtk.Entry())
|
||||
self.pwd2 = self.add_widget(_('New Password(confirm)'), gtk.Entry())
|
||||
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'),
|
||||
|
@ -147,16 +160,24 @@ class ConfigDialog(gtk.Dialog):
|
|||
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)
|
||||
self.pwd2.set_visibility(False)
|
||||
|
||||
for item in self.templates:
|
||||
self.template.append_text(item)
|
||||
self.button_style
|
||||
if not self.config.get("template") in self.templates:
|
||||
self.config.set("template","deluge")
|
||||
|
||||
self.user.set_text(self.config.get("user"))
|
||||
self.pwd.set_text(self.config.get("pwd"))
|
||||
for item in [_('Text and image'), _('Image Only'), _('Text Only')]:
|
||||
self.button_style.append_text(item)
|
||||
if not self.config.get("button_style"):
|
||||
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.torrent_dir.set_filename(self.config.get("torrent_dir"))
|
||||
self.download_dir.set_filename(self.config.get("download_dir"))
|
||||
self.vbox.pack_start(self.vb, True, True, 0)
|
||||
|
@ -177,11 +198,21 @@ class ConfigDialog(gtk.Dialog):
|
|||
self.add_buttons(dgtk.STOCK_CLOSE, dgtk.RESPONSE_CLOSE)
|
||||
|
||||
def save_config(self):
|
||||
print 'save config'
|
||||
self.config.set("user", self.user.get_text())
|
||||
self.config.set("pwd", self.pwd.get_text())
|
||||
if self.pwd1.get_text() > '':
|
||||
if self.pwd1.get_text() <> self.pwd2.get_text():
|
||||
show_popup_warning(self,_("Confirmed Password <> New Password\n"
|
||||
+ "Password was not changed"))
|
||||
else:
|
||||
salt = str(random.getrandbits(500))
|
||||
m = md5()
|
||||
m.update(salt)
|
||||
m.update(unicode(self.pwd1.get_text()))
|
||||
self.config.set("pwd_salt", salt)
|
||||
self.config.set("pwd_md5", m.digest())
|
||||
|
||||
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.save(self.plugin.config_file)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
curl -F torrent=@./test1.torrent -F pwd=deluge http://localhost:8112/remote/torrent/add
|
|
@ -39,6 +39,7 @@ import dbus
|
|||
import deluge.common as common
|
||||
from dbus_pythonize import pythonize
|
||||
import base64
|
||||
from md5 import md5
|
||||
import random
|
||||
random.seed()
|
||||
|
||||
|
@ -182,7 +183,7 @@ class DbusManager(dbus.service.Object):
|
|||
not in 0.6
|
||||
"""
|
||||
retval = self.config.get(str(key))
|
||||
print 'get webui config:', str(key), retval
|
||||
#print 'get webui config:', str(key), retval
|
||||
if retval == None:
|
||||
retval = False #dbus does not accept None :(
|
||||
|
||||
|
@ -195,10 +196,18 @@ class DbusManager(dbus.service.Object):
|
|||
return data from wevbui config.
|
||||
not in 0.6
|
||||
"""
|
||||
print 'set webui config:', str(key), pythonize(value)
|
||||
#print 'set webui config:', str(key), pythonize(value)
|
||||
self.config.set(str(key), pythonize(value))
|
||||
self.config.save(self.config_file)
|
||||
|
||||
@dbus.service.method(dbus_interface=dbus_interface,
|
||||
in_signature="s",out_signature="b")
|
||||
def check_pwd(self, pwd):
|
||||
m = md5()
|
||||
m.update(self.config.get('pwd_salt'))
|
||||
m.update(pwd)
|
||||
return (m.digest() == self.config.get('pwd_md5'))
|
||||
|
||||
#internal
|
||||
def _add_torrent(self, filename):
|
||||
#dbus types break pickle, again.....
|
||||
|
|
|
@ -50,7 +50,7 @@ from webpy022 import template
|
|||
|
||||
import dbus
|
||||
|
||||
import gettext, os, platform, locale
|
||||
import gettext, os, platform, locale, traceback
|
||||
import random
|
||||
import base64
|
||||
from operator import attrgetter
|
||||
|
@ -105,7 +105,7 @@ def deluge_page_noauth(func):
|
|||
web.header("Content-Type", "text/html; charset=utf-8")
|
||||
web.header("Cache-Control", "no-cache, must-revalidate")
|
||||
res = func(self, name)
|
||||
print res
|
||||
print unicode(res)
|
||||
return deco
|
||||
|
||||
def check_session(func):
|
||||
|
@ -139,6 +139,17 @@ def error_page(error):
|
|||
web.header("Cache-Control", "no-cache, must-revalidate")
|
||||
print render.error(error)
|
||||
|
||||
def remote(func):
|
||||
"decorator for remote api's"
|
||||
def deco(self, name):
|
||||
try:
|
||||
print func(self, name)
|
||||
except Exception, e:
|
||||
print 'error:' + e.message
|
||||
print '-'*20
|
||||
print traceback.format_exc()
|
||||
return deco
|
||||
|
||||
#/framework
|
||||
|
||||
#utils:
|
||||
|
@ -191,7 +202,7 @@ def template_crop(text, end):
|
|||
return text[0:end - 3] + '...'
|
||||
return text
|
||||
|
||||
def sort_head(id,name):
|
||||
def template_sort_head(id,name):
|
||||
#got tired of doing these complex things inside templetor..
|
||||
vars = web.input(sort=None, order=None)
|
||||
active_up = False
|
||||
|
@ -210,18 +221,23 @@ def sort_head(id,name):
|
|||
|
||||
render = template.render('templates/%s/' % proxy.get_webui_config('template'))
|
||||
|
||||
template.Template.globals['crop'] = template_crop
|
||||
template.Template.globals['fspeed'] = common.fspeed
|
||||
template.Template.globals['fsize'] = common.fsize
|
||||
template.Template.globals['sorted'] = sorted
|
||||
template.Template.globals['_'] = _ #gettext/translations
|
||||
template.Template.globals['deluge_web_version'] = ('rev.'
|
||||
+ open(os.path.join(os.path.dirname(__file__),'revno')).read())
|
||||
template.Template.globals['render'] = render #for easy resuse of templates
|
||||
template.Template.globals['sort_head'] = sort_head
|
||||
template.Template.globals['get_config'] = proxy.get_webui_config
|
||||
template.Template.globals['self_url'] = web.changequery
|
||||
|
||||
template.Template.globals.update({
|
||||
'sort_head': template_sort_head,
|
||||
'crop': template_crop,
|
||||
'_': _ , #gettext/translations
|
||||
'str': str, #because % in templetor is broken.
|
||||
'sorted': sorted,
|
||||
'get_config': proxy.get_webui_config,
|
||||
'self_url': web.changequery,
|
||||
'fspeed': common.fspeed,
|
||||
'fsize': common.fsize,
|
||||
'render': render, #for easy resuse of templates
|
||||
'button_style': (proxy.get_webui_config('button_style')),
|
||||
'rev': ('rev.' +
|
||||
open(os.path.join(os.path.dirname(__file__),'revno')).read()),
|
||||
'version': (
|
||||
open(os.path.join(os.path.dirname(__file__),'version')).read())
|
||||
})
|
||||
#/template-defs
|
||||
|
||||
#routing:
|
||||
|
@ -237,9 +253,12 @@ urls = (
|
|||
"/refresh/set(.*)", "refresh_set",
|
||||
"/refresh/(.*)", "refresh",
|
||||
"/home(.*)", "home",
|
||||
"/about(.*)", "about",
|
||||
#default-pages
|
||||
"/", "login",
|
||||
"", "login"
|
||||
"", "login",
|
||||
#remote-api:
|
||||
"/remote/torrent/add(.*)", "remote_torrent_add"
|
||||
)
|
||||
|
||||
#/routing
|
||||
|
@ -248,20 +267,20 @@ urls = (
|
|||
class login:
|
||||
@deluge_page_noauth
|
||||
def GET(self, name):
|
||||
return render.login()
|
||||
vars = web.input(error = None)
|
||||
return render.login(vars.error)
|
||||
|
||||
def POST(self, name):
|
||||
vars = web.input(var = None, pwd = None)
|
||||
vars = web.input(pwd = None)
|
||||
|
||||
if (vars.user == proxy.get_webui_config('user')
|
||||
and vars.pwd == proxy.get_webui_config('pwd')):
|
||||
if proxy.check_pwd(vars.pwd):
|
||||
#start new session
|
||||
session_id = str(random.random())
|
||||
SESSIONS[session_id] = {"user":vars.user}
|
||||
SESSIONS[session_id] = {"not":"used"}
|
||||
setcookie("session_id", session_id)
|
||||
do_redirect()
|
||||
else:
|
||||
error_page(_("Username or Password is invalid."))
|
||||
seeother('/login?error=1')
|
||||
|
||||
class home:
|
||||
@check_session
|
||||
|
@ -332,6 +351,23 @@ class torrent_add:
|
|||
else:
|
||||
error_page(_("no data."))
|
||||
|
||||
class remote_torrent_add:
|
||||
"""
|
||||
For use in remote scripts etc.
|
||||
POST user and file
|
||||
Example : curl -F torrent=@./test1.torrent -F pwd=deluge http://localhost:8112/remote/torrent/add"
|
||||
"""
|
||||
@remote
|
||||
def POST(self, name):
|
||||
vars = web.input(pwd = None, torrent = {})
|
||||
|
||||
if not proxy.check_pwd(vars.pwd):
|
||||
return 'error:wrong password'
|
||||
|
||||
data_b64 = base64.b64encode(vars.torrent.file.read())
|
||||
proxy.add_torrent_filecontent(vars.torrent.filename,data_b64)
|
||||
return 'ok'
|
||||
|
||||
class torrent_delete:
|
||||
@deluge_page
|
||||
def GET(self, torrent_id):
|
||||
|
@ -383,6 +419,12 @@ class refresh_set:
|
|||
else:
|
||||
error_page(_('refresh must be > 0'))
|
||||
|
||||
class about:
|
||||
@deluge_page_noauth
|
||||
def GET(self, name):
|
||||
return render.about()
|
||||
|
||||
|
||||
#/pages
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -1 +1 @@
|
|||
40
|
||||
48
|
||||
|
|
|
@ -31,6 +31,15 @@ button.deluge_button {
|
|||
color: #000;
|
||||
}
|
||||
|
||||
div.error {
|
||||
background-color:#FFFFFF;
|
||||
color:#AA0000;
|
||||
font-weight:bold;
|
||||
-moz-border-radius:10px;
|
||||
width:200px;
|
||||
margin-bottom:20px;
|
||||
padding:10px;
|
||||
|
||||
}
|
||||
|
||||
/* Hides from IE-mac \*/
* html .clearfix {height: 1%;}
.clearfix {display: block;}
/* End hide from IE-mac */
|
|
@ -0,0 +1,39 @@
|
|||
$:render.header(_('About'))
|
||||
<div class="panel" style="text-align:left">
|
||||
<h2>Version</h2>
|
||||
<pre>$version </pre>
|
||||
<h2>Links</h2>
|
||||
<ul>
|
||||
<li><a href="http://deluge-torrent.org">Deluge</a></li>
|
||||
<li><a href="http://forum.deluge-torrent.org/viewtopic.php?f=9&t=425">
|
||||
WebUi forum Thread</a>
|
||||
</li>
|
||||
<li><a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GPL v2
|
||||
</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Authors</h2>
|
||||
<ul>
|
||||
<h3>WebUi</h3>
|
||||
<ul>
|
||||
<li>Martijn Voncken</li>
|
||||
</ul>
|
||||
<h3>Template</h3>
|
||||
<ul>
|
||||
<li>Martijn Voncken</li>
|
||||
<li>somedude</li>
|
||||
</ul>
|
||||
<h3>Deluge</h3>
|
||||
<ul>
|
||||
<li>Zach Tibbitts</li>
|
||||
<li>Alon Zakai</li>
|
||||
<li>Alon Zakai</li>
|
||||
<li>Marcos Pinto</li>
|
||||
<li>Andrew Resch</li>
|
||||
<li>Alex Dedul</li>
|
||||
</ul>
|
||||
</ul>
|
||||
*and all other authors/helpers/contributors I forgot to mention.
|
||||
</div>
|
||||
|
||||
$:render.footer()
|
|
@ -1,6 +1,6 @@
|
|||
$def with (error_msg)
|
||||
$:header(_('Error'))
|
||||
$:render.header(_('Error'))
|
||||
<pre class="error">
|
||||
$error_msg
|
||||
</pre>
|
||||
$:footer()
|
||||
$:render.footer()
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
$def with (title)
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>Deluge:$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" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/simple_site_style.css" />
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="page">
|
||||
|
||||
|
|
|
@ -54,5 +54,4 @@ $:render.part_button('POST', '/resume_all', _('Resume all'), 'tango/media-playba
|
|||
|
||||
$:render.part_refresh()
|
||||
|
||||
|
||||
$:render.footer()
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
$def with (error)
|
||||
$:render.header(_('Login'))
|
||||
<div class="panel">
|
||||
$if error > 0:
|
||||
<div class="error">$_("Password is invalid,try again")</div>
|
||||
|
||||
<form method="POST" id="loginform" action='/login'>
|
||||
<div id="loginpanel">
|
||||
<div class="form_row">
|
||||
<span class="form_label">$_('User')</span>
|
||||
<input type="text" name="user" id="user" class="form_input">
|
||||
</div>
|
||||
<div class="form_row">
|
||||
<span class="form_label">$_('Pass')</span>
|
||||
<span class="form_label">$_('Password')</span>
|
||||
<input type="password" name="pwd" id="pwd" class="form_input">
|
||||
</div>
|
||||
<div class="form_row">
|
||||
|
@ -15,6 +15,9 @@ $:render.header(_('Login'))
|
|||
<input type="submit" name="submit"
|
||||
id="submit" value="Submit" class="form_input">
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<a href="/about">$_('About')</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -3,11 +3,20 @@ $def with (method, url, title, image='')
|
|||
<form method="$method" action="$url" class="deluge_button">
|
||||
<button type="submit" class="deluge_button">
|
||||
<input type="hidden" name="redir" value="$self_url()">
|
||||
$if image:
|
||||
<image src="/static/images/$image" class="button"/>
|
||||
$else:
|
||||
<!--no image-->
|
||||
$if (button_style == 0):
|
||||
$title
|
||||
$if image:
|
||||
<image src="/static/images/$image" class="button" alt="$title"/>
|
||||
|
||||
$if (button_style == 1):
|
||||
$if image:
|
||||
<image src="/static/images/$image" class="button" alt="$title"/>
|
||||
$else:
|
||||
$title
|
||||
|
||||
$if (button_style == 2):
|
||||
$title
|
||||
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
|
@ -1,5 +1,5 @@
|
|||
<div id='refresh_panel'>
|
||||
<div class="panel" >
|
||||
<div id='refresh'>
|
||||
$_('Auto refresh:')
|
||||
$if get_config('auto_refresh'):
|
||||
($(get_config('refresh')) $_('seconds'))
|
||||
|
|
|
@ -3,7 +3,7 @@ $:render.header(_('Set Timeout'))
|
|||
<form action="/refresh/set" method="POST">
|
||||
$_('Refresh page every:')
|
||||
<input type="text" name="refresh" value="$get_config('refresh')" size="3">
|
||||
$_('Seconds')
|
||||
$_('seconds')
|
||||
<input type="submit" value="$_('Set')">
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -80,17 +80,7 @@ class="deluge_button">
|
|||
name="$torrent.action" value="$torrent.id">
|
||||
</form>
|
||||
|
||||
<div class="deluge_button">
|
||||
<form method="GET" action="/torrent/delete/$torrent.id" class="deluge_button">
|
||||
|
||||
<button type="submit" class="deluge_button">
|
||||
<image src="/static/images/tango/user-trash.png" /> $_('Delete')
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
$:render.part_button('GET', '/torrent/delete/' + str(torrent.id), _('Remove'), 'tango/user-trash.png')
|
||||
|
||||
<br>
|
||||
[<a onclick="javascript:toggle_dump()">$_('Debug:Data Dump')</a>]
|
||||
|
|
|
@ -10,16 +10,21 @@ Or use scite and my config: http://mvoncken.sohosted.com/deluge/SciTEUser.proper
|
|||
template language: http://webpy.org/templetor
|
||||
|
||||
Exposed methods and variables (c&p from deluge_webserver):
|
||||
|
||||
template.Template.globals['crop'] = template_crop
|
||||
template.Template.globals['fspeed'] = common.fspeed
|
||||
template.Template.globals['fsize'] = common.fsize
|
||||
template.Template.globals['sorted'] = sorted
|
||||
template.Template.globals['_'] = _ #gettext/translations
|
||||
template.Template.globals['deluge_web_version'] = '0.3alfa'
|
||||
template.Template.globals['render'] = render #for easy resuse of templates
|
||||
template.Template.globals['sort_head'] = sort_head
|
||||
template.Template.globals['get_config'] = proxy.get_webui_config
|
||||
'sort_head': template_sort_head,
|
||||
'crop': template_crop,
|
||||
'_': _ , #gettext/translations
|
||||
'str': str, #because % in templetor is broken.
|
||||
'sorted': sorted,
|
||||
'get_config': proxy.get_webui_config,
|
||||
'self_url': web.changequery,
|
||||
'fspeed': common.fspeed,
|
||||
'fsize': common.fsize,
|
||||
'render': render, #for easy resuse of templates
|
||||
'button_style': (proxy.get_webui_config('button_style')),
|
||||
'rev': ('rev.' +
|
||||
open(os.path.join(os.path.dirname(__file__),'revno')).read()),
|
||||
'version': (
|
||||
open(os.path.join(os.path.dirname(__file__),'version')).read())
|
||||
|
||||
I will update this file if there is interest in making templates.
|
||||
|
||||
|
|
|
@ -1,5 +1 @@
|
|||
revision-id: mvoncken@gmail.com-20070923193628-omqar5yaxatdmfu0
|
||||
date: 2007-09-23 21:36:28 +0200
|
||||
build-date: 2007-09-23 21:54:09 +0200
|
||||
revno: 30
|
||||
branch-nick: WebUi
|
||||
48
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
Commented out some code to enable a relative redirect.
|
||||
1:Commented out some code to enable a relative redirect.
|
||||
This is not according to HTTP/1.1 Spec
|
||||
But many deluge users will want to route the webui through firewalls/routers or use apache redirects.
|
||||
|
||||
2:Disabled logging in the builtin http-server.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -200,6 +200,9 @@ def runsimple(func, server_address=("0.0.0.0", 8080)):
|
|||
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', '-')
|
||||
|
|
Loading…
Reference in New Issue