diff --git a/.gitignore b/.gitignore index 3103336..cd2da12 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ !.gitignore !.gitempty *.log +settings_local.py video/* tmp/ +uploads/ *.pyc diff --git a/bpy_checkout.py b/bpy_checkout.py new file mode 100644 index 0000000..d663d4b --- /dev/null +++ b/bpy_checkout.py @@ -0,0 +1,32 @@ +# -*- coding: UTF-8 -*- + +import bpy +import sys +import json + +def main(): + if (len(sys.argv) == 8): + json_obj = json.loads(sys.argv[7]) + try: + action_name = json_obj["action_name"] + action_fake_is_valid = json_obj["action_fake_is_valid"] + min_frame_count = json_obj["min_frame_count"] + except: + sys.exit(4) + action = None + for i in bpy.data.actions: + if (i.name.upper() == action_name): + action = i + break + if (action == None): + sys.exit(5) + if not (action_fake_is_valid): + if (action.use_fake_user): + sys.exit(6) + if ((bpy.context.scene.frame_end - bpy.context.scene.frame_start) < min_frame_count): + sys.exit(7) + else: + sys.exit(8) + +if __name__ == "__main__": + main() diff --git a/bpy_render.py b/bpy_render.py new file mode 100644 index 0000000..e34496f --- /dev/null +++ b/bpy_render.py @@ -0,0 +1,76 @@ +# -*- coding: UTF-8 -*- + +import bpy +import json +import os +import sys +import shutil + +def configure_output(): + bpy.context.scene.frame_start = 0 + bpy.context.scene.frame_current = bpy.context.scene.frame_start + bpy.context.scene.frame_end = bpy.context.scene.frame_start + bpy.context.scene.render.resolution_x = 640 + bpy.context.scene.render.resolution_y = 480 + bpy.context.scene.render.resolution_percentage = 100 + bpy.context.scene.render.image_settings.file_format = 'H264' + bpy.context.scene.render.ffmpeg.format = 'MPEG4' + bpy.context.scene.render.ffmpeg.codec = 'H264' + bpy.context.scene.render.use_shadows = False + bpy.context.scene.render.use_raytrace = False + bpy.context.scene.render.use_envmaps = False + bpy.context.scene.render.use_motion_blur = False + bpy.context.scene.render.use_shadows = False + return + +def file_rename(file_full_path): + file_path = os.path.dirname(os.path.abspath(file_full_path)) + filename = os.path.basename(os.path.splitext(file_full_path)[0]) + extension = os.path.splitext(file_full_path)[1] + filename_reversed = "" + valid_char = False + for char in reversed(filename): + if (valid_char == True): + filename_reversed += char + if (char == "_"): + valid_char = True + try: + filename_reversed = filename_reversed[::-1] + new_filename = os.path.join(file_path, "%s%s" % (filename_reversed, extension)) + shutil.move(file_full_path, new_filename) + return new_filename + except Exception: + return "" + +def render_video(video_output = ""): + getcwd = os.path.dirname(os.path.abspath(__file__)) + base_path = os.path.join(getcwd, video_output) + bpy.context.scene.render.filepath = base_path + "_" + try: + bpy.ops.render.render(animation = True, write_still = False, layer = "", scene = "") + return str("%s%0.4i-%0.4i.mp4" % (bpy.context.scene.render.filepath, bpy.context.scene.frame_start, bpy.context.scene.frame_end)) + except: + return "" + +def main(): + if (len(sys.argv) == 8): + json_obj = json.loads(sys.argv[7]) + try: + video_output = json_obj["video_output"] + convert_to_webm = json_obj["convert_to_webm"] + except: + sys.exit(3) + try: + configure_output() + renamed_video = file_rename(render_video(video_output)) + base_path = os.path.splitext(renamed_video)[0] + if (convert_to_webm): + subprocess.call(["avconv", "-loglevel", "0", "-y", "-i", renamed_video, "-r", "24", "-vcodec", "libvpx", base_path + ".webm"]) + subprocess.call(["rm", renamed_video]) + except: + sys.exit(4) + else: + sys.exit(5) + +if __name__ == "__main__": + main() diff --git a/checkout.py b/checkout.py new file mode 100644 index 0000000..c04f8db --- /dev/null +++ b/checkout.py @@ -0,0 +1,91 @@ +# -*- coding: UTF-8 -*- + +import copy +import json +import math +import os +import sys +import subprocess + +getcwd = os.path.dirname(os.path.abspath(__file__)) +bpy_script_action = os.path.join(getcwd, "bpy_checkout.py") +bpy_script_render = os.path.join(getcwd, "bpy_render.py") + +def file_exists(file_path): + if ((os.path.isfile(file_path) == 1) and (os.path.exists(file_path) == 1)): + return True + else: + return False + +def check_action(blend_file = "", action_name = "", action_fake_is_valid = True, min_frame_count = 10, hide_output = True): + if (file_exists(blend_file)): + if not (isinstance(blend_file, str) and isinstance(action_name, str)): + return 1 + if not (isinstance(action_fake_is_valid, bool) and isinstance(min_frame_count, int)): + return 1 + if (action_name == ""): + action_name = os.path.splitext(blend_file)[0] + try: + json_object = json.JSONEncoder().encode( + { + "action_name": action_name.upper(), + "action_fake_is_valid": action_fake_is_valid, + "min_frame_count": min_frame_count + } + ) + if (hide_output): + dev_null = open(os.devnull, 'w') + return subprocess.call(['blender', '-b', blend_file, '-noaudio', '-P', bpy_script_action, "--", json_object], stdout = dev_null, stderr = dev_null) + else: + return subprocess.call(['blender', '-b', blend_file, '-noaudio', '-P', bpy_script_action, "--", json_object]) + except: + return 2 + else: + return 3 + +def render_video(blend_file = "", video_output = "", convert_to_webm = True, hide_output = False): + if (file_exists(blend_file)): + if not (isinstance(blend_file, str) and isinstance(video_output, str)): + return 1 + try: + json_object = json.JSONEncoder().encode( + { + "video_output": video_output.upper(), + "convert_to_webm": convert_to_webm + } + ) + if (hide_output): + dev_null = open(os.devnull, 'w') + return subprocess.call(['blender', '-b', blend_file, '-noaudio', '-P', bpy_script_render, "--", json_object], stdout = dev_null, stderr = dev_null) + else: + return subprocess.call(['blender', '-b', blend_file, '-noaudio', '-P', bpy_script_render, "--", json_object]) + except: + return 2 + else: + return 3 + +def main(): + print("check_action return:", check_action("casa.blend")) + # return codes + # 0: [OK] Blend file and Action Name exists + # 1: [ERROR] Args to check_action no match types + # 2: [ERROR] Subprocess interrupt + # 3: [ERROR] Blend file not exists + # 4: [ERROR] JSON Key no match + # 5: [ERROR] Action in blend file no exists + # 6: [ERROR] Action is fake user + # 7: [ERROR] Timeline Frame Count is less than 10 + # 8: [ERROR] Args count no match + + print("render_video return:", render_video("casa.blend", "casa")) + # return codes + # 0: [OK] Video.mp4 generated + # 1: [ERROR] Args to check_action no match types + # 2: [ERROR] Subprocess interrupt + # 3: [ERROR] JSON Key no match + # 4: [ERROR] Except in process + # 5: [ERROR] Args count no match + return + +if __name__ == "__main__": + main() diff --git a/corretor.py b/corretor.py index a6e415b..497316e 100644 --- a/corretor.py +++ b/corretor.py @@ -3,46 +3,47 @@ from werkzeug import secure_filename import pbclient import os import pyutil +import checkout class Corretor: - + def __init__(self, configuration, template_env): self.config = configuration self.env = template_env self.__setup_pb_client() self.__setup_upload_folder() - + def __setup_pb_client(self): - pbclient.set('endpoint', self.config['PYBOSSA_ENDPOINT']) + pbclient.set('endpoint', self.config['PYBOSSA_ENDPOINT']) pbclient.set('api_key', self.config['PYBOSSA_API_KEY']) - + def __setup_upload_folder(self): upload_folder = self.config['UPLOAD_FOLDER'] if not os.path.exists(upload_folder): os.makedirs(upload_folder) - + def __find_project(self, app_short_name): projects = pbclient.find_project(short_name=app_short_name) return projects[0] if len(projects) > 0 else None - + def __setup_project(self, project): self.__create_tasks(project) self.__update_project_info(project) - + def __create_tasks(self, project): test_signs = ["ENSINADO", "ENTANTO", "ENTENDIDO"] for sign in test_signs: task = dict(sign_name=sign, submission_date=pyutil.get_date_now()) pbclient.create_task(project.id, task) - - def __update_project_info(self, project): + + def __update_project_info(self, project): template = self.env.get_template('template.html') project.info['task_presenter'] = template.render(server=self.config['HOST_ENDPOINT']) project.info['thumbnail'] = self.config['HOST_ENDPOINT'] + "/img/thumbnail.png" project.info['sched'] = "incremental" project.allow_anonymous_contributors = False pbclient.update_project(project) - + def create_project(self): app_short_name = self.config['PYBOSSA_APP_SHORT_NAME'] project = self.__find_project(app_short_name) @@ -54,23 +55,23 @@ class Corretor: if (project): self.__setup_project(project) result_msg = "The project " + app_short_name + " was created." - else: + else: result_msg = "The project " + app_short_name + " couldn't be created. Check the server log for details." pyutil.log(result_msg) - return result_msg + return result_msg - def update_project(self): + def update_project(self): app_short_name = self.config['PYBOSSA_APP_SHORT_NAME'] project = self.__find_project(app_short_name) self.__update_project_info(project) result_msg = "The project " + app_short_name + " was updated." pyutil.log(result_msg) return result_msg - + def __allowed_file(self, filename): allowed_extensions = set(['blend']) return '.' in filename and filename.rsplit('.', 1)[1] in allowed_extensions - + def upload_file(self): upload_session_id = request.form['upload_session_id'] sign_name = request.form['sign_name'] @@ -88,10 +89,13 @@ class Corretor: os.makedirs(upload_dir) uploaded_file = os.path.join(upload_dir, filename) file.save(uploaded_file) - renamed_file = os.path.join(upload_dir, secure_filename(sign_name + "_CORRIGIDO.blend")) + renamed_file = os.path.join(upload_dir, secure_filename(sign_name + ".blend")) os.rename(uploaded_file, renamed_file) - # validar o .blend - code = 200 - result_msg = "File " + filename + " was uploaded." + if (checkout.check_action(renamed_file, sign_name) == 0): + result_msg = "File " + filename + " was uploaded." + code = 200 + else: + result_msg = "File " + filename + " has not expected structure of blend file." + code = 400 pyutil.log(result_msg) return make_response(result_msg, code) diff --git a/view/template.html b/view/template.html index 81fba54..6b6c22e 100755 --- a/view/template.html +++ b/view/template.html @@ -147,13 +147,20 @@ $("#finish-button").addClass("enabled-button"); $("#finish-button").off("click").on("click", function() { // endpoint - /finish_task - // enviar mensagem via POST para renderizar video - upload//_CORRIGIDO.blend + // enviar mensagem via POST para renderizar video - upload//.blend enableLoading(); - setTimeout(function() { - disableLoading(); - status = status_dict[$("#finish-button").text().trim()]; - saveAnswer(task, deferred, status); - }, 3000); + $.post("{{ server }}/finish_task", + { + "upload_session_id": upload_session_id, + "sign_name": task.info.sign_name + }, + function(response) { + console.log(response); + disableLoading(); + status = status_dict[$("#finish-button").text().trim()]; + saveAnswer(task, deferred, status); + } + ); }); } -- libgit2 0.21.2