f1tness_parser/obsidian/notes_parser.py
2025-08-31 14:43:31 +03:00

131 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import re
from pprint import pprint
from typing import List, Tuple
from datetime import datetime
from obsidian.mapper import obsidian_unique_exercies_mapping
from obsidian.py_models import Approach, Exercise, Training
from utils.date_refactor import parse_training_date
current_directory = os.path.dirname(os.path.abspath(__file__))
PROJECT_ROOT_DIR = os.getcwd()
def get_data_path():
notes_data_dir = os.path.join(PROJECT_ROOT_DIR, "data")
return notes_data_dir
def get_obsidian_examples_file(example_file_name: str):
return os.path.join(get_data_path(), f"{example_file_name}")
def read_example_file(example_file_name: str):
path_to_example: str = get_obsidian_examples_file(example_file_name)
with open(path_to_example, "r") as f:
content = f.read()
return content
def serialize_exercise(reps: str, weight: str, name: str) -> Exercise:
# Split reps into array of int's
reps_list: List[int] = [int(rep) for rep in reps.split("-")]
weight_splitted: bool = False
weight_list: List[float] = []
if weight:
weight_str_list: List[str] = [weight for weight in weight.split("-")]
# Check if weight is splitted
if any(split_anchor in weight_str_list[0] for split_anchor in ["x", "х"]):
weight_splitted = True
splitter = "x" if "x" in weight_str_list[0] else "х"
weight_list = [float(xweight.split(splitter)[0]) for xweight in weight_str_list]
else:
weight_list = [float(w) for w in weight_str_list]
approaches = []
if not weight:
for rep_index in range(0, len(reps_list)):
approach = Approach(weight=0.0, reps=reps_list[rep_index])
approaches.append(approach)
else:
weight_pointer = 0
for rep_index in range(0, len(reps_list)):
approach = Approach(weight=weight_list[weight_pointer], reps=reps_list[rep_index])
if rep_index < len(weight_list) - 1:
weight_pointer += 1
approaches.append(approach)
exercise = Exercise(
name=name, approaches=approaches, splitted_weight=weight_splitted
)
return exercise
def parse_training_exercises(exercise_line: str) -> Exercise:
stripped: List[str] = [entry.strip() for entry in exercise_line.split("|")][1:-1]
for entry in stripped:
if entry in ["Упражнение", "Вес", "Подходы"]:
raise ValueError
if stripped:
if "---" in stripped[0]:
raise ValueError
if len(stripped) != 3:
raise ValueError
return serialize_exercise(
name=stripped[0], weight=stripped[1], reps=stripped[2]
)
raise ValueError("No valid exercise data found")
def parse_training_header(
training_data_line: str,
) -> Tuple[bool, str, str, str]:
pattern: str = r"#\s(?P<date>\d+.\d+.\d+)\s\((?P<trainer>.+)-(?P<year_counter>.+)\)"
match = re.search(pattern, training_data_line)
if match:
date = match.group("date").strip()
trainer = match.group("trainer").strip()
year_count = match.group("year_counter").strip()
return True, date, trainer, year_count
return False, "", "", ""
def filter_training_data(training_data: str):
cleaned_text = re.sub(r"^\s*?\n", "", training_data, flags=re.MULTILINE)
return cleaned_text
def parse_training_data():
training_data: str = filter_training_data(read_example_file("obsidian.md"))
lines = training_data.splitlines()
current_training = None
trains = []
for index, line in enumerate(lines):
header_parsed, date, trainer, year_count = parse_training_header(line)
if index == len(lines) - 1:
trains.append(current_training)
if header_parsed:
trains.append(current_training)
current_training = Training(
# date=datetime.strptime(date, "%d.%m.%Y").date(), exercises=[]
date=parse_training_date(date),
exercises=[],
)
continue
try:
exr = parse_training_exercises(line)
current_training.exercises.append(exr)
except ValueError:
pass
return trains[1:]
def remap_unique_exercises(obsidian_trainings: List[Training]) -> List[Training]:
for obsidian_training in obsidian_trainings:
if not obsidian_training or not obsidian_training.exercises:
continue
for obsidian_exercise in obsidian_training.exercises:
mapped_name = obsidian_unique_exercies_mapping.get(obsidian_exercise.name)
if mapped_name is not None:
obsidian_exercise.name = mapped_name
return obsidian_trainings