diff --git a/pom.xml b/pom.xml
index a5ea503..57e1fbf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -151,5 +151,10 @@
pf4j
3.13.0
+
+ xom
+ xom
+ 1.3.9
+
\ No newline at end of file
diff --git a/src/main/java/com/fpghoti/biscuit/Main.java b/src/main/java/com/fpghoti/biscuit/Main.java
index 3d730f4..ddf52c6 100644
--- a/src/main/java/com/fpghoti/biscuit/Main.java
+++ b/src/main/java/com/fpghoti/biscuit/Main.java
@@ -14,6 +14,7 @@ import com.fpghoti.biscuit.commands.console.GuildSayCommand;
import com.fpghoti.biscuit.commands.console.SayCommand;
import com.fpghoti.biscuit.commands.console.ShutdownConsoleCommand;
import com.fpghoti.biscuit.commands.discord.AddCommand;
+import com.fpghoti.biscuit.commands.discord.AddYTFeedCommand;
import com.fpghoti.biscuit.commands.discord.ChanIDCommand;
import com.fpghoti.biscuit.commands.discord.DivideCommand;
import com.fpghoti.biscuit.commands.discord.GetConfigCommand;
@@ -100,6 +101,7 @@ public class Main {
private static Cage cage;
private static File pluginsDir;
public static File audioDir;
+ //public static File ytFeedDir;
private static PluginController pluginController;
private static AudioPlayerManager playerManager;
@@ -131,9 +133,7 @@ public class Main {
playerManager = new DefaultAudioPlayerManager();
AudioSourceManagers.registerLocalSource(playerManager);
YoutubeAudioSourceManager ytSourceManager = new dev.lavalink.youtube.YoutubeAudioSourceManager();
- //LocalAudioSourceManager localSourceManager = new LocalAudioSourceManager();
playerManager.registerSourceManager(ytSourceManager);
- //playerManager.registerSourceManager(localSourceManager);
AudioSourceManagers.registerRemoteSources(playerManager,
com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager.class);
@@ -175,6 +175,7 @@ public class Main {
CommandManager.addCommand(new ToggleRoleCommand());
CommandManager.addCommand(new SquareRootCommand());
CommandManager.addCommand(new AddCommand());
+ CommandManager.addCommand(new AddYTFeedCommand());
CommandManager.addCommand(new SubtractCommand());
CommandManager.addCommand(new MultiplyCommand());
CommandManager.addCommand(new DivideCommand());
diff --git a/src/main/java/com/fpghoti/biscuit/commands/discord/AddYTFeedCommand.java b/src/main/java/com/fpghoti/biscuit/commands/discord/AddYTFeedCommand.java
new file mode 100644
index 0000000..e04cf16
--- /dev/null
+++ b/src/main/java/com/fpghoti/biscuit/commands/discord/AddYTFeedCommand.java
@@ -0,0 +1,52 @@
+package com.fpghoti.biscuit.commands.discord;
+
+import com.fpghoti.biscuit.Main;
+import com.fpghoti.biscuit.commands.base.ClientCommand;
+import com.fpghoti.biscuit.guild.BiscuitGuild;
+import com.fpghoti.biscuit.rest.MessageText;
+import com.fpghoti.biscuit.util.PermUtil;
+import com.fpghoti.biscuit.util.Util;
+
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+//import net.dv8tion.jda.api.entities.TextChannel;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+
+public class AddYTFeedCommand extends ClientCommand{
+
+ public AddYTFeedCommand() {
+ name = "Add YouTube Feed";
+ description = "Sets bot to post YouTube uploads for a specified YouTube channel RSS feed inside the text channel the command was run in";
+ usage = Main.getMainBiscuit().getProperties().getCommandSignifier() + "addytfeed ";
+ minArgs = 1;
+ maxArgs = 1000000;
+ identifiers.add("addytfeed");
+ }
+
+ @Override
+ public void execute(String[] args, MessageReceivedEvent event) {
+ System.out.println("0");
+ BiscuitGuild b = BiscuitGuild.getBiscuitGuild(event.getGuild());
+ b.log(event.getAuthor().getName() + " issued a command: -addytfeed " + args[0]);
+ System.out.println("A");
+ if((PermUtil.isAdmin(event.getMember()))) {
+ System.out.println("B");
+ Guild g = event.getGuild();
+ TextChannel c = event.getChannel().asTextChannel();
+ String alias = args[0];
+ String channelURL = args[1];
+ String message = Util.getArgsMessage(2, args);
+ System.out.println("C");
+ boolean success = b.addYoutubeFeed(alias, c, channelURL, message);
+ System.out.println("D");
+ if(success) {
+ MessageText.send(event.getChannel().asTextChannel(), "YouTube Feed has been created.");
+ }else {
+ MessageText.send(event.getChannel().asTextChannel(), "There was an error creating the YouTube feed.");
+ }
+ }else {
+ MessageText.send(event.getChannel().asTextChannel(), "You do not have permission to create a YouTube feed.");
+ }
+ }
+
+}
diff --git a/src/main/java/com/fpghoti/biscuit/config/BiscuitConfig.java b/src/main/java/com/fpghoti/biscuit/config/BiscuitConfig.java
index c6ccda9..590cfcf 100644
--- a/src/main/java/com/fpghoti/biscuit/config/BiscuitConfig.java
+++ b/src/main/java/com/fpghoti/biscuit/config/BiscuitConfig.java
@@ -152,7 +152,7 @@ public class BiscuitConfig {
//Add properties to appear in both types of configs here
added = addProperty("ChatLog", "true", prop, added, silent);
- added = addProperty("AllowSpamPunish", "true", prop, added, silent);
+ added = addProperty("AllowSpamPunish", "false", prop, added, silent);
added = addProperty("Channels-To-Not-Chatlog", "ignore_me,ignore_me2,ignore_me3", prop, added, silent);
added = addProperty("NaughtyList", "piff,word123,another1", prop, added, silent);
added = addProperty("Restrict-Cmd-Channels", "false", prop, added, silent);
diff --git a/src/main/java/com/fpghoti/biscuit/guild/BiscuitGuild.java b/src/main/java/com/fpghoti/biscuit/guild/BiscuitGuild.java
index b5129d7..1dfed5b 100644
--- a/src/main/java/com/fpghoti/biscuit/guild/BiscuitGuild.java
+++ b/src/main/java/com/fpghoti/biscuit/guild/BiscuitGuild.java
@@ -1,11 +1,18 @@
package com.fpghoti.biscuit.guild;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Properties;
import java.util.Timer;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import com.fpghoti.biscuit.Main;
import com.fpghoti.biscuit.PluginCore;
@@ -15,6 +22,8 @@ import com.fpghoti.biscuit.config.BiscuitProperties;
import com.fpghoti.biscuit.logging.BColor;
import com.fpghoti.biscuit.logging.BiscuitLogger;
import com.fpghoti.biscuit.rest.MessageText;
+import com.fpghoti.biscuit.rss.YTFeed;
+import com.fpghoti.biscuit.rss.YTFeedConfig;
import com.fpghoti.biscuit.timer.BiscuitTimer;
import com.fpghoti.biscuit.timer.task.ChatCountTimer;
import com.fpghoti.biscuit.timer.task.DecrementTimer;
@@ -29,7 +38,6 @@ import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Invite;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
-//import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.User;
@@ -83,9 +91,11 @@ public class BiscuitGuild {
private Timer timer;
private List timers;
private File captchaDir;
+ private File ytFeedDir;
//private Cage cage;
private Guild guild;
private HashMap inviteUses;
+ private HashMap ytfeeds;
private BiscuitConfig config;
private BiscuitProperties properties;
private GuildMessageStore messageStore;
@@ -106,6 +116,7 @@ public class BiscuitGuild {
this.properties = new BiscuitProperties(this);
this.rolequeue = new HashMap();
this.player = Main.getPlayerManager().createPlayer();
+ this.ytfeeds = new HashMap();
scheduler = new AudioScheduler(this);
player.addListener(scheduler);
@@ -115,9 +126,19 @@ public class BiscuitGuild {
if(!Main.isPlugin) {
captchaDir = new File("captcha");
captchaDir.mkdir();
+ if(guild != null) {
+ File f = new File("ytchannels");
+ f.mkdir();
+ ytFeedDir = new File(f, guild.getId());
+ ytFeedDir.mkdir();
+ }
}else {
captchaDir = new File(PluginCore.plugin.getDataFolder(), "captcha");
captchaDir.mkdir();
+ if(guild != null) {
+ ytFeedDir = new File(PluginCore.plugin.getDataFolder(), "ytchannels\\" + guild.getId());
+ ytFeedDir.mkdirs();
+ }
}
if(isMain) {
wipeCaptchaDir();
@@ -131,6 +152,20 @@ public class BiscuitGuild {
});
}
}
+
+ if(guild != null) {
+ loadYoutubeFeeds();
+ Runnable post = () -> {
+ try {
+ log("Updating Youtube feeds...");
+ postYoutubeFeeds();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ };
+ ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+ scheduler.scheduleAtFixedRate(post, 0, 1, TimeUnit.MINUTES);
+ }
}
public BiscuitConfig getConfig() {
@@ -161,6 +196,87 @@ public class BiscuitGuild {
return scheduler;
}
+ public YTFeedConfig loadYouTubeFeedConfig(String alias) {
+ alias = alias.toLowerCase();
+ String channelID = "null";
+ String youTubeChannelURL = "null";
+ String message = "null";
+ String lastVideo = "null";
+
+ Properties prop = new Properties();
+ InputStream input = null;
+
+ File config = new File(ytFeedDir, alias);
+
+ if(!config.exists()) {
+ logger.error("Could not locate YouTube feed config.");
+ return null;
+ }
+
+ try {
+ input = new FileInputStream(config);
+ prop.load(input);
+ channelID = prop.getProperty("TextChannelID");
+ youTubeChannelURL = prop.getProperty("YouTubeChannelURL");
+ message = prop.getProperty("Message");
+ lastVideo = prop.getProperty("LastVideo");
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ TextChannel textChannel = jda.getTextChannelById(channelID);
+ if(textChannel == null) {
+ logger.error("Error retrieving Text Channel from YouTube feed file.");
+ return null;
+ }
+ YTFeed feed = new YTFeed(alias, textChannel, youTubeChannelURL, message);
+ feed.setLastVideo(lastVideo);
+ return new YTFeedConfig(this, feed);
+ }
+
+ public void loadYoutubeFeeds() {
+ ytfeeds.clear();
+ File[] files = ytFeedDir.listFiles();
+ for(File f : files) {
+ String alias = f.getName().toLowerCase();
+ ytfeeds.put(alias, loadYouTubeFeedConfig(alias));
+ }
+ }
+
+ public boolean addYoutubeFeed(String alias, TextChannel channel, String channelURL, String message) {
+ alias = alias.toLowerCase();
+ if(guild == null || ytfeeds.containsKey(alias)) {
+ return false;
+ }
+ YTFeed feed = new YTFeed(alias, channel, channelURL, message);
+ //Generate a file for the feed
+ new YTFeedConfig(this, feed);
+ //Loads all feeds from files into hash map
+ loadYoutubeFeeds();
+ return true;
+ }
+
+ public void postYoutubeFeeds() throws IOException {
+ for(String s : ytfeeds.keySet()) {
+ YTFeedConfig config = ytfeeds.get(s);
+ YTFeed feed = config.getFeed();
+ feed.post();
+ config.setLastPosted(feed.getLastVideo());
+ }
+ }
+
+ public File getYTFeedDir() {
+ return ytFeedDir;
+ }
+
public void log(String message) {
if(properties == null) {
logger.info(message);
diff --git a/src/main/java/com/fpghoti/biscuit/rss/YTEntry.java b/src/main/java/com/fpghoti/biscuit/rss/YTEntry.java
new file mode 100644
index 0000000..acfabeb
--- /dev/null
+++ b/src/main/java/com/fpghoti/biscuit/rss/YTEntry.java
@@ -0,0 +1,67 @@
+package com.fpghoti.biscuit.rss;
+
+import java.awt.Color;
+
+import com.fpghoti.biscuit.util.Util;
+
+import net.dv8tion.jda.api.EmbedBuilder;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.MessageEmbed;
+
+public class YTEntry {
+
+ private String id;
+ private String title;
+ private String author;
+ private String description;
+ private String thumbnail;
+
+ public YTEntry(String id, String title, String author, String description, String thumbnail) {
+ this.id = id;
+ this.title = title;
+ this.author = author;
+ this.description = description;
+ this.thumbnail = thumbnail;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getThumbnail() {
+ return thumbnail;
+ }
+
+ public String getURL() {
+ return "https://www.youtube.com/watch?v=" + id;
+ }
+
+ public MessageEmbed getEmbedMessage() {
+ EmbedBuilder embed = new EmbedBuilder();
+ embed.setTitle(title, getURL());
+ embed.setColor(Color.RED);
+
+ String descPreview = description.substring(0, Math.min(description.length(), 200));
+ if(descPreview.length() < description.length()) {
+ descPreview += "...";
+ }
+
+ embed.setDescription(descPreview);
+ embed.setAuthor(author, null, null);
+ embed.setThumbnail(thumbnail);
+ return embed.build();
+ }
+
+}
diff --git a/src/main/java/com/fpghoti/biscuit/rss/YTFeed.java b/src/main/java/com/fpghoti/biscuit/rss/YTFeed.java
new file mode 100644
index 0000000..aec8b34
--- /dev/null
+++ b/src/main/java/com/fpghoti/biscuit/rss/YTFeed.java
@@ -0,0 +1,143 @@
+package com.fpghoti.biscuit.rss;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fpghoti.biscuit.guild.BiscuitGuild;
+import com.fpghoti.biscuit.rest.MessageText;
+
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import nu.xom.Builder;
+import nu.xom.Document;
+import nu.xom.Element;
+import nu.xom.Elements;
+import nu.xom.ParsingException;
+
+public class YTFeed {
+
+ private BiscuitGuild guild;
+ private String alias;
+ private TextChannel channel;
+ private String channelURL;
+ private String message;
+ private String lastVideo;
+
+ public YTFeed(String alias, TextChannel channel, String channelURL, String message) {
+ this.guild = BiscuitGuild.getBiscuitGuild(channel.getGuild());
+ this.alias = alias;
+ this.channel = channel;
+ this.channelURL = channelURL;
+ this.message = message;
+ lastVideo = "";
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public TextChannel getTextChannel() {
+ return channel;
+ }
+
+ public String getChannelURL() {
+ return channelURL;
+ }
+
+ public String getMesage() {
+ return message;
+ }
+
+ public String getLastVideo() {
+ return lastVideo;
+ }
+
+ public void setLastVideo(String link) {
+ lastVideo = link;
+ }
+
+ public void post(){
+ List ytentries = getEntries();
+ int index = 0;
+ int lastVidIndex = -1;
+ for(YTEntry entry : ytentries) {
+ String link = entry.getURL();
+ if(link.equals(lastVideo)) {
+ lastVidIndex = index;
+ }
+ index++;
+ }
+ index = 0;
+ for(YTEntry entry : ytentries) {
+ if(index > lastVidIndex) {
+ String link = entry.getURL();
+ lastVideo = link;
+ MessageText.send(channel, message);
+ MessageText.send(channel, entry.getEmbedMessage());
+ }
+ index++;
+ }
+ }
+
+ public List getEntries() {
+ List ytentries = new ArrayList();
+
+ Builder builder = new Builder();
+ Document doc = null;
+ try {
+ doc = builder.build(channelURL);
+ } catch (ParsingException | IOException e) {
+ guild.error("Unable to parse feed: " + channelURL);
+ MessageText.send(channel, "Unable to parse feed: " + channelURL);
+ }
+
+ Element rss = doc.getRootElement();
+ Elements entries = rss.getChildElements();
+ for(Element entry : entries){
+ if(entry.getLocalName().equals("entry")) {
+
+ String id = "";
+ String title = "";
+ String author = "";
+ String description = "";
+ String thumbnail = "";
+
+ Elements values = entry.getChildElements();
+ for(Element value : values){
+ if(value.getLocalName().equals("videoId")) {
+ id = value.getValue();
+ }
+ if(value.getLocalName().equals("title")) {
+ title = value.getValue();
+ }
+ if(value.getLocalName().equals("author")) {
+ Elements subvalues = value.getChildElements();
+ for(Element subvalue : subvalues) {
+ if(subvalue.getLocalName().equals("name")) {
+ author = subvalue.getValue();
+ }
+ }
+ }
+ if(value.getLocalName().equals("group")) {
+ Elements subvalues = value.getChildElements();
+ for(Element subvalue : subvalues) {
+ if(subvalue.getLocalName().equals("description")) {
+ description = subvalue.getValue();
+ }
+ if(subvalue.getLocalName().equals("thumbnail")) {
+ thumbnail = subvalue.getAttributeValue("url");
+ }
+ }
+ }
+ }
+
+ ytentries.add(new YTEntry(id, title, author, description, thumbnail));
+ }
+ }
+
+ return ytentries.reversed();
+
+ }
+
+}
diff --git a/src/main/java/com/fpghoti/biscuit/rss/YTFeedConfig.java b/src/main/java/com/fpghoti/biscuit/rss/YTFeedConfig.java
new file mode 100644
index 0000000..7c9f252
--- /dev/null
+++ b/src/main/java/com/fpghoti/biscuit/rss/YTFeedConfig.java
@@ -0,0 +1,149 @@
+package com.fpghoti.biscuit.rss;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.commons.configuration2.PropertiesConfigurationLayout;
+import org.apache.commons.configuration2.ex.ConfigurationException;
+
+import com.fpghoti.biscuit.guild.BiscuitGuild;
+
+public class YTFeedConfig {
+
+ private BiscuitGuild biscuit;
+ private YTFeed feed;
+ private File config;
+
+ public YTFeedConfig(BiscuitGuild b, YTFeed feed) {
+ this.biscuit = b;
+ this.feed = feed;
+ generateConfig();
+ }
+
+ public BiscuitGuild getGuild() {
+ return biscuit;
+ }
+
+ public YTFeed getFeed() {
+ return feed;
+ }
+
+ public void generateConfig() {
+
+ String name = feed.getAlias();
+
+ File config = new File(biscuit.getYTFeedDir(), name);
+
+ if (!config.exists()) {
+ try {
+ config.createNewFile();
+ updateConfig(config);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }else {
+ updateConfig(config);
+ }
+ this.config = config;
+ }
+
+
+ public void setLastPosted(String link) {
+ PropertiesConfiguration prop = new PropertiesConfiguration();
+ PropertiesConfigurationLayout layout = new PropertiesConfigurationLayout();
+ prop.setLayout(layout);
+ try {
+ layout.load(prop, new FileReader(config));
+ FileWriter fw = new FileWriter(config);
+ prop.setProperty("LastVideo", link);
+ feed.setLastVideo(link);
+ layout.save(prop, fw);
+ } catch (ConfigurationException e) {
+ e.printStackTrace();
+ biscuit.error("There was an issue updating a YouTube feed file.");
+ return;
+ } catch (IOException e) {
+ e.printStackTrace();
+ biscuit.error("There was an issue updating a YouTube feed file.");
+ return;
+ }
+ }
+
+ private void updateConfig(File config) {
+ PropertiesConfiguration prop = new PropertiesConfiguration();
+ PropertiesConfigurationLayout layout = new PropertiesConfigurationLayout();
+ prop.setLayout(layout);
+ try {
+ layout.load(prop, new FileReader(config));
+ FileWriter fw = new FileWriter(config);
+ addNewOptions(prop);
+ layout.save(prop, fw);
+ } catch (ConfigurationException e) {
+ e.printStackTrace();
+ biscuit.error("There was an issue preparing a YouTube feed config for updates.");
+ return;
+ } catch (IOException e) {
+ e.printStackTrace();
+ biscuit.error("There was an issue preparing a YouTube feed config for updates.");
+ return;
+ }
+ }
+
+ private void addNewOptions(PropertiesConfiguration prop) {
+ if(feed == null) {
+ return;
+ }
+
+ addProperty("Alias", feed.getAlias(), prop);
+ addProperty("TextChannelID", feed.getTextChannel().getId(), prop);
+ addProperty("YouTubeChannelURL", feed.getChannelURL(), prop);
+ addProperty("Message", feed.getMesage(), prop);
+ addProperty("LastVideo", "", prop);
+ }
+
+ private void addProperty(String key, String value, PropertiesConfiguration prop) {
+ if(prop.getProperty(key) == null) {
+ prop.addProperty(key, value);
+ }
+ }
+
+ public String getFromConfig(String property){
+
+ String setting = "";
+
+ Properties prop = new Properties();
+ InputStream input = null;
+
+ File config = new File(biscuit.getYTFeedDir(), feed.getAlias());
+
+ if(!config.exists()) {
+ return "";
+ }
+
+ try {
+ input = new FileInputStream(config);
+ prop.load(input);
+ setting = prop.getProperty(property);
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ return setting;
+
+ }
+
+}
diff --git a/src/main/java/com/fpghoti/biscuit/util/Util.java b/src/main/java/com/fpghoti/biscuit/util/Util.java
index c2854ac..d4b31ba 100644
--- a/src/main/java/com/fpghoti/biscuit/util/Util.java
+++ b/src/main/java/com/fpghoti/biscuit/util/Util.java
@@ -83,5 +83,16 @@ public class Util {
String last = s[s.length - 1];
return last;
}
+
+ public static String getArgsMessage(int startAt, String[] args) {
+ String message = "";
+ for(int i = startAt; i < args.length; i++) {
+ message = message + args[i] + " ";
+ }
+ if (message.length() > 0) {
+ message = message.substring(0, message.length() - 1);
+ }
+ return message;
+ }
}
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index 0f89553..5b184f5 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -38,4 +38,6 @@
+
+
\ No newline at end of file