o
    PcH                     @   s~   d Z ddlZddlZddlZddlmZmZ ddlmZmZm	Z	m
Z
 ddlZddlZddlZG dd dZG dd deZdS )	zSClasses to convert FIT files to GPX, including tools to process Strava Bulk Export
    N)datetime	timedelta)DictUnionOptionalTuplec                   @   s   e Zd ZdZddefddZdejjde	e
eeeeef f fdd	Zdejjdee	e
eeee
ef f  fd
dZde
deejejf fddZ		dddZdd Zdd ZdS )	ConverterzOMain converter that holds the FIT > pd.DataFrame and pd.DataFrame > GPX methodsF
status_msgc                 C   s   || _ g d| _g d| _dS )zMain constructor for StravaConverter
        Parameters:
            status_msg (bool): Option to have the Converter print to console with status messages,
            such as number of files converted.
        )latitude	longitudelap	timestampaltitudeenhanced_altitudetemperature
heart_ratecadencespeedenhanced_speedpower)number
start_timetotal_distancetotal_elapsed_time	max_speedmax_heart_rateavg_heart_rateN)r	   _colnames_points_colnames_laps)selfr	    r    =/var/www/html/gps/gps/lib/python3.10/site-packages/fit2gpx.py__init__   s   
zConverter.__init__framereturnc                 C   s4   i }| j dd D ]}||r||||< q	|S )zWExtract some data from a FIT frame representing a lap and return it as a dict.
           N)r   	has_field	get_valuer   r#   datafieldr    r    r!   _get_fit_laps6   s   
