From 4904db724f111933083a423e13d14bb53cc8e391 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 5 Nov 2019 18:14:43 +0100 Subject: [PATCH] initial version of form working --- rowers/forms.py | 163 ++++++++++++++------------- rowers/templates/embedded_video.html | 27 ++++- rowers/views/statements.py | 129 +++++++++++---------- rowers/views/workoutviews.py | 45 ++++++-- 4 files changed, 209 insertions(+), 155 deletions(-) diff --git a/rowers/forms.py b/rowers/forms.py index 18434a88..ce4faf29 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -51,6 +51,11 @@ class FlexibleDecimalField(forms.DecimalField): value = value.replace('.', '').replace(',', '.') return super(FlexibleDecimalField, self).to_python(value) +# Video Analysis creation form +class VideoAnalysisCreateForm(forms.Form): + url = forms.CharField(max_length=255,required=True,label='YouTube Video URL') + delay = forms.IntegerField(initial=0,label='Delay (seconds)') + # BillingForm form class BillingForm(forms.Form): amount = FlexibleDecimalField(required=True,decimal_places=2, @@ -59,7 +64,7 @@ class BillingForm(forms.Form): payment_method_nonce = forms.CharField(max_length=255,required=True) paymenttype = forms.CharField(max_length=255,required=True) tac= forms.BooleanField(required=True,initial=False) - + # login form class LoginForm(forms.Form): @@ -73,8 +78,8 @@ class SearchForm(forms.Form): attrs={'placeholder': 'keyword or leave empty'}), label='Filter by Keyword') - - + + # simple form for Contact page. Sends email to info@rowsandall.com class EmailForm(forms.Form): firstname = forms.CharField(max_length=255) @@ -107,7 +112,7 @@ class MetricsForm(forms.Form): avghr = forms.IntegerField(required=False,label='Average Heart Rate') avgpwr = forms.IntegerField(required=False,label='Average Power') avgspm = forms.FloatField(required=False,label='Average SPM') - + # Upload the CrewNerd Summary CSV class CNsummaryForm(forms.Form): file = forms.FileField(required=True,validators=[must_be_csv]) @@ -120,7 +125,7 @@ class SummaryStringForm(forms.Form): class TeamInviteCodeForm(forms.Form): code = forms.CharField(max_length=10,label='Team Code', ) - + # Used for testing the POST API for StrokeData class StrokeDataForm(forms.Form): strokedata = forms.CharField(label='payload',widget=forms.Textarea) @@ -133,7 +138,7 @@ class ImageForm(forms.Form): def __init__(self, *args, **kwargs): from django.forms.widgets import HiddenInput super(ImageForm, self).__init__(*args, **kwargs) - + # The form used for uploading images class CourseForm(forms.Form): @@ -147,9 +152,9 @@ class CourseForm(forms.Form): def __init__(self, *args, **kwargs): from django.forms.widgets import HiddenInput super(CourseForm, self).__init__(*args, **kwargs) - - -# The form used for uploading files + + +# The form used for uploading files class DocumentsForm(forms.Form): title = forms.CharField(required=False) file = forms.FileField(required=False, @@ -157,7 +162,7 @@ class DocumentsForm(forms.Form): workouttype = forms.ChoiceField(required=True, choices=Workout.workouttypes) - + boattype = forms.ChoiceField(required=True, choices=mytypes.boattypes, label = "Boat Type") @@ -181,7 +186,7 @@ from rowers.utils import ( defaultleft,defaultmiddle ) - + # Form to change Workflow page layout class WorkFlowLeftPanelForm(forms.Form): @@ -212,14 +217,14 @@ class WorkFlowLeftPanelForm(forms.Form): self.base_fields['leftpanel'].initial=panels else: panels = defaultleft - - + + super(WorkFlowLeftPanelForm,self).__init__(*args, **kwargs) - + class WorkFlowMiddlePanelForm(forms.Form): panels = defaultmiddle - + middlepanel = forms.MultipleChoiceField( label='', @@ -237,7 +242,7 @@ class WorkFlowMiddlePanelForm(forms.Form): # 'css/uid-manage-form.css'], } js = ['/admin/jsi18n/'] - + def __init__(self, *args, **kwargs): if 'instance' in kwargs: r = kwargs.pop('instance') @@ -245,7 +250,7 @@ class WorkFlowMiddlePanelForm(forms.Form): self.base_fields['middlepanel'].initial=panels else: panels = defaultmiddle - + super(WorkFlowMiddlePanelForm,self).__init__(*args, **kwargs) class WorkFlowLeftPanelElement(forms.Form): @@ -265,8 +270,8 @@ class WorkFlowMiddlePanelElement(forms.Form): choices=panelchoices, initial='None', ) - - + + # The form to indicate additional actions to be performed immediately # after a successful upload @@ -359,7 +364,7 @@ class TeamUploadOptionsForm(forms.Form): class Meta: fields = ['make_plot','plottype'] - + # This form is used on the Workout Split page class WorkoutSplitForm(forms.Form): splitchoices = ( @@ -386,7 +391,7 @@ class WorkoutSplitForm(forms.Form): label='Split Mode', choices=splitchoices, widget = forms.CheckboxSelectMultiple()) - + # This form is used on the Analysis page to add a custom distance/time # trial and predict the pace from rowers.utils import rankingdistances,rankingdurations @@ -427,14 +432,14 @@ class PredictedPieceForm(forms.Form): choices=rankingdistancechoices,initial=rankingdistances, label='Ranking Distances' ) - + trankingdurations = forms.MultipleChoiceField( required=True, choices=rankingdurationchoices, initial=[a for a,b in rankingdurationchoices], label='Ranking Durations' ) - + value = forms.FloatField(initial=10,label='Free ranking piece (minutes)') pieceunit = forms.ChoiceField(required=True,choices=unitchoices, initial='t',label='Unit') @@ -451,17 +456,17 @@ class PredictedPieceFormNoDistance(forms.Form): thetuple = (timestr,timestr) rankingdurationchoices.append(thetuple) - + trankingdurations = forms.MultipleChoiceField( required=True, choices=rankingdurationchoices, initial=[a for a,b in rankingdurationchoices], label='Ranking Durations' ) - + value = forms.FloatField(initial=10,label='Free ranking piece') - + # On the Geeky side, to update stream information for river dwellers class UpdateStreamForm(forms.Form): unitchoices = ( @@ -545,16 +550,16 @@ class FitnessMetricForm(forms.Form): ('rower','indoor rower'), ('water','on the water') ) - + mode = forms.ChoiceField(required=True, choices=modechoices, initial='rower', label='Workout Mode' ) - + class Meta: fields = ['startdate','enddate','mode'] - + class SessionDateShiftForm(forms.Form): shiftstartdate = forms.DateField( initial=timezone.now(), @@ -563,7 +568,7 @@ class SessionDateShiftForm(forms.Form): class Meta: fields = ['shiftstartdate'] - + # Form used to select workouts for the past N days class DeltaDaysForm(forms.Form): deltadays = forms.IntegerField(initial=7,required=False,label='') @@ -599,7 +604,7 @@ class RegistrationFormTermsOfService(RegistrationForm): tos = forms.BooleanField(widget=forms.CheckboxInput, label='I have read and agree to the Terms of Service', error_messages={'required': "You must agree to the terms to register"}) - + class RegistrationFormUniqueEmail(RegistrationFormTermsOfService): @@ -631,20 +636,20 @@ class RegistrationFormSex(RegistrationFormUniqueEmail): adaptivecategories = mytypes.adaptivetypes thisyear = timezone.now().year - + birthdate = forms.DateTimeField( widget=SelectDateWidget(years=range(1900,thisyear)), initial = datetime.date(year=1970, month=4, day=15)) - + def clean_birthdate(self): dob = self.cleaned_data['birthdate'] age = (timezone.now() - dob).days/365 if age < 16: raise forms.ValidationError('Must be at least 16 years old to register') return self.cleaned_data['birthdate'] - + sex = forms.ChoiceField(required=False, choices=sexcategories, initial='not specified', @@ -655,10 +660,10 @@ class RegistrationFormSex(RegistrationFormUniqueEmail): adaptiveclass = forms.ChoiceField(label='Adaptive Classification', choices=adaptivecategories,initial='None',required=False) - + # def __init__(self, *args, **kwargs): # self.fields['sex'].initial = 'not specified' - + # Time field supporting microseconds. Not used, I believe. class MyTimeField(forms.TimeField): @@ -673,7 +678,7 @@ class PowerIntervalUpdateForm(forms.Form): ('pace','Pace'), ('work','Work per Stroke'), ) - + pace = forms.DurationField(required=False,label='Pace (/500m)') power = forms.IntegerField(required=False,label='Power (W)') work = forms.IntegerField(required=False,label='Work per Stroke (J)') @@ -681,10 +686,10 @@ class PowerIntervalUpdateForm(forms.Form): required=True, initial='power', label='Use') - + # Form used to update interval stats class IntervalUpdateForm(forms.Form): - + def __init__(self, *args, **kwargs): typechoices = ( (1,'single time'), @@ -733,7 +738,7 @@ class HistoForm(forms.Form): includereststrokes = forms.BooleanField(initial=False,label='Include Rest Strokes',required=False) histoparam = forms.ChoiceField(choices=parchoices,initial='power', label='Metric') - + class AnalysisOptionsForm(forms.Form): modality = forms.ChoiceField(choices=workouttypes, label='Workout Type', @@ -744,8 +749,8 @@ class AnalysisOptionsForm(forms.Form): rankingonly = forms.BooleanField(initial=False, label='Only Ranking Pieces', required=False) - - + + # form to select modality and boat type for trend flex class TrendFlexModalForm(forms.Form): modality = forms.ChoiceField(choices=workouttypes, @@ -759,7 +764,7 @@ class TrendFlexModalForm(forms.Form): required=False) - + # This form sets options for the summary stats page class StatsOptionsForm(forms.Form): includereststrokes = forms.BooleanField(initial=False,label='Include Rest Strokes',required=False) @@ -772,13 +777,13 @@ class StatsOptionsForm(forms.Form): initial = mytypes.waterboattype) - + def __init__(self, *args, **kwargs): super(StatsOptionsForm, self).__init__(*args,**kwargs) for type in mytypes.checktypes: self.fields[type] = forms.BooleanField(initial=True,required=False) - + class PlanSelectForm(forms.Form): plan = forms.ModelChoiceField(queryset=PaidPlan.objects.all(), widget=forms.RadioSelect,required=True) @@ -812,10 +817,10 @@ class PlanSelectForm(forms.Form): "price","shortname" ) - + class CourseSelectForm(forms.Form): course = forms.ModelChoiceField(queryset=GeoCourse.objects.all()) - + class WorkoutMultipleCompareForm(forms.Form): workouts = forms.ModelMultipleChoiceField( queryset=Workout.objects.filter(), @@ -824,8 +829,8 @@ class WorkoutMultipleCompareForm(forms.Form): def __init__(self, *args, **kwargs): super(WorkoutMultipleCompareForm,self).__init__(*args,**kwargs) self.fields['workouts'].queryset = Workout.objects.filter() - - + + class PlannedSessionMultipleCloneForm(forms.Form): plannedsessions = forms.ModelMultipleChoiceField( queryset=PlannedSession.objects.all(), @@ -867,7 +872,7 @@ class AnalysisChoiceForm(forms.Form): ) axchoices = dict((x,y) for x,y in axchoices) axchoices = list(sorted(axchoices.items(), key = lambda x:x[1])) - + yaxchoices = list((ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time']) yaxchoices = dict((x,y) for x,y in yaxchoices) @@ -877,7 +882,7 @@ class AnalysisChoiceForm(forms.Form): ('line','Line Plot'), ('scatter','Scatter Plot'), ) - + yaxchoices2 = list( (ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time'] ) @@ -914,7 +919,7 @@ class AnalysisChoiceForm(forms.Form): palette = forms.ChoiceField(choices=palettechoices, label = 'Color Scheme', initial='monochrome_blue') - + spmmin = forms.FloatField(initial=15, required=False,label = 'Min SPM') spmmax = forms.FloatField(initial=55, @@ -927,7 +932,7 @@ class AnalysisChoiceForm(forms.Form): includereststrokes = forms.BooleanField(initial=False, required=False, label='Include Rest Strokes') - + class BoxPlotChoiceForm(forms.Form): yparam = forms.ChoiceField(choices=parchoices,initial='spm', label='Metric') @@ -971,7 +976,7 @@ class MultiFlexChoiceForm(forms.Form): palette = forms.ChoiceField(choices=palettechoices, label = 'Color Scheme', initial='monochrome_blue') - + class ChartParamChoiceForm(forms.Form): plotchoices = ( ('line','Line Plot'), @@ -993,7 +998,7 @@ class FusionMetricChoiceForm(ModelForm): class Meta: model = Workout fields = [] - + posneg = ( ('pos','Workout 2 starts after Workout 1'), ('neg','Workout 2 starts before Workout 1'), @@ -1021,14 +1026,14 @@ class FusionMetricChoiceForm(ModelForm): formaxlabels2.pop(label) except KeyError: pass - + metricchoices = list(sorted(formaxlabels2.items(), key = lambda x:x[1])) self.fields['columns'].choices = metricchoices class PlannedSessionSelectForm(forms.Form): def __init__(self, sessionchoices, *args, **kwargs): - initialsession = kwargs.pop('initialsession',None) + initialsession = kwargs.pop('initialsession',None) super(PlannedSessionSelectForm, self).__init__(*args,**kwargs) self.fields['plannedsession'] = forms.ChoiceField( @@ -1040,7 +1045,7 @@ class PlannedSessionSelectForm(forms.Form): class WorkoutSessionSelectForm(forms.Form): - + def __init__(self, workoutdata, *args, **kwargs): super(WorkoutSessionSelectForm, self).__init__(*args, **kwargs) @@ -1053,7 +1058,7 @@ class WorkoutSessionSelectForm(forms.Form): ) - + class RaceResultFilterForm(forms.Form): boatclasses = (type for type in mytypes.workouttypes if type[0] in mytypes.rowtypes) boatclassinitial = [t for t in mytypes.rowtypes] @@ -1069,7 +1074,7 @@ class RaceResultFilterForm(forms.Form): ) adaptivecategories = mytypes.adaptivetypes - + sex = forms.MultipleChoiceField( choices=sexchoices, initial=['male','female','mixed'], @@ -1081,7 +1086,7 @@ class RaceResultFilterForm(forms.Form): initial=boatclassinitial, label='Boat/Erg Class', widget=forms.CheckboxSelectMultiple()) - + boattype = forms.MultipleChoiceField( choices=boattypes, label='Boat Type', @@ -1106,7 +1111,7 @@ class RaceResultFilterForm(forms.Form): def __init__(self, *args, **kwargs): if 'records' in kwargs: records = kwargs.pop('records',None) - + super(RaceResultFilterForm,self).__init__(*args,**kwargs) if records: @@ -1135,7 +1140,7 @@ class RaceResultFilterForm(forms.Form): if choice[0] in theboatclasses: boatclasschoices.append(choice) self.fields['boatclass'].choices = boatclasschoices - + # boattype try: theboattypees = [record.boattype for record in records] @@ -1151,7 +1156,7 @@ class RaceResultFilterForm(forms.Form): if choice[0] in theboattypees: boattypechoices.append(choice) self.fields['boattype'].choices = boattypechoices - + # weightcategory theweightcategoryes = [record.weightcategory for record in records] theweightcategoryes = list(set(theweightcategoryes)) @@ -1177,7 +1182,7 @@ class RaceResultFilterForm(forms.Form): if choice[0] in theadaptivecategoryes: adaptivecategorychoices.append(choice) self.fields['adaptivecategory'].choices = adaptivecategorychoices - + class WorkoutRaceSelectForm(forms.Form): # evaluate_after = forms.TimeField( # input_formats=['%H:%M:%S.%f', @@ -1188,7 +1193,7 @@ class WorkoutRaceSelectForm(forms.Form): # '%M'], # label = 'Only Evaluate After:', # required=False) - + def __init__(self, workoutdata,entries, *args, **kwargs): super(WorkoutRaceSelectForm, self).__init__(*args, **kwargs) @@ -1206,7 +1211,7 @@ class WorkoutRaceSelectForm(forms.Form): initial = entries['initial'], ) -# self.fields['evaluate_after'] = +# self.fields['evaluate_after'] = # form to send messages to team members class TeamMessageForm(forms.Form): @@ -1256,7 +1261,7 @@ class PlannedSessionTeamMemberForm(forms.Form): members = forms.ModelMultipleChoiceField( queryset=Rower.objects.all(), widget=forms.CheckboxSelectMultiple()) - + def __init__(self, thesession, *args, **kwargs): super(PlannedSessionTeamMemberForm,self).__init__(*args,**kwargs) @@ -1283,13 +1288,13 @@ class VirtualRaceSelectForm(forms.Form): ('my','My Races'), ('all','All Races'), ) - + regattatype = forms.ChoiceField( label='Type', choices = regattatypechoices, initial = 'upcoming', ) - + country = forms.ChoiceField( label='Country', choices = get_countries() @@ -1311,7 +1316,7 @@ class FlexOptionsForm(forms.Form): ) plottype = forms.ChoiceField(choices=plotchoices,initial='line', label='Chart Type') - + class ForceCurveOptionsForm(forms.Form): includereststrokes = forms.BooleanField(initial=False, required = False, label='Include Rest Strokes') @@ -1322,15 +1327,15 @@ class ForceCurveOptionsForm(forms.Form): ) plottype = forms.ChoiceField(choices=plotchoices,initial='line', label='Individual Stroke Chart Type') - - + + class FlexAxesForm(forms.Form): axchoices = list( (ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','None'] ) axchoices = dict((x,y) for x,y in axchoices) axchoices = list(sorted(axchoices.items(), key = lambda x:x[1])) - + yaxchoices = list((ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time']) yaxchoices = dict((x,y) for x,y in yaxchoices) @@ -1355,9 +1360,9 @@ class FlexAxesForm(forms.Form): super(FlexAxesForm, self).__init__(*args, **kwargs) rower = Rower.objects.get(user=request.user) - + axchoicespro = ( - ('',ax[1]) if ax[4] == 'pro' and ax[0] else (ax[0],ax[1]) for ax in axes + ('',ax[1]) if ax[4] == 'pro' and ax[0] else (ax[0],ax[1]) for ax in axes ) axchoicesbasicx = [] @@ -1375,12 +1380,8 @@ class FlexAxesForm(forms.Form): if ax[0] not in ['cumdist','distance','time']: axchoicesbasicy.insert(0,('None',ax[1]+' (PRO)')) - + if rower.rowerplan == 'basic': self.fields['xaxis'].choices = axchoicesbasicx self.fields['yaxis1'].choices = axchoicesbasicy self.fields['yaxis2'].choices = axchoicesbasicy - - - - diff --git a/rowers/templates/embedded_video.html b/rowers/templates/embedded_video.html index fff9c356..c0ceff75 100644 --- a/rowers/templates/embedded_video.html +++ b/rowers/templates/embedded_video.html @@ -45,6 +45,11 @@ seconds +
  • + SPM + + +
  • Boat Speed @@ -70,12 +75,13 @@ var boatspeed = data["boatspeed"]; var latitude = data["latitude"]; var longitude = data["longitude"]; + var spm = data["spm"] function onYouTubeIframeAPIReady() { player = new YT.Player('player', { height: '390', width: '640', - videoId: '9dLFC2q9RWc', + videoId: '{{ video_id }}', events: { 'onReady': onPlayerReady } @@ -92,8 +98,10 @@ velo = boatspeed[Math.round(videotime)]; lat = latitude[Math.round(videotime)]; lon = longitude[Math.round(videotime)]; + strokerate = spm[Math.round(videotime)]; document.getElementById("time").innerHTML = Math.round(videotime); document.getElementById("speed").innerHTML = velo; + document.getElementById("spm").innerHTML = strokerate; var newLatLng = new L.LatLng(lat, lon); marker.setLatLng(newLatLng); } @@ -117,6 +125,23 @@
  • +
  • + {% if not video_id %} +

    + To load your video, paste the URL of your YouTube video in the form below, + and submit the form. +

    + {% endif %} +

    +

    + + {{ form.as_table }} +
    + {% csrf_token %} + +
    +

    +
  • {% endlanguage %} diff --git a/rowers/views/statements.py b/rowers/views/statements.py index 069bd438..20d848a8 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -58,7 +58,8 @@ from rowers.forms import ( RaceResultFilterForm,PowerIntervalUpdateForm,FlexAxesForm, FlexOptionsForm,DataFrameColumnsForm,OteWorkoutTypeForm, MetricsForm,DisqualificationForm,disqualificationreasons, - disqualifiers,SearchForm,BillingForm,PlanSelectForm + disqualifiers,SearchForm,BillingForm,PlanSelectForm, + VideoAnalysisCreateForm ) from django.urls import reverse, reverse_lazy @@ -80,7 +81,7 @@ from rowers.forms import ( UpdateStreamForm,WorkoutMultipleCompareForm,ChartParamChoiceForm, FusionMetricChoiceForm,BoxPlotChoiceForm,MultiFlexChoiceForm, TrendFlexModalForm,WorkoutSplitForm,WorkoutJoinParamForm, - AnalysisOptionsForm, AnalysisChoiceForm, + AnalysisOptionsForm, AnalysisChoiceForm, PlannedSessionMultipleCloneForm,SessionDateShiftForm,RowerTeamForm, ) from rowers.models import ( @@ -255,7 +256,7 @@ def getfavorites(r,row): workoutsource = row.workoutsource if 'speedcoach2' in row.workoutsource: workoutsource = 'speedcoach2' - + favorites = FavoriteChart.objects.filter(user=r, workouttype__in=matchworkouttypes).order_by("id") favorites2 = FavoriteChart.objects.filter(user=r, @@ -264,12 +265,12 @@ def getfavorites(r,row): favorites = favorites | favorites2 - + maxfav = len(favorites)-1 return favorites,maxfav - + def get_workout_default_page(request,id): if request.user.is_anonymous: return reverse('workout_view',kwargs={'id':id}) @@ -279,7 +280,7 @@ def get_workout_default_page(request,id): return reverse('workout_edit_view',kwargs={'id':id}) else: return reverse('workout_workflow_view',kwargs={'id':id}) - + def getrequestrower(request,rowerid=0,userid=0,notpermanent=False): userid = int(userid) @@ -288,12 +289,12 @@ def getrequestrower(request,rowerid=0,userid=0,notpermanent=False): if notpermanent == False: if rowerid == 0 and 'rowerid' in request.session: rowerid = request.session['rowerid'] - + if userid != 0: rowerid = 0 - + try: - + if rowerid != 0: r = Rower.objects.get(id=rowerid) elif userid != 0: @@ -301,7 +302,7 @@ def getrequestrower(request,rowerid=0,userid=0,notpermanent=False): r = getrower(u) else: r = getrower(request.user) - + except Rower.DoesNotExist: raise Http404("Rower doesn't exist") @@ -321,12 +322,12 @@ def getrequestplanrower(request,rowerid=0,userid=0,notpermanent=False): if notpermanent == False: if rowerid == 0 and 'rowerid' in request.session: rowerid = request.session['rowerid'] - + if userid != 0: rowerid = 0 - + try: - + if rowerid != 0: r = Rower.objects.get(id=rowerid) elif userid != 0: @@ -334,7 +335,7 @@ def getrequestplanrower(request,rowerid=0,userid=0,notpermanent=False): r = getrower(u) else: r = getrower(request.user) - + except Rower.DoesNotExist: raise Http404("Rower doesn't exist") @@ -374,20 +375,20 @@ def get_workout(id): def get_workout_permitted(user,id): w = get_workout(id) - + if (checkworkoutuser(user,w)==False): raise PermissionDenied("Access denied") - + return w - + def get_workout_permittedview(user,id): w = get_workout(id) - + if (checkworkoutuserview(user,w)==False): raise PermissionDenied("Access denied") - + return w - + def getvalue(data): perc = 0 total = 1 @@ -412,7 +413,7 @@ class SessionTaskListener(threading.Thread): self.redis = r self.pubsub = self.redis.pubsub() self.pubsub.subscribe(channels) - + def work(self, item): try: @@ -420,10 +421,10 @@ class SessionTaskListener(threading.Thread): total,done,id,session_key = getvalue(data) perc = int(100.*done/total) cache.set(id,perc,3600) - + except TypeError: pass - + def run(self): for item in self.pubsub.listen(): if item['data'] == "KILL": @@ -497,14 +498,14 @@ def remove_asynctask(request,id): oldtasks = request.session['async_tasks'] except KeyError: oldtasks = [] - + newtasks = [] for task in oldtasks: if id not in task[0]: newtasks += [(task[0],task[1])] request.session['async_tasks'] = newtasks - + def get_job_result(jobid): if settings.TESTING: return None @@ -522,7 +523,7 @@ def get_job_result(jobid): result = job.result except NoSuchJobError: return None - + return result verbose_job_status = { @@ -551,7 +552,7 @@ def get_job_status(jobid): job = celery_result.AsyncResult(jobid) jobresult = job.result - + if 'fail' in job.status.lower(): jobresult = '0' summary = { @@ -566,7 +567,7 @@ def get_job_status(jobid): status = job.status except AttributeError: status = job.get_status() - + summary = { 'status':status, 'result':job.result, @@ -611,7 +612,7 @@ def kill_async_job(request,id='aap'): cancel_job(id,connection=redis_connection) except NoSuchJobError: pass - + remove_asynctask(request,id) cache.delete(id) url = reverse(session_jobs_status) @@ -637,7 +638,7 @@ def raise_500(request): # try: # request.session['async_tasks'] += [(job.id,'long_test_task')] # except KeyError: -# request.session['async_tasks'] = [(job.id,'long_test_task')] +# request.session['async_tasks'] = [(job.id,'long_test_task')] # # url = reverse(session_jobs_status) # @@ -654,7 +655,7 @@ def raise_500(request): # try: # request.session['async_tasks'] += [(job.id,'long_test_task2')] # except KeyError: -# request.session['async_tasks'] = [(job.id,'long_test_task2')] +# request.session['async_tasks'] = [(job.id,'long_test_task2')] # # url = reverse(session_jobs_status) # @@ -689,7 +690,7 @@ def post_progress(request,id=None,value=0): else: # request method is not POST return HttpResponse('GET method not allowed',status=405) - + def get_all_queued_jobs(userid=0): r = StrictRedis() @@ -709,13 +710,13 @@ def get_all_queued_jobs(userid=0): 'function':'', 'meta':job.info, })) - + ids = [j.id for j in queue.jobs] ids += [j.id for j in queuehigh.jobs] ids += [j.id for j in queuelow.jobs] ids += [j.id for j in queuefailed.jobs] - + for id in ids: job = Job.fetch(id,connection=redis_connection) jobs.append( @@ -766,14 +767,14 @@ def get_stored_tasks_status(request): taskstatus.append(this_task_status) - + return taskstatus @login_required() def get_thumbnails(request,id): row = get_workout_permitted(request.user,id) - + r = getrower(request.user) result = request.user.is_authenticated and ispromember(request.user) if result: @@ -788,15 +789,15 @@ def get_thumbnails(request,id): favorites,maxfav = getfavorites(r,row) charts = [] - + charts = thumbnails_set(r,encoder.decode_hex(id),favorites) try: - if charts[0]['script'] == '': + if charts[0]['script'] == '': charts = [] except IndexError: charts = [] - + return JSONResponse(charts) def get_blog_posts(request): @@ -810,7 +811,7 @@ def get_blog_posts(request): 'title':blogpost.title, 'link':blogpost.link, } - + jsondata.append(thedict) return JSONResponse(jsondata) @@ -827,12 +828,12 @@ def get_blog_posts_old(request): blogs_json = [] except ConnectionError: pass - + blogposts = [] - + for postdata in blogs_json[0:3]: - + try: title = postdata['title']['rendered'].encode( 'ascii','xmlcharrefreplace') @@ -841,7 +842,7 @@ def get_blog_posts_old(request): title = postdata['title']['rendered'].encode( 'ascii','xmlcharrefreplace').decode('utf-8') - + thedict = { 'title': title, # 'author': '', @@ -874,7 +875,7 @@ Hoi """ } - + return JSONResponse([object,object]) @login_required() @@ -935,7 +936,7 @@ def get_my_teams(user): teams1 = therower.team.all() except AttributeError: teams1 = [] - + teams2 = Team.objects.filter(manager=user) teams = list(set(teams1).union(set(teams2))) except TypeError: @@ -960,10 +961,10 @@ def get_time(second): hours = int((second-24.*3600.*days)/3600.) % 24 minutes = int((second-3600.*(hours+24.*days))/60.) % 60 sec = int(second-3600.*(hours+24.*days)-60.*minutes) % 60 - microsecond = int(1.0e6*(second-3600.*(hours+24.*days)-60.*minutes-sec)) + microsecond = int(1.0e6*(second-3600.*(hours+24.*days)-60.*minutes-sec)) return datetime.time(hours,minutes,sec,microsecond) - + # get the workout ID from the SportTracks URI def getidfromsturi(uri,length=8): return uri[len(uri)-length:] @@ -975,7 +976,7 @@ def getidfromuri(uri): return m.group(2) - + from rowers.utils import ( geo_distance,serialize_list,deserialize_list,uniqify, str2bool,range_to_color_hex,absolute,myqueue,get_call, @@ -997,11 +998,11 @@ def iscoachmember(user): except Rower.DoesNotExist: r = Rower(user=user) r.save() - + result = user.is_authenticated and ('coach' in r.rowerplan) else: result = False - + return result def cancreateteam(user): @@ -1092,7 +1093,7 @@ def sendmail(request): messages.error(request,'You have to answer YES to the question') return HttpResponseRedirect('/rowers/email/') else: - return HttpResponseRedirect('/rowers/email/') + return HttpResponseRedirect('/rowers/email/') else: return HttpResponseRedirect('/rowers/email/') @@ -1106,7 +1107,7 @@ def add_workout_from_strokedata(user,importid,data,strokedata, workouttype = data['type'] except KeyError: workouttype = 'rower' - + if workouttype not in [x[0] for x in Workout.workouttypes]: workouttype = 'other' try: @@ -1128,14 +1129,14 @@ def add_workout_from_strokedata(user,importid,data,strokedata, rowdatetime = iso8601.parse_date(data['start_date']) except ParseError: rowdatetime = iso8601.parse_date(data['date']) - - + + try: c2intervaltype = data['workout_type'] - + except KeyError: c2intervaltype = '' - + try: title = data['name'] except KeyError: @@ -1177,7 +1178,7 @@ def add_workout_from_strokedata(user,importid,data,strokedata, spm = strokedata.loc[:,'spm'] except KeyError: spm = 0*dist2 - + try: hr = strokedata.loc[:,'hr'] except KeyError: @@ -1189,7 +1190,7 @@ def add_workout_from_strokedata(user,importid,data,strokedata, velo = 500./pace power = 2.8*velo**3 - + # save csv # Create data frame with all necessary data to write to csv df = pd.DataFrame({'TimeStamp (sec)':unixtime, @@ -1211,9 +1212,9 @@ def add_workout_from_strokedata(user,importid,data,strokedata, ' ElapsedTime (sec)':seconds }) - + df.sort_values(by='TimeStamp (sec)',ascending=True) - + timestr = strftime("%Y%m%d-%H%M%S") @@ -1249,11 +1250,11 @@ def add_workout_from_strokedata(user,importid,data,strokedata, dosummary=True ) - + return id,message - + def keyvalue_get_default(key,options,def_options): @@ -1288,5 +1289,3 @@ def trydf(df,aantal,column): import rowers.teams as teams from rowers.models import C2WorldClassAgePerformance - - diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index a492e6be..7e25ec74 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -12,6 +12,7 @@ from urllib.parse import urlparse, parse_qs def default(o): if isinstance(o, numpy.int64): return int(o) + if isinstance(o, numpy.int32): return int(o) raise TypeError def get_video_id(url): @@ -53,32 +54,59 @@ def workout_video_view(request,id=0): # get workout w = get_workout_permitted(request.user,id) + # get video ID and offset + if request.method == 'POST': + form = VideoAnalysisCreateForm(request.POST) + if form.is_valid(): + url = form.cleaned_data['url'] + delay = form.cleaned_data['delay'] + video_id = get_video_id(url) + else: + video_id = None + delay = 0 + else: + form = VideoAnalysisCreateForm() + video_id = None + delay = 0 + # get data - df = getsmallrowdata_db(['time','velo'],ids=[w.id]) + df = getsmallrowdata_db(['time','velo','spm'],ids=[w.id], + workstrokesonly=False,doclean=False,compute=False) df['time'] = (df['time']-df['time'].min())/1000. df.sort_values(by='time',inplace=True) + + df.set_index(pd.to_timedelta(df['time'],unit='s'),inplace=True) df2 = df.resample('1s').mean().interpolate() + + + mask = df2['time'] < delay + df2 = df2.mask(mask).dropna() + df2['time'] = (df2['time']-df2['time'].min()) + boatspeed = (100*df2['velo']).astype(int)/100. + spm = (10*df2['spm']).astype(int)/10. coordinates = dataprep.get_latlon_time(w.id) + mask = coordinates['time'] < delay + coordinates = coordinates.mask(mask).dropna() + coordinates['time'] = coordinates['time']-coordinates['time'].min() coordinates.set_index(pd.to_timedelta(coordinates['time'],unit='s'),inplace=True) coordinates = coordinates.resample('1s').mean().interpolate() latitude = coordinates['latitude'] longitude = coordinates['longitude'] - # get video - url = "https://www.youtube.com/watch?time_continue=496&v=9dLFC2q9RWc" - video_id = get_video_id(url) - # create map mapscript, mapdiv = leaflet_chart_video(latitude,longitude, w.name) # bundle data - data = {'boatspeed':[ v for v in boatspeed.values], - 'latitude':[ l for l in latitude.values], - 'longitude':[ l for l in longitude.values]} + data = { + 'boatspeed':[ v for v in boatspeed.values], + 'latitude':[ l for l in latitude.values], + 'longitude':[ l for l in longitude.values], + 'spm':[ s for s in spm.values ] + } return render(request, 'embedded_video.html', @@ -89,6 +117,7 @@ def workout_video_view(request,id=0): 'mapscript': mapscript, 'mapdiv': mapdiv, 'video_id': video_id, + 'form':form, }) # Show the EMpower Oarlock generated Stroke Profile