diff --git a/languages/cs.yml b/languages/cs.yml index 88aea7fbe..3cf651e10 100644 --- a/languages/cs.yml +++ b/languages/cs.yml @@ -1,7 +1,7 @@ language: name: "Czech" locale: "cs" - version: "2.3.7" + version: "2.4.0" author: "Pogy__" logging: banned: ":airplane_departure: %s **zablokován.**" @@ -182,6 +182,10 @@ label: position: "Pozice %s" feedback: "Zpětná vazba" github: "Github" + queueAdd: "Přidat do fronty" + song: "Skladba" + shuffle: "Zamíchat" + loop: "Smyčka" message: default: usage: "Použití {guild_prefix}%s." @@ -208,6 +212,10 @@ message: invalidOptionChannel: "Daný kanál neexistuje, jak jej vybrat? Jste průvodce?" missingOption: "Musíte zadat hodnotu pro možnost %s!" nameChangeFailed: "Nelze změnit mou vlastní přezdívku!" + time: + date: "Použijte platné datum!\nVezměte prosím na vědomí, že používáme formát dd.MM.yyyy (day.month.year)!" + time: "Použijte prosím platný čas!\\nPamatuj, že používáme formát HH/mm (hodina/minuta)!" + notEnough: "Zadaný čas nestačí!" birthday: added: self: "Vaše narozeniny byly přidány!" @@ -217,8 +225,6 @@ message: self: "Vaše narozeniny byly odstraněny!" other: "Narozeniny %s byly odstraněny!" noPerms: "Nemáte oprávnění k odstranění narozenin!" - other: - dateError: "Použijte platné datum!\nVezměte prosím na vědomí, že používáme formát dd.MM.yyyy (day.month.year)!" instagramNotifier: added: "Bylo vytvořeno oznámení Instagram pro uživatele %s!" list: "Zde jsou všechny Instagram oznámení které byly nastaveny:\n```%s```" @@ -349,6 +355,7 @@ message: resume: "Hráč byl obnoven!" shuffle: "Fronta byla zamíchána!" songInfo: "**Skladba:**```%s od %s```\n%s `[%s/%s]` %s" + songInfoSlim: "%s od %s" songQueueEmpty: "Fronta je prázdná!" songQueue: "Fronta obsahuje následující skladby: %s" volume: @@ -512,6 +519,12 @@ message: infractions: success: "Uživatel %s má %s přestupků!" empty: "Uživatel %s nema žádné přestupky!" + schedule: + added: "The schedule has been successfully created!" + delete: + success: "The schedule has been successfully deleted!" + failed: "The given schedule does not exist!" + list: "Here is a list of all schedules: ```%s```" game: description: blackjack: "Hrajte Blackjack se svými přáteli!" @@ -606,6 +619,8 @@ command: warn: "Upozornit uživatele a nechat je potrestat automaticky." infractions: "Zobrazit všechna varování uživatele." musicquiz: "Zahrajte si s přáteli hudební kvíz!" + musicpanel: "Přístup k jednoduchému uživatelskému rozhraní pro správu hudebního systému!" + schedule: "Naplánovat zprávy na později nebo na opakovaný čas!" category: info: "Slouží ke shromažďování informací nebo poskytování informací." moderation: "Nástroje pro moderování, které vám mohou pomoci spravovat uživatele nebo zabránit porušení pravidel na serveru." diff --git a/languages/de.yml b/languages/de.yml index f6d49652c..628de4d91 100644 --- a/languages/de.yml +++ b/languages/de.yml @@ -1,7 +1,7 @@ language: name: "German" locale: "de" - version: "2.3.7" + version: "2.4.0" author: "Presti" logging: banned: ":airplane_departure: %s **gebannt.**" @@ -182,6 +182,10 @@ label: position: "Position %s" feedback: "Feedback" github: "Github" + queueAdd: "Zur Song-Liste hinzufügen" + song: "Song" + shuffle: "Mischen" + loop: "Song-Schleife" message: default: usage: "Nutzung {guild_prefix}%s." @@ -208,6 +212,10 @@ message: invalidOptionChannel: "Dieser Channel ist nicht bekannt. Kannst du zaubern?" missingOption: "Du musst einen Wert für die Option %s angeben!" nameChangeFailed: "Ich konnte meinen eigenen Nickname nicht bearbeiten!" + time: + date: "Bitte gebe ein richtiges Datum an!\nTipp wir nutzen das dd.MM.yyy (tag.monat.jahr) Format!" + time: "Bitte gebe eine richtige Zeit an!\nTipp wir nutzen das HH/mm (stunde/minute (24-stunden)) Format!" + notEnough: "Die angegebene Zeit ist nicht genügend!" birthday: added: self: "Dein Geburtstag wurde hinzugefügt!" @@ -217,8 +225,6 @@ message: self: "Dein Geburtstag wurde entfernt!" other: "Der Geburtstag von %s wurde entfernt!" noPerms: "Du hast keine Berechtigung um Geburtstage zu entfernen!" - other: - dateError: "Bitte nutze das richtige Datums format! (day.month.year)!" instagramNotifier: added: "Ein Instagram Notifier wurde für %s erstellt!" list: "Hier ist eine Liste mit allen Instagram Notifier:\n```%s```" @@ -349,6 +355,7 @@ message: resume: "Der Musikspieler wurde fortgesetzt!" shuffle: "Die Songliste wurde gemischt!" songInfo: "**Song:**```%s von %s```\n%s `[%s/%s]` %s" + songInfoSlim: "%s von %s" songQueueEmpty: "Die Songliste ist leer!" songQueue: "Die Songliste enthält diese Songs: %s" volume: @@ -512,6 +519,12 @@ message: infractions: success: "Der Nutzer %s hat %s Verwarnungen!" empty: "Der Nutzer %s hat keine Verwarnungen!" + schedule: + added: "Eine geplante Nachricht wurde erfolgreich erstellt!" + delete: + success: "Eine geplante Nachricht wurde erfolgreich gelöscht!" + failed: "Die angegebene geplante Nachricht existiert nicht!" + list: "Hier ist eine Liste aller geplanten Nachrichten: ```%s```" game: description: blackjack: "Spiele Blackjack mit deinen Freunden!" @@ -606,6 +619,8 @@ command: warn: "Warne einen Nutzer und lass ihn automatisch bestraft werden." infractions: "Zeige alle Verwarnungen eines Nutzers an." musicquiz: "Spiele mit deinen Freunden eine Runde Musik Quiz!" + musicpanel: "Ein simples UI zum Nutzen vom Musik System!" + schedule: "Plane Nachrichten für später und für eine wiederholte Zeit!" category: info: "Wird verwendet, um Informationen zu sammeln oder Informationen zu geben." moderation: "Moderations-Tools, die Ihnen beim Verwalten von Benutzern helfen oder das Missachten von Regeln auf dem Server verhindern können." diff --git a/languages/en-GB.yml b/languages/en-GB.yml index 914332b5d..fb0ecd8e1 100644 --- a/languages/en-GB.yml +++ b/languages/en-GB.yml @@ -1,7 +1,7 @@ language: name: "English (UK)" locale: "en-GB" - version: "2.3.7" + version: "2.4.0" author: "Presti" logging: banned: ":airplane_departure: %s **banned.**" @@ -214,7 +214,7 @@ message: nameChangeFailed: "Could not change the my own nickname!" time: date: "Please use a valid Date!\nNote that we use the the format dd.MM.yyyy (day.month.year)!" - time: "Please use a valid Time!\Note that we use the format HH/mm (hour/minute (24-hour))" + time: "Please use a valid Time!\nNote that we use the format HH/mm (hour/minute (24-hour))!" notEnough: "The entered time is not enough!" birthday: added: @@ -519,6 +519,12 @@ message: infractions: success: "The User %s has %s infractions!" empty: "The User %s has no infractions!" + schedule: + added: "The schedule has been successfully created!" + delete: + success: "The schedule has been successfully deleted!" + failed: "The given schedule does not exist!" + list: "Here is a list of all schedules: ```%s```" game: description: blackjack: "Play Blackjack with your friends!" diff --git a/languages/id.yml b/languages/id.yml index d65fd681c..2abc03dbd 100644 --- a/languages/id.yml +++ b/languages/id.yml @@ -1,7 +1,7 @@ language: name: "Indonesia" locale: "id" - version: "2.3.7" + version: "2.4.0" author: "Gorengan_Hunter, SpyCat" logging: banned: ":airplane_departure: %s **telah diban.**" @@ -182,6 +182,10 @@ label: position: "Posisi %s" feedback: "Masukan" github: "Github" + queueAdd: "Tambahkan ke antrian" + song: "Lagu" + shuffle: "Acak" + loop: "Ulang" message: default: usage: "Penggunaan {guild_prefix}%s." @@ -208,6 +212,10 @@ message: invalidOptionChannel: "Channel yang diberikan tidak ada, bagaimana kamu memilih ini? Apakah kamu seorang penyihir?" missingOption: "Kamu perlu memberikan nilai untuk opsi %s!" nameChangeFailed: "Tidak dapat mengganti nickname ku!" + time: + date: "Harap gunakan tanggal yang valid!\nPerhatikan bahwa kami menggunakan format dd.MM.yyyy (day.month.year)!" + time: "Harap gunakan waktu yang valid!\nPerhatikan bahwa kami menggunakan format HH/mm (jam/menit (24-jam))!" + notEnough: "Waktu yang dimasukkan tidak cukup!" birthday: added: self: "Ulang Tahun mu telah ditambahkan!" @@ -217,8 +225,6 @@ message: self: "Ulang Tahun mu telah dihapus!" other: "Ulang Tahun %s telah dihapus!" noPerms: "Kamu tidak punya izin untuk menghapus Ulang Tahun!" - other: - dateError: "Harap gunakan tanggal yang valid!\nPerhatikan bahwa kami menggunakan format dd.MM.yyyy (day.month.year)!" instagramNotifier: added: "Pemberitahuan Instagram telah dibuat untuk %s!" list: "Dibawah ini daftar Notifier Instagram yang telah disetup:\n```%s```" @@ -349,6 +355,7 @@ message: resume: "Pemutar telah di ditemukan!" shuffle: "Antrian telah diacak!" songInfo: "**Lagu:**```%s oleh %s```\n%s `[%s/%s]` %s" + songInfoSlim: "%s oleh %s" songQueueEmpty: "Antrian kosong!" songQueue: "Di antrian terdapat musik berikut: %s" volume: @@ -512,6 +519,12 @@ message: infractions: success: "User %s memiliki %s pelanggaran!" empty: "User %s tidak memiliki pelanggaran!" + schedule: + added: "The schedule has been successfully created!" + delete: + success: "The schedule has been successfully deleted!" + failed: "The given schedule does not exist!" + list: "Here is a list of all schedules: ```%s```" game: description: blackjack: "Mainkan Blackjack dengan temanmu!" @@ -606,6 +619,8 @@ command: warn: "Peringati user dan biarkan dia dihukum otomatis." infractions: "Tampilkan semua peringatan yang dimiliki user." musicquiz: "Mainkan Kuis Musik dengan teman anda!" + musicpanel: "Akses UI sederhana untuk mengelola Sistem Musik!" + schedule: "Jadwalkan pesan untuk nanti atau untuk diulang!" category: info: "Dipakai untuk mendapatkan informasi atau memberi informasi." moderation: "Alat moderasi untuk membantumu menjaga servermu!" diff --git a/languages/pl.yml b/languages/pl.yml index 763dcc18e..76024cd31 100644 --- a/languages/pl.yml +++ b/languages/pl.yml @@ -1,7 +1,7 @@ language: name: "Polish" locale: "pl" - version: "2.3.7" + version: "2.4.0" author: "Trust" logging: banned: ":airplane_departure: %s **zbanowany/a.**" @@ -182,6 +182,10 @@ label: position: "Pozycja %s" feedback: "Informacja do producenta" github: "GitHub" + queueAdd: "Dodaj do kolejki" + song: "Pieśń" + shuffle: "Losuj" + loop: "Pętla" message: default: usage: "Użycie {guild_prefix}%s." @@ -208,6 +212,10 @@ message: invalidOptionChannel: "Podany kanał nie istnieje, jak go wybrałeś? Czy jesteś Czarodziejem?" missingOption: "Musisz podać wartość dla opcji %s!" nameChangeFailed: "Nie mogłem zmienić swoje imię!" + time: + date: "Proszę użyć poprawnej daty!\nZauważ, że używamy formatu dd.mm.rrrr (dzień.miesiąc.rok)!" + time: "Proszę użyć poprawnego czasu!\nPamiętaj, że używamy formatu HH/mm (godzina/minuta (24-godziny))!" + notEnough: "Wprowadzony czas nie wystarczy!" birthday: added: self: "Twoje urodziny zostały dodane!" @@ -217,8 +225,6 @@ message: self: "Twoje urodziny zostały usunięte!" other: "Urodziny %s zostały usunięte!" noPerms: "Nie masz uprawnień do usunięcia urodzin!" - other: - dateError: "Proszę użyć poprawnej daty!\nZauważ, że używamy formatu dd.mm.rrrr (dzień.miesiąc.rok)!" instagramNotifier: added: "Powiadomienie o Instagramie zostało utworzone dla użytkownika %s!" list: "Tutaj są wszystkie powiadomienia o Instagram'u, które zostały skonfigurowane:\n```%s```" @@ -349,6 +355,7 @@ message: resume: "Odtwarzacz został wznowiony!" shuffle: "Kolejka została zlosowana!" songInfo: "**Pieśń:**```%s autorstwa %s```\n%s `[%s/%s]` %s" + songInfoSlim: "%s autorstwa %s" songQueueEmpty: "Kolejka jest pusta!" songQueue: "Kolejka zawiera następujące pieśni: %s" volume: @@ -512,6 +519,12 @@ message: infractions: success: "Użytkownik %s ma %s infrakcji!" empty: "Użytkownik %s nie ma żadnych infrakcji!" + schedule: + added: "Harmonogram został utworzony!" + delete: + success: "Harmonogram został usunięty!" + failed: "Podany harmonogram nie istnieje!" + list: "Oto lista wszystkich harmonogramów: ```%s```" game: description: blackjack: "Zagraj w Blackjack z przyjaciółmi!" @@ -606,6 +619,8 @@ command: warn: "Ostrzegaj użytkownika i pozwól im być karani automatycznie." infractions: "Pokaż wszystkie ostrzeżenia użytkownika." musicquiz: "Zagraj z przyjaciółmi grę w Quiz!" + musicpanel: "Uzyskaj dostęp do prostego interfejsu użytkownika, aby zarządzać systemem muzycznym!" + schedule: "Zaplanuj wiadomości na później lub na powtarzający się czas!" category: info: "Wykorzystywane do gromadzenia informacji lub przekazywania informacji." moderation: "Narzędzia moderacyjne, które mogą pomóc ci zarządzać użytkownikami lub zapobiec łamania zasad na serwerze." diff --git a/pom.xml b/pom.xml index 5e5fc45bb..b05b55cb1 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ de.presti Ree6 - 2.3.9 + 2.4.0 jar @@ -52,7 +52,7 @@ net.dv8tion JDA - 5.0.0-beta.5 + 5.0.0-beta.6 com.github.walkyst @@ -74,7 +74,7 @@ io.sentry sentry - 6.15.0 + 6.16.0 me.carleslc.Simple-YAML @@ -144,19 +144,19 @@ com.github.Ree6-Applications Ree6-SQL - 1b00250427 + 433261d192 org.slf4j slf4j-api - 2.0.6 + 2.0.7 ch.qos.logback logback-classic - 1.4.5 + 1.4.6 diff --git a/src/main/java/de/presti/ree6/audio/music/MusicWorker.java b/src/main/java/de/presti/ree6/audio/music/MusicWorker.java index 9dbfe9ebe..b8f68d8e7 100644 --- a/src/main/java/de/presti/ree6/audio/music/MusicWorker.java +++ b/src/main/java/de/presti/ree6/audio/music/MusicWorker.java @@ -4,7 +4,6 @@ import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; import com.sedmelluq.discord.lavaplayer.source.bandcamp.BandcampAudioSourceManager; -import com.sedmelluq.discord.lavaplayer.source.local.LocalAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.twitch.TwitchStreamAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.vimeo.VimeoAudioSourceManager; @@ -12,6 +11,7 @@ import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import de.presti.ree6.audio.music.source.RestrictedHttpAudioSourceManager; import de.presti.ree6.commands.CommandEvent; import de.presti.ree6.language.LanguageService; import de.presti.ree6.main.Main; @@ -66,7 +66,7 @@ public MusicWorker() { playerManager.registerSourceManager(new VimeoAudioSourceManager()); playerManager.registerSourceManager(new TwitchStreamAudioSourceManager()); playerManager.registerSourceManager(new YoutubeAudioSourceManager()); - playerManager.registerSourceManager(new LocalAudioSourceManager()); + playerManager.registerSourceManager(new RestrictedHttpAudioSourceManager()); } /** diff --git a/src/main/java/de/presti/ree6/audio/music/source/RestrictedHttpAudioSourceManager.java b/src/main/java/de/presti/ree6/audio/music/source/RestrictedHttpAudioSourceManager.java new file mode 100644 index 000000000..392e325ae --- /dev/null +++ b/src/main/java/de/presti/ree6/audio/music/source/RestrictedHttpAudioSourceManager.java @@ -0,0 +1,48 @@ +package de.presti.ree6.audio.music.source; + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.track.AudioItem; +import com.sedmelluq.discord.lavaplayer.track.AudioReference; + +import java.util.Arrays; + +/** + * A restricted version of {@link HttpAudioSourceManager}. + */ +public class RestrictedHttpAudioSourceManager extends HttpAudioSourceManager { + + /** + * A whitelist for every URL that is allowed. + */ + static final String[] WHITELIST = { + "https://cdn.blurp.com", + "https://api.streamelements.com/kappa/v2/speech", + }; + + /** + * A {@link AudioReference} for later use as return value if the URL is not whitelisted. + */ + static final AudioReference invalidReference = new AudioReference("INVALID", "Blocked URL!"); + + @Override + public AudioItem loadItem(AudioPlayerManager manager, AudioReference reference) { + reference = checkWhitelisting(reference); + return super.loadItem(manager, reference); + } + + /** + * A method used to check everything + * @param reference the {@link AudioReference} parsed from above. + * @return either the invalid Reference or the input back. + */ + public AudioReference checkWhitelisting(AudioReference reference) { + String url = reference.identifier; + + if (Arrays.stream(WHITELIST).anyMatch(url::startsWith)) { + return reference; + } + + return invalidReference; + } +} diff --git a/src/main/java/de/presti/ree6/commands/impl/community/Schedule.java b/src/main/java/de/presti/ree6/commands/impl/community/Schedule.java index 674bba340..996c50dfe 100644 --- a/src/main/java/de/presti/ree6/commands/impl/community/Schedule.java +++ b/src/main/java/de/presti/ree6/commands/impl/community/Schedule.java @@ -6,22 +6,21 @@ import de.presti.ree6.commands.interfaces.ICommand; import de.presti.ree6.sql.SQLSession; import de.presti.ree6.sql.entities.ScheduledMessage; +import de.presti.ree6.sql.entities.webhook.WebhookScheduledMessage; import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Webhook; +import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.internal.interactions.CommandDataImpl; -import org.apache.commons.validator.GenericValidator; -import org.apache.commons.validator.routines.DateValidator; import java.time.Duration; import java.time.Instant; -import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; import java.util.Map; /** @@ -66,7 +65,8 @@ public void onPerform(CommandEvent commandEvent) { .append(Instant.ofEpochMilli(scheduledMessage.getDelayAmount()) .atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH/mm"))); } - // TODO:: list response message. + + commandEvent.reply(commandEvent.getResource("message.schedule.list")); } case "delete" -> { @@ -77,19 +77,20 @@ public void onPerform(CommandEvent commandEvent) { Map.of("gid", commandEvent.getGuild().getIdLong(), "id", id.getAsLong())); if (scheduledMessage != null) { - // TODO:: add success message. SQLSession.getSqlConnector().getSqlWorker().deleteEntity(scheduledMessage); + commandEvent.reply(commandEvent.getResource("message.schedule.delete.success")); } else { - // TODO:: add failed message. + commandEvent.reply(commandEvent.getResource("message.schedule.delete.failed")); } } case "create" -> { - OptionMapping repeat = commandEvent.getOption("repeat"); OptionMapping month = commandEvent.getOption("month"); OptionMapping day = commandEvent.getOption("day"); OptionMapping hour = commandEvent.getOption("hour"); OptionMapping minute = commandEvent.getOption("minute"); + OptionMapping channel = commandEvent.getOption("channel"); + OptionMapping repeat = commandEvent.getOption("repeat"); long fullTime = 0; if (month != null) fullTime += Duration.ofDays(31 * month.getAsLong()).toMillis(); @@ -102,11 +103,26 @@ public void onPerform(CommandEvent commandEvent) { return; } - // TODO:: check for webhook and use existing one. + GuildChannelUnion guildChannel = channel.getAsChannel(); + ScheduledMessage scheduledMessage = new ScheduledMessage(); + + WebhookScheduledMessage webhookScheduledMessage = + SQLSession.getSqlConnector().getSqlWorker().getEntity(new WebhookScheduledMessage(), + "SELECT * FROM ScheduledMessageWebhooks WHERE gid = :gid AND actualChannelId = :channel", + Map.of("gid", commandEvent.getGuild().getId(),"channel", guildChannel.getIdLong())); + + if (webhookScheduledMessage == null) { + Webhook webhook = guildChannel.asStandardGuildMessageChannel().createWebhook("Ree6-Schedule").complete(); + + webhookScheduledMessage = SQLSession.getSqlConnector().getSqlWorker() + .updateEntity(new WebhookScheduledMessage(commandEvent.getGuild().getId(), webhook.getId(), webhook.getToken(), guildChannel.getIdLong())); + } + + scheduledMessage.setScheduledMessageWebhook(webhookScheduledMessage); scheduledMessage.setDelayAmount(fullTime); scheduledMessage.setRepeated(repeat.getAsBoolean()); - // TODO:: add success message. + commandEvent.reply(commandEvent.getResource("message.schedule.added")); } default -> commandEvent.reply(commandEvent.getResource("message.default.invalidOption")); @@ -120,12 +136,13 @@ public void onPerform(CommandEvent commandEvent) { public CommandData getCommandData() { return new CommandDataImpl("schedule", "command.description.schedule") .addSubcommands(new SubcommandData("create", "Create a new scheduled Message.") - .addOption(OptionType.INTEGER, "month", "The months of the delay.", false) - .addOption(OptionType.INTEGER, "day", "The days of the delay.", false) - .addOption(OptionType.INTEGER, "hour", "The hours of the delay.", false) - .addOption(OptionType.INTEGER, "minute", "The minutes of the delay.", false) - .addOption(OptionType.BOOLEAN, "repeat", "If the schedule should be repeated.", true), - new SubcommandData("list", "List all scheduled Messages."), + .addOption(OptionType.CHANNEL, "channel", "The channel it should be sent to.", true) + .addOption(OptionType.BOOLEAN, "repeat", "If the schedule should be repeated.", true) + .addOption(OptionType.INTEGER, "month", "The months of the delay.", false) + .addOption(OptionType.INTEGER, "day", "The days of the delay.", false) + .addOption(OptionType.INTEGER, "hour", "The hours of the delay.", false) + .addOption(OptionType.INTEGER, "minute", "The minutes of the delay.", false), + new SubcommandData("list", "List all scheduled Messages."), new SubcommandData("delete", "Delete a scheduled Message.") .addOptions(new OptionData(OptionType.INTEGER, "id", "The ID of the scheduled Message", true).setMinValue(1))); } diff --git a/src/main/java/de/presti/ree6/commands/impl/community/Ticket.java b/src/main/java/de/presti/ree6/commands/impl/community/Ticket.java index b33a57156..fbd227a01 100644 --- a/src/main/java/de/presti/ree6/commands/impl/community/Ticket.java +++ b/src/main/java/de/presti/ree6/commands/impl/community/Ticket.java @@ -68,7 +68,7 @@ public void onPerform(CommandEvent commandEvent) { Tickets finalTickets = tickets; - logChannel.getAsChannel().asTextChannel().createWebhook("Ticket-Log").queue(webhook -> { + logChannel.getAsChannel().asStandardGuildMessageChannel().createWebhook("Ticket-Log").queue(webhook -> { finalTickets.setLogChannelId(webhook.getIdLong()); finalTickets.setLogChannelWebhookToken(webhook.getToken()); commandEvent.getGuild().createCategory("Tickets").addPermissionOverride(commandEvent.getGuild().getPublicRole(), null, EnumSet.of(Permission.VIEW_CHANNEL)).queue(category1 -> { diff --git a/src/main/java/de/presti/ree6/events/MenuEvents.java b/src/main/java/de/presti/ree6/events/MenuEvents.java index 6906d6096..7ea9f4e4c 100644 --- a/src/main/java/de/presti/ree6/events/MenuEvents.java +++ b/src/main/java/de/presti/ree6/events/MenuEvents.java @@ -184,6 +184,9 @@ public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { } else { guildMusicManager.getPlayer().setPaused(true); } + } else { + Main.getInstance().getCommandManager().sendMessage(LanguageService.getByGuild(event.getGuild(), "message.music.notConnected"), + event.getChannel(), event.getHook()); } } @@ -191,14 +194,24 @@ public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { event.deferReply(true).queue(); GuildMusicManager guildMusicManager = Main.getInstance().getMusicWorker().getGuildAudioPlayer(event.getGuild()); - if (guildMusicManager != null) guildMusicManager.getPlayer().setPaused(true); + if (guildMusicManager != null) { + guildMusicManager.getPlayer().setPaused(true); + } else { + Main.getInstance().getCommandManager().sendMessage(LanguageService.getByGuild(event.getGuild(), "message.music.notConnected"), + event.getChannel(), event.getHook()); + } } case "re_music_skip" -> { event.deferReply(true).queue(); GuildMusicManager guildMusicManager = Main.getInstance().getMusicWorker().getGuildAudioPlayer(event.getGuild()); - if (guildMusicManager != null) guildMusicManager.getScheduler().nextTrack(event.getChannel(), true); + if (guildMusicManager != null) { + Main.getInstance().getMusicWorker().skipTrack(event.getChannel(), event.getHook(),1,true); + } else { + Main.getInstance().getCommandManager().sendMessage(LanguageService.getByGuild(event.getGuild(), "message.music.notConnected"), + event.getChannel(), event.getHook()); + } } case "re_music_loop" -> { @@ -219,6 +232,9 @@ public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { em.setFooter(event.getGuild().getName() + " - " + Data.ADVERTISEMENT, event.getGuild().getIconUrl()); Main.getInstance().getCommandManager().sendMessage(em, event.getChannel(), event.getHook()); + } else { + Main.getInstance().getCommandManager().sendMessage(LanguageService.getByGuild(event.getGuild(), "message.music.notConnected"), + event.getChannel(), event.getHook()); } } @@ -240,6 +256,9 @@ public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { em.setFooter(event.getGuild().getName() + " - " + Data.ADVERTISEMENT, event.getGuild().getIconUrl()); Main.getInstance().getCommandManager().sendMessage(em, event.getChannel(), event.getHook()); + } else { + Main.getInstance().getCommandManager().sendMessage(LanguageService.getByGuild(event.getGuild(), "message.music.notConnected"), + event.getChannel(), event.getHook()); } } @@ -303,8 +322,8 @@ public void onModalInteraction(@NotNull ModalInteractionEvent event) { case "re_music_add_modal" -> { event.deferReply(true).queue(); - - Main.getInstance().getMusicWorker().playSong(event.getValue("re_music_add_modal_song").getAsString(), event.getGuild(), event.getMember(), event.getChannel(), event.getInteraction().getHook()); + Main.getInstance().getMusicWorker().playSong(event.getValue("re_music_add_modal_song").getAsString(), + event.getGuild(), event.getMember(), event.getChannel(), event.getInteraction().getHook()); } case "statisticsSetupTwitchModal" -> { diff --git a/src/main/java/de/presti/ree6/streamtools/StreamActionContainer.java b/src/main/java/de/presti/ree6/streamtools/StreamActionContainer.java index 2a8ff74fd..aed480c81 100644 --- a/src/main/java/de/presti/ree6/streamtools/StreamActionContainer.java +++ b/src/main/java/de/presti/ree6/streamtools/StreamActionContainer.java @@ -1,5 +1,6 @@ package de.presti.ree6.streamtools; +import com.github.twitch4j.common.events.TwitchEvent; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -86,9 +87,10 @@ public StreamActionContainer(StreamAction streamAction) { /** * Run all Actions. * + * @param twitchEvent The related Twitch event. * @param userInput The User Input. */ - public void runActions(String userInput) { + public void runActions(TwitchEvent twitchEvent, String userInput) { actions.forEach((run) -> { String[] args = run.getArguments(); @@ -100,7 +102,7 @@ public void runActions(String userInput) { } } - run.getAction().runAction(guild, args); + run.getAction().runAction(guild, twitchEvent, args); }); } } diff --git a/src/main/java/de/presti/ree6/streamtools/action/IStreamAction.java b/src/main/java/de/presti/ree6/streamtools/action/IStreamAction.java index 87151ae9e..bd5622811 100644 --- a/src/main/java/de/presti/ree6/streamtools/action/IStreamAction.java +++ b/src/main/java/de/presti/ree6/streamtools/action/IStreamAction.java @@ -1,5 +1,6 @@ package de.presti.ree6.streamtools.action; +import com.github.twitch4j.common.events.TwitchEvent; import net.dv8tion.jda.api.entities.Guild; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,7 +13,8 @@ public interface IStreamAction { /** * Run the specific action. * @param guild The guild where the action should be executed. + * @param twitchEvent The twitch event that was fired. * @param arguments Arguments for the action. (Can be null) */ - void runAction(@NotNull Guild guild, @Nullable String[] arguments); + void runAction(@NotNull Guild guild, @Nullable TwitchEvent twitchEvent, @Nullable String[] arguments); } diff --git a/src/main/java/de/presti/ree6/streamtools/action/impl/PlayBlerpStreamAction.java b/src/main/java/de/presti/ree6/streamtools/action/impl/PlayBlerpStreamAction.java new file mode 100644 index 000000000..0764ee96f --- /dev/null +++ b/src/main/java/de/presti/ree6/streamtools/action/impl/PlayBlerpStreamAction.java @@ -0,0 +1,68 @@ +package de.presti.ree6.streamtools.action.impl; + +import com.github.twitch4j.common.events.TwitchEvent; +import com.github.twitch4j.pubsub.events.RewardRedeemedEvent; +import de.presti.ree6.main.Main; +import de.presti.ree6.streamtools.action.IStreamAction; +import de.presti.ree6.streamtools.action.StreamActionInfo; +import de.presti.ree6.utils.external.RequestUtility; +import lombok.NoArgsConstructor; +import net.dv8tion.jda.api.entities.Guild; +import org.jetbrains.annotations.NotNull; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * StreamAction used to play a blerp sound that is bound to a specific channel reward. + */ +@NoArgsConstructor +@StreamActionInfo(name = "PlayBlerp", command = "play-blerp", description = "Plays the blerp audio of a reward.", introduced = "2.4.0") +public class PlayBlerpStreamAction implements IStreamAction { + + /** + * RegEx to detect a Blerp link in the redemption itself. + */ + String blerpRegEx = "https:\\/\\/blerp\\.com\\/soundbites\\/[a-zA-Z0-9]+"; + + /** + * RegEx to take the CDN Url of that sound out of the HTML content. + */ + String blerpPageRegEx = "https:\\/\\/cdn\\.blerp\\.com\\/normalized\\/[a-zA-Z0-9]+"; + + /** + * A {@link Pattern} to actually detect it. + */ + Pattern blerpPattern = Pattern.compile(blerpRegEx); + + /** + * A {@link Pattern} to actually detect it. + */ + Pattern blerpPagePattern = Pattern.compile(blerpPageRegEx); + + /** + * @inheritDoc + */ + @Override + public void runAction(@NotNull Guild guild, TwitchEvent twitchEvent, String[] arguments) { + if (twitchEvent == null) return; + + if (!Main.getInstance().getMusicWorker().isConnectedMember(guild.getSelfMember())) return; + + if (twitchEvent instanceof RewardRedeemedEvent rewardRedeemedEvent) { + String prompt = rewardRedeemedEvent.getRedemption().getReward().getPrompt().toLowerCase(); + Matcher matcher = blerpPattern.matcher(prompt); + if (matcher.find()) { + String blerpUrl = matcher.group(1); + + String blerpPageResponse = RequestUtility.requestString(RequestUtility.Request.builder().url(blerpUrl).GET().build()); + + Matcher pageMatcher = blerpPagePattern.matcher(blerpPageResponse); + if (matcher.find()) { + Main.getInstance().getMusicWorker().loadAndPlay(guild, null, null, + pageMatcher.group(1),null, true, false); + } + } + } + } +} diff --git a/src/main/java/de/presti/ree6/streamtools/action/impl/PlayTTSStreamAction.java b/src/main/java/de/presti/ree6/streamtools/action/impl/PlayTTSStreamAction.java index 43d08e409..1e0fb7330 100644 --- a/src/main/java/de/presti/ree6/streamtools/action/impl/PlayTTSStreamAction.java +++ b/src/main/java/de/presti/ree6/streamtools/action/impl/PlayTTSStreamAction.java @@ -1,5 +1,6 @@ package de.presti.ree6.streamtools.action.impl; +import com.github.twitch4j.common.events.TwitchEvent; import de.presti.ree6.main.Main; import de.presti.ree6.streamtools.action.StreamActionInfo; import de.presti.ree6.streamtools.action.IStreamAction; @@ -25,26 +26,15 @@ public class PlayTTSStreamAction implements IStreamAction { * @inheritDoc */ @Override - public void runAction(@NotNull Guild guild, String[] arguments) { + public void runAction(@NotNull Guild guild, TwitchEvent twitchEvent, String[] arguments) { if (arguments == null || arguments.length == 0) { return; } if (!Main.getInstance().getMusicWorker().isConnectedMember(guild.getSelfMember())) return; - String text = String.join(" ", arguments); - - RequestUtility.Request request = RequestUtility.Request.builder() - .url("https://api.streamelements.com/kappa/v2/speech?voice=Brian&text=" + URLEncoder.encode(text, StandardCharsets.UTF_8)) - .GET().build(); - byte[] tts = RequestUtility.requestBytes(request); - - Path filePath = Path.of("storage/tmp/", RandomUtils.randomString(16, false) + ".mp3"); - - try { - Files.write(filePath, tts); - Main.getInstance().getMusicWorker().loadAndPlay(guild, null, null, filePath.toAbsolutePath().toString(), null, true, false); - } catch (Exception ignore) { - } + Main.getInstance().getMusicWorker().loadAndPlay(guild, null, null, + "https://api.streamelements.com/kappa/v2/speech?voice=Brian&text=" + URLEncoder.encode(String.join(" ", arguments), StandardCharsets.UTF_8), + null, true, false); } } diff --git a/src/main/java/de/presti/ree6/streamtools/action/impl/PlayUrlStreamAction.java b/src/main/java/de/presti/ree6/streamtools/action/impl/PlayUrlStreamAction.java index 6bbbe733b..016c039b4 100644 --- a/src/main/java/de/presti/ree6/streamtools/action/impl/PlayUrlStreamAction.java +++ b/src/main/java/de/presti/ree6/streamtools/action/impl/PlayUrlStreamAction.java @@ -1,5 +1,6 @@ package de.presti.ree6.streamtools.action.impl; +import com.github.twitch4j.common.events.TwitchEvent; import de.presti.ree6.main.Main; import de.presti.ree6.streamtools.action.StreamActionInfo; import de.presti.ree6.streamtools.action.IStreamAction; @@ -19,7 +20,7 @@ public class PlayUrlStreamAction implements IStreamAction { * @param arguments Arguments for the action. (Can be null) */ @Override - public void runAction(@NotNull Guild guild, String[] arguments) { + public void runAction(@NotNull Guild guild, TwitchEvent twitchEvent, String[] arguments) { if (arguments == null || arguments.length == 0) { return; } diff --git a/src/main/java/de/presti/ree6/streamtools/action/impl/SayStreamAction.java b/src/main/java/de/presti/ree6/streamtools/action/impl/SayStreamAction.java index 898fc75b4..34971caf0 100644 --- a/src/main/java/de/presti/ree6/streamtools/action/impl/SayStreamAction.java +++ b/src/main/java/de/presti/ree6/streamtools/action/impl/SayStreamAction.java @@ -1,5 +1,6 @@ package de.presti.ree6.streamtools.action.impl; +import com.github.twitch4j.common.events.TwitchEvent; import de.presti.ree6.main.Main; import de.presti.ree6.streamtools.action.StreamActionInfo; import de.presti.ree6.streamtools.action.IStreamAction; @@ -19,7 +20,7 @@ public class SayStreamAction implements IStreamAction { * @inheritDoc */ @Override - public void runAction(@NotNull Guild guild, String[] arguments) { + public void runAction(@NotNull Guild guild, TwitchEvent twitchEvent, String[] arguments) { if (arguments == null || arguments.length == 0) { return; } diff --git a/src/main/java/de/presti/ree6/streamtools/action/impl/VoiceJoinStreamAction.java b/src/main/java/de/presti/ree6/streamtools/action/impl/VoiceJoinStreamAction.java index 3d49e1d14..eb20da680 100644 --- a/src/main/java/de/presti/ree6/streamtools/action/impl/VoiceJoinStreamAction.java +++ b/src/main/java/de/presti/ree6/streamtools/action/impl/VoiceJoinStreamAction.java @@ -1,5 +1,6 @@ package de.presti.ree6.streamtools.action.impl; +import com.github.twitch4j.common.events.TwitchEvent; import de.presti.ree6.main.Main; import de.presti.ree6.streamtools.action.StreamActionInfo; import de.presti.ree6.streamtools.action.IStreamAction; @@ -20,7 +21,7 @@ public class VoiceJoinStreamAction implements IStreamAction { * @inheritDoc */ @Override - public void runAction(@NotNull Guild guild, String[] arguments) { + public void runAction(@NotNull Guild guild, TwitchEvent twitchEvent, String[] arguments) { if (arguments == null || arguments.length == 0) { return; } diff --git a/src/main/java/de/presti/ree6/streamtools/action/impl/VoiceLeaveStreamAction.java b/src/main/java/de/presti/ree6/streamtools/action/impl/VoiceLeaveStreamAction.java index 6ab949d83..0e5ed5bb0 100644 --- a/src/main/java/de/presti/ree6/streamtools/action/impl/VoiceLeaveStreamAction.java +++ b/src/main/java/de/presti/ree6/streamtools/action/impl/VoiceLeaveStreamAction.java @@ -1,5 +1,6 @@ package de.presti.ree6.streamtools.action.impl; +import com.github.twitch4j.common.events.TwitchEvent; import de.presti.ree6.main.Main; import de.presti.ree6.streamtools.action.StreamActionInfo; import de.presti.ree6.streamtools.action.IStreamAction; @@ -18,7 +19,7 @@ public class VoiceLeaveStreamAction implements IStreamAction { * @inheritDoc */ @Override - public void runAction(@NotNull Guild guild, String[] arguments) { + public void runAction(@NotNull Guild guild, TwitchEvent twitchEvent, String[] arguments) { if (!Main.getInstance().getMusicWorker().isConnectedMember(guild.getSelfMember())) return; Main.getInstance().getMusicWorker().disconnect(guild); diff --git a/src/main/java/de/presti/ree6/utils/apis/Notifier.java b/src/main/java/de/presti/ree6/utils/apis/Notifier.java index e9413e176..1437e483d 100644 --- a/src/main/java/de/presti/ree6/utils/apis/Notifier.java +++ b/src/main/java/de/presti/ree6/utils/apis/Notifier.java @@ -180,7 +180,7 @@ public Notifier() { if (!event.getRedemption().getChannelId().equalsIgnoreCase(container.getTwitchChannelId())) return; if (container.getExtraArgument() == null || event.getRedemption().getReward().getId().equals(container.getExtraArgument())) { - container.runActions(event.getRedemption().getUserInput()); + container.runActions(event, event.getRedemption().getUserInput()); } }); }); @@ -190,7 +190,7 @@ public Notifier() { list.forEach(container -> { if (!event.getChannelId().equalsIgnoreCase(container.getTwitchChannelId())) return; - container.runActions(event.getData().getUsername()); + container.runActions(event, event.getData().getUsername()); }); }); @@ -199,7 +199,7 @@ public Notifier() { list.forEach(container -> { if (!event.getBroadcasterUserId().equalsIgnoreCase(container.getTwitchChannelId())) return; - container.runActions(event.getUserName()); + container.runActions(null, event.getUserName()); }); }); diff --git a/src/main/java/de/presti/ree6/utils/external/RequestUtility.java b/src/main/java/de/presti/ree6/utils/external/RequestUtility.java index 33f84fb2a..f724fb334 100644 --- a/src/main/java/de/presti/ree6/utils/external/RequestUtility.java +++ b/src/main/java/de/presti/ree6/utils/external/RequestUtility.java @@ -15,6 +15,8 @@ import java.net.http.HttpResponse; import java.util.ArrayList; import java.util.List; +import java.util.Scanner; +import java.util.regex.Pattern; /** * Utility used to work with HTTP Requests. @@ -152,6 +154,38 @@ public static byte[] requestBytes(Request request) { return new byte[0]; } + /** + * Send a Request. + * @param request the Request. + * @return a {@link String} + */ + public static String requestString(Request request) { + try (InputStream httpResponse = request(request)) { + + if (httpResponse == null) { + return ""; + } + + try { + Scanner scanner = new Scanner(httpResponse); + StringBuilder stringBuilder = new StringBuilder(); + + while(scanner.hasNext()){ + stringBuilder.append(scanner.nextLine()); + } + + return stringBuilder.toString(); + } catch (Exception ex) { + log.error("Couldn't send a Request!", ex); + } + } catch (IOException e) { + log.error("Couldn't send a Request!", e); + return ""; + } + + return ""; + } + /** * Utility class for Requests. */