mirror of
https://git.deluge-torrent.org/deluge
synced 2025-08-02 22:48:40 +00:00
queue
This commit is contained in:
parent
335c037add
commit
c2a7c9fe92
7 changed files with 23 additions and 265 deletions
|
@ -28,255 +28,4 @@
|
||||||
# but you are not obligated to do so. If you do not wish to do so, delete
|
# 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
|
# this exception statement from your version. If you delete this exception
|
||||||
|
|
||||||
plugin_name = "Web User Interface"
|
|
||||||
plugin_author = "Martijn Voncken"
|
|
||||||
plugin_version = "rev."
|
|
||||||
plugin_description = """A Web based User Interface
|
|
||||||
|
|
||||||
Firefox greasemonkey script: http://userscripts.org/scripts/show/12639
|
|
||||||
|
|
||||||
Remotely add a file: "curl -F torrent=@./test1.torrent -F pwd=deluge http://localhost:8112/remote/torrent/add"
|
|
||||||
|
|
||||||
Advanced template is only tested on firefox and garanteed not to work in IE6
|
|
||||||
|
|
||||||
ssl keys are located in WebUi/ssl/
|
|
||||||
|
|
||||||
Other contributors:
|
|
||||||
*somedude : template enhancements.
|
|
||||||
*markybob : stability : synced with his changes in deluge-svn.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
import deluge.common
|
|
||||||
from webserver_common import ws,REVNO,VERSION
|
|
||||||
|
|
||||||
try:
|
|
||||||
import deluge.pref
|
|
||||||
from deluge.dialogs import show_popup_warning
|
|
||||||
except ImportError:
|
|
||||||
print 'WebUi:not imported as a plugin'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
from dbus_interface import get_dbus_manager
|
|
||||||
except:
|
|
||||||
print 'error importing dbus-interface!'
|
|
||||||
pass #for unit-test.
|
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
import gtk
|
|
||||||
import os
|
|
||||||
from subprocess import Popen
|
|
||||||
from md5 import md5
|
|
||||||
from threading import Thread
|
|
||||||
import random
|
|
||||||
random.seed()
|
|
||||||
|
|
||||||
plugin_version += REVNO
|
|
||||||
plugin_description += VERSION
|
|
||||||
|
|
||||||
def deluge_init(deluge_path):
|
|
||||||
global path
|
|
||||||
path = deluge_path
|
|
||||||
|
|
||||||
def enable(core, interface):
|
|
||||||
global path
|
|
||||||
return plugin_WebUi(path, core, interface)
|
|
||||||
|
|
||||||
class plugin_WebUi(object):
|
|
||||||
def __init__(self, path, deluge_core, deluge_interface):
|
|
||||||
self.path = path
|
|
||||||
self.core = deluge_core
|
|
||||||
self.interface = deluge_interface
|
|
||||||
self.proc = None
|
|
||||||
self.web_server = None
|
|
||||||
if not deluge.common.windows_check():
|
|
||||||
import commands
|
|
||||||
status = commands.getstatusoutput(
|
|
||||||
'ps x |grep -v grep |grep run_webserver')
|
|
||||||
if status[0] == 0:
|
|
||||||
os.kill(int(status[1].split()[0]), 9)
|
|
||||||
time.sleep(1) #safe time to wait for kill to finish.
|
|
||||||
self.config_file = deluge.common.CONFIG_DIR + "/webui.conf"
|
|
||||||
self.config = deluge.pref.Preferences(self.config_file, False)
|
|
||||||
try:
|
|
||||||
self.config.load()
|
|
||||||
except IOError:
|
|
||||||
# File does not exist
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not self.config.get('port'): #ugly way to detect new config file.
|
|
||||||
#set default values:
|
|
||||||
self.config.set("port", 8112)
|
|
||||||
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")
|
|
||||||
|
|
||||||
if self.config.get("cache_templates") == None:
|
|
||||||
self.config.set("cache_templates", True)
|
|
||||||
|
|
||||||
if deluge.common.windows_check():
|
|
||||||
self.config.set("run_in_thread", True)
|
|
||||||
else:
|
|
||||||
self.config.set("run_in_thread", False)
|
|
||||||
|
|
||||||
if self.config.get("use_https") == None:
|
|
||||||
self.config.set("use_https", False)
|
|
||||||
|
|
||||||
self.dbus_manager = get_dbus_manager(deluge_core, deluge_interface,
|
|
||||||
self.config, self.config_file)
|
|
||||||
|
|
||||||
self.start_server()
|
|
||||||
|
|
||||||
def unload(self):
|
|
||||||
print 'WebUI:unload..'
|
|
||||||
self.kill_server()
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
## This will be only called if your plugin is configurable
|
|
||||||
def configure(self,parent_dialog):
|
|
||||||
d = ConfigDialog(self.config, self, parent_dialog)
|
|
||||||
if d.run() == gtk.RESPONSE_OK:
|
|
||||||
d.save_config()
|
|
||||||
d.destroy()
|
|
||||||
|
|
||||||
def start_server(self):
|
|
||||||
self.kill_server()
|
|
||||||
|
|
||||||
if self.config.get("run_in_thread"):
|
|
||||||
print 'Start Webui(inside gtk)..'
|
|
||||||
ws.init_gtk_05() #reload changed config.
|
|
||||||
from deluge_webserver import WebServer #only import in threaded mode
|
|
||||||
|
|
||||||
|
|
||||||
self.web_server = WebServer()
|
|
||||||
self.web_server.start_gtk()
|
|
||||||
|
|
||||||
else:
|
|
||||||
print 'Start Webui(in process)..'
|
|
||||||
server_bin = os.path.dirname(__file__) + '/run_webserver'
|
|
||||||
self.proc = Popen((server_bin,'env=0.5'))
|
|
||||||
|
|
||||||
def kill_server(self):
|
|
||||||
if self.web_server:
|
|
||||||
print "webserver: stop"
|
|
||||||
self.web_server.stop_gtk()
|
|
||||||
self.web_server = None
|
|
||||||
if self.proc:
|
|
||||||
print "webserver: kill %i" % self.proc.pid
|
|
||||||
os.system("kill -9 %i" % self.proc.pid)
|
|
||||||
time.sleep(1) #safe time to wait for kill to finish.
|
|
||||||
self.proc = None
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
self.kill_server()
|
|
||||||
|
|
||||||
class ConfigDialog(gtk.Dialog):
|
|
||||||
"""
|
|
||||||
sorry, can't get used to gui builders.
|
|
||||||
from what I read glade is better, but i dont want to invest time in them.
|
|
||||||
"""
|
|
||||||
def __init__(self, config, plugin, parent):
|
|
||||||
gtk.Dialog.__init__(self ,parent=parent)
|
|
||||||
self.config = config
|
|
||||||
self.plugin = plugin
|
|
||||||
self.vb = gtk.VBox()
|
|
||||||
self.set_title(_("WebUi Config"))
|
|
||||||
|
|
||||||
template_path = os.path.join(os.path.dirname(__file__), 'templates')
|
|
||||||
self.templates = [dirname for dirname
|
|
||||||
in os.listdir(template_path)
|
|
||||||
if os.path.isdir(os.path.join(template_path, dirname))
|
|
||||||
and not dirname.startswith('.')]
|
|
||||||
|
|
||||||
self.port = self.add_widget(_('Port Number'), gtk.SpinButton())
|
|
||||||
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.cache_templates = self.add_widget(_('Cache Templates'),
|
|
||||||
gtk.CheckButton())
|
|
||||||
self.use_https = self.add_widget(_('https://'),
|
|
||||||
gtk.CheckButton())
|
|
||||||
|
|
||||||
#self.share_downloads = self.add_widget(_('Share Download Directory'),
|
|
||||||
# gtk.CheckButton())
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
if not self.config.get("template") in self.templates:
|
|
||||||
self.config.set("template","deluge")
|
|
||||||
|
|
||||||
for item in [_('Text and image'), _('Image Only'), _('Text Only')]:
|
|
||||||
self.button_style.append_text(item)
|
|
||||||
if self.config.get("button_style") == None:
|
|
||||||
self.config.set("button_style", 2)
|
|
||||||
|
|
||||||
self.port.set_value(int(self.config.get("port")))
|
|
||||||
self.template.set_active(
|
|
||||||
self.templates.index(self.config.get("template")))
|
|
||||||
self.button_style.set_active(self.config.get("button_style"))
|
|
||||||
#self.share_downloads.set_active(
|
|
||||||
# bool(self.config.get("share_downloads")))
|
|
||||||
|
|
||||||
self.cache_templates.set_active(self.config.get("cache_templates"))
|
|
||||||
self.use_https.set_active(self.config.get("use_https"))
|
|
||||||
|
|
||||||
self.vbox.pack_start(self.vb, True, True, 0)
|
|
||||||
self.vb.show_all()
|
|
||||||
|
|
||||||
self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL
|
|
||||||
,gtk.STOCK_OK, gtk.RESPONSE_OK)
|
|
||||||
|
|
||||||
def add_widget(self,label,w=None):
|
|
||||||
hb = gtk.HBox()
|
|
||||||
lbl = gtk.Label(label)
|
|
||||||
lbl.set_size_request(200,20)
|
|
||||||
hb.pack_start(lbl,False,False, 0)
|
|
||||||
hb.pack_start(w,True,True, 0)
|
|
||||||
|
|
||||||
self.vb.pack_start(hb,False,False, 0)
|
|
||||||
return w
|
|
||||||
self.add_buttons(dgtk.STOCK_CLOSE, dgtk.RESPONSE_CLOSE)
|
|
||||||
|
|
||||||
def save_config(self):
|
|
||||||
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:
|
|
||||||
sm = md5()
|
|
||||||
sm.update(str(random.getrandbits(5000)))
|
|
||||||
salt = sm.digest()
|
|
||||||
self.config.set("pwd_salt", salt)
|
|
||||||
#
|
|
||||||
m = md5()
|
|
||||||
m.update(salt)
|
|
||||||
m.update(unicode(self.pwd1.get_text()))
|
|
||||||
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("cache_templates", self.cache_templates.get_active())
|
|
||||||
self.config.set("use_https", self.use_https.get_active())
|
|
||||||
#self.config.set("share_downloads", self.share_downloads.get_active())
|
|
||||||
self.config.save(self.plugin.config_file)
|
|
||||||
self.plugin.start_server() #restarts server
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ import page_decorators as deco
|
||||||
import config_tabs_webui #auto registers
|
import config_tabs_webui #auto registers
|
||||||
import config_tabs_deluge #auto registers
|
import config_tabs_deluge #auto registers
|
||||||
from config import config_page
|
from config import config_page
|
||||||
import torrent_options
|
from torrent_options import torrent_options
|
||||||
from torrent_move import torrent_move
|
from torrent_move import torrent_move
|
||||||
#import forms
|
#import forms
|
||||||
#
|
#
|
||||||
|
@ -75,6 +75,7 @@ urls = (
|
||||||
"/torrent/queue/up/(.*)", "torrent_queue_up",
|
"/torrent/queue/up/(.*)", "torrent_queue_up",
|
||||||
"/torrent/queue/down/(.*)", "torrent_queue_down",
|
"/torrent/queue/down/(.*)", "torrent_queue_down",
|
||||||
"/torrent/files/(.*)","torrent_files",
|
"/torrent/files/(.*)","torrent_files",
|
||||||
|
"/torrent/options/(.*)","torrent_options",
|
||||||
"/pause_all", "pause_all",
|
"/pause_all", "pause_all",
|
||||||
"/resume_all", "resume_all",
|
"/resume_all", "resume_all",
|
||||||
"/refresh/set", "refresh_set",
|
"/refresh/set", "refresh_set",
|
||||||
|
@ -171,6 +172,7 @@ class torrent_info_inner:
|
||||||
return render.torrent_info_inner(torrent, active_tab)
|
return render.torrent_info_inner(torrent, active_tab)
|
||||||
|
|
||||||
#next 4 classes: a pattern is emerging here.
|
#next 4 classes: a pattern is emerging here.
|
||||||
|
#todo: DRY (in less lines of code)
|
||||||
class torrent_start:
|
class torrent_start:
|
||||||
@deco.check_session
|
@deco.check_session
|
||||||
@deco.torrent_ids
|
@deco.torrent_ids
|
||||||
|
@ -221,10 +223,10 @@ class torrent_queue_up:
|
||||||
@deco.torrent_list
|
@deco.torrent_list
|
||||||
def POST(self, torrent_list):
|
def POST(self, torrent_list):
|
||||||
#a bit too verbose..
|
#a bit too verbose..
|
||||||
torrent_list.sort(lambda x, y : x.queue_pos - y.queue_pos)
|
torrent_list.sort(lambda x, y : x.queue - y.queue)
|
||||||
torrent_ids = [t.id for t in torrent_list]
|
torrent_ids = [t.id for t in torrent_list]
|
||||||
for torrent_id in torrent_ids:
|
for torrent_id in torrent_ids:
|
||||||
ws.proxy.queue_up(torrent_id)
|
ws.proxy.queue_queue_up(torrent_id)
|
||||||
do_redirect()
|
do_redirect()
|
||||||
|
|
||||||
class torrent_queue_down:
|
class torrent_queue_down:
|
||||||
|
@ -232,10 +234,10 @@ class torrent_queue_down:
|
||||||
@deco.torrent_list
|
@deco.torrent_list
|
||||||
def POST(self, torrent_list):
|
def POST(self, torrent_list):
|
||||||
#a bit too verbose..
|
#a bit too verbose..
|
||||||
torrent_list.sort(lambda x, y : x.queue_pos - y.queue_pos)
|
torrent_list.sort(lambda x, y : x.queue - y.queue)
|
||||||
torrent_ids = [t.id for t in torrent_list]
|
torrent_ids = [t.id for t in torrent_list]
|
||||||
for torrent_id in reversed(torrent_ids):
|
for torrent_id in reversed(torrent_ids):
|
||||||
ws.proxy.queue_down(torrent_id)
|
ws.proxy.queue_queue_down(torrent_id)
|
||||||
do_redirect()
|
do_redirect()
|
||||||
|
|
||||||
class torrent_files:
|
class torrent_files:
|
||||||
|
@ -267,7 +269,7 @@ class resume_all:
|
||||||
class refresh:
|
class refresh:
|
||||||
def GET(self, name):
|
def GET(self, name):
|
||||||
return self.POST(name)
|
return self.POST(name)
|
||||||
#WRONG, but makes it easyer to link with <a href in the status-bar
|
#WRONG, but makes it easyer to link with <a href> in the status-bar
|
||||||
|
|
||||||
@deco.check_session
|
@deco.check_session
|
||||||
def POST(self, name):
|
def POST(self, name):
|
||||||
|
@ -306,7 +308,7 @@ class about:
|
||||||
class logout:
|
class logout:
|
||||||
def GET(self):
|
def GET(self):
|
||||||
return self.POST()
|
return self.POST()
|
||||||
#WRONG, but makes it easyer to link with <a href in the status-bar
|
#WRONG, but makes it easyer to link with <a href> in the status-bar
|
||||||
|
|
||||||
@deco.check_session
|
@deco.check_session
|
||||||
def POST(self, name):
|
def POST(self, name):
|
||||||
|
|
|
@ -65,7 +65,7 @@ $for t in torrent_list:
|
||||||
<thead class="fixedHeader">
|
<thead class="fixedHeader">
|
||||||
<tr>
|
<tr>
|
||||||
$:(sort_head('calc_state_str', 'S'))
|
$:(sort_head('calc_state_str', 'S'))
|
||||||
$:(sort_head('queue_pos', '#'))
|
$:(sort_head('queue', '#'))
|
||||||
$:(sort_head('name', _('Name')))
|
$:(sort_head('name', _('Name')))
|
||||||
$:(sort_head('total_size', _('Size')))
|
$:(sort_head('total_size', _('Size')))
|
||||||
$:(sort_head('progress', _('Progress')))
|
$:(sort_head('progress', _('Progress')))
|
||||||
|
@ -93,7 +93,7 @@ $for torrent in torrent_list:
|
||||||
name="pauseresume" value="submit" />
|
name="pauseresume" value="submit" />
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
<td>$torrent.queue_pos</td>
|
<td>$torrent.queue</td>
|
||||||
<td style="width:100px; overflow:hidden;white-space: nowrap">
|
<td style="width:100px; overflow:hidden;white-space: nowrap">
|
||||||
$(crop(torrent.name, 40))</td>
|
$(crop(torrent.name, 40))</td>
|
||||||
<td>$fsize(torrent.total_size)</td>
|
<td>$fsize(torrent.total_size)</td>
|
||||||
|
|
|
@ -4,7 +4,7 @@ $:render.header(_('Torrent list'))
|
||||||
<table class="torrent_list" border=0 id='torrent_table'>
|
<table class="torrent_list" border=0 id='torrent_table'>
|
||||||
<tr>
|
<tr>
|
||||||
$:(sort_head('calc_state_str', 'S'))
|
$:(sort_head('calc_state_str', 'S'))
|
||||||
$:(sort_head('queue_pos', '#'))
|
$:(sort_head('queue', '#'))
|
||||||
$:(sort_head('name', _('Name')))
|
$:(sort_head('name', _('Name')))
|
||||||
$:(sort_head('total_size', _('Size')))
|
$:(sort_head('total_size', _('Size')))
|
||||||
$:(sort_head('progress', _('Progress')))
|
$:(sort_head('progress', _('Progress')))
|
||||||
|
|
|
@ -58,7 +58,7 @@ $fspeed(torrent.download_rate)</td></td></tr>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr><td class="info_label">$_('Queue Position'):</td>
|
<tr><td class="info_label">$_('Queue Position'):</td>
|
||||||
<td class="info_value">$torrent.queue_pos </td>
|
<td class="info_value">$torrent.queue </td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -50,5 +50,12 @@ class TorrentOptionsForm(forms.Form):
|
||||||
_('Prioritize first and last pieces'))
|
_('Prioritize first and last pieces'))
|
||||||
private = forms.CheckBox(_('Private'))
|
private = forms.CheckBox(_('Private'))
|
||||||
|
|
||||||
template.Template.globals["forms"].torrent_options = lambda torrent : TorrentOptionsForm(torrent)
|
class torrent_options:
|
||||||
|
@deco.check_session
|
||||||
|
@deco.torrent
|
||||||
|
def POST(self, torrent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template.Template.globals["forms"].torrent_options = lambda torrent : TorrentOptionsForm(torrent)
|
|
@ -73,10 +73,10 @@ TORRENT_KEYS = ['name', 'total_size', 'num_files', 'num_pieces', 'piece_length',
|
||||||
'total_wanted', 'tracker', 'trackers', 'tracker_status', 'save_path',
|
'total_wanted', 'tracker', 'trackers', 'tracker_status', 'save_path',
|
||||||
'files', 'file_priorities', 'compact', 'max_connections',
|
'files', 'file_priorities', 'compact', 'max_connections',
|
||||||
'max_upload_slots', 'max_download_speed', 'prioritize_first_last',
|
'max_upload_slots', 'max_download_speed', 'prioritize_first_last',
|
||||||
'private','max_upload_speed',
|
'private','max_upload_speed','queue',
|
||||||
|
|
||||||
#REMOVE:
|
#REMOVE:
|
||||||
"is_seed","total_download","total_upload","uploaded_memory","queue_pos",
|
"is_seed","total_download","total_upload","uploaded_memory",
|
||||||
"user_paused"
|
"user_paused"
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue