fix youtube favicon fetching

This commit is contained in:
Athou
2015-06-04 12:28:20 +02:00
parent dcd5f3d529
commit 9adc993472
6 changed files with 70 additions and 35 deletions

View File

@@ -13,6 +13,9 @@ app:
# put your google analytics tracking code here # put your google analytics tracking code here
googleAnalyticsTrackingCode: googleAnalyticsTrackingCode:
# put your google server key (used for youtube favicon fetching)
googleAuthKey:
# number of http threads # number of http threads
backgroundThreads: 3 backgroundThreads: 3

View File

@@ -13,6 +13,9 @@ app:
# put your google analytics tracking code here # put your google analytics tracking code here
googleAnalyticsTrackingCode: googleAnalyticsTrackingCode:
# put your google server key (used for youtube favicon fetching)
googleAuthKey:
# number of http threads # number of http threads
backgroundThreads: 3 backgroundThreads: 3

View File

@@ -13,6 +13,9 @@ app:
# put your google analytics tracking code here # put your google analytics tracking code here
googleAnalyticsTrackingCode: googleAnalyticsTrackingCode:
# put your google server key (used for youtube favicon fetching)
googleAuthKey:
# number of http threads # number of http threads
backgroundThreads: 3 backgroundThreads: 3

View File

@@ -353,6 +353,12 @@
<version>0.9.15</version> <version>0.9.15</version>
</dependency> </dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-youtube</artifactId>
<version>v3-rev138-1.20.0</version>
</dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>

View File

@@ -77,6 +77,8 @@ public class CommaFeedConfiguration extends Configuration {
private String googleAnalyticsTrackingCode; private String googleAnalyticsTrackingCode;
private String googleAuthKey;
@NotNull @NotNull
@Min(1) @Min(1)
@Valid @Valid

View File

@@ -1,18 +1,31 @@
package com.commafeed.backend.favicon; package com.commafeed.backend.favicon;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup; import org.apache.http.NameValuePair;
import org.jsoup.nodes.Document; import org.apache.http.client.utils.URLEncodedUtils;
import org.jsoup.select.Elements;
import com.commafeed.CommaFeedConfiguration;
import com.commafeed.backend.HttpGetter; import com.commafeed.backend.HttpGetter;
import com.commafeed.backend.HttpGetter.HttpResult; import com.commafeed.backend.HttpGetter.HttpResult;
import com.commafeed.backend.model.Feed; import com.commafeed.backend.model.Feed;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.model.Channel;
import com.google.api.services.youtube.model.ChannelListResponse;
import com.google.api.services.youtube.model.Thumbnail;
@Slf4j @Slf4j
@RequiredArgsConstructor(onConstructor = @__({ @Inject })) @RequiredArgsConstructor(onConstructor = @__({ @Inject }))
@@ -20,40 +33,60 @@ import com.commafeed.backend.model.Feed;
public class YoutubeFaviconFetcher extends AbstractFaviconFetcher { public class YoutubeFaviconFetcher extends AbstractFaviconFetcher {
private final HttpGetter getter; private final HttpGetter getter;
private final CommaFeedConfiguration config;
@Override @Override
public byte[] fetch(Feed feed) { public byte[] fetch(Feed feed) {
String url = feed.getUrl(); String url = feed.getUrl();
if (!url.toLowerCase().contains("://gdata.youtube.com/")) { if (!url.toLowerCase().contains("youtube.com/feeds/videos.xml")) {
return null; return null;
} }
String userName = extractUserName(url); String googleAuthKey = config.getApplicationSettings().getGoogleAuthKey();
if (userName == null) { if (googleAuthKey == null) {
log.debug("no google auth key configured");
return null; return null;
} }
String profileUrl = "https://gdata.youtube.com/feeds/users/" + userName;
byte[] bytes = null; byte[] bytes = null;
String contentType = null; String contentType = null;
try { try {
log.debug("Getting YouTube user's icon, {}", url); List<NameValuePair> params = URLEncodedUtils.parse(url.substring(url.indexOf("?") + 1), StandardCharsets.UTF_8);
Optional<NameValuePair> userId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("user")).findFirst();
// initial get to translate username to obscure user thumbnail URL Optional<NameValuePair> channelId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("channel")).findFirst();
HttpResult profileResult = getter.getBinary(profileUrl, TIMEOUT); System.out.println(userId.isPresent());
Document doc = Jsoup.parse(new String(profileResult.getContent()), profileUrl); if (!userId.isPresent() && !channelId.isPresent()) {
Elements thumbnails = doc.select("media|thumbnail");
if (thumbnails.isEmpty()) {
return null; return null;
} }
String thumbnailUrl = thumbnails.get(0).attr("abs:url");
// final get to actually retrieve the thumbnail YouTube youtube = new YouTube.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(),
HttpResult iconResult = getter.getBinary(thumbnailUrl, TIMEOUT); new HttpRequestInitializer() {
@Override
public void initialize(HttpRequest request) throws IOException {
}
}).setApplicationName("CommaFeed").build();
YouTube.Channels.List list = youtube.channels().list("snippet");
list.setKey(googleAuthKey);
if (userId.isPresent()) {
list.setForUsername(userId.get().getValue());
} else {
list.setId(channelId.get().getValue());
}
log.debug("contacting youtube api");
ChannelListResponse response = list.execute();
if (response.getItems().isEmpty()) {
log.debug("youtube api returned no items");
return null;
}
Channel channel = response.getItems().get(0);
Thumbnail thumbnail = channel.getSnippet().getThumbnails().getDefault();
log.debug("fetching favicon");
HttpResult iconResult = getter.getBinary(thumbnail.getUrl(), TIMEOUT);
bytes = iconResult.getContent(); bytes = iconResult.getContent();
contentType = iconResult.getContentType(); contentType = iconResult.getContentType();
} catch (Exception e) { } catch (Exception e) {
@@ -65,19 +98,4 @@ public class YoutubeFaviconFetcher extends AbstractFaviconFetcher {
} }
return bytes; return bytes;
} }
private String extractUserName(String url) {
int apiOrBase = url.indexOf("/users/");
if (apiOrBase == -1) {
return null;
}
int userEndSlash = url.indexOf('/', apiOrBase + "/users/".length());
if (userEndSlash == -1) {
return null;
}
return url.substring(apiOrBase + "/users/".length(), userEndSlash);
}
} }