mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-11 06:40:53 +00:00
use image size in conjunction with "stage" URL marker to determine stage image
This commit is contained in:
1 parent
1b46a87d79
commit
7dc02f6540
12 files changed
+146
-53
No files matched your search
+8
@@ -0,0 +1,8 @@
|
||||
package com.sap.sailing.domain.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface ImageSize extends Serializable {
|
||||
int getWidth();
|
||||
int getHeight();
|
||||
}
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
package com.sap.sailing.domain.common.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.ImageSize;
|
||||
|
||||
public class ImageSizeImpl implements ImageSize {
|
||||
private static final long serialVersionUID = 1170701774852068780L;
|
||||
private int width;
|
||||
private int height;
|
||||
ImageSizeImpl() {} // for GWT serialization
|
||||
public ImageSizeImpl(int width, int height) {
|
||||
super();
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "("+getWidth()+"x"+getHeight()+")";
|
||||
}
|
||||
}
|
||||
|
||||
+1
-5
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.base;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.sap.sailing.domain.common.ImageSize;
|
||||
import com.sap.sailing.domain.common.Renamable;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.WithID;
|
||||
@@ -121,11 +122,6 @@ public interface EventBase extends Named, WithDescription, Renamable, WithID {
|
||||
|
||||
Iterable<? extends LeaderboardGroupBase> getLeaderboardGroups();
|
||||
|
||||
public static interface ImageSize {
|
||||
int getWidth();
|
||||
int getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* For the images references by the image URLs in {@link #getImageURLs()}, {@link #getSponsorImageURLs()} and {@link #getLogoImageURL()}
|
||||
* determines the image dimensions.
|
||||
|
||||
-22
@@ -221,26 +221,4 @@ public abstract class EventBaseImpl implements EventBase {
|
||||
this.officialWebsiteURL = officialWebsiteURL;
|
||||
}
|
||||
|
||||
public static class ImageSizeImpl implements ImageSize {
|
||||
private final int width;
|
||||
private final int height;
|
||||
public ImageSizeImpl(int width, int height) {
|
||||
super();
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "("+getWidth()+"x"+getHeight()+")";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -9,6 +9,7 @@ import java.util.concurrent.ExecutionException;
|
||||
import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.domain.base.LeaderboardGroupBase;
|
||||
import com.sap.sailing.domain.base.Venue;
|
||||
import com.sap.sailing.domain.common.ImageSize;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
|
||||
/**
|
||||
@@ -33,7 +34,7 @@ public class StrippedEventImpl extends EventBaseImpl {
|
||||
boolean isPublic, UUID id, Iterable<LeaderboardGroupBase> leaderboardGroups) {
|
||||
super(name, startDate, endDate, venue, isPublic, id);
|
||||
this.leaderboardGroups = leaderboardGroups;
|
||||
this.imageSizes = new HashMap<URL, EventBase.ImageSize>();
|
||||
this.imageSizes = new HashMap<URL, ImageSize>();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.net.URL;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.sap.sailing.domain.common.ImageSize;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,9 @@ import javax.imageio.stream.ImageInputStream;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Venue;
|
||||
import com.sap.sailing.domain.common.ImageSize;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.ImageSizeImpl;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
|
||||
+5
-10
@@ -1,15 +1,14 @@
|
||||
package com.sap.sailing.gwt.home.client.place.start;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.activity.shared.AbstractActivity;
|
||||
import com.google.gwt.event.shared.EventBus;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.AcceptsOneWidget;
|
||||
import com.sap.sailing.gwt.home.client.shared.placeholder.Placeholder;
|
||||
@@ -50,9 +49,8 @@ public class StartActivity extends AbstractActivity {
|
||||
List<EventBaseDTO> upcomingSoonEvents = new ArrayList<EventBaseDTO>();
|
||||
List<EventBaseDTO> popularEvents = new ArrayList<EventBaseDTO>();
|
||||
Date now = new Date();
|
||||
Calendar cal = new GregorianCalendar();
|
||||
cal.setTime(now);
|
||||
int currentYear = cal.get(Calendar.YEAR);
|
||||
DateTimeFormat yearFetcher = DateTimeFormat.getFormat("yyyy");
|
||||
String currentYear = yearFetcher.format(now);
|
||||
final int MAX_STAGE_EVENTS = 10;
|
||||
final long FOUR_WEEK_IN_MS = 4L * (1000 * 60 * 60 * 24 * 7);
|
||||
|
||||
@@ -62,11 +60,8 @@ public class StartActivity extends AbstractActivity {
|
||||
featuredEvents.add(new Pair<StageEventType, EventBaseDTO>(StageEventType.RUNNING, event));
|
||||
} else if (event.startDate.after(now) && event.startDate.getTime() - now.getTime() < FOUR_WEEK_IN_MS) {
|
||||
upcomingSoonEvents.add(event);
|
||||
} else {
|
||||
cal.setTime(event.endDate);
|
||||
if (event.endDate.before(now) && cal.get(Calendar.YEAR) == currentYear) {
|
||||
recentEventsOfSameYear.add(event);
|
||||
}
|
||||
} else if (event.endDate.before(now) && yearFetcher.format(event.endDate).equals(currentYear)) {
|
||||
recentEventsOfSameYear.add(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-1
@@ -3271,17 +3271,32 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
eventDTO.id = (UUID) event.getId();
|
||||
eventDTO.setDescription(event.getDescription());
|
||||
eventDTO.setOfficialWebsiteURL(event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null);
|
||||
eventDTO.setLogoImageURL(event.getLogoImageURL() != null ? event.getLogoImageURL().toString() : null);
|
||||
if (event.getLogoImageURL() == null) {
|
||||
eventDTO.setLogoImageURL(null);
|
||||
} else {
|
||||
eventDTO.setLogoImageURL(event.getLogoImageURL().toString());
|
||||
setImageSize(event, eventDTO, event.getLogoImageURL());
|
||||
}
|
||||
for(URL url: event.getSponsorImageURLs()) {
|
||||
eventDTO.addSponsorImageURL(url.toString());
|
||||
setImageSize(event, eventDTO, url);
|
||||
}
|
||||
for(URL url: event.getImageURLs()) {
|
||||
eventDTO.addImageURL(url.toString());
|
||||
setImageSize(event, eventDTO, url);
|
||||
}
|
||||
for(URL url: event.getVideoURLs()) {
|
||||
eventDTO.addVideoURL(url.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void setImageSize(EventBase event, EventBaseDTO eventDTO, URL imageURL) {
|
||||
try {
|
||||
eventDTO.setImageSize(imageURL.toString(), event.getImageSize(imageURL));
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
logger.log(Level.FINE, "Was unable to obtain image size for "+imageURL+" earlier.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private EventDTO convertToEventDTO(Event event, boolean withStatisticalData) {
|
||||
EventDTO eventDTO = new EventDTO(event.getName());
|
||||
|
||||
+80
-11
@@ -1,15 +1,22 @@
|
||||
package com.sap.sailing.gwt.ui.shared;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
||||
import com.sap.sailing.domain.common.ImageSize;
|
||||
import com.sap.sailing.domain.common.dto.NamedDTO;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class EventBaseDTO extends NamedDTO implements IsSerializable {
|
||||
private static final long serialVersionUID = 818666323178097939L;
|
||||
private static final String STAGE_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE = "stage";
|
||||
public VenueDTO venue;
|
||||
public Date startDate;
|
||||
public Date endDate;
|
||||
@@ -26,6 +33,11 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable {
|
||||
/** placeholder for social media URL's -> attributes will be implemented later on */
|
||||
private String facebookURL;
|
||||
private String twitterURL;
|
||||
/**
|
||||
* For the image URL keys holds the sizes of these images if known. An image size is "known" by this object if it was
|
||||
* provided to the {@link #setImageSize} method.
|
||||
*/
|
||||
private Map<String, ImageSize> imageSizes;
|
||||
|
||||
/**
|
||||
* The base URL for the server instance on which the data for this event can be reached. Could be something like
|
||||
@@ -45,11 +57,13 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable {
|
||||
|
||||
public EventBaseDTO(List<? extends LeaderboardGroupBaseDTO> leaderboardGroups) {
|
||||
this.leaderboardGroups = leaderboardGroups;
|
||||
this.imageSizes = new HashMap<String, ImageSize>();
|
||||
}
|
||||
|
||||
public EventBaseDTO(String name, List<? extends LeaderboardGroupBaseDTO> leaderboardGroups) {
|
||||
super(name);
|
||||
this.leaderboardGroups = leaderboardGroups;
|
||||
this.imageSizes = new HashMap<String, ImageSize>();
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
@@ -113,24 +127,63 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable {
|
||||
return imageURLs;
|
||||
}
|
||||
|
||||
/**
|
||||
* The stage image is determined from the {@link #imageURLs} collection by a series of heuristics and fall-back rules:
|
||||
* <ol>
|
||||
* <li>If one or more image URLs has "stage" (ignoring case) in its name, only they are considered candidates.</li>
|
||||
* <li>If no image URL has "stage" (ignoring case) in its name, all images from {@link #imageURLs} are considered candidates.</li>
|
||||
* <li>From all candidates, the one with the biggest known size (determined by the product of width and height) is chosen.</li>
|
||||
* <li>If the size isn't known for any candidate, the first candidate in {@link #imageURLs} is picked.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public String getStageImageURL() {
|
||||
String result = null;
|
||||
for(String imageUrl: imageURLs) {
|
||||
// FIXME consolidate with getPhotoGalleryImageURLs, removing redundant "STAGE" code
|
||||
// TODO use image size to find largest image(s) in case none is explicitly marked with "state" in its URL
|
||||
if(imageUrl.contains("stage") || imageUrl.contains("STAGE")) {
|
||||
result = imageUrl;
|
||||
break;
|
||||
}
|
||||
final String result;
|
||||
if (imageURLs.isEmpty()) {
|
||||
result = null;
|
||||
} else {
|
||||
Comparator<String> stageImageComparator = new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
final int result;
|
||||
if (o1.toLowerCase().contains(STAGE_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE)) {
|
||||
if (o2.toLowerCase().contains(STAGE_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE)) {
|
||||
result = compareBySize(o1, o2);
|
||||
} else {
|
||||
// o1 has stage indicator substring in its URL but o2 doesn't; o1 ranks greater
|
||||
result = 1;
|
||||
}
|
||||
} else {
|
||||
if (o2.toLowerCase().contains(STAGE_IMAGE_URL_SUBSTRING_INDICATOR_CASE_INSENSITIVE)) {
|
||||
result = -1; // o1 does not and o2 does have stage indicator substring, so o2 ranks greater
|
||||
} else {
|
||||
// both don't have stage indicator; compare by size
|
||||
result = compareBySize(o1, o2);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int compareBySize(String o1, String o2) {
|
||||
final int result;
|
||||
final ImageSize o1Size = getImageSize(o1);
|
||||
final ImageSize o2Size = getImageSize(o2);
|
||||
result = (o1Size == null ? 0 : (o1Size.getWidth() * o1Size.getHeight()))
|
||||
- (o2Size == null ? 0 : (o2Size.getWidth() * o2Size.getHeight()));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
List<String> sortedImageURLs = new ArrayList<>(imageURLs);
|
||||
Collections.sort(sortedImageURLs, stageImageComparator);
|
||||
result = sortedImageURLs.get(sortedImageURLs.size() - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<String> getPhotoGalleryImageURLs() {
|
||||
String stageImageURL = getStageImageURL(); // if set, exclude stage image from photo gallery
|
||||
List<String> result = new ArrayList<String>();
|
||||
for(String imageUrl: imageURLs) {
|
||||
// FIXME consolidate with getStageImageURL, removing redundant "STAGE" code
|
||||
if(!imageUrl.contains("stage") && !imageUrl.contains("STAGE")) {
|
||||
for (String imageUrl : imageURLs) {
|
||||
if (!Util.equalsWithNull(imageUrl, stageImageURL)) {
|
||||
result.add(imageUrl);
|
||||
}
|
||||
}
|
||||
@@ -172,5 +225,21 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable {
|
||||
public void setTwitterURL(String twitterURL) {
|
||||
this.twitterURL = twitterURL;
|
||||
}
|
||||
|
||||
public void setImageSize(String imageURL, ImageSize imageSize) {
|
||||
if (imageSize == null) {
|
||||
imageSizes.remove(imageURL);
|
||||
} else {
|
||||
imageSizes.put(imageURL, imageSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of the image referenced by <code>imageURL</code> or <code>null</code> if that size is not known
|
||||
* of the image URL is none of those known to this event, in particular neither of {@link #getImageURLs()}
|
||||
* or {@link #getSponsorImageURLs()}.
|
||||
*/
|
||||
public ImageSize getImageSize(String imageURL) {
|
||||
return imageSizes.get(imageURL);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -12,8 +12,8 @@ import org.json.simple.JSONObject;
|
||||
import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.domain.base.LeaderboardGroupBase;
|
||||
import com.sap.sailing.domain.base.Venue;
|
||||
import com.sap.sailing.domain.base.impl.EventBaseImpl;
|
||||
import com.sap.sailing.domain.base.impl.StrippedEventImpl;
|
||||
import com.sap.sailing.domain.common.impl.ImageSizeImpl;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
@@ -95,7 +95,7 @@ public class EventBaseJsonDeserializer implements JsonDeserializer<EventBase> {
|
||||
try {
|
||||
result.setImageSize(
|
||||
new URL((String) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_URL)),
|
||||
new EventBaseImpl.ImageSizeImpl(
|
||||
new ImageSizeImpl(
|
||||
((Number) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_WIDTH)).intValue(),
|
||||
((Number) imageURLAndSizeJson.get(EventBaseJsonSerializer.FIELD_IMAGE_HEIGHT)).intValue()));
|
||||
} catch (MalformedURLException e) {
|
||||
|
||||
+1
-1
@@ -9,9 +9,9 @@ import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.domain.base.EventBase.ImageSize;
|
||||
import com.sap.sailing.domain.base.LeaderboardGroupBase;
|
||||
import com.sap.sailing.domain.base.Venue;
|
||||
import com.sap.sailing.domain.common.ImageSize;
|
||||
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
|
||||
|
||||
public class EventBaseJsonSerializer implements JsonSerializer<EventBase> {
|
||||
|
||||
Reference in new issue
Block a user