diff --git a/config.py.example b/config.py.example
index 6dc234e3c34afdfbf50fb23bea26e140ee158129..186b638439da3da382799862eb27ab9d449e4038 100644
--- a/config.py.example
+++ b/config.py.example
@@ -25,6 +25,7 @@ SQLITE_INIT_DATA = True
 
 #LDAP_HOST = 'rumo.fsmpi.rwth-aachen.de'
 LDAP_PORT = 636
+LDAP_GROUPS = ['users']
 #ICAL_URL = 'https://user:password@mail.fsmpi.rwth-aachen.de/SOGo/....ics'
 ERROR_PAGE = 'static/500.html'
 RWTH_IP_RANGES = ['134.130.0.0/16', '137.226.0.0/16', '134.61.0.0/16', '192.35.229.0/24', '2a00:8a60::/32']
diff --git a/db.py b/db.py
index a4cac848bd6421e307d0b408f1039191a03b4a70..866d3d1d77e280931912085d680c9f39954a6c39 100644
--- a/db.py
+++ b/db.py
@@ -152,24 +152,14 @@ if 'LDAP_HOST' in config:
 	def ldapauth(user, password):
 		user = LDAP_USERRE.sub(r'', user.lower())
 		try:
-			conn = ldap3.Connection(ldap3.Server(config['LDAP_HOST'], port=config['LDAP_PORT'], use_ssl=True), 'uid=%s,ou=users,dc=fsmpi,dc=rwth-aachen,dc=de'%user, password, auto_bind=True)
-			groups = []
-			if conn.search("ou=groups,dc=fsmpi,dc=rwth-aachen,dc=de", "(&(cn=*)(memberUid=%s))"%user, attributes=['cn']):
-				groups = [e['attributes']['cn'][0] for e in conn.response]
-			conn.unbind()
-			return user, groups
-		except ldap3.core.exceptions.LDAPExceptionError:
-			return None, []
-
-	def ldapget(user):
-		user = LDAP_USERRE.sub(r'', user.lower())
-		conn = ldap3.Connection(ldap3.Server(config['LDAP_HOST'], port=config['LDAP_PORT'], use_ssl=True), auto_bind=True)
-		conn.search("ou=users,dc=fsmpi,dc=rwth-aachen,dc=de", "(uid=%s)"%user,
-				attributes=ldap3.ALL_ATTRIBUTES)
-		if not conn.response:
-			return {}
-		e = conn.response[0]
-		return {'uid': user, 'givenName': e['attributes']['givenName'][0], 'sn':e['attributes']['sn'][0]}
+			conn = ldap3.Connection(ldap3.Server(config['LDAP_HOST'], port=config['LDAP_PORT'], use_ssl=True), 'fsmpi\\%s'%user, password, auto_bind=True, check_names=False)
+		except ldap3.core.exceptions.LDAPBindError:
+			return {}, []
+		conn.search("cn=users,dc=fsmpi,dc=rwth-aachen,dc=de", "(cn=%s)"%user, attributes=['memberOf', 'givenName', 'sn'])
+		info = {'uid': user, 'givenName': conn.response[0]['attributes']['givenName'][0], 'sn': conn.response[0]['attributes']['sn'][0]}
+		groups = [g.split(',')[0].split('=')[-1] for g in conn.response[0]['attributes']['memberOf']]
+		conn.unbind()
+		return info, groups
 
 else:
 	notldap = {
@@ -180,9 +170,5 @@ else:
 	def ldapauth(user, password):
 		user = LDAP_USERRE.sub(r'', user.lower())
 		if config.get('DEBUG') and user in notldap and password == notldap[user][0]:
-			return user, notldap[user][1]
-		return None, []
-
-	def ldapget(user):
-		user = LDAP_USERRE.sub(r'', user.lower())
-		return notldap[user][2]
+			return notldap[user][2], notldap[user][1]
+		return {}, []
diff --git a/icalexport.py b/icalexport.py
index 9f360f623d721b65e5e8fd857d60309efa95e73a..8ab175842f0ccc80c3464213a34ff817aeb88027 100644
--- a/icalexport.py
+++ b/icalexport.py
@@ -7,28 +7,24 @@ def export_lectures(lectures, name):
 	cal = icalendar.Calendar()
 	cal.add('prodid', '-//Video AG//rwth.video//')
 	cal.add('version', '1.0')
-
-	courses = {};
 	for l in lectures:
 		event = icalendar.Event()
-		if not l['course_id'] in courses:
-			courses[l['course_id']] = query('SELECT * from courses WHERE id = ?',l['course_id'])[0]
-		c = courses[l['course_id']]
-
-		event.add('summary', c['short']+' : '+l['title'])
-		event.add('description', l['internal'])
-		event.add('uid', 'lecture_'+str(l['id'])+'@rwth.video')
-		event.add('comment', l['comment'])
+		event.add('summary', l['course']['short']+': '+l['title'])
+		event.add('description', '\n\n'.join([s for s in [
+					l['comment'],
+					l['internal'],
+					'Zuständig: '+l['course']['responsible'] if l['course']['responsible'] else ''
+			] if s]))
+		event.add('uid', '%i@rwth.video'%l['id'])
 		event.add('dtstamp', datetime.utcnow())
-		event.add('categories', c['short'])
+		event.add('categories', l['course']['short'])
 		event.add('dtstart', l['time'])
 		event.add('location', l['place'])
 		event.add('dtend', l['time'] + timedelta(minutes=l['duration']))
 		cal.add_component(event)
-
-	H = Headers()
-	H.add_header("Content-Disposition", "inline", filename=name)
-	return Response(cal.to_ical(), mimetype="text/calendar", headers=H)
+	h = Headers()
+	h.add_header("Content-Disposition", "inline", filename=name)
+	return Response(cal.to_ical(), mimetype="text/calendar", headers=h)
 
 def calperm(func):
 	@wraps(func)
@@ -46,21 +42,16 @@ def calperm(func):
 			return redirect(url_for('index'))
 	return decorator
 
-@app.route('/internal/ical/semester/<semester>')
-@calperm
-def ical_semester(semester):
-	if semester == 'zeitlos':
-		semester_q = ''
-	else:
-		semester_q = semester
-	return export_lectures(query('SELECT lectures.* FROM lectures JOIN courses ON courses.id = lectures.course_id WHERE courses.semester = ? AND lectures.visible = 1', semester_q),'videoag_semester_'+semester+'.ics')
-
 @app.route('/internal/ical/all')
 @calperm
 def ical_all():
-	return export_lectures(query('SELECT lectures.* FROM lectures WHERE lectures.visible = 1'),'videoag_all.ics')
+	return export_lectures(query('''SELECT lectures.*, "course" AS sep, courses.*
+				FROM lectures JOIN courses ON courses.id = lectures.course_id
+				WHERE NOT norecording AND NOT external ORDER BY time DESC LIMIT 1000'''),'videoag_all.ics')
 
 @app.route('/internal/ical/course/<course>')
 @calperm
 def ical_course(course):
-	return export_lectures(query('SELECT lectures.* FROM lectures JOIN courses ON courses.id = lectures.course_id WHERE courses.handle = ? AND lectures.visible = 1', course),'videoag_course_'+course+'.ics')
+	return export_lectures(query('''SELECT lectures.*, "course" AS sep, courses.*
+				FROM lectures JOIN courses ON courses.id = lectures.course_id
+				WHERE courses.handle = ? AND NOT norecording AND NOT external ORDER BY time DESC''', course),'videoag_course_'+course+'.ics')
diff --git a/server.py b/server.py
index 860e9699c7aa99e88f8ed93f99e006a0431c4954..1631071f941a81499b1444d25fe8ccda7d9f8d9f 100644
--- a/server.py
+++ b/server.py
@@ -72,7 +72,7 @@ app.jinja_env.globals['gitversion'] = { 'hash': output[1], 'longhash': output[0]
 if not config.get('SECRET_KEY', None):
 	config['SECRET_KEY'] = os.urandom(24)
 
-from db import query, modify, show, searchquery, ldapauth, ldapget
+from db import query, modify, show, searchquery, ldapauth
 
 mod_endpoints = []
 
@@ -502,17 +502,23 @@ def search():
 	return render_template('search.html', searchtext=request.args['q'], courses=courses, lectures=lectures)
 
 def check_mod(user, groups):
-	return user and 'users' in groups
+	if not user:
+		return False
+	for group in config['LDAP_GROUPS']:
+		if group in groups:
+			return True
+	return False
 
 @app.route('/internal/login', methods=['GET', 'POST'])
 def login():
 	if request.method == 'GET':
 		return render_template('login.html')
-	user, groups = ldapauth(request.form.get('user'), request.form.get('password'))
+	userinfo, groups = ldapauth(request.form.get('user'), request.form.get('password'))
+	user = userinfo.get('uid')
 	if not check_mod(user, groups):
 		flash('Login fehlgeschlagen!')
 		return render_template('login.html')
-	session['user'] = ldapget(user)
+	session['user'] = userinfo
 	dbuser = query('SELECT * FROM users WHERE name = ?', user)
 	if not dbuser:
 		modify('INSERT INTO users (name, realname, fsacc, level, calendar_key, rfc6238) VALUES (?, ?, ?, 1, "", "")', user, session['user']['givenName'], user)
diff --git a/static/style.css b/static/style.css
index 870481be8d90ca6103f983ccc4c05f8197dc46c1..d7b4089a70c19f615ef90f4666da3e88ba0ca501 100644
--- a/static/style.css
+++ b/static/style.css
@@ -74,6 +74,10 @@
 	}
 }
 
+.footer {
+	z-index: 100;
+}
+
 .plot-view {
 	height: 600px;
 }
diff --git a/templates/macros.html b/templates/macros.html
index 0c87bac504b0d0ac2b792a8206679fec194c28aa..432956f9b084bcbe18b77d9f269b4622873a6b1b 100644
--- a/templates/macros.html
+++ b/templates/macros.html
@@ -52,7 +52,6 @@
 <video id="videoplayer" style="width: 100%" class="video-js vjs-default-skin vjs-big-play-centered" width="640" height="320" controls data-wasnotplayed="1"  data-setup='{ "language":"de", "plugins" : {"hotkeys": {"seekStep": 15, "enableVolumeScroll": false, "alwaysCaptureHotkeys": true}, "videoJsResolutionSwitcher": { "ui": true, "default": "720p", "dynamicLabel": false } }, "customControlsOnMobile": true, "playbackRates": [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 4] }'>
 	{% for v in videos|sort(attribute='formats.player_prio', reverse=True) %}
 	<source type="{{ v.formats.mimetype }}" src="{{ config.VIDEOPREFIX }}/{{ v.path }}" data-label="{{ v.formats.description }}" data-res="{{v.formats.resolution}}" data-aspect="{{v.formats.aspect}}" data-player_prio="{{v.formats.player_prio}}"/>
-	{{ v|safe }}
 	{% endfor %}
 	<track srclang="de" kind="chapters" src="{{ url_for('chapters',lectureid=lecture.id) }}" />
 </video>