package com.skcraft.playblock.media;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.sk89q.mapquery.MapQuery;
import com.skcraft.playblock.util.HttpRequest;
/**
* Looks up information about YouTube URIs.
*/
public class YouTube implements MediaProvider {
private static final String API_URL = "https://www.googleapis.com/youtube/v3/";
/**
* API key for accessing YouTube, managed by sk89q.
*/
private static final String API_KEY = "AIzaSyC8boYCJH5S5Z5pTuwx6HIUWYGeRZh-MOs";
/**
* Basic regex for parsing ISO-8601 durations.
*/
private static final Pattern LENGTH_PATTERN = Pattern.compile("^PT(?:([0-9]+)H)?(?:([0-9]+)M)?(?:([0-9]+)S)?$", Pattern.CASE_INSENSITIVE);
/**
* Regex for matching YouTube links (including youtu.be links).
*/
private static final Pattern urlPattern = Pattern.compile("^https?://(?:www\\.)?" + // https://www.
// portion
"(?:youtube\\.com/+watch\\?.*(?<=[&\\?])v=|youtu\\.be/+)" + // Prefix
"([A-Za-z0-9_\\-]+).*$", // Video ID
Pattern.CASE_INSENSITIVE);
@Override
public int getConfidence(String uri) {
return urlPattern.matcher(uri).matches() ? DEFAULT_CONFIDENCE : NO_CONFIDENCE;
}
@Override
public Media lookup(String uri) throws IOException {
Matcher m = urlPattern.matcher(uri);
if (!m.matches()) {
return new Media(uri); // Empty
}
return queryVideo(m.group(1));
}
private Media queryVideo(String id) throws IOException {
HttpRequest request = new HttpRequest(API_URL + "videos");
request.addQueryParam("key", API_KEY);
request.addQueryParam("id", id);
request.addQueryParam("part", "snippet,contentDetails,status");
String data = request.readText();
MapQuery result = MapQuery.fromJsonApi(data, "error.message");
MapQuery entry = result.wrapMapQuery("items.0");
// Video is missing?
if (!entry.containsPath("id")) {
return null;
}
Media info = new Media("http://youtube.com/watch?v=" + entry.getString("id"));
info.setTitle(entry.getString("snippet.title"));
info.setDescription(entry.getString("snippet.description"));
info.setLength(parseLength(entry.getString("contentDetails.duration")));
return info;
}
private Long parseLength(String text) {
if (text == null) {
return null;
}
// Example: "PT2M58S" -- ISO-8601
// Not really a compliant parser
Matcher m = LENGTH_PATTERN.matcher(text);
if (m.matches()) {
String hr = m.group(1);
String min = m.group(2);
String sec = m.group(3);
long duration = 0;
if (hr != null)
duration += Long.parseLong(hr) * 60 * 60;
if (min != null)
duration += Long.parseLong(min) * 60;
if (sec != null)
duration += Long.parseLong(sec);
return duration * 1000; // Milliseconds
}
return null;
}
public Media[] search(String query, int startIndex, int maxResults) throws IOException {
HttpRequest request = new HttpRequest(API_URL + "search");
request.addQueryParam("part", "id,snippet");
request.addQueryParam("maxResults", Integer.toString(maxResults));
request.addQueryParam("order", "relevance");
request.addQueryParam("q", query);
request.addQueryParam("type", "video");
request.addQueryParam("key", API_KEY);
String data = request.readText();
MapQuery result = MapQuery.fromJsonApi(data, "error.message");
Media[] results = new Media[maxResults];
for (int i = 0; i < maxResults; i++) {
MapQuery entry = result.wrapMapQuery("items." + i);
Media videoResult = new Media("http://youtube.com/watch?v=" + entry.getString("id.videoId"));
videoResult.setTitle(entry.getString("snippet.title"));
videoResult.setThumbnail(entry.getString("snippet.thumbnails.default.url"));
videoResult.setCreator(entry.getString("snippet.channelTitle"));
results[i] = videoResult;
}
return results;
}
}