diff --git a/db.py b/db.py
index bdbfb7b93ff1becb01b5e32d8f630d506ac3a8d6..1fa42f3a3d6a710e0cf34463c60aa2efe8186f2b 100644
--- a/db.py
+++ b/db.py
@@ -61,7 +61,15 @@ def query(operation, *params, delim="sep"):
 	operation, params = fix_query(operation, params)
 	cur = get_dbcursor()
 	cur.execute(operation, params)
-	rows = cur.fetchall()
+	rows = []
+	try:
+		rows = cur.fetchall()
+	except mysql.connector.errors.InterfaceError as ie:
+		if ie.msg == 'No result set to fetch from.':
+			# no problem, we were just at the end of the result set
+			pass
+		else:
+			raise
 	res = []
 	for row in rows:
 		res.append({})
@@ -114,7 +122,7 @@ if 'LDAP_HOST' in config:
 		try:
 			conn = ldap3.Connection(config['LDAP_HOST'], 'uid=%s,ou=users,dc=fsmpi,dc=rwth-aachen,dc=de'%user, password, auto_bind=True)
 			if conn.search("ou=groups,dc=fsmpi,dc=rwth-aachen,dc=de", "(&(cn=*)(memberUid=%s))"%user, attributes=['cn']):
-				groups = [e.cn.value for e in conn.entries]
+				groups = [e['attributes']['cn'][0] for e in conn.response]
 			conn.unbind()
 			return user, groups
 		except ldap3.core.exceptions.LDAPBindError:
@@ -125,10 +133,10 @@ if 'LDAP_HOST' in config:
 		conn = ldap3.Connection('ldaps://rumo.fsmpi.rwth-aachen.de', auto_bind=True)
 		conn.search("ou=users,dc=fsmpi,dc=rwth-aachen,dc=de", "(uid=%s)"%user,
 				attributes=ldap3.ALL_ATTRIBUTES)
-		if not conn.entries:
+		if not conn.response:
 			return {}