zConverter._get_fit_lapsc                 C   s   i }| dr| dsdS |ddu r|ddu rdS |dd |d< |dd |d< | jdd D ]}| |rE||||< q7|S )z`Extract some data from an FIT frame representing a track point and return it as a dict.
        position_latposition_longNgllfAr
   r      )r&   r'   r   r(   r    r    r!   _get_fit_pointsE   s   
zConverter._get_fit_pointsfnamec                 C   s
  t j|d }| dkrtjdg }g }d}t|C}|D ]8}t|tj	j
rZ|jdkrC| |}|durB||d< || q"|jdkrZ| |}	||	d< ||	 |d7 }q"W d   n1 sew   Y  tj|| jd}
|
jdd	d
 tj|| jd}|
|fS )a<  Takes the path to a FIT file and returns two Pandas DataFrames for lap data and point data
        Parameters:
            fname (str): string representing file path of the FIT file
        Returns:
            dfs (tuple): df containing data about the laps , df containing data about the individual points.
        r%   .fitInput file must be a .FIT file.recordNr   r   columnsTinplace)ospathsplitextlower	fitdecode
exceptionsFitHeaderError	FitReader
isinstancerecordsFitDataMessagenamer/   appendr+   pd	DataFramer   	set_indexr   )r   r0   input_extensiondata_points	data_lapslap_nofit_filer#   single_point_datasingle_lap_datadf_laps	df_pointsr    r    r!   fit_to_dataframes^   s6   





zConverter.fit_to_dataframesr
   r   Nc
              	      s$  ||g}
|r|
 | |r|
 | t fdd|
D r!tdtj }tj }|j | tj }|j	 | ||jd _
|	|jd _t|sO|nd|jd _||jd _ jD ]1}tjj j||f  j||f |r{t j||f nd|r j||f ndd}|j | q^|S )a  
        Convert a pandas dataframe to gpx
        Parameters:
            df_points (pd.DataFrame): pandas dataframe containing at minimum lat and long info of points
            col_alt (str): name of the altitudes column
            col_time (str): name of the time column
            col_long (str): name of the longitudes column
            col_lat (str): name of the latitudes column
            gpx_name (str): name for the gpx track (note is not the same as the file name)
            gpx_desc (str): description for the gpx track
            gpx_type : activity type for the gpx track (can be str, or int)
            gpx_link (str): link to the gpx activity
        c                 3   s    | ]}| j vV  qd S Nr4   ).0elemrP   r    r!   	<genexpr>   s    z-Converter.dataframe_to_gpx.<locals>.<genexpr>zThe input dataframe must consist of point coordinates in longitude and latitude. Ideally, it should be the df_points output from the fit_to_dataframes() method.r   N)r
   r   time	elevation)rD   anyKeyErrorgpxpygpxGPXGPXTracktracksGPXTrackSegmentsegmentsrC   typerE   isnadescriptionlinkindexGPXTrackPointloc	Timestamppoints)r   rP   col_latcol_longcol_timecol_altgpx_namegpx_descgpx_linkgpx_typecols_to_checkr\   	gpx_trackgpx_segmentidxtrack_pointr    rU   r!   dataframe_to_gpx   s2   





zConverter.dataframe_to_gpxc                 C   s   t j|d }|dkrtdt j|d }|dkr td| |\}}ddg}|D ]#}||  dkrP|d	|   dkrP|| j|d	|  d
d q-| j|ddddd}	t	|d}
|

|	  W d   |	S 1 ssw   Y  |	S )zMethod to convert a FIT file into a GPX file
        Parameters:
            f_in (str): file path to FIT activity
            f_out (str): file path to save the converted FIT file
        r%   r1   r2   .gpxz Output file must be a .gpx file.r   r   r   	enhanced_Tr6   r
   r   r   rP   rk   rl   rm   rn   wN)r8   r9   r:   	Exception	TypeErrorrQ   countfillnarx   openwriteto_xml)r   f_inf_outrH   output_extensionrO   rP   enhanced_fieldsr*   r\   fr    r    r!   
fit_to_gpx   s2   &	
zConverter.fit_to_gpxc                 C   s   |d dkr
|d7 }|r|d dkr|d7 }t j|s!t | dd t |D }|D ]}| j|| |t j|d  d d q-| jrQtt	| d d	S d	S )
zMethod to convert all FIT files in a directory to GPX files
        Parameters:
            dir_in (str): path to directory with all FIT activities
            dir_out (str): path to directory to save the converted FIT files to
          /c                 S      g | ]
}d |  v r|qS r1   r;   rS   r   r    r    r!   
<listcomp>       z-Converter.fit_to_gpx_bulk.<locals>.<listcomp>r   ry   )r   r   z" files converted from .fit to .gpxN)
r8   r9   isdirmkdirlistdirr   r:   r	   printlen)r   dir_indir_out	fit_files
f_activityr    r    r!   fit_to_gpx_bulk   s   
zConverter.fit_to_gpx_bulk)F)r
   r   NNNNNN)__name__
__module____qualname____doc__boolr"   r<   rA   rB   r   strr   floatr   r   intr+   r   r/   r   rE   rF   rQ   rx   r   r   r    r    r    r!   r      s    
%


)
8'r   c                       s:   e Zd ZdZd fdd	Zdd Zdd Zd	d
 Z  ZS )StravaConverterzRConverter to use when converting .FIT files from Strava data download to GPX filesNc                    s   t    |d dkr|d7 }|r|d dkr|d7 }|s!|d }dt|vs0tj|d s4tdtj|s?t| || _|| _	| jd | _
dS )	a1  Main constructor for StravaConverter
        Parameters:
            dir_in (str): path to main strava data download folder
            dir_out (str): path to directory to save the converted FIT files to.
              If not provided, saves to an 'activities_gpx' directory in the main directory
        r   r   zactivities_gpx/zactivities.csv
activitieszThe input directory must be the main Strava data download directory, i.e. must contain activities.csv and have a sub directory named "activities".zactivities/N)superr"   r8   r   r9   r   r}   r   _dir_in_dir_out_dir_activities)r   r   r   	__class__r    r!   r"     s   

zStravaConverter.__init__c              
      s  t dd t jD } fddt jD }|D ]G}|dd}|t jv r-qt|d#}t|d}t|| W d	   n1 sJw   Y  W d	   n1 sYw   Y  t	| q j
rt t j|kr|tt | d
 d	S td d	S d	S )zKMethod to unzip .gz files to their native format (e.g. gpx, tcx, fit, etc.)c                 S   s   h | ]	}| d d qS ).r   )splitr   r    r    r!   	<setcomp>1  s    z3StravaConverter.unzip_activities.<locals>.<setcomp>c                    s   g | ]}d |v r j | qS ).gz)r   r   r   r    r!   r   4  s    z4StravaConverter.unzip_activities.<locals>.<listcomp>r    rbwbNz  zipped files have been unzippedz0ERROR: Certain files have been deleted. Oopsies.)r   r8   r   r   replacegzipr   shutilcopyfileobjremover	   r   )r   cnt_activites	zip_pathspath_zip
path_unzipr   r   r    r   r!   unzip_activities.  s$   z StravaConverter.unzip_activitiesc              	   C   sb  t | jd d}dd t| jD }|D ]}| | j| \}}|j|d j	
| jdddf  }|d }|d	 }|d
 }	| sPt	|dd}t |	rXd}	n|	 sdt	|	dd}	||d |	d| d}
| jd|ddddd|
}| j| d }t|d}||  W d   n1 sw   Y  | jrtt| d qdS )znMethod to convert all FIT files in a directory to GPX files, adding metadata from Strava to GPX files
        /activities.csvr   c                 S   r   r   r   r   r    r    r!   r   W  r   z5StravaConverter.strava_fit_to_gpx.<locals>.<listcomp>Filenamer   NActivity IDActivity NameActivity DescriptionasciiignoreActivity Type"https://www.strava.com/activities/)ro   rr   rp   rq   r
   r   r   r   r{   ry   r|   zM files have been converted from .fit to .gpx files containing Strava metadatar    )rE   read_csvr   r   r8   r   r   rQ   rh   r   containsilocto_dictisasciiencoderc   rx   r   r   r   r   r	   r   r   )r   df_actsr   r   rO   rP   mdact_idact_nameact_descstrava_argsr\   path_outr   r    r    r!   strava_fit_to_gpxN  sH   (

z!StravaConverter.strava_fit_to_gpxc              	      sv   fddt  jD }t jd d}|D ]}|j|d j	| j
dddf  }|d }|d	 }|d
 }| sHt|dd}t|rPd}n| s\t|dd}t j| ddd}t|}	||	jd _|d |	jd _||	jd _d| |	jd _ j| d }
t|
d}||	  W d   n1 sw   Y   jrtt| d qdS )z[Method adds Strava metadata to default GPX files (i.e. files downloaded as GPX from Strava)c                    s(   g | ]}d |v r|t  jvr|qS )ry   )r8   r   r   r   r   r    r!   r     s   ( z7StravaConverter.add_metadata_to_gpx.<locals>.<listcomp>r   r   r   r   Nr   r   r   r   r   rzutf-8)encodingr   r   ry   r|   z+ .gpx files have had Strava metadata added.)r8   r   r   rE   r   r   r   rh   r   r   r   r   r   r   rc   r   r[   parser_   rC   rb   rd   re   r   r   r   r	   r   r   )r   	gpx_filesr   gpx_pathr   r   r   r   f_gpxr\   r   r   r    r   r!   add_metadata_to_gpx  s6   (

z#StravaConverter.add_metadata_to_gpxrR   )	r   r   r   r   r"   r   r   r   __classcell__r    r    r   r!   r   
  s    ! ;r   )r   r8   r   r   r   r   typingr   r   r   r   pandasrE   	gpxpy.gpxr[   r<   r   r   r    r    r    r!   <module>   s     }