diff --git a/cutprogress.py b/cutprogress.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc216881b9da0f692fb689b4220be2338a691d7a
--- /dev/null
+++ b/cutprogress.py
@@ -0,0 +1,27 @@
+from server import *
+from datetime import time
+
+@app.route('/internal/cutprogress')
+@app.route('/internal/users/<int:user>/cutprogress')
+@register_navbar('Schnittfortschritt', icon='spinner', iconlib='fa')
+@mod_required
+def cutprogress(user=None):
+	allsemester = query('SELECT DISTINCT semester from courses ORDER BY semester DESC');
+	semester = request.values.get('semester', allsemester[0]['semester'])
+	coursesraw = query('SELECT courses.id, courses.handle, courses.short FROM courses WHERE semester = ?', semester)
+	courses = []
+	maxlecturecount = 0
+	for course in coursesraw:
+		course['lectures'] = query('SELECT lectures.title, lectures.time, lectures.id FROM lectures WHERE lectures.course_id= ? AND NOT lectures.deleted AND NOT lectures.norecording ORDER BY lectures.time', course['id'])
+		maxlecturecount = max(len(course['lectures']),maxlecturecount)
+		for lecture in course['lectures']:
+			lecture['videos'] = query('SELECT videos.path, formats.description as formatdesc FROM videos JOIN formats ON (videos.video_format = formats.id) WHERE videos.lecture_id = ? AND NOT videos.deleted', lecture['id'])
+		course['responsible'] = query('''SELECT users.*
+				FROM responsible
+				JOIN users ON (responsible.user_id = users.id AND responsible.course_id = ?)
+				ORDER BY users.realname ASC''', course['id'])
+		if len(course['responsible']) == 0:
+			course['responsible'] = [{"realname": "Niemand", "id": -1}]
+		if not user or user in [ r['id'] for r in course['responsible'] ]:
+			courses.append(course)
+	return render_template('cutprogress.html', allsemester=allsemester, semester=semester, courses=courses, maxlecturecount=maxlecturecount, user=user)
diff --git a/server.py b/server.py
index bf5ebaa25565eb8ba3e15d56c794d4e393961b74..08473197df571c5a5f35e3a4a45c695723744f65 100644
--- a/server.py
+++ b/server.py
@@ -501,3 +501,4 @@ import timetable
 import chapters
 import icalexport
 import livestreams
+import cutprogress
diff --git a/static/style.css b/static/style.css
index d7b4089a70c19f615ef90f4666da3e88ba0ca501..f2d8898f3dc7998e1ac94cdbb0edd9c087b84f2e 100644
--- a/static/style.css
+++ b/static/style.css
@@ -128,3 +128,14 @@
 	font-size: 27px;
 	margin: 20px;
 }
+
+th.rotate {
+  height: 140px;
+  white-space: nowrap;
+}
+
+th.rotate > div {
+  transform:
+    rotate(270deg)
+    translate(-50px,0px);
+}
diff --git a/templates/cutprogress.html b/templates/cutprogress.html
new file mode 100644
index 0000000000000000000000000000000000000000..34ae9ea619bec864cddd4284b762773a8ff24b2b
--- /dev/null
+++ b/templates/cutprogress.html
@@ -0,0 +1,59 @@
+{% extends "base.html" %}
+{% block content %}
+<div class="panel-group">
+	<div class="panel panel-default">
+		<div class="panel-heading">
+			<span class="panel-title">
+				Semester <select id="semesterselect" name="semester"></select>
+			</span>
+		</div>
+		<div class="panel-body table-responsive">
+			<table class="table table-condensed table-bordered">
+				<tr>
+				{% for course in courses %}
+					<th class="text-center rotate">
+						<div>
+							<a title="Zuständig: {{ course.responsible|join(attribute='realname') }}" href="{{ url_for("course", handle=course.handle) }}">{{ course.short }}</a>
+						</div>
+					</th>
+				{% endfor %}
+				</tr>
+				{% for i in range(maxlecturecount) %}
+				<tr class="text-center">
+					{% for course in courses %}
+					<td>
+						{% set l = course.lectures[i]|d({}) %}
+						{% if "time" in l %}
+						<a href="{{ url_for("course", handle=course.handle) }}#lecture-{{ l.id }}" title="{{ l.time }} &#10;Titel: {{ l.title|replace('\n','') }} &#10;Videos: {{ l.videos|count }} &#10;Internes Kommentar: {{ l.internal }}">
+							{% if l.time < datetime.now() %}
+								{% if l.videos|count == 0 %}
+								<span style="color: red" aria-hidden="true" class="fa fa-times"></span>
+								{% else %}
+								<span style="color: green" aria-hidden="true" class="glyphicon glyphicon-ok"></span>
+								{% endif %}
+							{% else %}
+								<span style="color: grey" aria-hidden="true" class="fa fa-times"></span>
+							{% endif %}
+							</a>
+						{% else %}
+						{% endif %}
+					</td>
+					{% endfor %}
+				</tr>
+				{% endfor %}
+			</table>
+		</div>
+	</div>
+</div>
+<script>
+$( document ).ready(function () {
+	{% for s in allsemester %}
+	$("#semesterselect").append('<option value="{{ s.semester}}">{{ s.semester|semester }}</option>');
+	{% endfor %}
+	$("#semesterselect").val("{{ semester }}")
+	$("#semesterselect").on("change", function () {
+		window.location.href="{{ url_for('cutprogress', user=user) }}?semester="+$("#semesterselect").val();
+	});
+});
+</script>
+{% endblock %}
diff --git a/tests.py b/tests.py
index 3de756841844773c0932432561c596be45915eab..1106b576b79095bae8c4d69d4c6077b4de4c36a4 100755
--- a/tests.py
+++ b/tests.py
@@ -274,6 +274,13 @@ class VideoTestCase(unittest.TestCase):
 			r = self.app.get('/internal/import/257/now')
 			assert r.status_code == 200
 
+	def test_cutprogress(self):
+		with self.app as c:
+			self.login(c)
+			r = self.app.get('/internal/cutprogress')
+			assert r.status_code == 200
+
+
 if __name__ == '__main__':
 	unittest.main()