summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Walter Purcaro <vuolter@users.noreply.github.com> 2015-05-13 03:04:39 +0200
committerGravatar Walter Purcaro <vuolter@users.noreply.github.com> 2015-05-13 03:04:39 +0200
commita6e82c2de410f17a37a3c54c0e38d8dff45d4451 (patch)
tree46c2d7abd9c60ebc20ed01f802e3832f7b0ed2e5
parentGeneral fixup (1) (diff)
downloadpyload-a6e82c2de410f17a37a3c54c0e38d8dff45d4451.tar.xz
General fixup (2)
-rwxr-xr-xpyload/Core.py53
-rw-r--r--pyload/config/default.conf15
-rw-r--r--pyload/webui/App/api.py26
-rw-r--r--pyload/webui/App/app.py52
-rw-r--r--pyload/webui/App/cnl.py30
-rw-r--r--pyload/webui/App/json.py38
-rw-r--r--pyload/webui/App/utils.py8
-rw-r--r--pyload/webui/themes/Next/tml/logs.html2
8 files changed, 114 insertions, 110 deletions
diff --git a/pyload/Core.py b/pyload/Core.py
index 0fa9e6a44..445a3586d 100755
--- a/pyload/Core.py
+++ b/pyload/Core.py
@@ -457,40 +457,41 @@ class Core(object):
self.log = logging.getLogger("log")
self.log.setLevel(level)
- date_fmt = "%Y-%m-%d %H:%M:%S"
- fh_fmt = "%(asctime)s %(levelname)-8s %(message)s"
-
- fh_frm = logging.Formatter(fh_fmt, date_fmt) #: file handler formatter
- console_frm = fh_frm #: console formatter did not use colors as default
+ format = "%(asctime)s %(levelname)-8s %(message)s"
+ datefmt = "%Y-%m-%d %H:%M:%S"
+ console_formatter = logging.Formatter(format, datefmt) #: console formatter did not use colors as default
# Console formatter with colors
if self.config.get("log", "color_console"):
import colorlog
- if self.config.get("log", "console_mode") == "label":
- c_fmt = "%(asctime)s %(log_color)s%(bold)s%(white)s %(levelname)-8s%(reset)s %(message)s"
- clr = {
- 'DEBUG' : "bg_cyan" ,
- 'INFO' : "bg_green" ,
- 'WARNING' : "bg_yellow",
- 'ERROR' : "bg_red" ,
- 'CRITICAL': "bg_purple",
+ format = "%(log_color)s%(asctime)s%(reset)s %(label_log_color)s %(levelname)-8s %(reset)s %(log_color)s%(message)s"
+ datefmt = "%Y-%m-%d %H:%M:%S"
+
+ log_color = {
+ 'DEBUG' : "bold,cyan" ,
+ 'WARNING' : "bold,yellow",
+ 'ERROR' : "bold,red" ,
+ 'CRITICAL': "bold,purple",
+ }
+ secondary_log_colors = {
+ 'label': {
+ 'DEBUG' : "bold,white,bg_cyan" ,
+ 'INFO' : "bold,white,bg_green" ,
+ 'WARNING' : "bold,white,bg_yellow",
+ 'ERROR' : "bold,white,bg_red" ,
+ 'CRITICAL': "bold,white,bg_purple",
}
+ }
- else:
- c_fmt = "%(log_color)s%(asctime)s %(levelname)-8s %(message)s"
- clr = {
- 'DEBUG' : "cyan" ,
- 'WARNING' : "yellow",
- 'ERROR' : "red" ,
- 'CRITICAL': "purple",
- }
-
- console_frm = colorlog.ColoredFormatter(c_fmt, date_fmt, clr)
+ console_formatter = colorlog.ColoredFormatter(format,
+ datefmt,
+ log_color,
+ secondary_log_colors=secondary_log_colors)
# Set console formatter
console = logging.StreamHandler(sys.stdout)
- console.setFormatter(console_frm)
+ console.setFormatter(console_formatter)
self.log.addHandler(console)
log_folder = self.config.get("log", "log_folder")
@@ -499,6 +500,8 @@ class Core(object):
# Set file handler formatter
if self.config.get("log", "file_log"):
+ file_handler_formatter = console_formatter
+
if self.config.get("log", "log_rotate"):
file_handler = logging.handlers.RotatingFileHandler(os.path.join(log_folder, 'log.txt'),
maxBytes=self.config.get("log", "log_size") * 1024,
@@ -507,7 +510,7 @@ class Core(object):
else:
file_handler = logging.FileHandler(os.path.join(log_folder, 'log.txt'), encoding="utf8")
- file_handler.setFormatter(fh_frm)
+ file_handler.setFormatter(file_handler_formatter)
self.log.addHandler(file_handler)
diff --git a/pyload/config/default.conf b/pyload/config/default.conf
index c70d4d71a..5586e5466 100644
--- a/pyload/config/default.conf
+++ b/pyload/config/default.conf
@@ -13,7 +13,7 @@ ssl - "SSL":
webui - "Web User Interface":
bool activated : "Activated" = True
- auto;threaded;fastcgi;lightweight server : "Server" = auto
+ auto;threaded;fastcgi;lightweight server : "Server" = threaded
bool https : "Use HTTPS" = False
ip host : "IP" = 0.0.0.0
int port : "Port" = 8001
@@ -21,13 +21,12 @@ webui - "Web User Interface":
str prefix : "Path Prefix" = None
log - "Log":
- bool file_log : "File Log" = True
- folder log_folder : "Folder" = Logs
- int log_count : "Count" = 5
- int log_size : "Size in KB" = 100
- bool log_rotate : "Log Rotate" = True
- bool color_console : "Colored console" = True
- label;line console_mode : "Colored console mode" = line
+ bool file_log : "File Log" = True
+ folder log_folder : "Folder" = Logs
+ int log_count : "Count" = 5
+ int log_size : "Size in KB" = 100
+ bool log_rotate : "Log Rotate" = True
+ bool color_console : "Colored console" = True
general - "General":
en; language : "Language" = en
diff --git a/pyload/webui/App/api.py b/pyload/webui/App/api.py
index 31366b902..155b7c39f 100644
--- a/pyload/webui/App/api.py
+++ b/pyload/webui/App/api.py
@@ -26,12 +26,12 @@ class TBaseEncoder(json.JSONEncoder):
@bottle.route('/api/<func><args:re:[a-zA-Z0-9\-_/\"\'\[\]%{},]*>')
@bottle.route('/api/<func><args:re:[a-zA-Z0-9\-_/\"\'\[\]%{},]*>', method='POST')
def call_api(func, args=""):
- response.headers.replace("Content-type", "application/json")
- response.headers.append("Cache-Control", "no-cache, must-revalidate")
+ bottle.response.headers.replace("Content-type", "application/json")
+ bottle.response.headers.append("Cache-Control", "no-cache, must-revalidate")
- s = request.environ.get('beaker.session')
- if 'session' in request.POST:
- s = s.get_by_id(request.POST['session'])
+ s = bottle.request.environ.get('beaker.session')
+ if 'session' in bottle.request.POST:
+ s = s.get_by_id(bottle.request.POST['session'])
if not s or not s.get("authenticated", False):
return bottle.HTTPError(403, json_dumps("Forbidden"))
@@ -42,7 +42,7 @@ def call_api(func, args=""):
args = args.split("/")[1:]
kwargs = {}
- for x, y in itertools.chain(request.GET.iteritems(), request.POST.iteritems()):
+ for x, y in itertools.chain(bottle.request.GET.iteritems(), bottle.request.POST.iteritems()):
if x == "session":
continue
kwargs[x] = urllib.unquote(y)
@@ -69,11 +69,11 @@ def callApi(func, *args, **kwargs):
# post -> username, password
@bottle.route('/api/login', method='POST')
def login():
- response.headers.replace("Content-type", "application/json")
- response.headers.append("Cache-Control", "no-cache, must-revalidate")
+ bottle.response.headers.replace("Content-type", "application/json")
+ bottle.response.headers.append("Cache-Control", "no-cache, must-revalidate")
- user = request.forms.get("username")
- password = request.forms.get("password")
+ user = bottle.request.forms.get("username")
+ password = bottle.request.forms.get("password")
info = PYLOAD.checkAuth(user, password)
@@ -92,8 +92,8 @@ def login():
@bottle.route('/api/logout')
def logout():
- response.headers.replace("Content-type", "application/json")
- response.headers.append("Cache-Control", "no-cache, must-revalidate")
+ bottle.response.headers.replace("Content-type", "application/json")
+ bottle.response.headers.append("Cache-Control", "no-cache, must-revalidate")
- s = request.environ.get('beaker.session')
+ s = bottle.request.environ.get('beaker.session')
s.delete()
diff --git a/pyload/webui/App/app.py b/pyload/webui/App/app.py
index 9d031e659..bb4a2ff8e 100644
--- a/pyload/webui/App/app.py
+++ b/pyload/webui/App/app.py
@@ -23,7 +23,7 @@ from pyload.utils import formatSize, fs_join, fs_encode, fs_decode
def pre_processor():
- s = request.environ.get('beaker.session')
+ s = bottle.request.environ.get('beaker.session')
user = parse_userdata(s)
perms = parse_permissions(s)
status = {}
@@ -46,7 +46,7 @@ def pre_processor():
'status': status,
'captcha': captcha,
'perms': perms,
- 'url': request.url,
+ 'url': bottle.request.url,
'update': update,
'plugins': plugins}
@@ -88,12 +88,12 @@ def server_min(theme, file):
@bottle.route('/<theme>/<file:re:.+\.js>')
def server_js(theme, file):
- response.headers['Content-Type'] = "text/javascript; charset=UTF-8"
+ bottle.response.headers['Content-Type'] = "text/javascript; charset=UTF-8"
if "/render/" in file or ".render." in file or True:
- response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
+ bottle.response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
time.gmtime(time.time() + 24 * 7 * 60 * 60))
- response.headers['Cache-control'] = "public"
+ bottle.response.headers['Cache-control'] = "public"
path = "/".join((theme, file))
return env.get_template(path).render()
@@ -103,16 +103,16 @@ def server_js(theme, file):
@bottle.route('/<theme>/<file:path>')
def server_static(theme, file):
- response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
+ bottle.response.headers['Expires'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
time.gmtime(time.time() + 24 * 7 * 60 * 60))
- response.headers['Cache-control'] = "public"
+ bottle.response.headers['Cache-control'] = "public"
- return bottle.static_file(file, root=join(THEME_DIR, THEME, theme))
+ return bottle.static_file(file, root=os.path.join(THEME_DIR, THEME, theme))
@bottle.route('/favicon.ico')
def favicon():
- return bottle.static_file("icon.ico", root=join(PYLOAD_DIR, "docs", "resources"))
+ return bottle.static_file("icon.ico", root=os.path.join(PYLOAD_DIR, "docs", "resources"))
@bottle.route('/login', method="GET")
@@ -130,8 +130,8 @@ def nopermission():
@bottle.route('/login', method='POST')
def login_post():
- user = request.forms.get("username")
- password = request.forms.get("password")
+ user = bottle.request.forms.get("username")
+ password = bottle.request.forms.get("password")
info = PYLOAD.checkAuth(user, password)
@@ -144,7 +144,7 @@ def login_post():
@bottle.route('/logout')
def logout():
- s = request.environ.get('beaker.session')
+ s = bottle.request.environ.get('beaker.session')
s.delete()
return render_to_response("logout.html", proc=[pre_processor])
@@ -156,7 +156,7 @@ def home():
try:
res = [toDict(x) for x in PYLOAD.statusDownloads()]
except Exception:
- s = request.environ.get('beaker.session')
+ s = bottle.request.environ.get('beaker.session')
s.delete()
return bottle.redirect("/login")
@@ -383,30 +383,29 @@ def path(file="", path=""):
@bottle.route('/logs/<item>', method='POST')
@login_required('LOGS')
def logs(item=-1):
- s = request.environ.get('beaker.session')
+ s = bottle.request.environ.get('beaker.session')
perpage = s.get('perpage', 34)
reversed = s.get('reversed', False)
warning = ""
conf = PYLOAD.getConfigValue("log", "file_log")
- color_template = PYLOAD.getConfigValue("log", "color_template") if PYLOAD.getConfigValue("log", "color_console") else ""
if not conf:
warning = "Warning: File log is disabled, see settings page."
- perpage_p = ((20, 20), (34, 34), (40, 40), (100, 100), (0, 'all'))
+ perpage_p = ((20, 20), (50, 50), (100, 100), (250, 250), (0, 'all'))
fro = None
- if request.environ.get('REQUEST_METHOD', "GET") == "POST":
+ if bottle.request.environ.get('REQUEST_METHOD', "GET") == "POST":
try:
- fro = datetime.datetime.strptime(request.forms['from'], '%d.%m.%Y %H:%M:%S')
+ fro = datetime.datetime.strptime(bottle.request.forms['from'], '%d.%m.%Y %H:%M:%S')
except Exception:
pass
try:
- perpage = int(request.forms['perpage'])
+ perpage = int(bottle.request.forms['perpage'])
s['perpage'] = perpage
- reversed = bool(request.forms.get('reversed', False))
+ reversed = bool(bottle.request.forms.get('reversed', False))
s['reversed'] = reversed
except Exception:
pass
@@ -444,13 +443,16 @@ def logs(item=-1):
time = ' '
level = '?'
message = l
+
if item == -1 and dtime is not None and fro <= dtime:
item = counter #: found our datetime.datetime
+
if item >= 0:
data.append({'line': counter, 'date': date + " " + time, 'level': level, 'message': message})
perpagecheck += 1
if fro is None and dtime is not None: #: if fro not set set it to first showed line
fro = dtime
+
if perpagecheck >= perpage > 0:
break
@@ -462,7 +464,7 @@ def logs(item=-1):
'reversed': reversed, 'perpage': perpage, 'perpage_p': sorted(perpage_p),
'iprev': 1 if item - perpage < 1 else item - perpage,
'inext': (item + perpage) if item + perpage < len(log) else item,
- 'color_template': color_template.title()},
+ 'color_console': PYLOAD.getConfigValue("log", "color_console")},
[pre_processor])
@@ -479,10 +481,10 @@ def admin():
get_permission(data['perms'], data['permission'])
data['perms']['admin'] = data['role'] is 0
- s = request.environ.get('beaker.session')
- if request.environ.get('REQUEST_METHOD', "GET") == "POST":
+ s = bottle.request.environ.get('beaker.session')
+ if bottle.request.environ.get('REQUEST_METHOD', "GET") == "POST":
for name in user:
- if request.POST.get("%s|admin" % name, False):
+ if bottle.request.POST.get("%s|admin" % name, False):
user[name]['role'] = 0
user[name]['perms']['admin'] = True
elif name != s['name']:
@@ -493,7 +495,7 @@ def admin():
for perm in perms:
user[name]['perms'][perm] = False
- for perm in request.POST.getall("%s|perms" % name):
+ for perm in bottle.request.POST.getall("%s|perms" % name):
user[name]['perms'][perm] = True
user[name]['permission'] = set_permission(user[name]['perms'])
diff --git a/pyload/webui/App/cnl.py b/pyload/webui/App/cnl.py
index 07b966f5e..814cf276f 100644
--- a/pyload/webui/App/cnl.py
+++ b/pyload/webui/App/cnl.py
@@ -17,8 +17,8 @@ from pyload.webui import PYLOAD, DL_ROOT, JS
def local_check(function):
def _view(*args, **kwargs):
- if request.environ.get("REMOTE_ADDR", "0") in ("127.0.0.1", "localhost") \
- or request.environ.get("HTTP_HOST", "0") in ("127.0.0.1:9666", "localhost:9666"):
+ if bottle.request.environ.get("REMOTE_ADDR", "0") in ("127.0.0.1", "localhost") \
+ or bottle.request.environ.get("HTTP_HOST", "0") in ("127.0.0.1:9666", "localhost:9666"):
return function(*args, **kwargs)
else:
return bottle.HTTPError(403, "Forbidden")
@@ -37,8 +37,8 @@ def flash(id="0"):
@bottle.route('/flash/add', method='POST')
@local_check
def add(request):
- package = request.POST.get('referer', None)
- urls = filter(lambda x: x != "", request.POST['urls'].split("\n"))
+ package = bottle.request.POST.get('referer', None)
+ urls = filter(lambda x: x != "", bottle.request.POST['urls'].split("\n"))
if package:
PYLOAD.addPackage(package, urls, 0)
@@ -51,8 +51,8 @@ def add(request):
@bottle.route('/flash/addcrypted', method='POST')
@local_check
def addcrypted():
- package = request.forms.get('referer', 'ClickNLoad Package')
- dlc = request.forms['crypted'].replace(" ", "+")
+ package = bottle.request.forms.get('referer', 'ClickNLoad Package')
+ dlc = bottle.request.forms['crypted'].replace(" ", "+")
dlc_path = os.path.join(DL_ROOT, package.replace("/", "").replace("\\", "").replace(":", "") + ".dlc")
with open(dlc_path, "wb") as dlc_file:
@@ -69,9 +69,9 @@ def addcrypted():
@bottle.route('/flash/addcrypted2', method='POST')
@local_check
def addcrypted2():
- package = request.forms.get("source", None)
- crypted = request.forms['crypted']
- jk = request.forms['jk']
+ package = bottle.request.forms.get("source", None)
+ crypted = bottle.request.forms['crypted']
+ jk = bottle.request.forms['jk']
crypted = base64.standard_b64decode(urllib.unquote(crypted.replace(" ", "+")))
if JS:
@@ -121,13 +121,13 @@ def addcrypted2():
@bottle.route('/flashgot', method='POST')
@local_check
def flashgot():
- if request.environ['HTTP_REFERER'] not in ("http://localhost:9666/flashgot", "http://127.0.0.1:9666/flashgot"):
+ if bottle.request.environ['HTTP_REFERER'] not in ("http://localhost:9666/flashgot", "http://127.0.0.1:9666/flashgot"):
return bottle.HTTPError()
- autostart = int(request.forms.get('autostart', 0))
- package = request.forms.get('package', None)
- urls = filter(lambda x: x != "", request.forms['urls'].split("\n"))
- folder = request.forms.get('dir', None)
+ autostart = int(bottle.request.forms.get('autostart', 0))
+ package = bottle.request.forms.get('package', None)
+ urls = filter(lambda x: x != "", bottle.request.forms['urls'].split("\n"))
+ folder = bottle.request.forms.get('dir', None)
if package:
PYLOAD.addPackage(package, urls, autostart)
@@ -151,7 +151,7 @@ def crossdomain():
@bottle.route('/flash/checkSupportForUrl')
@local_check
def checksupport():
- url = request.GET.get("url")
+ url = bottle.request.GET.get("url")
res = PYLOAD.checkURLs([url])
supported = (not res[0][1] is None)
diff --git a/pyload/webui/App/json.py b/pyload/webui/App/json.py
index 98eb8c4f2..f75ad7517 100644
--- a/pyload/webui/App/json.py
+++ b/pyload/webui/App/json.py
@@ -153,14 +153,14 @@ def link_order(ids):
@bottle.route('/json/add_package', method='POST')
@login_required('ADD')
def add_package():
- name = request.forms.get("add_name", "New Package").strip()
- queue = int(request.forms['add_dest'])
- links = decode(request.forms['add_links'])
+ name = bottle.request.forms.get("add_name", "New Package").strip()
+ queue = int(bottle.request.forms['add_dest'])
+ links = decode(bottle.request.forms['add_links'])
links = links.split("\n")
- pw = request.forms.get("add_password", "").strip("\n\r")
+ pw = bottle.request.forms.get("add_password", "").strip("\n\r")
try:
- f = request.files['add_file']
+ f = bottle.request.files['add_file']
if not name or name == "New Package":
name = f.name
@@ -198,10 +198,10 @@ def move_package(dest, id):
@login_required('MODIFY')
def edit_package():
try:
- id = int(request.forms.get("pack_id"))
- data = {"name": request.forms.get("pack_name").decode("utf8", "ignore"),
- "folder": request.forms.get("pack_folder").decode("utf8", "ignore"),
- "password": request.forms.get("pack_pws").decode("utf8", "ignore")}
+ id = int(bottle.request.forms.get("pack_id"))
+ data = {"name": bottle.request.forms.get("pack_name").decode("utf8", "ignore"),
+ "folder": bottle.request.forms.get("pack_folder").decode("utf8", "ignore"),
+ "password": bottle.request.forms.get("pack_pws").decode("utf8", "ignore")}
PYLOAD.setPackageData(id, data)
return {"response": "success"}
@@ -214,9 +214,9 @@ def edit_package():
@bottle.route('/json/set_captcha', method='POST')
@login_required('ADD')
def set_captcha():
- if request.environ.get('REQUEST_METHOD', "GET") == "POST":
+ if bottle.request.environ.get('REQUEST_METHOD', "GET") == "POST":
try:
- PYLOAD.setCaptchaResult(request.forms['cap_id'], request.forms['cap_result'])
+ PYLOAD.setCaptchaResult(bottle.request.forms['cap_id'], bottle.request.forms['cap_result'])
except Exception:
pass
@@ -255,7 +255,7 @@ def load_config(category, section):
@bottle.route('/json/save_config/<category>', method='POST')
@login_required("SETTINGS")
def save_config(category):
- for key, value in request.POST.iteritems():
+ for key, value in bottle.request.POST.iteritems():
try:
section, option = key.split("|")
except Exception:
@@ -269,9 +269,9 @@ def save_config(category):
@bottle.route('/json/add_account', method='POST')
@login_required("ACCOUNTS")
def add_account():
- login = request.POST['account_login']
- password = request.POST['account_password']
- type = request.POST['account_type']
+ login = bottle.request.POST['account_login']
+ password = bottle.request.POST['account_password']
+ type = bottle.request.POST['account_type']
PYLOAD.updateAccount(type, login, password)
@@ -281,7 +281,7 @@ def add_account():
def update_accounts():
deleted = [] #: dont update deleted accs or they will be created again
- for name, value in request.POST.iteritems():
+ for name, value in bottle.request.POST.iteritems():
value = value.strip()
if not value:
continue
@@ -305,9 +305,9 @@ def update_accounts():
@bottle.route('/json/change_password', method='POST')
def change_password():
- user = request.POST['user_login']
- oldpw = request.POST['login_current_password']
- newpw = request.POST['login_new_password']
+ user = bottle.request.POST['user_login']
+ oldpw = bottle.request.POST['login_current_password']
+ newpw = bottle.request.POST['login_new_password']
if not PYLOAD.changePassword(user, oldpw, newpw):
print "Wrong password"
diff --git a/pyload/webui/App/utils.py b/pyload/webui/App/utils.py
index 18d66c302..e827552df 100644
--- a/pyload/webui/App/utils.py
+++ b/pyload/webui/App/utils.py
@@ -66,7 +66,7 @@ def set_permission(perms):
def set_session(request, info):
- s = request.environ.get('beaker.session')
+ s = bottle.request.environ.get('beaker.session')
s['authenticated'] = True
s['user_id'] = info['id']
s['name'] = info['name']
@@ -89,19 +89,19 @@ def login_required(perm=None):
def _dec(func):
def _view(*args, **kwargs):
- s = request.environ.get('beaker.session')
+ s = bottle.request.environ.get('beaker.session')
if s.get("name", None) and s.get("authenticated", False):
if perm:
perms = parse_permissions(s)
if perm not in perms or not perms[perm]:
- if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
+ if bottle.request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return bottle.HTTPError(403, "Forbidden")
else:
return bottle.redirect("/nopermission")
return func(*args, **kwargs)
else:
- if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
+ if bottle.request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return bottle.HTTPError(403, "Forbidden")
else:
return bottle.redirect("/login")
diff --git a/pyload/webui/themes/Next/tml/logs.html b/pyload/webui/themes/Next/tml/logs.html
index f0f25a9dd..ab5d4f18c 100644
--- a/pyload/webui/themes/Next/tml/logs.html
+++ b/pyload/webui/themes/Next/tml/logs.html
@@ -27,7 +27,7 @@
<div class="logdiv">
<table class="logtable" cellpadding="0" cellspacing="0">
{% for line in log %}
- <tr><td class="logline">{{line.line}}</td><td class="{{color_template}}{{line.level}}">{{line.date}}</td><td class="loglevel loglevel{{color_template}}{{line.level}}"><span>{{line.level}}</span></td><td class="{{color_template}}{{line.level}}">{{line.message}}</td></tr>
+ <tr><td class="logline">{{line.line}}</td><td class="{{color_console}}{{line.level}}">{{line.date}}</td><td class="loglevel loglevel{{color_console}}{{line.level}}"><span>{{line.level}}</span></td><td class="{{color_console}}{{line.level}}">{{line.message}}</td></tr>
{% endfor %}
</table>
</div>