import java.io.File;
import java.net.URL;
import java.net.URLEncoder;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pircbotx.Channel;
import org.pircbotx.PircBotX;
import org.pircbotx.ShockyBot;
import org.pircbotx.User;
import org.pircbotx.hooks.events.ActionEvent;
import org.pircbotx.hooks.events.MessageEvent;
import pl.shockah.HTTPQuery;
import pl.shockah.StringTools;
import pl.shockah.shocky.Data;
import pl.shockah.shocky.Module;
import pl.shockah.shocky.Shocky;
import pl.shockah.shocky.Utils;
import pl.shockah.shocky.cmds.Command;
import pl.shockah.shocky.cmds.CommandCallback;
import pl.shockah.shocky.cmds.Parameters;
import pl.shockah.shocky.interfaces.IAcceptURLs;
public class ModuleYoutube extends Module implements IAcceptURLs {
protected Command cmd;
private ArrayList<Pattern> patternsAction = new ArrayList<Pattern>(), patternsMessage = new ArrayList<Pattern>();
public static CharSequence getVideoInfo(User user, String vID) {
HTTPQuery q = null;
String key = Data.config.getString("youtube-key");
if (key.isEmpty())
return null;
try {
StringBuilder sb = new StringBuilder("https://www.googleapis.com/youtube/v3/videos?part=snippet%2Cstatistics%2CcontentDetails&key=");
sb.append(URLEncoder.encode(key,"UTF8")).append("&id=").append(URLEncoder.encode(vID,"UTF8")).append(""aUser=").append(URLEncoder.encode(user.getHostmask(),"UTF8"));
sb.append("&fields=items(snippet(channelTitle%2Ctitle)%2CcontentDetails%2Fduration%2Cstatistics(likeCount%2CdislikeCount%2CviewCount))");
q = HTTPQuery.create(sb.toString());
q.connect(true,false);
JSONObject jItem = new JSONObject(q.readWhole());
q.close();
if (jItem.has("error"))
return "Error: "+jItem.getJSONObject("error").getString("message");
JSONArray items = jItem.optJSONArray("items");
if (items == null || items.length() == 0)
return null;
JSONObject item = items.getJSONObject(0);
JSONObject snippet = item.getJSONObject("snippet");
JSONObject statistics = item.getJSONObject("statistics");
JSONObject contentDetails = item.getJSONObject("contentDetails");
String vUploader = StringTools.unicodeParse(snippet.getString("channelTitle"));
String vTitle = StringTools.unicodeParse(snippet.getString("title"));
String vDuration = Utils.timeAgo(contentDetails.getString("duration"));
double likes = statistics.getInt("likeCount");
double dislikes = statistics.getInt("dislikeCount");
long views = statistics.getLong("viewCount");
sb = new StringBuilder();
sb.append(vTitle);
sb.append(" | length ").append(vDuration);
if (likes > 0)
sb.append(" | rated ").append(String.format("%.0f%%", likes * 100D / (likes + dislikes)));
sb.append(" | ").append(NumberFormat.getNumberInstance().format(views)).append(" view");
if (views != 1)
sb.append('s');
sb.append(" | by ").append(vUploader);
return sb.toString();
} catch (Exception e) {e.printStackTrace();}
return null;
}
public static CharSequence getVideoSearch(User user, String query, boolean data, boolean url) {
HTTPQuery q = null;
String key = Data.config.getString("youtube-key");
if (key.isEmpty())
return null;
try {
StringBuilder sb = new StringBuilder("https://www.googleapis.com/youtube/v3/search?safeSearch=none&part=snippet&type=video&maxResults=1&fields=items%2Fid%2FvideoId&key=");
sb.append(URLEncoder.encode(key,"UTF8")).append("&q=").append(URLEncoder.encode(query,"UTF8")).append(""aUser=").append(URLEncoder.encode(user.getHostmask(),"UTF8"));
q = HTTPQuery.create(sb.toString());
q.connect(true,false);
JSONObject jItem = new JSONObject(q.readWhole());
q.close();
if (jItem.has("error"))
return "Error: "+jItem.getJSONObject("error").getString("message");
JSONArray items = jItem.optJSONArray("items");
if (items == null || items.length() == 0)
return null;
sb = new StringBuilder();
JSONObject item = items.getJSONObject(0);
String vID = item.getJSONObject("id").getString("videoId");
if (data) {
CharSequence info = getVideoInfo(user, vID);
if (info == null)
return null;
sb.append(info);
if (url)
sb.append(" | ");
}
if (url)
sb.append("http://youtu.be/").append(vID);
return sb.toString();
} catch (Exception e) {e.printStackTrace();}
return null;
}
public String name() {return "youtube";}
public boolean isListener() {return true;}
public void onEnable(File dir) {
Data.config.setNotExists("yt-otherbot",false);
Data.config.setNotExists("youtube-key","");
Data.protectedKeys.add("youtube-key");
Command.addCommands(this, cmd = new CmdYoutube());
Command.addCommand(this, "yt", cmd);
Command.addCommand(this, "y", cmd);
patternsAction.add(Pattern.compile("^.*?(?:(?:playing)|(?:listening (?:to)?)):? (.+)$"));
patternsMessage.add(Pattern.compile("^np: (.*)$"));
}
public void onDisable() {
patternsAction.clear();
patternsMessage.clear();
Command.removeCommands(cmd);
}
@Override
public boolean shouldAcceptURL(URL u) {
if (u == null)
return false;
if (!u.getProtocol().startsWith("http"))
return false;
String host = u.getHost();
return host.contentEquals("youtu.be") || host.endsWith("youtube.com");
}
@Override
public void handleURL(PircBotX bot, Channel channel, User sender, List<URL> urls) {
if (bot == null || urls == null || urls.isEmpty() || (channel == null && sender == null))
return;
if (channel != null && (!isEnabled(channel.getName()) || Data.forChannel(channel).getBoolean("yt-otherbot")))
return;
StringBuilder sb = new StringBuilder();
Iterator<URL> iter = urls.iterator();
while (iter.hasNext()) {
URL u = iter.next();
String id = null;
String host = u.getHost();
if (host.contentEquals("youtu.be")) {
if (u.getPath().isEmpty())
continue;
id = u.getPath().substring(1);
}
else if (host.endsWith("youtube.com")) {
StringTokenizer tok1 = new StringTokenizer(u.getQuery(),"&");
while (tok1.hasMoreTokens()) {
StringTokenizer tok2 = new StringTokenizer(tok1.nextToken(),"=");
if (tok2.countTokens()!=2)
continue;
String key = tok2.nextToken();
String value = tok2.nextToken();
if (key.contentEquals("v")) {
id = value;
break;
}
}
}
if (id == null)
continue;
CharSequence result = getVideoInfo(sender, id);
if (result == null)
continue;
if (urls.size() > 1)
sb.append(id).append(": ");
sb.append(result);
if (iter.hasNext())
sb.append('\n');
}
if (sb.length() == 0)
return;
String result = StringTools.limitLength(StringTools.formatLines(sb));
if (channel != null)
bot.sendMessage(channel, result);
else if (sender != null)
bot.sendMessage(sender, result);
}
public void onMessage(MessageEvent<ShockyBot> event) {
if (Data.isBlacklisted(event.getUser())) return;
handleEvent(event.getBot(),event.getChannel(),event.getUser(),event.getMessage(),patternsMessage);
/*if (!Data.forChannel(event.getChannel()).getBoolean("yt-otherbot")) {
Matcher m = patternURL.matcher(event.getMessage());
while (m.find()) {
String vID = m.group(1);
if (vID == null) vID = m.group(2);
String result = getVideoInfo(vID);
if (result == null) return;
Shocky.sendChannel(event.getBot(),event.getChannel(),event.getUser().getNick()+": "+result);
}
}*/
}
public void onAction(ActionEvent<ShockyBot> event) {
if (Data.isBlacklisted(event.getUser())) return;
handleEvent(event.getBot(),event.getChannel(),event.getUser(),event.getAction(),patternsAction);
}
private static void handleEvent(PircBotX bot, Channel channel, User user, CharSequence cs, Iterable<Pattern> patterns) {
for (Pattern p : patterns) {
Matcher m = p.matcher(cs);
if (m.find()) {
String s = m.group(1);
if (s.startsWith("http://") || s.startsWith("www.//") || s.startsWith("youtu.be/") || s.startsWith("youtube/")) return;
CharSequence result = getVideoSearch(user,s,!Data.forChannel(channel).getBoolean("yt-otherbot"),true);
if (result == null) return;
s = Utils.mungeAllNicks(channel,0,result);
Shocky.sendChannel(bot,channel,user.getNick()+": "+s);
break;
}
}
}
public class CmdYoutube extends Command {
public String command() {return "youtube";}
public String help(Parameters params) {
StringBuilder sb = new StringBuilder();
sb.append("youtube/yt/y");
sb.append("\nyoutube {query} - returns the first YouTube search result");
return sb.toString();
}
public void doCommand(Parameters params, CommandCallback callback) {
if (params.tokenCount == 0) {
callback.type = EType.Notice;
callback.append(help(params));
return;
}
CharSequence search = getVideoSearch(params.sender,params.input,!Data.forChannel(params.channel).getBoolean("yt-otherbot"),true);
if (search != null && search.length() > 0) {
search = Utils.mungeAllNicks(params.channel,0,search,params.sender);
callback.append(search);
} else {
callback.type = EType.Notice;
callback.append("No results were found.");
}
}
}
}