def post(self, request): printer = request.auth pic = request.FILES['pic'] pic_id = int(timezone.now().timestamp()) internal_url, external_url = save_file_obj( 'raw/{}/{}.jpg'.format(printer.id, pic_id), pic, settings.PICS_CONTAINER) if not printer.is_printing(): redis.printer_pic_set(printer.id, {'img_url': external_url}, ex=STATUS_TTL_SECONDS) return command_response(printer) req = requests.get(settings.ML_API_HOST + '/p/', params={'img': internal_url}, headers=ml_api_auth_headers(), verify=False) req.raise_for_status() resp = req.json() detections = resp['detections'] prediction, _ = PrinterPrediction.objects.get_or_create( printer=printer) update_prediction_with_detections(prediction, detections) prediction.save() pic.file.seek( 0) # Reset file object pointer so that we can load it again tagged_img = io.BytesIO() detections_to_visualize = [ d for d in detections if d[1] > VISUALIZATION_THRESH ] overlay_detections(Image.open(pic), detections_to_visualize).save(tagged_img, "JPEG") tagged_img.seek(0) _, external_url = save_file_obj( 'tagged/{}/{}.jpg'.format(printer.id, pic_id), tagged_img, settings.PICS_CONTAINER) redis.printer_pic_set(printer.id, {'img_url': external_url}, ex=STATUS_TTL_SECONDS) prediction_json = serializers.serialize("json", [ prediction, ]) redis.printer_p_json_set(printer.id, pic_id, prediction_json, ex=60 * 60 * 24 * 2) if is_failing(prediction, printer.detective_sensitivity, escalating_factor=settings.ESCALATING_FACTOR): pause_if_needed(printer) elif is_failing(prediction, printer.detective_sensitivity, escalating_factor=1): alert_if_needed(printer) return command_response(printer)
def handle(self, *args, **options): timelapse_path = options['timelapse'] poster_path = options['poster'] p_json_path = options['p_json'] creator = options['creator'] tl_basename = path.basename(timelapse_path) post_basename = path.basename(poster_path) with open(timelapse_path, 'rb') as tl_file: _, tl_url = save_file_obj(tl_basename, tl_file, settings.TIMELAPSE_CONTAINER) with open(poster_path, 'rb') as poster_file: _, poster_url = save_file_obj(post_basename, poster_file, settings.TIMELAPSE_CONTAINER) with open(p_json_path, 'r') as f: frame_p = json.load(f) if len(PublicTimelapse.objects.filter(title=tl_basename)) == 1: PublicTimelapse.objects.filter(title=tl_basename).update( video_url=tl_url, poster_url=poster_url, creator_name=creator, frame_p=frame_p) else: PublicTimelapse.objects.create(title=tl_basename, video_url=tl_url, poster_url=poster_url, creator_name=creator, frame_p=frame_p)
def compile_timelapse(self, print_id): print = Print.objects.get(id=print_id) end_time = print.finished_at or print.cancelled_at if (end_time - print.started_at).total_seconds() < settings.TIMELAPSE_MINIMUM_SECONDS: print.delete() return to_dir = os.path.join(tempfile.gettempdir(), str(print.id)) shutil.rmtree(to_dir, ignore_errors=True) os.mkdir(to_dir) print_pics = filter_pics_by_start_end(list_file_obj('raw/{}/'.format(print.printer.id), settings.PICS_CONTAINER), print.started_at, end_time) print_pics.sort() if print_pics: local_pics = download_files(print_pics, to_dir) last_pic = local_pics[-1] mp4_filename = '{}.mp4'.format(print.id) output_mp4 = os.path.join(to_dir, mp4_filename) subprocess.run('ffmpeg -y -r 30 -pattern_type glob -i {}/*.jpg -c:v libx264 -pix_fmt yuv420p {}'.format(last_pic.parent, output_mp4).split(' '), check=True) shutil.copyfile(last_pic, os.path.join(to_dir, '{}.jpg'.format(print.id))) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj('private/{}'.format(mp4_filename), mp4_file, settings.TIMELAPSE_CONTAINER) with open(last_pic, 'rb') as poster_file: _, poster_file_url = save_file_obj('private/{}_poster.jpg'.format(print.id), poster_file, settings.TIMELAPSE_CONTAINER) print.video_url = mp4_file_url print.poster_url = poster_file_url print.save() # build tagged timelapse print_pics = filter_pics_by_start_end(list_file_obj('tagged/{}/'.format(print.printer.id), settings.PICS_CONTAINER), print.started_at, end_time) print_pics.sort() if print_pics: local_pics = download_files(print_pics, to_dir) mp4_filename = '{}_tagged.mp4'.format(print.id) output_mp4 = os.path.join(to_dir, mp4_filename) subprocess.run('ffmpeg -y -r 30 -pattern_type glob -i {}/*.jpg -c:v libx264 -pix_fmt yuv420p {}'.format(local_pics[0].parent, output_mp4).split(' '), check=True) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj('private/{}'.format(mp4_filename), mp4_file, settings.TIMELAPSE_CONTAINER) preidction_json = [] for print_pic_filename in print_pics: try: m = re.search('tagged/(\d+)/(\d+).jpg', print_pic_filename) p_json = json.loads(redis.printer_p_json_get(m[1], m[2])) except (json.decoder.JSONDecodeError, TypeError): # In case there is no corresponding json, the file will be empty and JSONDecodeError will be thrown p_json = [{}] preidction_json += p_json preidction_json_io = io.BytesIO() preidction_json_io.write(json.dumps(preidction_json).encode('UTF-8')) preidction_json_io.seek(0) _, json_url = save_file_obj('private/{}_p.json'.format(print.id), preidction_json_io, settings.TIMELAPSE_CONTAINER) print.tagged_video_url = mp4_file_url print.prediction_json_url = json_url print.save() shutil.rmtree(to_dir, ignore_errors=True)
def save_print_snapshot(_print, input_path, unrotated_jpg_path=None, rotated_jpg_path=None, to_container=settings.TIMELAPSE_CONTAINER, to_long_term_storage=True): if not input_path: return (None, None) to_dir = tempfile.mkdtemp() shutil.rmtree(to_dir, ignore_errors=True) os.mkdir(to_dir) unrotated_jpg = os.path.join(to_dir, 'unrotated.jpg') with open(unrotated_jpg, 'wb') as file_obj: retrieve_to_file_obj(input_path, file_obj, settings.PICS_CONTAINER, long_term_storage=False) (unrotated_jpg_url, rotated_jpg_url) = (None, None) if unrotated_jpg_path: with open(unrotated_jpg, 'rb') as file_obj: _, unrotated_jpg_url = save_file_obj(unrotated_jpg_path, file_obj, to_container, long_term_storage=to_long_term_storage) if rotated_jpg_path: ffmpeg_extra_options = orientation_to_ffmpeg_options(_print.printer.settings) rotated_jpg = os.path.join(to_dir, 'rotated.jpg') cmd = f'ffmpeg -y -i {unrotated_jpg} {ffmpeg_extra_options} {rotated_jpg}' subprocess.run(cmd.split(), check=True) with open(rotated_jpg, 'rb') as file_obj: _, rotated_jpg_url = save_file_obj(rotated_jpg_path, file_obj, to_container, long_term_storage=to_long_term_storage) shutil.rmtree(to_dir, ignore_errors=True) return (unrotated_jpg_url, rotated_jpg_url)
def detect_timelapse(self, print_id): MAX_FRAME_NUM = 750 _print = Print.objects.get(pk=print_id) tmp_dir = os.path.join(tempfile.gettempdir(), str(_print.id)) tl_path = download_files([f'private/{_print.id}.mp4'], tmp_dir, container=settings.TIMELAPSE_CONTAINER)[0] jpgs_dir = os.path.join(tmp_dir, 'jpgs') shutil.rmtree(jpgs_dir, ignore_errors=True) os.makedirs(jpgs_dir) tagged_jpgs_dir = os.path.join(tmp_dir, 'tagged_jpgs') shutil.rmtree(tagged_jpgs_dir, ignore_errors=True) os.makedirs(tagged_jpgs_dir) ffprobe_cmd = subprocess.run(f'ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 {tl_path}'.split(), stdout=subprocess.PIPE) frame_num = int(ffprobe_cmd.stdout.strip()) fps = 30*MAX_FRAME_NUM/frame_num if frame_num > MAX_FRAME_NUM else 30 subprocess.run(f'ffmpeg -i {tl_path} -vf fps={fps} -qscale:v 2 {jpgs_dir}/{print_id}-%5d.jpg'.split()) predictions = [] last_prediction = PrinterPrediction() jpg_filenames = sorted(os.listdir(jpgs_dir)) for jpg_path in jpg_filenames: jpg_abs_path = os.path.join(jpgs_dir, jpg_path) with open(jpg_abs_path, 'rb') as pic: internal_url, _ = save_file_obj(f'raw/uploaded_prints/{jpg_path}', pic, settings.PICS_CONTAINER) req = requests.get(settings.ML_API_HOST + '/p/', params={'img': internal_url}, headers=ml_api_auth_headers(), verify=False) req.raise_for_status() detections = req.json()['detections'] update_prediction_with_detections(last_prediction, detections) predictions.append(last_prediction) if is_failing(last_prediction, 1, escalating_factor=1): _print.alerted_at = timezone.now() last_prediction = copy.deepcopy(last_prediction) detections_to_visualize = [d for d in detections if d[1] > VISUALIZATION_THRESH] overlay_detections(Image.open(jpg_abs_path), detections_to_visualize).save(os.path.join(tagged_jpgs_dir, jpg_path), "JPEG") predictions_json = serializers.serialize("json", predictions) _, json_url = save_file_obj(f'private/{_print.id}_p.json', io.BytesIO(str.encode(predictions_json)), settings.TIMELAPSE_CONTAINER) mp4_filename = f'{_print.id}_tagged.mp4' output_mp4 = os.path.join(tmp_dir, mp4_filename) subprocess.run(f'ffmpeg -y -r 30 -pattern_type glob -i {tagged_jpgs_dir}/*.jpg -c:v libx264 -pix_fmt yuv420p {output_mp4}'.split(), check=True) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj(f'private/{mp4_filename}', mp4_file, settings.TIMELAPSE_CONTAINER) with open(os.path.join(jpgs_dir, jpg_filenames[-1]), 'rb') as poster_file: _, poster_file_url = save_file_obj(f'private/{_print.id}_poster.jpg', poster_file, settings.TIMELAPSE_CONTAINER) _print.tagged_video_url = mp4_file_url _print.prediction_json_url = json_url _print.poster_url = poster_file_url _print.save() shutil.rmtree(tmp_dir, ignore_errors=True) send_timelapse_detection_done_email(_print)
def upload_print(request): if request.method == 'POST': _, file_extension = os.path.splitext(request.FILES['file'].name) video_path = f'{str(timezone.now().timestamp())}{file_extension}' save_file_obj(f'uploaded/{video_path}', request.FILES['file'], settings.TIMELAPSE_CONTAINER) preprocess_timelapse.delay(request.user.id, video_path, request.FILES['file'].name) return JsonResponse(dict(status='Ok')) else: return render(request, 'upload_print.html')
def post(self, request): printer = request.auth printer.refresh_from_db() # Connection is keep-alive, which means printer object can be stale. pic = request.FILES['pic'] pic = cap_image_size(pic) pic_id = str(timezone.now().timestamp()) if not printer.current_print: # Some times pics come in when current_print is not set - maybe because printer status is out of sync between plugin and server? pic_path = f'{printer.id}/0/{pic_id}.jpg' else: pic_path = f'{printer.id}/{printer.current_print.id}/{pic_id}.jpg' internal_url, external_url = save_file_obj(f'raw/{pic_path}', pic, settings.PICS_CONTAINER, long_term_storage=False) if not printer.should_watch() or not printer.actively_printing(): cache.printer_pic_set(printer.id, {'img_url': external_url}, ex=IMG_URL_TTL_SECONDS) send_status_to_web(printer.id) return Response({'result': 'ok'}) req = requests.get(settings.ML_API_HOST + '/p/', params={'img': internal_url}, headers=ml_api_auth_headers(), verify=False) req.raise_for_status() resp = req.json() cache.print_num_predictions_incr(printer.current_print.id) detections = resp['detections'] prediction, _ = PrinterPrediction.objects.get_or_create(printer=printer) update_prediction_with_detections(prediction, detections) prediction.save() if prediction.current_p > settings.THRESHOLD_LOW * 0.2: # Select predictions high enough for focused feedback cache.print_high_prediction_add(printer.current_print.id, prediction.current_p, pic_id) pic.file.seek(0) # Reset file object pointer so that we can load it again tagged_img = io.BytesIO() detections_to_visualize = [d for d in detections if d[1] > VISUALIZATION_THRESH] overlay_detections(Image.open(pic), detections_to_visualize).save(tagged_img, "JPEG") tagged_img.seek(0) _, external_url = save_file_obj(f'tagged/{pic_path}', tagged_img, settings.PICS_CONTAINER, long_term_storage=False) cache.printer_pic_set(printer.id, {'img_url': external_url}, ex=IMG_URL_TTL_SECONDS) prediction_json = serializers.serialize("json", [prediction, ]) p_out = io.BytesIO() p_out.write(prediction_json.encode('UTF-8')) p_out.seek(0) save_file_obj(f'p/{printer.id}/{printer.current_print.id}/{pic_id}.json', p_out, settings.PICS_CONTAINER, long_term_storage=False) if is_failing(prediction, printer.detective_sensitivity, escalating_factor=settings.ESCALATING_FACTOR): pause_if_needed(printer) elif is_failing(prediction, printer.detective_sensitivity, escalating_factor=1): alert_if_needed(printer) send_status_to_web(printer.id) return Response({'result': 'ok'})
def post(self, request): printer = request.auth pic = request.FILES['pic'] pic_id = int(timezone.now().timestamp()) internal_url, external_url = save_file_obj( 'raw/{}/{}.jpg'.format(printer.id, pic_id), pic, settings.PICS_CONTAINER) if not printer.is_printing(): redis.printer_pic_set(printer.id, {'img_url': external_url}, ex=STATUS_TTL_SECONDS) return command_response(printer) req = requests.get(settings.ML_API_HOST + '/p/', params={'img': internal_url}, headers=ml_api_auth_headers(), verify=False) req.raise_for_status() resp = req.json() detections = resp['detections'] prediction, _ = PrinterPrediction.objects.get_or_create( printer=printer) update_prediction_with_detections(prediction, detections) prediction.save() pic.file.seek( 0) # Reset file object pointer so that we can load it again tagged_img = io.BytesIO() overlay_detections(Image.open(pic), detections).save(tagged_img, "JPEG") tagged_img.seek(0) _, external_url = save_file_obj( 'tagged/{}/{}.jpg'.format(printer.id, pic_id), tagged_img, settings.PICS_CONTAINER) redis.printer_pic_set(printer.id, {'img_url': external_url}, ex=STATUS_TTL_SECONDS) prediction_json = serializers.serialize("json", [ prediction, ]) p_out = io.BytesIO() p_out.write(prediction_json.encode('UTF-8')) p_out.seek(0) save_file_obj('p/{}/{}.json'.format(printer.id, pic_id), p_out, settings.PICS_CONTAINER, return_url=False) if is_failing(prediction, printer.detective_sensitivity): alert_if_needed(printer) return command_response(printer)
def upload_print(request): if request.method == 'POST': _, file_extension = os.path.splitext(request.FILES['file'].name) video_path = f'{str(timezone.now().timestamp())}{file_extension}' save_file_obj(f'uploaded/{video_path}', request.FILES['file'], settings.PICS_CONTAINER) celery_app.send_task('app_ent.tasks.credit_dh_for_contribution', args=[request.user.id, 1, 'Credit | Upload "{}"'.format(request.FILES['file'].name[:100])]) preprocess_timelapse.delay(request.user.id, video_path, request.FILES['file'].name) return JsonResponse(dict(status='Ok')) else: return render(request, 'upload_print.html')
def upload_print(request): if request.method == 'POST': _, file_extension = os.path.splitext(request.FILES['file'].name) video_path = f'{str(timezone.now().timestamp())}{file_extension}' save_file_obj(f'uploaded/{video_path}', request.FILES['file'], settings.PICS_CONTAINER) user_credit = UserCredit.objects.create( user=request.user, reason=UserCredit.TIMELAPSE_UPLOAD, amount=4) preprocess_timelapse.delay(request.user.id, video_path, request.FILES['file'].name, user_credit.id) return JsonResponse(dict(status='Ok')) else: return render(request, 'upload_print.html')
def post(self, request): printer = request.auth pic = request.data['pic'] internal_url, external_url = save_file_obj('{}/{}.jpg'.format(printer.id, int(time.time())), pic, settings.PICS_CONTAINER) if not printer.current_print_filename or not printer.current_print_started_at: redis.printer_pic_set(printer.id, {'img_url': external_url, 'p': '0'}, ex=STATUS_TTL_SECONDS) return command_response(printer) params = { 'img': internal_url, 'session_id': "{}|{}".format(printer.id, int(printer.current_print_started_at.timestamp())) } req = requests.get(settings.ML_API_HOST + '/p', params=params, headers=ml_api_auth_headers(), verify=False) req.raise_for_status() resp = req.json() p = resp['p'] redis.printer_pic_set(printer.id, {'img_url': external_url, 'p': p}, ex=STATUS_TTL_SECONDS) print(resp['detections']) print(p) send_alert_if_needed(printer, p) return command_response(printer)
def preprocess_timelapse(self, user_id, video_path, filename): tmp_file_path = os.path.join(tempfile.gettempdir(), video_path) converted_mp4_path = tmp_file_path + '.mp4' Path(tmp_file_path).parent.mkdir(parents=True, exist_ok=True) with open(tmp_file_path, 'wb') as file_obj: retrieve_to_file_obj(f'uploaded/{video_path}', file_obj, settings.PICS_CONTAINER, long_term_storage=False) subprocess.run( f'ffmpeg -y -i {tmp_file_path} -c:v libx264 -pix_fmt yuv420p {converted_mp4_path}' .split(), check=True) _print = Print.objects.create(user_id=user_id, filename=filename, uploaded_at=timezone.now()) with open(converted_mp4_path, 'rb') as mp4_file: _, video_url = save_file_obj(f'private/{_print.id}.mp4', mp4_file, settings.TIMELAPSE_CONTAINER) _print.video_url = video_url _print.save() detect_timelapse.delay(_print.id) os.remove(tmp_file_path) os.remove(converted_mp4_path)
def save_print_snapshot(printer, input_path, dest_jpg_path, rotated=False, to_container=settings.PICS_CONTAINER, to_long_term_storage=True): if not input_path: return None img_bytes = io.BytesIO() retrieve_to_file_obj(input_path, img_bytes, settings.PICS_CONTAINER, long_term_storage=False) img_bytes.seek(0) tmp_img = Image.open(img_bytes) if rotated: if printer.settings['webcam_flipH']: tmp_img = tmp_img.transpose(Image.FLIP_LEFT_RIGHT) if printer.settings['webcam_flipV']: tmp_img = tmp_img.transpose(Image.FLIP_TOP_BOTTOM) if printer.settings['webcam_rotate90']: tmp_img = tmp_img.transpose(Image.ROTATE_90) img_bytes = io.BytesIO() tmp_img.save(img_bytes, "JPEG") img_bytes.seek(0) _, dest_jpg_url = save_file_obj(dest_jpg_path, img_bytes, to_container, long_term_storage=to_long_term_storage) return dest_jpg_url
def select_print_shots_for_feedback(_print): # Select up to 7 highest predictions that are apart from each other for at least 2 minutes def highest_7_predictions(prediction_list): selected_timestamps = [] for pred in prediction_list: pred_ts = float(pred[0]) if len([ts for ts in selected_timestamps if abs(ts - pred_ts) < 120]) > 0: # timestamp is within 2 minutes from one other selected predictions continue selected_timestamps += [pred_ts] if len(selected_timestamps) >= 7: break return sorted(selected_timestamps) selected_predictions = highest_7_predictions(redis.print_highest_predictions_get(_print.id)) to_dir = os.path.join(tempfile.gettempdir(), 'ff_' + str(_print.id)) shutil.rmtree(to_dir, ignore_errors=True) os.mkdir(to_dir) local_imgs = download_files([f'raw/{_print.printer.id}/{_print.id}/{ts}.jpg' for ts in selected_predictions], to_dir) for local_img in local_imgs: with open(local_img, 'rb') as local_img_file: _, img_url = save_file_obj(f'ff_printshots/raw/{_print.printer.id}/{_print.id}/{local_img.name}', local_img_file, settings.TIMELAPSE_CONTAINER) PrintShotFeedback.objects.create(print=_print, image_url=img_url)
def post(self, request): printer = request.auth printer.refresh_from_db() # Connection is keep-alive, which means printer object can be stale. if not request.path.startswith('/api/v1'): LOGGER.warn(f'Beta plugin connecting from {printer.id}') pic = request.FILES['pic'] pic_id = int(timezone.now().timestamp()) internal_url, external_url = save_file_obj('raw/{}/{}.jpg'.format(printer.id, pic_id), pic, settings.PICS_CONTAINER) if not printer.should_watch() or not printer.actively_printing(): redis.printer_pic_set(printer.id, {'img_url': external_url}, ex=STATUS_TTL_SECONDS) send_status_to_web(printer.id) return Response({'result': 'ok'}) req = requests.get(settings.ML_API_HOST + '/p/', params={'img': internal_url}, headers=ml_api_auth_headers(), verify=False) req.raise_for_status() resp = req.json() detections = resp['detections'] prediction, _ = PrinterPrediction.objects.get_or_create(printer=printer) update_prediction_with_detections(prediction, detections) prediction.save() pic.file.seek(0) # Reset file object pointer so that we can load it again tagged_img = io.BytesIO() detections_to_visualize = [d for d in detections if d[1] > VISUALIZATION_THRESH] overlay_detections(Image.open(pic), detections_to_visualize).save(tagged_img, "JPEG") tagged_img.seek(0) _, external_url = save_file_obj('tagged/{}/{}.jpg'.format(printer.id, pic_id), tagged_img, settings.PICS_CONTAINER) redis.printer_pic_set(printer.id, {'img_url': external_url}, ex=STATUS_TTL_SECONDS) prediction_json = serializers.serialize("json", [prediction, ]) redis.printer_p_json_set(printer.id, pic_id, prediction_json, ex=60*60*24*2) if is_failing(prediction, printer.detective_sensitivity, escalating_factor=settings.ESCALATING_FACTOR): pause_if_needed(printer) elif is_failing(prediction, printer.detective_sensitivity, escalating_factor=1): alert_if_needed(printer) redis.print_num_predictions_incr(printer.current_print.id) send_status_to_web(printer.id) return Response({'result': 'ok'})
def save_print_snapshot(_print, rotated_jpg_path, rotated_jpg_container, rotated_jpg_long_term): pic_dir = f'{_print.printer.id}/{_print.id}' print_pics = list_dir(f'raw/{pic_dir}/', settings.PICS_CONTAINER, long_term_storage=False) if not print_pics: return (None, None) print_pics.sort() to_dir = os.path.join(tempfile.gettempdir(), str(_print.id)) shutil.rmtree(to_dir, ignore_errors=True) os.mkdir(to_dir) unrotated_jpg = os.path.join(to_dir, 'unrotated.jpg') with open(unrotated_jpg, 'wb') as file_obj: retrieve_to_file_obj(print_pics[-1], file_obj, settings.PICS_CONTAINER, long_term_storage=False) with open(unrotated_jpg, 'rb') as file_obj: _, unrotated_jpg_url = save_file_obj( f'raw/{_print.printer.id}/unrotated.jpg', file_obj, settings.PICS_CONTAINER, long_term_storage=False) ffmpeg_extra_options = orientation_to_ffmpeg_options( _print.printer.settings) rotated_jpg = os.path.join(to_dir, 'rotated.jpg') cmd = f'ffmpeg -y -i {unrotated_jpg} {ffmpeg_extra_options} {rotated_jpg}' subprocess.run(cmd.split(), check=True) with open(rotated_jpg, 'rb') as file_obj: _, rotated_jpg_url = save_file_obj( rotated_jpg_path, file_obj, rotated_jpg_container, long_term_storage=rotated_jpg_long_term) shutil.rmtree(to_dir, ignore_errors=True) return (unrotated_jpg_url, rotated_jpg_url)
def generate_print_poster(_print): pic_dir = f'{_print.printer.id}/{_print.id}' print_pics = list_dir(f'raw/{pic_dir}/', settings.PICS_CONTAINER, long_term_storage=False) if not print_pics: return print_pics.sort() to_dir = os.path.join(tempfile.gettempdir(), str(_print.id)) shutil.rmtree(to_dir, ignore_errors=True) os.mkdir(to_dir) unrotated_jpg = os.path.join(to_dir, 'ss.jpg') with open(unrotated_jpg, 'wb') as file_obj: retrieve_to_file_obj(print_pics[-1], file_obj, settings.PICS_CONTAINER, long_term_storage=False) with open(unrotated_jpg, 'rb') as unrotated_jpg_file: _, ss_url = save_file_obj(f'raw/{_print.printer.id}/ss.jpg', unrotated_jpg_file, settings.PICS_CONTAINER, long_term_storage=False) redis.printer_pic_set(_print.printer.id, {'img_url': ss_url}, ex=IMG_URL_TTL_SECONDS) ffmpeg_extra_options = orientation_to_ffmpeg_options( _print.printer.settings) rotated_jpg = os.path.join(to_dir, 'rotated.jpg') cmd = f'ffmpeg -y -i {unrotated_jpg} {ffmpeg_extra_options} {rotated_jpg}' subprocess.run(cmd.split(), check=True) with open(rotated_jpg, 'rb') as poster_file: _, poster_file_url = save_file_obj( 'private/{}_poster.jpg'.format(_print.id), poster_file, settings.TIMELAPSE_CONTAINER) _print.poster_url = poster_file_url _print.save() shutil.rmtree(to_dir, ignore_errors=True)
def upload_gcode_file(request): if request.method == 'POST': _, file_extension = os.path.splitext(request.FILES['file'].name) gcode_file = GCodeFile.objects.create( user=request.user, filename=request.FILES['file'].name, safe_filename=re.sub(r'[^\w\.]', '_', request.FILES['file'].name), num_bytes=request.FILES['file'].size, ) _, ext_url = save_file_obj(f'{request.user.id}/{gcode_file.id}', request.FILES['file'], settings.GCODE_CONTAINER) gcode_file.url = ext_url gcode_file.save() return JsonResponse(dict(status='Ok')) else: return render(request, 'upload_print.html')
def save_print_snapshot(_print, input_path, dest_jpg_path, rotated=False, to_container=settings.PICS_CONTAINER, to_long_term_storage=True): if not input_path: return None to_dir = tempfile.mkdtemp() shutil.rmtree(to_dir, ignore_errors=True) os.mkdir(to_dir) temp_jpg = os.path.join(to_dir, 'unrotated.jpg') with open(temp_jpg, 'wb') as file_obj: retrieve_to_file_obj(input_path, file_obj, settings.PICS_CONTAINER, long_term_storage=False) if not rotated: dest_jpg = temp_jpg else: ffmpeg_extra_options = orientation_to_ffmpeg_options( _print.printer.settings) dest_jpg = os.path.join(to_dir, 'rotated.jpg') cmd = f'ffmpeg -y -i {temp_jpg} {ffmpeg_extra_options} {dest_jpg}' subprocess.run(cmd.split(), check=True) with open(dest_jpg, 'rb') as file_obj: _, dest_jpg_url = save_file_obj(dest_jpg_path, file_obj, to_container, long_term_storage=to_long_term_storage) shutil.rmtree(to_dir, ignore_errors=True) return dest_jpg_url
def compile_timelapse(print_id): _print = Print.objects.select_related('printer').get(id=print_id) to_dir = os.path.join(tempfile.gettempdir(), 'tl_' + str(_print.id)) shutil.rmtree(to_dir, ignore_errors=True) os.mkdir(to_dir) ffmpeg_extra_options = orientation_to_ffmpeg_options( _print.printer.settings) pic_dir = f'{_print.printer.id}/{_print.id}' print_pics = list_dir(f'raw/{pic_dir}/', settings.PICS_CONTAINER, long_term_storage=False) print_pics.sort() if print_pics: local_pics = download_files(print_pics, to_dir) mp4_filename = '{}.mp4'.format(_print.id) output_mp4 = os.path.join(to_dir, mp4_filename) cmd = 'ffmpeg -y -r 30 -pattern_type glob -i {}/*.jpg -c:v libx264 -pix_fmt yuv420p {} {}'.format( local_pics[-1].parent, ffmpeg_extra_options, output_mp4) subprocess.run(cmd.split(), check=True) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj('private/{}'.format(mp4_filename), mp4_file, settings.TIMELAPSE_CONTAINER) _print.video_url = mp4_file_url _print.save() # build tagged timelapse print_pics = list_dir(f'tagged/{pic_dir}/', settings.PICS_CONTAINER, long_term_storage=False) print_pics.sort() if print_pics: local_pics = download_files(print_pics, to_dir) mp4_filename = '{}_tagged.mp4'.format(_print.id) output_mp4 = os.path.join(to_dir, mp4_filename) cmd = 'ffmpeg -y -r 30 -pattern_type glob -i {}/*.jpg -c:v libx264 -pix_fmt yuv420p -vf pad=ceil(iw/2)*2:ceil(ih/2)*2 {} {}'.format( local_pics[0].parent, ffmpeg_extra_options, output_mp4) subprocess.run(cmd.split(), check=True) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj('private/{}'.format(mp4_filename), mp4_file, settings.TIMELAPSE_CONTAINER) json_files = list_dir(f'p/{pic_dir}/', settings.PICS_CONTAINER, long_term_storage=False) local_jsons = download_files(json_files, to_dir) prediction_json = [] num_missing_p_json = 0 for pic_path in local_pics: try: with open( str(pic_path).replace('tagged/', 'p/').replace('.jpg', '.json'), 'r') as f: p_json = json.load(f) except ( FileNotFoundError, json.decoder.JSONDecodeError ) as e: # In case there is no corresponding json, the file will be empty and JSONDecodeError will be thrown LOGGER.warn(e) p_json = [{}] num_missing_p_json += 1 if num_missing_p_json > 5: raise Exception('Too many missing p_json files.') prediction_json += p_json prediction_json_io = io.BytesIO() prediction_json_io.write(json.dumps(prediction_json).encode('UTF-8')) prediction_json_io.seek(0) _, json_url = save_file_obj('private/{}_p.json'.format(_print.id), prediction_json_io, settings.TIMELAPSE_CONTAINER) _print.tagged_video_url = mp4_file_url _print.prediction_json_url = json_url _print.save() shutil.rmtree(to_dir, ignore_errors=True) clean_up_print_pics(_print)
def compile_timelapse(print_id): _print = Print.objects.select_related('printer').get(id=print_id) to_dir = os.path.join(tempfile.gettempdir(), str(_print.id)) shutil.rmtree(to_dir, ignore_errors=True) os.mkdir(to_dir) ffmpeg_extra_options = orientation_to_ffmpeg_options( _print.printer.settings) pic_dir = f'{_print.printer.id}/{_print.id}' print_pics = list_dir(f'raw/{pic_dir}/', settings.PICS_CONTAINER, long_term_storage=False) print_pics.sort() if print_pics: local_pics = download_files(print_pics, to_dir) mp4_filename = '{}.mp4'.format(_print.id) output_mp4 = os.path.join(to_dir, mp4_filename) cmd = 'ffmpeg -y -r 30 -pattern_type glob -i {}/*.jpg -c:v libx264 -pix_fmt yuv420p {} {}'.format( local_pics[-1].parent, ffmpeg_extra_options, output_mp4) subprocess.run(cmd.split(), check=True) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj('private/{}'.format(mp4_filename), mp4_file, settings.TIMELAPSE_CONTAINER) _print.video_url = mp4_file_url _print.save() # build tagged timelapse print_pics = list_dir(f'tagged/{pic_dir}/', settings.PICS_CONTAINER, long_term_storage=False) print_pics.sort() if print_pics: local_pics = download_files(print_pics, to_dir) mp4_filename = '{}_tagged.mp4'.format(_print.id) output_mp4 = os.path.join(to_dir, mp4_filename) cmd = 'ffmpeg -y -r 30 -pattern_type glob -i {}/*.jpg -c:v libx264 -pix_fmt yuv420p -vf pad=ceil(iw/2)*2:ceil(ih/2)*2 {} {}'.format( local_pics[0].parent, ffmpeg_extra_options, output_mp4) subprocess.run(cmd.split(), check=True) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj('private/{}'.format(mp4_filename), mp4_file, settings.TIMELAPSE_CONTAINER) preidction_json = [] for print_pic_filename in print_pics: try: m = re.search('tagged/(\d+)/\d+/([\d.]+).jpg', print_pic_filename) p_json = json.loads(redis.printer_p_json_get(m[1], m[2])) except ( json.decoder.JSONDecodeError, TypeError ): # In case there is no corresponding json, the file will be empty and JSONDecodeError will be thrown p_json = [{}] preidction_json += p_json preidction_json_io = io.BytesIO() preidction_json_io.write(json.dumps(preidction_json).encode('UTF-8')) preidction_json_io.seek(0) _, json_url = save_file_obj('private/{}_p.json'.format(_print.id), preidction_json_io, settings.TIMELAPSE_CONTAINER) _print.tagged_video_url = mp4_file_url _print.prediction_json_url = json_url _print.save() shutil.rmtree(to_dir, ignore_errors=True) clean_up_print_pics(_print)
def compile_timelapse(self, print_id): pprint = Print.objects.get(id=print_id) end_time = pprint.finished_at or pprint.cancelled_at to_dir = os.path.join(tempfile.gettempdir(), str(pprint.id)) shutil.rmtree(to_dir, ignore_errors=True) os.mkdir(to_dir) print_pics = filter_pics_by_start_end( list_file_obj('raw/{}/'.format(pprint.printer.id), settings.PICS_CONTAINER), pprint.started_at, end_time) print_pics.sort() if print_pics: local_pics = download_files(print_pics, to_dir) last_pic = local_pics[-1] mp4_filename = '{}.mp4'.format(pprint.id) output_mp4 = os.path.join(to_dir, mp4_filename) subprocess.run( 'ffmpeg -y -pattern_type glob -i {}/*.jpg -c:v libx264 -vf fps=30 -pix_fmt yuv420p {}' .format(last_pic.parent, output_mp4).split(' '), check=True) shutil.copyfile(last_pic, os.path.join(to_dir, '{}.jpg'.format(pprint.id))) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj('private/{}'.format(mp4_filename), mp4_file, settings.TIMELAPSE_CONTAINER) with open(last_pic, 'rb') as poster_file: _, poster_file_url = save_file_obj( 'private/{}_poster.jpg'.format(pprint.id), poster_file, settings.TIMELAPSE_CONTAINER) pprint.video_url = mp4_file_url pprint.poster_url = poster_file_url pprint.save() # build tagged timelapse print_pics = filter_pics_by_start_end( list_file_obj('tagged/{}/'.format(pprint.printer.id), settings.PICS_CONTAINER), pprint.started_at, end_time) print_pics.sort() if print_pics: local_pics = download_files(print_pics, to_dir) mp4_filename = '{}_tagged.mp4'.format(pprint.id) output_mp4 = os.path.join(to_dir, mp4_filename) subprocess.run( 'ffmpeg -y -pattern_type glob -i {}/*.jpg -c:v libx264 -vf fps=30 -pix_fmt yuv420p {}' .format(local_pics[0].parent, output_mp4).split(' '), check=True) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj('private/{}'.format(mp4_filename), mp4_file, settings.TIMELAPSE_CONTAINER) json_files = [ print_pic.replace('tagged/', 'p/').replace('.jpg', '.json') for print_pic in print_pics ] local_jsons = download_files(json_files, to_dir) preidction_json = [] for p_json_file in local_jsons: with open(p_json_file, 'r') as f: try: p_json = json.load(f) except json.decoder.JSONDecodeError: # In case there is no corresponding json, the file will be empty and JSONDecodeError will be thrown p_json = [{}] preidction_json += p_json preidction_json_io = io.BytesIO() preidction_json_io.write(json.dumps(preidction_json).encode('UTF-8')) preidction_json_io.seek(0) _, json_url = save_file_obj('private/{}_p.json'.format(pprint.id), preidction_json_io, settings.TIMELAPSE_CONTAINER) pprint.tagged_video_url = mp4_file_url pprint.prediction_json_url = json_url pprint.save() shutil.rmtree(to_dir, ignore_errors=True)
def compile_timelapse(print_id): _print = Print.objects.select_related('printer').get(id=print_id) to_dir = os.path.join(tempfile.gettempdir(), str(_print.id)) shutil.rmtree(to_dir, ignore_errors=True) os.mkdir(to_dir) ffmpeg_extra_options = orientation_to_ffmpeg_options(_print.printer.settings) print_pics = filter_pics_by_start_end(list_file_obj('raw/{}/'.format(_print.printer.id), settings.PICS_CONTAINER), _print.started_at, _print.ended_at()) print_pics.sort() if print_pics: local_pics = download_files(print_pics, to_dir) mp4_filename = '{}.mp4'.format(_print.id) output_mp4 = os.path.join(to_dir, mp4_filename) cmd = 'ffmpeg -y -r 30 -pattern_type glob -i {}/*.jpg -c:v libx264 -pix_fmt yuv420p {} {}'.format(local_pics[-1].parent, ffmpeg_extra_options, output_mp4) subprocess.run(cmd.split(), check=True) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj('private/{}'.format(mp4_filename), mp4_file, settings.TIMELAPSE_CONTAINER) last_pic = os.path.join(to_dir, 'ss.jpg') # https://superuser.com/questions/1448665/ffmpeg-how-to-get-last-frame-from-a-video subprocess.run('ffmpeg -y -i {} -sseof -1 -update 1 -vframes 1 -q:v 2 {}'.format(output_mp4, last_pic).split(' '), check=True) with open(last_pic, 'rb') as poster_file: _, poster_file_url = save_file_obj('private/{}_poster.jpg'.format(_print.id), poster_file, settings.TIMELAPSE_CONTAINER) _print.video_url = mp4_file_url _print.poster_url = poster_file_url _print.save() # build tagged timelapse print_pics = filter_pics_by_start_end(list_file_obj('tagged/{}/'.format(_print.printer.id), settings.PICS_CONTAINER), _print.started_at, _print.ended_at()) print_pics.sort() if print_pics: local_pics = download_files(print_pics, to_dir) mp4_filename = '{}_tagged.mp4'.format(_print.id) output_mp4 = os.path.join(to_dir, mp4_filename) cmd = 'ffmpeg -y -r 30 -pattern_type glob -i {}/*.jpg -c:v libx264 -pix_fmt yuv420p {} {}'.format(local_pics[0].parent, ffmpeg_extra_options, output_mp4) subprocess.run(cmd.split(), check=True) with open(output_mp4, 'rb') as mp4_file: _, mp4_file_url = save_file_obj('private/{}'.format(mp4_filename), mp4_file, settings.TIMELAPSE_CONTAINER) preidction_json = [] for print_pic_filename in print_pics: try: m = re.search('tagged/(\d+)/(\d+).jpg', print_pic_filename) p_json = json.loads(redis.printer_p_json_get(m[1], m[2])) except (json.decoder.JSONDecodeError, TypeError): # In case there is no corresponding json, the file will be empty and JSONDecodeError will be thrown p_json = [{}] preidction_json += p_json preidction_json_io = io.BytesIO() preidction_json_io.write(json.dumps(preidction_json).encode('UTF-8')) preidction_json_io.seek(0) _, json_url = save_file_obj('private/{}_p.json'.format(_print.id), preidction_json_io, settings.TIMELAPSE_CONTAINER) _print.tagged_video_url = mp4_file_url _print.prediction_json_url = json_url _print.save() shutil.rmtree(to_dir, ignore_errors=True)