diff --git a/sorter.py b/sorter.py
index 2d6a3d4e80b8fd0d011b7e8cd569c833248151b3..0c8e7eea2f98a62b896b00d0e854867cb6c697b9 100644
--- a/sorter.py
+++ b/sorter.py
@@ -19,19 +19,18 @@ def sort_log():
 			LIMIT 50
 		'''),sorterrorlog=query('SELECT * FROM sorterrorlog ORDER BY sorterrorlog.`when` DESC'))
 
-
 def to_ascii(inputstring):
 	asciistring = inputstring
 	for charset in [('ä', 'ae'), ('ö', 'oe'), ('ü', 'ue'), ('ß', 'ss')]:
 		asciistring = asciistring.replace(charset[0],charset[1])
 	return asciistring
 
-def insert_video(lectureid,dbfilepath,filepath,fileformatid):
+def insert_video(lectureid, dbfilepath, fileformatid, hash="", filesize=-1):
 	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)
+		(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)
+		(?, 0, ?, ?, "", "", "", ?, ?, ?, ?, ?, ?)''',
+		lectureid, dbfilepath, fileformatid, datetime.now(), datetime.now(), datetime.now(), -1, hash, filesize)
 	query('INSERT INTO sortlog (lecture_id,video_id,path,`when`) VALUES (?,?,?,?)', lectureid, video_id, dbfilepath, datetime.now())
 	schedule_thumbnail(lectureid)
 	schedule_job('probe', {'path': dbfilepath, 'lecture_id': lectureid, 'video_id': video_id, 'import-chapters': True})
@@ -55,11 +54,12 @@ def schedule_thumbnail(lectureid, filePath=None):
 def sort_file(filename, course=None, lectures=None):
 	# filenames: <handle>-<sorter>-<format>.mp4
 	# "sorter" musst be found with fuzzy matching. "sorter" musst be one or more of the following types: (inside the loop)
-	
 	# '_' and ' ' are handled like '-'
 	splitfilename = filename.replace('_','-').replace(' ','-').split('-')
 	if not course:
-		handle = '-'.join(splitfilename[:2])
+		handle = splitfilename[0]
+		if splitfilename[0].endswith('ws') or splitfilename[0].endswith('ss'):
+			handle = '-'.join(splitfilename[:2])
 		courses = query('SELECT * FROM courses WHERE handle = ?', handle)
 		if not courses:
 			return []
@@ -87,7 +87,6 @@ def sort_file(filename, course=None, lectures=None):
 			data['keywords'].append(s)
 	# try to match the file on a single lecture
 	matches = []
-	
 	# first try date and time (if one of them is set)
 	if ('date' in data) or ('time' in data):
 		for lecture in lectures:
@@ -119,14 +118,63 @@ def sort_file(filename, course=None, lectures=None):
 			if found:
 				break
 	# now we should have found exactly one match
-	return matches
+	# default format is "unknown", with id 0
+	fmt = 0
+	formats = query('SELECT * FROM formats ORDER BY prio DESC')
+	for videoformat in formats:
+		# we match the last part of the file name without the extension
+		formatstring = splitfilename[-1].split('.',1)[0].lower()
+		if formatstring in videoformat['keywords'].replace(',',' ').split(' '):
+			fmt = videoformat['id']
+			break
+	return matches, fmt
+
+def log_sort_error(course_id, path, matches):
+	matches_id = []
+	for match in matches:
+		matches_id.append(str(match['id']))
+	query('INSERT INTO sorterrorlog_data (course_id, path, matches, `when`, time_updated, time_created) VALUES (?, ?, ?, ?, ?, ?)',
+			course_id, path, ','.join(matches_id), datetime.now(), datetime.now(), datetime.now())
+
+def sort_api_token_required(func):
+	@wraps(func)
+	def decorator(*args, **kwargs):
+		if 'apikey' in request.values:
+			token = request.values['apikey']
+		elif request.get_json() and ('apikey' in request.get_json()):
+			token = request.get_json()['apikey']
+		else:
+			token = None
+		if not token == config.get('SORTER_API_KEY', [None]):
+			return 'Permission denied', 403
+		else:
+			return func(*args, **kwargs)
+	return decorator
+
+@app.route('/internal/sort/encoded/<filename>')
+@sort_api_token_required
+def sort_encoded(filename):
+	matches, fmt = sort_file(filename)
+	if len(matches) != 1:
+		log_sort_error(-1, 'kodiert/'+filename, matches)
+		return "Could not match filename", 400
+	lecture = matches[0]
+	course = query('SELECT * FROM courses WHERE id = ?', lecture['course_id'])[0]
+	if course['autopublish']:
+		schedule_job('publish_video', {'source': filename, 'path': 'pub/'+course['handle']+'/'+filename, 'lecture_id': lecture['id'], 'format_id': fmt})
+	return 'OK', 200
+
+@job_handler('publish_video')
+def handle_published_video(jobid, jobtype, data, state, status):
+	if 'lecture_id' not in data or 'format_id' not in data:
+		return
+	insert_video(data['lecture_id'], data['path'], data['format_id'], hash=status['hash'], filesize=status['filesize'])
 
 @app.route('/internal/sort/now')
 @mod_required
 @sched_func(600)
 def sort_now():
 	courses = query('SELECT * FROM courses')
-	formats = query('SELECT * FROM formats ORDER BY prio')
 	for course in courses:
 		modify('BEGIN')
 		for mountpoint in config['VIDEOMOUNT']:
@@ -151,34 +199,16 @@ def sort_now():
 							break
 					if ignore:
 						continue
-					filepath = coursepath + '/' + filename
 					if not os.path.splitext(filename)[1] == '.mp4':
 						continue
-					matches = sort_file(filename, course=course, lectures=lectures)
+					matches, fmt = sort_file(filename, course=course, lectures=lectures)
 					dbfilepath = mountpoint['prefix']+course['handle']+'/'+filename
 					if len(matches) == 1:
-						# now match the format
-						splitfilename = filename.replace('_','-').replace(' ','-').split('-')
-						# default format is "unknown", with id 0
-						fmt = 0
-						for videoformat in formats:
-							#we match the last part of the file name without the extension
-							formatstring = splitfilename[-1].split('.',1)[0].lower()
-							if formatstring in videoformat['keywords'].replace(',',' ').split(' '):
-								fmt = videoformat['id']
-								break
-						# insert the video into videos_data and log
-						insert_video( matches[0]['id'], dbfilepath, filepath, fmt)
+						insert_video(matches[0]['id'], dbfilepath, fmt)
 					else:
-						# if we couldn't match the video on exactly one lecture, log an error
-						matches_id = []
-						for match in matches:
-							matches_id.append(str(match['id']))
-						query('INSERT INTO sorterrorlog_data (course_id,path,matches,`when`,time_updated,time_created) VALUES (?,?,?,?,?,?)', course['id'], dbfilepath, ','.join(matches_id), datetime.now(), datetime.now(), datetime.now())
+						log_sort_error(course['id'], dbfilepath, matches)
 				except Exception:
 					traceback.print_exc()
-
-		
 		modify('COMMIT')
 	if 'ref' in request.values:
 		return redirect(request.values['ref'])