summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config11
-rw-r--r--module/web/ServerThread.py15
-rw-r--r--module/web/WebServer.py374
-rw-r--r--module/web/ajax/__init__.py (renamed from module/web/__init__.py)0
-rw-r--r--module/web/ajax/models.py3
-rw-r--r--module/web/ajax/tests.py23
-rw-r--r--module/web/ajax/urls.py0
-rw-r--r--module/web/ajax/views.py1
-rw-r--r--module/web/bottle.py1231
-rw-r--r--module/web/main.html29
-rw-r--r--module/web/main.js42
-rw-r--r--module/web/manage.py12
-rw-r--r--module/web/media/css/default.css145
-rw-r--r--module/web/media/css/window.css (renamed from module/web/static/window.css)0
-rw-r--r--module/web/media/img/Button-Add-grey.png (renamed from module/web/static/default/Button-Add-grey.png)bin2112 -> 2112 bytes
-rw-r--r--module/web/media/img/Button-Add.png (renamed from module/web/static/default/Button-Add.png)bin2110 -> 2110 bytes
-rw-r--r--module/web/media/img/Button-Pause-grey.png (renamed from module/web/static/default/Button-Pause-grey.png)bin1932 -> 1932 bytes
-rw-r--r--module/web/media/img/Button-Pause.png (renamed from module/web/static/default/Button-Pause.png)bin2146 -> 2146 bytes
-rw-r--r--module/web/media/img/Button-Play-grey.png (renamed from module/web/static/default/Button-Play-grey.png)bin1938 -> 1938 bytes
-rw-r--r--module/web/media/img/Button-Play.png (renamed from module/web/static/default/Button-Play.png)bin2023 -> 2023 bytes
-rw-r--r--module/web/media/img/big_button.gif (renamed from module/web/static/window/big_button.gif)bin1905 -> 1905 bytes
-rw-r--r--module/web/media/img/big_button_over.gif (renamed from module/web/static/window/big_button_over.gif)bin728 -> 728 bytes
-rw-r--r--module/web/media/img/body.png (renamed from module/web/static/window/body.png)bin402 -> 402 bytes
-rw-r--r--module/web/media/img/closebtn.gif (renamed from module/web/static/window/closebtn.gif)bin254 -> 254 bytes
-rw-r--r--module/web/media/img/drag_corner.gif (renamed from module/web/static/window/drag_corner.gif)bin76 -> 76 bytes
-rw-r--r--module/web/media/img/full.png (renamed from module/web/static/window/full.png)bin3543 -> 3543 bytes
-rw-r--r--module/web/media/img/head-login.png (renamed from module/web/static/default/head-login.png)bin1288 -> 1288 bytes
-rw-r--r--module/web/media/img/head-menu-development.png (renamed from module/web/static/default/head-menu-development.png)bin1324 -> 1324 bytes
-rw-r--r--module/web/media/img/head-menu-download.png (renamed from module/web/static/default/head-menu-download.png)bin721 -> 721 bytes
-rw-r--r--module/web/media/img/head-menu-home.png (renamed from module/web/static/default/head-menu-home.png)bin920 -> 920 bytes
-rw-r--r--module/web/media/img/head-menu-index.png (renamed from module/web/static/default/head-menu-index.png)bin482 -> 482 bytes
-rw-r--r--module/web/media/img/head-menu-news.png (renamed from module/web/static/default/head-menu-news.png)bin628 -> 628 bytes
-rw-r--r--module/web/media/img/head-menu-recent.png (renamed from module/web/static/default/head-menu-recent.png)bin932 -> 932 bytes
-rw-r--r--module/web/media/img/head-menu-wiki.png (renamed from module/web/static/default/head-menu-wiki.png)bin1204 -> 1204 bytes
-rw-r--r--module/web/media/img/head-search-noshadow.png (renamed from module/web/static/default/head-search-noshadow.png)bin1187 -> 1187 bytes
-rw-r--r--module/web/media/img/head_bg1.png (renamed from module/web/static/default/head_bg1.png)bin125 -> 125 bytes
-rw-r--r--module/web/media/img/page-tools-backlinks.png (renamed from module/web/static/default/page-tools-backlinks.png)bin540 -> 540 bytes
-rw-r--r--module/web/media/img/page-tools-edit.png (renamed from module/web/static/default/page-tools-edit.png)bin574 -> 574 bytes
-rw-r--r--module/web/media/img/page-tools-revisions.png (renamed from module/web/static/default/page-tools-revisions.png)bin603 -> 603 bytes
-rw-r--r--module/web/media/img/progress-bar-back.gif (renamed from module/web/static/default/progress-bar-back.gif)bin10819 -> 10819 bytes
-rw-r--r--module/web/media/img/progress-bar.gif (renamed from module/web/static/default/progress-bar.gif)bin10819 -> 10819 bytes
-rw-r--r--module/web/media/img/pyload-logo-edited3.5-new-font-small.png (renamed from module/web/static/default/pyload-logo-edited3.5-new-font-small.png)bin8457 -> 8457 bytes
-rw-r--r--module/web/media/img/tab-background.png (renamed from module/web/static/default/tab-background.png)bin179 -> 179 bytes
-rw-r--r--module/web/media/img/tabs-border-bottom.png (renamed from module/web/static/default/tabs-border-bottom.png)bin163 -> 163 bytes
-rw-r--r--module/web/media/img/user-actions-logout.png (renamed from module/web/static/default/user-actions-logout.png)bin799 -> 799 bytes
-rw-r--r--module/web/media/img/user-actions-profile.png (renamed from module/web/static/default/user-actions-profile.png)bin628 -> 628 bytes
-rw-r--r--module/web/media/js/home.js (renamed from module/web/static/default/home.js)0
-rw-r--r--module/web/media/js/mootools-1.2.3-core.js (renamed from module/web/static/mootools-1.2.3-core.js)0
-rw-r--r--module/web/media/js/mootools-1.2.3.1-more.js (renamed from module/web/static/mootools-1.2.3.1-more.js)0
-rw-r--r--module/web/media/js/status.js (renamed from module/web/static/default/status.js)0
-rw-r--r--module/web/pyload.dbbin0 -> 32768 bytes
-rw-r--r--module/web/pyload/__init__.py0
-rw-r--r--module/web/pyload/admin.py1
-rw-r--r--module/web/pyload/models.py21
-rw-r--r--module/web/pyload/tests.py23
-rw-r--r--module/web/pyload/urls.py7
-rw-r--r--module/web/pyload/views.py80
-rw-r--r--module/web/settings.py127
-rw-r--r--module/web/static/default.css189
-rw-r--r--module/web/static/favicon.icobin7206 -> 0 bytes
-rw-r--r--module/web/templates/default.tpl230
-rw-r--r--module/web/templates/default/base.html99
-rw-r--r--module/web/templates/default/downloads.html16
-rw-r--r--module/web/templates/default/home.html1
-rw-r--r--module/web/templates/default/login.html35
-rw-r--r--module/web/templates/default/logout.html9
-rw-r--r--module/web/templates/default/logs.html16
-rw-r--r--module/web/templates/default/queue.html16
-rw-r--r--module/web/templates/default/window.html (renamed from module/web/templates/window.tpl)0
-rw-r--r--module/web/templates/footer.tpl6
-rw-r--r--module/web/templates/header.tpl24
-rw-r--r--module/web/urls.py30
-rwxr-xr-xpyLoadCli.py4
-rwxr-xr-xpyLoadCore.py27
74 files changed, 707 insertions, 2140 deletions
diff --git a/config b/config
index c593674f6..03307f1a4 100644
--- a/config
+++ b/config
@@ -11,10 +11,15 @@ key = ssl.key
[webinterface]
activated = True
-listenaddr = 0.0.0.0
port = 8080
-username = User
-password = webpw
+template = default
+local = True
+ssl = None #ONLY SPECIFY IF PYLOAD NOT RUN ON YOUR LOCALHOST
+username = None
+adress = None
+port = None
+pw = None
+
[log]
file_log = True
diff --git a/module/web/ServerThread.py b/module/web/ServerThread.py
new file mode 100644
index 000000000..803dc5dc5
--- /dev/null
+++ b/module/web/ServerThread.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+import threading
+import os
+from os.path import join
+
+class WebServer(threading.Thread):
+ def __init__(self, pycore):
+ threading.Thread.__init__(self)
+ self.pycore = pycore
+ self.setDaemon(True)
+
+ def run(self):
+ self.pycore.logger.info("Starting Webserver @ Port 8000")
+ os.system("python " + join(self.pycore.path,"module","web","manage.py runserver"))
+ #@TODO: really bad approach, better would be real python code, or subprocess \ No newline at end of file
diff --git a/module/web/WebServer.py b/module/web/WebServer.py
deleted file mode 100644
index 15541676b..000000000
--- a/module/web/WebServer.py
+++ /dev/null
@@ -1,374 +0,0 @@
-#import sys
-#from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
-#from xmlrpclib import ServerProxy
-#from time import time
-#import re
-#
-#class Handler(BaseHTTPRequestHandler):
-#
-# def do_GET(self):
-# global coreserver
-# stdout = sys.stdout
-# sys.stdout = self.wfile
-# if self.path == "/":
-# print "Server Runs"
-# elif self.path == "/downloads":
-# print self.get_downloads()
-# elif re.search("/add=.?", self.path):
-# if re.match(is_url, self.path.split("/add=")[1]):
-# coreserver.add_urls([self.path.split("/add=")[1]])
-# print "Link Added"
-# else:
-# try:
-# print open(self.path[1:], 'r').read()
-# except IOError:
-# self.send_error(404)
-#
-# def format_size(self, size):
-# return str(size / 1024) + " MiB"
-#
-# def format_time(self,seconds):
-# seconds = int(seconds)
-# hours, seconds = divmod(seconds, 3600)
-# minutes, seconds = divmod(seconds, 60)
-# return "%.2i:%.2i:%.2i" % (hours, minutes, seconds)
-#
-# def get_downloads(self):
-# data = coreserver.status_downloads()
-# for download in data:
-# print "<h3>%s</h3>" % download["name"]
-# if download["status"] == "downloading":
-# percent = download["percent"]
-# z = percent / 4
-# print "<h3>%s</h3>" % dl_name
-# print "<font face='font-family:Fixedsys,Courier,monospace;'>[" + z * "#" + (25-z) * "&nbsp;" + "]</font>" + str(percent) + "%<br />"
-# print "Speed: " + str(int(download['speed'])) + " kb/s"
-# print "Size: " + self.format_size(download['size'])
-# print "Finished in: " + self.format_time(download['eta'])
-# print "ID: " + str(download['id'])
-# dl_status = "[" + z * "#" + (25-z) * " " + "] " + str(percent) + "%" + " Speed: " + str(int(download['speed'])) + " kb/s" + " Size: " + self.format_size(download['size']) + " Finished in: " + self.format_time(download['eta']) + " ID: " + str(download['id'])
-# if download["status"] == "waiting":
-# print "waiting: " + self.format_time(download["wait_until"]- time())
-#
-#is_url = re.compile("^(((https?|ftp)\:\/\/)?([\w\.\-]+(\:[\w\.\&%\$\-]+)*@)?((([^\s\(\)\<\>\\\"\.\[\]\,@;:]+)(\.[^\s\(\)\<\>\\\"\.\[\]\,@;:]+)*(\.[a-zA-Z]{2,4}))|((([01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}([01]?\d{1,2}|2[0-4]\d|25[0-5])))(\b\:(6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)\b)?((\/[^\/][\w\.\,\?\'\\\/\+&%\$#\=~_\-@]*)*[^\.\,\?\"\'\(\)\[\]!;<>{}\s\x7F-\xFF])?)$",re.IGNORECASE)
-#
-#coreserver = None
-#
-#class WebServer():
-#
-# def start(self):
-# try:
-# global coreserver
-# coreserver = ServerProxy("https://testuser:testpw@localhost:1337", allow_none=True)
-# webserver = HTTPServer(('',8080),Handler)
-# print 'server started at port 8080'
-# webserver.serve_forever()
-# except KeyboardInterrupt:
-# webserver.socket.close()
-#
-#if __name__ == "__main__":
-# web = WebServer()
-# web.start()
-
-
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-#Copyright (C) 2009 RaNaN
-#
-#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 3 of the License,
-#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, see <http://www.gnu.org/licenses/>.
-#
-###
-import random
-import threading
-import time
-
-import bottle
-from bottle import abort
-from bottle import redirect
-from bottle import request
-from bottle import response
-from bottle import route
-from bottle import run
-from bottle import send_file
-from bottle import template
-
-
-core = None
-core_methods = None
-
-PATH = "./module/web/"
-TIME = time.strftime("%a, %d %b %Y 00:00:00 +0000", time.localtime()) #set time to current day
-USERS = {}
-# TODO: Implement new server methods
-@route('/login', method='POST')
-def do_login():
- #print request.GET
-
-
- username = core.config['webinterface']['username']
- pw = core.config['webinterface']['password']
-
- if request.POST['u'] == username and request.POST['p'] == pw:
-
- id = int(random.getrandbits(16))
- ua = request.HEADER("HTTP_USER_AGENT")
- ip = request.HEADER("REMOTE_ADDR")
-
- auth = {}
-
- auth['ua'] = ua
- auth['ip'] = ip
- auth['user'] = username
-
- USERS[id] = auth
-
- response.COOKIES['user'] = username
- response.COOKIES['id'] = id
-
- return template('default', page='loggedin', user=username)
- else:
- return template('default', page='login')
-
-@route('/login')
-def login():
-
- if check_auth(request):
- redirect("/")
-
- return template('default', page='login')
-
-@route('/logout')
-def logout():
- try:
- del USERS[int(request.COOKIES.get('id'))]
- except:
- pass
-
- redirect("/login")
-
-@route('/')
-def home():
-
- if not check_auth(request):
- redirect("/login")
-
- username = request.COOKIES.get('user')
-
- dls = core_methods.status_downloads()
-
- for dl in dls:
- dl['eta'] = str(core.format_time(dl['eta']))
- dl['wait_until'] = str(core.format_time(dl['wait_until'] - time.time()))
-
-
- return template('default', page='home', links=dls, user=username, status=core_methods.status_server())
-
-@route('/queue')
-def queue():
-
- if not check_auth(request):
- redirect("/login")
-
- username = request.COOKIES.get('user')
-
- return template('default', page='queue', links=core_methods.get_queue(), user=username, status=core_methods.status_server())
-
-@route('/downloads')
-def downloads():
-
- if not check_auth(request):
- redirect("/login")
-
- username = request.COOKIES.get('user')
-
- return template('default', page='downloads', links=core_methods.status_downloads(), user=username, status=core_methods.status_server())
-
-
-@route('/logs')
-def logs():
-
- if not check_auth(request):
- redirect("/login")
-
- username = request.COOKIES.get('user')
-
- return template('default', page='logs', links=core_methods.status_downloads(), user=username, status=core_methods.status_server())
-
-@route('/json/links')
-def get_links():
- response.header['Cache-Control'] = 'no-cache, must-revalidate'
- response.content_type = 'application/json'
-
- if not check_auth(request):
- abort(404, "No Access")
-
- json = '{ "downloads": ['
-
- downloads = core_methods.status_downloads()
- ids = []
-
- for dl in downloads:
- ids.append(dl['id'])
- json += '{'
- json += '"id": %s, "name": "%s", "speed": %s, "eta": "%s", "kbleft": %s, "size": %s, "percent": %s, "wait": "%s", "status": "%s"'\
- % (str(dl['id']), str(dl['name']), str(int(dl['speed'])), str(core.format_time(dl['eta'])), dl['kbleft'], dl['size'], dl['percent'], str(core.format_time(dl['wait_until'] - time.time())), dl['status'])
-
- json += "},"
-
- if json.endswith(","): json = json[:-1]
-
- json += '], "ids": %s }' % str(ids)
-
- return json
-
-@route('/json/status')
-def get_status():
- response.header['Cache-Control'] = 'no-cache, must-revalidate'
- response.content_type = 'application/json'
-
- if not check_auth(request):
- abort(404, "No Access")
-
- data = core_methods.status_server()
-
- if data['pause']:
- status = "paused"
- else:
- status = "running"
-
- json = '{ "status": "%s", "speed": "%s", "queue": "%s" }' % (status, str(int(data['speed'])), str(data['queue']))
-
- return json
-@route('json/addpackage', method='POST')
-def add_package():
- response.header['Cache-Control'] = 'no-cache, must-revalidate'
- response.content_type = 'application/json'
-
- if not check_auth(request):
- abort(404, "No Access")
-
- links = request.POST['links'].split('\n')
- name = request.POST['name']
- core_methods.add_package(name, links)
-
-@route('/json/addlinks', method='POST')
-def add_links():
- response.header['Cache-Control'] = 'no-cache, must-revalidate'
- response.content_type = 'application/json'
-
- if not check_auth(request):
- abort(404, "No Access")
-
- links = request.POST['links'].split('\n')
-
- core.add_links(links)
-
- return "{}"
-
-@route('/json/pause')
-def pause():
- response.header['Cache-Control'] = 'no-cache, must-revalidate'
- response.content_type = 'application/json'
-
- if not check_auth(request):
- abort(404, "No Access")
-
- core.thread_list.pause = True
-
- return "{}"
-
-
-@route('/json/play')
-def play():
- response.header['Cache-Control'] = 'no-cache, must-revalidate'
- response.content_type = 'application/json'
-
- if not check_auth(request):
- abort(404, "No Access")
-
- core.thread_list.pause = False
-
- return "{}"
-
-@route('/favicon.ico')
-def favicon():
-
- if request.HEADER("HTTP_IF_MODIFIED_SINCE") == TIME: abort(304, "Not Modified")
-
- response.header['Last-Modified'] = TIME
-
- send_file('favicon.ico', root=(PATH + 'static/'))
-
-@route('static/:section/:filename')
-def static_folder(section, filename):
-
- if request.HEADER("HTTP_IF_MODIFIED_SINCE") == TIME: abort(304, "Not Modified")
-
- response.header['Last-Modified'] = TIME
- send_file(filename, root=(PATH + 'static/' + section))
-
-@route('/static/:filename')
-def static_file(filename):
-
- if request.HEADER("HTTP_IF_MODIFIED_SINCE") == TIME: abort(304, "Not Modified")
-
- response.header['Last-Modified'] = TIME
- send_file(filename, root=(PATH + 'static/'))
-
-
-def check_auth(req):
-
- try:
- user = req.COOKIES.get('user')
- id = int(req.COOKIES.get('id'))
- ua = req.HEADER("HTTP_USER_AGENT")
- ip = req.HEADER("REMOTE_ADDR")
-
- if USERS[id]['user'] == user and USERS[id]['ua'] == ua and USERS[id]['ip'] == ip:
- return True
- except:
- return False
-
- return False
-
-
-class WebServer(threading.Thread):
- def __init__(self, pycore):
- threading.Thread.__init__(self)
-
- global core, core_methods, TIME
- core = pycore
- core_methods = pycore.server_methods
- self.core = pycore
- self.setDaemon(True)
-
- if pycore.config['general']['debug_mode']:
- bottle.debug(True)
- TIME = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())
- else:
- bottle.debug(False)
-
- #@TODO remove
- #TIME = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())
-
- bottle.TEMPLATE_PATH.append('./module/web/templates/')
-
- def run(self):
- self.core.logger.info("Starting Webinterface on %s port %s" % (self.core.config['webinterface']['listenaddr'],self.core.config['webinterface']['port']))
- try:
- run(host=self.core.config['webinterface']['listenaddr'], port=int(self.core.config['webinterface']['port']), quiet=True)
- except:
- self.core.logger.error("Failed starting webserver, no webinterface available: Can't create socket")
- exit() \ No newline at end of file
diff --git a/module/web/__init__.py b/module/web/ajax/__init__.py
index e69de29bb..e69de29bb 100644
--- a/module/web/__init__.py
+++ b/module/web/ajax/__init__.py
diff --git a/module/web/ajax/models.py b/module/web/ajax/models.py
new file mode 100644
index 000000000..71a836239
--- /dev/null
+++ b/module/web/ajax/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/module/web/ajax/tests.py b/module/web/ajax/tests.py
new file mode 100644
index 000000000..2247054b3
--- /dev/null
+++ b/module/web/ajax/tests.py
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
diff --git a/module/web/ajax/urls.py b/module/web/ajax/urls.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/module/web/ajax/urls.py
diff --git a/module/web/ajax/views.py b/module/web/ajax/views.py
new file mode 100644
index 000000000..60f00ef0e
--- /dev/null
+++ b/module/web/ajax/views.py
@@ -0,0 +1 @@
+# Create your views here.
diff --git a/module/web/bottle.py b/module/web/bottle.py
deleted file mode 100644
index 41a8c8fc0..000000000
--- a/module/web/bottle.py
+++ /dev/null
@@ -1,1231 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Bottle is a fast and simple micro-framework for small web applications. It
-offers request dispatching (Routes) with url parameter support, templates,
-key/value databases, a built-in HTTP Server and adapters for many third party
-WSGI/HTTP-server and template engines - all in a single file and with no
-dependencies other than the Python Standard Library.
-
-Homepage and documentation: http://wiki.github.com/defnull/bottle
-
-Special thanks to Stefan Matthias Aust [http://github.com/sma]
- for his contribution to SimpleTemplate
-
-Licence (MIT)
--------------
-
- Copyright (c) 2009, Marcel Hellkamp.
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-
-
-Example
--------
-
- from bottle import route, run, request, response, send_file, abort
-
- @route('/')
- def hello_world():
- return 'Hello World!'
-
- @route('/hello/:name')
- def hello_name(name):
- return 'Hello %s!' % name
-
- @route('/hello', method='POST')
- def hello_post():
- name = request.POST['name']
- return 'Hello %s!' % name
-
- @route('/static/:filename#.*#')
- def static_file(filename):
- send_file(filename, root='/path/to/static/files/')
-
- run(host='localhost', port=8080)
-
-"""
-
-__author__ = 'Marcel Hellkamp'
-__version__ = '0.6.4'
-__license__ = 'MIT'
-
-import types
-import sys
-import cgi
-import mimetypes
-import os
-import os.path
-import traceback
-import re
-import random
-import threading
-import time
-import warnings
-import email.utils
-from wsgiref.headers import Headers as HeaderWrapper
-from Cookie import SimpleCookie
-import anydbm as dbm
-import subprocess
-import thread
-
-
-try:
- from urlparse import parse_qs
-except ImportError: # pragma: no cover
- from cgi import parse_qs
-
-try:
- import cPickle as pickle
-except ImportError: # pragma: no cover
- import pickle as pickle
-
-try:
- try:
- from json import dumps as json_dumps
- except ImportError: # pragma: no cover
- from simplejson import dumps as json_dumps
-except ImportError: # pragma: no cover
- json_dumps = None
-
-
-
-
-
-
-# Exceptions and Events
-
-class BottleException(Exception):
- """ A base class for exceptions used by bottle. """
- pass
-
-
-class HTTPError(BottleException):
- """
- A way to break the execution and instantly jump to an error handler.
- """
- def __init__(self, status, text):
- self.output = text
- self.http_status = int(status)
- BottleException.__init__(self, status, text)
-
- def __repr__(self):
- return 'HTTPError(%d,%s)' % (self.http_status, repr(self.output))
-
- def __str__(self):
- return HTTP_ERROR_TEMPLATE % {
- 'status' : self.http_status,
- 'url' : request.path,
- 'error_name' : HTTP_CODES.get(self.http_status, 'Unknown').title(),
- 'error_message' : ''.join(self.output)
- }
-
-
-class BreakTheBottle(BottleException):
- """
- Not an exception, but a straight jump out of the controller code.
- Causes the Bottle to instantly call start_response() and return the
- content of output
- """
- def __init__(self, output):
- self.output = output
-
-
-
-
-
-
-# WSGI abstraction: Request and response management
-
-_default_app = None
-def default_app(newapp = None):
- """
- Returns the current default app or sets a new one.
- Defaults to an instance of Bottle
- """
- global _default_app
- if newapp:
- _default_app = newapp
- if not _default_app:
- _default_app = Bottle()
- return _default_app
-
-
-class Bottle(object):
-
- def __init__(self, catchall=True, optimize=False, autojson=True):
- self.simple_routes = {}
- self.regexp_routes = {}
- self.default_route = None
- self.error_handler = {}
- self.optimize = optimize
- self.autojson = autojson
- self.catchall = catchall
- self.serve = True
-
- def match_url(self, url, method='GET'):
- """
- Returns the first matching handler and a parameter dict or (None, None)
- """
- url = url.strip().lstrip("/ ")
- # Search for static routes first
- route = self.simple_routes.get(method,{}).get(url,None)
- if route:
- return (route, {})
-
- routes = self.regexp_routes.get(method,[])
- for i in range(len(routes)):
- match = routes[i][0].match(url)
- if match:
- handler = routes[i][1]
- if i > 0 and self.optimize and random.random() <= 0.001:
- routes[i-1], routes[i] = routes[i], routes[i-1]
- return (handler, match.groupdict())
- if self.default_route:
- return (self.default_route, {})
- if method == 'HEAD': # Fall back to GET
- return self.match_url(url)
- else:
- return (None, None)
-
- def add_controller(self, route, controller, **kargs):
- """ Adds a controller class or object """
- if '{action}' not in route and 'action' not in kargs:
- raise BottleException("Routes to controller classes or object MUST"
- " contain an {action} placeholder or use the action-parameter")
- for action in (m for m in dir(controller) if not m.startswith('_')):
- handler = getattr(controller, action)
- if callable(handler) and action == kargs.get('action', action):
- self.add_route(route.replace('{action}', action), handler, **kargs)
-
- def add_route(self, route, handler, method='GET', simple=False, **kargs):
- """ Adds a new route to the route mappings. """
- if isinstance(handler, type) and issubclass(handler, BaseController):
- handler = handler()
- if isinstance(handler, BaseController):
- self.add_controller(route, handler, method=method, simple=simple, **kargs)
- return
- method = method.strip().upper()
- route = route.strip().lstrip('$^/ ').rstrip('$^ ')
- if re.match(r'^(\w+/)*\w*$', route) or simple:
- self.simple_routes.setdefault(method, {})[route] = handler
- else:
- route = re.sub(r':([a-zA-Z_]+)(?P<uniq>[^\w/])(?P<re>.+?)(?P=uniq)',
- r'(?P<\1>\g<re>)',route)
- route = re.sub(r':([a-zA-Z_]+)', r'(?P<\1>[^/]+)', route)
- route = re.compile('^%s$' % route)
- self.regexp_routes.setdefault(method, []).append([route, handler])
-
- def route(self, url, **kargs):
- """
- Decorator for request handler.
- Same as add_route(url, handler, **kargs).
- """
- def wrapper(handler):
- self.add_route(url, handler, **kargs)
- return handler
- return wrapper
-
- def set_default(self, handler):
- self.default_route = handler
-
- def default(self):
- """ Decorator for request handler. Same as add_defroute( handler )."""
- def wrapper(handler):
- self.set_default(handler)
- return handler
- return wrapper
-
- def set_error_handler(self, code, handler):
- """ Adds a new error handler. """
- self.error_handler[int(code)] = handler
-
- def error(self, code=500):
- """
- Decorator for error handler.
- Same as set_error_handler(code, handler).
- """
- def wrapper(handler):
- self.set_error_handler(code, handler)
- return handler
- return wrapper
-
- def cast(self, out):
- """
- Cast the output to an iterable of strings or something WSGI can handle.
- Set Content-Type and Content-Length when possible. Then clear output
- on HEAD requests.
- Supports: False, str, unicode, list(unicode), dict(), open()
- """
- if not out:
- out = []
- response.header['Content-Length'] = '0'
- elif isinstance(out, types.StringType):
- out = [out]
- elif isinstance(out, unicode):
- out = [out.encode(response.charset)]
- elif isinstance(out, list) and isinstance(out[0], unicode):
- out = map(lambda x: x.encode(response.charset), out)
- elif self.autojson and json_dumps and isinstance(out, dict):
- out = [json_dumps(out)]
- response.content_type = 'application/json'
- elif hasattr(out, 'read'):
- out = request.environ.get('wsgi.file_wrapper',
- lambda x: iter(lambda: x.read(8192), ''))(out)
- if isinstance(out, list) and len(out) == 1:
- response.header['Content-Length'] = str(len(out[0]))
- if not hasattr(out, '__iter__'):
- raise TypeError('Request handler for route "%s" returned [%s] '
- 'which is not iterable.' % (request.path, type(out).__name__))
- return out
-
-
- def __call__(self, environ, start_response):
- """ The bottle WSGI-interface. """
- request.bind(environ)
- response.bind()
- try: # Unhandled Exceptions
- try: # Bottle Error Handling
- if not self.serve:
- abort(503, "Server stopped")
- handler, args = self.match_url(request.path, request.method)
- if not handler:
- raise HTTPError(404, "Not found")
- output = handler(**args)
- db.close()
- except BreakTheBottle, e:
- output = e.output
- except HTTPError, e:
- response.status = e.http_status
- output = self.error_handler.get(response.status, str)(e)
- output = self.cast(output)
- if response.status in (100, 101, 204, 304) or request.method == 'HEAD':
- output = [] # rfc2616 section 4.3
- except (KeyboardInterrupt, SystemExit, MemoryError):
- raise
- except Exception, e:
- response.status = 500
- if self.catchall:
- err = "Unhandled Exception: %s\n" % (repr(e))
- if DEBUG:
- err += TRACEBACK_TEMPLATE % traceback.format_exc(10)
- output = [str(HTTPError(500, err))]
- request._environ['wsgi.errors'].write(err)
- else:
- raise
- status = '%d %s' % (response.status, HTTP_CODES[response.status])
- start_response(status, response.wsgiheaders())
- return output
-
-
-
-class Request(threading.local):
- """ Represents a single request using thread-local namespace. """
-
- def bind(self, environ):
- """
- Binds the enviroment of the current request to this request handler
- """
- self._environ = environ
- self.environ = self._environ
- self._GET = None
- self._POST = None
- self._GETPOST = None
- self._COOKIES = None
- self.path = self._environ.get('PATH_INFO', '/').strip()
- if not self.path.startswith('/'):
- self.path = '/' + self.path
-
- @property
- def method(self):
- """ Get the request method (GET,POST,PUT,DELETE,...) """
- return self._environ.get('REQUEST_METHOD', 'GET').upper()
-
- @property
- def query_string(self):
- """ Get content of QUERY_STRING """
- return self._environ.get('QUERY_STRING', '')
-
- @property
- def input_length(self):
- """ Get content of CONTENT_LENGTH """
- try:
- return max(0,int(self._environ.get('CONTENT_LENGTH', '0')))
- except ValueError:
- return 0
-
- @property
- def GET(self):
- """ Get a dict with GET parameters. """
- if self._GET is None:
- data = parse_qs(self.query_string, keep_blank_values=True)
- self._GET = {}
- for key, value in data.iteritems():
- if len(value) == 1:
- self._GET[key] = value[0]
- else:
- self._GET[key] = value
- return self._GET
-
- @property
- def POST(self):
- """ Get a dict with parsed POST or PUT data. """
- if self._POST is None:
- data = cgi.FieldStorage(fp=self._environ['wsgi.input'],
- environ=self._environ, keep_blank_values=True)
- self._POST = {}
- for item in data.list:
- name = item.name
- if not item.filename:
- item = item.value
- self._POST.setdefault(name, []).append(item)
- for key in self._POST:
- if len(self._POST[key]) == 1:
- self._POST[key] = self._POST[key][0]
- return self._POST
-
- @property
- def params(self):
- """ Returns a mix of GET and POST data. POST overwrites GET """
- if self._GETPOST is None:
- self._GETPOST = dict(self.GET)
- self._GETPOST.update(dict(self.POST))
- return self._GETPOST
-
- @property
- def COOKIES(self):
- """ Returns a dict with COOKIES. """
- if self._COOKIES is None:
- raw_dict = SimpleCookie(self._environ.get('HTTP_COOKIE',''))
- self._COOKIES = {}
- for cookie in raw_dict.itervalues():
- self._COOKIES[cookie.key] = cookie.value
- return self._COOKIES
-
- def HEADER(self, header):
- """Returns HTTP header"""
- return self._environ.get(header, '')
-
-class Response(threading.local):
- """ Represents a single response using thread-local namespace. """
-
- def bind(self):
- """ Clears old data and creates a brand new Response object """
- self._COOKIES = None
- self.status = 200
- self.header_list = []
- self.header = HeaderWrapper(self.header_list)
- self.content_type = 'text/html'
- self.error = None
- self.charset = 'utf8'
-
- def wsgiheaders(self):
- ''' Returns a wsgi conform list of header/value pairs '''
- for c in self.COOKIES.itervalues():
- self.header.add_header('Set-Cookie', c.OutputString())
- return [(h.title(), str(v)) for h, v in self.header.items()]
-
- @property
- def COOKIES(self):
- if not self._COOKIES:
- self._COOKIES = SimpleCookie()
- return self._COOKIES
-
- def set_cookie(self, key, value, **kargs):
- """
- Sets a Cookie. Optional settings:
- expires, path, comment, domain, max-age, secure, version, httponly
- """
- self.COOKIES[key] = value
- for k, v in kargs.iteritems():
- self.COOKIES[key][k] = v
-
- def get_content_type(self):
- """ Get the current 'Content-Type' header. """
- return self.header['Content-Type']
-
- def set_content_type(self, value):
- if 'charset=' in value:
- self.charset = value.split('charset=')[-1].split(';')[0].strip()
- self.header['Content-Type'] = value
-
- content_type = property(get_content_type, set_content_type, None,
- get_content_type.__doc__)
-
-
-class BaseController(object):
- _singleton = None
- def __new__(cls, *a, **k):
- if not cls._singleton:
- cls._singleton = object.__new__(cls, *a, **k)
- return cls._singleton
-
-
-def abort(code=500, text='Unknown Error: Appliction stopped.'):
- """ Aborts execution and causes a HTTP error. """
- raise HTTPError(code, text)
-
-
-def redirect(url, code=307):
- """ Aborts execution and causes a 307 redirect """
- response.status = code
- response.header['Location'] = url
- raise BreakTheBottle("")
-
-
-def send_file(filename, root, guessmime = True, mimetype = None):
- """ Aborts execution and sends a static files as response. """
- root = os.path.abspath(root) + os.sep
- filename = os.path.abspath(os.path.join(root, filename.strip('/\\')))
-
- if not filename.startswith(root):
- abort(401, "Access denied.")
- if not os.path.exists(filename) or not os.path.isfile(filename):
- abort(404, "File does not exist.")
- if not os.access(filename, os.R_OK):
- abort(401, "You do not have permission to access this file.")
-
- if guessmime and not mimetype:
- mimetype = mimetypes.guess_type(filename)[0]
- if not mimetype: mimetype = 'text/plain'
- response.content_type = mimetype
-
- stats = os.stat(filename)
- if 'Last-Modified' not in response.header:
- lm = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(stats.st_mtime))
- response.header['Last-Modified'] = lm
- if 'HTTP_IF_MODIFIED_SINCE' in request.environ:
- ims = request.environ['HTTP_IF_MODIFIED_SINCE']
- # IE sends "<date>; length=146"
- ims = ims.split(";")[0].strip()
- ims = parse_date(ims)
- if ims is not None and ims >= stats.st_mtime:
- abort(304, "Not modified")
- if 'Content-Length' not in response.header:
- response.header['Content-Length'] = str(stats.st_size)
- raise BreakTheBottle(open(filename, 'rb'))
-
-
-def parse_date(ims):
- """
- Parses date strings usually found in HTTP header and returns UTC epoch.
- Understands rfc1123, rfc850 and asctime.
- """
- try:
- ts = email.utils.parsedate_tz(ims)
- if ts is not None:
- if ts[9] is None:
- return time.mktime(ts[:8] + (0,)) - time.timezone
- else:
- return time.mktime(ts[:8] + (0,)) - ts[9] - time.timezone
- except (ValueError, IndexError):
- return None
-
-
-
-
-
-
-# Decorators
-
-def validate(**vkargs):
- """
- Validates and manipulates keyword arguments by user defined callables.
- Handles ValueError and missing arguments by raising HTTPError(403).
- """
- def decorator(func):
- def wrapper(**kargs):
- for key, value in vkargs.iteritems():
- if key not in kargs:
- abort(403, 'Missing parameter: %s' % key)
- try:
- kargs[key] = value(kargs[key])
- except ValueError, e:
- abort(403, 'Wrong parameter format for: %s' % key)
- return func(**kargs)
- return wrapper
- return decorator
-
-
-def route(url, **kargs):
- """
- Decorator for request handler. Same as add_route(url, handler, **kargs).
- """
- return default_app().route(url, **kargs)
-
-def default():
- """
- Decorator for request handler. Same as set_default(handler).
- """
- return default_app().default()
-
-def error(code=500):
- """
- Decorator for error handler. Same as set_error_handler(code, handler).
- """
- return default_app().error(code)
-
-
-
-
-
-
-# Server adapter
-
-class WSGIAdapter(object):
- def run(self, handler): # pragma: no cover
- pass
-
- def __repr__(self):
- return "%s()" % (self.__class__.__name__)
-
-
-class CGIServer(WSGIAdapter):
- def run(self, handler):
- from wsgiref.handlers import CGIHandler
- CGIHandler().run(handler)
-
-
-class ServerAdapter(WSGIAdapter):
- def __init__(self, host='127.0.0.1', port=8080, **kargs):
- WSGIAdapter.__init__(self)
- self.host = host
- self.port = int(port)
- self.options = kargs
-
- def __repr__(self):
- return "%s (%s:%d)" % (self.__class__.__name__, self.host, self.port)
-
-
-class WSGIRefServer(ServerAdapter):
- def run(self, handler):
- from wsgiref.simple_server import make_server
- srv = make_server(self.host, self.port, handler)
- srv.serve_forever()
-
-
-class CherryPyServer(ServerAdapter):
- def run(self, handler):
- from cherrypy import wsgiserver
- server = wsgiserver.CherryPyWSGIServer((self.host, self.port), handler)
- server.start()
-
-
-class FlupServer(ServerAdapter):
- def run(self, handler):
- from flup.server.fcgi import WSGIServer
- WSGIServer(handler, bindAddress=(self.host, self.port)).run()
-
-
-class PasteServer(ServerAdapter):
- def run(self, handler):
- from paste import httpserver
- from paste.translogger import TransLogger
- app = TransLogger(handler)
- httpserver.serve(app, host=self.host, port=str(self.port))
-
-
-class FapwsServer(ServerAdapter):
- """
- Extremly fast webserver using libev.
- See http://william-os4y.livejournal.com/
- Experimental ...
- """
- def run(self, handler):
- import fapws._evwsgi as evwsgi
- from fapws import base
- evwsgi.start(self.host, self.port)
- evwsgi.set_base_module(base)
- def app(environ, start_response):
- environ['wsgi.multiprocess'] = False
- return handler(environ, start_response)
- evwsgi.wsgi_cb(('',app))
- evwsgi.run()
-
-
-def run(app=None, server=WSGIRefServer, host='127.0.0.1', port=8080,
- interval=1, reloader=False, **kargs):
- """ Runs bottle as a web server. """
- if not app:
- app = default_app()
-
- quiet = bool(kargs.get('quiet', False))
-
- # Instantiate server, if it is a class instead of an instance
- if isinstance(server, type):
- if issubclass(server, CGIServer):
- server = server()
- elif issubclass(server, ServerAdapter):
- server = server(host=host, port=port, **kargs)
-
- if not isinstance(server, WSGIAdapter):
- raise RuntimeError("Server must be a subclass of WSGIAdapter")
-
- if not quiet and isinstance(server, ServerAdapter): # pragma: no cover
- if not reloader or os.environ.get('BOTTLE_CHILD') == 'true':
- print "Bottle server starting up (using %s)..." % repr(server)
- print "Listening on http://%s:%d/" % (server.host, server.port)
- print "Use Ctrl-C to quit."
- print
- else:
- print "Bottle auto reloader starting up..."
-
- try:
- if reloader and interval:
- reloader_run(server, app, interval)
- else:
- server.run(app)
- except KeyboardInterrupt:
- if not quiet: # pragma: no cover
- print "Shutting Down..."
-
-
-#TODO: If the parent process is killed (with SIGTERM) the childs survive...
-def reloader_run(server, app, interval):
- if os.environ.get('BOTTLE_CHILD') == 'true':
- # We are a child process
- files = dict()
- for module in sys.modules.values():
- file_path = getattr(module, '__file__', None)
- if file_path and os.path.isfile(file_path):
- file_split = os.path.splitext(file_path)
- if file_split[1] in ('.py', '.pyc', '.pyo'):
- file_path = file_split[0] + '.py'
- files[file_path] = os.stat(file_path).st_mtime
- thread.start_new_thread(server.run, (app,))
- while True:
- time.sleep(interval)
- for file_path, file_mtime in files.iteritems():
- if not os.path.exists(file_path):
- print "File changed: %s (deleted)" % file_path
- elif os.stat(file_path).st_mtime > file_mtime:
- print "File changed: %s (modified)" % file_path
- else: continue
- print "Restarting..."
- app.serve = False
- time.sleep(interval) # be nice and wait for running requests
- sys.exit(3)
- while True:
- args = [sys.executable] + sys.argv
- environ = os.environ.copy()
- environ['BOTTLE_CHILD'] = 'true'
- exit_status = subprocess.call(args, env=environ)
- if exit_status != 3:
- sys.exit(exit_status)
-
-
-
-
-
-# Templates
-
-class TemplateError(HTTPError):
- def __init__(self, message):
- HTTPError.__init__(self, 500, message)
-
-class BaseTemplate(object):
- def __init__(self, template='', name=None, filename=None, lookup=[]):
- """
- Create a new template.
- If a name is provided, but no filename and no template string, the
- filename is guessed using the lookup path list.
- Subclasses can assume that either self.template or self.filename is set.
- If both are present, self.template should be used.
- """
- self.name = name
- self.filename = filename
- self.template = template
- self.lookup = lookup
- if self.name and not self.filename:
- for path in self.lookup:
- fpath = os.path.join(path, self.name+'.tpl')
- if os.path.isfile(fpath):
- self.filename = fpath
- if not self.template and not self.filename:
- raise TemplateError('Template (%s) not found.' % self.name)
- self.prepare()
-
- def prepare(self):
- """
- Run preparatios (parsing, caching, ...).
- It should be possible to call this multible times to refresh a template.
- """
- raise NotImplementedError
-
- def render(self, **args):
- """
- Render the template with the specified local variables and return an
- iterator of strings (bytes). This must be thread save!
- """
- raise NotImplementedError
-
-
-class MakoTemplate(BaseTemplate):
- output_encoding=None
- input_encoding=None
- default_filters=None
- global_variables={}
-
- def prepare(self):
- from mako.template import Template
- from mako.lookup import TemplateLookup
- #TODO: This is a hack... http://github.com/defnull/bottle/issues#issue/8
- mylookup = TemplateLookup(directories=map(os.path.abspath, self.lookup)+['./'])
- if self.template:
- self.tpl = Template(self.template,
- lookup=mylookup,
- output_encoding=MakoTemplate.output_encoding,
- input_encoding=MakoTemplate.input_encoding,
- default_filters=MakoTemplate.default_filters
- )
- else:
- self.tpl = Template(filename=self.filename,
- lookup=mylookup,
- output_encoding=MakoTemplate.output_encoding,
- input_encoding=MakoTemplate.input_encoding,
- default_filters=MakoTemplate.default_filters
- )
-
- def render(self, **args):
- _defaults = MakoTemplate.global_variables.copy()
- _defaults.update(args)
- return self.tpl.render(**_defaults)
-
-
-class CheetahTemplate(BaseTemplate):
- def prepare(self):
- from Cheetah.Template import Template
- self.context = threading.local()
- self.context.vars = {}
- if self.template:
- self.tpl = Template(source=self.template, searchList=[self.context.vars])
- else:
- self.tpl = Template(file=self.filename, searchList=[self.context.vars])
-
- def render(self, **args):
- self.context.vars.update(args)
- out = str(self.tpl)
- self.context.vars.clear()
- return [out]
-
-
-class Jinja2Template(BaseTemplate):
- env = None # hopefully, a Jinja environment is actually thread-safe
-
- def prepare(self):
- if not self.env:
- from jinja2 import Environment, FunctionLoader
- self.env = Environment(line_statement_prefix="#", loader=FunctionLoader(self.loader))
- if self.template:
- self.tpl = self.env.from_string(self.template)
- else:
- self.tpl = self.env.get_template(self.filename)
-
- def render(self, **args):
- return self.tpl.render(**args).encode("utf-8")
-
- def loader(self, name):
- if not name.endswith(".tpl"):
- for path in self.lookup:
- fpath = os.path.join(path, name+'.tpl')
- if os.path.isfile(fpath):
- name = fpath
- break
- f = open(name)
- try: return f.read()
- finally: f.close()
-
-
-class SimpleTemplate(BaseTemplate):
- re_python = re.compile(r'^\s*%\s*(?:(if|elif|else|try|except|finally|for|'
- 'while|with|def|class)|(include|rebase)|(end)|(.*))')
- re_inline = re.compile(r'\{\{(.*?)\}\}')
- dedent_keywords = ('elif', 'else', 'except', 'finally')
-
- def prepare(self):
- if self.template:
- code = self.translate(self.template)
- self.co = compile(code, '<string>', 'exec')
- else:
- code = self.translate(open(self.filename).read())
- self.co = compile(code, self.filename, 'exec')
-
- def translate(self, template):
- indent = 0
- strbuffer = []
- code = []
- self.includes = dict()
- class PyStmt(str):
- def __repr__(self): return 'str(' + self + ')'
- def flush(allow_nobreak=False):
- if len(strbuffer):
- if allow_nobreak and strbuffer[-1].endswith("\\\\\n"):
- strbuffer[-1]=strbuffer[-1][:-3]
- code.append(' ' * indent + "_stdout.append(%s)" % repr(''.join(strbuffer)))
- code.append((' ' * indent + '\n') * len(strbuffer)) # to preserve line numbers
- del strbuffer[:]
- for line in template.splitlines(True):
- m = self.re_python.match(line)
- if m:
- flush(allow_nobreak=True)
- keyword, subtpl, end, statement = m.groups()
- if keyword:
- if keyword in self.dedent_keywords:
- indent -= 1
- code.append(" " * indent + line[m.start(1):])
- indent += 1
- elif subtpl:
- tmp = line[m.end(2):].strip().split(None, 1)
- if not tmp:
- code.append(' ' * indent + "_stdout.extend(_base)\n")
- else:
- name = tmp[0]
- args = tmp[1:] and tmp[1] or ''
- if name not in self.includes:
- self.includes[name] = SimpleTemplate(name=name, lookup=self.lookup)
- if subtpl == 'include':
- code.append(' ' * indent +
- "_ = _includes[%s].execute(_stdout, %s)\n"
- % (repr(name), args))
- else:
- code.append(' ' * indent +
- "_tpl['_rebase'] = (_includes[%s], dict(%s))\n"
- % (repr(name), args))
- elif end:
- indent -= 1
- code.append(' ' * indent + '#' + line[m.start(3):])
- elif statement:
- code.append(' ' * indent + line[m.start(4):])
- else:
- splits = self.re_inline.split(line) # text, (expr, text)*
- if len(splits) == 1:
- strbuffer.append(line)
- else:
- flush()
- for i in range(1, len(splits), 2):
- splits[i] = PyStmt(splits[i])
- splits = [x for x in splits if bool(x)]
- code.append(' ' * indent + "_stdout.extend(%s)\n" % repr(splits))
- flush()
- return ''.join(code)
-
- def execute(self, stdout, **args):
- args['_stdout'] = stdout
- args['_includes'] = self.includes
- args['_tpl'] = args
- eval(self.co, args)
- if '_rebase' in args:
- subtpl, args = args['_rebase']
- args['_base'] = stdout[:] #copy stdout
- del stdout[:] # clear stdout
- return subtpl.execute(stdout, **args)
- return args
- def render(self, **args):
- """ Render the template using keyword arguments as local variables. """
- stdout = []
- self.execute(stdout, **args)
- return stdout
-
-
-
-def template(tpl, template_adapter=SimpleTemplate, **args):
- '''
- Get a rendered template as a string iterator.
- You can use a name, a filename or a template string as first parameter.
- '''
- lookup = args.get('template_lookup', TEMPLATE_PATH)
- if tpl not in TEMPLATES or DEBUG:
- if "\n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl:
- TEMPLATES[tpl] = template_adapter(template=tpl, lookup=lookup)
- elif '.' in tpl:
- TEMPLATES[tpl] = template_adapter(filename=tpl, lookup=lookup)
- else:
- TEMPLATES[tpl] = template_adapter(name=tpl, lookup=lookup)
- if not TEMPLATES[tpl]:
- abort(500, 'Template (%s) not found' % tpl)
- args['abort'] = abort
- args['request'] = request
- args['response'] = response
- return TEMPLATES[tpl].render(**args)
-
-
-def mako_template(tpl_name, **kargs):
- kargs['template_adapter'] = MakoTemplate
- return template(tpl_name, **kargs)
-
-def cheetah_template(tpl_name, **kargs):
- kargs['template_adapter'] = CheetahTemplate
- return template(tpl_name, **kargs)
-
-def jinja2_template(tpl_name, **kargs):
- kargs['template_adapter'] = Jinja2Template
- return template(tpl_name, **kargs)
-
-def view(tpl_name, **defaults):
- ''' Decorator: Rendes a template for a handler.
- Return a dict of template vars to fill out the template.
- '''
- def decorator(func):
- def wrapper(**kargs):
- out = func(**kargs)
- defaults.update(out)
- return template(tpl_name, **defaults)
- return wrapper
- return decorator
-
-def mako_view(tpl_name, **kargs):
- kargs['template_adapter'] = MakoTemplate
- return view(tpl_name, **kargs)
-
-def cheetah_view(tpl_name, **kargs):
- kargs['template_adapter'] = CheetahTemplate
- return view(tpl_name, **kargs)
-
-def jinja2_view(tpl_name, **kargs):
- kargs['template_adapter'] = Jinja2Template
- return view(tpl_name, **kargs)
-
-
-
-
-
-
-
-# Database
-
-class BottleBucket(object): # pragma: no cover
- """ Memory-caching wrapper around anydbm """
- def __init__(self, name):
- self.__dict__['name'] = name
- self.__dict__['db'] = dbm.open(DB_PATH + '/%s.db' % name, 'c')
- self.__dict__['mmap'] = {}
-
- def __getitem__(self, key):
- if key not in self.mmap:
- self.mmap[key] = pickle.loads(self.db[key])
- return self.mmap[key]
-
- def __setitem__(self, key, value):
- if not isinstance(key, str): raise TypeError("Bottle keys must be strings")
- self.mmap[key] = value
-
- def __delitem__(self, key):
- if key in self.mmap:
- del self.mmap[key]
- del self.db[key]
-
- def __getattr__(self, key):
- try: return self[key]
- except KeyError: raise AttributeError(key)
-
- def __setattr__(self, key, value):
- self[key] = value
-
- def __delattr__(self, key):
- try: del self[key]
- except KeyError: raise AttributeError(key)
-
- def __iter__(self):
- return iter(self.ukeys())
-
- def __contains__(self, key):
- return key in self.ukeys()
-
- def __len__(self):
- return len(self.ukeys())
-
- def keys(self):
- return list(self.ukeys())
-
- def ukeys(self):
- return set(self.db.keys()) | set(self.mmap.keys())
-
- def save(self):
- self.close()
- self.__init__(self.name)
-
- def close(self):
- for key in self.mmap:
- pvalue = pickle.dumps(self.mmap[key], pickle.HIGHEST_PROTOCOL)
- if key not in self.db or pvalue != self.db[key]:
- self.db[key] = pvalue
- self.mmap.clear()
- if hasattr(self.db, 'sync'):
- self.db.sync()
- if hasattr(self.db, 'close'):
- self.db.close()
-
- def clear(self):
- for key in self.db:
- del self.db[key]
- self.mmap.clear()
-
- def update(self, other):
- self.mmap.update(other)
-
- def get(self, key, default=None):
- try:
- return self[key]
- except KeyError:
- if default:
- return default
- raise
-
-
-class BottleDB(threading.local): # pragma: no cover
- """ Holds multible BottleBucket instances in a thread-local way. """
- def __init__(self):
- self.__dict__['open'] = {}
-
- def __getitem__(self, key):
- warnings.warn("Please do not use bottle.db anymore. This feature is deprecated. You may use anydb directly.", DeprecationWarning)
- if key not in self.open and not key.startswith('_'):
- self.open[key] = BottleBucket(key)
- return self.open[key]
-
- def __setitem__(self, key, value):
- if isinstance(value, BottleBucket):
- self.open[key] = value
- elif hasattr(value, 'items'):
- if key not in self.open:
- self.open[key] = BottleBucket(key)
- self.open[key].clear()
- for k, v in value.iteritems():
- self.open[key][k] = v
- else:
- raise ValueError("Only dicts and BottleBuckets are allowed.")
-
- def __delitem__(self, key):
- if key not in self.open:
- self.open[key].clear()
- self.open[key].save()
- del self.open[key]
-
- def __getattr__(self, key):
- try: return self[key]
- except KeyError: raise AttributeError(key)
-
- def __setattr__(self, key, value):
- self[key] = value
-
- def __delattr__(self, key):
- try: del self[key]
- except KeyError: raise AttributeError(key)
-
- def save(self):
- self.close()
- self.__init__()
-
- def close(self):
- for db in self.open:
- self.open[db].close()
- self.open.clear()
-
-
-
-
-
-
-# Modul initialization and configuration
-
-DB_PATH = './'
-TEMPLATE_PATH = ['./', './views/']
-TEMPLATES = {}
-DEBUG = False
-HTTP_CODES = {
- 100: 'CONTINUE',
- 101: 'SWITCHING PROTOCOLS',
- 200: 'OK',
- 201: 'CREATED',
- 202: 'ACCEPTED',
- 203: 'NON-AUTHORITATIVE INFORMATION',
- 204: 'NO CONTENT',
- 205: 'RESET CONTENT',
- 206: 'PARTIAL CONTENT',
- 300: 'MULTIPLE CHOICES',
- 301: 'MOVED PERMANENTLY',
- 302: 'FOUND',
- 303: 'SEE OTHER',
- 304: 'NOT MODIFIED',
- 305: 'USE PROXY',
- 306: 'RESERVED',
- 307: 'TEMPORARY REDIRECT',
- 400: 'BAD REQUEST',
- 401: 'UNAUTHORIZED',
- 402: 'PAYMENT REQUIRED',
- 403: 'FORBIDDEN',
- 404: 'NOT FOUND',
- 405: 'METHOD NOT ALLOWED',
- 406: 'NOT ACCEPTABLE',
- 407: 'PROXY AUTHENTICATION REQUIRED',
- 408: 'REQUEST TIMEOUT',
- 409: 'CONFLICT',
- 410: 'GONE',
- 411: 'LENGTH REQUIRED',
- 412: 'PRECONDITION FAILED',
- 413: 'REQUEST ENTITY TOO LARGE',
- 414: 'REQUEST-URI TOO LONG',
- 415: 'UNSUPPORTED MEDIA TYPE',
- 416: 'REQUESTED RANGE NOT SATISFIABLE',
- 417: 'EXPECTATION FAILED',
- 500: 'INTERNAL SERVER ERROR',
- 501: 'NOT IMPLEMENTED',
- 502: 'BAD GATEWAY',
- 503: 'SERVICE UNAVAILABLE',
- 504: 'GATEWAY TIMEOUT',
- 505: 'HTTP VERSION NOT SUPPORTED',
-}
-
-HTTP_ERROR_TEMPLATE = """
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
-<html>
- <head>
- <title>Error %(status)d: %(error_name)s</title>
- </head>
- <body>
- <h1>Error %(status)d: %(error_name)s</h1>
- <p>Sorry, the requested URL <tt>%(url)s</tt> caused an error:</p>
- <pre>
- %(error_message)s
- </pre>
- </body>
-</html>
-"""
-
-TRACEBACK_TEMPLATE = """
-<h2>Traceback:</h2>
-<pre>
-%s
-</pre>
-"""
-
-request = Request()
-response = Response()
-db = BottleDB()
-local = threading.local()
-
-#TODO: Global and app local configuration (debug, defaults, ...) is a mess
-
-def debug(mode=True):
- global DEBUG
- DEBUG = bool(mode)
-
-def optimize(mode=True):
- default_app().optimize = bool(mode)
-
-
diff --git a/module/web/main.html b/module/web/main.html
deleted file mode 100644
index 87f0d7408..000000000
--- a/module/web/main.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<title>pyLoad - Webinterface</title>
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
- <head>
- <title>pyLoad - Webinterface</title>
- <script src="main.js" type="text/javascript"></script>
- </head>
- <body>
- <h1>pyLoad - Webinterface</h1>
- <div name="status_server">
- Status: running Speed: 600kb/s Files in queue: 0
- </div>
- <div name="actions">
- <div id="add_urls">
- <form name="add_urls_form">
- <input type="text" name="new_url" />
- <input type="button" value="Add Link" onclick="addUrl(document.add_urls_form.new_url.value)" >
- </form>
- </div>
- (START) (PAUSE) (ADD)
- </div>
- <h2>Downloads</h2>
- <div id="downloads">
- Lade Downloads
- </div>
- </body>
-</html>
-
diff --git a/module/web/main.js b/module/web/main.js
deleted file mode 100644
index a286df991..000000000
--- a/module/web/main.js
+++ /dev/null
@@ -1,42 +0,0 @@
-function getXmlHttpRequestObject() {
- if (window.XMLHttpRequest) {
- return new XMLHttpRequest(); //Not IE
- } else if(window.ActiveXObject) {
- return new ActiveXObject("Microsoft.XMLHTTP"); //IE
- } else {
- alert("Your browser doesn't support the XmlHttpRequest object. Better upgrade to Firefox.");
- }
-}
-var req = getXmlHttpRequestObject();
-
-function getDownloads() {
- req.onreadystatechange = function() {
- if (req.readyState == 4) {
- if(req.status==200) {
- document.getElementById('downloads').innerHTML = req.responseText;
- } else {
- alert("Fehler:\nHTTP-Status: "+req.status+"\nHTTP-Statustext: "+req.statusText);
- }
- };
- }
- req.open("GET", '/downloads', true);
- req.send(null);
-}
-
-function addUrl(new_url) {
- req.onreadystatechange = function() {
- if (req.readyState == 4) {
- if(req.status==200) {
- document.getElementById('add_urls').innerHTML = req.responseText;
- } else {
- alert("Fehler:\nHTTP-Status: "+req.status+"\nHTTP-Statustext: "+req.statusText);
- }
- };
- }
- url = "/add=" + new_url
- req.open("GET", url, true);
- req.send(null);
-}
-
-window.setInterval("getDownloads()", 1000);
-
diff --git a/module/web/manage.py b/module/web/manage.py
new file mode 100644
index 000000000..ae9495854
--- /dev/null
+++ b/module/web/manage.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+from django.core.management import execute_manager
+
+try:
+ import settings # Assumed to be in the same directory.
+except ImportError:
+ import sys
+ sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ execute_manager(settings)
diff --git a/module/web/media/css/default.css b/module/web/media/css/default.css
new file mode 100644
index 000000000..b5701cf43
--- /dev/null
+++ b/module/web/media/css/default.css
@@ -0,0 +1,145 @@
+div.no{display:inline;margin:0;padding:0;}.hidden{display:none;}
+div.error{background:#fcc url(media/img/error.png) 0.5em 0px no-repeat;color:#000;border-bottom:1px solid #faa;font-size:90%;margin:0;padding-left:3em;overflow:hidden;}
+div.info{background:#ccf url(static/default/info.png) 0.5em 0px no-repeat;color:#000;border-bottom:1px solid #aaf;font-size:90%;margin:0;padding-left:3em;overflow:hidden;}
+div.success{background:#cfc url(static/default/success.png) 0.5em 0px no-repeat;color:#000;border-bottom:1px solid #afa;font-size:90%;margin:0;padding-left:3em;overflow:hidden;}
+div.notify{background:#ffc url(media/img/notify.png) 0.5em 0px no-repeat;color:#000;border-bottom:1px solid #ffa;font-size:90%;margin:0;padding-left:3em;overflow:hidden;}
+.medialeft{float:left;}.mediaright{float:right;}
+.mediacenter{display:block;margin-left:auto;margin-right:auto;}
+.leftalign{text-align:left;}
+.centeralign{text-align:center;}
+.rightalign{text-align:right;}
+em.u{font-style:normal;text-decoration:underline;}
+em em.u{font-style:italic;}
+.code .br0{color:#6c6;}
+.code .co1{color:#808080;font-style:italic;}
+.code .co2{color:#808080;font-style:italic;}
+.code .co3{color:#808080;}
+.code .coMULTI{color:#808080;font-style:italic;}
+.code .es0{color:#009;font-weight:bold;}.code .kw1{color:#b1b100;}
+.code .kw2{color:#000;font-weight:bold;}.code .kw3{color:#006;}
+.code .kw4{color:#933;}.code .kw5{color:#00f;}.code .me1{color:#060;}.code .me2{color:#060;}
+.code .nu0{color:#c6c;}.code .re0{color:#00f;}.code .re1{color:#00f;}.code .re2{color:#00f;}.code .re3{color:#f33;font-weight:bold;}.code .re4{color:#099;}.code .st0{color:#f00;}.code .sy0{color:#6c6;}
+div.dokuwiki table.pagelist,div.dokuwiki table.ul{border:0;padding:0;border-spacing:0;margin-bottom:1em;border-collapse:collapse;}
+div.dokuwiki table.pagelist tr{border-top:1px solid #8cacbb;border-bottom:1px solid #8cacbb;}
+div.dokuwiki table.pagelist th,div.dokuwiki table.pagelist td{padding:1px 1em 1px 0;}
+div.dokuwiki table.ul th,div.dokuwiki table.ul td{padding:0 1em 0 0;}
+div.dokuwiki table.ul ul{margin:0 0 0 1.5em;}
+div.dokuwiki table.pagelist th,div.dokuwiki table.ul th{background-color:#dee7ec;}
+div.dokuwiki th.page,div.dokuwiki th.date,div.dokuwiki th.user,div.dokuwiki th.desc,div.dokuwiki th.comments,div.dokuwiki th.linkbacks,div.dokuwiki th.tags,div.dokuwiki td.date,div.dokuwiki td.user,div.dokuwiki td.desc,div.dokuwiki td.comments,div.dokuwiki td.linkbacks,div.dokuwiki td.tags{color:#666;font-size:80%;}
+div.dokuwiki td.date{text-align:right;}div.dokuwiki div.include div.secedit{float:right;margin-left:1em;margin-top:-18px;}
+div.dokuwiki div.inclmeta{border-top:1px dotted #8cacbb;padding-top:0.2em;color:#666;font-size:80%;line-height:1.25;margin-top:0.5em;margin-bottom:2em;}
+div.dokuwiki div.inclmeta a.permalink{background:transparent url(media/img/link.gif) 0px 1px no-repeat;padding:1px 0px 1px 16px;}
+div.dokuwiki div.inclmeta abbr.published{background:transparent url(media/img/date.gif) 0px 1px no-repeat;padding:1px 0px 1px 16px;border-bottom:0;}
+div.dokuwiki div.inclmeta span.author{background:transparent url(media/img/user.gif) 0px 1px no-repeat;padding:1px 0px 1px 16px;}
+div.dokuwiki div.inclmeta span.comment{background:transparent url(media/img/comment.gif) 0px 1px no-repeat;padding:1px 0px 1px 16px;}
+div.dokuwiki div.inclmeta div.tags{border-top:0;font-size:100%;float:right;clear:none;}#plugin__manager{}#plugin__manager h2{margin-left:0;}
+#plugin__manager form{display:block;margin:0;padding:0;}
+#plugin__manager legend{display:none;}
+#plugin__manager fieldset{width:auto;}
+#plugin__manager .button{margin:0;}
+#plugin__manager p,#plugin__manager label{text-align:left;}
+#plugin__manager .hidden{display:none;}#plugin__manager .new{background:#dee7ec;}
+#plugin__manager input[disabled]{color:#ccc;border-color:#ccc;}
+#plugin__manager .pm_menu,#plugin__manager .pm_info{margin-left:0;text-align:left;}
+#plugin__manager .pm_menu{float:left;width:48%;}
+#plugin__manager .pm_info{float:right;width:50%;}
+#plugin__manager .common{}#plugin__manager .common form{}
+#plugin__manager .common fieldset{margin:0;padding:0 0 1.0em 0;text-align:left;border:none;}
+#plugin__manager .common label{padding:0 0 0.5em 0;}
+#plugin__manager .common input{}
+#plugin__manager .common input.edit{width:24em;margin:0.5em;}
+#plugin__manager .common .button{}
+#plugin__manager form.plugins{}
+#plugin__manager .plugins fieldset{color:#000;background:#fff;text-align:right;border-top:none;border-right:none;border-left:none;}
+#plugin__manager .plugins fieldset.protected{background:#fdd;color:#000;}
+#plugin__manager .plugins fieldset.disabled{background:#e0e0e0;color:#a8a8a8;}
+#plugin__manager .plugins .legend{color:#000;background:inherit;display:block;margin:0;padding:0;font-size:1em;line-height:1.4em;font-weight:normal;text-align:left;float:left;padding:0;clear:none;}
+#plugin__manager .plugins .button{font-size:95%;}#plugin__manager .plugins fieldset.buttons{border:none;}
+#plugin__manager .plugins fieldset.buttons .button{float:left;}
+#plugin__manager .pm_info h3{margin-left:0;}#plugin__manager .pm_info dl{margin:1em 0;padding:0;}
+#plugin__manager .pm_info dt{width:6em;float:left;clear:left;margin:0;padding:0;}
+#plugin__manager .pm_info dd{margin:0 0 0 7em;padding:0;background:none;}
+#plugin__manager .plugins .enable{float:left;width:auto;margin-right:0.5em;}
+#config__manager div.success,#config__manager div.error,#config__manager div.info{background-position:0.5em;padding:0.5em;text-align:center;}
+#config__manager fieldset{margin:1em;width:auto;margin-bottom:2em;background-color:#dee7ec;color:#000;padding:0 1em;}
+#config__manager legend{font-size:1.25em;}
+#config__manager form{}#config__manager table{margin:1em 0;width:100%;}#config__manager fieldset td{text-align:left;}
+#config__manager fieldset td.value{width:31em;}#config__manager td.label{padding:0.8em 0 0.6em 1em;vertical-align:top;
+}#config__manager td.label label{clear:left;display:block;}
+#config__manager td.label img{padding:0 10px;vertical-align:middle;float:right;}
+#config__manager td.label span.outkey{font-size:70%;margin-top:-1.7em;margin-left:-1em;display:block;background-color:#fff;color:#666;float:left;padding:0 0.1em;position:relative;z-index:1;}
+#config__manager td input.edit{width:30em;}#config__manager td .input{width:30.8em;}
+#config__manager td select.edit{}#config__manager td textarea.edit{width:27.5em;height:4em;}
+#config__manager tr .input,#config__manager tr input,#config__manager tr textarea,#config__manager tr select{background-color:#fff;color:#000;}
+#config__manager tr.default .input,#config__manager tr.default input,#config__manager tr.default textarea,#config__manager tr.default select,#config__manager .selectiondefault{background-color:#cdf;color:#000;}
+#config__manager tr.protected .input,#config__manager tr.protected input,#config__manager tr.protected textarea,#config__manager tr.protected select,#config__manager tr.protected .selection{background-color:#fcc!important;color:#000 !important;}
+#config__manager td.error{background-color:red;color:#000;}#config__manager .selection{width:14.8em;float:left;margin:0 0.3em 2px 0;}#config__manager .selection label{float:right;width:14em;font-size:90%;}
+* html #config__manager .selection label{padding-top:2px;}
+#config__manager .selection input.checkbox{padding-left:0.7em;}
+#config__manager .other{clear:both;padding-top:0.5em;}
+#config__manager .other label{padding-left:2px;font-size:90%;}.dokuwiki div.plugin_translation{float:right;font-size:95%;}
+.dokuwiki div.plugin_translation ul{display:inline;padding:0;margin:0;}
+.dokuwiki div.plugin_translation ul li{float:left;list-style-type:none;padding:0;margin:0;}
+.dokuwiki div.plugin_translation ul li a.wikilink1:link,.dokuwiki div.plugin_translation ul li a.wikilink1:hover,.dokuwiki div.plugin_translation ul li a.wikilink1:active,.dokuwiki div.plugin_translation ul li a.wikilink1:visited{background-color:#000080;color:#fff !important;text-decoration:none;padding:0 0.2em;margin:0.1em 0.2em;border:none !important;}
+.dokuwiki div.plugin_translation ul li a.wikilink2:link,.dokuwiki div.plugin_translation ul li a.wikilink2:hover,.dokuwiki div.plugin_translation ul li a.wikilink2:active,.dokuwiki div.plugin_translation ul li a.wikilink2:visited{background-color:#808080;color:#fff !important;text-decoration:none;padding:0 0.2em;margin:0.1em 0.2em;border:none !important;}
+.dokuwiki div.plugin_translation ul li a img{opacity:0.5;border:0;}
+.dokuwiki div.plugin_translation ul li a.wikilink2 img{}.dokuwiki div.plugin_translation span.curid a img{opacity:1.0;height:15px;}
+.dokuwiki div.plugin_translation ul li a:hover img{opacity:1.0;height:15px;}#user__manager tr.disabled{color:#6f6f6f;background:#e4e4e4;}
+#user__manager tr.user_info{vertical-align:top;}
+#user__manager div.edit_user{width:46%;float:left;}#user__manager table{margin-bottom:1em;}#user__manager input.button[disabled]{color:#ccc!important;border-color:#ccc!important;}div.dokuwiki div.newentry_form{clear:both;text-align:center;margin-bottom:1em;}
+div.dokuwiki #blog__newentry_form input.edit{width:95%;}div.dokuwiki tr.draft,div.dokuwiki div.draft{opacity:0.5;}
+div.dokuwiki div.autoarchive_selector ul{list-style-type:none;clear:left;margin:0 0.5em 0 0;}
+div.dokuwiki div.autoarchive_selector ul div.li{float:left;margin:0 1em 0 0;}
+div.dokuwiki div.autoarchive_selector ul ul{float:left;clear:none;}div.dokuwiki div.autoarchive_selector ul ul div.li{margin:0;}div#acl_manager div#acl__tree{font-size:90%;width:25%;height:300px;float:left;overflow:auto;border:1px solid #8cacbb;text-align:left;}
+div#acl_manager div#acl__tree a.cur{background-color:#ff9;font-weight:bold;}
+div#acl_manager div#acl__tree ul{list-style-type:none;margin:0;padding:0;}div#acl_manager div#acl__tree li{padding-left:1em;}div#acl_manager div#acl__tree ul img{margin-right:0.25em;cursor:pointer;}
+div#acl_manager div#acl__detail{width:73%;height:300px;float:right;overflow:auto;}
+div#acl_manager div#acl__detail fieldset{width:90%;}
+div#acl_manager div#acl__detail div#acl__user{border:1px solid #8cacbb;padding:0.5em;margin-bottom:0.6em;}
+div#acl_manager table.inline{width:100%;margin:0;}
+div#acl_manager .aclgroup{background:transparent url(media/img/group.png) 0px 1px no-repeat;padding:1px 0px 1px 18px;}
+div#acl_manager .acluser{background:transparent url(media/img/user.png) 0px 1px no-repeat;padding:1px 0px 1px 18px;}
+div#acl_manager .aclpage{background:transparent url(media/img/page.png) 0px 1px no-repeat;padding:1px 0px 1px 18px;}
+div#acl_manager .aclns{background:transparent url(media/img/ns.png) 0px 1px no-repeat;padding:1px 0px 1px 18px;}
+div#acl_manager label.disabled{color:#666!important;}
+#acl_manager label{text-align:left;font-weight:normal;display:inline;}
+#acl_manager table{margin-left:10%;width:80%;}#acl_manager table tr{background-color:inherit;}
+#acl_manager table tr:hover{background-color:#dee7ec;}
+
+
+a.interwiki{background:transparent url(/lib/images/interwiki.png) 0px 1px no-repeat;padding-left:16px;}
+a.iw_wp{background-image:url(/media/img/wp.gif)}
+a.iw_wpde{background-image:url(/media/img/wpde.gif)}
+a.iw_wpmeta{background-image:url(/media/img/wpmeta.gif)}
+a.iw_doku{background-image:url(/media/img/doku.gif)}
+a.iw_dokubug{background-image:url(/media/img/dokubug.gif)}
+a.iw_amazon{background-image:url(/media/img/amazon.gif)}
+a.iw_amazon_de{background-image:url(/media/img/amazon.de.gif)}
+a.iw_amazon_uk{background-image:url(/media/img/amazon.uk.gif)}
+a.iw_phpfn{background-image:url(/media/img/phpfn.gif)}
+a.iw_coral{background-image:url(/media/img/coral.gif)}
+a.iw_sb{background-image:url(/media/img/sb.gif)}
+a.iw_google{background-image:url(/media/img/google.gif)}
+a.iw_meatball{background-image:url(/media/img/meatball.gif)}
+a.iw_wiki{background-image:url(/media/img/wiki.gif)}
+a.mediafile{background:transparent url(/media/img/file.png) 0px 1px no-repeat;padding-left:18px;padding-bottom:1px;}a.mf_jpg{background-image:url(/media/img/jpg.png)}a.mf_jpeg{background-image:url(/media/img/jpeg.png)}a.mf_gif{background-image:url(/media/img/gif.png)}a.mf_png{background-image:url(/media/img/png.png)}a.mf_tgz{background-image:url(/media/img/tgz.png)}a.mf_tar{background-image:url(/media/img/tar.png)}a.mf_gz{background-image:url(/media/img/gz.png)}a.mf_bz2{background-image:url(/media/img/bz2.png)}
+a.mf_zip{background-image:url(/media/img/zip.png)}a.mf_rar{background-image:url(/media/img/rar.png)}a.mf_pdf{background-image:url(/media/img/pdf.png)}a.mf_ps{background-image:url(/media/img/ps.png)}a.mf_doc{background-image:url(/media/img/doc.png)}a.mf_xls{background-image:url(/media/img/xls.png)}a.mf_ppt{background-image:url(/media/img/ppt.png)}a.mf_rtf{background-image:url(/media/img/rtf.png)}a.mf_swf{background-image:url(/media/img/swf.png)}a.mf_rpm{background-image:url(/media/img/rpm.png)}a.mf_deb{background-image:url(/media/img/deb.png)}a.mf_sxw{background-image:url(/media/img/sxw.png)}a.mf_sxc{background-image:url(/media/img/sxc.png)}a.mf_sxi{background-image:url(/media/img/sxi.png)}a.mf_sxd{background-image:url(/media/img/sxd.png)}a.mf_odc{background-image:url(/media/img/odc.png)}a.mf_odf{background-image:url(/media/img/odf.png)}a.mf_odg{background-image:url(/media/img/odg.png)}
+a.mf_odi{background-image:url(/media/img/odi.png)}a.mf_odp{background-image:url(/media/img/odp.png)}a.mf_ods{background-image:url(/media/img/ods.png)}a.mf_odt{background-image:url(/media/img/odt.png)}body{margin:0px;padding:0px;background-color:white;color:black;font-size:12px;font-family:Verdana,Helvetica,"Lucida Grande",Lucida,Arial,sans-serif;font-family:sans-serif;font-size:99,96%;font-size-adjust:none;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;}hr{border-width:0px;border-bottom:1px #aaa dotted;}img{border:none;}form{margin:0px;padding:0px;border:none;display:inline;background:transparent;}ul li{margin:5px;}textarea{font-family:monospace;}table{margin:0.5em 0;border-collapse:collapse;}td{padding:0.25em;border:1pt solid #ADB9CC;}a{color:#3465a4;text-decoration:none;}a:hover{text-decoration:underline;}
+a.wikilink2{color:#a40000 !important;}.dokuwiki h1 a,.dokuwiki h2 a,.dokuwiki h3 a,.dokuwiki h4 a,.dokuwiki h5 a,.dokuwiki a.nolink{color:#000 !important;text-decoration:none !important;}
+option{border:0px none #fff;}strong.highlight{background-color:#fc9;padding:1pt;}#pagebottom{clear:both;}hr{height:1px;color:#c0c0c0;background-color:#c0c0c0;border:none;margin:.2em 0 .2em 0;}pre{padding:0.5em;font-family:courier,monospace;border:1px solid #c0c0c0;background:#F0ECE6;white-space:pre;white-space:pre-wrap;word-wrap:break-word;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;}.invisible{margin:0px;border:0px;padding:0px;height:0px;visibility:hidden;}.left{float:left !important;}.right{float:right !important;}.center{text-align:center;}div#body-wrapper{padding:40px 40px 10px 40px;font-size:127%;}
+div#content{margin-top:-20px;padding:0;font-size:14px;color:black;line-height:1.5em;}h1,h2,h3,h4,h5,h6{background:transparent none repeat scroll 0 0;border-bottom:1px solid #aaa;color:black;font-weight:normal;margin:0;padding:0;padding-bottom:0.17em;padding-top:0.5em;}h1{font-size:188%;line-height:1.2em;margin-bottom:0.1em;padding-bottom:0;}h2{font-size:150%;}h3,h4,h5,h6{border-bottom:none;font-weight:bold;}h3{font-size:132%;}h4{font-size:116%;}h5{font-size:100%;}h6{font-size:80%;}ul#page-actions{float:right;margin:10px 10px 0 10px;padding:6px;color:black;background-color:#ececec;list-style-type:none;-moz-border-radius:5px;}ul#user-actions{padding:5px;margin:0;display:inline;color:black;background-color:#ececec;list-style-type:none;-moz-border-radius:3px;}ul#page-actions li,ul#user-actions li{display:inline;}ul#page-actions a,ul#user-actions a{text-decoration:none;color:black;display:inline;margin:0 3px;padding:2px 0px 2px 18px;}
+ul#page-actions a:hover,ul#page-actions a:focus,ul#user-actions a:hover,ul#user-actions a:focus{text-decoration:underline;}.hidden{display:none;}a.urlextern{color:#36B;background:transparent url(/media/img/external-10.2.png) no-repeat scroll right center;padding:0 13px 0 0;}a[href^="http://www.pyload.org"]:after,a.noextlink:after{background:none;padding:0;}a.action.index{background:transparent url(/media/img/wiki-tools-index.png) 0px 1px no-repeat;}a.action.recent{background:transparent url(/media/img/wiki-tools-recent.png) 0px 1px no-repeat;}a.logout{background:transparent url(/media/img/user-actions-logout.png) 0px 1px no-repeat;}
+a.admin{background:transparent url(/media/img/user-actions-admin.png) 0px 1px no-repeat;}a.profile{background:transparent url(/media/img/user-actions-profile.png) 0px 1px no-repeat;}a.create,a.edit{background:transparent url(/media/img/page-tools-edit.png) 0px 1px no-repeat;}a.source,a.show{background:transparent url(/media/img/page-tools-source.png) 0px 1px no-repeat;}a.revisions{background:transparent url(/media/img/page-tools-revisions.png) 0px 1px no-repeat;}a.subscribe,a.unsubscribe{background:transparent url(/media/img/page-tools-subscribe.png) 0px 1px no-repeat;}a.backlink{background:transparent url(/media/img/page-tools-backlinks.png) 0px 1px no-repeat;}#head-panel{background:#525252 url(/media/img/head_bg1.png) bottom left repeat-x;}#head-panel h1{display:none;margin:0;text-decoration:none;padding-top:0.8em;padding-left:3.3em;font-size:2.6em;color:#eeeeec;}#head-panel #head-logo{float:left;margin:5px 0 -15px 5px;padding:0;overflow:visible;}#head-menu{background:transparent url(/media/img/tabs-border-bottom.png) 0 100% repeat-x;width:100%;float:left;margin:0;padding:0;padding-top:0.8em;}
+#head-menu ul{list-style:none;margin:0 1em 0 2em;}#head-menu ul li{float:left;margin:0;margin-left:0.3em;font-size:14px;margin-bottom:4px;}#head-menu ul li.selected,#head-menu ul li:hover{margin-bottom:0px;}#head-menu ul li a img{height:22px;width:22px;vertical-align:middle;}#head-menu ul li a,#head-menu ul li a:link{float:left;text-decoration:none;color:#555;background:#eaeaea url(/media/img/tab-background.png) 0 100% repeat-x;padding:3px 7px 3px 7px;border:2px solid #ccc;border-bottom:0px solid transparent;padding-bottom:3px;-moz-border-radius:5px;}#head-menu ul li a:hover,#head-menu ul li a:focus{color:#111;padding-bottom:7px;border-bottom:0px none transparent;outline:none;-moz-border-radius-bottomright:0px;-moz-border-radius-bottomleft:0px;}#head-menu ul li a:focus{margin-bottom:-4px;}#head-menu ul li.selected a{color:#3566A5;background:#fff;padding-bottom:7px;border-bottom:0px none transparent;-moz-border-radius-bottomright:0px;-moz-border-radius-bottomleft:0px;}#head-menu ul li.selected a:hover,#head-menu ul li.selected a:focus{color:#111;}div#head-search-and-login{float:right;margin:0 1em 0 0;background-color:#222;padding:4px;color:white;-moz-border-radius-bottomright:6px;-moz-border-radius-bottomleft:6px;}div#head-search-and-login form{display:inline;padding:0 3px;}div#head-search-and-login form input{border:2px solid #888;background:#eee;font-size:14px;padding:2px;-moz-border-radius:3px;}div#head-search-and-login form input:focus{background:#fff;}#head-search{font-size:14px;}#head-username,#head-password{width:80px;font-size:14px;}#pageinfo{clear:both;color:#888;padding:0.6em 0;margin:0;}#foot{font-style:normal;color:#888;text-align:center;}#foot a{color:#aaf;}#foot img{vertical-align:middle;}ul.toc{padding:0;padding-left:20px;margin-left:0;margin-right:10px;list-style:none;}ul.toc li{list-style:circle;}ul.toc li a{text-decoration:none;color:black;}ul.toc li a:hover{text-decoration:underline;}div.toc{border:1px dotted #888;background:#f0f0f0;margin:1em 0 1em 1em;float:right;font-size:95%;}div.toc .tocheader{font-weight:bold;margin:0.5em 1em;}div.toc ol{margin:1em 0.5em 1em 1em;padding:0;}div.toc ol li{margin:0;padding:0;margin-left:1em;}div.toc ol ol{margin:0.5em 0.5em 0.5em 1em;padding:0;}div.recentchanges table{clear:both;}div#editor-help{font-size:90%;border:1px dotted #888;padding:0ex 1ex 1ex 1ex;background:#f7f6f2;}div#preview{margin-top:1em;}label.block{display:block;text-align:right;font-weight:bold;}label.simple{display:block;text-align:left;font-weight:normal;}label.block input.edit{width:50%;}fieldset{width:300px;text-align:center;padding:0.5em;margin:auto;}div.editor{margin:0 0 0 0;}table{margin:0.5em 0;border-collapse:collapse;}td{padding:0.25em;border:1pt solid #ADB9CC;}td p{margin:0;padding:0;}.u{text-decoration:underline;}.footnotes ul{padding:0 2em;margin:0 0 1em;}.footnotes li{list-style:none;}.recentchanges p{margin:0.25em;}.recentchanges td{vertical-align:top;border:none;border-bottom:1pt solid #F0ECE6;background:#F7F6F2;}.rcdaybreak td{background:#729fcf;border:none;}.rcdaybreak td a{font-size:0.88em;}.rcicon1,.rcicon2{text-align:center;}.rcpagelink{width:33%;}.rctime{font-size:0.88em;white-space:nowrap;}.rceditor{white-space:nowrap;font-size:0.88em;}.rccomment{width:66%;color:gray;font-size:0.88em;}.rcrss{float:right;}.recentchanges[dir="rtl"] .rcrss{float:left;}.userpref table,.userpref td{border:none;}div.codearea{margin:0.5em 0;padding:0;border:1pt solid #AEBDCC;background-color:#F3F5F7;color:black;}div.codearea pre{margin:0;padding:10pt;border:none;}a.codenumbers{margin:0 10pt;font-size:0.85em;color:gray;}div.codearea pre span.LineNumber{color:gray;}div.codearea pre span.ID{color:#000;}div.codearea pre span.Operator{color:#0000c0;}div.codearea pre span.Char{color:#004080;}div.codearea pre span.Comment{color:#008000;}div.codearea pre span.Number{color:#0080c0;}div.codearea pre span.String{color:#004080;}div.codearea pre span.SPChar{color:#0000c0;}div.codearea pre span.ResWord{color:#a00000;}div.codearea pre span.ConsWord{color:#008080;font-weight:bold;}div.codearea pre span.Error{color:#ff8080;border:solid 1.5pt #f00;}div.codearea pre span.ResWord2{color:#0080ff;font-weight:bold;}div.codearea pre span.Special{color:#00f;}div.codearea pre span.Preprc{color:#803999;}#message{clear:both;padding:5px 10px;background-color:#eee;border-bottom:2px solid #ccc;}#message p{margin:5px 0;padding:0;font-weight:bold;}#message div.buttons{font-weight:normal;}.diff{width:99%;}.diff-title{background-color:#C0C0C0;}.searchresult dd span{font-weight:bold;}.diff{width:100%;border:none;}.diff-blockheader{font-weight:bold;background:#e5e5e5;font-size:1.2em;border-top:2px solid #444;padding:5px;}.diff th{font-size:120%;width:50%;font-weight:normal;text-align:left;padding-bottom:3px;}.diff td{font-family:monospace;font-size:100%;border:none;}.diff-addedline{background-color:#dfd;}.diff-deletedline{background-color:#ffb;}.diff-context{color:#888;}.diff-addedline{background-color:#E0FFE0;vertical-align:sub;}.diff-deletedline{background-color:#FFFFE0;background-color:#f4cece;vertical-align:sub;}
+.diff-addedline strong{background-color:#80FF80;background-color:#8ae234;}
+.diff-deletedline strong{background-color:#FFFF80;background-color:#ef2929;background-color:#d78383;}
+
+
+
+.box{ background:url(/media/img/progress-bar-back.gif) right center no-repeat; width:200px; height:20px; float:left; }
+.perc{ background:url(/media/img/progress-bar.gif) right center no-repeat; height:20px; }
+.boxtext{ font-family:tahoma, arial, sans-serif; font-size:11px; color:#000; float:none; padding:3px 0 0 10px; }
+.statusbutton{width:32px;height:32px;float:left;margin-left:-32px;margin-right:5px;opacity:0;cursor:pointer}
+
+.dlsize{float:left; padding-right: 8px;}
+.dlspeed{float:left; padding-right: 8px;} \ No newline at end of file
diff --git a/module/web/static/window.css b/module/web/media/css/window.css
index aaccae082..aaccae082 100644
--- a/module/web/static/window.css
+++ b/module/web/media/css/window.css
diff --git a/module/web/static/default/Button-Add-grey.png b/module/web/media/img/Button-Add-grey.png
index 6659e230e..6659e230e 100644
--- a/module/web/static/default/Button-Add-grey.png
+++ b/module/web/media/img/Button-Add-grey.png
Binary files differ
diff --git a/module/web/static/default/Button-Add.png b/module/web/media/img/Button-Add.png
index 602da4131..602da4131 100644
--- a/module/web/static/default/Button-Add.png
+++ b/module/web/media/img/Button-Add.png
Binary files differ
diff --git a/module/web/static/default/Button-Pause-grey.png b/module/web/media/img/Button-Pause-grey.png
index d1017e974..d1017e974 100644
--- a/module/web/static/default/Button-Pause-grey.png
+++ b/module/web/media/img/Button-Pause-grey.png
Binary files differ
diff --git a/module/web/static/default/Button-Pause.png b/module/web/media/img/Button-Pause.png
index 68f3ffc3a..68f3ffc3a 100644
--- a/module/web/static/default/Button-Pause.png
+++ b/module/web/media/img/Button-Pause.png
Binary files differ
diff --git a/module/web/static/default/Button-Play-grey.png b/module/web/media/img/Button-Play-grey.png
index 9f44c2289..9f44c2289 100644
--- a/module/web/static/default/Button-Play-grey.png
+++ b/module/web/media/img/Button-Play-grey.png
Binary files differ
diff --git a/module/web/static/default/Button-Play.png b/module/web/media/img/Button-Play.png
index 1ce1ed913..1ce1ed913 100644
--- a/module/web/static/default/Button-Play.png
+++ b/module/web/media/img/Button-Play.png
Binary files differ
diff --git a/module/web/static/window/big_button.gif b/module/web/media/img/big_button.gif
index 7680490ea..7680490ea 100644
--- a/module/web/static/window/big_button.gif
+++ b/module/web/media/img/big_button.gif
Binary files differ
diff --git a/module/web/static/window/big_button_over.gif b/module/web/media/img/big_button_over.gif
index 2e3ee10d2..2e3ee10d2 100644
--- a/module/web/static/window/big_button_over.gif
+++ b/module/web/media/img/big_button_over.gif
Binary files differ
diff --git a/module/web/static/window/body.png b/module/web/media/img/body.png
index 7ff1043e0..7ff1043e0 100644
--- a/module/web/static/window/body.png
+++ b/module/web/media/img/body.png
Binary files differ
diff --git a/module/web/static/window/closebtn.gif b/module/web/media/img/closebtn.gif
index 3e27e6030..3e27e6030 100644
--- a/module/web/static/window/closebtn.gif
+++ b/module/web/media/img/closebtn.gif
Binary files differ
diff --git a/module/web/static/window/drag_corner.gif b/module/web/media/img/drag_corner.gif
index befb1adf1..befb1adf1 100644
--- a/module/web/static/window/drag_corner.gif
+++ b/module/web/media/img/drag_corner.gif
Binary files differ
diff --git a/module/web/static/window/full.png b/module/web/media/img/full.png
index fea52af76..fea52af76 100644
--- a/module/web/static/window/full.png
+++ b/module/web/media/img/full.png
Binary files differ
diff --git a/module/web/static/default/head-login.png b/module/web/media/img/head-login.png
index b59b7cbbf..b59b7cbbf 100644
--- a/module/web/static/default/head-login.png
+++ b/module/web/media/img/head-login.png
Binary files differ
diff --git a/module/web/static/default/head-menu-development.png b/module/web/media/img/head-menu-development.png
index 8ef08e2e5..8ef08e2e5 100644
--- a/module/web/static/default/head-menu-development.png
+++ b/module/web/media/img/head-menu-development.png
Binary files differ
diff --git a/module/web/static/default/head-menu-download.png b/module/web/media/img/head-menu-download.png
index 98c5da9db..98c5da9db 100644
--- a/module/web/static/default/head-menu-download.png
+++ b/module/web/media/img/head-menu-download.png
Binary files differ
diff --git a/module/web/static/default/head-menu-home.png b/module/web/media/img/head-menu-home.png
index 9d62109aa..9d62109aa 100644
--- a/module/web/static/default/head-menu-home.png
+++ b/module/web/media/img/head-menu-home.png
Binary files differ
diff --git a/module/web/static/default/head-menu-index.png b/module/web/media/img/head-menu-index.png
index 44d631064..44d631064 100644
--- a/module/web/static/default/head-menu-index.png
+++ b/module/web/media/img/head-menu-index.png
Binary files differ
diff --git a/module/web/static/default/head-menu-news.png b/module/web/media/img/head-menu-news.png
index 43950ebc9..43950ebc9 100644
--- a/module/web/static/default/head-menu-news.png
+++ b/module/web/media/img/head-menu-news.png
Binary files differ
diff --git a/module/web/static/default/head-menu-recent.png b/module/web/media/img/head-menu-recent.png
index fc9b0497f..fc9b0497f 100644
--- a/module/web/static/default/head-menu-recent.png
+++ b/module/web/media/img/head-menu-recent.png
Binary files differ
diff --git a/module/web/static/default/head-menu-wiki.png b/module/web/media/img/head-menu-wiki.png
index 07cf0102d..07cf0102d 100644
--- a/module/web/static/default/head-menu-wiki.png
+++ b/module/web/media/img/head-menu-wiki.png
Binary files differ
diff --git a/module/web/static/default/head-search-noshadow.png b/module/web/media/img/head-search-noshadow.png
index aafdae015..aafdae015 100644
--- a/module/web/static/default/head-search-noshadow.png
+++ b/module/web/media/img/head-search-noshadow.png
Binary files differ
diff --git a/module/web/static/default/head_bg1.png b/module/web/media/img/head_bg1.png
index f2848c3cc..f2848c3cc 100644
--- a/module/web/static/default/head_bg1.png
+++ b/module/web/media/img/head_bg1.png
Binary files differ
diff --git a/module/web/static/default/page-tools-backlinks.png b/module/web/media/img/page-tools-backlinks.png
index 3eb6a9ce3..3eb6a9ce3 100644
--- a/module/web/static/default/page-tools-backlinks.png
+++ b/module/web/media/img/page-tools-backlinks.png
Binary files differ
diff --git a/module/web/static/default/page-tools-edit.png b/module/web/media/img/page-tools-edit.png
index 188e1c12b..188e1c12b 100644
--- a/module/web/static/default/page-tools-edit.png
+++ b/module/web/media/img/page-tools-edit.png
Binary files differ
diff --git a/module/web/static/default/page-tools-revisions.png b/module/web/media/img/page-tools-revisions.png
index 5c3b8587f..5c3b8587f 100644
--- a/module/web/static/default/page-tools-revisions.png
+++ b/module/web/media/img/page-tools-revisions.png
Binary files differ
diff --git a/module/web/static/default/progress-bar-back.gif b/module/web/media/img/progress-bar-back.gif
index 0c8f68211..0c8f68211 100644
--- a/module/web/static/default/progress-bar-back.gif
+++ b/module/web/media/img/progress-bar-back.gif
Binary files differ
diff --git a/module/web/static/default/progress-bar.gif b/module/web/media/img/progress-bar.gif
index 746f77175..746f77175 100644
--- a/module/web/static/default/progress-bar.gif
+++ b/module/web/media/img/progress-bar.gif
Binary files differ
diff --git a/module/web/static/default/pyload-logo-edited3.5-new-font-small.png b/module/web/media/img/pyload-logo-edited3.5-new-font-small.png
index 2443cd8b1..2443cd8b1 100644
--- a/module/web/static/default/pyload-logo-edited3.5-new-font-small.png
+++ b/module/web/media/img/pyload-logo-edited3.5-new-font-small.png
Binary files differ
diff --git a/module/web/static/default/tab-background.png b/module/web/media/img/tab-background.png
index 29a5d1991..29a5d1991 100644
--- a/module/web/static/default/tab-background.png
+++ b/module/web/media/img/tab-background.png
Binary files differ
diff --git a/module/web/static/default/tabs-border-bottom.png b/module/web/media/img/tabs-border-bottom.png
index 02440f428..02440f428 100644
--- a/module/web/static/default/tabs-border-bottom.png
+++ b/module/web/media/img/tabs-border-bottom.png
Binary files differ
diff --git a/module/web/static/default/user-actions-logout.png b/module/web/media/img/user-actions-logout.png
index 0010931e2..0010931e2 100644
--- a/module/web/static/default/user-actions-logout.png
+++ b/module/web/media/img/user-actions-logout.png
Binary files differ
diff --git a/module/web/static/default/user-actions-profile.png b/module/web/media/img/user-actions-profile.png
index 46573fff6..46573fff6 100644
--- a/module/web/static/default/user-actions-profile.png
+++ b/module/web/media/img/user-actions-profile.png
Binary files differ
diff --git a/module/web/static/default/home.js b/module/web/media/js/home.js
index 025dcfcc7..025dcfcc7 100644
--- a/module/web/static/default/home.js
+++ b/module/web/media/js/home.js
diff --git a/module/web/static/mootools-1.2.3-core.js b/module/web/media/js/mootools-1.2.3-core.js
index 25f1f9d03..25f1f9d03 100644
--- a/module/web/static/mootools-1.2.3-core.js
+++ b/module/web/media/js/mootools-1.2.3-core.js
diff --git a/module/web/static/mootools-1.2.3.1-more.js b/module/web/media/js/mootools-1.2.3.1-more.js
index f3e4b4121..f3e4b4121 100644
--- a/module/web/static/mootools-1.2.3.1-more.js
+++ b/module/web/media/js/mootools-1.2.3.1-more.js
diff --git a/module/web/static/default/status.js b/module/web/media/js/status.js
index 3923e80ca..3923e80ca 100644
--- a/module/web/static/default/status.js
+++ b/module/web/media/js/status.js
diff --git a/module/web/pyload.db b/module/web/pyload.db
new file mode 100644
index 000000000..8d34ef89c
--- /dev/null
+++ b/module/web/pyload.db
Binary files differ
diff --git a/module/web/pyload/__init__.py b/module/web/pyload/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/module/web/pyload/__init__.py
diff --git a/module/web/pyload/admin.py b/module/web/pyload/admin.py
new file mode 100644
index 000000000..40a96afc6
--- /dev/null
+++ b/module/web/pyload/admin.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
diff --git a/module/web/pyload/models.py b/module/web/pyload/models.py
new file mode 100644
index 000000000..293c01109
--- /dev/null
+++ b/module/web/pyload/models.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from django.db import models
+#from django.contrib.auth.models.User import User as UserProfile
+# Create your models here.
+
+
+class Perm(models.Model):
+ """ extended pyLoad user Profile """
+
+ #user = models.ForeignKey(UserProfile, unique=True)
+ #template = models.CharField(maxlength=30)
+
+ class Meta:
+ permissions = (
+ ("can_see_dl", "Can see Downloads"),
+ ("can_add", "Can add Downloads"),
+ ("can_delete", "Can delete Downloads"),
+ ("can_download", "Can download Files"),
+ ("can_see_logs", "Can see logs"),
+ ("can_change_status", "Can change status"),
+ ) \ No newline at end of file
diff --git a/module/web/pyload/tests.py b/module/web/pyload/tests.py
new file mode 100644
index 000000000..2247054b3
--- /dev/null
+++ b/module/web/pyload/tests.py
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
diff --git a/module/web/pyload/urls.py b/module/web/pyload/urls.py
new file mode 100644
index 000000000..9c7942492
--- /dev/null
+++ b/module/web/pyload/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('',
+ (r'^login/$', 'pyload.views.login'),
+ (r'^home/$', 'pyload.views.home'),
+ (r'^test/$', 'pyload.views.home'),
+)
diff --git a/module/web/pyload/views.py b/module/web/pyload/views.py
new file mode 100644
index 000000000..c42511ede
--- /dev/null
+++ b/module/web/pyload/views.py
@@ -0,0 +1,80 @@
+# Create your views here.
+from django.http import HttpResponse
+from django.http import HttpResponseRedirect
+from django.http import HttpResponseGone
+from django.conf import settings
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+from django.contrib.auth.decorators import login_required
+from os.path import join
+
+
+def check_server(function):
+ def _dec(view_func):
+ def _view(request, *args, **kwargs):
+ try:
+ version = settings.PYLOAD.get_server_version()
+ return view_func(request, *args, **kwargs)
+ except Exception, e:
+ return base(request, messages=['Can\'t connect to pyLoad. Please check your configuration and make sure pyLoad is running.',str(e)])
+
+ _view.__name__ = view_func.__name__
+ _view.__dict__ = view_func.__dict__
+ _view.__doc__ = view_func.__doc__
+
+ return _view
+
+ if function is None:
+ return _dec
+ else:
+ return _dec(function)
+
+
+def permission(perm):
+ def _dec(view_func):
+ def _view(request, *args, **kwargs):
+ if request.user.has_perm(perm):
+ return view_func(request, *args, **kwargs)
+ else:
+ return base(request, messages=['You don\'t have permission to view this page.'])
+
+ _view.__name__ = view_func.__name__
+ _view.__dict__ = view_func.__dict__
+ _view.__doc__ = view_func.__doc__
+
+ return _view
+
+ return _dec
+
+
+def base(request, messages):
+ return render_to_response(join(settings.TEMPLATE,'base.html'), {'messages': messages},RequestContext(request))
+
+@login_required
+#@permission('perm.permissions.can_see_dl') @TODO: Permissions not working :(
+@check_server
+def home(request):
+ return render_to_response(join(settings.TEMPLATE,'home.html'), RequestContext(request))
+
+
+@login_required
+#@permission('pyload.perm.can_see_dl')
+@check_server
+def queue(request):
+ return render_to_response(join(settings.TEMPLATE,'queue.html'), RequestContext(request))
+
+
+@login_required
+#@permission('pyload.user.can_download')
+@check_server
+def downloads(request):
+ return render_to_response(join(settings.TEMPLATE,'downloads.html'), RequestContext(request))
+
+
+@login_required
+#@permission('pyload.user.can_see_logs')
+@check_server
+def logs(request):
+ return render_to_response(join(settings.TEMPLATE,'logs.html'), RequestContext(request))
+
+ \ No newline at end of file
diff --git a/module/web/settings.py b/module/web/settings.py
new file mode 100644
index 000000000..0dc86d699
--- /dev/null
+++ b/module/web/settings.py
@@ -0,0 +1,127 @@
+# -*- coding: utf-8 -*-
+# Django settings for pyload project.
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+import ConfigParser
+import os.path
+from os import chdir
+from os.path import dirname
+from os.path import abspath
+from os import sep
+import xmlrpclib
+
+SERVER_VERSION = "0.3"
+
+PROJECT_DIR = os.path.dirname(__file__)
+
+#chdir(dirname(abspath(__file__)) + sep)
+config = ConfigParser.SafeConfigParser()
+config.read(os.path.join(PROJECT_DIR,"..","..","config"))
+
+ssl = ""
+
+if config.get("ssl", "activated") == "True":
+ ssl = "s"
+
+server_url = "http%s://%s:%s@%s:%s/" % (
+ ssl,
+ config.get("remote", "username"),
+ config.get("remote", "password"),
+ config.get("remote", "listenaddr"),
+ config.get("remote", "port")
+ )
+
+PYLOAD = xmlrpclib.ServerProxy(server_url, allow_none=True)
+
+TEMPLATE = config.get('webinterface','template')
+
+ADMINS = (
+ # ('Your Name', 'your_email@domain.com'),
+ )
+
+MANAGERS = ADMINS
+
+DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+DATABASE_NAME = 'pyload.db' # Or path to database file if using sqlite3.
+DATABASE_USER = '' # Not used with sqlite3.
+DATABASE_PASSWORD = '' # Not used with sqlite3.
+DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
+DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'America/Chicago'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = os.path.join(PROJECT_DIR, "media/")
+
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+
+#MEDIA_URL = 'http://localhost:8000/media'
+MEDIA_URL = '/media/'
+#MEDIA_URL = os.path.join(PROJECT_DIR, "media/")
+
+LOGIN_REDIRECT_URL = "/"
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/media/admin/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = '+u%%1t&c7!e$0$*gu%w2$@to)h0!&x-r*9e+-=wa4*zxat%x^t'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.load_template_source',
+ 'django.template.loaders.app_directories.load_template_source',
+ # 'django.template.loaders.eggs.load_template_source',
+ )
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ )
+
+ROOT_URLCONF = 'urls'
+
+TEMPLATE_DIRS = (
+ # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+ # Always use forward slashes, even on Windows.
+ # Don't forget to use absolute paths, not relative paths.
+ os.path.join(PROJECT_DIR, "templates"),
+ )
+
+INSTALLED_APPS = (
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ #'django.contrib.sites',
+ 'django.contrib.admin',
+ 'pyload',
+ 'ajax',
+ )
+
+
+AUTH_PROFILE_MODULE = 'pyload.User'
+LOGIN_URL = '/login' \ No newline at end of file
diff --git a/module/web/static/default.css b/module/web/static/default.css
deleted file mode 100644
index fd2e85eb9..000000000
--- a/module/web/static/default.css
+++ /dev/null
@@ -1,189 +0,0 @@
-a.interwiki{background:transparent url(static/default/interwiki.png) 0px 1px no-repeat;padding-left:16px;}
-a.iw_wp{background-image:url(static/default/interwiki/wp.gif)}
-a.iw_wpde{background-image:url(static/default/interwiki/wpde.gif)}
-a.iw_wpmeta{background-image:url(static/default/interwiki/wpmeta.gif)}
-a.iw_doku{background-image:url(static/default/interwiki/doku.gif)}
-a.iw_dokubug{background-image:url(static/default/interwiki/dokubug.gif)}
-a.iw_amazon{background-image:url(static/default/interwiki/amazon.gif)}
-a.iw_amazon_de{background-image:url(static/default/interwiki/amazon.de.gif)}
-a.iw_amazon_uk{background-image:url(static/default/interwiki/amazon.uk.gif)}
-a.iw_phpfn{background-image:url(static/default/interwiki/phpfn.gif)}
-a.iw_coral{background-image:url(static/default/interwiki/coral.gif)}
-a.iw_sb{background-image:url(static/default/interwiki/sb.gif)}
-a.iw_google{background-image:url(static/default/interwiki/google.gif)}
-a.iw_meatball{background-image:url(static/default/interwiki/meatball.gif)}
-a.iw_wiki{background-image:url(static/default/interwiki/wiki.gif)}
-a.mediafile{background:transparent url(static/default/file.png) 0px 1px no-repeat;padding-left:18px;padding-bottom:1px;}
-a.mf_jpg{background-image:url(static/default/jpg.png)}
-a.mf_jpeg{background-image:url(static/default/jpeg.png)}
-a.mf_gif{background-image:url(static/default/gif.png)}
-a.mf_png{background-image:url(static/default/png.png)}
-a.mf_tgz{background-image:url(static/default/tgz.png)}
-a.mf_tar{background-image:url(static/default/tar.png)}
-a.mf_gz{background-image:url(static/default/gz.png)}
-a.mf_bz2{background-image:url(static/default/bz2.png)}
-a.mf_zip{background-image:url(static/default/zip.png)}
-a.mf_rar{background-image:url(static/default/rar.png)}
-a.mf_pdf{background-image:url(static/default/pdf.png)}
-a.mf_ps{background-image:url(static/default/ps.png)}
-a.mf_doc{background-image:url(static/default/doc.png)}
-a.mf_xls{background-image:url(static/default/xls.png)}
-a.mf_ppt{background-image:url(static/default/ppt.png)}
-a.mf_rtf{background-image:url(static/default/rtf.png)}
-a.mf_swf{background-image:url(static/default/swf.png)}
-a.mf_rpm{background-image:url(static/default/rpm.png)}
-a.mf_deb{background-image:url(static/default/deb.png)}
-a.mf_sxw{background-image:url(static/default/sxw.png)}
-a.mf_sxc{background-image:url(static/default/sxc.png)}
-a.mf_sxi{background-image:url(static/default/sxi.png)}
-a.mf_sxd{background-image:url(static/default/sxd.png)}
-a.mf_odc{background-image:url(static/default/odc.png)}
-a.mf_odf{background-image:url(static/default/odf.png)}
-a.mf_odg{background-image:url(static/default/odg.png)}a.mf_odi{background-image:url(static/default/odi.png)}
-a.mf_odp{background-image:url(static/default/odp.png)}a.mf_ods{background-image:url(static/default/ods.png)}
-a.mf_odt{background-image:url(static/default/odt.png)}div.clearer{clear:both;line-height:0;height:0;overflow:hidden;}
-div.no{display:inline;margin:0;padding:0;}.hidden{display:none;}
-div.error{background:#fcc url(static/default/error.png) 0.5em 0px no-repeat;color:#000;border-bottom:1px solid #faa;font-size:90%;margin:0;padding-left:3em;overflow:hidden;}
-div.info{background:#ccf url(static/default/info.png) 0.5em 0px no-repeat;color:#000;border-bottom:1px solid #aaf;font-size:90%;margin:0;padding-left:3em;overflow:hidden;}
-div.success{background:#cfc url(static/default/success.png) 0.5em 0px no-repeat;color:#000;border-bottom:1px solid #afa;font-size:90%;margin:0;padding-left:3em;overflow:hidden;}
-div.notify{background:#ffc url(static/default/notify.png) 0.5em 0px no-repeat;color:#000;border-bottom:1px solid #ffa;font-size:90%;margin:0;padding-left:3em;overflow:hidden;}
-.medialeft{float:left;}.mediaright{float:right;}
-.mediacenter{display:block;margin-left:auto;margin-right:auto;}
-.leftalign{text-align:left;}
-.centeralign{text-align:center;}
-.rightalign{text-align:right;}
-em.u{font-style:normal;text-decoration:underline;}
-em em.u{font-style:italic;}
-.code .br0{color:#6c6;}
-.code .co1{color:#808080;font-style:italic;}
-.code .co2{color:#808080;font-style:italic;}
-.code .co3{color:#808080;}
-.code .coMULTI{color:#808080;font-style:italic;}
-.code .es0{color:#009;font-weight:bold;}.code .kw1{color:#b1b100;}
-.code .kw2{color:#000;font-weight:bold;}.code .kw3{color:#006;}
-.code .kw4{color:#933;}.code .kw5{color:#00f;}.code .me1{color:#060;}.code .me2{color:#060;}
-.code .nu0{color:#c6c;}.code .re0{color:#00f;}.code .re1{color:#00f;}.code .re2{color:#00f;}.code .re3{color:#f33;font-weight:bold;}.code .re4{color:#099;}.code .st0{color:#f00;}.code .sy0{color:#6c6;}
-div.dokuwiki table.pagelist,div.dokuwiki table.ul{border:0;padding:0;border-spacing:0;margin-bottom:1em;border-collapse:collapse;}
-div.dokuwiki table.pagelist tr{border-top:1px solid #8cacbb;border-bottom:1px solid #8cacbb;}
-div.dokuwiki table.pagelist th,div.dokuwiki table.pagelist td{padding:1px 1em 1px 0;}
-div.dokuwiki table.ul th,div.dokuwiki table.ul td{padding:0 1em 0 0;}
-div.dokuwiki table.ul ul{margin:0 0 0 1.5em;}
-div.dokuwiki table.pagelist th,div.dokuwiki table.ul th{background-color:#dee7ec;}
-div.dokuwiki th.page,div.dokuwiki th.date,div.dokuwiki th.user,div.dokuwiki th.desc,div.dokuwiki th.comments,div.dokuwiki th.linkbacks,div.dokuwiki th.tags,div.dokuwiki td.date,div.dokuwiki td.user,div.dokuwiki td.desc,div.dokuwiki td.comments,div.dokuwiki td.linkbacks,div.dokuwiki td.tags{color:#666;font-size:80%;}
-div.dokuwiki td.date{text-align:right;}div.dokuwiki div.include div.secedit{float:right;margin-left:1em;margin-top:-18px;}
-div.dokuwiki div.inclmeta{border-top:1px dotted #8cacbb;padding-top:0.2em;color:#666;font-size:80%;line-height:1.25;margin-top:0.5em;margin-bottom:2em;}
-div.dokuwiki div.inclmeta a.permalink{background:transparent url(static/default/link.gif) 0px 1px no-repeat;padding:1px 0px 1px 16px;}
-div.dokuwiki div.inclmeta abbr.published{background:transparent url(static/default/date.gif) 0px 1px no-repeat;padding:1px 0px 1px 16px;border-bottom:0;}
-div.dokuwiki div.inclmeta span.author{background:transparent url(static/default/user.gif) 0px 1px no-repeat;padding:1px 0px 1px 16px;}
-div.dokuwiki div.inclmeta span.comment{background:transparent url(static/default/comment.gif) 0px 1px no-repeat;padding:1px 0px 1px 16px;}
-div.dokuwiki div.inclmeta div.tags{border-top:0;font-size:100%;float:right;clear:none;}#plugin__manager{}#plugin__manager h2{margin-left:0;}
-#plugin__manager form{display:block;margin:0;padding:0;}
-#plugin__manager legend{display:none;}
-#plugin__manager fieldset{width:auto;}
-#plugin__manager .button{margin:0;}
-#plugin__manager p,#plugin__manager label{text-align:left;}
-#plugin__manager .hidden{display:none;}#plugin__manager .new{background:#dee7ec;}
-#plugin__manager input[disabled]{color:#ccc;border-color:#ccc;}
-#plugin__manager .pm_menu,#plugin__manager .pm_info{margin-left:0;text-align:left;}
-#plugin__manager .pm_menu{float:left;width:48%;}
-#plugin__manager .pm_info{float:right;width:50%;}
-#plugin__manager .common{}#plugin__manager .common form{}
-#plugin__manager .common fieldset{margin:0;padding:0 0 1.0em 0;text-align:left;border:none;}
-#plugin__manager .common label{padding:0 0 0.5em 0;}
-#plugin__manager .common input{}
-#plugin__manager .common input.edit{width:24em;margin:0.5em;}
-#plugin__manager .common .button{}
-#plugin__manager form.plugins{}
-#plugin__manager .plugins fieldset{color:#000;background:#fff;text-align:right;border-top:none;border-right:none;border-left:none;}
-#plugin__manager .plugins fieldset.protected{background:#fdd;color:#000;}
-#plugin__manager .plugins fieldset.disabled{background:#e0e0e0;color:#a8a8a8;}
-#plugin__manager .plugins .legend{color:#000;background:inherit;display:block;margin:0;padding:0;font-size:1em;line-height:1.4em;font-weight:normal;text-align:left;float:left;padding:0;clear:none;}
-#plugin__manager .plugins .button{font-size:95%;}#plugin__manager .plugins fieldset.buttons{border:none;}
-#plugin__manager .plugins fieldset.buttons .button{float:left;}
-#plugin__manager .pm_info h3{margin-left:0;}#plugin__manager .pm_info dl{margin:1em 0;padding:0;}
-#plugin__manager .pm_info dt{width:6em;float:left;clear:left;margin:0;padding:0;}
-#plugin__manager .pm_info dd{margin:0 0 0 7em;padding:0;background:none;}
-#plugin__manager .plugins .enable{float:left;width:auto;margin-right:0.5em;}
-#config__manager div.success,#config__manager div.error,#config__manager div.info{background-position:0.5em;padding:0.5em;text-align:center;}
-#config__manager fieldset{margin:1em;width:auto;margin-bottom:2em;background-color:#dee7ec;color:#000;padding:0 1em;}
-#config__manager legend{font-size:1.25em;}
-#config__manager form{}#config__manager table{margin:1em 0;width:100%;}#config__manager fieldset td{text-align:left;}
-#config__manager fieldset td.value{width:31em;}#config__manager td.label{padding:0.8em 0 0.6em 1em;vertical-align:top;
-}#config__manager td.label label{clear:left;display:block;}
-#config__manager td.label img{padding:0 10px;vertical-align:middle;float:right;}
-#config__manager td.label span.outkey{font-size:70%;margin-top:-1.7em;margin-left:-1em;display:block;background-color:#fff;color:#666;float:left;padding:0 0.1em;position:relative;z-index:1;}
-#config__manager td input.edit{width:30em;}#config__manager td .input{width:30.8em;}
-#config__manager td select.edit{}#config__manager td textarea.edit{width:27.5em;height:4em;}
-#config__manager tr .input,#config__manager tr input,#config__manager tr textarea,#config__manager tr select{background-color:#fff;color:#000;}
-#config__manager tr.default .input,#config__manager tr.default input,#config__manager tr.default textarea,#config__manager tr.default select,#config__manager .selectiondefault{background-color:#cdf;color:#000;}
-#config__manager tr.protected .input,#config__manager tr.protected input,#config__manager tr.protected textarea,#config__manager tr.protected select,#config__manager tr.protected .selection{background-color:#fcc!important;color:#000 !important;}
-#config__manager td.error{background-color:red;color:#000;}#config__manager .selection{width:14.8em;float:left;margin:0 0.3em 2px 0;}#config__manager .selection label{float:right;width:14em;font-size:90%;}
-* html #config__manager .selection label{padding-top:2px;}
-#config__manager .selection input.checkbox{padding-left:0.7em;}
-#config__manager .other{clear:both;padding-top:0.5em;}
-#config__manager .other label{padding-left:2px;font-size:90%;}.dokuwiki div.plugin_translation{float:right;font-size:95%;}
-.dokuwiki div.plugin_translation ul{display:inline;padding:0;margin:0;}
-.dokuwiki div.plugin_translation ul li{float:left;list-style-type:none;padding:0;margin:0;}
-.dokuwiki div.plugin_translation ul li a.wikilink1:link,.dokuwiki div.plugin_translation ul li a.wikilink1:hover,.dokuwiki div.plugin_translation ul li a.wikilink1:active,.dokuwiki div.plugin_translation ul li a.wikilink1:visited{background-color:#000080;color:#fff !important;text-decoration:none;padding:0 0.2em;margin:0.1em 0.2em;border:none !important;}
-.dokuwiki div.plugin_translation ul li a.wikilink2:link,.dokuwiki div.plugin_translation ul li a.wikilink2:hover,.dokuwiki div.plugin_translation ul li a.wikilink2:active,.dokuwiki div.plugin_translation ul li a.wikilink2:visited{background-color:#808080;color:#fff !important;text-decoration:none;padding:0 0.2em;margin:0.1em 0.2em;border:none !important;}
-.dokuwiki div.plugin_translation ul li a img{opacity:0.5;border:0;}
-.dokuwiki div.plugin_translation ul li a.wikilink2 img{}.dokuwiki div.plugin_translation span.curid a img{opacity:1.0;height:15px;}
-.dokuwiki div.plugin_translation ul li a:hover img{opacity:1.0;height:15px;}#user__manager tr.disabled{color:#6f6f6f;background:#e4e4e4;}
-#user__manager tr.user_info{vertical-align:top;}
-#user__manager div.edit_user{width:46%;float:left;}#user__manager table{margin-bottom:1em;}#user__manager input.button[disabled]{color:#ccc!important;border-color:#ccc!important;}div.dokuwiki div.newentry_form{clear:both;text-align:center;margin-bottom:1em;}
-div.dokuwiki #blog__newentry_form input.edit{width:95%;}div.dokuwiki tr.draft,div.dokuwiki div.draft{opacity:0.5;}
-div.dokuwiki div.autoarchive_selector ul{list-style-type:none;clear:left;margin:0 0.5em 0 0;}
-div.dokuwiki div.autoarchive_selector ul div.li{float:left;margin:0 1em 0 0;}
-div.dokuwiki div.autoarchive_selector ul ul{float:left;clear:none;}div.dokuwiki div.autoarchive_selector ul ul div.li{margin:0;}div#acl_manager div#acl__tree{font-size:90%;width:25%;height:300px;float:left;overflow:auto;border:1px solid #8cacbb;text-align:left;}
-div#acl_manager div#acl__tree a.cur{background-color:#ff9;font-weight:bold;}
-div#acl_manager div#acl__tree ul{list-style-type:none;margin:0;padding:0;}div#acl_manager div#acl__tree li{padding-left:1em;}div#acl_manager div#acl__tree ul img{margin-right:0.25em;cursor:pointer;}
-div#acl_manager div#acl__detail{width:73%;height:300px;float:right;overflow:auto;}
-div#acl_manager div#acl__detail fieldset{width:90%;}
-div#acl_manager div#acl__detail div#acl__user{border:1px solid #8cacbb;padding:0.5em;margin-bottom:0.6em;}
-div#acl_manager table.inline{width:100%;margin:0;}
-div#acl_manager .aclgroup{background:transparent url(static/default/group.png) 0px 1px no-repeat;padding:1px 0px 1px 18px;}
-div#acl_manager .acluser{background:transparent url(static/default/user.png) 0px 1px no-repeat;padding:1px 0px 1px 18px;}
-div#acl_manager .aclpage{background:transparent url(static/default/page.png) 0px 1px no-repeat;padding:1px 0px 1px 18px;}
-div#acl_manager .aclns{background:transparent url(static/default/ns.png) 0px 1px no-repeat;padding:1px 0px 1px 18px;}
-div#acl_manager label.disabled{color:#666!important;}
-#acl_manager label{text-align:left;font-weight:normal;display:inline;}
-#acl_manager table{margin-left:10%;width:80%;}#acl_manager table tr{background-color:inherit;}
-#acl_manager table tr:hover{background-color:#dee7ec;}
-
-
-a.interwiki{background:transparent url(/lib/images/interwiki.png) 0px 1px no-repeat;padding-left:16px;}
-a.iw_wp{background-image:url(/static/default/wp.gif)}
-a.iw_wpde{background-image:url(/static/default/wpde.gif)}
-a.iw_wpmeta{background-image:url(/static/default/wpmeta.gif)}
-a.iw_doku{background-image:url(/static/default/doku.gif)}
-a.iw_dokubug{background-image:url(/static/default/dokubug.gif)}
-a.iw_amazon{background-image:url(/static/default/amazon.gif)}
-a.iw_amazon_de{background-image:url(/static/default/amazon.de.gif)}
-a.iw_amazon_uk{background-image:url(/static/default/amazon.uk.gif)}
-a.iw_phpfn{background-image:url(/static/default/phpfn.gif)}
-a.iw_coral{background-image:url(/static/default/coral.gif)}
-a.iw_sb{background-image:url(/static/default/sb.gif)}
-a.iw_google{background-image:url(/static/default/google.gif)}
-a.iw_meatball{background-image:url(/static/default/meatball.gif)}
-a.iw_wiki{background-image:url(/static/default/wiki.gif)}
-a.mediafile{background:transparent url(/static/default/file.png) 0px 1px no-repeat;padding-left:18px;padding-bottom:1px;}a.mf_jpg{background-image:url(/static/default/jpg.png)}a.mf_jpeg{background-image:url(/static/default/jpeg.png)}a.mf_gif{background-image:url(/static/default/gif.png)}a.mf_png{background-image:url(/static/default/png.png)}a.mf_tgz{background-image:url(/static/default/tgz.png)}a.mf_tar{background-image:url(/static/default/tar.png)}a.mf_gz{background-image:url(/static/default/gz.png)}a.mf_bz2{background-image:url(/static/default/bz2.png)}
-a.mf_zip{background-image:url(/static/default/zip.png)}a.mf_rar{background-image:url(/static/default/rar.png)}a.mf_pdf{background-image:url(/static/default/pdf.png)}a.mf_ps{background-image:url(/static/default/ps.png)}a.mf_doc{background-image:url(/static/default/doc.png)}a.mf_xls{background-image:url(/static/default/xls.png)}a.mf_ppt{background-image:url(/static/default/ppt.png)}a.mf_rtf{background-image:url(/static/default/rtf.png)}a.mf_swf{background-image:url(/static/default/swf.png)}a.mf_rpm{background-image:url(/static/default/rpm.png)}a.mf_deb{background-image:url(/static/default/deb.png)}a.mf_sxw{background-image:url(/static/default/sxw.png)}a.mf_sxc{background-image:url(/static/default/sxc.png)}a.mf_sxi{background-image:url(/static/default/sxi.png)}a.mf_sxd{background-image:url(/static/default/sxd.png)}a.mf_odc{background-image:url(/static/default/odc.png)}a.mf_odf{background-image:url(/static/default/odf.png)}a.mf_odg{background-image:url(/static/default/odg.png)}
-a.mf_odi{background-image:url(/static/default/odi.png)}a.mf_odp{background-image:url(/static/default/odp.png)}a.mf_ods{background-image:url(/static/default/ods.png)}a.mf_odt{background-image:url(/static/default/odt.png)}body{margin:0px;padding:0px;background-color:white;color:black;font-size:12px;font-family:Verdana,Helvetica,"Lucida Grande",Lucida,Arial,sans-serif;font-family:sans-serif;font-size:99,96%;font-size-adjust:none;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;}hr{border-width:0px;border-bottom:1px #aaa dotted;}img{border:none;}form{margin:0px;padding:0px;border:none;display:inline;background:transparent;}ul li{margin:5px;}textarea{font-family:monospace;}table{margin:0.5em 0;border-collapse:collapse;}td{padding:0.25em;border:1pt solid #ADB9CC;}a{color:#3465a4;text-decoration:none;}a:hover{text-decoration:underline;}
-a.wikilink2{color:#a40000 !important;}.dokuwiki h1 a,.dokuwiki h2 a,.dokuwiki h3 a,.dokuwiki h4 a,.dokuwiki h5 a,.dokuwiki a.nolink{color:#000 !important;text-decoration:none !important;}
-option{border:0px none #fff;}strong.highlight{background-color:#fc9;padding:1pt;}#pagebottom{clear:both;}hr{height:1px;color:#c0c0c0;background-color:#c0c0c0;border:none;margin:.2em 0 .2em 0;}pre{padding:0.5em;font-family:courier,monospace;border:1px solid #c0c0c0;background:#F0ECE6;white-space:pre;white-space:pre-wrap;word-wrap:break-word;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;}.invisible{margin:0px;border:0px;padding:0px;height:0px;visibility:hidden;}.left{float:left !important;}.right{float:right !important;}.center{text-align:center;}div#body-wrapper{padding:40px 40px 10px 40px;font-size:127%;}
-div#content{margin-top:-20px;padding:0;font-size:14px;color:black;line-height:1.5em;}h1,h2,h3,h4,h5,h6{background:transparent none repeat scroll 0 0;border-bottom:1px solid #aaa;color:black;font-weight:normal;margin:0;padding:0;padding-bottom:0.17em;padding-top:0.5em;}h1{font-size:188%;line-height:1.2em;margin-bottom:0.1em;padding-bottom:0;}h2{font-size:150%;}h3,h4,h5,h6{border-bottom:none;font-weight:bold;}h3{font-size:132%;}h4{font-size:116%;}h5{font-size:100%;}h6{font-size:80%;}ul#page-actions{float:right;margin:10px 10px 0 10px;padding:6px;color:black;background-color:#ececec;list-style-type:none;-moz-border-radius:5px;}ul#user-actions{padding:5px;margin:0;display:inline;color:black;background-color:#ececec;list-style-type:none;-moz-border-radius:3px;}ul#page-actions li,ul#user-actions li{display:inline;}ul#page-actions a,ul#user-actions a{text-decoration:none;color:black;display:inline;margin:0 3px;padding:2px 0px 2px 18px;}
-ul#page-actions a:hover,ul#page-actions a:focus,ul#user-actions a:hover,ul#user-actions a:focus{text-decoration:underline;}.hidden{display:none;}a.urlextern{color:#36B;background:transparent url(/static/default/external-10.2.png) no-repeat scroll right center;padding:0 13px 0 0;}a[href^="http://www.pyload.org"]:after,a.noextlink:after{background:none;padding:0;}a.action.index{background:transparent url(/static/default/wiki-tools-index.png) 0px 1px no-repeat;}a.action.recent{background:transparent url(/static/default/wiki-tools-recent.png) 0px 1px no-repeat;}a.logout{background:transparent url(/static/default/user-actions-logout.png) 0px 1px no-repeat;}
-a.admin{background:transparent url(/static/default/user-actions-admin.png) 0px 1px no-repeat;}a.profile{background:transparent url(/static/default/user-actions-profile.png) 0px 1px no-repeat;}a.create,a.edit{background:transparent url(/static/default/page-tools-edit.png) 0px 1px no-repeat;}a.source,a.show{background:transparent url(/static/default/page-tools-source.png) 0px 1px no-repeat;}a.revisions{background:transparent url(/static/default/page-tools-revisions.png) 0px 1px no-repeat;}a.subscribe,a.unsubscribe{background:transparent url(/static/default/page-tools-subscribe.png) 0px 1px no-repeat;}a.backlink{background:transparent url(/static/default/page-tools-backlinks.png) 0px 1px no-repeat;}#head-panel{background:#525252 url(/static/default/head_bg1.png) bottom left repeat-x;}#head-panel h1{display:none;margin:0;text-decoration:none;padding-top:0.8em;padding-left:3.3em;font-size:2.6em;color:#eeeeec;}#head-panel #head-logo{float:left;margin:5px 0 -15px 5px;padding:0;overflow:visible;}#head-menu{background:transparent url(/static/default/tabs-border-bottom.png) 0 100% repeat-x;width:100%;float:left;margin:0;padding:0;padding-top:0.8em;}
-#head-menu ul{list-style:none;margin:0 1em 0 2em;}#head-menu ul li{float:left;margin:0;margin-left:0.3em;font-size:14px;margin-bottom:4px;}#head-menu ul li.selected,#head-menu ul li:hover{margin-bottom:0px;}#head-menu ul li a img{height:22px;width:22px;vertical-align:middle;}#head-menu ul li a,#head-menu ul li a:link{float:left;text-decoration:none;color:#555;background:#eaeaea url(/static/default/tab-background.png) 0 100% repeat-x;padding:3px 7px 3px 7px;border:2px solid #ccc;border-bottom:0px solid transparent;padding-bottom:3px;-moz-border-radius:5px;}#head-menu ul li a:hover,#head-menu ul li a:focus{color:#111;padding-bottom:7px;border-bottom:0px none transparent;outline:none;-moz-border-radius-bottomright:0px;-moz-border-radius-bottomleft:0px;}#head-menu ul li a:focus{margin-bottom:-4px;}#head-menu ul li.selected a{color:#3566A5;background:#fff;padding-bottom:7px;border-bottom:0px none transparent;-moz-border-radius-bottomright:0px;-moz-border-radius-bottomleft:0px;}#head-menu ul li.selected a:hover,#head-menu ul li.selected a:focus{color:#111;}div#head-search-and-login{float:right;margin:0 1em 0 0;background-color:#222;padding:4px;color:white;-moz-border-radius-bottomright:6px;-moz-border-radius-bottomleft:6px;}div#head-search-and-login form{display:inline;padding:0 3px;}div#head-search-and-login form input{border:2px solid #888;background:#eee;font-size:14px;padding:2px;-moz-border-radius:3px;}div#head-search-and-login form input:focus{background:#fff;}#head-search{font-size:14px;}#head-username,#head-password{width:80px;font-size:14px;}#pageinfo{clear:both;color:#888;padding:0.6em 0;margin:0;}#foot{font-style:normal;color:#888;text-align:center;}#foot a{color:#aaf;}#foot img{vertical-align:middle;}ul.toc{padding:0;padding-left:20px;margin-left:0;margin-right:10px;list-style:none;}ul.toc li{list-style:circle;}ul.toc li a{text-decoration:none;color:black;}ul.toc li a:hover{text-decoration:underline;}div.toc{border:1px dotted #888;background:#f0f0f0;margin:1em 0 1em 1em;float:right;font-size:95%;}div.toc .tocheader{font-weight:bold;margin:0.5em 1em;}div.toc ol{margin:1em 0.5em 1em 1em;padding:0;}div.toc ol li{margin:0;padding:0;margin-left:1em;}div.toc ol ol{margin:0.5em 0.5em 0.5em 1em;padding:0;}div.recentchanges table{clear:both;}div#editor-help{font-size:90%;border:1px dotted #888;padding:0ex 1ex 1ex 1ex;background:#f7f6f2;}div#preview{margin-top:1em;}label.block{display:block;text-align:right;font-weight:bold;}label.simple{display:block;text-align:left;font-weight:normal;}label.block input.edit{width:50%;}fieldset{width:300px;text-align:center;padding:0.5em;margin:auto;}div.editor{margin:0 0 0 0;}table{margin:0.5em 0;border-collapse:collapse;}td{padding:0.25em;border:1pt solid #ADB9CC;}td p{margin:0;padding:0;}.u{text-decoration:underline;}.footnotes ul{padding:0 2em;margin:0 0 1em;}.footnotes li{list-style:none;}.recentchanges p{margin:0.25em;}.recentchanges td{vertical-align:top;border:none;border-bottom:1pt solid #F0ECE6;background:#F7F6F2;}.rcdaybreak td{background:#729fcf;border:none;}.rcdaybreak td a{font-size:0.88em;}.rcicon1,.rcicon2{text-align:center;}.rcpagelink{width:33%;}.rctime{font-size:0.88em;white-space:nowrap;}.rceditor{white-space:nowrap;font-size:0.88em;}.rccomment{width:66%;color:gray;font-size:0.88em;}.rcrss{float:right;}.recentchanges[dir="rtl"] .rcrss{float:left;}.userpref table,.userpref td{border:none;}div.codearea{margin:0.5em 0;padding:0;border:1pt solid #AEBDCC;background-color:#F3F5F7;color:black;}div.codearea pre{margin:0;padding:10pt;border:none;}a.codenumbers{margin:0 10pt;font-size:0.85em;color:gray;}div.codearea pre span.LineNumber{color:gray;}div.codearea pre span.ID{color:#000;}div.codearea pre span.Operator{color:#0000c0;}div.codearea pre span.Char{color:#004080;}div.codearea pre span.Comment{color:#008000;}div.codearea pre span.Number{color:#0080c0;}div.codearea pre span.String{color:#004080;}div.codearea pre span.SPChar{color:#0000c0;}div.codearea pre span.ResWord{color:#a00000;}div.codearea pre span.ConsWord{color:#008080;font-weight:bold;}div.codearea pre span.Error{color:#ff8080;border:solid 1.5pt #f00;}div.codearea pre span.ResWord2{color:#0080ff;font-weight:bold;}div.codearea pre span.Special{color:#00f;}div.codearea pre span.Preprc{color:#803999;}#message{clear:both;padding:5px 10px;background-color:#eee;border-bottom:2px solid #ccc;}#message p{margin:5px 0;padding:0;font-weight:bold;}#message div.buttons{font-weight:normal;}.diff{width:99%;}.diff-title{background-color:#C0C0C0;}.searchresult dd span{font-weight:bold;}.diff{width:100%;border:none;}.diff-blockheader{font-weight:bold;background:#e5e5e5;font-size:1.2em;border-top:2px solid #444;padding:5px;}.diff th{font-size:120%;width:50%;font-weight:normal;text-align:left;padding-bottom:3px;}.diff td{font-family:monospace;font-size:100%;border:none;}.diff-addedline{background-color:#dfd;}.diff-deletedline{background-color:#ffb;}.diff-context{color:#888;}.diff-addedline{background-color:#E0FFE0;vertical-align:sub;}.diff-deletedline{background-color:#FFFFE0;background-color:#f4cece;vertical-align:sub;}
-.diff-addedline strong{background-color:#80FF80;background-color:#8ae234;}
-.diff-deletedline strong{background-color:#FFFF80;background-color:#ef2929;background-color:#d78383;}
-
-
-
-.box{ background:url(/static/default/progress-bar-back.gif) right center no-repeat; width:200px; height:20px; float:left; }
-.perc{ background:url(/static/default/progress-bar.gif) right center no-repeat; height:20px; }
-.boxtext{ font-family:tahoma, arial, sans-serif; font-size:11px; color:#000; float:none; padding:3px 0 0 10px; }
-.statusbutton{width:32px;height:32px;float:left;margin-left:-32px;margin-right:5px;opacity:0;cursor:pointer}
-
-.dlsize{float:left; padding-right: 8px;}
-.dlspeed{float:left; padding-right: 8px;} \ No newline at end of file
diff --git a/module/web/static/favicon.ico b/module/web/static/favicon.ico
deleted file mode 100644
index 58b1f4b89..000000000
--- a/module/web/static/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/module/web/templates/default.tpl b/module/web/templates/default.tpl
deleted file mode 100644
index 3f5e8d8e8..000000000
--- a/module/web/templates/default.tpl
+++ /dev/null
@@ -1,230 +0,0 @@
-%header = 'pyLoad Webinterface'
-%js = ['mootools-1.2.3-core.js','mootools-1.2.3.1-more.js']
-
-%if page== "home": js.append('default/home.js')
-%end
-%if page== "loggedin": red=True
-%else: red=False
-%end
-%if page != "loggedin" and page != "login": js.append('default/status.js')
-%end
-
-%include header title=header, use_js=js, use_css=['default.css','window.css'], redirect=red
-
-%include window id="addlinks", width=400, caption="Add links", body="<input id='pname' type='text' style='width: 345px;' value='Package'/><textarea rows=10 style='width: 345px;' id='linkarea'></textarea>", button="Add"
-
-<a class="anchor" name="top" id="top"></a>
-
-<div id="head-panel">
-
-
- <div id="head-search-and-login">
-
-%if page != "login":
- <img src="static/default/head-login.png" alt="User:" style="vertical-align:middle; margin:2px" /><span style="padding-right: 2px;">{{user}}</span>
- <ul id="user-actions">
- <li><a href="/logout" class="action logout" rel="nofollow">Logout</a></li>
- <li></li>
- <li></li>
- </ul>
-%else:
- <span style="padding-right: 2px;">Please Login!</span>
-
-
-%end
- </div>
-
- <a href="/"><img id="head-logo" src="/static/default/pyload-logo-edited3.5-new-font-small.png" alt="pyLoad" /></a>
-
- <div id="head-menu">
- <ul>
- <li class="
- %if page == "home" or page == "login":
- selected
- %endif
- "><a href="/" title=""><img src="static/default/head-menu-home.png" alt="" /> Home</a></li>
- <li class="
- %if page == "queue":
- selected
- %endif
- "><a href="/queue" title=""><img src="static/default/head-menu-download.png" alt="" /> Queue</a></li>
- <li class="
- %if page == "downloads":
- selected
- %endif
- "><a href="/downloads" title=""><img src="static/default/head-menu-development.png" alt="" /> Downloads</a></li>
- <li class="right"><a href="/logs" class="action index" accesskey="x" rel="nofollow"><img src="static/default/head-menu-index.png" alt="" />Logs</a></li> </ul>
- </div>
-
- <div style="clear:both;"></div>
-</div>
-
-<ul id="page-actions">
- <li><a href="" class="action revisions" accesskey="o" rel="nofollow">Reload page</a></li>
-
-</ul>
-
-<div id="body-wrapper" class="dokuwiki">
-
- <div id="content" lang="en" dir="ltr">
-
-
-<h1><a name="pyload_download_manager_for_1_click_hoster" id="pyload_download_manager_for_1_click_hoster">pyLoad — Webinterface</a>
-</h1>
-
-
-%if page != "loggedin" and page != "login":
-
-<div id="statusbar">
- <div id="status" style="float: left;padding: 8px;">
-Status:
-</div>
- <div id="speed" style="float: left;padding: 8px">
-Speed: 
-</div>
-
- <div id="queue" style="float: left;padding: 8px">
-Files in queue: 
-</div>
-
-<div style="padding-top:2px">
-
-<div style="background-image:url(static/default/Button-Play.png);width:32px;height:32px;float:left"></div>
-<div class= "statusbutton" style="background-image:url(static/default/Button-Play-grey.png); visibility: visible; opacity: 0.01"></div>
-<div style="background-image:url(static/default/Button-Pause.png);width:32px;height:32px;float:left"></div>
-<div class= "statusbutton" style="background-image:url(static/default/Button-Pause-grey.png); visibility: visible; opacity: 0.01"></div>
-<div style="background-image:url(static/default/Button-Add.png);width:32px;height:32px;float:left"></div>
-<div class= "statusbutton" style="background-image:url(static/default/Button-Add-grey.png); visibility: visible; opacity: 0.01"></div>
-
-
-</div>
-
-</div>
-
-%end
-
-
-<br>
-
-<div class="level1" style="clear:both">
-
-%if page == "login":
-
-</div>
-<div class="centeralign">
-<form action="" method="post" accept-charset="utf-8" id="login"><div class="no">
-<input type="hidden" name="do" value="login" /><fieldset ><legend>Login</legend>
-<label class="block" for="focus__this"><span>Username</span> <input type="text" id="focus__this" name="u" class="edit" /></label><br />
-<label class="block"><span>Password</span> <input type="password" name="p" class="edit" /></label><br />
-<input type="submit" value="Login" class="button" />
-</fieldset>
-</div></form>
-</div>
-<br>
-
-%elif page== "home":
-<h2>Downloads:</h2>
-
-<div id="dlcontainer">
-
-% for link in links:
-
-
-<div class="download" id="dl{{link['id']}}" style="color: #000">
-<p></p>
-
-<b>{{link['name']}}</b>
-<br>
-<script type="text/javascript">
-pbs[{{link['id']}}] = new dwProgressBar({
- container: document.id('dl{{link['id']}}'),
- startPercentage: {{link['percent']}},
- speed: 1000,
- id: {{link['id']}},
- boxID: 'box',
- percentageID: 'perc',
- displayText: true,
- displayID: 'boxtext'
-});
-
-dls.push({{link['id']}})
-
-</script>
-
-
-<div class="dlsize">
-{{int((link['size'] - link['kbleft']) / 1024)}}/{{int(link['size']) / 1024}} MB
-</div>
-
-
-<div class="dlspeed">
-{{int(link['speed'])}} kb/s
-</div>
-
-
-<div class="dltime">
-{{link['eta']}}
-</div>
-
-
-</div>
-
-
-<script type="text/javascript">
-$$("#dl{{link['id']}}")[0].hover(function(e){
-
-this.morph({'color': '#f00'});
-
-}, function(e){
-
-this.morph({'color': '#000'});
-
-});
-
-
-</script>
-
-
-%end
-
-</div>
-
-
-%elif page=="loggedin":
-
-
-<b>You were successfully logged in</b>
-
-%elif page=="queue":
-
-<ul>
-
-%for package in links:
-
-<li>{{package.name}}</li>
-
-%end
-
-</ul>
-
-Currently in Development
-
-%elif page=="downloads":
-
-Currently in Development
-
-
-%end
- <hr style="clear: both;" />
-
-<div id="foot">© 2008-2009 the pyLoad Team
-
- <a href="#top" class="action top" accesskey="x"><span>Back to top</span></a><br />
- <!--<div class="breadcrumbs"></div>-->
-
-
-</div>
-
-</div>
-
-%include footer use_js=[] \ No newline at end of file
diff --git a/module/web/templates/default/base.html b/module/web/templates/default/base.html
new file mode 100644
index 000000000..096692a3c
--- /dev/null
+++ b/module/web/templates/default/base.html
@@ -0,0 +1,99 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/default.css">
+{% block head %}
+{% endblock %}
+<title>{% block title %}pyLoad Webinterface{% endblock %}</title>
+</head>
+
+<a class="anchor" name="top" id="top"></a>
+
+<div id="head-panel">
+
+<div id="head-search-and-login">
+
+{% if user.is_authenticated %}
+<img src="{{ MEDIA_URL }}img/head-login.png" alt="User:" style="vertical-align:middle; margin:2px" /><span style="padding-right: 2px;">{{user.username}}</span>
+ <ul id="user-actions">
+ <li><a href="/logout" class="action logout" rel="nofollow">Logout</a></li>
+ {% if user.is_staff %}
+ <li><a href="/admin" class="action profile" rel="nofollow">Administrate</a></li>
+ {% endif %}
+ <li></li>
+ <li></li>
+ </ul>
+{% else %}
+ <span style="padding-right: 2px;">Please Login!</span>
+{% endif %}
+
+ </div>
+
+ <a href="/"><img id="head-logo" src="{{ MEDIA_URL }}img/pyload-logo-edited3.5-new-font-small.png" alt="pyLoad" /></a>
+
+ <div id="head-menu">
+ <ul>
+
+ {% block menu %}
+ <li class="selected">
+ <a href="/" title=""><img src="{{ MEDIA_URL }}img/head-menu-home.png" alt="" /> Home</a>
+ </li>
+ <li>
+ <a href="/queue/" title=""><img src="{{ MEDIA_URL }}img/head-menu-download.png" alt="" /> Queue</a></li>
+ <li>
+ <a href="/downloads/" title=""><img src="{{ MEDIA_URL }}img/head-menu-development.png" alt="" /> Downloads</a></li>
+ <li class="right">
+ <a href="/logs/" class="action index" accesskey="x" rel="nofollow"><img src="{{ MEDIA_URL }}img/head-menu-index.png" alt="" />Logs</a>
+ </li>
+ {% endblock %}
+
+ </ul>
+ </div>
+
+ <div style="clear:both;"></div>
+</div>
+
+<ul id="page-actions">
+ <li><a href="" class="action revisions" accesskey="o" rel="nofollow">Reload page</a></li>
+
+</ul>
+
+<div id="body-wrapper" class="dokuwiki">
+
+<div id="content" lang="en" dir="ltr">
+
+<h1><a name="pyload_download_manager_for_1_click_hoster" id="pyload_download_manager_for_1_click_hoster">pyLoad — Webinterface</a>
+</h1>
+
+{% block statusbar %}
+{% endblock %}
+
+
+<br>
+
+<div class="level1" style="clear:both">
+</div>
+
+{% for message in messages %}
+ <b><p>{{message}}</p></b>
+{% endfor %}
+
+{% block content %}
+{% endblock content %}
+
+ <hr style="clear: both;" />
+
+<div id="foot">© 2008-2010 the pyLoad Team
+
+ <a href="#top" class="action top" accesskey="x"><span>Back to top</span></a><br />
+ <!--<div class="breadcrumbs"></div>-->
+
+
+</div>
+</div>
+</head>
+<body>
diff --git a/module/web/templates/default/downloads.html b/module/web/templates/default/downloads.html
new file mode 100644
index 000000000..3c9bb5df4
--- /dev/null
+++ b/module/web/templates/default/downloads.html
@@ -0,0 +1,16 @@
+{% extends 'default/base.html' %}
+
+{% block title %}Downloads - {{block.super}} {% endblock %}
+
+{% block menu %}
+<li>
+ <a href="/" title=""><img src="{{ MEDIA_URL }}img/head-menu-home.png" alt="" /> Home</a>
+</li>
+<li>
+ <a href="/queue" title=""><img src="{{ MEDIA_URL }}img/head-menu-download.png" alt="" /> Queue</a></li>
+<li class="selected">
+ <a href="/downloads" title=""><img src="{{ MEDIA_URL }}img/head-menu-development.png" alt="" /> Downloads</a></li>
+<li class="right">
+ <a href="/logs" class="action index" accesskey="x" rel="nofollow"><img src="{{ MEDIA_URL }}img/head-menu-index.png" alt="" />Logs</a>
+</li>
+{% endblock %} \ No newline at end of file
diff --git a/module/web/templates/default/home.html b/module/web/templates/default/home.html
new file mode 100644
index 000000000..895302e61
--- /dev/null
+++ b/module/web/templates/default/home.html
@@ -0,0 +1 @@
+{% extends 'default/base.html' %} \ No newline at end of file
diff --git a/module/web/templates/default/login.html b/module/web/templates/default/login.html
new file mode 100644
index 000000000..851802c4f
--- /dev/null
+++ b/module/web/templates/default/login.html
@@ -0,0 +1,35 @@
+{% extends 'default/base.html' %}
+
+{% block title %}Login - {{block.super}} {% endblock %}
+
+{% block content %}
+
+<div class="centeralign">
+<form action="" method="post" accept-charset="utf-8" id="login">
+ <div class="no">
+ <input type="hidden" name="do" value="login" />
+ <fieldset>
+ <legend>Login</legend>
+ <label class="block" for="focus__this">
+ <span>Username</span>
+ {{ form.username }}
+ </label>
+ <br />
+ <label class="block">
+ <span>Password</span>
+ {{ form.password }}
+ </label>
+ <br />
+ <input type="submit" value="Login" class="button" />
+ </fieldset>
+ </div>
+</form>
+
+{% if form.errors %}
+<p>Your username and password didn't match. Please try again.</p>
+{% endif %}
+
+</div>
+<br>
+
+{% endblock %} \ No newline at end of file
diff --git a/module/web/templates/default/logout.html b/module/web/templates/default/logout.html
new file mode 100644
index 000000000..4d00bf6d5
--- /dev/null
+++ b/module/web/templates/default/logout.html
@@ -0,0 +1,9 @@
+{% extends 'default/base.html' %}
+
+{% block head %}
+<meta http-equiv="refresh" content="3; url=/">
+{% endblock %}
+
+{% block content %}
+<p><b>You were successfully logged out.</b></p>
+{% endblock %} \ No newline at end of file
diff --git a/module/web/templates/default/logs.html b/module/web/templates/default/logs.html
new file mode 100644
index 000000000..d6f392f58
--- /dev/null
+++ b/module/web/templates/default/logs.html
@@ -0,0 +1,16 @@
+{% extends 'default/base.html' %}
+
+{% block title %}Logs - {{block.super}} {% endblock %}
+
+{% block menu %}
+<li>
+ <a href="/" title=""><img src="{{ MEDIA_URL }}img/head-menu-home.png" alt="" /> Home</a>
+</li>
+<li>
+ <a href="/queue" title=""><img src="{{ MEDIA_URL }}img/head-menu-download.png" alt="" /> Queue</a></li>
+<li>
+ <a href="/downloads" title=""><img src="{{ MEDIA_URL }}img/head-menu-development.png" alt="" /> Downloads</a></li>
+<li class="right" class="selected">
+ <a href="/logs" class="action index" accesskey="x" rel="nofollow"><img src="{{ MEDIA_URL }}img/head-menu-index.png" alt="" />Logs</a>
+</li>
+{% endblock %} \ No newline at end of file
diff --git a/module/web/templates/default/queue.html b/module/web/templates/default/queue.html
new file mode 100644
index 000000000..b6a185b19
--- /dev/null
+++ b/module/web/templates/default/queue.html
@@ -0,0 +1,16 @@
+{% extends 'default/base.html' %}
+
+{% block title %}Queue - {{block.super}} {% endblock %}
+
+{% block menu %}
+<li>
+ <a href="/" title=""><img src="{{ MEDIA_URL }}img/head-menu-home.png" alt="" /> Home</a>
+</li>
+<li class="selected">
+ <a href="/queue" title=""><img src="{{ MEDIA_URL }}img/head-menu-download.png" alt="" /> Queue</a></li>
+<li>
+ <a href="/downloads" title=""><img src="{{ MEDIA_URL }}img/head-menu-development.png" alt="" /> Downloads</a></li>
+<li class="right">
+ <a href="/logs" class="action index" accesskey="x" rel="nofollow"><img src="{{ MEDIA_URL }}img/head-menu-index.png" alt="" />Logs</a>
+</li>
+{% endblock %} \ No newline at end of file
diff --git a/module/web/templates/window.tpl b/module/web/templates/default/window.html
index f756c4352..f756c4352 100644
--- a/module/web/templates/window.tpl
+++ b/module/web/templates/default/window.html
diff --git a/module/web/templates/footer.tpl b/module/web/templates/footer.tpl
deleted file mode 100644
index a59b414bf..000000000
--- a/module/web/templates/footer.tpl
+++ /dev/null
@@ -1,6 +0,0 @@
-%for item in use_js:
-<script type="text/javascript" src="static/{{item}}"></script>
-%end
-
-</body>
-</html>
diff --git a/module/web/templates/header.tpl b/module/web/templates/header.tpl
deleted file mode 100644
index 22c252e3c..000000000
--- a/module/web/templates/header.tpl
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-
-%for item in use_js:
-<script type="text/javascript" src="static/{{item}}"></script>
-%end
-
-%for item in use_css:
-<link rel="stylesheet" type="text/css" href="static/{{item}}">
-%end
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
-
-%if redirect:
-<meta http-equiv="refresh" content="3; url=/">
-%end
-
-<title>{{title}}</title>
-
-</head>
-<body>
diff --git a/module/web/urls.py b/module/web/urls.py
new file mode 100644
index 000000000..3e573aa95
--- /dev/null
+++ b/module/web/urls.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+from django.conf.urls.defaults import *
+from django.contrib import admin
+from django.conf import settings
+
+from os.path import join
+
+admin.autodiscover()
+
+urlpatterns = patterns('',
+ # Example:
+ # (r'^pyload/', include('pyload.foo.urls')),
+
+ # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
+ # to INSTALLED_APPS to enable admin documentation:
+ # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
+ # Uncomment the next line to enable the admin:
+ (r'^admin/', include(admin.site.urls)),
+ #(r'^json/', include(ajax.urls)),
+ (r'^media/(?P<path>.*)$', 'django.views.static.serve',
+ {'document_root': settings.MEDIA_ROOT}),
+ (r'^login/$', 'django.contrib.auth.views.login', {'template_name': join(settings.TEMPLATE,'login.html')}),
+ (r'^logout/$', 'django.contrib.auth.views.logout', {'template_name': join(settings.TEMPLATE,'logout.html')}),
+ (r'^home/$', 'pyload.views.home'),
+ (r'^downloads/$', 'pyload.views.downloads'),
+ (r'^queue/$', 'pyload.views.queue'),
+ (r'^logs/$', 'pyload.views.logs'),
+ (r'^$', 'pyload.views.home'),
+ )
diff --git a/pyLoadCli.py b/pyLoadCli.py
index b6d08a238..96165a7b5 100755
--- a/pyLoadCli.py
+++ b/pyLoadCli.py
@@ -22,14 +22,10 @@
SERVER_VERSION = "0.3"
import curses
-import traceback
-import string
-import os
from time import sleep, time
import xmlrpclib
from threading import RLock, Thread
import sys
-import os.path
from os import chdir
from os.path import dirname
from os.path import abspath
diff --git a/pyLoadCore.py b/pyLoadCore.py
index d806696ff..b39f2b667 100755
--- a/pyLoadCore.py
+++ b/pyLoadCore.py
@@ -38,6 +38,7 @@ from os.path import abspath
from os.path import basename
from os.path import dirname
from os.path import exists
+from os.path import join
from re import sub
import subprocess
from sys import argv
@@ -52,7 +53,7 @@ from module.file_list import File_List
from module.network.Request import Request
import module.remote.SecureXMLRPCServer as Server
from module.thread_list import Thread_List
-from module.web.WebServer import WebServer
+from module.web.ServerThread import WebServer
class Core(object):
""" pyLoad Core """
@@ -65,7 +66,7 @@ class Core(object):
def read_config(self):
""" read config and sets preferences """
self.configfile = ConfigParser.SafeConfigParser()
- self.configfile.read('config')
+ self.configfile.read(join(self.path,'config'))
for section in self.configfile.sections():
self.config[section] = {}
for option in self.configfile.options(section):
@@ -75,7 +76,7 @@ class Core(object):
def set_option(self, section, option, value):
self.config[option] = value
self.configfile.set(section, option, str(value))
- self.configfile.write(open('config', "wb"))
+ self.configfile.write(open(join(self.path,'config'), "wb"))
def read_option(self):
return self.config
@@ -102,7 +103,7 @@ class Core(object):
def start(self):
""" starts the machine"""
- chdir(dirname(abspath(__file__)) + sep)
+ self.path = dirname(__file__)
self.config = {}
self.plugin_folder = "module" + sep + "plugins"
@@ -117,6 +118,7 @@ class Core(object):
self.check_install("Crypto", "pycrypto to decode container files")
self.check_install("Image", "Python Image Libary (PIL) for captha reading")
self.check_install("pycurl", "pycurl for lower memory footprint while downloading")
+ self.check_install("django", "Django for webinterface")
self.check_install("tesseract", "tesseract for captcha reading", False)
self.check_install("gocr", "gocr for captcha reading", False)
self.check_file(self.config['log']['log_folder'], _("folder for logs"), True)
@@ -146,7 +148,7 @@ class Core(object):
self.server_methods.check_update()
self.init_server()
- #~ self.init_webserver() # start webinterface like cli, gui etc
+ self.init_webserver() # start webinterface like cli, gui etc
self.logger.info(_("Downloadtime: %s") % self.server_methods.is_time_download()) # debug only
@@ -184,18 +186,27 @@ class Core(object):
import traceback
traceback.print_exc()
+
+ def init_webserver(self):
+ if self.config['webinterface']['activated']:
+ self.webserver = WebServer(self)
+ self.webserver.start()
+
+
def init_logger(self, level):
- file_handler = logging.handlers.RotatingFileHandler(self.config['log']['log_folder'] + sep + 'log.txt', maxBytes=102400, backupCount=int(self.config['log']['log_count'])) #100 kib each
+
console = logging.StreamHandler(stdout)
frm = logging.Formatter("%(asctime)s: %(levelname)-8s %(message)s", "%d.%m.%Y %H:%M:%S")
- file_handler.setFormatter(frm)
+
console.setFormatter(frm)
self.logger = logging.getLogger("log") # settable in config
if self.config['log']['file_log']:
+ file_handler = logging.handlers.RotatingFileHandler(self.config['log']['log_folder'] + sep + 'log.txt', maxBytes=102400, backupCount=int(self.config['log']['log_count'])) #100 kib each
+ file_handler.setFormatter(frm)
self.logger.addHandler(file_handler)
self.logger.addHandler(console) #if console logging
@@ -206,7 +217,7 @@ class Core(object):
""" scan directory for scripts to execute"""
f = lambda x: False if x.startswith("#") or x.endswith("~") else True
self.scripts = {}
-
+ #@TODO: windows save?!
self.scripts['download_preparing'] = map(lambda x: 'scripts/download_preparing/' + x, filter(f, listdir('scripts/download_preparing')))
self.scripts['download_finished'] = map(lambda x: 'scripts/download_finished/' + x, filter(f, listdir('scripts/download_finished')))
self.scripts['package_finished'] = map(lambda x: 'scripts/package_finished/' + x, filter(f, listdir('scripts/package_finished')))