Compare commits

...

20 Commits

Author SHA1 Message Date
da0dd8a4a9 remove webui example template 2007-11-27 21:35:16 +00:00
d182928f8c tag release 2007-11-27 20:08:43 +00:00
0f680b43e3 tweak boost library variables 2007-11-26 16:42:07 +00:00
7bb59d19d8 update rev # 2007-11-26 16:08:48 +00:00
eba7d24550 webui tweaks rev 160 2007-11-26 16:06:55 +00:00
59116daf71 tweak get_index_from_unique_id 2007-11-26 06:07:47 +00:00
2b1a4a8a8e fix typo 2007-11-26 05:57:31 +00:00
fd2a3a5607 make sure simplerss does not load 2007-11-26 05:40:24 +00:00
1e541a5b43 fix indent 2007-11-26 04:57:28 +00:00
7e74457fac add catch to get_index_from_unique_id 2007-11-26 04:48:11 +00:00
4c2388499b tweak last 2007-11-26 02:20:40 +00:00
804b534009 catch invalid_handle on add_torrent 2007-11-26 02:04:55 +00:00
d8681a0593 another attempt for invalid handle 2007-11-26 00:59:28 +00:00
edb20e0c05 small lsd, dht, webseed, and socks fixes 2007-11-26 00:26:45 +00:00
3fb3bd9233 fix webseed 2007-11-26 00:17:48 +00:00
8dfb4b73eb try to catch invalid handle in deluge_core 2007-11-25 23:59:19 +00:00
3ea3b6b5b0 torrent info labels selectable 2007-11-25 22:02:44 +00:00
733ce63553 Apply logfile patch for Windows build from Slurdge. 2007-11-25 12:16:29 +00:00
715e3ce463 tag rc2 2007-11-25 02:04:04 +00:00
8730830470 tag 0.5.7rc1 2007-11-24 16:57:53 +00:00
109 changed files with 66361 additions and 42955 deletions

View File

@ -1,10 +1,14 @@
Deluge 0.5.7 (xx November 2007)
Deluge 0.5.7 (27 November 2007)
* Scrape support
* Manual force-recheck
* Add local peer discovery (aka local service discovery)
* Blocklist plugin will now display errors, instead of just crashing on a bad
list or wrong type
* Add torrent in paused state option
* Add advanced progress bar
* Fix bug in merging trackers
* Various updates to WebUI, including https support and advanced template by vonck7
* Add maximum connection attempts per second preference
* Fix bug where loaded plugins were forgotten if Deluge crashed
* Fix ratio bugs (hopefully for the last time)
* Add preference to only show file selection popup if torrent has multiple files
@ -18,6 +22,9 @@ Deluge 0.5.7 (xx November 2007)
* Add preference for the location of torrent files
* Add autoload folder
* Copy translator credits from Launchpad to our about->credits
* Differentiate between queued and paused torrents. Able to pause queued
torrents - patch by yobbobandana
* Show error when writing/permission problems occur
Deluge 0.5.6.2 (31 October 2007)
* Set default piece size to 256-KiB in TorrentCreator plugin and add 2048KiB

1
README
View File

@ -35,6 +35,7 @@ python-all version >= 2.4
python-dbus
python-gtk2 version >= 2.9
python-notify
python-pyopenssl
librsvg2-common
python-xdg
python-support

File diff suppressed because it is too large Load Diff

View File

@ -122,7 +122,7 @@
<child>
<widget class="GtkButton" id="button2">
<property name="visible">True</property>
<property name="label">gtk-no</property>
<property name="label" translatable="no">gtk-no</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
</widget>
@ -130,7 +130,7 @@
<child>
<widget class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="label">gtk-yes</property>
<property name="label" translatable="no">gtk-yes</property>
<property name="use_stock">True</property>
<property name="response_id">1</property>
</widget>
@ -197,7 +197,7 @@
<child>
<widget class="GtkImageMenuItem" id="menuitem12">
<property name="visible">True</property>
<property name="label">gtk-preferences</property>
<property name="label" translatable="no">gtk-preferences</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="preferences"/>
@ -227,7 +227,7 @@
<child>
<widget class="GtkImageMenuItem" id="menuitem14">
<property name="visible">True</property>
<property name="label">gtk-quit</property>
<property name="label" translatable="no">gtk-quit</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="quit"/>
@ -299,7 +299,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label">gtk-cancel</property>
<property name="label" translatable="no">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
</widget>
@ -310,7 +310,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label">gtk-ok</property>
<property name="label" translatable="no">gtk-ok</property>
<property name="use_stock">True</property>
<property name="response_id">1</property>
</widget>

View File

@ -64,7 +64,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label">gtk-cancel</property>
<property name="label" translatable="no">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="cancel_button_clicked"/>
@ -81,7 +81,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label">gtk-ok</property>
<property name="label" translatable="no">gtk-ok</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="ok_button_clicked"/>

View File

@ -57,7 +57,7 @@
<child>
<widget class="GtkButton" id="button2">
<property name="visible">True</property>
<property name="label">gtk-cancel</property>
<property name="label" translatable="no">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
</widget>
@ -65,7 +65,7 @@
<child>
<widget class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="label">gtk-ok</property>
<property name="label" translatable="no">gtk-ok</property>
<property name="use_stock">True</property>
<property name="response_id">1</property>
</widget>

View File

@ -31,7 +31,7 @@
<child>
<widget class="GtkButton" id="button_cancel">
<property name="visible">True</property>
<property name="label">gtk-cancel</property>
<property name="label" translatable="no">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
</widget>
@ -39,7 +39,7 @@
<child>
<widget class="GtkButton" id="button_ok">
<property name="visible">True</property>
<property name="label">gtk-ok</property>
<property name="label" translatable="no">gtk-ok</property>
<property name="use_stock">True</property>
<property name="response_id">1</property>
</widget>

File diff suppressed because it is too large Load Diff

View File

@ -41,10 +41,10 @@ namespace error
system_category = ASIO_WIN_OR_POSIX(0, 0),
/// Error codes from NetDB functions.
netdb_category = ASIO_WIN_OR_POSIX(_system_category, 1),
netdb_category = ASIO_WIN_OR_POSIX(system_category, 1),
/// Error codes from getaddrinfo.
addrinfo_category = ASIO_WIN_OR_POSIX(_system_category, 2),
addrinfo_category = ASIO_WIN_OR_POSIX(system_category, 2),
/// Miscellaneous error codes.
misc_category = ASIO_WIN_OR_POSIX(3, 3),

View File

@ -473,7 +473,7 @@ namespace libtorrent
// we might need more than one listen socket
std::list<listen_socket_t> m_listen_sockets;
listen_socket_t setup_listener(tcp::endpoint ep, int retries);
listen_socket_t setup_listener(tcp::endpoint ep, int retries, bool v6_only = false);
// the settings for the client
session_settings m_settings;

View File

@ -171,6 +171,21 @@ namespace libtorrent
return Endpoint(addr, port);
}
}
struct v6only
{
v6only(bool enable): m_value(enable) {}
template<class Protocol>
int level(Protocol const&) const { return IPPROTO_IPV6; }
template<class Protocol>
int name(Protocol const&) const { return IPV6_V6ONLY; }
template<class Protocol>
int const* data(Protocol const&) const { return &m_value; }
template<class Protocol>
size_t size(Protocol const&) const { return sizeof(m_value); }
int m_value;
};
}
#endif // TORRENT_SOCKET_HPP_INCLUDED

