111 lines
4.4 KiB
Python
111 lines
4.4 KiB
Python
import requests
|
|
from requests import RequestException
|
|
import json
|
|
import jinja2
|
|
from pathlib import Path
|
|
|
|
class Athletico():
|
|
def fetch_episodes_for_access_code(self, access_code:str) -> dict:
|
|
'''
|
|
Given a home access code, fetch exercise information
|
|
:param access_code: the access code to a home excercise program from Athletico
|
|
:return: a dict containing the exercise information
|
|
'''
|
|
session = requests.Session()
|
|
home_url = "https://athleticopt.medbridgego.com"
|
|
fetch_episodes_url = "https://athleticopt.medbridgego.com/api/v4/lite/episodes/"
|
|
|
|
session.get(home_url)
|
|
csrf_token = session.cookies.get('csrf_cookie_name')
|
|
|
|
session.post(
|
|
url="https://athleticopt.medbridgego.com/register_token",
|
|
data = {
|
|
"token": access_code,
|
|
"X-CSRF-Token": csrf_token,
|
|
"verify_access_code": "Verify+Access+Code"
|
|
}
|
|
)
|
|
|
|
response = session.get(fetch_episodes_url)
|
|
|
|
if response.ok and response.json() and response.json().get('status'):
|
|
return response.json().get('episodes')
|
|
else:
|
|
raise RequestException(f'Request Failed, {response.status_code}: {response.reason}')
|
|
|
|
def render(self, template: str, output: str, context: dict) -> str:
|
|
'''
|
|
Renders an HTML page.
|
|
:param template: Path to jinja template
|
|
:param output: Destination for .html file
|
|
:param context: The context to be passed to the render
|
|
:return: Path to html file
|
|
'''
|
|
|
|
output_filepath = Path(output)
|
|
template_filepath = Path(output)
|
|
environment = jinja2.Environment(loader=jinja2.FileSystemLoader())
|
|
template = environment.get_template(template_filepath)
|
|
page = template.render(**context)
|
|
|
|
output_filepath.mkdir(parents=True, exist_ok=True)
|
|
with output_filepath.open('w') as f:
|
|
f.write(page)
|
|
|
|
return str(output_filepath)
|
|
|
|
def save_episodes(self, episodes: list, destination: str= ".") -> None:
|
|
'''
|
|
Outputs episodes to disk in a folder structure
|
|
:param episodes: List of episode data, matches output of fetch_episodes_for_access_code
|
|
:param destination: Filepath to save to, defaults to current directory
|
|
:return: None
|
|
'''
|
|
|
|
destination_filepath = Path(destination)
|
|
destination_filepath.joinpath()
|
|
for episode in episodes:
|
|
episode_id = str(episode['id'])
|
|
program = episode['program']
|
|
exercises = []
|
|
episode_filepath = destination_filepath.joinpath('programs',episode["token"],'episodes')
|
|
episode_filepath.mkdir(parents=True, exist_ok=True)
|
|
|
|
for exercise in program['program_exercises']:
|
|
exercises.append(exercise)
|
|
exercise_id = str(exercise['id'])
|
|
exercise_filepath = destination_filepath.joinpath(destination,'exercises', exercise_id)
|
|
thumbnails_filepath = exercise_filepath.joinpath('thumbnails')
|
|
thumbnails_filepath.mkdir(parents=True, exist_ok=True)
|
|
for i, image in enumerate(exercise['exercise']['thumbnails']):
|
|
r = requests.get(image['image_filepath'])
|
|
fname = image['image_filepath'].split('/')[-1]
|
|
with thumbnails_filepath.joinpath(fname).open('wb') as f:
|
|
f.write(r.content)
|
|
|
|
with exercise_filepath.joinpath(exercise_id).with_suffix('.json').open('w') as f:
|
|
json.dump(exercise, f)
|
|
|
|
with exercise_filepath.joinpath(exercise_id).with_suffix('.txt').open('w') as f:
|
|
f.write(exercise['name'])
|
|
|
|
if exercise["exercise"]["video_file"]:
|
|
with exercise_filepath.joinpath('video_file').with_suffix('.m3u8').open('wb') as f:
|
|
try:
|
|
r = requests.get("http:"+exercise["exercise"]["video_file"])
|
|
except:
|
|
pass
|
|
f.write(r.content)
|
|
|
|
with exercise_filepath.joinpath('description').with_suffix('.html').open('w') as f:
|
|
f.write(exercise["exercise"]["description"])
|
|
|
|
|
|
with episode_filepath.joinpath(episode_id).with_suffix('.json').open('w') as f:
|
|
json.dump(episode, fp=f)
|
|
|
|
return
|
|
|
|
if __name__ == "__main__":
|
|
pass |