Get activity title from uploaded file, if it is present (#7)
* Use activity title from GPX file when present * Extend test * Test shortening of long names * Extract constant --------- Co-authored-by: Niklas Deutschmann <sonstharmlos@noreply.codeberg.org>
This commit is contained in:
parent
6afd7a5dad
commit
03b8e6d315
5 changed files with 56 additions and 15 deletions
|
|
@ -378,10 +378,16 @@ public class ActivityFileService {
|
|||
byte[] rawFile,
|
||||
ProcessingOptions options
|
||||
) throws JsonProcessingException {
|
||||
String activityTitle;
|
||||
if (title != null && !title.isBlank()) {
|
||||
activityTitle = title;
|
||||
} else if (parsedData.getTitle() != null) {
|
||||
// Try to use title from input file
|
||||
activityTitle = parsedData.getTitle();
|
||||
} else {
|
||||
// Generate title if not provided
|
||||
String activityTitle = title != null && !title.isBlank()
|
||||
? title
|
||||
: ActivityFormatter.generateActivityTitle(parsedData.getStartTime(), parsedData.getActivityType());
|
||||
activityTitle = ActivityFormatter.generateActivityTitle(parsedData.getStartTime(), parsedData.getActivityType());
|
||||
}
|
||||
|
||||
// Default to PUBLIC if visibility not specified
|
||||
Activity.Visibility activityVisibility = visibility != null ? visibility : Activity.Visibility.PRIVATE;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static net.javahippie.fitpub.util.ParsedActivityData.MAX_TITLE_LENGTH;
|
||||
|
||||
/**
|
||||
* Parser for GPX (GPS Exchange Format) files.
|
||||
* Extracts GPS coordinates, activity metrics from track points.
|
||||
|
|
@ -80,8 +82,12 @@ public class GpxParser {
|
|||
// Calculate duration
|
||||
parsedData.setTotalDuration(Duration.between(firstPoint.getTimestamp(), lastPoint.getTimestamp()));
|
||||
|
||||
// Extract activity type from metadata
|
||||
extractActivityType(doc, parsedData);
|
||||
// Extract activity type and title from metadata
|
||||
Optional<Element> track = getFirstTrack(doc);
|
||||
if (track.isPresent()) {
|
||||
extractActivityType(track.get(), parsedData);
|
||||
extractActivityTitle(track.get(), parsedData);
|
||||
}
|
||||
|
||||
// Determine timezone from first GPS coordinate
|
||||
determineTimezone(parsedData);
|
||||
|
|
@ -111,6 +117,8 @@ public class GpxParser {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Extracts track points from GPX document.
|
||||
*/
|
||||
|
|
@ -245,22 +253,41 @@ public class GpxParser {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts activity type from GPX metadata.
|
||||
/*
|
||||
* Returns the first <trk> element from the GPS XML
|
||||
*/
|
||||
private void extractActivityType(Document doc, ParsedActivityData parsedData) {
|
||||
private Optional<Element> getFirstTrack(Document doc) {
|
||||
NodeList tracks = doc.getElementsByTagName("trk");
|
||||
if (tracks.getLength() == 0) {
|
||||
tracks = doc.getElementsByTagNameNS("*", "trk");
|
||||
}
|
||||
|
||||
if (tracks.getLength() > 0) {
|
||||
Element track = (Element) tracks.item(0);
|
||||
return tracks.getLength() > 0 ? Optional.of((Element) tracks.item(0)) : Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts activity type from GPX metadata.
|
||||
*/
|
||||
private void extractActivityType(Element track, ParsedActivityData parsedData) {
|
||||
String type = getElementText(track, "type");
|
||||
if (type != null) {
|
||||
parsedData.setActivityType(mapGpxTypeToActivityType(type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts activity title from GPX metadata.
|
||||
*/
|
||||
private void extractActivityTitle(Element track, ParsedActivityData parsedData) {
|
||||
String title = getElementText(track, "name");
|
||||
if (title != null) {
|
||||
String shortenedTitle = title;
|
||||
if (title.length() > MAX_TITLE_LENGTH) {
|
||||
log.debug("Activity title was shortened to {} characters: {}", MAX_TITLE_LENGTH, title);
|
||||
shortenedTitle = title.substring(0, MAX_TITLE_LENGTH);
|
||||
}
|
||||
parsedData.setTitle(shortenedTitle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ import java.util.List;
|
|||
*/
|
||||
@Data
|
||||
public class ParsedActivityData {
|
||||
|
||||
static final int MAX_TITLE_LENGTH = 255;
|
||||
|
||||
private List<TrackPointData> trackPoints = new ArrayList<>();
|
||||
private LocalDateTime startTime;
|
||||
private LocalDateTime endTime;
|
||||
|
|
@ -30,6 +33,7 @@ public class ParsedActivityData {
|
|||
private BigDecimal elevationGain;
|
||||
private BigDecimal elevationLoss;
|
||||
private Activity.ActivityType activityType = Activity.ActivityType.OTHER;
|
||||
private String title;
|
||||
private ActivityMetricsData metrics;
|
||||
private String sourceFormat; // "FIT" or "GPX"
|
||||
private Boolean indoor = false; // Indicates if this is an indoor activity
|
||||
|
|
|
|||
|
|
@ -112,6 +112,10 @@ class GpxParserIntegrationTest {
|
|||
|
||||
// Verify at least some basic data
|
||||
assertNotNull(parsedData.getActivityType(), "Activity type should be determined");
|
||||
String parsedTitle = parsedData.getTitle();
|
||||
assertEquals(255, parsedTitle.length());
|
||||
assertTrue(parsedTitle.startsWith("Einmal Frust loswerden"));
|
||||
assertFalse(parsedTitle.contains("Shouldn't appear"));
|
||||
assertEquals(Activity.ActivityType.RUN, parsedData.getActivityType(),
|
||||
"Activity type should be RUN (from GPX <type>running</type>)");
|
||||
assertTrue(parsedData.getTrackPoints().size() > 0, "Should have at least one track point");
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<time>2022-07-03T19:47:51Z</time>
|
||||
</metadata>
|
||||
<trk>
|
||||
<name>Einmal Frust loswerden</name>
|
||||
<name>Einmal Frust loswerden blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel blafasel Shouldn't appear</name>
|
||||
<type>running</type>
|
||||
<trkseg>
|
||||
<trkpt lat="48.0140070" lon="7.8513840">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue