diff --git a/src/me/despawningbone/discordbot/command/info/Translate.java b/src/me/despawningbone/discordbot/command/info/Translate.java index 2e03c05..0de202d 100644 --- a/src/me/despawningbone/discordbot/command/info/Translate.java +++ b/src/me/despawningbone/discordbot/command/info/Translate.java @@ -1,131 +1,129 @@ package me.despawningbone.discordbot.command.info; import java.io.IOException; import java.time.OffsetDateTime; import java.util.Arrays; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import org.jsoup.Jsoup; import org.apache.commons.lang3.exception.ExceptionUtils; import org.json.JSONObject; import org.json.JSONTokener; import org.jsoup.Connection; import org.jsoup.Connection.Method; import org.jsoup.Connection.Response; -import org.jsoup.nodes.Document; import com.google.common.util.concurrent.ThreadFactoryBuilder; import me.despawningbone.discordbot.command.Command; import me.despawningbone.discordbot.command.CommandResult; import me.despawningbone.discordbot.command.CommandResult.CommandResultType; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.User; public class Translate extends Command { public Translate() { this.desc = "Translate some sentences!"; this.usage = "[-fromlang] [-tolang]"; this.remarks = Arrays.asList("Supported Languages: `en, ja, zh, de, es, fr, it, ru, pl, pt, nl`"); this.examples = Arrays.asList("-ja あなたも文化人だと思います", "-es despacito"); this.alias = Arrays.asList("tl"); /*try { refresh(); Response resp = Jsoup.connect("https://s.deepl.com/web/stats?request_type=jsonrpc").userAgent(agent) .requestBody("{\"jsonrpc\":\"2.0\",\"method\":\"WebAppPushStatistics\",\"params\":{\"value\":{\"instanceId\":\"" + cVars.getString("uid") + "\",\"event\":\"web/pageview\",\"url\":\"https://www.deepl.com/en/translator\",\"data\":{\"gaBlocked\":false,\"referrer\":\"https://www.google.com/\"}}},\"id\":" + id++ + "}").method(Method.POST).execute(); cookie = resp.cookies().get("LMTBID"); //System.out.println(cookie); } catch(IOException e) { e.printStackTrace(); }*/ executor.scheduleAtFixedRate(() -> refresh(), 0, 450, TimeUnit.SECONDS); } private int id = (ThreadLocalRandom.current().nextInt(1000) + 1) * 100000 + 1; private String cookie = null, agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0"; //private JSONObject cVars; //old ver only //private boolean update = true; final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setDaemon(true).setNameFormat("tl-scheduler-%d").build()); @Override public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) { //if(cookie == null) return new CommandResult(CommandResultType.FAILURE, "The translation service is unavailable right now!"); //disable of cookie not found try { String langF = "auto", langT = "EN", query = String.join(" ", args).replaceAll("\n", " ").replace("-", ""); //since it hates new lines and hyphens apparently if(Arrays.asList("-en", "-ja", "-zh", "-de", "-es", "-fr", "-it", "-ru", "-pl", "-pt", "-nl").contains(args[0].toLowerCase())) { langF = args[0].substring(1).toUpperCase(); query = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); } if(Arrays.asList("-en", "-ja", "-zh", "-de", "-es", "-fr", "-it", "-ru", "-pl", "-pt", "-nl").contains(args[args.length - 1].toLowerCase())) { langT = args[args.length - 1].substring(1).toUpperCase(); query = query.substring(0, query.length() - 3); } if((args.length < 5 ? query.length() > 40 : args.length > 20)) return new CommandResult(CommandResultType.INVALIDARGS, "Please type a shorter phrase to translate!"); //System.out.println(query); //System.out.println(id); //System.out.println("{\"jsonrpc\":\"2.0\",\"method\": \"LMT_handle_jobs\",\"params\":{\"jobs\":[{\"kind\":\"default\",\"raw_en_sentence\":\"" + query + "\",\"raw_en_context_before\":[],\"raw_en_context_after\":[],\"preferred_num_beams\":4,\"quality\":\"fast\"}]" // + ",\"lang\":{\"user_preferred_langs\":[\"JA\"],\"source_lang_user_selected\":\"auto\",\"target_lang\":\"" + langT + "\"},\"priority\":-1,\"timestamp\":" + OffsetDateTime.now().toEpochSecond() + "000},\"id\":" + id + "}"); /*if(update) { refresh(); update = false; executor.schedule(() -> update = true, 300, TimeUnit.SECONDS); }*/ Connection con = Jsoup.connect("https://www2.deepl.com/jsonrpc").userAgent(agent) + .header("Content-type", "application/json").ignoreContentType(true) .requestBody("{\"jsonrpc\":\"2.0\",\"method\": \"LMT_handle_jobs\",\"params\":{\"jobs\":[{\"kind\":\"default\",\"raw_en_sentence\":\"" + query + "\",\"raw_en_context_before\":[],\"raw_en_context_after\":[],\"preferred_num_beams\":4" + ((args.length < 2 ? query.length() > 5 : args.length > 5) ? "" : ",\"quality\":\"fast\"") + "}],\"commonJobParams\":{}" + ",\"lang\":{\"user_preferred_langs\":[\"EN\", \"JA\"],\"source_lang_user_selected\":\"" + langF + "\",\"target_lang\":\"" + langT + "\"},\"priority\":-1,\"timestamp\":" + OffsetDateTime.now().toEpochSecond() + "000},\"id\":" + id++ + "}"); if(cookie != null) con.cookie("LMTBID", cookie); Response resp = con.method(Method.POST).execute(); if(resp.hasCookie("LMTBID")) cookie = resp.cookie("LMTBID"); - Document doc = resp.parse(); - //System.out.println(doc.text()); - JSONObject main = new JSONObject(new JSONTokener(doc.text())).getJSONObject("result"); + JSONObject main = new JSONObject(new JSONTokener(resp.body())).getJSONObject("result"); EmbedBuilder eb = new EmbedBuilder(); eb.setColor(0x0f2b46); eb.setTitle("Translation: " + (langF.equals("auto") ? main.getString("source_lang") + "(detected)" : langF) + " -> " + main.getString("target_lang")); eb.addField("Original", query, true); String tl = ""; for(Object obj : main.getJSONArray("translations").getJSONObject(0).getJSONArray("beams")) { String p = ((JSONObject) obj).getString("postprocessed_sentence"); if(tl.isEmpty()) tl = p + "\n"; else tl += "*" + p + "*\n"; } eb.addField("Translated", tl, true); eb.setFooter("Translated by DeepL", "https://egress.storeden.net/gallery/5a2577c9ffe48e7e4b418464"); eb.setTimestamp(OffsetDateTime.now()); channel.sendMessage(eb.build()).queue(); return new CommandResult(CommandResultType.SUCCESS); } catch(IOException e) { String ex = ExceptionUtils.getStackTrace(e); /*if(ex.contains("Status=429")) { refresh(); return execute(channel, author, msg, args); } else { return new CommandResult(CommandResultType.ERROR, ex); }*/ return new CommandResult(CommandResultType.ERROR, ex); } } private void refresh() { //System.out.println(update); //System.out.println("{\"jsonrpc\":\"2.0\",\"method\":\"getClientState\",\"params\":{\"v\":\"20180814\"" + (cVars == null ? "" : "," + cVars.toString()) + "},\"id\":" + id++ + "}"); Connection con = Jsoup.connect("https://www.deepl.com/PHP/backend/clientState.php?request_type=jsonrpc&il=EN").userAgent(agent) .requestBody("{\"jsonrpc\":\"2.0\",\"method\":\"getClientState\",\"params\":{\"v\":\"20180814\"" + /*(cVars == null ? "" : ",\"clientVars\":" + cVars.toString()) + */"},\"id\":" + id++ + "}"); if(cookie != null) con.cookie("LMTBID", cookie); //JSONObject json = new JSONObject(new JSONTokener(con.post().text())); //System.out.println(json); //if(cVars == null) cVars = json.getJSONObject("result").getJSONObject("clientVars"); } } diff --git a/src/me/despawningbone/discordbot/command/music/TrackScheduler.java b/src/me/despawningbone/discordbot/command/music/TrackScheduler.java index eb08745..d29f201 100644 --- a/src/me/despawningbone/discordbot/command/music/TrackScheduler.java +++ b/src/me/despawningbone/discordbot/command/music/TrackScheduler.java @@ -1,200 +1,200 @@ package me.despawningbone.discordbot.command.music; import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; import me.despawningbone.discordbot.DiscordBot; import me.despawningbone.discordbot.command.music.AudioTrackHandler.TrackData; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import org.json.JSONObject; import org.json.JSONTokener; /** * This class schedules tracks for the audio player. It contains the queue of * tracks. */ public class TrackScheduler extends AudioEventAdapter { private final AudioPlayer player; private final BlockingQueue queue; private AudioTrackHandler ap; private Guild guild; public String loop = null; //way too lazy to use getter setters lmao /** * @param player * The audio player this scheduler uses */ public TrackScheduler(Guild parent, AudioTrackHandler handler, AudioPlayer player) { this.player = player; this.queue = new LinkedBlockingQueue<>(); this.ap = handler; this.guild = parent; } /** * Add the next track to queue or play right away if nothing is in the * queue. * * @param track * The track to play or add to queue. */ public void queue(AudioTrack track) { // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If // something is playing, it returns false and does nothing. In that case the player was already playing so this // track goes to the queue instead. if (!player.startTrack(track, true)) { queue.offer(track); } else if (loop != null && loop.equals("autoplay")) { //i dont think this is needed as people need to play something before autoplay can be toggled anyways queueAutoplay(track); } } /** * Start the next track, stopping the current one if it is playing. */ public void nextTrack() { //DONE rewrite to not include q.remove here so that stuff like interrupted wont break the queue? // Start the next track, regardless of if something is already playing or not. In case queue was empty, we are // giving null to startTrack, which is a valid argument and will simply stop the player. AudioTrack track = queue.poll(); player.startTrack(track, false); if(track == null) { //System.out.println("finished"); //debug loop = null; delayCloseConnection(player); //required because if not it will throw InterruptedException } } //seems to be called internally somehow; even when mayStartNext is false (REPLACED, STOPPED etc) this still fires //NVM ITS CALLED FROM AudioTrackHandler.skipTrack() LOL public void queueAutoplay(AudioTrack track) { //check duplicate please, some can get into a dead loop like cosMo@暴走P - WalpurgisNacht and Ice - 絶 //well randoming it works ap.ex.submit(() -> { //async so it can free up the event try { //System.out.println("autoplay"); InputStream input = new URL("https://www.googleapis.com/youtube/v3/search?part=snippet&relatedToVideoId=" + track.getIdentifier() + "&type=video&key=" + ap.GAPI).openStream(); JSONTokener result = new JSONTokener(new InputStreamReader(input, "UTF-8")); Member temp; try { temp = guild.getMemberByTag(track.getUserData(TrackData.class).getUserWithDiscriminator()); } catch (IllegalArgumentException e) { //track was autoplay queued before this temp = guild.getMemberById(DiscordBot.BotID); //fallback } final Member user = temp; int t = ThreadLocalRandom.current().nextInt(2); String url = "https://youtube.com/watch?v=" + new JSONObject(result).getJSONArray("items").getJSONObject(t).getJSONObject("id").getString("videoId"); ap.load(user, url, (n, l) -> { AudioTrack auto = l.get(0); auto.setUserData(new TrackData(auto.getInfo().uri, "Autoplay", auto.getDuration())); ap.queueTracks(l.subList(0, 1), user); }, ex -> { ex.printStackTrace(); DiscordBot.lastMusicCmd.get(guild.getId()).sendMessage("Something went wrong when loading next autoplay track: " + ex.getMessage()).queue(); loop = null; }); } catch (Exception e) { e.printStackTrace(); DiscordBot.lastMusicCmd.get(guild.getId()).sendMessage("Something went wrong when loading next autoplay track. Is the last track a youtube video?").queue(); loop = null; } }); } public List findTracks(int startIndex, int range) { AudioTrack[] a = queue.toArray(new AudioTrack[queue.size()]); int i = startIndex - 1 + range < 0 ? Integer.MAX_VALUE : startIndex - 1 + range; //prevent overflow AudioTrack[] t = Arrays.copyOfRange(a, startIndex - 1, Math.min(queue.size() + 1, i)); //accounts for first track player thats not in queue return Arrays.asList(t); } public AudioTrack removeTrack(int num) { Iterator i = queue.iterator(); num = num - 1; for (int times = 0; i.hasNext(); times++) { AudioTrack removed = i.next(); if (num == times) { i.remove(); return removed; } } return null; } public AudioTrack moveTrack(int from, int to) { List q = new ArrayList<>(Arrays.asList(queue.toArray(new AudioTrack[queue.size()]))); AudioTrack track = q.remove(from); q.add(to, track); synchronized (queue) { //obtain lock and operate before releasing or else queue might not be complete queue.clear(); for(AudioTrack t : q) queue.offer(t); } return track; } public void shuffleQueue() { List q = Arrays.asList(queue.toArray(new AudioTrack[queue.size()])); Collections.shuffle(q); synchronized (queue) { //obtain lock and operate before releasing or else queue might not be complete queue.clear(); for(AudioTrack t : q) queue.offer(t); } } public void clearSchedulerQueue() { queue.clear(); } public int getQueueSize() { return queue.size(); } @Override public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { // Only start the next track if the end reason is suitable for it (FINISHED or LOAD_FAILED or REPLACED) //System.out.println(endReason); //debug boolean mayStartNext = endReason.mayStartNext; if (mayStartNext) { //doesnt queue clone if skipped if (loop != null && loop.equals("loop")) { //so what the hecc if loop is null and i do loop.equals("Loop") it freezes the thread AudioTrack clone = track.makeClone(); TrackData origData = clone.getUserData(TrackData.class); clone.setUserData(new TrackData(origData.getUrl(), origData.getUserWithDiscriminator(), clone.getDuration())); //wipe votes queue.offer(clone); } nextTrack(); } if(mayStartNext || endReason == AudioTrackEndReason.REPLACED) { //queues new if skipped too if (loop != null && loop.equals("autoplay") && queue.size() < 1) { queueAutoplay(player.getPlayingTrack()); } } } - private void delayCloseConnection(AudioPlayer player) { + private void delayCloseConnection(AudioPlayer player) { //TODO configurable delay; dont leave if new things play within the delay ap.ex.schedule(() -> guild.getAudioManager().closeAudioConnection(), 1, TimeUnit.MILLISECONDS); } } \ No newline at end of file