me.ryandowling.allmightybot.AllmightyBot.java Source code

Java tutorial

Introduction

Here is the source code for me.ryandowling.allmightybot.AllmightyBot.java

Source

/*
 * Allmighty Bot - https://github.com/RyanTheAllmighty/AllmightyBot
 * Copyright (C) 2014 Ryan Dowling
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package me.ryandowling.allmightybot;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import me.ryandowling.allmightybot.commands.BaseCommand;
import me.ryandowling.allmightybot.commands.Command;
import me.ryandowling.allmightybot.commands.CommandBus;
import me.ryandowling.allmightybot.commands.TempCommand;
import me.ryandowling.allmightybot.data.ChatLog;
import me.ryandowling.allmightybot.data.Event;
import me.ryandowling.allmightybot.data.EventType;
import me.ryandowling.allmightybot.data.QuoteType;
import me.ryandowling.allmightybot.data.SeedType;
import me.ryandowling.allmightybot.data.Settings;
import me.ryandowling.allmightybot.data.Spam;
import me.ryandowling.allmightybot.data.TimedMessage;
import me.ryandowling.allmightybot.data.TwitchChatters;
import me.ryandowling.allmightybot.data.WorldType;
import me.ryandowling.allmightybot.listeners.CommandListener;
import me.ryandowling.allmightybot.listeners.LinkListener;
import me.ryandowling.allmightybot.listeners.SpamListener;
import me.ryandowling.allmightybot.listeners.StartupListener;
import me.ryandowling.allmightybot.listeners.TrollChatListener;
import me.ryandowling.allmightybot.listeners.UserListener;
import me.ryandowling.allmightybot.utils.TwitchAPI;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.pircbotx.Channel;
import org.pircbotx.Configuration;
import org.pircbotx.PircBotX;
import org.pircbotx.exception.IrcException;

import javax.swing.JOptionPane;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class AllmightyBot {
    public final static Gson GSON = new GsonBuilder().setPrettyPrinting().create();
    private static final Logger logger = LogManager.getLogger(App.class.getName());
    private static final String DATE = new SimpleDateFormat("dd-MM-yyyy").format(new Date());
    private Settings settings;
    private PircBotX pirc;

    private boolean shutDown = false;

    private boolean isShuttingDown = false;

    private Map<String, Date> userJoined = new ConcurrentHashMap<>();
    private Map<String, Map<String, Integer>> userOnlineTime = new ConcurrentHashMap<>();
    private Map<String, List<ChatLog>> userLogs = new ConcurrentHashMap<>();
    private List<Event> events = new ArrayList<>();
    private Map<String, Integer> streamOnlineTime = new ConcurrentHashMap<>();

    private Map<String, String> lang = new HashMap<>();

    private List<Spam> spams = new ArrayList<>();
    private List<String> allowedLinks = new ArrayList<>();
    private List<TimedMessage> timedMessages = new ArrayList<>();

    private StartupListener startupListener = new StartupListener(this);
    private UserListener userListener = new UserListener(this);
    private CommandListener commandListener = new CommandListener(this);
    private SpamListener spamListener = new SpamListener(this);
    private LinkListener linkListener = new LinkListener(this);
    private TrollChatListener trollChatListener = new TrollChatListener(this);

    private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

    private Map<String, Integer> topUsers;

    private boolean firstTime = false;

    public AllmightyBot() {
        if (Files.exists(Utils.getSettingsFile())) {
            try {
                this.settings = GSON.fromJson(FileUtils.readFileToString(Utils.getSettingsFile().toFile()),
                        Settings.class);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            this.settings = new Settings();
        }

        if (!this.settings.hasInitialSetupBeenCompleted()) {
            String input = null;

            input = JOptionPane.showInputDialog(null,
                    "Please enter the username of the Twitch user " + "to act " + "as the bot", "Twitch Username",
                    JOptionPane.QUESTION_MESSAGE);

            if (input == null) {
                logger.error("Failed to input proper things when setting up! Do it properly next time!");
                System.exit(0);
            }

            settings.setTwitchUsername(input);

            input = JOptionPane.showInputDialog(null,
                    "Please enter the IRC oauth token of the Twitch user " + "acting as the bot", "Twitch Token",
                    JOptionPane.QUESTION_MESSAGE);

            if (input == null) {
                logger.error("Failed to input proper things when setting up! Do it properly next time!");
                System.exit(0);
            }

            settings.setTwitchToken(input);

            input = JOptionPane.showInputDialog(null,
                    "Please enter the API token of the Twitch user " + "acting " + "as the bot", "Twitch API Token",
                    JOptionPane.QUESTION_MESSAGE);

            if (input == null) {
                logger.error("Failed to input proper things when setting up! Do it properly next time!");
                System.exit(0);
            }

            settings.setTwitchApiToken(input);

            input = JOptionPane.showInputDialog(null,
                    "Please enter the API client ID of the application using " + "the Twitch API",
                    "Twitch API Client ID", JOptionPane.QUESTION_MESSAGE);

            if (input == null) {
                logger.error("Failed to input proper things when setting up! Do it properly next time!");
                System.exit(0);
            }

            settings.setTwitchApiClientID(input);

            input = JOptionPane.showInputDialog(null,
                    "Please enter the username of the Twitch user whose "
                            + "channel you wish to join! Must be in all lowercase",
                    "User To Join", JOptionPane.QUESTION_MESSAGE);

            if (input == null) {
                logger.error("Failed to input proper things when setting up! Do it properly next time!");
                System.exit(0);
            }

            settings.setTwitchChannel(input);

            input = JOptionPane.showInputDialog(null,
                    "Please enter the name of the caster to display when " + "referencing them", "Casters Name",
                    JOptionPane.QUESTION_MESSAGE);

            if (input == null) {
                logger.error("Failed to input proper things when setting up! Do it properly next time!");
                System.exit(0);
            }

            settings.setCastersName(input);

            input = JOptionPane.showInputDialog(null,
                    "How often do you want to run the timed messages (in " + "minutes)?", "Timed Messages",
                    JOptionPane.QUESTION_MESSAGE);
            try {
                settings.setTimedMessagesInterval(Integer.parseInt(input) * 60);
            } catch (NumberFormatException e) {
                input = null;
            }

            input = JOptionPane.showInputDialog(null, "How long do you want to time people out for when they post "
                    + "links after 1 warning (in minutes)?", "Spam Timeouts", JOptionPane.QUESTION_MESSAGE);
            try {
                settings.setLinkTimeoutLength1(Integer.parseInt(input) * 60);
            } catch (NumberFormatException e) {
                input = null;
            }

            input = JOptionPane.showInputDialog(null,
                    "How long do you want to time people out for when they post "
                            + "links after 2 and more warnings (in minutes)?",
                    "Spam Timeouts", JOptionPane.QUESTION_MESSAGE);
            try {
                settings.setLinkTimeoutLength2(Integer.parseInt(input) * 60);
            } catch (NumberFormatException e) {
                input = null;
            }

            if (input == null) {
                logger.error("Failed to input proper things when setting up! Do it properly next time!");
                System.exit(0);
            }

            int reply = JOptionPane.showConfirmDialog(null,
                    "Do you want the bot to announce itself on join " + "(message "
                            + "customisable in the lang.json file after startup)?",
                    "Self Announce", JOptionPane.YES_NO_OPTION);
            if (reply != JOptionPane.YES_OPTION) {
                settings.setAnnounceOnJoin(false);
            }

            this.settings.initialSetupComplete();
            this.firstTime = true;
        }
    }

    private void loadBot() {
        Configuration.Builder<PircBotX> config = this.settings.getBuilder();

        String chatServerIP = null;
        try {
            chatServerIP = TwitchAPI.getChatServerIP(this.settings.getTwitchChannel());
            config.setServerHostname(chatServerIP);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }

        // Register the different listeners
        config.addListener(this.startupListener);
        config.addListener(this.userListener);
        config.addListener(this.commandListener);
        config.addListener(this.spamListener);
        config.addListener(this.linkListener);
        config.addListener(this.trollChatListener);

        addShutdownHook();

        this.pirc = new PircBotX(config.buildConfiguration());
    }

    private void addShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                shutDown();
            }
        }));
    }

    /**
     * Starts the bot up
     */

    public void startUp(boolean newStream) {
        logger.info("Bot starting up!");

        loadBot();

        if (newStream) {
            logger.info("This is a new stream!");
            this.settings.setStartTime(new Date());
            this.saveSettings();
        } else {
            logger.info("This is continuing an existing stream!");
        }

        if (this.firstTime) {
            logger.info("Creating default files!");
            this.settings.setupExampleStuff();
        }

        // Check the Twitch API token to make sure it's all good
        TwitchAPI.checkToken();

        loadCommands();
        loadUserChatLogs();
        loadUserOnlineTime();
        loadStreamOnlineTime();
        loadLang();
        loadSpamWatchers();
        loadTimedMessages();
        loadAllowedLinks();
        loadEvents();
        loadInitialUsers();

        Runnable r = new Runnable() {
            public void run() {
                while (true) {
                    if (shutDown) {
                        shutDown();
                        break;
                    }

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        new Thread(r).start();

        try {
            this.pirc.startBot();
        } catch (IOException | IrcException e) {
            e.printStackTrace();
        }

        System.exit(0);
    }

    private void loadEvents() {
        // Load the events from a previous run for today if they exist
        if (Files.exists(Utils.getEventsFile())) {
            try {
                Type listType = new TypeToken<ArrayList<Event>>() {
                }.getType();
                this.events = GSON.fromJson(FileUtils.readFileToString(Utils.getEventsFile().toFile()), listType);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void loadInitialUsers() {
        try {
            String json = Utils.readURLToString(
                    "http://tmi.twitch.tv/group/user/" + this.settings.getTwitchChannel() + "/chatters");
            TwitchChatters chatters = GSON.fromJson(json, TwitchChatters.class);

            for (Map.Entry<String, List<String>> entry : chatters.getChatters().entrySet()) {
                String key = entry.getKey();
                List<String> value = entry.getValue();

                for (String user : value) {
                    this.userJoined(user);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void loadCommands() {
        // Add all the commands
        try {
            Type listType = new TypeToken<ArrayList<TempCommand>>() {
            }.getType();
            List<TempCommand> tempCommands = GSON
                    .fromJson(FileUtils.readFileToString(Utils.getCommandsFile().toFile()), listType);

            if (tempCommands != null) {
                for (TempCommand command : tempCommands) {
                    try {
                        Class<?> commandClass = Class.forName(command.getType());
                        Constructor<?> commandConstructor;
                        Command commandToAdd;

                        if (command.isSeedCommand()) {
                            commandConstructor = commandClass.getConstructor(String.class, SeedType.class,
                                    int.class);
                            commandToAdd = (BaseCommand) commandConstructor.newInstance(command.getName(),
                                    command.getSeedType(), command.getTimeout());
                        } else if (command.isQuoteCommand()) {
                            commandConstructor = commandClass.getConstructor(String.class, QuoteType.class,
                                    int.class);
                            commandToAdd = (BaseCommand) commandConstructor.newInstance(command.getName(),
                                    command.getQuoteType(), command.getTimeout());
                        } else if (command.isWorldCommand()) {
                            commandConstructor = commandClass.getConstructor(String.class, WorldType.class,
                                    int.class);
                            commandToAdd = (BaseCommand) commandConstructor.newInstance(command.getName(),
                                    command.getWorldType(), command.getTimeout());
                        } else if (command.isAliasCommand()) {
                            commandConstructor = commandClass.getConstructor(String.class, String.class, int.class);
                            commandToAdd = (BaseCommand) commandConstructor.newInstance(command.getName(),
                                    command.getAliasedTo(), command.getTimeout());
                        } else if (command.hasReply()) {
                            commandConstructor = commandClass.getConstructor(String.class, String.class, int.class);
                            commandToAdd = (BaseCommand) commandConstructor.newInstance(command.getName(),
                                    command.getReply(), command.getTimeout());
                        } else {
                            commandConstructor = commandClass.getConstructor(String.class, int.class);
                            commandToAdd = (BaseCommand) commandConstructor.newInstance(command.getName(),
                                    command.getTimeout());
                        }

                        commandToAdd.setLevel(command.getLevel());

                        commandToAdd.load(); // Load anything the command requires

                        CommandBus.add(commandToAdd);
                        logger.debug("Added command !" + command.getName() + " of type " + command.getType());
                    } catch (ClassNotFoundException | InstantiationException | InvocationTargetException
                            | NoSuchMethodException | IllegalAccessException e) {
                        logger.error("Error loading command !" + command.getName() + " with type of "
                                + command.getType());
                        if (this.getSettings().shouldForceCommands()) {
                            logger.error("Force commands setting is on so we must exit since a command failed to "
                                    + "load!");
                            System.exit(1);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void loadUserChatLogs() {
        try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Utils.getUsersDir())) {
            for (Path path : directoryStream) {
                if (Files.isDirectory(path)) {
                    String username = path.getFileName().toString();
                    if (Files.exists(Utils.getUserChatFile(username))) {
                        Type type = new TypeToken<List<ChatLog>>() {
                        }.getType();
                        List<ChatLog> chatMessages = GSON.fromJson(
                                FileUtils.readFileToString(Utils.getUserChatFile(username).toFile()), type);
                        this.userLogs.put(username, chatMessages);
                    }
                }
            }
        } catch (IOException ex) {
        }
    }

    private void loadUserOnlineTime() {
        try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Utils.getUsersDir())) {
            for (Path path : directoryStream) {
                if (Files.isDirectory(path)) {
                    String username = path.getFileName().toString();
                    if (Files.exists(Utils.getUserLoginTimeFile(username))) {
                        Type type = new TypeToken<Map<String, Integer>>() {
                        }.getType();
                        Map<String, Integer> timeInChannel = GSON.fromJson(
                                FileUtils.readFileToString(Utils.getUserLoginTimeFile(username).toFile()), type);
                        this.userOnlineTime.put(username, timeInChannel);
                    }
                }
            }
        } catch (IOException ex) {
        }
    }

    private void loadStreamOnlineTime() {
        if (!Files.exists(Utils.getStreamOnlineTimeFile())) {
            return;
        }

        try {
            Type type = new TypeToken<Map<String, Integer>>() {
            }.getType();
            this.streamOnlineTime = GSON
                    .fromJson(FileUtils.readFileToString(Utils.getStreamOnlineTimeFile().toFile()), type);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void loadLang() {
        if (!Files.exists(Utils.getLangFile())) {
            logger.error("Error! Cannot find the lang.json file! We have to exit!");
            System.exit(1);
        }

        try {
            Type type = new TypeToken<Map<String, String>>() {
            }.getType();
            this.lang = GSON.fromJson(FileUtils.readFileToString(Utils.getLangFile().toFile()), type);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void loadSpamWatchers() {
        // Add all spam banning/timeout things
        try {
            Type listType = new TypeToken<ArrayList<Spam>>() {
            }.getType();
            this.spams = GSON.fromJson(FileUtils.readFileToString(Utils.getSpamFile().toFile()), listType);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void loadTimedMessages() {
        try {
            Type listType = new TypeToken<ArrayList<TimedMessage>>() {
            }.getType();
            this.timedMessages = GSON.fromJson(FileUtils.readFileToString(Utils.getTimedMessagesFile().toFile()),
                    listType);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void loadAllowedLinks() {
        // Add all allowed links
        try {
            Type listType = new TypeToken<ArrayList<String>>() {
            }.getType();
            this.allowedLinks = GSON.fromJson(FileUtils.readFileToString(Utils.getLinksFile().toFile()), listType);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void reload() {
        for (Map.Entry<String, Command> entry : CommandBus.getAll().entrySet()) {
            Command command = entry.getValue();
            command.save();
        }

        CommandBus.removeAll();

        loadCommands();

        this.spams.clear();

        loadSpamWatchers();
    }

    /**
     * Issues a shutdown command to safely shutdown and save all files needed
     */
    public void shutDown() {
        if (isShuttingDown) {
            return;
        }

        this.isShuttingDown = true;

        logger.info("Bot shutting down!");

        for (Map.Entry<String, Command> entry : CommandBus.getAll().entrySet()) {
            Command command = entry.getValue();
            command.save();
        }

        try {
            saveSettings();
            saveAllOnlineTime();

            for (Map.Entry<String, Map<String, Integer>> entry : this.userOnlineTime.entrySet()) {
                String key = entry.getKey();
                Map<String, Integer> value = entry.getValue();

                if (key == null || value == null) {
                    continue;
                }

                FileUtils.write(Utils.getUserLoginTimeFile(key).toFile(), GSON.toJson(value));
            }
            logger.debug("User login time saved!");

            for (Map.Entry<String, List<ChatLog>> entry : this.userLogs.entrySet()) {
                String key = entry.getKey();
                List<ChatLog> values = entry.getValue();

                if (key == null || values == null) {
                    continue;
                }

                FileUtils.write(Utils.getUserChatFile(key).toFile(), GSON.toJson(values));
            }
            logger.debug("User logs saved!");

            FileUtils.write(Utils.getEventsFile().toFile(), GSON.toJson(this.events));
            logger.debug("Events saved!");

            saveStreamOnlineTime();

            FileUtils.write(Utils.getStreamOnlineTimeFile().toFile(), GSON.toJson(this.streamOnlineTime));
            logger.debug("Online Time saved!");
        } catch (IOException e) {
            e.printStackTrace();
        }

        this.pirc.sendIRC().quitServer("Bye");
    }

    private void saveSettings() {
        try {
            FileUtils.write(Utils.getSettingsFile().toFile(), GSON.toJson(this.settings));
            logger.debug("Settings saved!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void saveStreamOnlineTime() {
        // Calculate and add the time we've been online for today
        int timeOnline = (int) Utils.getDateDiff(this.settings.getStartTime(), new Date(), TimeUnit.SECONDS);
        this.streamOnlineTime.put(DATE, timeOnline);
    }

    public int timeInChannel(String nick) {
        if (this.isShuttingDown) {
            logger.debug("We're shutting down, so no more requests please!");
        }

        if (nick == null) {
            logger.debug("A null user was passed into timeInChannel!");
            return 0;
        }

        if (nick.equalsIgnoreCase(this.getSettings().getTwitchUsername())) {
            return 0; // Bot should not be considered here
        }

        if (!this.userOnlineTime.containsKey(nick)) {
            return 0;
        }

        int timeOnline = 0;

        for (Map.Entry<String, Integer> entry : this.userOnlineTime.get(nick).entrySet()) {
            timeOnline += entry.getValue();
        }

        Date joined = this.userJoined.get(nick);

        if (joined != null) {
            // Add the time they've been in the channel for now
            timeOnline += (int) Utils.getDateDiff(joined, new Date(), TimeUnit.SECONDS);
        }

        return timeOnline;
    }

    public void userJoined(String nick) {
        if (this.isShuttingDown) {
            logger.debug("We're shutting down, so no more requests please!");
        }

        if (nick == null) {
            logger.debug("A null user joined!");
            return;
        }

        nick = nick.toLowerCase();

        if (nick.equalsIgnoreCase(this.getSettings().getTwitchUsername())) {
            return; // Bot should not be considered here
        }

        logger.debug("User " + nick + " joined!");
        this.events.add(new Event(EventType.USERJOIN, nick));

        Date joined = this.userJoined.get(nick);

        if (joined == null) {
            // User has just joined
            joined = new Date();
        } else {
            // User was already joined so add their time
            Map<String, Integer> timeOnline = this.userOnlineTime.get(nick);
            int online = 0;

            if (timeOnline != null && timeOnline.containsKey(DATE)) {
                online = timeOnline.get(DATE);
                online += (int) Utils.getDateDiff(joined, new Date(), TimeUnit.SECONDS);
            } else {
                timeOnline = new HashMap<>();
            }

            timeOnline.put(DATE, online);

            this.userOnlineTime.put(nick, timeOnline);
        }

        this.userJoined.put(nick, joined);
    }

    public void userParted(String nick, boolean kicked) {
        if (this.isShuttingDown) {
            logger.debug("We're shutting down, so no more requests please!");
        }

        if (nick == null) {
            logger.debug("A null user parted!");
            return;
        }

        nick = nick.toLowerCase();

        if (nick.equalsIgnoreCase(this.getSettings().getTwitchUsername())) {
            return; // Bot should not be considered here
        }

        logger.debug("User " + nick + " parted!");
        this.events.add(new Event((kicked ? EventType.USERKICK : EventType.USERPART), nick));

        Date joined = this.userJoined.get(nick);

        this.saveOnlineTime(nick, joined);
    }

    private void saveAllOnlineTime() {
        for (Map.Entry<String, Date> entry : this.userJoined.entrySet()) {
            this.saveOnlineTime(entry.getKey(), entry.getValue());
        }
    }

    private void saveOnlineTime(String username, Date joinedTime) {
        Map<String, Integer> timeOnline = this.userOnlineTime.get(username);
        int online = 0;

        if (timeOnline == null) {
            timeOnline = new HashMap<>();
        }

        if (timeOnline.containsKey(DATE)) {
            online = timeOnline.get(DATE);
        }

        online += (int) Utils.getDateDiff(joinedTime, new Date(), TimeUnit.SECONDS);

        timeOnline.put(DATE, online);

        this.userOnlineTime.put(username, timeOnline);

        this.userJoined.remove(username);
    }

    public void userSpoke(String nick, String message) {
        if (this.isShuttingDown) {
            logger.debug("We're shutting down, so no more requests please!");
        }

        if (nick == null) {
            logger.debug("A null user spoke!");
            return;
        }

        nick = nick.toLowerCase();

        if (nick.equalsIgnoreCase(this.getSettings().getTwitchUsername())) {
            return; // Bot should not be considered here
        }

        logger.debug("User " + nick + " spoke!");
        this.events.add(new Event(EventType.USERMESSAGE, nick));

        if (!this.userOnlineTime.containsKey(nick)) {
            this.userJoined(nick);
        }

        List<ChatLog> logs = this.userLogs.get(nick);

        if (logs == null) {
            logs = new ArrayList<>();
        }

        logs.add(new ChatLog(nick, message));

        this.userLogs.put(nick, logs);
    }

    public Settings getSettings() {
        return this.settings;
    }

    public boolean isRegular(String nick) {
        return false;
    }

    public List<Spam> getSpams() {
        return this.spams;
    }

    public void removeStartupListener() {
        if (this.startupListener != null) {
            this.pirc.getConfiguration().getListenerManager().removeListener(this.startupListener);
            this.startupListener = null;
        }
    }

    public void removeUserListener() {
        if (this.userListener != null) {
            this.pirc.getConfiguration().getListenerManager().removeListener(this.userListener);
            this.userListener = null;
        }
    }

    public void removeCommandListener() {
        if (this.commandListener != null) {
            this.pirc.getConfiguration().getListenerManager().removeListener(this.commandListener);
            this.commandListener = null;
        }
    }

    public void removeSpamListener() {
        if (this.spamListener != null) {
            this.pirc.getConfiguration().getListenerManager().removeListener(this.spamListener);
            this.spamListener = null;
        }
    }

    public void removeLinkListener() {
        if (this.linkListener != null) {
            this.pirc.getConfiguration().getListenerManager().removeListener(this.linkListener);
            this.linkListener = null;
        }
    }

    public void removeTrollChatListener() {
        if (this.trollChatListener != null) {
            this.pirc.getConfiguration().getListenerManager().removeListener(this.trollChatListener);
            this.trollChatListener = null;
        }
    }

    public void triggerShutdown() {
        // Remove the listeners
        this.removeStartupListener();
        this.removeUserListener();
        this.removeCommandListener();
        this.removeSpamListener();
        this.removeLinkListener();
        this.removeTrollChatListener();

        this.shutDown = true;
    }

    public int getTotalLiveTime(boolean forceSave) {
        int timeOnline = 0;

        if (forceSave) {
            saveStreamOnlineTime();
        }

        for (Map.Entry<String, Integer> entry : this.streamOnlineTime.entrySet()) {
            timeOnline += entry.getValue();
        }

        return timeOnline;
    }

    public List<String> getAllowedLinks() {
        return this.allowedLinks;
    }

    public boolean isModerator(String username) {
        for (String mod : this.settings.getModerators()) {
            if (mod.equalsIgnoreCase(username)) {
                return true;
            }
        }

        return false;
    }

    public void startTimedMessages() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                Channel toRun = null;
                for (Channel channel : pirc.getUserChannelDao().getAllChannels()) {
                    if (channel.getName().contains(settings.getTwitchChannel().toLowerCase())) {
                        toRun = channel;
                        break;
                    }
                }

                if (toRun == null) {
                    return;
                }

                // Run a random one of the Times Messages

                Random randomGenerator = new Random();
                int index = randomGenerator.nextInt(timedMessages.size());
                TimedMessage message = timedMessages.get(index);

                toRun.send().message(message.getMessage());
            }
        };

        this.executor.scheduleAtFixedRate(runnable, settings.getTimedMessagesInterval(),
                settings.getTimedMessagesInterval(), TimeUnit.SECONDS);
    }

    public String getLangValue(String key) {
        if (!this.lang.containsKey(key)) {
            logger.error("No lang value set for key " + key);
            return "Oh noes!";
        }

        return this.lang.get(key);
    }

    public Date getLastSpokeTime(String username) {
        username = username.toLowerCase();

        if (!this.userLogs.containsKey(username)) {
            return null;
        }

        return this.userLogs.get(username).get(this.userLogs.get(username).size() - 1).getTime();
    }

    public Date getFirstSpokeTime(String username) {
        username = username.toLowerCase();

        if (!this.userLogs.containsKey(username)) {
            return new Date();
        }

        return this.userLogs.get(username).get(0).getTime();
    }

    public List<TimedMessage> getTimedMessages() {
        return this.timedMessages;
    }

    public List<ChatLog> getUsersChatLog(String username) {
        return this.userLogs.get(username.toLowerCase());
    }
}