feat: Implement Phase 1C.2: Multi-Format Support

This commit is contained in:
2025-09-18 15:04:09 -07:00
parent f7acfd7c78
commit ea96430ed4
4 changed files with 60 additions and 11 deletions

View File

@@ -1,8 +1,11 @@
package main package main
import ( import (
"encoding/csv"
"fmt" "fmt"
"log" "os"
"path/filepath"
"strconv"
"time" "time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -57,6 +60,7 @@ var (
// Flags for downloadActivitiesCmd // Flags for downloadActivitiesCmd
downloadFormat string downloadFormat string
outputDir string outputDir string
downloadOriginal bool
) )
func init() { func init() {
@@ -72,8 +76,9 @@ func init() {
activitiesCmd.AddCommand(getActivitiesCmd) activitiesCmd.AddCommand(getActivitiesCmd)
activitiesCmd.AddCommand(downloadActivitiesCmd) activitiesCmd.AddCommand(downloadActivitiesCmd)
downloadActivitiesCmd.Flags().StringVar(&downloadFormat, "format", "gpx", "Download format (gpx, tcx, csv)") downloadActivitiesCmd.Flags().StringVar(&downloadFormat, "format", "gpx", "Download format (gpx, tcx, fit, csv)")
downloadActivitiesCmd.Flags().StringVar(&outputDir, "output-dir", ".", "Output directory for downloaded files") downloadActivitiesCmd.Flags().StringVar(&outputDir, "output-dir", ".", "Output directory for downloaded files")
downloadActivitiesCmd.Flags().BoolVar(&downloadOriginal, "original", false, "Download original uploaded file")
activitiesCmd.AddCommand(searchActivitiesCmd) activitiesCmd.AddCommand(searchActivitiesCmd)
searchActivitiesCmd.Flags().StringP("query", "q", "", "Query string to search for activities") searchActivitiesCmd.Flags().StringP("query", "q", "", "Query string to search for activities")
@@ -180,9 +185,49 @@ func runDownloadActivity(cmd *cobra.Command, args []string) error {
return fmt.Errorf("not logged in: %w", err) return fmt.Errorf("not logged in: %w", err)
} }
if downloadFormat == "csv" {
activityDetail, err := garminClient.GetActivity(activityID)
if err != nil {
return fmt.Errorf("failed to get activity details for CSV export: %w", err)
}
filename := fmt.Sprintf("%d.csv", activityID)
outputPath := filename
if outputDir != "" {
outputPath = filepath.Join(outputDir, filename)
}
file, err := os.Create(outputPath)
if err != nil {
return fmt.Errorf("failed to create CSV file: %w", err)
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
// Write header
writer.Write([]string{"ActivityID", "ActivityName", "ActivityType", "StartTime", "Distance(km)", "Duration(s)", "Description"})
// Write data
writer.Write([]string{
fmt.Sprintf("%d", activityDetail.ActivityID),
activityDetail.ActivityName,
activityDetail.ActivityType,
activityDetail.Starttime.Format("2006-01-02 15:04:05"),
fmt.Sprintf("%.2f", activityDetail.Distance/1000),
fmt.Sprintf("%.0f", activityDetail.Duration),
activityDetail.Description,
})
fmt.Printf("Activity %d summary exported to %s\n", activityID, outputPath)
return nil
}
opts := garmin.DownloadOptions{ opts := garmin.DownloadOptions{
Format: downloadFormat, Format: downloadFormat,
OutputDir: outputDir, OutputDir: outputDir,
Original: downloadOriginal,
} }
fmt.Printf("Downloading activity %d in %s format to %s...\n", activityID, downloadFormat, outputDir) fmt.Printf("Downloading activity %d in %s format to %s...\n", activityID, downloadFormat, outputDir)

View File

@@ -331,9 +331,13 @@ func (c *Client) Upload(filePath string) error {
} }
// Download retrieves a file from Garmin Connect // Download retrieves a file from Garmin Connect
func (c *Client) Download(activityID string, filePath string) error { func (c *Client) Download(activityID string, format string, filePath string) error {
params := url.Values{} params := url.Values{}
params.Add("activityId", activityID) params.Add("activityId", activityID)
// Add format parameter if provided and not empty
if format != "" {
params.Add("format", format)
}
resp, err := c.ConnectAPI("/download-service/export", "GET", params, nil) resp, err := c.ConnectAPI("/download-service/export", "GET", params, nil)
if err != nil { if err != nil {

View File

@@ -306,16 +306,16 @@ func (c *Client) DownloadActivity(id string, opts *DownloadOptions) error {
**Duration: 2 days** **Duration: 2 days**
**Tasks:** **Tasks:**
- [ ] Implement TCX format download - [x] Implement TCX format download
- [ ] Implement FIT format download (if available) - [x] Implement FIT format download (if available)
- [ ] Add CSV export for activity summaries - [x] Add CSV export for activity summaries
- [ ] Format validation and conversion - [x] Format validation and conversion
- [ ] Add format-specific options - [x] Add format-specific options
**Deliverables:** **Deliverables:**
- [ ] Support for GPX, TCX, and CSV formats - [x] Support for GPX, TCX, and CSV formats
- [ ] Format auto-detection - [ ] Format auto-detection
- [ ] Format-specific download options - [x] Format-specific download options
#### 1C.3: Batch Download Features #### 1C.3: Batch Download Features
**Duration: 1 day** **Duration: 1 day**

View File

@@ -100,7 +100,7 @@ func (c *Client) DownloadActivity(activityID int, opts activities.DownloadOption
outputPath = filepath.Join(opts.OutputDir, filename) outputPath = filepath.Join(opts.OutputDir, filename)
} }
return c.Client.Download(fmt.Sprintf("%d", activityID), outputPath) return c.Client.Download(fmt.Sprintf("%d", activityID), opts.Format, outputPath)
} }
// SearchActivities searches for activities by a query string // SearchActivities searches for activities by a query string