Commit a66e6c58401047a1fbe43f2014b0af72a8e8ad95
1 parent
104cb330
Exists in
master
Adiciona módulo de verificação do arquivo .blend e módulo de geração do vídeo
Showing
6 changed files
with
237 additions
and
25 deletions
Show diff stats
.gitignore
... | ... | @@ -0,0 +1,32 @@ |
1 | +# -*- coding: UTF-8 -*- | |
2 | + | |
3 | +import bpy | |
4 | +import sys | |
5 | +import json | |
6 | + | |
7 | +def main(): | |
8 | + if (len(sys.argv) == 8): | |
9 | + json_obj = json.loads(sys.argv[7]) | |
10 | + try: | |
11 | + action_name = json_obj["action_name"] | |
12 | + action_fake_is_valid = json_obj["action_fake_is_valid"] | |
13 | + min_frame_count = json_obj["min_frame_count"] | |
14 | + except: | |
15 | + sys.exit(4) | |
16 | + action = None | |
17 | + for i in bpy.data.actions: | |
18 | + if (i.name.upper() == action_name): | |
19 | + action = i | |
20 | + break | |
21 | + if (action == None): | |
22 | + sys.exit(5) | |
23 | + if not (action_fake_is_valid): | |
24 | + if (action.use_fake_user): | |
25 | + sys.exit(6) | |
26 | + if ((bpy.context.scene.frame_end - bpy.context.scene.frame_start) < min_frame_count): | |
27 | + sys.exit(7) | |
28 | + else: | |
29 | + sys.exit(8) | |
30 | + | |
31 | +if __name__ == "__main__": | |
32 | + main() | ... | ... |
... | ... | @@ -0,0 +1,76 @@ |
1 | +# -*- coding: UTF-8 -*- | |
2 | + | |
3 | +import bpy | |
4 | +import json | |
5 | +import os | |
6 | +import sys | |
7 | +import shutil | |
8 | + | |
9 | +def configure_output(): | |
10 | + bpy.context.scene.frame_start = 0 | |
11 | + bpy.context.scene.frame_current = bpy.context.scene.frame_start | |
12 | + bpy.context.scene.frame_end = bpy.context.scene.frame_start | |
13 | + bpy.context.scene.render.resolution_x = 640 | |
14 | + bpy.context.scene.render.resolution_y = 480 | |
15 | + bpy.context.scene.render.resolution_percentage = 100 | |
16 | + bpy.context.scene.render.image_settings.file_format = 'H264' | |
17 | + bpy.context.scene.render.ffmpeg.format = 'MPEG4' | |
18 | + bpy.context.scene.render.ffmpeg.codec = 'H264' | |
19 | + bpy.context.scene.render.use_shadows = False | |
20 | + bpy.context.scene.render.use_raytrace = False | |
21 | + bpy.context.scene.render.use_envmaps = False | |
22 | + bpy.context.scene.render.use_motion_blur = False | |
23 | + bpy.context.scene.render.use_shadows = False | |
24 | + return | |
25 | + | |
26 | +def file_rename(file_full_path): | |
27 | + file_path = os.path.dirname(os.path.abspath(file_full_path)) | |
28 | + filename = os.path.basename(os.path.splitext(file_full_path)[0]) | |
29 | + extension = os.path.splitext(file_full_path)[1] | |
30 | + filename_reversed = "" | |
31 | + valid_char = False | |
32 | + for char in reversed(filename): | |
33 | + if (valid_char == True): | |
34 | + filename_reversed += char | |
35 | + if (char == "_"): | |
36 | + valid_char = True | |
37 | + try: | |
38 | + filename_reversed = filename_reversed[::-1] | |
39 | + new_filename = os.path.join(file_path, "%s%s" % (filename_reversed, extension)) | |
40 | + shutil.move(file_full_path, new_filename) | |
41 | + return new_filename | |
42 | + except Exception: | |
43 | + return "" | |
44 | + | |
45 | +def render_video(video_output = ""): | |
46 | + getcwd = os.path.dirname(os.path.abspath(__file__)) | |
47 | + base_path = os.path.join(getcwd, video_output) | |
48 | + bpy.context.scene.render.filepath = base_path + "_" | |
49 | + try: | |
50 | + bpy.ops.render.render(animation = True, write_still = False, layer = "", scene = "") | |
51 | + return str("%s%0.4i-%0.4i.mp4" % (bpy.context.scene.render.filepath, bpy.context.scene.frame_start, bpy.context.scene.frame_end)) | |
52 | + except: | |
53 | + return "" | |
54 | + | |
55 | +def main(): | |
56 | + if (len(sys.argv) == 8): | |
57 | + json_obj = json.loads(sys.argv[7]) | |
58 | + try: | |
59 | + video_output = json_obj["video_output"] | |
60 | + convert_to_webm = json_obj["convert_to_webm"] | |
61 | + except: | |
62 | + sys.exit(3) | |
63 | + try: | |
64 | + configure_output() | |
65 | + renamed_video = file_rename(render_video(video_output)) | |
66 | + base_path = os.path.splitext(renamed_video)[0] | |
67 | + if (convert_to_webm): | |
68 | + subprocess.call(["avconv", "-loglevel", "0", "-y", "-i", renamed_video, "-r", "24", "-vcodec", "libvpx", base_path + ".webm"]) | |
69 | + subprocess.call(["rm", renamed_video]) | |
70 | + except: | |
71 | + sys.exit(4) | |
72 | + else: | |
73 | + sys.exit(5) | |
74 | + | |
75 | +if __name__ == "__main__": | |
76 | + main() | ... | ... |
... | ... | @@ -0,0 +1,91 @@ |
1 | +# -*- coding: UTF-8 -*- | |
2 | + | |
3 | +import copy | |
4 | +import json | |
5 | +import math | |
6 | +import os | |
7 | +import sys | |
8 | +import subprocess | |
9 | + | |
10 | +getcwd = os.path.dirname(os.path.abspath(__file__)) | |
11 | +bpy_script_action = os.path.join(getcwd, "bpy_checkout.py") | |
12 | +bpy_script_render = os.path.join(getcwd, "bpy_render.py") | |
13 | + | |
14 | +def file_exists(file_path): | |
15 | + if ((os.path.isfile(file_path) == 1) and (os.path.exists(file_path) == 1)): | |
16 | + return True | |
17 | + else: | |
18 | + return False | |
19 | + | |
20 | +def check_action(blend_file = "", action_name = "", action_fake_is_valid = True, min_frame_count = 10, hide_output = True): | |
21 | + if (file_exists(blend_file)): | |
22 | + if not (isinstance(blend_file, str) and isinstance(action_name, str)): | |
23 | + return 1 | |
24 | + if not (isinstance(action_fake_is_valid, bool) and isinstance(min_frame_count, int)): | |
25 | + return 1 | |
26 | + if (action_name == ""): | |
27 | + action_name = os.path.splitext(blend_file)[0] | |
28 | + try: | |
29 | + json_object = json.JSONEncoder().encode( | |
30 | + { | |
31 | + "action_name": action_name.upper(), | |
32 | + "action_fake_is_valid": action_fake_is_valid, | |
33 | + "min_frame_count": min_frame_count | |
34 | + } | |
35 | + ) | |
36 | + if (hide_output): | |
37 | + dev_null = open(os.devnull, 'w') | |
38 | + return subprocess.call(['blender', '-b', blend_file, '-noaudio', '-P', bpy_script_action, "--", json_object], stdout = dev_null, stderr = dev_null) | |
39 | + else: | |
40 | + return subprocess.call(['blender', '-b', blend_file, '-noaudio', '-P', bpy_script_action, "--", json_object]) | |
41 | + except: | |
42 | + return 2 | |
43 | + else: | |
44 | + return 3 | |
45 | + | |
46 | +def render_video(blend_file = "", video_output = "", convert_to_webm = True, hide_output = False): | |
47 | + if (file_exists(blend_file)): | |
48 | + if not (isinstance(blend_file, str) and isinstance(video_output, str)): | |
49 | + return 1 | |
50 | + try: | |
51 | + json_object = json.JSONEncoder().encode( | |
52 | + { | |
53 | + "video_output": video_output.upper(), | |
54 | + "convert_to_webm": convert_to_webm | |
55 | + } | |
56 | + ) | |
57 | + if (hide_output): | |
58 | + dev_null = open(os.devnull, 'w') | |
59 | + return subprocess.call(['blender', '-b', blend_file, '-noaudio', '-P', bpy_script_render, "--", json_object], stdout = dev_null, stderr = dev_null) | |
60 | + else: | |
61 | + return subprocess.call(['blender', '-b', blend_file, '-noaudio', '-P', bpy_script_render, "--", json_object]) | |
62 | + except: | |
63 | + return 2 | |
64 | + else: | |
65 | + return 3 | |
66 | + | |
67 | +def main(): | |
68 | + print("check_action return:", check_action("casa.blend")) | |
69 | + # return codes | |
70 | + # 0: [OK] Blend file and Action Name exists | |
71 | + # 1: [ERROR] Args to check_action no match types | |
72 | + # 2: [ERROR] Subprocess interrupt | |
73 | + # 3: [ERROR] Blend file not exists | |
74 | + # 4: [ERROR] JSON Key no match | |
75 | + # 5: [ERROR] Action in blend file no exists | |
76 | + # 6: [ERROR] Action is fake user | |
77 | + # 7: [ERROR] Timeline Frame Count is less than 10 | |
78 | + # 8: [ERROR] Args count no match | |
79 | + | |
80 | + print("render_video return:", render_video("casa.blend", "casa")) | |
81 | + # return codes | |
82 | + # 0: [OK] Video.mp4 generated | |
83 | + # 1: [ERROR] Args to check_action no match types | |
84 | + # 2: [ERROR] Subprocess interrupt | |
85 | + # 3: [ERROR] JSON Key no match | |
86 | + # 4: [ERROR] Except in process | |
87 | + # 5: [ERROR] Args count no match | |
88 | + return | |
89 | + | |
90 | +if __name__ == "__main__": | |
91 | + main() | ... | ... |
corretor.py
... | ... | @@ -3,46 +3,47 @@ from werkzeug import secure_filename |
3 | 3 | import pbclient |
4 | 4 | import os |
5 | 5 | import pyutil |
6 | +import checkout | |
6 | 7 | |
7 | 8 | class Corretor: |
8 | - | |
9 | + | |
9 | 10 | def __init__(self, configuration, template_env): |
10 | 11 | self.config = configuration |
11 | 12 | self.env = template_env |
12 | 13 | self.__setup_pb_client() |
13 | 14 | self.__setup_upload_folder() |
14 | - | |
15 | + | |
15 | 16 | def __setup_pb_client(self): |
16 | - pbclient.set('endpoint', self.config['PYBOSSA_ENDPOINT']) | |
17 | + pbclient.set('endpoint', self.config['PYBOSSA_ENDPOINT']) | |
17 | 18 | pbclient.set('api_key', self.config['PYBOSSA_API_KEY']) |
18 | - | |
19 | + | |
19 | 20 | def __setup_upload_folder(self): |
20 | 21 | upload_folder = self.config['UPLOAD_FOLDER'] |
21 | 22 | if not os.path.exists(upload_folder): |
22 | 23 | os.makedirs(upload_folder) |
23 | - | |
24 | + | |
24 | 25 | def __find_project(self, app_short_name): |
25 | 26 | projects = pbclient.find_project(short_name=app_short_name) |
26 | 27 | return projects[0] if len(projects) > 0 else None |
27 | - | |
28 | + | |
28 | 29 | def __setup_project(self, project): |
29 | 30 | self.__create_tasks(project) |
30 | 31 | self.__update_project_info(project) |
31 | - | |
32 | + | |
32 | 33 | def __create_tasks(self, project): |
33 | 34 | test_signs = ["ENSINADO", "ENTANTO", "ENTENDIDO"] |
34 | 35 | for sign in test_signs: |
35 | 36 | task = dict(sign_name=sign, submission_date=pyutil.get_date_now()) |
36 | 37 | pbclient.create_task(project.id, task) |
37 | - | |
38 | - def __update_project_info(self, project): | |
38 | + | |
39 | + def __update_project_info(self, project): | |
39 | 40 | template = self.env.get_template('template.html') |
40 | 41 | project.info['task_presenter'] = template.render(server=self.config['HOST_ENDPOINT']) |
41 | 42 | project.info['thumbnail'] = self.config['HOST_ENDPOINT'] + "/img/thumbnail.png" |
42 | 43 | project.info['sched'] = "incremental" |
43 | 44 | project.allow_anonymous_contributors = False |
44 | 45 | pbclient.update_project(project) |
45 | - | |
46 | + | |
46 | 47 | def create_project(self): |
47 | 48 | app_short_name = self.config['PYBOSSA_APP_SHORT_NAME'] |
48 | 49 | project = self.__find_project(app_short_name) |
... | ... | @@ -54,23 +55,23 @@ class Corretor: |
54 | 55 | if (project): |
55 | 56 | self.__setup_project(project) |
56 | 57 | result_msg = "The project " + app_short_name + " was created." |
57 | - else: | |
58 | + else: | |
58 | 59 | result_msg = "The project " + app_short_name + " couldn't be created. Check the server log for details." |
59 | 60 | pyutil.log(result_msg) |
60 | - return result_msg | |
61 | + return result_msg | |
61 | 62 | |
62 | - def update_project(self): | |
63 | + def update_project(self): | |
63 | 64 | app_short_name = self.config['PYBOSSA_APP_SHORT_NAME'] |
64 | 65 | project = self.__find_project(app_short_name) |
65 | 66 | self.__update_project_info(project) |
66 | 67 | result_msg = "The project " + app_short_name + " was updated." |
67 | 68 | pyutil.log(result_msg) |
68 | 69 | return result_msg |
69 | - | |
70 | + | |
70 | 71 | def __allowed_file(self, filename): |
71 | 72 | allowed_extensions = set(['blend']) |
72 | 73 | return '.' in filename and filename.rsplit('.', 1)[1] in allowed_extensions |
73 | - | |
74 | + | |
74 | 75 | def upload_file(self): |
75 | 76 | upload_session_id = request.form['upload_session_id'] |
76 | 77 | sign_name = request.form['sign_name'] |
... | ... | @@ -88,10 +89,13 @@ class Corretor: |
88 | 89 | os.makedirs(upload_dir) |
89 | 90 | uploaded_file = os.path.join(upload_dir, filename) |
90 | 91 | file.save(uploaded_file) |
91 | - renamed_file = os.path.join(upload_dir, secure_filename(sign_name + "_CORRIGIDO.blend")) | |
92 | + renamed_file = os.path.join(upload_dir, secure_filename(sign_name + ".blend")) | |
92 | 93 | os.rename(uploaded_file, renamed_file) |
93 | - # validar o .blend | |
94 | - code = 200 | |
95 | - result_msg = "File " + filename + " was uploaded." | |
94 | + if (checkout.check_action(renamed_file, sign_name) == 0): | |
95 | + result_msg = "File " + filename + " was uploaded." | |
96 | + code = 200 | |
97 | + else: | |
98 | + result_msg = "File " + filename + " has not expected structure of blend file." | |
99 | + code = 400 | |
96 | 100 | pyutil.log(result_msg) |
97 | 101 | return make_response(result_msg, code) | ... | ... |
view/template.html
... | ... | @@ -147,13 +147,20 @@ |
147 | 147 | $("#finish-button").addClass("enabled-button"); |
148 | 148 | $("#finish-button").off("click").on("click", function() { |
149 | 149 | // endpoint - /finish_task |
150 | - // enviar mensagem via POST para renderizar video - upload/<session_hash>/<task.info.sign_name>_CORRIGIDO.blend | |
150 | + // enviar mensagem via POST para renderizar video - upload/<session_hash>/<task.info.sign_name>.blend | |
151 | 151 | enableLoading(); |
152 | - setTimeout(function() { | |
153 | - disableLoading(); | |
154 | - status = status_dict[$("#finish-button").text().trim()]; | |
155 | - saveAnswer(task, deferred, status); | |
156 | - }, 3000); | |
152 | + $.post("{{ server }}/finish_task", | |
153 | + { | |
154 | + "upload_session_id": upload_session_id, | |
155 | + "sign_name": task.info.sign_name | |
156 | + }, | |
157 | + function(response) { | |
158 | + console.log(response); | |
159 | + disableLoading(); | |
160 | + status = status_dict[$("#finish-button").text().trim()]; | |
161 | + saveAnswer(task, deferred, status); | |
162 | + } | |
163 | + ); | |
157 | 164 | }); |
158 | 165 | } |
159 | 166 | ... | ... |