View File

@ -273,6 +273,9 @@ namespace libtorrent { namespace dht
udp::endpoint ep(listen_interface, listen_port);
m_socket.open(ep.protocol());
m_socket.bind(ep);
m_socket.async_receive_from(asio::buffer(&m_in_buf[m_buffer][0]
, m_in_buf[m_buffer].size()), m_remote_endpoint[m_buffer]
, m_strand.wrap(bind(&dht_tracker::on_receive, self(), _1, _2)));
}
void dht_tracker::tick(asio::error_code const& e)

View File

@ -814,13 +814,15 @@ namespace detail
return m_ipv6_interface;
}
session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep, int retries)
session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep
, int retries, bool v6_only)
{
asio::error_code ec;
listen_socket_t s;
s.sock.reset(new socket_acceptor(m_io_service));
s.sock->open(ep.protocol(), ec);
s.sock->set_option(socket_acceptor::reuse_address(true), ec);
if (ep.protocol() == tcp::v6()) s.sock->set_option(v6only(v6_only), ec);
s.sock->bind(ep, ec);
while (ec && retries > 0)
{
@ -913,7 +915,7 @@ namespace detail
s = setup_listener(
tcp::endpoint(address_v6::any(), m_listen_interface.port())
, m_listen_port_retries);
, m_listen_port_retries, true);
if (s.sock)
{
@ -2279,6 +2281,8 @@ namespace detail
INVARIANT_CHECK;
if (m_lsd) return;
m_lsd = new lsd(m_io_service
, m_listen_interface.address()
, bind(&session_impl::on_lsd_peer, this, _1, _2));
@ -2290,6 +2294,8 @@ namespace detail
INVARIANT_CHECK;
if (m_natpmp) return;
m_natpmp = new natpmp(m_io_service
, m_listen_interface.address()
, bind(&session_impl::on_port_mapping
@ -2308,6 +2314,8 @@ namespace detail
INVARIANT_CHECK;
if (m_upnp) return;
m_upnp = new upnp(m_io_service, m_half_open
, m_listen_interface.address()
, m_settings.user_agent

View File

@ -43,7 +43,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -54,8 +55,8 @@ namespace libtorrent
if (i == tcp::resolver::iterator())
{
asio::error_code ec = asio::error::operation_not_supported;
(*h)(e);
close();
(*h)(ec);
close(ec);
return;
}
@ -68,7 +69,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -93,7 +95,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -107,7 +110,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -119,8 +123,9 @@ namespace libtorrent
if (reply_version != 0)
{
(*h)(asio::error::operation_not_supported);
close();
asio::error_code ec = asio::error::operation_not_supported;
(*h)(ec);
close(ec);
return;
}
@ -140,7 +145,7 @@ namespace libtorrent
case 93: ec = asio::error::no_permission; break;
}
(*h)(ec);
close();
close(ec);
}
}

View File

@ -44,7 +44,8 @@ namespace libtorrent
if (e || i == tcp::resolver::iterator())
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -57,7 +58,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -86,7 +88,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -100,7 +103,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -113,7 +117,8 @@ namespace libtorrent
if (version < 5)
{
(*h)(asio::error::operation_not_supported);
close();
asio::error_code ec;
close(ec);
return;
}
@ -126,7 +131,8 @@ namespace libtorrent
if (m_user.empty())
{
(*h)(asio::error::operation_not_supported);
close();
asio::error_code ec;
close(ec);
return;
}
@ -144,7 +150,8 @@ namespace libtorrent
else
{
(*h)(asio::error::operation_not_supported);
close();
asio::error_code ec;
close(ec);
return;
}
}
@ -155,7 +162,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -170,7 +178,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -183,14 +192,16 @@ namespace libtorrent
if (version != 1)
{
(*h)(asio::error::operation_not_supported);
close();
asio::error_code ec;
close(ec);
return;
}
if (status != 0)
{
(*h)(asio::error::operation_not_supported);
close();
asio::error_code ec;
close(ec);
return;
}
@ -222,7 +233,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -236,7 +248,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
@ -248,7 +261,8 @@ namespace libtorrent
if (version < 5)
{
(*h)(asio::error::operation_not_supported);
close();
asio::error_code ec;
close(ec);
return;
}
int response = read_uint8(p);
@ -267,7 +281,8 @@ namespace libtorrent
case 8: e = asio::error::address_family_not_supported; break;
}
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}
p += 1; // reserved
@ -291,7 +306,8 @@ namespace libtorrent
else
{
(*h)(asio::error::operation_not_supported);
close();
asio::error_code ec;
close(ec);
return;
}
m_buffer.resize(skip_bytes);
@ -305,7 +321,8 @@ namespace libtorrent
if (e)
{
(*h)(e);
close();
asio::error_code ec;
close(ec);
return;
}

View File

@ -287,6 +287,9 @@ namespace libtorrent
#ifndef TORRENT_DISABLE_DHT
bool torrent::should_announce_dht() const
{
if (m_ses.m_listen_sockets.empty()) return false;
if (!m_ses.m_dht) return false;
// don't announce private torrents
if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false;
@ -434,7 +437,8 @@ namespace libtorrent
bind(&torrent::on_announce_disp, self, _1)));
// announce with the local discovery service
m_ses.announce_lsd(m_torrent_file->info_hash());
if (!m_paused)
m_ses.announce_lsd(m_torrent_file->info_hash());
}
else
{
@ -444,13 +448,12 @@ namespace libtorrent
}
#ifndef TORRENT_DISABLE_DHT
if (m_paused) return;
if (!m_ses.m_dht) return;
ptime now = time_now();
if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
{
m_last_dht_announce = now;
// TODO: There should be a way to abort an announce operation on the dht.
// when the torrent is destructed
if (m_ses.m_listen_sockets.empty()) return;
m_ses.m_dht->announce(m_torrent_file->info_hash()
, m_ses.m_listen_sockets.front().external_port
@ -2250,15 +2253,15 @@ namespace libtorrent
#ifndef TORRENT_DISABLE_DHT
// only start the announce if we want to announce with the dht
if (should_announce_dht())
ptime now = time_now();
if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
{
if (m_abort) return;
// force the DHT to reannounce
m_last_dht_announce = time_now() - minutes(15);
m_last_dht_announce = now;
boost::weak_ptr<torrent> self(shared_from_this());
m_announce_timer.expires_from_now(seconds(1));
m_announce_timer.async_wait(m_ses.m_strand.wrap(
bind(&torrent::on_announce_disp, self, _1)));
m_ses.m_dht->announce(m_torrent_file->info_hash()
, m_ses.m_listen_sockets.front().external_port
, m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1)));
}
#endif

View File

