def restart_file(): """ restart a File :return: "" """ file_id = request.form["file_id"] file = File.query.filter_by(id=file_id).first() if not file: abort(404) if ProcessRepository.is_running(file.id): ProcessRepository.cancel_process(file.id) else: # clear progress, cancel_process() also does this file.clear() # set status of file to "queued" file.status = StatusMap.queued.value db.session.commit() # check if it's necessary to start new processes ProcessRepository.check_and_start_processes() return ""
def test_file_done(): with patch("os.rename") as m_rename: with patch("os.remove") as m_remove: # add fake_file to database in order to test renaming filename = "ThisIsAmazing.11.12.10.PyEncode.Is.The.Best.SEPARATOR.1080p.MP4-ABC.mp4" path = "/this/path/is/fake" fake_file = File(id=1, filename=path + os.sep + filename) fake_file.output_filename = filename + ".pyencode" db.session.add(fake_file) db.session.commit() # set options we want to test config["encoding"]["delete_old_file"] = "True" config["encoding"]["rename_enabled"] = "True" config["encoding"][ "rename_search"] = r"(?P<head>.+)(?P<resolution>1080|720|2160)(?:p|P)\.(?P<tail>.+)\.(?P<extension>\w{3})" config["encoding"]["rename_replace"] = r"\g<head>720p.\g<tail>-selfmade.mkv" expected_filename = "ThisIsAmazing.11.12.10.PyEncode.Is.The.Best.SEPARATOR.720p.MP4-ABC-selfmade.mkv" ProcessRepository.processes[fake_file.id] = None ProcessRepository.file_done(fake_file) m_remove.assert_called_once_with(fake_file.filename) m_rename.assert_called_once_with(path + os.sep + fake_file.output_filename, path + os.sep + expected_filename) return
def test_file_done(): with patch("os.rename") as m_rename: with patch("os.remove") as m_remove: # add fake_file to database in order to test renaming filename = "ThisIsAmazing.11.12.10.PyEncode.Is.The.Best.SEPARATOR.1080p.MP4-ABC.mp4" path = "/this/path/is/fake" fake_file = File(id=1, filename=path + os.sep + filename) fake_file.output_filename = filename + ".pyencode" db.session.add(fake_file) db.session.commit() # set options we want to test config["encoding"]["delete_old_file"] = "True" config["encoding"]["rename_enabled"] = "True" config["encoding"][ "rename_search"] = r"(?P<head>.+)(?P<resolution>1080|720|2160)(?:p|P)\.(?P<tail>.+)\.(?P<extension>\w{3})" config["encoding"][ "rename_replace"] = r"\g<head>720p.\g<tail>-selfmade.mkv" expected_filename = "ThisIsAmazing.11.12.10.PyEncode.Is.The.Best.SEPARATOR.720p.MP4-ABC-selfmade.mkv" ProcessRepository.processes[fake_file.id] = None ProcessRepository.file_done(fake_file) m_remove.assert_called_once_with(fake_file.filename) m_rename.assert_called_once_with( path + os.sep + fake_file.output_filename, path + os.sep + expected_filename) return
def restart_package(): """ restart a Package :return: "" """ package_id = request.form["package_id"] package = Package.query.filter_by(id=package_id).first() if not package: abort(404) # cancel all currently running processes that belong to this package for file in package.files: if ProcessRepository.is_running(file.id): ProcessRepository.cancel_process(file.id) else: # clear progress, cancel_process() also does this file.clear() # set status of each file to "queued" file.status = StatusMap.queued.value db.session.commit() # check if it's necessary to start new processes ProcessRepository.check_and_start_processes() return ""
def delete_package(): """ delete a Package :return: "" """ package_id = request.form["package_id"] package = Package.query.filter_by(id=package_id).first() if not package: abort(404) # cancel all currently running processes that belong to this package for file in package.files: if ProcessRepository.is_running(file.id): ProcessRepository.cancel_process(file.id) # mark this file to be deleted (even though SQLAlchemy handles this already) db.session.delete(file) db.session.delete(package) db.session.commit() # check if it's necessary to start new processes ProcessRepository.check_and_start_processes() return ""
def toggle_encoding_active(): """ toggle the current encoding active status (from either True to False and vice-versa) :return: "" """ ProcessRepository.set_encoding_active(not ProcessRepository.encoding_active) return ""
def cancel_processes(): """ cancel all currently running Processes and check for new processes :return: "" """ ProcessRepository.cancel_all_processes() # after cancelling check if it's necessary to start new processes ProcessRepository.check_and_start_processes() return ""
def run(self): """ run the encoding """ # probe file first frame_count = self.ffmpeg_probe_frame_count() if frame_count == -1: app.logger.debug("Probing of " + self.file.filename + " failed - aborting...") ProcessRepository.file_failed(self.file) return # app.logger.debug("Probing of " + file.filename + " successful.. frame count: " + str(frame_count)) split_path = os.path.split(self.file.filename) path = split_path[0] original_filename = split_path[1] filename_noext = os.path.split( os.path.splitext(original_filename)[0])[1] # form output filename and store it in self.file for later use self.file.output_filename = filename_noext + ".pyencode" cmd = ["ffmpeg"] cmd.extend(["-i", self.file.filename]) # add parameters from config cmd.extend(shlex.split(config.get("encoding", "parameters"))) cmd.extend(["-y", path + os.sep + self.file.output_filename]) app.logger.debug("Starting encoding of " + self.file.filename + " with %s" % " ".join(cmd)) for info in self.run_ffmpeg(cmd, frame_count): if info["return_code"] != -1: app.logger.debug( "Error occured while running ffmpeg. Last lines of output: " ) app.logger.debug("\n".join(info["last_lines"])) ProcessRepository.file_failed(self.file) return # store information in database # convert kB to bytes info["ffmpeg_size"] *= 1024 # we don't need the return_code anymore (and don't want to store it) info.pop("return_code") # update file in DB File.query.filter_by(id=self.file.id).update(info) db.session.commit() # update self.file for k in info: setattr(self.file, k, info[k]) # tell ProcessRepository there's some progress going on ProcessRepository.file_progress(self.file) if self.active: ProcessRepository.file_done(self.file)
def test_check_and_start_processes(self, mock_probe, mock_run): def mocked_run_ffmpeg(cmd, frame_count): yield { "return_code": -1, "ffmpeg_eta": 1, "ffmpeg_progress": 0, "ffmpeg_bitrate": 0, "ffmpeg_time": 0, "ffmpeg_size": 0, "ffmpeg_fps": 0 } # mock run_ffmpeg() mock_run.side_effect = mocked_run_ffmpeg # add Package package = Package(queue=True) db.session.add(package) # add File file = File(status=StatusMap.queued.value, filename="dummy.mkv", size=100 * 1024) db.session.add(file) package.files.append(file) db.session.commit() # set parallel processes to 1 config["general"]["parallel_processes"] = "1" # start processing with patch("os.rename"): with patch("os.remove"): ProcessRepository.set_encoding_active(True) self.assertTrue(mock_run.called) self.assertTrue(mock_run.call_count == 1) received = self.socketio_client.get_received() # there should have gotten one file_started and file_done event triggered self.assertEqual( len([x for x in received if x["name"] == "file_started"]), 1) self.assertEqual( len([x for x in received if x["name"] == "file_done"]), 1) # the status should be "finished" now # self.assertEqual(File.query.filter_by(id=file.id).first().status, StatusMap.finished.value) # print(File.query.filter_by(id=file.id).first().status) return
def test_set_encoding_active(self): # encoding_active should be False when creating app self.assertFalse(ProcessRepository.encoding_active) ProcessRepository.set_encoding_active(True) # ... and should be True now self.assertTrue(ProcessRepository.encoding_active) # test we received active_changed with the correct data received = self.socketio_client.get_received() self.assertEqual(len(received), 1) self.assertEqual(received[0]["name"], "active_changed") self.assertEqual(received[0]["args"], [{"active": True}]) return
def run(self): """ run the encoding """ # probe file first frame_count = self.ffmpeg_probe_frame_count() if frame_count == -1: app.logger.debug("Probing of " + self.file.filename + " failed - aborting...") ProcessRepository.file_failed(self.file) return # app.logger.debug("Probing of " + file.filename + " successful.. frame count: " + str(frame_count)) split_path = os.path.split(self.file.filename) path = split_path[0] original_filename = split_path[1] filename_noext = os.path.split(os.path.splitext(original_filename)[0])[1] # form output filename and store it in self.file for later use self.file.output_filename = filename_noext + ".pyencode" cmd = ["ffmpeg"] cmd.extend(["-i", self.file.filename]) # add parameters from config cmd.extend(shlex.split(config.get("encoding", "parameters"))) cmd.extend(["-y", path + os.sep + self.file.output_filename]) app.logger.debug("Starting encoding of " + self.file.filename + " with %s" % " ".join(cmd)) for info in self.run_ffmpeg(cmd, frame_count): if info["return_code"] != -1: app.logger.debug("Error occured while running ffmpeg. Last lines of output: ") app.logger.debug("\n".join(info["last_lines"])) ProcessRepository.file_failed(self.file) return # store information in database # convert kB to bytes info["ffmpeg_size"] *= 1024 # we don't need the return_code anymore (and don't want to store it) info.pop("return_code") # update file in DB File.query.filter_by(id=self.file.id).update(info) db.session.commit() # update self.file for k in info: setattr(self.file, k, info[k]) # tell ProcessRepository there's some progress going on ProcessRepository.file_progress(self.file) if self.active: ProcessRepository.file_done(self.file)
def add_package(): """ add a new Package :return: "1" """ i = 0 paths = json.loads(request.form["paths"]) for path in paths: paths[i] = html.unescape(path) path = paths[i] if not os.path.isfile(path): print(path + " does not exist..") return "not_existing" i += 1 last_package = Package.query.filter_by(queue=True).order_by(Package.position.desc()).limit(1).first() if not last_package: position = 0 else: position = last_package.position + 1 package = Package(user=current_user, title=request.form["title"], queue=(request.form["queue"] == "1"), position=position) db.session.add(package) file_pos = 0 for path in paths: file = File(filename=path, size=os.path.getsize(path), status=StatusMap.queued.value, position=file_pos) package.files.append(file) file_pos += 1 db.session.commit() # after adding, see if we have to start processes ProcessRepository.check_and_start_processes() return "1"
def delete_file(): """ delete a File :return: "" """ file_id = request.form["file_id"] file = File.query.filter_by(id=file_id).first() if not file: abort(404) # cancel the currently running processes that if ProcessRepository.is_running(file.id): ProcessRepository.cancel_process(file.id) db.session.delete(file) db.session.commit() # check if it's necessary to start new processes ProcessRepository.check_and_start_processes() return ""
def test_check_and_start_processes(self, mock_probe, mock_run): def mocked_run_ffmpeg(cmd, frame_count): yield {"return_code": -1, "ffmpeg_eta": 1, "ffmpeg_progress": 0, "ffmpeg_bitrate": 0, "ffmpeg_time": 0, "ffmpeg_size": 0, "ffmpeg_fps": 0} # mock run_ffmpeg() mock_run.side_effect = mocked_run_ffmpeg # add Package package = Package(queue=True) db.session.add(package) # add File file = File(status=StatusMap.queued.value, filename="dummy.mkv", size=100 * 1024) db.session.add(file) package.files.append(file) db.session.commit() # set parallel processes to 1 config["general"]["parallel_processes"] = "1" # start processing with patch("os.rename"): with patch("os.remove"): ProcessRepository.set_encoding_active(True) self.assertTrue(mock_run.called) self.assertTrue(mock_run.call_count == 1) received = self.socketio_client.get_received() # there should have gotten one file_started and file_done event triggered self.assertEqual(len([x for x in received if x["name"] == "file_started"]), 1) self.assertEqual(len([x for x in received if x["name"] == "file_done"]), 1) # the status should be "finished" now # self.assertEqual(File.query.filter_by(id=file.id).first().status, StatusMap.finished.value) # print(File.query.filter_by(id=file.id).first().status) return
def fail_on_exit(): """ on exit cancel all processes """ ProcessRepository.cancel_all_processes()
def setUp(self): super().setUp() self.socketio_client = socketio.test_client(app) ProcessRepository.set_encoding_active(False) self.socketio_client.queue.clear()