From 3313298fa289f7c45831e4fd90f963f84d24b4c5 Mon Sep 17 00:00:00 2001 From: gabriel becker Date: Thu, 31 Aug 2023 23:15:41 +1000 Subject: [PATCH] Base scripts create working openworkout file with videos --- .gitignore | 3 + create_open_workout_database.py | 60 ++++++++-------- exercise_config.py | 13 ++++ load_exercises.py | 16 ++--- map_yaml_to_database.py | 121 ++++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 40 deletions(-) create mode 100644 .gitignore create mode 100644 exercise_config.py create mode 100644 map_yaml_to_database.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c7aa7fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +data +**.*mp4 +**.*json diff --git a/create_open_workout_database.py b/create_open_workout_database.py index 5c10f0a..237092b 100644 --- a/create_open_workout_database.py +++ b/create_open_workout_database.py @@ -1,4 +1,4 @@ -import json + WORKOUT_DATABASE = { "countFinishedTraining": 0, @@ -11,7 +11,7 @@ WORKOUT_DATABASE = { } -def create_work_database(name, workout_sessions): +def create_workout_database(name, workout_sessions): new_db = dict(WORKOUT_DATABASE) new_content = { "name": name, @@ -32,10 +32,10 @@ WORKOUT_SESSION = { } -def create_work_session(workout_items: list): +def create_workout_session(workout_items: list): new_session = dict(WORKOUT_SESSION) new_session_content = { - "workoutItems": workout_items + 'workoutItems': workout_items } new_session.update(new_session_content) return new_session @@ -43,49 +43,51 @@ def create_work_session(workout_items: list): WOPRKOUT_ITEM = { "breakTime": 2, - "description": "Stand up with your legs spread and your hands touching overhead. Then as you jump, bring your legs back together and put your arms to your sides. You can speed these up or slow them down to suit your fitness level.", + "description": "", "elapsedTime": 0, "finished": False, "imagePath": "jumping_jack.png", "isImagePathExternal": False, "isTimeMode": True, "isVideoMode": True, - "isVideoPathExternal": False, + "isVideoPathExternal": True, "name": "Jumping Jack", "orderNr": -1, "prepTime": 5, "repetitionCount": 5, - "videoPath": "jumping_jack.mp4", + "videoPath": "", "workoutItemId": 0, "workoutSessionId": 1, "workoutTime": 30 } -def create_item(): +def get_item_id(): + start = 0 + while True: + yield start + start += 1 + + +def create_item(name, workout_time, n_repetitions, description=None, preparation_time=5, video_path=None): + is_video_mode = True if video_path else False + new_item = dict(WOPRKOUT_ITEM) new_item_content = { - "description": "Stand up with your legs spread and your hands touching overhead. Then as you jump, bring your legs back together and put your arms to your sides. You can speed these up or slow them down to suit your fitness level.", - "elapsedTime": 0, - "imagePath": "jumping_jack.png", - "isImagePathExternal": False, - "isTimeMode": True, - "isVideoMode": True, - "prepTime": 5, - "repetitionCount": 5, - "videoPath": "jumping_jack.mp4", - "workoutTime": 30 + "name": name, + 'description': description or '', + 'elapsedTime': 0, + 'imagePath': '', + 'isImagePathExternal': False, + 'isTimeMode': True, + 'isVideoMode': is_video_mode, + 'prepTime': preparation_time, + 'repetitionCount': n_repetitions, + 'videoPath': video_path, + "orderNr": next(get_item_id()), + "workoutItemId": 0, + "workoutSessionId": 1, + 'workoutTime': workout_time } new_item.update(new_item_content) return new_item - - -def lasdikfsh(): - items = [create_item()] - sessions = [create_work_session(items)] - db = create_work_database('urdur', sessions) - with open("your_json_file.json", "w") as fp: - json.dump(db , fp) - -if __name__ == '__main__': - lasdikfsh() diff --git a/exercise_config.py b/exercise_config.py new file mode 100644 index 0000000..c397a8b --- /dev/null +++ b/exercise_config.py @@ -0,0 +1,13 @@ +from dataclasses import dataclass + + +@dataclass +class ExerciseConfig: + name: str + video: str + start: int + end: int + +@dataclass +class WorkoutConfig: + pass diff --git a/load_exercises.py b/load_exercises.py index 450f08a..1c5ae66 100644 --- a/load_exercises.py +++ b/load_exercises.py @@ -1,16 +1,10 @@ import yaml import pytube import tempfile -import imageio - -from pathlib import Path from functools import lru_cache import moviepy.editor as mpy -FILE = 'data/input/samples/exercises.yaml' - - @lru_cache(5) def get_video(url): output_dir = tempfile.mktemp() @@ -18,26 +12,26 @@ def get_video(url): video.streams.filter(res="360p").first().download(filename=output_dir) return output_dir + def create_gif_from_video_and_timestamps(video_path, start, end): video = mpy.VideoFileClip(video_path) clip: mpy.VideoFileClip = video.subclip(start, end) output_dir = tempfile.mktemp() + '.mp4' - clip.set_fps(2) clip.without_audio().write_videofile(output_dir) return output_dir -if __name__ == '__main__': - file = open(FILE) +def load_file_and_media_links(file_path): + file = open(file_path) exercises = yaml.safe_load(file) for ex in exercises['exercises']: name = ex['name'] video_url = ex['video'] start = ex['start'] end = ex['end'] - + video_path = get_video(video_url) gif = create_gif_from_video_and_timestamps(video_path, start, end) ex['gif_path'] = gif - print(gif) + return exercises diff --git a/map_yaml_to_database.py b/map_yaml_to_database.py new file mode 100644 index 0000000..33b08c7 --- /dev/null +++ b/map_yaml_to_database.py @@ -0,0 +1,121 @@ +import json +import tempfile +import zipfile +import os + +from load_exercises import load_file_and_media_links +from create_open_workout_database import create_workout_session, create_item, create_workout_database + + +ITEM_KEY_MEDIA_TYPE_MAP = { + 'video': 'videoPath', + 'image': 'imagePath', +} + +def get_all_media_from_db_by_type(db, media_type): + item_key = ITEM_KEY_MEDIA_TYPE_MAP[media_type] + media = list() + for session in db['workoutSessions']: + for workout_item in session['workoutItems']: + media.append(workout_item[item_key]) + media = list(set(media)) + return media + + +def map_source_destination(media_files, root_destination): + media_maps = list() + for file_path in media_files: + dest = get_destination_maps(file_path, root_destination) + media_maps.append((file_path, dest)) + return media_maps + + +def get_destination_maps(input_path, relative_destination): + file = os.path.basename(input_path) + destination_file_path = f'{relative_destination}/{file}' + return destination_file_path + + +def get_remote_formatted_media_path(root_name: str, media_type: str, file_path: str): + actual_file = os.path.basename(file_path) + remote_root = 'file:///data/user/0/com.health.openworkout/files' + new_media_path = f'{remote_root}/{root_name}/{media_type}/{actual_file}' + return new_media_path + + +def refactor_media_paths_in_db(db): + db_name = db['name'] + for session in db['workoutSessions']: + for workout_item in session['workoutItems']: + item_has_video = workout_item['videoPath'] != '' + if item_has_video: + new_formatted_path = get_remote_formatted_media_path( + media_type='video', + root_name=db_name, + file_path=workout_item['videoPath'] + ) + workout_item['videoPath'] = new_formatted_path + item_has_image = workout_item['imagePath'] != '' + if item_has_image: + new_formatted_path = get_remote_formatted_media_path( + media_type='image', + root_name=db_name, + file_path=workout_item['imagePath'] + ) + workout_item['imagePath'] = new_formatted_path + return db + + +def save_workout_file(output_files, db_file, video_files=tuple(), image_files=tuple()): + video_maps = map_source_destination(video_files, 'video') + image_maps = map_source_destination(image_files, 'image') + media_maps = video_maps + image_maps + + db_json = tempfile.mktemp() + with open(db_json, 'w') as f: + json.dump(db_file, f) + + with zipfile.ZipFile(output_files, 'w') as zip_file: + zip_file.write(db_json, arcname='database.json') + for source, dest in media_maps: + zip_file.write(source, arcname=dest) + + +def map_config_to_workout_file(config): + items = [ + create_item( + name=item['name'], + workout_time=30, + n_repetitions=1, + description=None, + preparation_time=5, + video_path=item['gif_path'] + ) + for item in config['exercises'] + ] + sessions = [create_workout_session(items)] * 30 + db = create_workout_database(config['name'], sessions) + return db + + +def process_config_into_workout_file(config, output_file = None): + db = map_config_to_workout_file(config) + videos = get_all_media_from_db_by_type(db, media_type='video') + images = get_all_media_from_db_by_type(db, media_type='image') + db = refactor_media_paths_in_db(db) + + output_file_name = output_file or f"{db['name']}.zip" + save_workout_file( + output_files=output_file_name, + db_file=db, + video_files=videos, + ) + + +FILE = 'data/input/samples/exercises.yaml' + + +if __name__ == '__main__': + config = load_file_and_media_links(FILE) + process_config_into_workout_file(config) +