@ -306,10 +306,12 @@ namespace libtorrent
namespace
{
bool range_contains(peer_request const& range, peer_request const& req)
bool range_contains(peer_request const& range, peer_request const& req, int piece_size)
{
return range.start <= req.start
&& range.start + range.length >= req.start + req.length;
size_type range_start = size_type(range.piece) * piece_size + range.start;
size_type req_start = size_type(req.piece) * piece_size + req.start;
return range_start <= req_start
&& range_start + range.length >= req_start + req.length;
}
}
@ -470,6 +472,9 @@ namespace libtorrent
}
}
// std::cerr << "REQUESTS: m_requests: " << m_requests.size()
// << " file_requests: " << m_file_requests.size() << std::endl;
torrent_info const& info = t->torrent_file();
if (m_requests.empty() || m_file_requests.empty())
@ -480,16 +485,16 @@ namespace libtorrent
, range_end - range_start);
peer_request front_request = m_requests.front();
/*
size_type rs = size_type(in_range.piece) * info.piece_length() + in_range.start;
size_type re = rs + in_range.length;
size_type fs = size_type(front_request.piece) * info.piece_length() + front_request.start;
size_type fe = fs + front_request.length;
if (fs < rs || fe > re)
{
throw std::runtime_error("invalid range in HTTP response");
}
std::cerr << "RANGE: r = (" << rs << ", " << re << " ) "
"f = (" << fs << ", " << fe << ") "
"file_index = " << file_index << " received_body = " << m_received_body << std::endl;
*/
// skip the http header and the blocks we've already read. The
// http_body.begin is now in sync with the request at the front
// of the request queue
@ -504,11 +509,16 @@ namespace libtorrent
bool range_overlaps_request = in_range.start + in_range.length
> front_request.start + int(m_piece.size());
if (!range_overlaps_request)
{
throw std::runtime_error("invalid range in HTTP response");
}
// if the request is contained in the range (i.e. the entire request
// fits in the range) we should not start a partial piece, since we soon
// will receive enough to call incoming_piece() and pass the read buffer
// directly (in the next loop below).
if (range_overlaps_request && !range_contains(in_range, front_request))
if (range_overlaps_request && !range_contains(in_range, front_request, info.piece_length()))
{
// the start of the next block to receive is stored
// in m_piece. We need to append the rest of that
@ -549,7 +559,7 @@ namespace libtorrent
// report all received blocks to the bittorrent engine
while (!m_requests.empty()
&& range_contains(in_range, m_requests.front())
&& range_contains(in_range, m_requests.front(), info.piece_length())
&& recv_buffer.left() >= m_requests.front().length)
{
peer_request r = m_requests.front();

View File

@ -96,12 +96,7 @@ class movetorrentMenu:
if path:
self.paused_or_not = {}
for unique_id in unique_ids:
self.paused_or_not[unique_id] = self.core.is_user_paused(unique_id)
if not self.paused_or_not[unique_id]:
self.core.set_user_pause(unique_id, True, enforce_queue=False)
self.core.move_storage(unique_id, path)
if not self.paused_or_not[unique_id]:
self.core.set_user_pause(unique_id, False, enforce_queue=False)
def configure(self, window):
import os.path

View File

@ -63,7 +63,7 @@ class plugin_Search:
### Note: All other plugins should use self.interface.toolbar
### when adding items to the toolbar
self.se = ''
self.toolbar = self.interface.wtree.get_widget("tb_right")
self.toolbar = self.interface.wtree.get_widget("tb_left")
self.engines = deluge.pref.Preferences(self.conf_file, False)
self.search_entry = gtk.Entry()
self.search_entry.connect("activate", self.torrent_search)

View File

@ -75,6 +75,5 @@ class webseedMenu:
self.dialog.hide()
if response:
text = self.glade.get_widget("txt_url").get_text().strip()
if common.is_url(text):
if deluge.common.is_url(text):
self.core.add_url_seed(self.unique_ID, text)

View File

@ -37,7 +37,9 @@ 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"
There is support for multiple templates, but just one is included.
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.
@ -203,11 +205,8 @@ class ConfigDialog(gtk.Dialog):
gtk.combo_box_new_text())
self.cache_templates = self.add_widget(_('Cache Templates'),
gtk.CheckButton())
"""
temporary disable for 0.5.7
self.use_https = self.add_widget(_('Use https://'),
self.use_https = self.add_widget(_('https://'),
gtk.CheckButton())
"""
#self.share_downloads = self.add_widget(_('Share Download Directory'),
# gtk.CheckButton())
@ -236,7 +235,7 @@ class ConfigDialog(gtk.Dialog):
# bool(self.config.get("share_downloads")))
self.cache_templates.set_active(self.config.get("cache_templates"))
"""0.5.7.. self.use_https.set_active(self.config.get("use_https"))"""
self.use_https.set_active(self.config.get("use_https"))
self.vbox.pack_start(self.vb, True, True, 0)
self.vb.show_all()
@ -272,7 +271,7 @@ class ConfigDialog(gtk.Dialog):
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())
#0.5.7.. self.config.set("use_https", self.use_https.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

View File

@ -50,7 +50,7 @@ urls = (
"/torrent/stop/(.*)", "torrent_stop",
"/torrent/start/(.*)", "torrent_start",
"/torrent/reannounce/(.*)", "torrent_reannounce",
"/torrent/add", "torrent_add",
"/torrent/add(.*)", "torrent_add",
"/torrent/delete/(.*)", "torrent_delete",
"/torrent/queue/up/(.*)", "torrent_queue_up",
"/torrent/queue/down/(.*)", "torrent_queue_down",
@ -98,21 +98,36 @@ class index:
@deluge_page
@auto_refreshed
def GET(self, name):
vars = web.input(sort=None, order=None)
vars = web.input(sort=None, order=None ,filter=None , category=None)
status_rows = [get_torrent_status(torrent_id)
torrent_list = [get_torrent_status(torrent_id)
for torrent_id in ws.proxy.get_session_state()]
all_torrents = torrent_list[:]
#filter-state
if vars.filter:
torrent_list = filter_torrent_state(torrent_list, vars.filter)
setcookie("filter", vars.filter)
else:
setcookie("filter", "")
#filter-cat
if vars.category:
torrent_list = [t for t in torrent_list if t.category == vars.category]
setcookie("category", vars.category)
else:
setcookie("category", "")
#sorting:
if vars.sort:
status_rows.sort(key=attrgetter(vars.sort))
torrent_list.sort(key=attrgetter(vars.sort))
if vars.order == 'up':
status_rows = reversed(status_rows)
torrent_list = reversed(torrent_list)
setcookie("order", vars.order)
setcookie("sort", vars.sort)
return ws.render.index(status_rows)
return ws.render.index(torrent_list, all_torrents)
class torrent_info:
@deluge_page
@ -162,16 +177,29 @@ class torrent_add:
@check_session
def POST(self, name):
vars = web.input(url = None, torrent = {})
"""
allows:
*posting of url
*posting file-upload
*posting of data as string(for greasemonkey-private)
"""
if vars.url and vars.torrent.filename:
vars = web.input(url = None, torrent = {},
torrent_name=None, torrent_data = None)
torrent_name = vars.torrent_name
torrent_data = vars.torrent_data
if vars.torrent.filename:
torrent_name = vars.torrent.filename
torrent_data = vars.torrent.file.read()
if vars.url and torrent_name:
error_page(_("Choose an url or a torrent, not both."))
if vars.url:
ws.proxy.add_torrent_url(vars.url)
do_redirect()
elif vars.torrent.filename:
data = vars.torrent.file.read()
data_b64 = base64.b64encode(data)
elif torrent_name:
data_b64 = base64.b64encode(torrent_data)
#b64 because of strange bug-reports related to binary data
ws.proxy.add_torrent_filecontent(vars.torrent.filename, data_b64)
do_redirect()
@ -213,14 +241,24 @@ class torrent_delete:
class torrent_queue_up:
@check_session
def POST(self, name):
for torrent_id in sorted(name.split(',')):
#a bit too verbose..
torrent_ids = name.split(',')
torrents = [get_torrent_status(id) for id in torrent_ids]
torrents.sort(lambda x, y : x.queue_pos - y.queue_pos)
torrent_ids = [t.id for t in torrents]
for torrent_id in torrent_ids:
ws.proxy.queue_up(torrent_id)
do_redirect()
class torrent_queue_down:
@check_session
def POST(self, name):
for torrent_id in reversed(sorted(name.split(','))):
#a bit too verbose..
torrent_ids = name.split(',')
torrents = [get_torrent_status(id) for id in torrent_ids]
torrents.sort(lambda x, y : x.queue_pos - y.queue_pos)
torrent_ids = [t.id for t in torrents]
for torrent_id in reversed(torrent_ids):
ws.proxy.queue_down(torrent_id)
do_redirect()

View File

@ -1 +1 @@
143
160

View File

@ -1,13 +1,18 @@
from __future__ import with_statement
import os
import re
template_dir = '~/prj/WebUi/templates/deluge'
template_dir = os.path.expanduser(template_dir )
template_dirs = ['~/prj/WebUi/templates/deluge',
'~/prj/WebUi/templates/advanced']
template_dirs = [os.path.expanduser(template_dir ) for template_dir in template_dirs]
files = [os.path.join(template_dir,fname)
for fname in os.listdir(template_dir)
if fname.endswith('.html')]
files = []
for template_dir in template_dirs:
files += [os.path.join(template_dir,fname)
for fname in os.listdir(template_dir)
if fname.endswith('.html')]
all_strings = []
for filename in files:

View File

@ -1,5 +1,6 @@
_('# Of Files')
_('About')
_('Add')
_('Add Torrent')
_('Add torrent')
_('Apply')
@ -13,6 +14,7 @@ _('Delete .torrent file')
_('Delete downloaded files.')
_('Details')
_('Disable')
_('Down')
_('Down Speed')
_('Download')
_('Downloaded')
@ -27,19 +29,20 @@ _('Next Announce')
_('Off')
_('Password')
_('Password is invalid,try again')
_('Pause')
_('Pause all')
_('Peers')
_('Pieces')
_('Progress')
_('Queue Down')
_('Queue Position')
_('Queue Up')
_('Queue pos:')
_('Ratio')
_('Reannounce')
_('Refresh page every:')
_('Remove')
_('Remove %s ')
_('Remove %s?')
_('Remove torrent')
_('Resume')
_('Resume all')
_('Seeders')
_('Set')
@ -47,11 +50,13 @@ _('Set Timeout')
_('Share Ratio')
_('Size')
_('Speed')
_('Start')
_('Submit')
_('Torrent list')
_('Total Size')
_('Tracker')
_('Tracker Status')
_('Up')
_('Up Speed')
_('Upload')
_('Upload torrent')

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA1sPXr1O6l2J9NAEvEYQ/JFDSVcJHh9YxP7kPdjsu7k9Ih845
BHMX52A3Ypbe5MHe2bCj/8dRYCixRdF1KUTAKXdzc7mw9prgf3sS3RvmfcRsln6u
x7XRg7YprZJ46hFmcHiUPRgtTFLuFO2YWBnqxu/caTtAxx3PdoK6LDVnuVjHYofC
8uD4A9k6yL/jj3Yrkf8WYQqJ6pJcMAz/2c8ZXlBuiUCb9j5xKTzYoJaiUkKN2YrA
hoxRxfI7Zc7MH2yWw8/fTZJbGXo8nrfek7coSE7yQS1M6ciwkYk5VO2mBVJBJgAT
QUR/jGfLzEqNKXghQ564v9wmuFmUMd99a0tkVwIDAQABAoIBACID6sluLYOEqefu
uBHCLG4IDwheOQ4esrYxDW3gedJs5EP+ObGmuQaAisUmuC7rNeysuYzteMoOJ+Wz
AyeCKB1pOfP+WTT12tDWIWq73InW7ov3jJ89AO4nj/pZ1KTeFKeDsZbrmWEZUXQn
HZX2pOTVYMeaBuyCoDVZBzuxSbhlON4wS6ClMhem+eBOxg351CDTZa2cbq7Ffcos
VP7LY2ORQYNDTQSLguV/dJrFSotB8Eoz2xIpg5XR7msp6lzPzyAd+Aoz/T1lYxCY
IFZCJYKnIpgoYQvmtUlhQrdD8P0J4Kth7I8NgkWvXCKazQjhpUm+wojLKD0G7Kcz
9znIV+ECgYEA+qfp1C8jWbaAn1yAeORUA9aB6aGIURfOpZjnCvtMWM0Nu0nAJYDv
X7L5GRa1ulfKhfUG1Jv/ynMKXYuBUDhyccYLpP7BHpd29Arr7YAgb52KaD1PoKNa
Z45c61dj4sFoCmJEbDoL21UGb0LX3mc4XzPzwWs8AKfLW4aZh1NwCisCgYEA21gJ
Hy3egBgMT9+nVjqsgtIXgJOnzQRhvRwT7IFf392ZyFi8iM+pDUsx1yj0zSG4XNPw
NY8VtZuTBUlG73RKcrrz31jhCMfLCnoRkQeweZv0QWzbLU3V8DleUYdjFc/t0me5
4NBR9lBlwYHgyU3GQ814vum+m0IAH0Ng1UxAVIUCgYAFOHwZTEYLN07kgtO2MOND
FTOtfwzMy5clQdMGGofTjanMjdOvtEjIEH05tYxhbjSsp5bV1M32FIFRw3cVCafw
kLRrYlb5YSQ8HwIc9z81s+1PEH/ZE63tXDy5Nh/BeE/Hb5aHPopCrjmtFZJTcojt
CrL4A1jDlrsYk+wcsnMx8wKBgEhJJQhvd2pDgps4G8+hGoUqc7Bd+OjpzsQh4rcI
k+4U+7847zkvJolJBK3hw3tu53FAL2OXOhJVqQgO9B+p9XcGAaTTh6X7IgDb5bok
DJanPMHq+/hcNGssnNbFhXQEyF2U7X8XaEuCh2ZURR5SUUq7BlX0dmp4P84NyHXC
4Vh5AoGAZYWkXxQUGzVm+H3fPpmETWGRNFDTimzi+6N+/uHkqkiDa3LGSnabmKh+
voKm//DUjEVGlAZ3CGOjO/5SlZc/zjkgh1vg7KOU4x7DqVOuZjom5Tx3ZI4xVVVt
tVtvK0qjzUTVcwAQALN/PNak+gs9534e954rmA9kmc3xBe4ho9M=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDlzCCAn+gAwIBAgIJAPnW/GEzRy8xMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNV
BAYTAkFVMRUwEwYDVQQIEwxUaGUgSW50ZXJuZXQxFTATBgNVBAoTDERlbHVnZSBX
ZWJ1aTAeFw0wNzExMjQxMDAzNDRaFw0wODExMjMxMDAzNDRaMDsxCzAJBgNVBAYT
AkFVMRUwEwYDVQQIEwxUaGUgSW50ZXJuZXQxFTATBgNVBAoTDERlbHVnZSBXZWJ1
aTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANbD169TupdifTQBLxGE
PyRQ0lXCR4fWMT+5D3Y7Lu5PSIfOOQRzF+dgN2KW3uTB3tmwo//HUWAosUXRdSlE
wCl3c3O5sPaa4H97Et0b5n3EbJZ+rse10YO2Ka2SeOoRZnB4lD0YLUxS7hTtmFgZ
6sbv3Gk7QMcdz3aCuiw1Z7lYx2KHwvLg+APZOsi/4492K5H/FmEKieqSXDAM/9nP
GV5QbolAm/Y+cSk82KCWolJCjdmKwIaMUcXyO2XOzB9slsPP302SWxl6PJ633pO3
KEhO8kEtTOnIsJGJOVTtpgVSQSYAE0FEf4xny8xKjSl4IUOeuL/cJrhZlDHffWtL
ZFcCAwEAAaOBnTCBmjAdBgNVHQ4EFgQU1BbX1/4WtAKRKmWI1gqryIoj7BQwawYD
VR0jBGQwYoAU1BbX1/4WtAKRKmWI1gqryIoj7BShP6Q9MDsxCzAJBgNVBAYTAkFV
MRUwEwYDVQQIEwxUaGUgSW50ZXJuZXQxFTATBgNVBAoTDERlbHVnZSBXZWJ1aYIJ
APnW/GEzRy8xMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAEoiSz5x
hRCplxUG34g3F5yJe0QboqzJ/XmECfO80a980C/WVeivM2Kb1uafsKNp+WK7wD8g
mei+todYXG+fD8WmG41LG87Xi2Xe4SlAcemEpGcC5F1bpCdvqnVAWFnqoF88FOHx
NDlrq5H5lhMH9wVrX9qJvxL+StaDJ0sFk4kMGWEN+bdSYfFdBQzF903nPtm+PlvO
1Uo6gCuRTMYM5J1DC/GpNpo/Fzrkgm8mMf1MYy3rljiNgMt2rnxhtwi6jugwyMui
id6Of6gYAtvhi7kmaUpdI5PHO35dqRK7pHXH+YXaulosCPw/+bSRptFTykeEMrBj
CzotqJ+74MwXZyM=
-----END CERTIFICATE-----

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 B

View File

@ -4,7 +4,10 @@
Theme Name: Simple
Theme URI: http://deluge-torrent.org
Description: Deluge Theme
Description: Deluge Theme
Version: 1.0
-----------------------------------------------------------
*/
@ -55,9 +58,6 @@ tr.torrent_table_selected {
#main form table tr th {
background: #1f3044;
font-size: 16px;
#main form table tr th {
background: #1f3044;
font-size: 16px;
border: 0px;
white-space: nowrap;
}
@ -71,4 +71,21 @@ body.inner {
#main form table tr th a {
color: #8fa6c3;
font-size: 16px;
font-size: 16px;
white-space: nowrap;
}
#main form table tr th a, a:active, a:visited { color: #8fa6c3; text-decoration: none; }
#main form table tr th a:hover {color: #fff; text-decoration: underline;}
#main form table tr td a {
color: #fff;
font-size: 12px;
white-space: nowrap;
}
#main form table tr td a, a:active, a:visited { color: #fff; text-decoration: none;}
#main form table tr td a:hover {color: #fff; text-decoration: underline;}
#main a {
color: #fff;
font-size: 12px;

View File

@ -1,14 +1,49 @@
$def with (torrent_list)
$def with (torrent_list, all_torrents)
$:render.header(_('Torrent list'))
<div class="panel" id="toolbar">
<a href='/torrent/add' >[Add]</a>
<a href='#' onclick=' toolbar_post("/torrent/queue/up/")'>[Up]</a>
<a href='#' onclick=' toolbar_post("/torrent/queue/down/")'>[Down]</a>
<a href='#' onclick=' toolbar_get("/torrent/delete/")'>[Delete]</a>
<a href='#' onclick=' toolbar_get("/torrent/info/")'>[Info]</a>
<a href='#' onclick=' toolbar_post("/torrent/stop/")'>[Pause]</a>
<a href='#' onclick=' toolbar_post("/torrent/start/")'>[Start]</a>
<a class='toolbar_btn' href="#"
onclick='toolbar_get("/torrent/add/",0)'
title='$_("Add")'><img class='toolbar_btn'
src='/static/images/tango/list-add.png'></a>
<a class='toolbar_btn' href="#"
onclick='toolbar_get("/torrent/delete/",2)'><img class='toolbar_btn'
src='/static/images/tango/list-remove.png'
title='$_("Remove")'></a>
<a class='toolbar_btn' href="#"
onclick='toolbar_post("/torrent/stop/",2)'
title='$_("Pause")'><img class='toolbar_btn'
src='/static/images/tango/pause.png'
></a>
<a class='toolbar_btn' href="#"
onclick='toolbar_post("/torrent/start/",2)'
title='$_("Start")'><img class='toolbar_btn'
src='/static/images/tango/start.png'></a>
<a class='toolbar_btn' href="#"
onclick='toolbar_post("/torrent/queue/up/",2)'
title='$_("Up")'><img class='toolbar_btn'
src='/static/images/tango/queue-up.png'></a>
<a class='toolbar_btn' href="#"
onclick='toolbar_post("/torrent/queue/down/",2)'
title='$_("Down")'><img class='toolbar_btn'
src='/static/images/tango/queue-down.png'></a>
<a class='toolbar_btn' href="#"
onclick='toolbar_get("/torrent/info/",1)'
title='$_("Details")'><img class='toolbar_btn'
src='/static/images/tango/details.png'></a>
$:category_tabs(all_torrents)
</div>
<!--
@ -21,10 +56,10 @@ $#end
-->
<form action="/torrent/pause" method="POST">
<div id="tableContainer" class="tableContainer">
<table class="torrent_list" border=1>
<table class="torrent_list" border=1 id="torrent_list">
<thead class="fixedHeader">
<tr>
$:(sort_head('calc_state_str', 'S'))
@ -32,6 +67,7 @@ $#end
$:(sort_head('name', _('Name')))
$:(sort_head('total_size', _('Size')))
$:(sort_head('progress', _('Progress')))
$:(sort_head('category', _('Tracker')))
$:(sort_head('num_seeds', _('Seeders')))
$:(sort_head('num_peers', _('Peers')))
$:(sort_head('download_rate', _('Download')))
@ -45,11 +81,14 @@ $#end
$#4-space indentation is mandatory for for-loops in templetor!
$for torrent in torrent_list:
<tr class="torrent_table" onclick="on_click_row(event, '$torrent.id')" id="torrent_$torrent.id">
<td><input type="image"
src="/static/images/$(torrent.calc_state_str)16.png"
name="$torrent.action" value="$torrent.id"
onclick="state.row_js_continue = false;">
</td>
<td>
<form action="/torrent/$torrent.action/$torrent.id" method="POST"
class="pause_resume">
<input type="image"
src="/static/images/$(torrent.calc_state_str)16.png"
name="pauseresume" value="submit" />
</form>
</td>
<td>$torrent.queue_pos</td>
<td style="width:100px; overflow:hidden;white-space: nowrap">
$(crop(torrent.name, 40))</td>
@ -61,10 +100,21 @@ $for torrent in torrent_list:
</div>
</div>
</td>
<td>$torrent.category</td>
<td>$torrent.num_seeds ($torrent.total_seeds)</td>
<td>$torrent.num_peers ($torrent.total_peers)</td>
<td>$fspeed(torrent.download_rate)</td>
<td>$fspeed(torrent.upload_rate)</td>
<td>
$if (torrent.download_rate):
$fspeed(torrent.download_rate)
$else:
&nbsp;
</td>
<td>
$if (torrent.upload_rate):
$fspeed(torrent.upload_rate)
$else:
&nbsp;
</td>
<td>$torrent.eta</td>
<td>$("%.3f" % torrent.distributed_copies)</td>
<td>$("%.3f" % torrent.ratio)</td\>
@ -73,7 +123,6 @@ $for torrent in torrent_list:
</table>
</div>
</form>
$:part_stats()
@ -84,6 +133,8 @@ $:part_stats()
</iframe>
</div>
<br />
<script language='javascript'>

View File

@ -0,0 +1,37 @@
$def with (filter_tabs, category_tabs)
<form method="GET" id="category_form">
<input type="hidden" name="sort" value="$get('sort')">
<input type="hidden" name="order" value="$get('order')">
<select name='filter' id='filter'
onchange="document.getElementById('category_form').submit()"
title="$_('Filter on state')">
$for tab in filter_tabs:
<option value="$tab.filter"
$if tab.filter == get('filter'):
selected
>
$tab.title
</option>
</select>
<select name='category' id='category'
onchange="document.getElementById('category_form').submit()"
title="$_('Filter on Tracker')">
$for tab in category_tabs:
<option value="$tab.category"
$if tab.category == get('category'):
selected
>
$tab.title
</option>
</select>
<input type="image" id='toolbar_refresh'
src='/static/images/tango/view-refresh.png'
title='$_('Refresh')'
>
</form>

View File

@ -1,16 +1,32 @@
/*
/*
-----------------------------------------------------------
Theme Name: Simple
Theme URI: http://deluge-torrent.org
Description: Deluge Theme
Version: 1.0
Description: Deluge Theme
-----------------------------------------------------------
*/
*/
BODY {
background: #304663 url(../../static/images/simple_bg.jpg) repeat-x;
font-family: Bitstream Vera,Verdana;
font-size: 10pt;
margin: 0;
padding:0;
border:0;
}
/* GENERIC STYLES */
a img {border: 0px}
hr {color: #627082; margin: 15px 0 15px 0;}
td {font-family: Bitstream Vera,Verdana;}
tr {font-family: Bitstream Vera,Verdana;}
table {font-family: Bitstream Vera,Verdana;}
div {font-family: Bitstream Vera,Verdana;}
/* STRUCTURE */
@ -92,6 +108,12 @@ body.inner {
.info {
text-align: right;
padding: 0 50px 0 0;
color: #8fa6c3;
font-size: 16px;
letter-spacing: 4px;
font-weight: bold;
}
.title {
color: #dce4ee;
font-size: 32px;
@ -110,15 +132,18 @@ body.inner {
border:1px solid #68a;
background: #99acc3;
.title {
color: #000;
/*vertical-align:middle;*/
font-size: 32px;
padding: 10px 50px 0 0;
-moz-border-radius:5px;
/*margin-top:5px;*/
}
input:hover {
background-color:#68a;
}
TEXTAREA{
border:1px solid #23344b;
@ -128,9 +153,95 @@ body.inner {
.footertext a { color: #c0c0c0; text-decoration:none;}
.footertext a:visited { color: #c0c0c0; text-decoration:none;}
.footertext a:active { color: #c0c0c0; text-decoration:none;}
.footertext a:hover {color: #fff; text-decoration: underline;}
.footertext {
text-align: center;
padding: 60px 0 0 0;
font-size: 8pt;
left: -100px;
font-family: Bitstream Vera,Verdana;
color: #fff;
position: relative;
}
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
div.progress_bar{
background-color:#4573a5;
/*color:blue;*/
-moz-border-radius:5px; /*ff only setting*/
}
div.progress_bar_outer { /*used in table-view*/
width:150px;
}
td.progress_bar {
white-space: nowrap;
}
td.info_label {
font-weight: bold;
}
td {
font-size: 10pt;
color: #d1dae5;
white-space: nowrap;
}
tr {
font-size: 10pt;
color: #d1dae5;
}
div.panel {
padding:10px;
width:750px;
background-color: #37506f;
-moz-border-radius:10px; /*ff-only!*/
margin-top:10px;
margin-bottom:10px;
}
/*New styles:*/
div.deluge_button {
display:inline;
}
form.deluge_button {
display:inline;
}
button.deluge_button {
background-color: #37506f;
border:1px solid #68a;
background: #99acc3;
color: #000;
vertical-align:middle;
-moz-border-radius:7px;
}
button.deluge_button:hover {
background-color:#68a;
}
div.error {
background-color:#FFFFFF;
color:#AA0000;
font-weight:bold;
-moz-border-radius:10px;
width:200px;
margin-bottom:20px;
padding:10px;

View File

@ -29,10 +29,17 @@ function on_click_row(e,id) {
function on_click_row_js(e, id) {
/*real onClick event*/
if (!e.ctrlKey) {
deselect_rows();
deselect_all_rows();
select_row(id);
open_inner_details(id);
}
else if (state.selected_rows.indexOf(id) != -1) {
deselect_row(id);
}
else{
select_row(id);
open_inner_details(id);
}
select_row(id);
open_inner_details(id);
}
function select_row(id){
@ -43,19 +50,30 @@ function select_row(id){
setCookie('selected_rows',state.selected_rows);
}
}
function deselect_rows(){
for (i in state.selected_rows) {
deselect_row(state.selected_rows[i]);
}
state.selected_rows = new Array();
}
function deselect_row(id){
var row = get_row(id);
if (row) {
row.className = 'torrent_table'
/*TODO : remove from state.selected_rows*/
/*remove from state.selected_rows*/
var idx = state.selected_rows.indexOf(id);
state.selected_rows.splice(idx,1);
setCookie('selected_rows',state.selected_rows);
}
}
function deselect_all_rows(){
/*unbind state.selected_rows from for..in:
there must be a better way to do this*/
var a = new Array()
for (i in state.selected_rows) {
a[a.length] = state.selected_rows[i];
}
for (i in a){
deselect_row(a[i]);
}
}
function reselect_rows(){
var selected_rows = getCookie('selected_rows').split(',');
for (i in getCookie('selected_rows')) {
@ -79,19 +97,24 @@ function on_click_do_nothing(e, id){
on_click_action = on_click_do_nothing;
/*toobar buttons, */
function toolbar_post(url) {
/*this feels hacky, but it's the only way i know of*/
var ids = state.selected_rows.join(',');
var form = $('toolbar_form');
form.action = url +ids;
form.submit();
function toolbar_post(url, selected) {
if ((!selected) || (state.selected_rows.length > 0)) {
var ids = state.selected_rows.join(',');
var form = $('toolbar_form');
form.action = url +ids;
form.submit();
}
return false;
}
function toolbar_get(url) {
/*this feels hacky, but it's the only way i know of*/
var ids = state.selected_rows.join(',');
window.location.href = url +ids;
function toolbar_get(url , selected) {
if (!selected) {
window.location.href = url
}
else if (state.selected_rows.length > 0) {
var ids = state.selected_rows.join(',');
window.location.href = url +ids;
}
return false;
}

View File

@ -1,7 +1,7 @@
$def with (torrent_list)
$def with (torrent_list, all_torrents)
$:render.header(_('Torrent list'))
<table class="torrent_list" border=1>
<table class="torrent_list" border=0 id='torrent_table'>
<tr>
$:(sort_head('calc_state_str', 'S'))
$:(sort_head('queue_pos', '#'))
@ -20,13 +20,10 @@ $#4-space indentation is mandatory for for-loops in templetor!
$for torrent in torrent_list:
<tr class="torrent_table" id="torrent_$torrent.id">
<td>
<form action="/torrent/$torrent.action/$torrent.id" method="POST">
<form action="/torrent/$torrent.action/$torrent.id" method="POST" class="pause_resume">
<input type="image"
src="/static/images/$(torrent.calc_state_str)16.png"
name="pauseresume" value="submit" />
</form>
</td>
name="pauseresume" value="submit" /></form></td>
<td>$torrent.queue_pos</td>
<td style="width:100px; overflow:hidden;white-space: nowrap">
<a href="/torrent/info/$torrent.id" >
@ -53,8 +50,8 @@ $for torrent in torrent_list:
<div class="panel">
$: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', '/pause_all', _('Pause all'), 'tango/pause.png')
$:render.part_button('POST', '/resume_all', _('Resume all'), 'tango/start.png')
<!--$:render.part_button('POST', '/logout', _('Logout'), 'tango/system-log-out.png')-->
</div>

View File

@ -1,6 +1,6 @@
$def with (column_id, column_name, order, active_up, active_down)
<th class="torrent_table">
<a href="/index?sort=$column_id&order=$order">
<a href="/index?sort=$column_id&order=$order&filter=$get('filter')&category=$get('category')">
$column_name\
$if active_up:
<img src="/static/images/tango/up.png" />

View File

@ -68,10 +68,10 @@ $fspeed(torrent.download_rate)</td></td></tr>
<td class="info_value">$torrent.num_files</td></tr>
<tr><td class="info_label">$_('Tracker'):</td>
<td class="info_value">$(crop(torrent.tracker, 30))</td></tr>
<td class="info_value" title="$torrent.tracker">$(crop(torrent.tracker, 30))</td></tr>
<tr><td class="info_label">$_('Tracker Status'):</td>
<td class="info_value">$torrent.tracker_status </td></tr>
<td class="info_value" title="$torrent.tracker_status">$(crop(torrent.tracker_status, 30)) </td></tr>
<tr><td class="info_label">$_('Next Announce'):</td>
<td class="info_value">$torrent.next_announce </td></tr>

View File

@ -12,7 +12,7 @@ $else:
$:render.part_button('POST', '/torrent/stop/' + str(torrent.id), _('Pause'), 'tango/pause.png')
$:render.part_button('GET', '/torrent/delete/' + str(torrent.id), _('Remove'), 'tango/user-trash.png')
$:render.part_button('GET', '/torrent/delete/' + str(torrent.id), _('Remove'), 'tango/list-remove.png')
$:render.part_button('POST', '/torrent/reannounce/' + str(torrent.id), _('Reannounce'), 'tango/view-refresh.png')
$:render.part_button('POST', '/torrent/queue/up/' + str(torrent.id), _('Queue Up'), 'tango/queue-up.png')

View File

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

View File

@ -1,12 +0,0 @@
$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

@ -1,42 +0,0 @@
$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

@ -211,7 +211,7 @@ class TestIntegration(TestWebUiBase):
#delete all, nice use case for refactoring delete..
torrent_ids = ws.proxy.get_session_state()
for torrent in torrent_ids:
ws.proxy.remove_torrent(torrent, False, False)
ws.proxy.remove_torrent([torrent], False, False)
torrent_ids = ws.proxy.get_session_state()
self.assertEqual(torrent_ids, [])
@ -237,14 +237,14 @@ class TestIntegration(TestWebUiBase):
#pause all
self.assert_303('/pause_all','/index', post=1)
#pause worked?
pause_status = [get_status(id)["paused"] for id in ws.proxy.get_session_state()]
pause_status = [get_status(id)["user_paused"] for id in ws.proxy.get_session_state()]
for paused in pause_status:
self.assertEqual(paused, True)
#resume all
self.assert_303('/resume_all','/index', post=1)
#resume worked?
pause_status = [get_status(id)["paused"] for id in ws.proxy.get_session_state()]
pause_status = [get_status(id)["user_paused"] for id in ws.proxy.get_session_state()]
for paused in pause_status:
self.assertEqual(paused,False)
#pause again.
@ -253,10 +253,10 @@ class TestIntegration(TestWebUiBase):
torrent_id = self.first_torrent_id
#single resume.
self.assert_303('/torrent/start/%s' % torrent_id ,'/index', post=1)
self.assertEqual(get_status(torrent_id)["paused"] ,False)
self.assertEqual(get_status(torrent_id)["user_paused"] ,False)
#single pause
self.assert_303('/torrent/stop/%s' % torrent_id,'/index', post=1)
self.assertEqual(get_status(torrent_id)["paused"] , True)
self.assertEqual(get_status(torrent_id)["user_paused"] , True)
def testQueue(self):
#find last:

View File

@ -1,5 +1,5 @@
revision-id: mvoncken@gmail.com-20070930083408-sv8mo0mi1rbjnfvk
date: 2007-11-21 15:10:08 +0200
build-date: 2007-11-21 15:34:50 +0200
revno: 143
date: 2007-11-26 15:10:08 +0200
build-date: 2007-11-26 15:34:50 +0200
revno: 160
branch-nick: WebUi

View File

@ -42,7 +42,7 @@ import pickle
import sys
from webpy022 import template
random.seed()
path = os.path.dirname(__file__)
webui_path = os.path.dirname(__file__)
ENV = 'UNKNOWN'
@ -68,11 +68,11 @@ class subclassed_render(object):
"""
def __init__(self, template_dirname, cache=False):
self.base_template = template.render(
os.path.join(path, 'templates/deluge/'),
os.path.join(webui_path, 'templates/deluge/'),
cache=cache)
self.sub_template = template.render(
os.path.join(path, 'templates/%s/' % template_dirname),
os.path.join(webui_path, 'templates/%s/' % template_dirname),
cache=cache)
def __getattr__(self, attr):

View File

@ -56,6 +56,7 @@ from operator import attrgetter
import datetime
import pickle
from md5 import md5
from urlparse import urlparse
from deluge import common
from webserver_common import REVNO, VERSION
@ -97,13 +98,20 @@ def do_redirect():
"""for redirects after a POST"""
vars = web.input(redir = None)
ck = cookies()
url_vars = {}
if vars.redir:
seeother(vars.redir)
elif ("order" in ck and "sort" in ck):
seeother(url("/index", sort=ck['sort'], order=ck['order']))
else:
seeother(url("/index"))
return
#todo:cleanup
if ("order" in ck and "sort" in ck):
url_vars.update({'sort':ck['sort'] ,'order':ck['order'] })
if ("filter" in ck) and ck['filter']:
url_vars['filter'] = ck['filter']
if ("category" in ck) and ck['category']:
url_vars['category'] = ck['category']
seeother(url("/index", **url_vars))
def error_page(error):
web.header("Content-Type", "text/html; charset=utf-8")
@ -211,6 +219,12 @@ def get_torrent_status(torrent_id):
status["id"] = torrent_id
url = urlparse(status.tracker)
if hasattr(url,'hostname'):
status.category = url.hostname or 'unknown'
else:
status.category = 'No-tracker'
#for naming the status-images
status.calc_state_str = "downloading"
if status.paused:
@ -219,7 +233,7 @@ def get_torrent_status(torrent_id):
status.calc_state_str = "seeding"
#action for torrent_pause
if status.calc_state_str == "inactive":
if status.user_paused:
status.action = "start"
else:
status.action = "stop"
@ -250,9 +264,59 @@ def get_torrent_status(torrent_id):
raise Exception('Non Unicode for key:%s' % (k, ))
return status
def get_categories(torrent_list):
trackers = [(torrent['category'] or 'unknown') for torrent in torrent_list]
categories = {}
for tracker in trackers:
categories[tracker] = categories.get(tracker,0) + 1
return categories
def filter_torrent_state(torrent_list,filter_name):
filters = {
'downloading': lambda t: (not t.paused and not t.is_seed)
,'queued':lambda t: (t.paused and not t.user_paused)
,'paused':lambda t: (t.user_paused)
,'seeding':lambda t:(t.is_seed and not t.paused )
}
filter_func = filters[filter_name]
return [t for t in torrent_list if filter_func(t)]
#/utils
#template-defs:
def category_tabs(torrent_list):
categories = get_categories(torrent_list)
filter_tabs = [Storage(title='All (%s)' % len(torrent_list),
filter=None, category=None)]
#static filters
for title, filter_name in [
(_('Downloading'),'downloading') ,
(_('Queued'),'queued') ,
(_('Paused'),'paused') ,
(_('Seeding'),'seeding')
]:
title += ' (%s)' % (
len(filter_torrent_state(torrent_list, filter_name)), )
filter_tabs.append(Storage(title=title, filter=filter_name))
categories = [x for x in get_categories(torrent_list).iteritems()]
categories.sort()
#trackers:
category_tabs = []
category_tabs.append(
Storage(title=_('Trackers'),category=None))
for title,count in categories:
category = title
title += ' (%s)' % (count, )
category_tabs.append(Storage(title=title, category=category))
return ws.render.part_categories(filter_tabs, category_tabs)
def template_crop(text, end):
if len(text) > end:
return text[0:end - 3] + '...'
@ -283,6 +347,7 @@ def get_config(var):
template.Template.globals.update({
'sort_head': template_sort_head,
'part_stats':template_part_stats,
'category_tabs':category_tabs,
'crop': template_crop,
'_': _ , #gettext/translations
'str': str, #because % in templetor is broken.
@ -295,7 +360,6 @@ template.Template.globals.update({
'rev': 'rev.%s' % (REVNO, ),
'version': VERSION,
'getcookie':getcookie,
'js_enabled': lambda : ws.config.get('use_javascript'),
'get': lambda (var): getattr(web.input(**{var:None}), var) # unreadable :-(
})
#/template-defs
@ -304,14 +368,15 @@ def create_webserver(urls, methods):
from webpy022.request import webpyfunc
from webpy022 import webapi
from gtk_cherrypy_wsgiserver import CherryPyWSGIServer
import os
func = webapi.wsgifunc(webpyfunc(urls, methods, False))
server_address=("0.0.0.0", int(ws.config.get('port')))
server = CherryPyWSGIServer(server_address, func, server_name="localhost")
if ws.config.get('use_https'):
server.ssl_certificate = ws.config.get('ssl_certificate')
server.ssl_private_key = ws.config.get('ssl_private_key')
server.ssl_certificate = os.path.join(ws.webui_path,'ssl/deluge.pem')
server.ssl_private_key = os.path.join(ws.webui_path,'ssl/deluge.key')
print "http://%s:%d/" % server_address
return server
@ -321,4 +386,5 @@ __all__ = ['deluge_page_noauth', 'deluge_page', 'remote',
'auto_refreshed', 'check_session',
'do_redirect', 'error_page','start_session','getcookie'
,'setcookie','create_webserver','end_session',
'get_torrent_status', 'check_pwd','static_handler']
'get_torrent_status', 'check_pwd','static_handler','get_categories'
,'template','filter_torrent_state']

1749
po/ar.po

File diff suppressed because it is too large Load Diff

1681
po/ast.po

File diff suppressed because it is too large Load Diff

1798
po/bg.po

File diff suppressed because it is too large Load Diff

2426
po/bs.po Normal file

File diff suppressed because it is too large Load Diff

3018
po/ca.po

File diff suppressed because it is too large Load Diff

1749
po/cs.po

File diff suppressed because it is too large Load Diff

2028
po/da.po

File diff suppressed because it is too large Load Diff

1837
po/de.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1628
po/el.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1681
po/eo.po

File diff suppressed because it is too large Load Diff

1795
po/es.po

File diff suppressed because it is too large Load Diff

1688
po/et.po

File diff suppressed because it is too large Load Diff

1681
po/eu.po

File diff suppressed because it is too large Load Diff

1777
po/fi.po

File diff suppressed because it is too large Load Diff

1925
po/fr.po

File diff suppressed because it is too large Load Diff

1705
po/gl.po

File diff suppressed because it is too large Load Diff

1752
po/he.po

File diff suppressed because it is too large Load Diff

2426
po/hi.po Normal file

File diff suppressed because it is too large Load Diff

1724
po/hr.po

File diff suppressed because it is too large Load Diff

1939
po/hu.po

File diff suppressed because it is too large Load Diff

1717
po/id.po

File diff suppressed because it is too large Load Diff

1681
po/is.po

File diff suppressed because it is too large Load Diff

2214
po/it.po

File diff suppressed because it is too large Load Diff

1683
po/ja.po

File diff suppressed because it is too large Load Diff

2053
po/ka.po

File diff suppressed because it is too large Load Diff

1683
po/ko.po

File diff suppressed because it is too large Load Diff

1687
po/ku.po

File diff suppressed because it is too large Load Diff

1681
po/la.po

File diff suppressed because it is too large Load Diff

1706
po/lt.po

File diff suppressed because it is too large Load Diff

1845
po/lv.po

File diff suppressed because it is too large Load Diff

2752
po/mk.po

File diff suppressed because it is too large Load Diff

1759
po/ms.po

File diff suppressed because it is too large Load Diff

1814
po/nb.po

File diff suppressed because it is too large Load Diff

2426
po/nds.po Normal file

File diff suppressed because it is too large Load Diff

1890
po/nl.po

File diff suppressed because it is too large Load Diff

1775
po/pl.po

File diff suppressed because it is too large Load Diff

2161
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1821
po/ro.po

File diff suppressed because it is too large Load Diff

1966
po/ru.po

File diff suppressed because it is too large Load Diff

1681
po/si.po

File diff suppressed because it is too large Load Diff

1921
po/sk.po

File diff suppressed because it is too large Load Diff

1893
po/sl.po

File diff suppressed because it is too large Load Diff

2001
po/sr.po

File diff suppressed because it is too large Load Diff

2165
po/sv.po

File diff suppressed because it is too large Load Diff

1681
po/ta.po

File diff suppressed because it is too large Load Diff

1681
po/tlh.po

File diff suppressed because it is too large Load Diff

1593
po/tr.po

File diff suppressed because it is too large Load Diff

1681
po/uk.po

File diff suppressed because it is too large Load Diff

1717
po/vi.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More