-		e = conn.entries[0]
-		return {'uid': user, 'givenName': e.givenName.value, 'sn':e.sn.value}
+		e = conn.response[0]
+		return {'uid': user, 'givenName': e['attributes']['givenName'][0], 'sn':e['attributes']['sn'][0]}
 
 else:
 	notldap = {
diff --git a/worker.py b/jobs.py
similarity index 100%
rename from worker.py
rename to jobs.py
diff --git a/server.py b/server.py
index 18044168bfd12f8a616adad27f7063fab58f5305..2d86e9c2023419769896b6853b5b3a0e46bf9ae0 100644
--- a/server.py
+++ b/server.py
@@ -172,6 +172,11 @@ def handle_errors(endpoint, text, code, *errors, **epargs):
 def handle_not_found(e):
 	return render_endpoint('index', 'Diese Seite existiert nicht!'), 404
 
+# debian ships jinja2 without this test...
+@app.template_test(name='equalto')
+def equalto(a,b):
+	return a == b
+
 @app.template_filter(name='semester')
 def human_semester(s, long=False):
 	if not s or s == 'zeitlos' or len(s) != 6:
@@ -205,7 +210,7 @@ def get_announcements(minlevel=0):
 	offset = timedelta()
 	if ismod():
 		offset = timedelta(hours=24)
-	return query('SELECT * FROM announcements WHERE NOT deleted AND (time_expire ISNULL OR time_expire > ?) AND (? OR (visible AND time_publish < ?)) AND level >= ? ORDER BY level DESC', datetime.now()-offset, ismod(), datetime.now(), minlevel)
+	return query('SELECT * FROM announcements WHERE NOT deleted AND ((time_expire = NULL) OR time_expire > ?) AND (? OR (visible AND time_publish < ?)) AND level >= ? ORDER BY level DESC', datetime.now()-offset, ismod(), datetime.now(), minlevel)
 
 @app.template_filter()
 def fixnl(s):
@@ -385,7 +390,7 @@ def edit(prefix='', ignore=[]):
 		prefix = request.args['prefix']
 	modify('BEGIN')
 	changes = request.values.items()
-	if request.is_json:
+	if (request.method == 'POST') and (request.get_json()):
 		changes = request.get_json().items()
 	for key, val in changes:
 		if key in ignore:
@@ -414,7 +419,7 @@ def create(table):
 			columns.append(column)
 			values.append(val)
 	args = request.values
-	if request.is_json:
+	if (request.method == 'POST') and (request.get_json()):
 		args = request.get_json()
 	for column, val in args.items():
 		if column == 'ref':
@@ -539,5 +544,5 @@ if 'ICAL_URL' in config:
 	import meetings
 if 'L2P_APIKEY' in config:
 	import l2pauth
-import worker
+import jobs
 import timetable
diff --git a/sorter.py b/sorter.py
index af01c081c1eee2d5934ac23456297425a3ac5b65..b41213e70cc0d9fbdf9d33da2fc0d988872e3b8c 100644
--- a/sorter.py
+++ b/sorter.py
@@ -26,6 +26,15 @@ def to_ascii(inputstring):
 		asciistring = asciistring.replace(charset[0],charset[1])
 	return asciistring
 
+def insert_video(lectureid,dbfilepath,filepath,fileformatid):
+	video_id = modify('''INSERT INTO videos_data 
+		(lecture_id,visible,path,video_format,title,comment,internal,file_modified,time_created,time_updated,created_by,hash,file_size)
+		VALUES 
+		(?,0,?,?,"","","",?,?,?,?,"",?)''',
+		lectureid, dbfilepath, fileformatid, datetime.now(), datetime.now(), datetime.now(), -1, os.stat(filepath).st_size)
+	query('INSERT INTO sortlog (lecture_id,video_id,path,`when`) VALUES (?,?,?,?)', lectureid, video_id, dbfilepath, datetime.now())
+
+
 @app.route('/sort/now')
 @mod_required
 @sched_func(600)
@@ -130,13 +139,7 @@ def sort_now():
 						if not 'format' in data:
 							data['format'] = 0
 						# insert the video into videos_data and log
-						video_id = modify('''
-							INSERT INTO videos_data 
-								(lecture_id,visible,path,video_format,title,comment,internal,file_modified,time_created,time_updated,created_by,hash,file_size)
-							VALUES 
-								(?,0,?,?,"","","",?,?,?,?,"",?)''',
-							matches[0]['id'], dbfilepath, data['format'], datetime.now(), datetime.now(), datetime.now(), -1, os.stat(filepath).st_size)
-						query('INSERT INTO sortlog (lecture_id,video_id,path,`when`) VALUES (?,?,?,?)', matches[0]['id'], video_id, dbfilepath, datetime.now())
+						insert_video( matches[0]['id'], dbfilepath, filepath, fileformatid)
 					else:
 						# if we couldn't match the video on exactly one lecture, log an error
 						matches_id = []
diff --git a/templates/base.html b/templates/base.html
index d036b5d9435125c32153133958ecdad247c4a633..21aac8398d4e60acc85c03a905a087ffef2956ab 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -119,6 +119,7 @@
 				</div>
 			</div>
 		</div>
+		{% block footer %}
 		<footer class="footer hidden-print">
 			<div class="container-fluid">
 				<ul class="list-inline" style="margin-top: 5px;">
@@ -139,6 +140,7 @@
 					</li>
 			</div>
 		</footer>
+		{% endblock %}
 	</body>
 	{% if ismod() %}
 		<script>
diff --git a/templates/embed.html b/templates/embed.html
index 2aca631f7574714ec41f3b49429aebb94df98d57..1c5fd04e203ca332fab8c53b2461e7dc9f3286c0 100644
--- a/templates/embed.html
+++ b/templates/embed.html
@@ -14,3 +14,5 @@
 </div>
 
 {% endblock %}
+{% block footer %}
+{% endblock %}
diff --git a/templates/import_campus.html b/templates/import_campus.html
index 59ba43b802cbca588bb1211f1a17c15f3287467c..74de6f088815fcce9dc93a5c4f4bec5a313ca5f9 100644
--- a/templates/import_campus.html
+++ b/templates/import_campus.html
@@ -8,7 +8,7 @@
 		</div>
 		<div class="panel-body">
 			<div>
-				<p>Es folgen viele Pärchen an Campus-URL und Veranstaltungstyp Pärchen. Die Campus URL bekommt man aus dem Campus-System (<a href="https://www.campus.rwth-aachen.de/rwth/all/groups.asp">hier</a>). Der Veranstaltungstyp ist z.B. "Vorlesung" oder "Übung" oder "Praktikum".
+				<p>Es folgen viele Pärchen an Campus-URL und Veranstaltungstyp Pärchen. Die Campus URL bekommt man aus dem Campus-System (<a href="https://www.campus.rwth-aachen.de/rwth/all/groups.asp" target="_blank">hier</a>). Der Veranstaltungstyp ist z.B. "Vorlesung" oder "Übung" oder "Praktikum".
 				</p>
 				<form method="post">
 					<ul class="list-group row" style="margin-left: 0px; margin-right: 0px;">
diff --git a/templates/lecture.html b/templates/lecture.html
index 76a45805df7b9a03e33484fc28fb6cc5deb45473..ec272032efb77fd381ea69b6a6f954e3a58404c7 100644
--- a/templates/lecture.html
+++ b/templates/lecture.html
@@ -42,9 +42,9 @@
 						<th></th>
 					</tr>
 					{% for c in chapters|sort(attribute='time') %}
-					<tr onclick="videojs('videoplayer').currentTime({{c['time']}})">
+					<tr>
 						<td>{{ loop.index }}</td>
-						<td>{{ vtttime(c['time']) }}</td>
+						<td><a href="javascript:videojs('videoplayer').currentTime({{c['time']}})">{{ vtttime(c['time']) }}</a></td>
 						<td>{{ moderator_editor(['chapters',c.id,'text'],c['text']) }}</td>
 						<td>{{ moderator_checkbox(['chapters',c.id,'visible'], c.visible) }}</td>
 						<td>{{ moderator_delete(['chapters',c.id,'deleted']) }}</td>