diff options
author | RaNaN <Mast3rRaNaN@hotmail.de> | 2009-12-15 17:48:30 +0100 |
---|---|---|
committer | RaNaN <Mast3rRaNaN@hotmail.de> | 2009-12-15 17:48:30 +0100 |
commit | 95d09b338ac7aed2b387bf143a5cfd1c4b29f612 (patch) | |
tree | 2f6c078f95bbc80f423609bacab8066fe86d7067 | |
parent | gui queue view - unstable (non thread safe) (diff) | |
download | pyload-95d09b338ac7aed2b387bf143a5cfd1c4b29f612.tar.xz |
new Django webinterface(in development), small fixes
-rw-r--r-- | config | 11 | ||||
-rw-r--r-- | module/web/ServerThread.py | 15 | ||||
-rw-r--r-- | module/web/WebServer.py | 374 | ||||
-rw-r--r-- | module/web/ajax/__init__.py (renamed from module/web/__init__.py) | 0 | ||||
-rw-r--r-- | module/web/ajax/models.py | 3 | ||||
-rw-r--r-- | module/web/ajax/tests.py | 23 | ||||
-rw-r--r-- | module/web/ajax/urls.py | 0 | ||||
-rw-r--r-- | module/web/ajax/views.py | 1 | ||||
-rw-r--r-- | module/web/bottle.py | 1231 | ||||
-rw-r--r-- | module/web/main.html | 29 | ||||
-rw-r--r-- | module/web/main.js | 42 | ||||
-rw-r--r-- | module/web/manage.py | 12 | ||||
-rw-r--r-- | module/web/media/css/default.css | 145 | ||||
-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) | bin | 2112 -> 2112 bytes | |||
-rw-r--r-- | module/web/media/img/Button-Add.png (renamed from module/web/static/default/Button-Add.png) | bin | 2110 -> 2110 bytes | |||
-rw-r--r-- | module/web/media/img/Button-Pause-grey.png (renamed from module/web/static/default/Button-Pause-grey.png) | bin | 1932 -> 1932 bytes | |||
-rw-r--r-- | module/web/media/img/Button-Pause.png (renamed from module/web/static/default/Button-Pause.png) | bin | 2146 -> 2146 bytes | |||
-rw-r--r-- | module/web/media/img/Button-Play-grey.png (renamed from module/web/static/default/Button-Play-grey.png) | bin | 1938 -> 1938 bytes | |||
-rw-r--r-- | module/web/media/img/Button-Play.png (renamed from module/web/static/default/Button-Play.png) | bin | 2023 -> 2023 bytes | |||
-rw-r--r-- | module/web/media/img/big_button.gif (renamed from module/web/static/window/big_button.gif) | bin | 1905 -> 1905 bytes | |||
-rw-r--r-- | module/web/media/img/big_button_over.gif (renamed from module/web/static/window/big_button_over.gif) | bin | 728 -> 728 bytes | |||
-rw-r--r-- | module/web/media/img/body.png (renamed from module/web/static/window/body.png) | bin | 402 -> 402 bytes | |||
-rw-r--r-- | module/web/media/img/closebtn.gif (renamed from module/web/static/window/closebtn.gif) | bin | 254 -> 254 bytes | |||
-rw-r--r-- | module/web/media/img/drag_corner.gif (renamed from module/web/static/window/drag_corner.gif) | bin | 76 -> 76 bytes | |||
-rw-r--r-- | module/web/media/img/full.png (renamed from module/web/static/window/full.png) | bin | 3543 -> 3543 bytes | |||
-rw-r--r-- | module/web/media/img/head-login.png (renamed from module/web/static/default/head-login.png) | bin | 1288 -> 1288 bytes | |||
-rw-r--r-- | module/web/media/img/head-menu-development.png (renamed from module/web/static/default/head-menu-development.png) | bin | 1324 -> 1324 bytes | |||
-rw-r--r-- | module/web/media/img/head-menu-download.png (renamed from module/web/static/default/head-menu-download.png) | bin | 721 -> 721 bytes | |||
-rw-r--r-- | module/web/media/img/head-menu-home.png (renamed from module/web/static/default/head-menu-home.png) | bin | 920 -> 920 bytes | |||
-rw-r--r-- | module/web/media/img/head-menu-index.png (renamed from module/web/static/default/head-menu-index.png) | bin | 482 -> 482 bytes | |||
-rw-r--r-- | module/web/media/img/head-menu-news.png (renamed from module/web/static/default/head-menu-news.png) | bin | 628 -> 628 bytes | |||
-rw-r--r-- | module/web/media/img/head-menu-recent.png (renamed from module/web/static/default/head-menu-recent.png) | bin | 932 -> 932 bytes | |||
-rw-r--r-- | module/web/media/img/head-menu-wiki.png (renamed from module/web/static/default/head-menu-wiki.png) | bin | 1204 -> 1204 bytes | |||
-rw-r--r-- | module/web/media/img/head-search-noshadow.png (renamed from module/web/static/default/head-search-noshadow.png) | bin | 1187 -> 1187 bytes | |||
-rw-r--r-- | module/web/media/img/head_bg1.png (renamed from module/web/static/default/head_bg1.png) | bin | 125 -> 125 bytes | |||
-rw-r--r-- | module/web/media/img/page-tools-backlinks.png (renamed from module/web/static/default/page-tools-backlinks.png) | bin | 540 -> 540 bytes | |||
-rw-r--r-- | module/web/media/img/page-tools-edit.png (renamed from module/web/static/default/page-tools-edit.png) | bin | 574 -> 574 bytes | |||
-rw-r--r-- | module/web/media/img/page-tools-revisions.png (renamed from module/web/static/default/page-tools-revisions.png) | bin | 603 -> 603 bytes | |||
-rw-r--r-- | module/web/media/img/progress-bar-back.gif (renamed from module/web/static/default/progress-bar-back.gif) | bin | 10819 -> 10819 bytes | |||
-rw-r--r-- | module/web/media/img/progress-bar.gif (renamed from module/web/static/default/progress-bar.gif) | bin | 10819 -> 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) | bin | 8457 -> 8457 bytes | |||
-rw-r--r-- | module/web/media/img/tab-background.png (renamed from module/web/static/default/tab-background.png) | bin | 179 -> 179 bytes | |||
-rw-r--r-- | module/web/media/img/tabs-border-bottom.png (renamed from module/web/static/default/tabs-border-bottom.png) | bin | 163 -> 163 bytes | |||
-rw-r--r-- | module/web/media/img/user-actions-logout.png (renamed from module/web/static/default/user-actions-logout.png) | bin | 799 -> 799 bytes | |||
-rw-r--r-- | module/web/media/img/user-actions-profile.png (renamed from module/web/static/default/user-actions-profile.png) | bin | 628 -> 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.db | bin | 0 -> 32768 bytes | |||
-rw-r--r-- | module/web/pyload/__init__.py | 0 | ||||
-rw-r--r-- | module/web/pyload/admin.py | 1 | ||||
-rw-r--r-- | module/web/pyload/models.py | 21 | ||||
-rw-r--r-- | module/web/pyload/tests.py | 23 | ||||
-rw-r--r-- | module/web/pyload/urls.py | 7 | ||||
-rw-r--r-- | module/web/pyload/views.py | 80 | ||||
-rw-r--r-- | module/web/settings.py | 127 | ||||
-rw-r--r-- | module/web/static/default.css | 189 | ||||
-rw-r--r-- | module/web/static/favicon.ico | bin | 7206 -> 0 bytes | |||
-rw-r--r-- | module/web/templates/default.tpl | 230 | ||||
-rw-r--r-- | module/web/templates/default/base.html | 99 | ||||
-rw-r--r-- | module/web/templates/default/downloads.html | 16 | ||||
-rw-r--r-- | module/web/templates/default/home.html | 1 | ||||
-rw-r--r-- | module/web/templates/default/login.html | 35 | ||||
-rw-r--r-- | module/web/templates/default/logout.html | 9 | ||||
-rw-r--r-- | module/web/templates/default/logs.html | 16 | ||||
-rw-r--r-- | module/web/templates/default/queue.html | 16 | ||||
-rw-r--r-- | module/web/templates/default/window.html (renamed from module/web/templates/window.tpl) | 0 | ||||
-rw-r--r-- | module/web/templates/footer.tpl | 6 | ||||
-rw-r--r-- | module/web/templates/header.tpl | 24 | ||||
-rw-r--r-- | module/web/urls.py | 30 | ||||
-rwxr-xr-x | pyLoadCli.py | 4 | ||||
-rwxr-xr-x | pyLoadCore.py | 27 |
74 files changed, 707 insertions, 2140 deletions
@@ -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) * " " + "]</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 Binary files differindex 6659e230e..6659e230e 100644 --- a/module/web/static/default/Button-Add-grey.png +++ b/module/web/media/img/Button-Add-grey.png diff --git a/module/web/static/default/Button-Add.png b/module/web/media/img/Button-Add.png Binary files differindex 602da4131..602da4131 100644 --- a/module/web/static/default/Button-Add.png +++ b/module/web/media/img/Button-Add.png diff --git a/module/web/static/default/Button-Pause-grey.png b/module/web/media/img/Button-Pause-grey.png Binary files differindex d1017e974..d1017e974 100644 --- a/module/web/static/default/Button-Pause-grey.png +++ b/module/web/media/img/Button-Pause-grey.png diff --git a/module/web/static/default/Button-Pause.png b/module/web/media/img/Button-Pause.png Binary files differindex 68f3ffc3a..68f3ffc3a 100644 --- a/module/web/static/default/Button-Pause.png +++ b/module/web/media/img/Button-Pause.png diff --git a/module/web/static/default/Button-Play-grey.png b/module/web/media/img/Button-Play-grey.png Binary files differindex 9f44c2289..9f44c2289 100644 --- a/module/web/static/default/Button-Play-grey.png +++ b/module/web/media/img/Button-Play-grey.png diff --git a/module/web/static/default/Button-Play.png b/module/web/media/img/Button-Play.png Binary files differindex 1ce1ed913..1ce1ed913 100644 --- a/module/web/static/default/Button-Play.png +++ b/module/web/media/img/Button-Play.png diff --git a/module/web/static/window/big_button.gif b/module/web/media/img/big_button.gif Binary files differindex 7680490ea..7680490ea 100644 --- a/module/web/static/window/big_button.gif +++ b/module/web/media/img/big_button.gif diff --git a/module/web/static/window/big_button_over.gif b/module/web/media/img/big_button_over.gif Binary files differindex 2e3ee10d2..2e3ee10d2 100644 --- a/module/web/static/window/big_button_over.gif +++ b/module/web/media/img/big_button_over.gif diff --git a/module/web/static/window/body.png b/module/web/media/img/body.png Binary files differindex 7ff1043e0..7ff1043e0 100644 --- a/module/web/static/window/body.png +++ b/module/web/media/img/body.png diff --git a/module/web/static/window/closebtn.gif b/module/web/media/img/closebtn.gif Binary files differindex 3e27e6030..3e27e6030 100644 --- a/module/web/static/window/closebtn.gif +++ b/module/web/media/img/closebtn.gif diff --git a/module/web/static/window/drag_corner.gif b/module/web/media/img/drag_corner.gif Binary files differindex befb1adf1..befb1adf1 100644 --- a/module/web/static/window/drag_corner.gif +++ b/module/web/media/img/drag_corner.gif diff --git a/module/web/static/window/full.png b/module/web/media/img/full.png Binary files differindex fea52af76..fea52af76 100644 --- a/module/web/static/window/full.png +++ b/module/web/media/img/full.png diff --git a/module/web/static/default/head-login.png b/module/web/media/img/head-login.png Binary files differindex b59b7cbbf..b59b7cbbf 100644 --- a/module/web/static/default/head-login.png +++ b/module/web/media/img/head-login.png diff --git a/module/web/static/default/head-menu-development.png b/module/web/media/img/head-menu-development.png Binary files differindex 8ef08e2e5..8ef08e2e5 100644 --- a/module/web/static/default/head-menu-development.png +++ b/module/web/media/img/head-menu-development.png diff --git a/module/web/static/default/head-menu-download.png b/module/web/media/img/head-menu-download.png Binary files differindex 98c5da9db..98c5da9db 100644 --- a/module/web/static/default/head-menu-download.png +++ b/module/web/media/img/head-menu-download.png diff --git a/module/web/static/default/head-menu-home.png b/module/web/media/img/head-menu-home.png Binary files differindex 9d62109aa..9d62109aa 100644 --- a/module/web/static/default/head-menu-home.png +++ b/module/web/media/img/head-menu-home.png diff --git a/module/web/static/default/head-menu-index.png b/module/web/media/img/head-menu-index.png Binary files differindex 44d631064..44d631064 100644 --- a/module/web/static/default/head-menu-index.png +++ b/module/web/media/img/head-menu-index.png diff --git a/module/web/static/default/head-menu-news.png b/module/web/media/img/head-menu-news.png Binary files differindex 43950ebc9..43950ebc9 100644 --- a/module/web/static/default/head-menu-news.png +++ b/module/web/media/img/head-menu-news.png diff --git a/module/web/static/default/head-menu-recent.png b/module/web/media/img/head-menu-recent.png Binary files differindex fc9b0497f..fc9b0497f 100644 --- a/module/web/static/default/head-menu-recent.png +++ b/module/web/media/img/head-menu-recent.png diff --git a/module/web/static/default/head-menu-wiki.png b/module/web/media/img/head-menu-wiki.png Binary files differindex 07cf0102d..07cf0102d 100644 --- a/module/web/static/default/head-menu-wiki.png +++ b/module/web/media/img/head-menu-wiki.png diff --git a/module/web/static/default/head-search-noshadow.png b/module/web/media/img/head-search-noshadow.png Binary files differindex aafdae015..aafdae015 100644 --- a/module/web/static/default/head-search-noshadow.png +++ b/module/web/media/img/head-search-noshadow.png diff --git a/module/web/static/default/head_bg1.png b/module/web/media/img/head_bg1.png Binary files differindex f2848c3cc..f2848c3cc 100644 --- a/module/web/static/default/head_bg1.png +++ b/module/web/media/img/head_bg1.png diff --git a/module/web/static/default/page-tools-backlinks.png b/module/web/media/img/page-tools-backlinks.png Binary files differindex 3eb6a9ce3..3eb6a9ce3 100644 --- a/module/web/static/default/page-tools-backlinks.png +++ b/module/web/media/img/page-tools-backlinks.png diff --git a/module/web/static/default/page-tools-edit.png b/module/web/media/img/page-tools-edit.png Binary files differindex 188e1c12b..188e1c12b 100644 --- a/module/web/static/default/page-tools-edit.png +++ b/module/web/media/img/page-tools-edit.png diff --git a/module/web/static/default/page-tools-revisions.png b/module/web/media/img/page-tools-revisions.png Binary files differindex 5c3b8587f..5c3b8587f 100644 --- a/module/web/static/default/page-tools-revisions.png +++ b/module/web/media/img/page-tools-revisions.png diff --git a/module/web/static/default/progress-bar-back.gif b/module/web/media/img/progress-bar-back.gif Binary files differindex 0c8f68211..0c8f68211 100644 --- a/module/web/static/default/progress-bar-back.gif +++ b/module/web/media/img/progress-bar-back.gif diff --git a/module/web/static/default/progress-bar.gif b/module/web/media/img/progress-bar.gif Binary files differindex 746f77175..746f77175 100644 --- a/module/web/static/default/progress-bar.gif +++ b/module/web/media/img/progress-bar.gif 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 Binary files differindex 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 diff --git a/module/web/static/default/tab-background.png b/module/web/media/img/tab-background.png Binary files differindex 29a5d1991..29a5d1991 100644 --- a/module/web/static/default/tab-background.png +++ b/module/web/media/img/tab-background.png diff --git a/module/web/static/default/tabs-border-bottom.png b/module/web/media/img/tabs-border-bottom.png Binary files differindex 02440f428..02440f428 100644 --- a/module/web/static/default/tabs-border-bottom.png +++ b/module/web/media/img/tabs-border-bottom.png diff --git a/module/web/static/default/user-actions-logout.png b/module/web/media/img/user-actions-logout.png Binary files differindex 0010931e2..0010931e2 100644 --- a/module/web/static/default/user-actions-logout.png +++ b/module/web/media/img/user-actions-logout.png diff --git a/module/web/static/default/user-actions-profile.png b/module/web/media/img/user-actions-profile.png Binary files differindex 46573fff6..46573fff6 100644 --- a/module/web/static/default/user-actions-profile.png +++ b/module/web/media/img/user-actions-profile.png 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 Binary files differnew file mode 100644 index 000000000..8d34ef89c --- /dev/null +++ b/module/web/pyload.db 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 Binary files differdeleted file mode 100644 index 58b1f4b89..000000000 --- a/module/web/static/favicon.ico +++ /dev/null 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'))) |