mirror of
https://git.deluge-torrent.org/deluge
synced 2025-08-02 22:48:40 +00:00
webui sync r168
This commit is contained in:
parent
93d0ab797b
commit
b803d39d63
33 changed files with 204 additions and 44 deletions
|
@ -97,7 +97,7 @@ class plugin_WebUi(object):
|
||||||
if status[0] == 0:
|
if status[0] == 0:
|
||||||
os.kill(int(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 = os.path.join(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)
|
||||||
try:
|
try:
|
||||||
self.config.load()
|
self.config.load()
|
||||||
|
@ -162,7 +162,7 @@ class plugin_WebUi(object):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print 'Start Webui(in process)..'
|
print 'Start Webui(in process)..'
|
||||||
server_bin = os.path.join(os.path.dirname(__file__), 'run_webserver')
|
server_bin = os.path.dirname(__file__) + '/run_webserver'
|
||||||
self.proc = Popen((server_bin,'env=0.5'))
|
self.proc = Popen((server_bin,'env=0.5'))
|
||||||
|
|
||||||
def kill_server(self):
|
def kill_server(self):
|
||||||
|
|
|
@ -11,9 +11,9 @@ http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
|
||||||
__all__ = ["debugerror", "djangoerror"]
|
__all__ = ["debugerror", "djangoerror"]
|
||||||
|
|
||||||
import sys, urlparse, pprint
|
import sys, urlparse, pprint
|
||||||
from webpy022.net import websafe
|
from lib.webpy022.net import websafe
|
||||||
from webpy022.template import Template
|
from lib.webpy022.template import Template
|
||||||
import webpy022.webapi as web
|
import lib.webpy022.webapi as web
|
||||||
import webserver_common as ws
|
import webserver_common as ws
|
||||||
from traceback import format_tb
|
from traceback import format_tb
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,15 @@
|
||||||
import webserver_common as ws
|
import webserver_common as ws
|
||||||
from webserver_framework import *
|
from webserver_framework import *
|
||||||
|
|
||||||
import webpy022 as web
|
import lib.webpy022 as web
|
||||||
from webpy022.http import seeother, url
|
from lib.webpy022.http import seeother, url
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from json_api import json_api
|
||||||
|
|
||||||
#routing:
|
#routing:
|
||||||
urls = (
|
urls = (
|
||||||
"/login", "login",
|
"/login", "login",
|
||||||
|
@ -64,6 +66,7 @@ urls = (
|
||||||
"/logout", "logout",
|
"/logout", "logout",
|
||||||
#remote-api:
|
#remote-api:
|
||||||
"/remote/torrent/add(.*)", "remote_torrent_add",
|
"/remote/torrent/add(.*)", "remote_torrent_add",
|
||||||
|
"/json/(.*)","json_api",
|
||||||
#static:
|
#static:
|
||||||
"/static/(.*)", "static",
|
"/static/(.*)", "static",
|
||||||
"/template/static/(.*)", "template_static",
|
"/template/static/(.*)", "template_static",
|
||||||
|
|
132
plugins/WebUi/json_api.py
Normal file
132
plugins/WebUi/json_api.py
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# webserver_framework.py
|
||||||
|
#
|
||||||
|
# Copyright (C) Martijn Voncken 2007 <mvoncken@gmail.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, write to:
|
||||||
|
# The Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
# In addition, as a special exception, the copyright holders give
|
||||||
|
# permission to link the code of portions of this program with the OpenSSL
|
||||||
|
# library.
|
||||||
|
# You must obey the GNU General Public License in all respects for all of
|
||||||
|
# the code used other than OpenSSL. If you modify file(s) with this
|
||||||
|
# exception, you may extend this exception to your version of the file(s),
|
||||||
|
# but you are not obligated to do so. If you do not wish to do so, delete
|
||||||
|
# this exception statement from your version. If you delete this exception
|
||||||
|
# statement from all source files in the program, then also delete it here.
|
||||||
|
"""
|
||||||
|
json api.
|
||||||
|
only used for XUL and/or external scripts
|
||||||
|
it would be possible not to incluse the python-json dependency.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import deluge.ui.client as proxy
|
||||||
|
from new import instancemethod
|
||||||
|
from inspect import getargspec
|
||||||
|
from webserver_framework import remote,ws,get_torrent_status,log
|
||||||
|
proxy = ws.proxy
|
||||||
|
|
||||||
|
def to_json(obj):
|
||||||
|
from lib.pythonize import pythonize
|
||||||
|
obj = pythonize(obj)
|
||||||
|
try:
|
||||||
|
import json
|
||||||
|
return json.write(obj)
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError("""Install python-json using your package-manager
|
||||||
|
http://sourceforge.net/projects/json-py/""")
|
||||||
|
|
||||||
|
class json_api:
|
||||||
|
"""
|
||||||
|
eperimental json api
|
||||||
|
generic proxy for all methods onm self.
|
||||||
|
"""
|
||||||
|
illegal_methods = ['shutdown', 'socket', 'xmlrpclib','pickle','os',
|
||||||
|
'is_localhost','CoreProxy','connect_on_new_core', 'connect_on_no_core',
|
||||||
|
'connected','deluge','GET','POST']
|
||||||
|
def __init__(self):
|
||||||
|
self._add_proxy_methods()
|
||||||
|
|
||||||
|
@remote
|
||||||
|
def GET(self,name):
|
||||||
|
if name.startswith('_'):
|
||||||
|
raise AttributeError('_ methods are illegal!')
|
||||||
|
if name in self.illegal_methods:
|
||||||
|
raise AttributeError('Illegal method , I smell a rat!')
|
||||||
|
if not(hasattr(self,name)):
|
||||||
|
raise AttributeError('No such Method')
|
||||||
|
|
||||||
|
method = getattr(self,name)
|
||||||
|
kwargs = {}
|
||||||
|
|
||||||
|
result = method(**kwargs)
|
||||||
|
|
||||||
|
return to_json(result)
|
||||||
|
|
||||||
|
POST = GET
|
||||||
|
|
||||||
|
def list_methods(self):
|
||||||
|
"""
|
||||||
|
list all json methods
|
||||||
|
returns a dict of {methodname:{args:[list of kwargs],doc:'string'},..}
|
||||||
|
"""
|
||||||
|
methods = [getattr(self,m) for m in dir(self)
|
||||||
|
if not m.startswith('_')
|
||||||
|
and (not m in self.illegal_methods)
|
||||||
|
and callable(getattr(self,m))
|
||||||
|
]
|
||||||
|
|
||||||
|
return dict([(f.__name__,
|
||||||
|
{'args':getargspec(f)[0],'doc':(f.__doc__ or '').strip()})
|
||||||
|
for f in methods])
|
||||||
|
|
||||||
|
def _add_proxy_methods(self):
|
||||||
|
methods = [getattr(proxy,m) for m in dir(proxy)
|
||||||
|
if not m.startswith('_')
|
||||||
|
and (not m in self.illegal_methods)
|
||||||
|
and callable(getattr(proxy,m))
|
||||||
|
]
|
||||||
|
for m in methods:
|
||||||
|
setattr(self,m.__name__,m)
|
||||||
|
|
||||||
|
#extra's:
|
||||||
|
def list_torrents(self):
|
||||||
|
return [get_torrent_status(torrent_id)
|
||||||
|
for torrent_id in ws.proxy.get_session_state()]
|
||||||
|
|
||||||
|
get_torrent_status = get_torrent_status
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from pprint import pprint
|
||||||
|
#proxy.set_core_uri('http://localhost:58846') #How to configure this?
|
||||||
|
j = json_api()
|
||||||
|
if True:
|
||||||
|
print 'list-methods:'
|
||||||
|
methods = j.list_methods()
|
||||||
|
names = methods.keys()
|
||||||
|
names.sort()
|
||||||
|
for name in names:
|
||||||
|
m = methods[name]
|
||||||
|
print "%s(%s)\n %s\n" % (name , m['args'] , m['doc'])
|
||||||
|
|
||||||
|
#j.GET('list_torrents')
|
||||||
|
j.POST('list_torrents')
|
||||||
|
|
0
plugins/WebUi/lib/__init__.py
Normal file
0
plugins/WebUi/lib/__init__.py
Normal file
8
plugins/WebUi/lib/readme.txt
Normal file
8
plugins/WebUi/lib/readme.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
This folder may only contain general purpose utilities/files/tools.
|
||||||
|
They should be usable outside of deluge.
|
||||||
|
|
||||||
|
Disclaimer:
|
||||||
|
|
||||||
|
Some may have been adapted to work better with deluge.
|
||||||
|
But they will not other import parts of deluge or Webui.
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
165
|
|
|
@ -47,7 +47,7 @@ $:render.header(_('Torrent list'))
|
||||||
|
|
||||||
|
|
||||||
<div id="tableContainer" class="tableContainer">
|
<div id="tableContainer" class="tableContainer">
|
||||||
<table class="torrent_list" border=1 id="torrent_list">
|
<table class="torrent_list" border=0 cellspacing=0 cellpadding=2 id="torrent_list">
|
||||||
<thead class="fixedHeader">
|
<thead class="fixedHeader">
|
||||||
<tr>
|
<tr>
|
||||||
$:(sort_head('calc_state_str', 'S'))
|
$:(sort_head('calc_state_str', 'S'))
|
||||||
|
@ -67,9 +67,10 @@ $:render.header(_('Torrent list'))
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="scrollContent">
|
<tbody class="scrollContent">
|
||||||
|
$altrow(True)
|
||||||
$#4-space indentation is mandatory for for-loops in templetor!
|
$#4-space indentation is mandatory for for-loops in templetor!
|
||||||
$for torrent in torrent_list:
|
$for torrent in torrent_list:
|
||||||
<tr class="torrent_table" onclick="on_click_row(event, '$torrent.id')" id="torrent_$torrent.id">
|
<tr class="$altrow()" onclick="on_click_row(event, '$torrent.id')" id="torrent_$torrent.id">
|
||||||
<td>
|
<td>
|
||||||
<form action="/torrent/$torrent.action/$torrent.id" method="POST"
|
<form action="/torrent/$torrent.action/$torrent.id" method="POST"
|
||||||
class="pause_resume">
|
class="pause_resume">
|
||||||
|
|
|
@ -78,6 +78,19 @@ tr.torrent_table:hover {
|
||||||
background-color:#68a;
|
background-color:#68a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr.altrow0:hover {
|
||||||
|
background-color:#68a;
|
||||||
|
}
|
||||||
|
tr.altrow1:hover {
|
||||||
|
background-color:#68a;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.altrow1{
|
||||||
|
background-color: #37506f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tr.torrent_table_selected {
|
tr.torrent_table_selected {
|
||||||
background-color:#900;
|
background-color:#900;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +98,9 @@ tr.torrent_table_selected {
|
||||||
th.torrent_table:hover {
|
th.torrent_table:hover {
|
||||||
background-color:#68a;
|
background-color:#68a;
|
||||||
}
|
}
|
||||||
|
th.torrent_table {
|
||||||
|
background-color: #37506f;
|
||||||
|
}
|
||||||
|
|
||||||
img.button {
|
img.button {
|
||||||
margin-bottom:0px;
|
margin-bottom:0px;
|
||||||
|
|
|
@ -45,6 +45,9 @@ function on_click_row_js(e, id) {
|
||||||
function select_row(id){
|
function select_row(id){
|
||||||
var row = get_row(id);
|
var row = get_row(id);
|
||||||
if (row) {
|
if (row) {
|
||||||
|
if (!(row.default_class_name)) {
|
||||||
|
row.default_class_name = row.className;
|
||||||
|
}
|
||||||
row.className = 'torrent_table_selected';
|
row.className = 'torrent_table_selected';
|
||||||
state.selected_rows[state.selected_rows.length] = id;
|
state.selected_rows[state.selected_rows.length] = id;
|
||||||
setCookie('selected_rows',state.selected_rows);
|
setCookie('selected_rows',state.selected_rows);
|
||||||
|
@ -54,7 +57,7 @@ function select_row(id){
|
||||||
function deselect_row(id){
|
function deselect_row(id){
|
||||||
var row = get_row(id);
|
var row = get_row(id);
|
||||||
if (row) {
|
if (row) {
|
||||||
row.className = 'torrent_table'
|
row.className = row.default_class_name
|
||||||
/*remove from state.selected_rows*/
|
/*remove from state.selected_rows*/
|
||||||
var idx = state.selected_rows.indexOf(id);
|
var idx = state.selected_rows.indexOf(id);
|
||||||
state.selected_rows.splice(idx,1);
|
state.selected_rows.splice(idx,1);
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<div id='refresh_panel'>
|
|
||||||
<div class="panel" >
|
|
||||||
$_('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
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,5 +0,0 @@
|
||||||
revision-id: mvoncken@gmail.com-20070930083408-sv8mo0mi1rbjnfvk
|
|
||||||
date: 2007-12-05 15:10:08 +0200
|
|
||||||
build-date: 2007-12-05 15:34:50 +0200
|
|
||||||
revno: 165
|
|
||||||
branch-nick: WebUi
|
|
|
@ -31,8 +31,8 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
initializes config,render and proxy.
|
initializes config,render and proxy.
|
||||||
contains all hacks to support running in process0.5 ,run inside-gtk0.5 and
|
All hacks go here, so this is a really ugly source-file..
|
||||||
run in process0.6
|
Support running in process0.5 ,run inside-gtk0.5 and run in process0.6
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -41,7 +41,7 @@ import random
|
||||||
import pickle
|
import pickle
|
||||||
import sys
|
import sys
|
||||||
import base64
|
import base64
|
||||||
from webpy022 import template
|
from lib.webpy022 import template
|
||||||
|
|
||||||
random.seed()
|
random.seed()
|
||||||
webui_path = os.path.dirname(__file__)
|
webui_path = os.path.dirname(__file__)
|
||||||
|
@ -163,7 +163,8 @@ def init_gtk_05():
|
||||||
def init_logger():
|
def init_logger():
|
||||||
#only for 0.5..
|
#only for 0.5..
|
||||||
import logging
|
import logging
|
||||||
logging.basicConfig(level=logging.DEBUG,format="[%(levelname)-8s] %(module)s:%(lineno)d %(message)s")
|
logging.basicConfig(level=logging.DEBUG,
|
||||||
|
format="[%(levelname)s] %(message)s")
|
||||||
globals()['log'] = logging
|
globals()['log'] = logging
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,13 @@ Todo's before stable:
|
||||||
-clear finished?
|
-clear finished?
|
||||||
-torrent files.
|
-torrent files.
|
||||||
"""
|
"""
|
||||||
import webpy022 as web
|
import lib.webpy022 as web
|
||||||
|
|
||||||
from webpy022.webapi import cookies, setcookie as w_setcookie
|
from lib.webpy022.webapi import cookies, setcookie as w_setcookie
|
||||||
from webpy022.http import seeother, url
|
from lib.webpy022.http import seeother, url
|
||||||
from webpy022 import template,changequery as self_url
|
from lib.webpy022 import template,changequery as self_url
|
||||||
from webpy022.utils import Storage
|
from lib.webpy022.utils import Storage
|
||||||
from static_handler import static_handler
|
from lib.static_handler import static_handler
|
||||||
|
|
||||||
from deluge.common import fsize,fspeed
|
from deluge.common import fsize,fspeed
|
||||||
|
|
||||||
|
@ -144,7 +144,8 @@ def check_session(func):
|
||||||
return func if session is valid, else redirect to login page.
|
return func if session is valid, else redirect to login page.
|
||||||
"""
|
"""
|
||||||
def deco(self, name = None):
|
def deco(self, name = None):
|
||||||
log.debug('%s.%s(name=%s)' % (self.__class__.__name__,func.__name__,name))
|
log.debug('%s.%s(name=%s)' % (self.__class__.__name__, func.__name__,
|
||||||
|
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 ws.SESSIONS:
|
if ck.has_key("session_id") and ck["session_id"] in ws.SESSIONS:
|
||||||
|
@ -282,6 +283,7 @@ def filter_torrent_state(torrent_list,filter_name):
|
||||||
,'queued':lambda t: (t.paused and not t.user_paused)
|
,'queued':lambda t: (t.paused and not t.user_paused)
|
||||||
,'paused':lambda t: (t.user_paused)
|
,'paused':lambda t: (t.user_paused)
|
||||||
,'seeding':lambda t:(t.is_seed and not t.paused )
|
,'seeding':lambda t:(t.is_seed and not t.paused )
|
||||||
|
,'active':lambda t: (t.download_rate > 0 or t.upload_rate > 0)
|
||||||
}
|
}
|
||||||
filter_func = filters[filter_name]
|
filter_func = filters[filter_name]
|
||||||
return [t for t in torrent_list if filter_func(t)]
|
return [t for t in torrent_list if filter_func(t)]
|
||||||
|
@ -300,7 +302,8 @@ def category_tabs(torrent_list):
|
||||||
(_('Downloading'),'downloading') ,
|
(_('Downloading'),'downloading') ,
|
||||||
(_('Queued'),'queued') ,
|
(_('Queued'),'queued') ,
|
||||||
(_('Paused'),'paused') ,
|
(_('Paused'),'paused') ,
|
||||||
(_('Seeding'),'seeding')
|
(_('Seeding'),'seeding'),
|
||||||
|
(_('Active'),'active')
|
||||||
]:
|
]:
|
||||||
title += ' (%s)' % (
|
title += ' (%s)' % (
|
||||||
len(filter_torrent_state(torrent_list, filter_name)), )
|
len(filter_torrent_state(torrent_list, filter_name)), )
|
||||||
|
@ -349,6 +352,17 @@ def template_part_stats():
|
||||||
def get_config(var):
|
def get_config(var):
|
||||||
return ws.config.get(var)
|
return ws.config.get(var)
|
||||||
|
|
||||||
|
irow = 0
|
||||||
|
def altrow(reset = False):
|
||||||
|
global irow
|
||||||
|
if reset:
|
||||||
|
irow = 1
|
||||||
|
return
|
||||||
|
irow +=1
|
||||||
|
irow = irow % 2
|
||||||
|
return "altrow%s" % irow
|
||||||
|
|
||||||
|
|
||||||
template.Template.globals.update({
|
template.Template.globals.update({
|
||||||
'sort_head': template_sort_head,
|
'sort_head': template_sort_head,
|
||||||
'part_stats':template_part_stats,
|
'part_stats':template_part_stats,
|
||||||
|
@ -357,6 +371,7 @@ template.Template.globals.update({
|
||||||
'_': _ , #gettext/translations
|
'_': _ , #gettext/translations
|
||||||
'str': str, #because % in templetor is broken.
|
'str': str, #because % in templetor is broken.
|
||||||
'sorted': sorted,
|
'sorted': sorted,
|
||||||
|
'altrow':altrow,
|
||||||
'get_config': get_config,
|
'get_config': get_config,
|
||||||
'self_url': self_url,
|
'self_url': self_url,
|
||||||
'fspeed': common.fspeed,
|
'fspeed': common.fspeed,
|
||||||
|
@ -370,9 +385,9 @@ template.Template.globals.update({
|
||||||
#/template-defs
|
#/template-defs
|
||||||
|
|
||||||
def create_webserver(urls, methods):
|
def create_webserver(urls, methods):
|
||||||
from webpy022.request import webpyfunc
|
from lib.webpy022.request import webpyfunc
|
||||||
from webpy022 import webapi
|
from lib.webpy022 import webapi
|
||||||
from gtk_cherrypy_wsgiserver import CherryPyWSGIServer
|
from lib.gtk_cherrypy_wsgiserver import CherryPyWSGIServer
|
||||||
import os
|
import os
|
||||||
|
|
||||||
func = webapi.wsgifunc(webpyfunc(urls, methods, False))
|
func = webapi.wsgifunc(webpyfunc(urls, methods, False))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue