Commit 1359dc33 authored by Andreas Valder's avatar Andreas Valder

removed duplicated spaces, see #346

parent effd6235
......@@ -20,7 +20,7 @@ def suggest_chapter(lectureid):
lectureid, time, text, datetime.now(), datetime.now(), session.get('user', {'dbid':None})['dbid'], submitter)
if 'ref' in request.values:
return redirect(request.values['ref'])
return 'OK', 200
return 'OK', 200
@app.route('/internal/chapters/<int:lectureid>')
def chapters(lectureid):
......@@ -33,5 +33,5 @@ def chapters(lectureid):
c['end'] = last['start'] if last else 9999
last = c
if 'json' in request.values:
return Response(json.dumps([{'time': c['time'], 'text': c['text']} for c in chapters]), mimetype='application/json')
return Response(json.dumps([{'time': c['time'], 'text': c['text']} for c in chapters]), mimetype='application/json')
return Response(render_template('chapters.srt',chapters=chapters), 200, {'Content-Type':'text/vtt'})
......@@ -9,7 +9,7 @@ def list_import_sources(id):
for i in request.values:
group, importid, field = i.split('.', 2)
if group == 'campus':
if not importid in campus:
if not importid in campus:
campus[importid] = {}
campus[importid][field] = request.values[i]
for i in campus:
......
......@@ -5,7 +5,7 @@ import random
from sorter import schedule_thumbnail
@app.route('/internal/jobs/overview')
@register_navbar('Jobs', iconlib='fa', icon='suitcase')
@register_navbar('Jobs', iconlib='fa', icon='suitcase')
@mod_required
def jobs_overview():
if 'page' in request.args:
......@@ -31,7 +31,7 @@ def jobs_overview():
'state': request.args.get('state','failed'),
'worker': request.args.get('worker','%') }
pagecount = math.ceil(query('SELECT count(id) as count FROM jobs WHERE (type like ?) AND (worker like ? OR (worker IS NULL AND ? = "%")) AND (state like ?)', filter['type'], filter['worker'], filter['worker'], filter['state'])[0]['count']/pagesize)
pagecount = math.ceil(query('SELECT count(id) as count FROM jobs WHERE (type like ?) AND (worker like ? OR (worker IS NULL AND ? = "%")) AND (state like ?)', filter['type'], filter['worker'], filter['worker'], filter['state'])[0]['count']/pagesize)
jobs = query('SELECT * FROM jobs WHERE (type like ?) AND (worker like ? OR (worker IS NULL AND ? = "%")) AND (state like ?) ORDER BY `time_created` DESC LIMIT ? OFFSET ?', filter['type'], filter['worker'], filter['worker'], filter['state'], pagesize, page*pagesize)
return render_template('jobs_overview.html',worker=worker,jobs=jobs, filter_values=filter_values, filter=filter, page=page, pagesize=pagesize, pagecount=pagecount)
......@@ -117,7 +117,7 @@ def jobs_ping(id):
@app.route('/internal/jobs/api/worker/<hostname>/schedule', methods=['POST'])
@jobs_api_token_required
def jobs_schedule(hostname):
hostdata = request.get_json()
hostdata = request.get_json()
if not hostdata:
return 'no hostdata sent', 400
job = None
......@@ -136,4 +136,4 @@ def jobs_schedule(hostname):
except:
job = None
sleep(random.randinti(0,50))
return Response(json.dumps(job, default=date_json_handler), mimetype='application/json')
return Response(json.dumps(job, default=date_json_handler), mimetype='application/json')
......@@ -102,7 +102,7 @@ def sort_now():
try:
if len(s) == 6:
data['date'] = datetime.strptime(s,'%y%m%d').date()
elif len(s) == 4:
elif len(s) == 4:
data['time'] = datetime.strptime(s,'%H%M').time()
else:
data['keywords'].append(s)
......@@ -122,7 +122,7 @@ def sort_now():
if ('time' in data) and (lecture['time'].time() != data['time']):
continue
matches.append(lecture)
# if we can't match exactly based on date and time, we have to match keywords
# if we can't match exactly based on date and time, we have to match keywords
if ((len(matches) != 1) and (len(data['keywords']) > 0)):
#only test lectures with the correct date/time, if we have any. Else test for matches in all lectures of this course
if len(matches) == 0:
......@@ -132,8 +132,7 @@ def sort_now():
for lecture in matches:
for keyword in data['keywords']:
# first test for exact match, else make it asci and try substring test
if (keyword == lecture[field]) or \
(str(keyword).lower() in str(to_ascii(lecture[field]).lower())):
if (keyword == lecture[field]) or (str(keyword).lower() in str(to_ascii(lecture[field]).lower())):
found = True
matches = [lecture]
if found:
......@@ -171,5 +170,5 @@ def sort_now():
if 'ref' in request.values:
return redirect(request.values['ref'])
else:
return 'OK', 200
return 'OK', 200
......@@ -14,10 +14,10 @@ def stats():
year = int(s['semester'][0:4])
if s['semester'].endswith('ss'):
s['from'] = datetime(year,4,1)
s['to'] = datetime(year,10,1)
s['to'] = datetime(year,10,1)
if s['semester'].endswith('ws'):
s['from'] = datetime(year,10,1)
s['to'] = datetime(year+1,4,1)
s['to'] = datetime(year+1,4,1)
return render_template('stats.html',semester=semester,filter=request.args.get('filter'))
statsqueries = {}
......@@ -57,7 +57,7 @@ def stats_generic(req, param=None):
if key not in res:
res[key] = []
res[key].append(val)
return Response(json.dumps([res], default=plotly_date_handler), mimetype='application/json')
return Response(json.dumps([res], default=plotly_date_handler), mimetype='application/json')
@app.route('/internal/stats/viewsperday/<req>')
@app.route('/internal/stats/viewsperday/<req>/<param>')
......@@ -146,5 +146,5 @@ def stats_viewsperday(req, param=""):
trace['x'].append(start)
trace['y'].append(data.get(start, {}).get(trace['name'], 0))
start += timedelta(days=1)
return Response(json.dumps(res, default=plotly_date_handler), mimetype='application/json')
return Response(json.dumps(res, default=plotly_date_handler), mimetype='application/json')
......@@ -12,7 +12,7 @@ app.add_template_global(max, name='max')
# get git commit
output = subprocess.check_output(['git', "log", "-g", "-1", "--pretty=%H # %h # %d # %s"]).decode('UTF-8').split('#', 3)
app.jinja_env.globals['gitversion'] = { 'hash': output[1], 'longhash': output[0], 'branch': output[2], 'msg': output[3] }
app.jinja_env.globals['gitversion'] = {'hash': output[1], 'longhash': output[0], 'branch': output[2], 'msg': output[3]}
@app.template_global()
def ismod(*args):
......
......@@ -147,7 +147,7 @@
</div>
</div>
{% block footer %}
<footer class="footer hidden-print" {% if config.DEBUG %} style="background-color: red" {% endif %} >
<footer class="footer hidden-print" {% if config.DEBUG %} style="background-color: red" {% endif %} >
<div class="container-fluid">
<ul class="list-inline" style="margin-top: 5px;">
<li>
......
{% macro summary(course) %}
{% if course.organizer %}
{% if course.organizer %}
Veranstalter: {{ course.organizer }}<br>
{% endif %}
{% endif %}
<p>{{ course.description }}</p>
{% endmacro %}
<?xml version="1.0" encoding="utf-8"?>
......
......@@ -38,7 +38,7 @@
<p>Unser Server hat keine (nein, absolut keine!) Bandbreitenbegrenzung, also bekommst du schon für einen einzigen Download die volle Geschwindigkeit und wirst selbst mit solchen Programmen keine schnelleren Downloads erfahren. Zu viele Verbindungen sorgen nur für exzessive Systemlast und damit langsamere Downloads für alle, dich eingeschlossen.</p>
{% endcall %}
{% call faqentry("duration", "Wieso dauert das so lange, bis Videos verfügbar sind?") %}
<p>Bis wir ein Video veröffentlichen können, ist erst noch eine Bearbeitung notwendig, der "Schnitt". Zuerst müssen die Rohdaten auf den jeweiligen Rechner, auf dem geschnittten wird, kopiert werden. Pro Vorlesung fallen mindestens 20GB an Daten an, oft auch gerne mal das doppelte oder mehr.Teilweise ist noch entpacken, transcodieren oder sonstiges bearbeiten der einzelnen Dateien nötig, bevor sie für Premiere (der Software von Adobe, die wir für den Schnitt verwenden) lesbar sind und unseren eigenen Ansprüchen genügen.</p>
<p>Bis wir ein Video veröffentlichen können, ist erst noch eine Bearbeitung notwendig, der "Schnitt". Zuerst müssen die Rohdaten auf den jeweiligen Rechner, auf dem geschnittten wird, kopiert werden. Pro Vorlesung fallen mindestens 20GB an Daten an, oft auch gerne mal das doppelte oder mehr.Teilweise ist noch entpacken, transcodieren oder sonstiges bearbeiten der einzelnen Dateien nötig, bevor sie für Premiere (der Software von Adobe, die wir für den Schnitt verwenden) lesbar sind und unseren eigenen Ansprüchen genügen.</p>
<p>Dann erst beginnt der eigentliche Schnitt. Dieser kann weniger als eine Stunde dauern, manchmal aber auch um vieles mehr. Das hängt unter Anderem davon ab, wie viele zu synchronisierende Medien verwendet werden, ob wir die Audiodateien oder die Farben der Kameraaufzeichnungen nachträglich korrigieren bzw manuell Folien einfügen müssen, ob Overheadprojektoren verwendet werden (deren Aufnahme ist oft ohne langwieriger Bearbeitung nicht sinnvoll lesbar) und und und...</p>
<p>Wenn wir dann schließlich mit dem bearbeiteten Video zufrieden sind, muss es noch konvertiert werden, damit es so abspielbar ist, wie ihr es von unseren Videos gewohnt seid. Dies dauert ohne aufwändige Bearbeitungen auf unseren Schnittrechnern in etwa so lang, wie auch die Veranstaltung geht. Wenn allerdings Bearbeitungen gemacht wurden, kann ein Video gern auch mal 20 Stunden im Encoder verbringen. Schließlich veröffentlichen wir dann das fertige Video auf unserer Website.</p>
<p>Es kann immer mal passieren, dass in einer Vorlesung etwas schief läuft und einzelne Videos viel zeitaufwändiger sind als die anderen in einer Veranstaltungsreihe. Wir versuchen, über die Textfelder innerhalb der Terminliste der zugehörigen Veranstaltung mit euch zu kommunizieren und euch Informationen zu den (noch nicht) hochgeladenen Videos zu geben.</p>
......@@ -52,8 +52,8 @@
<p>Wer auf ein bestimmtes Videos zugreifen kann, wird auf der Veranstaltungsseite durch Symbole auf der rechten Seite angezeigt. Dabei gibt es folgende Möglichkeiten:</p>
<ul>
<li><strong>Öffentliche</strong> Videos (<span class="fa fa-globe"></span>) können von jedem abgespielt werden.</li>
<li><strong>RWTH-interne</strong> Videos (<span class="fa" style="width: 25px; height: 17px; background-size: cover; background-image: url('/static/rwth.png');"></span>) sind nur für RWTH-Angehörige verfügbar. Zum Anschauen ist eine Authentifizierung über das RWTH-Single-Sign-On nötig.</li>
<li><strong>Lernraum-interne</strong> Videos (<span class="fa" style="width: 12px; height: 14px; background-size: cover; background-image: url('/static/l2p-logo.gif');"></span>) sind nur für Teilnehmer eines bestimmten L2P-Lernraums zugänglich. Wir überprüfen dies, indem du uns kurzzeitig Zugriff auf deinen L2P-Account gibst, aus dem wir die Liste deiner Lernräume auslesen. Solltest du eine Vorlesung hören, dem zugehörigen Lernraum aber nicht hinzugefügt worden sein, melde dich bitte beim entsprechenden Dozenten.</li>
<li><strong>RWTH-interne</strong> Videos (<span class="fa" style="width: 25px; height: 17px; background-size: cover; background-image: url('/static/rwth.png');"></span>) sind nur für RWTH-Angehörige verfügbar. Zum Anschauen ist eine Authentifizierung über das RWTH-Single-Sign-On nötig.</li>
<li><strong>Lernraum-interne</strong> Videos (<span class="fa" style="width: 12px; height: 14px; background-size: cover; background-image: url('/static/l2p-logo.gif');"></span>) sind nur für Teilnehmer eines bestimmten L2P-Lernraums zugänglich. Wir überprüfen dies, indem du uns kurzzeitig Zugriff auf deinen L2P-Account gibst, aus dem wir die Liste deiner Lernräume auslesen. Solltest du eine Vorlesung hören, dem zugehörigen Lernraum aber nicht hinzugefügt worden sein, melde dich bitte beim entsprechenden Dozenten.</li>
<li><strong>Passwort-geschützte</strong> Videos (<span class="fa fa-lock"></span>) sind nur nach Eingabe eines Passworts verfügbar, welches jedem zur Verfügung gestellt wurde, der Zugriff haben sollte. In der Regel gibt es gute Gründe, warum dieser Zugriffsschutz gewählt wurde.</li>
</ul>
<p>Falls du keinen Zugriff auf ein Video hast, wird dies auf der Player-Seite angezeigt und ggf. auf die weiteren Schritte zur Authentifizierung verwiesen. Die erläuterten Möglichkeiten decken nicht jeden denkbaren Fall ab. Solltest du Zugriff auf eine Veranstaltung benötigen, aber aus irgendwelchen Gründen nicht haben, schreib uns eine Mail.<p>
......
......@@ -15,7 +15,7 @@
{%for i in import_campus %}
<li class="list-group-item form-inline row">
<span class="input-group col-xs-8">
<input class="form-control" type="text" name="campus.{{i.id}}.url" value="{{i.url}}" id="campus-{{i.id}}-url" placeholder="url">
<input class="form-control" type="text" name="campus.{{i.id}}.url" value="{{i.url}}" id="campus-{{i.id}}-url" placeholder="url">
</span>
<span class="input-group col-xs-2">
<input class="form-control" type="test" name="campus.{{i.id}}.type" value="{{i.type}}" id="campus-{{i.id}}-type" placeholder="type">
......
......@@ -128,7 +128,7 @@
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h1 class="panel-title">Neueste Videos <a class="fa fa-rss-square pull-right" aria-hidden="true" href="{{url_for('feed')}}" style="text-decoration: none"></a></h1>
<h1 class="panel-title">Neueste Videos <a class="fa fa-rss-square pull-right" aria-hidden="true" href="{{url_for('feed')}}" style="text-decoration: none"></a></h1>
</div>
<ul class="list-group videopreview">
{% for i in latestvideos %}
......
......@@ -19,7 +19,7 @@
{% endif %}
</div>
<div class="col-xs-4">
<div>{{ lecture['title']|fixnl|safe }}</div>
<div>{{ lecture['title']|fixnl|safe }}</div>
</div>
</div>
</div>
......@@ -39,7 +39,7 @@
</li>
{% endif %}
<li>
{{ lecture['title']|fixnl|safe }}
{{ lecture['title']|fixnl|safe }}
</li>
</ul>
</div>
......@@ -54,7 +54,7 @@
{% else %}
{% set mfrag = "#t="+seek %}
{% endif %}
<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] }'>
<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 }}{{mfrag}}" data-label="{{ v.formats.description }}" data-res="{{v.formats.resolution}}" data-aspect="{{v.formats.aspect}}" data-player_prio="{{v.formats.player_prio}}"/>
{% endfor %}
......@@ -207,7 +207,7 @@ $('#embedcodebtn').popover(
{% macro lecture_list_item(lecture,videos,global_permissions,chapters=[]) %}
<li class="list-group-item{% if lecture.norecording %} text-muted{% endif %}" id="lecture-{{lecture.id}}">
<div class="row">
{% if ismod() or (videos|length > 0) %}
{% if ismod() or (videos|length > 0) %}
<div style="background-image: url('{{ config.VIDEOPREFIX }}/thumbnail/l_{{lecture.id}}.jpg')" class="col-sm-2 col-xs-12 thumbnailimg">
{% if not videos|length is equalto 0 %}
<a href="{{url_for('lecture', course=lecture.course.handle, id=lecture.id)}}">
......@@ -218,7 +218,7 @@ $('#embedcodebtn').popover(
<ul class="list-unstyled col-sm-3 col-xs-12">
<li>{{ moderator_editor(['lectures',lecture.id,'title'], lecture.title) }}{{livelabel((lecture.live and lecture.time > datetime.now()-timedelta(days=1)), videos|selectattr("livehandle")|list|length)}}</li>
{% if lecture.speaker or ismod() %}<li>Gehalten von {{ moderator_editor(['lectures',lecture.id,'speaker'], lecture.speaker) }}</li>{% endif %}
{% if ismod() %}
{% if ismod() %}
<li>{{ moderator_editor(['lectures',lecture.id,'time'], lecture.time) }} </li>
<li>Dauer: {{ moderator_editor(['lectures',lecture.id,'duration'], lecture.duration) }} min</li>
<li>ID: <a href="{{url_for('course',handle=lecture.course.handle)}}#lecture-{{lecture.id}}">{{lecture.id}}</a></li>
......@@ -231,7 +231,7 @@ $('#embedcodebtn').popover(
{% for chapter in chapters %}
<li><span class="glyphicon glyphicon-play"></span> <a href="{{url_for('lecture', course=lecture.course.handle, id=lecture.id, t=chapter.time)}}">{{chapter.text}}</a></li>
{% endfor %}
{% if ismod() %}
{% if ismod() %}
<li>{{ moderator_editor(['lectures',lecture.id,'internal'], lecture.internal) }}</li>
<li>Sichtbar: {{ moderator_checkbox(['lectures',lecture.id,'visible'], lecture.visible) }}</li>
<li>Livestream geplant: {{ moderator_checkbox(['lectures',lecture.id,'live'], lecture.live) }}</li>
......@@ -322,17 +322,17 @@ $('#embedcodebtn').popover(
{% set permlogos = '<span class="fa fa-lock" aria-hidden="true"></span>' %}
{% endif %}
{% if permdescription[0] == 'l2p' %}
{% set permlogos = '<span class="fa" aria-hidden="true" style="width: 12px; height: 14px; background-size: cover; background-image: url(\'/static/l2p-logo.gif\');"></span>' %}
{% set permlogos = '<span class="fa" aria-hidden="true" style="width: 12px; height: 14px; background-size: cover; background-image: url(\'/static/l2p-logo.gif\');"></span>' %}
{% endif %}
{% if permdescription[0] == 'rwth' %}
{% set permlogos = '<span class="fa" aria-hidden="true" style="width: 25px; height: 20px; background-size: cover; background-image: url(\'/static/rwth.png\');"></span>' %}
{% set permlogos = '<span class="fa" aria-hidden="true" style="width: 25px; height: 20px; background-size: cover; background-image: url(\'/static/rwth.png\');"></span>' %}
{% endif %}
{% if permdescription[0] == 'fsmpi' %}
{% set permlogos = '<span class="fa" aria-hidden="true" style="width: 25px; height: 20px; background-size: cover; background-image: url(\'/static/fsmpi.png\');"></span>' %}
{% set permlogos = '<span class="fa" aria-hidden="true" style="width: 25px; height: 20px; background-size: cover; background-image: url(\'/static/fsmpi.png\');"></span>' %}
{% endif %}
{% if ismod() %}
<button class="btn btn-default" data-toggle="modal" data-target="#editperm" data-type="{{ type }}" data-id="{{ id }}">
<button class="btn btn-default" data-toggle="modal" data-target="#editperm" data-type="{{ type }}" data-id="{{ id }}">
{{ permlogos|safe }}
</button>
{% else %}
......
......@@ -6,7 +6,7 @@
<div class="panel-heading">
<h1 class="panel-title">Sortierlog
<a class="btn btn-default" href="{{url_for('sort_now', ref=request.url)}}">Jetzt einsortieren</a>
<button class="btn btn-default" onclick="$('button[data-path^=\'sorterrorlog.\'][data-path$=\'.deleted\']').each(function (e) { moderator.api.set($(this).data('path'),1,false); }); window.location.reload();">Alle Fehler entfernen</button>
<button class="btn btn-default" onclick="$('button[data-path^=\'sorterrorlog.\'][data-path$=\'.deleted\']').each(function (e) { moderator.api.set($(this).data('path'),1,false); }); window.location.reload();">Alle Fehler entfernen</button>
</h1>
</div>
<div class="panel-body">
......
......@@ -31,7 +31,7 @@
<div class="panel-heading">
<span class="panel-title"><a name="semesterstats"></a>Semester <select id="semesterselect" name="semester"><option value="">alle</option></select></span>
</div>
<div class="panel-body" >
<div class="panel-body" >
<div class=col-xs-12">
<p class="text-center">Zuschauer pro Veranstaltung</p>
<div class="plot-view" data-url="{{url_for('stats_viewsperday', req="courses", filter=filter)}}"></div>
......
......@@ -8,7 +8,7 @@
</h1>
</div>
<div class="hidden-print">
<div style="margin-top: 10px; padding: 15px;" class="col-xs-12">
<div style="margin-top: 10px; padding: 15px;" class="col-xs-12">
<a href="{{url_for('timetable', kw=kw-1) }}" class="pull-left btn btn-default">{{ "<<" }}</a>
<a href="{{url_for('timetable', kw=kw+1) }}" class="pull-right btn btn-default">{{ ">>" }}</a>
<a href="{{url_for('timetable', kw=0) }}" style="width: 80px;" class="btn btn-default center-block">today</a>
......@@ -30,9 +30,9 @@
{% set time_index = loop.index %}
<tr{% if t.strftime("%M") == "00" %} class="hourlytime"{% endif %}>
{# display time in first row if its a full hour #}
{% if ((time_index - 1) is divisibleby 4) %} <td rowspan="4" style="vertical-align: top;">{{ t.strftime("%H:%M") }}</td> {% endif %}
{% if ((time_index - 1) is divisibleby 4) %} <td rowspan="4" style="vertical-align: top;">{{ t.strftime("%H:%M") }}</td> {% endif %}
{# iterate over days if if it is a working day or we have lectures on that day (optionaly skip weekends) #}
{% for d in days if (d.index < 5) or (d.lectures|length) > 0 %}
{% for d in days if (d.index < 5) or (d.lectures|length) > 0 %}
{% for col in range(1,d.maxcol+1) %}
{# iterate over all lextures but only consider those that are in the current column and happen in the 15 min block #}
......
......@@ -68,7 +68,7 @@ def timetable():
# who the hell inserts lectures with zero length?!?!?
l['time_end'] = l['time']+timedelta(minutes=max(l['duration'],1))
# create sweepline input array
sweeplinetupels = [(l['time'],True,l) for l in i['lectures']]
sweeplinetupels = [(l['time'],True,l) for l in i['lectures']]
sweeplinetupels += [(l['time_end'],False,l) for l in i['lectures']]
tmp = []
for x in sweeplinetupels:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment