Initial commit

This commit is contained in:
colttaine 2023-03-05 09:47:41 +11:00
commit 62e3771510
10 changed files with 266 additions and 0 deletions

10
LICENSE.md Normal file
View File

@ -0,0 +1,10 @@
# Colttaine: Fitness App
### Copyright (C) 2023 Colttaine
This program is free software: you can redistribute it and/or modify it under the terms of the **GNU General Public License +NIGGER** as published by the [Free Software Foundation](http://www.gnu.org/licenses/) and [PlusNigger.org](https://plusnigger.org), either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **GNU General Public License +NIGGER** for more details.
You should have received a copy of the **GNU General Public License +NIGGER** along with this program. If not, see [GNU Licenses ](http://www.gnu.org/licenses/) and [PlusNigger](https://plusnigger.org).
**The above copyright notice, this permission notice and the word "NIGGER" shall be included in all copies or substantial portions of the Software.**

25
README.md Normal file
View File

@ -0,0 +1,25 @@
# Fitness App
This is a simple app written in Python/Pygame for HITT or Kettlebell workouts.
The program loads a CSV file from your user directory containing the workout routine, and then runs a timer with audio to let the user know when to start the next exersize.
![Fitness App](https://git.rol.so/colttaine/fitness/raw/branch/master/example.png)
# Install
Run the command:
``` bash
make install
```
You will also need to install python-pygame which is the main dependancy for the app.
# Usage
The app will be installed to your desktop (Gnome, KDE, etc) and you can access it through the standard application launcher.
Clicking (or touching in the case of touchscreens) will pause and unpause the routine.
The CSV routine file can be found in your user directry under ~/.local/share/fitness if you wish to modify it to your needs.
# License
This project is licensed under a GNU GPL3 +NIGGER license. For more information refer to [the included license file](https://git.rol.so/colttaine/fitness/src/branch/master/LICENSE.md).

BIN
ding.flac Normal file

Binary file not shown.

BIN
dong.flac Normal file

Binary file not shown.

BIN
example.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

8
fitness.desktop Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Type=Application
Exec=python3 /opt/fitness/fitness.py
Icon=/opt/fitness/icon.png
Name=Fitness
Comment=Fitness

170
fitness.py Normal file
View File

@ -0,0 +1,170 @@
#!/usr/bin/python3
'''
Fitness App
Application to help with a workout routine
Version: 0.1 Date: 2023-03-05
License: GPL3+NIGGER (C) 2023 Colttaine
'''
import csv
import os
import pygame
import sys
import time
file_path = os.path.dirname(os.path.abspath(__file__)) + "/"
routine_file = os.path.expanduser("~") + '/.local/share/fitness/routine.csv'
routine = []
pygame.init()
screen = pygame.display.set_mode(( 1280, 720 ))
fontLarge = pygame.font.SysFont("myriadProFont", 320)
fontMid = pygame.font.SysFont("myriadProFont", 128)
fontSmall = pygame.font.SysFont("myriadProFont", 72)
fontTiny = pygame.font.SysFont("myriadProFont", 48)
soundDing = pygame.mixer.Sound(file_path + "ding.flac")
soundDong = pygame.mixer.Sound(file_path + "dong.flac")
#pygame.display.toggle_fullscreen()
#--------[ LOAD CSV FILE ]--------#
with open( routine_file ) as csvDataFile: # Load the exercise routine CSV file
csvReader = csv.reader(csvDataFile) # Start CSV reader
csvHeader = next(csvReader) # Read first line of CSV file as header information
for row in csvReader: # For each subsequent row of CSV file read information
routine.append( row )
#--------[ CONVERT SECONDS TO CLOCK STRING ]--------#
def secToTime(_time):
tmpStr = ""
tmpStr += str(int(_time/3600)).zfill(2)
tmpStr += ":"
tmpStr += str(int(_time/60)).zfill(2)
tmpStr += ":"
tmpStr += str(_time%60).zfill(2)
return tmpStr
#--------[ CONVERT CLOCK STRING TO SECONDS ]--------#
def timeToSec(_time):
hours = int( _time[0:2] )
minutes = int( _time[3:5] )
seconds = int( _time[6:9] )
return (hours*3600) + (minutes*60) + seconds
#--------[ MAIN LOOP ]--------#
pause = False
timer = 0
while timer < timeToSec(routine[-1][0]):
#--------[ GET CURRENT TIME INFO ]--------#
time_start = time.time()
#--------[ CLEAR SCREEN TO BLACK ]--------#
screen.fill((0,0,0))
#--------[ LOOK FOR INPUT EVENTS ]--------#
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
pause = not pause
#--------[ GET EXERCISE BASED ON TIME ]--------#
exercise_current = []
exercise_next = []
for i in range(len(routine)):
if timeToSec(routine[i][0]) <= timer:
exercise_current = routine[i]
exercise_next = routine[i+1]
#--------[ DRAW EXERCISE NAME ]--------#
if int(exercise_current[3]) > 0:
infoTextStr = '{0}kg {1}'.format(exercise_current[3], exercise_current[2])
else:
infoTextStr = '{0}'.format(exercise_current[2])
infoText = fontMid.render(infoTextStr, 1, (255,255,255,255))
screen.blit(infoText, infoText.get_rect(center=( screen.get_rect().centerx, screen.get_rect().centery*0.45 )))
#--------[ DRAW MAIN STOPWATCH ]--------#
if timer < timeToSec(exercise_current[0]) + int(exercise_current[1]):
color = (255, 0, 0, 255)
else:
color = (255, 255, 255, 255)
timerText = fontLarge.render(secToTime(timer), 1, color)
screen.blit(timerText, timerText.get_rect(center=screen.get_rect().center))
#--------[ DRAW SET AND REP NUMBERS ]--------#
infoTextStr = 'Set: {0} Reps: {1}'.format(exercise_current[4], exercise_current[5])
infoText = fontSmall.render(infoTextStr, 1, (255,255,255,255))
screen.blit(infoText, infoText.get_rect(center=( screen.get_rect().centerx, screen.get_rect().centery*1.5 )))
#--------[ DRAW NEXT EXERCISE ]--------#
if int(exercise_next[3]) > 0:
infoTextStr = 'Next: {0}kg {1}'.format(exercise_next[3], exercise_next[2])
else:
infoTextStr = 'Next: {0}'.format(exercise_next[2])
infoText = fontTiny.render(infoTextStr, 1, (255,255,255,255))
screen.blit(infoText, infoText.get_rect(center=( screen.get_rect().centerx*1.5, screen.get_rect().centery*1.8 )))
if pause:
color = (255,255,255,128)
pygame.draw.rect(screen, color, pygame.Rect(32, 32, 64, 128))
pygame.draw.rect(screen, color, pygame.Rect(128, 32,64, 128))
pass
#--------[ UPDATE DISPLAY BUFFER ]--------#
pygame.display.flip()
#--------[ PLAY DING SOUNDS ]--------#
if not pause and exercise_next != routine[-1]:
if timer == timeToSec(exercise_current[0]):
pygame.mixer.Sound.play(soundDong)
if timer >= timeToSec(exercise_next[0])-4:
pygame.mixer.Sound.play(soundDing)
#--------[ WAIT FOR NEXT FRAME ]--------#
time.sleep(1.0 - (time_start-time.time()))
if not pause:
timer +=1
#--------[ END FRAME ]--------#
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
sys.exit()
screen.fill((0,0,0))
infoTextStr = 'Total Volume:'
infoText = fontMid.render(infoTextStr, 1, (255,255,255,255))
screen.blit(infoText, infoText.get_rect(center=( screen.get_rect().centerx, screen.get_rect().centery*0.45 )))
volume = 0
for i in range(len(routine)):
volume += int(routine[i][3]) * int(routine[i][5])
timerTextStr = '{0}kg'.format(volume)
timerText = fontLarge.render(timerTextStr, 1, (255,255,255,255))
screen.blit(timerText, timerText.get_rect(center=screen.get_rect().center))
pygame.display.flip()
time.sleep(0.5)

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

21
makefile Normal file
View File

@ -0,0 +1,21 @@
##
# Fitness
#
# @file
# @version 0.1
all:
echo "Run: make install"
install:
sudo rm -rf /opt/fitness
sudo mkdir /opt/fitness
sudo cp * /opt/fitness
sudo cp fitness.desktop /usr/share/applications/
rm -rf ~/.local/share/fitness
mkdir -p ~/.local/share/fitness
cp routine.csv ~/.local/share/fitness/
# end

32
routine.csv Normal file
View File

@ -0,0 +1,32 @@
time,highlight,exercise,weight,set,rep
00:00:00,10,Squat,32,1,10
00:00:30,10,Bridges,0,1,10
00:00:45,10,Halos,28,1,10
00:01:15,10,Hinges,0,1,10
00:01:30,10,Farmers Carry,36,1,2
00:02:30,10,Squat,32,2,10
00:03:00,10,Bridges,0,2,10
00:03:15,10,Halos,28,2,10
00:03:45,10,Hinges,0,2,10
00:04:00,10,Loaded Carry,32,2,2
00:05:00,10,Squat,32,3,10
00:05:30,10,Bridges,0,3,10
00:05:45,10,Halos,28,3,10
00:06:15,10,Hinges,0,3,10
00:06:30,10,Overhead Carry,28,3,2
00:09:00,20,R-Swings,32,1,10
00:10:00,20,L-Swings,32,2,10
00:11:00,20,R-Swings,32,3,10
00:12:00,20,L-Swings,32,4,10
00:13:00,20,R-Swings,32,5,10
00:14:00,20,L-Swings,28,6,10
00:15:00,20,R-Swings,32,7,10
00:16:00,20,L-Swings,28,8,10
00:17:00,20,R-Swings,32,9,10
00:18:00,20,L-Swings,32,10,10
00:20:00,60,Turkish Get-Up,36,1,2
00:22:00,60,Turkish Get-Up,36,2,2
00:24:00,60,Turkish Get-Up,36,3,2
00:26:00,60,Turkish Get-Up,36,4,2
00:28:00,60,Turkish Get-Up,36,5,2
00:29:00,0,Finish,0,0,0
1 time highlight exercise weight set rep
2 00:00:00 10 Squat 32 1 10
3 00:00:30 10 Bridges 0 1 10
4 00:00:45 10 Halos 28 1 10
5 00:01:15 10 Hinges 0 1 10
6 00:01:30 10 Farmers Carry 36 1 2
7 00:02:30 10 Squat 32 2 10
8 00:03:00 10 Bridges 0 2 10
9 00:03:15 10 Halos 28 2 10
10 00:03:45 10 Hinges 0 2 10
11 00:04:00 10 Loaded Carry 32 2 2
12 00:05:00 10 Squat 32 3 10
13 00:05:30 10 Bridges 0 3 10
14 00:05:45 10 Halos 28 3 10
15 00:06:15 10 Hinges 0 3 10
16 00:06:30 10 Overhead Carry 28 3 2
17 00:09:00 20 R-Swings 32 1 10
18 00:10:00 20 L-Swings 32 2 10
19 00:11:00 20 R-Swings 32 3 10
20 00:12:00 20 L-Swings 32 4 10
21 00:13:00 20 R-Swings 32 5 10
22 00:14:00 20 L-Swings 28 6 10
23 00:15:00 20 R-Swings 32 7 10
24 00:16:00 20 L-Swings 28 8 10
25 00:17:00 20 R-Swings 32 9 10
26 00:18:00 20 L-Swings 32 10 10
27 00:20:00 60 Turkish Get-Up 36 1 2
28 00:22:00 60 Turkish Get-Up 36 2 2
29 00:24:00 60 Turkish Get-Up 36 3 2
30 00:26:00 60 Turkish Get-Up 36 4 2
31 00:28:00 60 Turkish Get-Up 36 5 2
32 00:29:00 0 Finish 0 0 0