mirror of
https://github.com/chrisb09/MusicBot.git
synced 2026-11-05 17:02:35 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9484c373ff | ||
|
|
860822d520 | ||
|
|
a0c313047f | ||
|
|
db69ea6787 | ||
|
|
5dba2c355b | ||
|
|
9fd246ac25 | ||
|
|
6a15bbb0df | ||
|
|
16bc176685 | ||
|
|
50e8bff831 | ||
|
|
9c012eb169 | ||
|
|
87771df1fb | ||
|
|
5d35f5bb4c | ||
|
|
ecd8cdf77b | ||
|
|
39e5bf7786 | ||
|
|
650a9ea996 | ||
|
|
0e0c05acf9 | ||
|
|
2e52ecac3b | ||
|
|
450ee7acb8 | ||
|
|
a7b56b67ab | ||
|
|
fedb97e1c7 | ||
|
|
68f951dc63 | ||
|
|
01eee8813a | ||
|
|
3df09a4cd2 | ||
|
|
0084ba7baf | ||
|
|
35e756df9b | ||
|
|
426e28ed8c | ||
|
|
dd72baca0d | ||
|
|
ac4e09cbd9 | ||
|
|
fd01d94cf2 | ||
|
|
95f72937c8 | ||
|
|
792cb7a8b7 | ||
|
|
03ba83f06b | ||
|
|
3b3a483b17 | ||
|
|
1874252ff6 | ||
|
|
aa8e430ff1 | ||
|
|
204bb6f04a | ||
|
|
9ec21bf329 | ||
|
|
b419191bad | ||
|
|
aa89145ae8 | ||
|
|
293733f0e7 | ||
|
|
7be02b1fe2 | ||
|
|
1ac46d9ec5 | ||
|
|
026ce87440 | ||
|
|
e5f34cc900 | ||
|
|
c9a2477f86 | ||
|
|
61a18a1db7 | ||
|
|
7fb44e296b | ||
|
|
4ae9f05776 | ||
|
|
84facb8b82 | ||
|
|
070938b326 | ||
|
|
58a9e76edb | ||
|
|
96ffcd8291 | ||
|
|
844a1bb75a | ||
|
|
6094e49ab2 | ||
|
|
88ce3e1149 | ||
|
|
463bf75783 | ||
|
|
348fc3ceec | ||
|
|
30eafb9239 | ||
|
|
c95f2248f3 | ||
|
|
b80b0c8459 | ||
|
|
4a8392fdb9 | ||
|
|
9d6584525c | ||
|
|
909b655f5c | ||
|
|
859e5c5862 | ||
|
|
43b63f1ba8 | ||
|
|
eca2563abf | ||
|
|
e6bfd1841f | ||
|
|
f140b41bf5 | ||
|
|
8733899aa0 |
No files matched your search
@@ -53,5 +53,12 @@ body:
|
||||
required: true
|
||||
- label: I have searched for similar issues [on the issues page](https://github.com/jagrosh/MusicBot/issues?q=is%3Aissue)
|
||||
required: true
|
||||
- label: "I am running the latest version of the bot: "
|
||||
- label: I am using an official release from [the releases page](https://github.com/jagrosh/MusicBot/releases)
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: JMusicBot Version
|
||||
description: Which version of JMusicBot are you running?
|
||||
validations:
|
||||
required: true
|
||||
+2
-1
@@ -4,4 +4,5 @@
|
||||
/test/
|
||||
*.json
|
||||
*.txt
|
||||
nb*.xml
|
||||
nb*.xml
|
||||
dockerfile
|
||||
@@ -1,5 +1,105 @@
|
||||
<img align="right" src="https://i.imgur.com/zrE80HY.png" height="200" width="200">
|
||||
|
||||
## Demo
|
||||
|
||||
If you only want to temporarily join the demo server, use this link: [https://discord.gg/4cp9CvjwaW](https://discord.gg/4cp9CvjwaW)
|
||||
|
||||
If you want to join the demo server permanently, use this link: [https://discord.gg/hK95396uB3](https://discord.gg/hK95396uB3)
|
||||
|
||||
# This fork
|
||||
|
||||
We had to update to JDA 6, switch to jda-chewtils to make the bot work again.
|
||||
Also, we somewhat regularly bump [lavaplayer](https://mvnrepository.com/artifact/dev.arbjerg/lavaplayer)/[lavalink](https://maven.lavalink.dev/#/releases/dev/lavalink/youtube/common) to their new versions. I will try to update this automatically in the future.
|
||||
|
||||
Additionally, this fork includes the following PRs from other people:
|
||||
|
||||
### Support for logging into your (burner) youtube account:
|
||||
|
||||
[PR-1670](https://github.com/jagrosh/MusicBot/pull/1670)
|
||||
|
||||
### To allow building the project from source
|
||||
[PR-1703](https://github.com/jagrosh/MusicBot/pull/1703)
|
||||
|
||||
### Add YouTube PO token & IP rotation
|
||||
https://github.com/jagrosh/MusicBot/pull/1772
|
||||
|
||||
|
||||
### For PO_Tokens: In your bot folder, edit "config.txt" and add
|
||||
```
|
||||
ytpotoken = "PO_TOKEN_HERE"
|
||||
ytvisitordata = "VISITOR_DATA_HERE"
|
||||
```
|
||||
|
||||
To get po_token and visitor_data, use [youtube-trusted-session-generator](https://github.com/iv-org/youtube-trusted-session-generator)
|
||||
|
||||
|
||||
If you have problems with this fork, you could also check out [this other fork](https://github.com/SeVile/MusicBot).
|
||||
|
||||
## Requirements for 0.5+ and above
|
||||
|
||||
Since we updated JDA from version 4 to 6 to fix various issues, we had to enable the MESSAGE_CONTENT intent. If you let your bot join more than 100 servers(guilds), you now need to enable this intent in the [Discord Developer Portal](https://discord.com/developers/applications).
|
||||
More information can be found in the [JDA documentation](https://jda.wiki/using-jda/gateway-intents-and-member-cache-policy/).
|
||||
Note, however, that this is a privileged intent and will require a valid use-case for your bot to be verified in over 75 servers (it will only show up in the portal when on at least 76 servers according to the documentation).
|
||||
|
||||
### DAVE / Voice encryption (JDA 6.3+)
|
||||
|
||||
Discord requires DAVE for voice on modern API versions (JDA 6.3+).
|
||||
This fork uses `libdave-jvm` (`0.1.0`) and configures DAVE during startup.
|
||||
|
||||
The shaded jar includes native binaries for:
|
||||
- Linux glibc x86_64
|
||||
- Linux musl x86_64 (Alpine containers)
|
||||
- Windows x86_64
|
||||
- macOS (universal)
|
||||
|
||||
If you deploy on a different architecture, add the matching `moe.kyokobot.libdave:natives-*` dependency in `pom.xml`.
|
||||
|
||||
## Easy deployment via docker
|
||||
|
||||
Additionally, i thought a corresponding docker image would make things better:
|
||||
|
||||
The image can be found on [dockerhub](https://hub.docker.com/r/chrisb09/jmusicbot)
|
||||
|
||||
Docker-compose:
|
||||
|
||||
```yaml
|
||||
version: '2.2'
|
||||
|
||||
services:
|
||||
jmusicbot:
|
||||
image: chrisb09/jmusicbot:latest
|
||||
container_name: jmusicbot
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./config:/jmb/config
|
||||
```
|
||||
|
||||
although, obviously you should change `./config` to whatever path is right for your setup.
|
||||
Source code for the docker image is also on [Github](https://github.com/chrisb09/jmb-container).
|
||||
|
||||
### Windows
|
||||
|
||||
If you want to run the bot on a windows host without docker, you obviously need to install java, and if you want to run it in the background something like [nssm](http://nssm.cc/) can be helpful.
|
||||
|
||||
|
||||
## YouTube-Login
|
||||
|
||||
Obviously you still need to log in if you want to use youtube properly, hence you need to enable this in the config.
|
||||
If you are using a pre-existing config, simply add:
|
||||
```
|
||||
/ If you set this to true, the bot will use a Google account to play YouTube tracks.
|
||||
// This is only needed if you are experiencing issues with YouTube playback.
|
||||
// Once enabled, instructions for login will be written to the console and DMs.
|
||||
// DO NOT use your main Google account! Use an alternative account.
|
||||
|
||||
youtubeoauth2=true
|
||||
```
|
||||
|
||||
If you start with a clean slate this line should already be present, albeit with `false` being the default.
|
||||
As the author of the PR reiterates multiple times, do not use your main google account as using your account for a bot is most certainly against the ToS and thus you are endangering said account.
|
||||
|
||||
To add the account you simply have to follow the very basic instructions printed either in the console or sent to you from the bot via discord after you have started it, open the linked google page and paste the code.
|
||||
|
||||
# JMusicBot
|
||||
|
||||
[](https://github.com/jagrosh/MusicBot/releases/latest)
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.jagrosh</groupId>
|
||||
<artifactId>JMusicBot</artifactId>
|
||||
<version>Snapshot</version>
|
||||
<version>0.5.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>m2-chew</id>
|
||||
<name>Maven Chewtral</name>
|
||||
<url>https://m2.chew.pro/releases</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>dv8tion</id>
|
||||
<name>m2-dv8tion</name>
|
||||
@@ -14,14 +19,17 @@
|
||||
</repository>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<name>bintray</name>
|
||||
<url>https://jcenter.bintray.com</url>
|
||||
<name>Maven Central</name>
|
||||
<url>https://repo.maven.apache.org/maven2</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
<snapshots>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
<updatePolicy>always</updatePolicy>
|
||||
</snapshots>
|
||||
</repository>
|
||||
@@ -35,6 +43,11 @@
|
||||
<name>Lavalink Repository</name>
|
||||
<url>https://maven.lavalink.dev/releases</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>arbjergDevSnapshots</id>
|
||||
<name>Lavalink Repository</name>
|
||||
<url>https://maven.lavalink.dev/snapshots</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
@@ -42,30 +55,118 @@
|
||||
<dependency>
|
||||
<groupId>net.dv8tion</groupId>
|
||||
<artifactId>JDA</artifactId>
|
||||
<version>4.4.1_353</version>
|
||||
<version>6.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jagrosh</groupId>
|
||||
<artifactId>jda-utilities</artifactId>
|
||||
<version>3.0.5</version>
|
||||
<type>pom</type>
|
||||
<groupId>moe.kyokobot.libdave</groupId>
|
||||
<artifactId>adapter-jda</artifactId>
|
||||
<version>0.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>moe.kyokobot.libdave</groupId>
|
||||
<artifactId>impl-jni</artifactId>
|
||||
<version>0.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>moe.kyokobot.libdave</groupId>
|
||||
<artifactId>natives-linux-x86-64</artifactId>
|
||||
<version>0.1.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>moe.kyokobot.libdave</groupId>
|
||||
<artifactId>natives-linux-musl-x86-64</artifactId>
|
||||
<version>0.1.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>moe.kyokobot.libdave</groupId>
|
||||
<artifactId>natives-win-x86-64</artifactId>
|
||||
<version>0.1.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>moe.kyokobot.libdave</groupId>
|
||||
<artifactId>natives-darwin</artifactId>
|
||||
<version>0.1.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pw.chew</groupId>
|
||||
<artifactId>jda-chewtils-command</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pw.chew</groupId>
|
||||
<artifactId>jda-chewtils-commons</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pw.chew</groupId>
|
||||
<artifactId>jda-chewtils-examples</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pw.chew</groupId>
|
||||
<artifactId>jda-chewtils-menu</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>
|
||||
<groupId>com.github.chew.jda-chewtils</groupId>
|
||||
<artifactId>jda-chewtils-command</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.chew.jda-chewtils</groupId>
|
||||
<artifactId>jda-chewtils-menu</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.chew.jda-chewtils</groupId>
|
||||
<artifactId>jda-chewtils-commons</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency> -->
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>com.github.chew.jda-chewtils</groupId>
|
||||
<artifactId>jda-chewtils-command</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.chew.jda-chewtils</groupId>
|
||||
<artifactId>jda-chewtils-menu</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.chew.jda-chewtils</groupId>
|
||||
<artifactId>jda-chewtils-commons</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
-->
|
||||
<!-- Music Dependencies -->
|
||||
<dependency>
|
||||
<groupId>dev.arbjerg</groupId>
|
||||
<artifactId>lavaplayer</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<version>2.2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.arbjerg</groupId>
|
||||
<artifactId>lavaplayer-ext-youtube-rotator</artifactId>
|
||||
<version>2.2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.lavalink.youtube</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>1.4.0</version>
|
||||
<version>1.16.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.jagrosh</groupId>
|
||||
<artifactId>JLyrics</artifactId>
|
||||
<version>master-SNAPSHOT</version>
|
||||
<version>master</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.dunctebot</groupId>
|
||||
@@ -77,7 +178,7 @@
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.13</version>
|
||||
<version>1.5.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe</groupId>
|
||||
@@ -87,8 +188,35 @@
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.15.3</version>
|
||||
<version>1.14.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
<artifactId>selenium-java</artifactId>
|
||||
<version>4.27.0</version>
|
||||
<!-- https://github.com/SeleniumHQ/selenium/issues/13791 -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
<artifactId>selenium-devtools-v85</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
<artifactId>selenium-devtools-v129</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
<artifactId>selenium-devtools-v130</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.bonigarcia</groupId>
|
||||
<artifactId>webdrivermanager</artifactId>
|
||||
<version>5.9.2</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- Testing Dependencies -->
|
||||
<dependency>
|
||||
|
||||
@@ -9,7 +9,7 @@ DOWNLOAD=true
|
||||
LOOP=true
|
||||
|
||||
download() {
|
||||
if [ $DOWNLOAD == true ]; then
|
||||
if [ $DOWNLOAD = true ]; then
|
||||
URL=$(curl -s https://api.github.com/repos/jagrosh/MusicBot/releases/latest \
|
||||
| grep -i "browser_download_url.*\.jar" \
|
||||
| sed 's/.*\(http.*\)"/\1/')
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.jagrosh.jmusicbot.gui.GUI;
|
||||
import com.jagrosh.jmusicbot.playlist.PlaylistLoader;
|
||||
import com.jagrosh.jmusicbot.settings.SettingsManager;
|
||||
import java.util.Objects;
|
||||
import com.jagrosh.jmusicbot.utils.YoutubeOauth2TokenHandler;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
@@ -44,6 +45,7 @@ public class Bot
|
||||
private final PlaylistLoader playlists;
|
||||
private final NowplayingHandler nowplaying;
|
||||
private final AloneInVoiceHandler aloneInVoiceHandler;
|
||||
private final YoutubeOauth2TokenHandler youTubeOauth2TokenHandler;
|
||||
|
||||
private boolean shuttingDown = false;
|
||||
private JDA jda;
|
||||
@@ -56,7 +58,9 @@ public class Bot
|
||||
this.settings = settings;
|
||||
this.playlists = new PlaylistLoader(config);
|
||||
this.threadpool = Executors.newSingleThreadScheduledExecutor();
|
||||
this.players = new PlayerManager(this);
|
||||
this.youTubeOauth2TokenHandler = new YoutubeOauth2TokenHandler();
|
||||
this.youTubeOauth2TokenHandler.init();
|
||||
this.players = new PlayerManager(this, config);
|
||||
this.players.init();
|
||||
this.nowplaying = new NowplayingHandler(this);
|
||||
this.nowplaying.init();
|
||||
@@ -103,6 +107,11 @@ public class Bot
|
||||
{
|
||||
return aloneInVoiceHandler;
|
||||
}
|
||||
|
||||
public YoutubeOauth2TokenHandler getYouTubeOauth2Handler()
|
||||
{
|
||||
return youTubeOauth2TokenHandler;
|
||||
}
|
||||
|
||||
public JDA getJDA()
|
||||
{
|
||||
|
||||
@@ -18,11 +18,16 @@ package com.jagrosh.jmusicbot;
|
||||
import com.jagrosh.jmusicbot.entities.Prompt;
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import com.jagrosh.jmusicbot.utils.TimeUtil;
|
||||
import com.jagrosh.jmusicbot.utils.YouTubeUtil;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.tools.ip.IpBlock;
|
||||
import com.typesafe.config.*;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.dv8tion.jda.api.OnlineStatus;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
|
||||
@@ -41,8 +46,10 @@ public class BotConfig
|
||||
private Path path = null;
|
||||
private String token, prefix, altprefix, helpWord, playlistsFolder, logLevel,
|
||||
successEmoji, warningEmoji, errorEmoji, loadingEmoji, searchingEmoji,
|
||||
evalEngine;
|
||||
private boolean stayInChannel, songInGame, npImages, updatealerts, useEval, dbots;
|
||||
chromePath, chromeDriverPath, evalEngine;
|
||||
private YouTubeUtil.RoutingPlanner ytRoutingPlanner;
|
||||
private List<IpBlock> ytIpBlocks;
|
||||
private boolean youtubeOauth2, stayInChannel, songInGame, npImages, updatealerts, chromeHeadless, useEval, dbots;
|
||||
private long owner, maxSeconds, aloneTimeUntilStop;
|
||||
private int maxYTPlaylistPages;
|
||||
private double skipratio;
|
||||
@@ -84,6 +91,7 @@ public class BotConfig
|
||||
searchingEmoji = config.getString("searching");
|
||||
game = OtherUtil.parseGame(config.getString("game"));
|
||||
status = OtherUtil.parseStatus(config.getString("status"));
|
||||
youtubeOauth2 = config.getBoolean("youtubeoauth2");
|
||||
stayInChannel = config.getBoolean("stayinchannel");
|
||||
songInGame = config.getBoolean("songinstatus");
|
||||
npImages = config.getBoolean("npimages");
|
||||
@@ -96,6 +104,11 @@ public class BotConfig
|
||||
aloneTimeUntilStop = config.getLong("alonetimeuntilstop");
|
||||
playlistsFolder = config.getString("playlistsfolder");
|
||||
aliases = config.getConfig("aliases");
|
||||
chromePath = config.getString("chromepath");
|
||||
chromeDriverPath = config.getString("chromedriverpath");
|
||||
chromeHeadless = config.getBoolean("chromeheadless");
|
||||
ytRoutingPlanner = config.getEnum(YouTubeUtil.RoutingPlanner.class, "ytroutingplanner");
|
||||
ytIpBlocks = config.getStringList("ytipblocks").stream().map(YouTubeUtil::parseIpBlock).collect(Collectors.toList());
|
||||
transforms = config.getConfig("transforms");
|
||||
skipratio = config.getDouble("skipratio");
|
||||
dbots = owner == 113156185389092864L;
|
||||
@@ -293,6 +306,11 @@ public class BotConfig
|
||||
return helpWord;
|
||||
}
|
||||
|
||||
public boolean useYoutubeOauth2()
|
||||
{
|
||||
return youtubeOauth2;
|
||||
}
|
||||
|
||||
public boolean getStay()
|
||||
{
|
||||
return stayInChannel;
|
||||
@@ -323,6 +341,31 @@ public class BotConfig
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
public String getChromePath()
|
||||
{
|
||||
return chromePath.equals("AUTO") ? null : chromePath;
|
||||
}
|
||||
|
||||
public String getChromeDriverPath()
|
||||
{
|
||||
return chromeDriverPath.equals("AUTO") ? null : chromeDriverPath;
|
||||
}
|
||||
|
||||
public boolean getChromeHeadless()
|
||||
{
|
||||
return chromeHeadless;
|
||||
}
|
||||
|
||||
public YouTubeUtil.RoutingPlanner getYTRoutingPlanner()
|
||||
{
|
||||
return ytRoutingPlanner;
|
||||
}
|
||||
|
||||
public List<IpBlock> getYTIpBlocks()
|
||||
{
|
||||
return ytIpBlocks;
|
||||
}
|
||||
|
||||
public boolean useEval()
|
||||
{
|
||||
return useEval;
|
||||
|
||||
@@ -28,10 +28,13 @@ import com.jagrosh.jmusicbot.entities.Prompt;
|
||||
import com.jagrosh.jmusicbot.gui.GUI;
|
||||
import com.jagrosh.jmusicbot.settings.SettingsManager;
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import moe.kyokobot.libdave.NativeDaveFactory;
|
||||
import moe.kyokobot.libdave.jda.LDJDADaveSessionFactory;
|
||||
import java.awt.Color;
|
||||
import java.util.Arrays;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import net.dv8tion.jda.api.*;
|
||||
import net.dv8tion.jda.api.audio.AudioModuleConfig;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||
import net.dv8tion.jda.api.utils.cache.CacheFlag;
|
||||
@@ -40,6 +43,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
import static com.jagrosh.jmusicbot.utils.YouTubeUtil.GetPoTokenAndVisitorData;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author John Grosh (jagrosh)
|
||||
@@ -47,10 +52,10 @@ import ch.qos.logback.classic.Level;
|
||||
public class JMusicBot
|
||||
{
|
||||
public final static Logger LOG = LoggerFactory.getLogger(JMusicBot.class);
|
||||
public final static Permission[] RECOMMENDED_PERMS = {Permission.MESSAGE_READ, Permission.MESSAGE_WRITE, Permission.MESSAGE_HISTORY, Permission.MESSAGE_ADD_REACTION,
|
||||
public final static Permission[] RECOMMENDED_PERMS = {Permission.VIEW_CHANNEL, Permission.MESSAGE_SEND, Permission.MESSAGE_HISTORY, Permission.MESSAGE_ADD_REACTION,
|
||||
Permission.MESSAGE_EMBED_LINKS, Permission.MESSAGE_ATTACH_FILES, Permission.MESSAGE_MANAGE, Permission.MESSAGE_EXT_EMOJI,
|
||||
Permission.VOICE_CONNECT, Permission.VOICE_SPEAK, Permission.NICKNAME_CHANGE};
|
||||
public final static GatewayIntent[] INTENTS = {GatewayIntent.DIRECT_MESSAGES, GatewayIntent.GUILD_MESSAGES, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES};
|
||||
public final static GatewayIntent[] INTENTS = {GatewayIntent.DIRECT_MESSAGES, GatewayIntent.GUILD_MESSAGES, GatewayIntent.GUILD_MESSAGE_REACTIONS, GatewayIntent.GUILD_VOICE_STATES, GatewayIntent.MESSAGE_CONTENT, GatewayIntent.GUILD_EXPRESSIONS, GatewayIntent.SCHEDULED_EVENTS};
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
@@ -118,10 +123,11 @@ public class JMusicBot
|
||||
{
|
||||
JDA jda = JDABuilder.create(config.getToken(), Arrays.asList(INTENTS))
|
||||
.enableCache(CacheFlag.MEMBER_OVERRIDES, CacheFlag.VOICE_STATE)
|
||||
.disableCache(CacheFlag.ACTIVITY, CacheFlag.CLIENT_STATUS, CacheFlag.EMOTE, CacheFlag.ONLINE_STATUS)
|
||||
.disableCache(CacheFlag.ACTIVITY, CacheFlag.CLIENT_STATUS, CacheFlag.ONLINE_STATUS)
|
||||
.setActivity(config.isGameNone() ? null : Activity.playing("loading..."))
|
||||
.setStatus(config.getStatus()==OnlineStatus.INVISIBLE || config.getStatus()==OnlineStatus.OFFLINE
|
||||
? OnlineStatus.INVISIBLE : OnlineStatus.DO_NOT_DISTURB)
|
||||
.setAudioModuleConfig(createAudioModuleConfig())
|
||||
.addEventListeners(client, waiter, new Listener(bot))
|
||||
.setBulkDeleteSplittingEnabled(true)
|
||||
.build();
|
||||
@@ -147,11 +153,10 @@ public class JMusicBot
|
||||
+ "on https://discord.com/developers/applications/" + jda.getSelfUser().getId() + "/bot");
|
||||
}
|
||||
}
|
||||
catch (LoginException ex)
|
||||
catch(IllegalStateException ex)
|
||||
{
|
||||
prompt.alert(Prompt.Level.ERROR, "JMusicBot", ex + "\nPlease make sure you are "
|
||||
+ "editing the correct config.txt file, and that you have used the "
|
||||
+ "correct token (not the 'secret'!)\nConfig Location: " + config.getConfigLocation());
|
||||
prompt.alert(Prompt.Level.ERROR, "JMusicBot", ex.getMessage());
|
||||
LOG.error("Failed to initialize DAVE protocol support", ex);
|
||||
System.exit(1);
|
||||
}
|
||||
catch(IllegalArgumentException ex)
|
||||
@@ -166,6 +171,24 @@ public class JMusicBot
|
||||
+ "attempting to connect, please make sure you're connected to the internet");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
GetPoTokenAndVisitorData(config.getChromePath(), config.getChromeDriverPath(), config.getChromeHeadless());
|
||||
}
|
||||
|
||||
private static AudioModuleConfig createAudioModuleConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeDaveFactory.ensureAvailable();
|
||||
LOG.info("Configured DAVE protocol support using libdave-jvm.");
|
||||
return new AudioModuleConfig()
|
||||
.withDaveSessionFactory(new LDJDADaveSessionFactory(new NativeDaveFactory()));
|
||||
}
|
||||
catch(Throwable ex)
|
||||
{
|
||||
throw new IllegalStateException("Unable to initialize DAVE protocol support via libdave-jvm. "
|
||||
+ "Verify native dependencies are present for this platform (Linux glibc/musl x86_64, Windows x86_64, or macOS).", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static CommandClient createCommandClient(BotConfig config, SettingsManager settings, Bot bot)
|
||||
|
||||
@@ -17,15 +17,17 @@ package com.jagrosh.jmusicbot;
|
||||
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import com.jagrosh.jmusicbot.utils.YoutubeOauth2TokenHandler;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.api.events.ReadyEvent;
|
||||
import net.dv8tion.jda.api.events.ShutdownEvent;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
import net.dv8tion.jda.api.events.session.ReadyEvent;
|
||||
import net.dv8tion.jda.api.events.session.ShutdownEvent;
|
||||
import net.dv8tion.jda.api.events.guild.GuildJoinEvent;
|
||||
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent;
|
||||
import net.dv8tion.jda.api.events.message.guild.GuildMessageDeleteEvent;
|
||||
import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
@@ -85,12 +87,29 @@ public class Listener extends ListenerAdapter
|
||||
catch(Exception ignored) {} // ignored
|
||||
}, 0, 24, TimeUnit.HOURS);
|
||||
}
|
||||
if (bot.getConfig().useYoutubeOauth2())
|
||||
{
|
||||
YoutubeOauth2TokenHandler.Data data = bot.getYouTubeOauth2Handler().getData();
|
||||
if (data != null)
|
||||
{
|
||||
PrivateChannel channel = bot.getJDA().openPrivateChannelById(bot.getConfig().getOwnerId()).complete();
|
||||
channel
|
||||
.sendMessage(
|
||||
"# DO NOT AUTHORISE THIS WITH YOUR MAIN GOOGLE ACCOUNT!!!\n"
|
||||
+ "## Create or use an alternative/burner Google account!\n"
|
||||
+ "To give JMusicBot access to your Google account, go to "
|
||||
+ data.getAuthorisationUrl()
|
||||
+ " and enter the code **" + data.getCode() + "**")
|
||||
.queue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMessageDelete(GuildMessageDeleteEvent event)
|
||||
public void onMessageDelete(MessageDeleteEvent event)
|
||||
{
|
||||
bot.getNowplayingHandler().onMessageDelete(event.getGuild(), event.getMessageIdLong());
|
||||
if(event.isFromGuild())
|
||||
bot.getNowplayingHandler().onMessageDelete(event.getGuild(), event.getMessageIdLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.jagrosh.jmusicbot.queue.AbstractQueue;
|
||||
import com.jagrosh.jmusicbot.settings.QueueType;
|
||||
import com.jagrosh.jmusicbot.utils.TimeUtil;
|
||||
import com.jagrosh.jmusicbot.settings.RepeatMode;
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
|
||||
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
|
||||
@@ -37,11 +36,13 @@ import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioTrack;
|
||||
import java.nio.ByteBuffer;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
import net.dv8tion.jda.api.audio.AudioSendHandler;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
@@ -54,6 +55,7 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
public final static String PAUSE_EMOJI = "\u23F8"; // ⏸
|
||||
public final static String STOP_EMOJI = "\u23F9"; // ⏹
|
||||
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(AudioHandler.class);
|
||||
|
||||
private final List<AudioTrack> defaultQueue = new LinkedList<>();
|
||||
private final Set<String> votes = new HashSet<>();
|
||||
@@ -119,7 +121,7 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
|
||||
public boolean isMusicPlaying(JDA jda)
|
||||
{
|
||||
return guild(jda).getSelfMember().getVoiceState().inVoiceChannel() && audioPlayer.getPlayingTrack()!=null;
|
||||
return guild(jda).getSelfMember().getVoiceState().inAudioChannel() && audioPlayer.getPlayingTrack()!=null;
|
||||
}
|
||||
|
||||
public Set<String> getVotes()
|
||||
@@ -203,8 +205,20 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) {
|
||||
LoggerFactory.getLogger("AudioHandler").error("Track " + track.getIdentifier() + " has failed to play", exception);
|
||||
public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception)
|
||||
{
|
||||
if (
|
||||
exception.getMessage().equals("Sign in to confirm you're not a bot")
|
||||
|| exception.getMessage().equals("Please sign in")
|
||||
)
|
||||
LOGGER.error(
|
||||
"Track {} has failed to play: {}"
|
||||
+ "You will need to sign in to Google to play YouTube tracks. More info: https://jmusicbot.com/youtube-oauth2",
|
||||
track.getIdentifier(),
|
||||
exception.getMessage()
|
||||
);
|
||||
else
|
||||
LOGGER.error("Track {} has failed to play", track.getIdentifier(), exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -216,14 +230,14 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
|
||||
|
||||
// Formatting
|
||||
public Message getNowPlaying(JDA jda)
|
||||
public MessageCreateData getNowPlaying(JDA jda)
|
||||
{
|
||||
if(isMusicPlaying(jda))
|
||||
{
|
||||
Guild guild = guild(jda);
|
||||
AudioTrack track = audioPlayer.getPlayingTrack();
|
||||
MessageBuilder mb = new MessageBuilder();
|
||||
mb.append(FormatUtil.filter(manager.getBot().getConfig().getSuccess()+" **Now Playing in "+guild.getSelfMember().getVoiceState().getChannel().getAsMention()+"...**"));
|
||||
MessageCreateBuilder mb = new MessageCreateBuilder();
|
||||
mb.addContent(FormatUtil.filter(manager.getBot().getConfig().getSuccess()+" **Now Playing in "+guild.getSelfMember().getVoiceState().getChannel().getAsMention()+"...**"));
|
||||
EmbedBuilder eb = new EmbedBuilder();
|
||||
eb.setColor(guild.getSelfMember().getColor());
|
||||
RequestMetadata rm = getRequestMetadata();
|
||||
@@ -264,10 +278,10 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler
|
||||
else return null;
|
||||
}
|
||||
|
||||
public Message getNoMusicPlaying(JDA jda)
|
||||
public MessageCreateData getNoMusicPlaying(JDA jda)
|
||||
{
|
||||
Guild guild = guild(jda);
|
||||
return new MessageBuilder()
|
||||
return new MessageCreateBuilder()
|
||||
.setContent(FormatUtil.filter(manager.getBot().getConfig().getSuccess()+" **Now Playing...**"))
|
||||
.setEmbeds(new EmbedBuilder()
|
||||
.setTitle("No music playing")
|
||||
|
||||
@@ -27,9 +27,11 @@ import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.exceptions.PermissionException;
|
||||
import net.dv8tion.jda.api.exceptions.RateLimitedException;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageEditData;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -54,7 +56,7 @@ public class NowplayingHandler
|
||||
|
||||
public void setLastNPMessage(Message m)
|
||||
{
|
||||
lastNP.put(m.getGuild().getIdLong(), new Pair<>(m.getTextChannel().getIdLong(), m.getIdLong()));
|
||||
lastNP.put(m.getGuild().getIdLong(), new Pair<>(m.getChannel().getIdLong(), m.getIdLong()));
|
||||
}
|
||||
|
||||
public void clearLastNPMessage(Guild guild)
|
||||
@@ -81,7 +83,7 @@ public class NowplayingHandler
|
||||
continue;
|
||||
}
|
||||
AudioHandler handler = (AudioHandler)guild.getAudioManager().getSendingHandler();
|
||||
Message msg = handler.getNowPlaying(bot.getJDA());
|
||||
MessageCreateData msg = handler.getNowPlaying(bot.getJDA());
|
||||
if(msg==null)
|
||||
{
|
||||
msg = handler.getNoMusicPlaying(bot.getJDA());
|
||||
@@ -89,7 +91,7 @@ public class NowplayingHandler
|
||||
}
|
||||
try
|
||||
{
|
||||
tc.editMessageById(pair.getValue(), msg).queue(m->{}, t -> lastNP.remove(guildId));
|
||||
tc.editMessageById(pair.getValue(), MessageEditData.fromCreateData(msg)).queue(m->{}, t -> lastNP.remove(guildId));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@@ -105,7 +107,7 @@ public class NowplayingHandler
|
||||
// update bot status if applicable
|
||||
if(bot.getConfig().getSongInStatus())
|
||||
{
|
||||
if(track!=null && bot.getJDA().getGuilds().stream().filter(g -> g.getSelfMember().getVoiceState().inVoiceChannel()).count()<=1)
|
||||
if(track!=null && bot.getJDA().getGuilds().stream().filter(g -> g.getSelfMember().getVoiceState().inAudioChannel()).count()<=1)
|
||||
bot.getJDA().getPresence().setActivity(Activity.listening(track.getInfo().title));
|
||||
else
|
||||
bot.resetGame();
|
||||
|
||||
@@ -17,6 +17,9 @@ package com.jagrosh.jmusicbot.audio;
|
||||
|
||||
import com.dunctebot.sourcemanagers.DuncteBotSources;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.BotConfig;
|
||||
import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import com.jagrosh.jmusicbot.utils.YouTubeUtil;
|
||||
import com.sedmelluq.discord.lavaplayer.container.MediaContainerRegistry;
|
||||
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
|
||||
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
|
||||
@@ -29,8 +32,21 @@ import com.sedmelluq.discord.lavaplayer.source.nico.NicoAudioSourceManager;
|
||||
import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager;
|
||||
import com.sedmelluq.discord.lavaplayer.source.twitch.TwitchStreamAudioSourceManager;
|
||||
import com.sedmelluq.discord.lavaplayer.source.vimeo.VimeoAudioSourceManager;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.YoutubeIpRotatorSetup;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.planner.AbstractRoutePlanner;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.planner.BalancingIpRoutePlanner;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.planner.NanoIpRoutePlanner;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.tools.ip.IpBlock;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.tools.ip.Ipv4Block;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.tools.ip.Ipv6Block;
|
||||
import dev.lavalink.youtube.YoutubeAudioSourceManager;
|
||||
import dev.lavalink.youtube.clients.Web;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -38,18 +54,31 @@ import net.dv8tion.jda.api.entities.Guild;
|
||||
*/
|
||||
public class PlayerManager extends DefaultAudioPlayerManager
|
||||
{
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(PlayerManager.class);
|
||||
private final Bot bot;
|
||||
|
||||
public PlayerManager(Bot bot)
|
||||
private final BotConfig config;
|
||||
|
||||
public PlayerManager(Bot bot, BotConfig config)
|
||||
{
|
||||
this.bot = bot;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
TransformativeAudioSourceManager.createTransforms(bot.getConfig().getTransforms()).forEach(t -> registerSourceManager(t));
|
||||
|
||||
|
||||
YoutubeAudioSourceManager yt = new YoutubeAudioSourceManager(true);
|
||||
if (config.getYTRoutingPlanner() != YouTubeUtil.RoutingPlanner.NONE)
|
||||
{
|
||||
AbstractRoutePlanner routePlanner = YouTubeUtil.createRouterPlanner(config.getYTRoutingPlanner(), config.getYTIpBlocks());
|
||||
YoutubeIpRotatorSetup rotator = new YoutubeIpRotatorSetup(routePlanner);
|
||||
|
||||
rotator.forConfiguration(yt.getHttpInterfaceManager(), false)
|
||||
.withMainDelegateFilter(yt.getContextFilter())
|
||||
.setup();
|
||||
}
|
||||
|
||||
yt.setPlaylistPageCount(bot.getConfig().getMaxYTPlaylistPages());
|
||||
registerSourceManager(yt);
|
||||
|
||||
@@ -66,7 +95,42 @@ public class PlayerManager extends DefaultAudioPlayerManager
|
||||
|
||||
DuncteBotSources.registerAll(this, "en-US");
|
||||
}
|
||||
|
||||
|
||||
private YoutubeAudioSourceManager setupYoutubeAudioSourceManager()
|
||||
{
|
||||
YoutubeAudioSourceManager yt = new YoutubeAudioSourceManager(true);
|
||||
yt.setPlaylistPageCount(bot.getConfig().getMaxYTPlaylistPages());
|
||||
|
||||
// OAuth2 setup
|
||||
if (bot.getConfig().useYoutubeOauth2())
|
||||
{
|
||||
String token = null;
|
||||
try
|
||||
{
|
||||
token = Files.readString(OtherUtil.getPath("youtubetoken.txt"));
|
||||
}
|
||||
catch (NoSuchFileException e)
|
||||
{
|
||||
/* ignored */
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOGGER.warn("Failed to read YouTube OAuth2 token file: {}", e.getMessage());
|
||||
return yt;
|
||||
}
|
||||
LOGGER.debug("Read YouTube OAuth2 refresh token from youtubetoken.txt");
|
||||
try
|
||||
{
|
||||
yt.useOauth2(token, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warn("Failed to authorise with YouTube. If this issue persists, delete the youtubetoken.txt file to reauthorise.", e);
|
||||
}
|
||||
}
|
||||
return yt;
|
||||
}
|
||||
|
||||
public Bot getBot()
|
||||
{
|
||||
return bot;
|
||||
|
||||
@@ -21,8 +21,8 @@ import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import net.dv8tion.jda.api.entities.GuildVoiceState;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
import net.dv8tion.jda.api.exceptions.PermissionException;
|
||||
|
||||
/**
|
||||
@@ -64,11 +64,11 @@ public abstract class MusicCommand extends Command
|
||||
}
|
||||
if(beListening)
|
||||
{
|
||||
VoiceChannel current = event.getGuild().getSelfMember().getVoiceState().getChannel();
|
||||
VoiceChannel current = (VoiceChannel) event.getGuild().getSelfMember().getVoiceState().getChannel();
|
||||
if(current==null)
|
||||
current = settings.getVoiceChannel(event.getGuild());
|
||||
GuildVoiceState userState = event.getMember().getVoiceState();
|
||||
if(!userState.inVoiceChannel() || userState.isDeafened() || (current!=null && !userState.getChannel().equals(current)))
|
||||
if(!userState.inAudioChannel() || userState.isDeafened() || (current!=null && !userState.getChannel().equals(current)))
|
||||
{
|
||||
event.replyError("You must be listening in "+(current==null ? "a voice channel" : current.getAsMention())+" to use that!");
|
||||
return;
|
||||
@@ -81,7 +81,7 @@ public abstract class MusicCommand extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
if(!event.getGuild().getSelfMember().getVoiceState().inVoiceChannel())
|
||||
if(!event.getGuild().getSelfMember().getVoiceState().inAudioChannel())
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.AdminCommand;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -54,7 +54,8 @@ public class SettcCmd extends AdminCommand
|
||||
}
|
||||
else
|
||||
{
|
||||
List<TextChannel> list = FinderUtil.findTextChannels(event.getArgs(), event.getGuild());
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
List<TextChannel> list = (List) FinderUtil.findTextChannels(event.getArgs(), event.getGuild());
|
||||
if(list.isEmpty())
|
||||
event.reply(event.getClient().getWarning()+" No Text Channels found matching \""+event.getArgs()+"\"");
|
||||
else if (list.size()>1)
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.AdminCommand;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -54,7 +54,8 @@ public class SetvcCmd extends AdminCommand
|
||||
}
|
||||
else
|
||||
{
|
||||
List<VoiceChannel> list = FinderUtil.findVoiceChannels(event.getArgs(), event.getGuild());
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
List<VoiceChannel> list = (List) FinderUtil.findVoiceChannels(event.getArgs(), event.getGuild());
|
||||
if(list.isEmpty())
|
||||
event.reply(event.getClient().getWarning()+" No Voice Channels found matching \""+event.getArgs()+"\"");
|
||||
else if (list.size()>1)
|
||||
|
||||
@@ -23,10 +23,10 @@ import com.jagrosh.jmusicbot.settings.RepeatMode;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -48,10 +48,10 @@ public class SettingsCmd extends Command
|
||||
protected void execute(CommandEvent event)
|
||||
{
|
||||
Settings s = event.getClient().getSettingsFor(event.getGuild());
|
||||
MessageBuilder builder = new MessageBuilder()
|
||||
.append(EMOJI + " **")
|
||||
.append(FormatUtil.filter(event.getSelfUser().getName()))
|
||||
.append("** settings:");
|
||||
MessageCreateBuilder builder = new MessageCreateBuilder()
|
||||
.addContent(EMOJI + " **")
|
||||
.addContent(FormatUtil.filter(event.getSelfUser().getName()))
|
||||
.addContent("** settings:");
|
||||
TextChannel tchan = s.getTextChannel(event.getGuild());
|
||||
VoiceChannel vchan = s.getVoiceChannel(event.getGuild());
|
||||
Role role = s.getRole(event.getGuild());
|
||||
@@ -70,9 +70,9 @@ public class SettingsCmd extends Command
|
||||
+ "\nDefault Playlist: " + (s.getDefaultPlaylist() == null ? "None" : "**" + s.getDefaultPlaylist() + "**")
|
||||
)
|
||||
.setFooter(event.getJDA().getGuilds().size() + " servers | "
|
||||
+ event.getJDA().getGuilds().stream().filter(g -> g.getSelfMember().getVoiceState().inVoiceChannel()).count()
|
||||
+ event.getJDA().getGuilds().stream().filter(g -> g.getSelfMember().getVoiceState().inAudioChannel()).count()
|
||||
+ " audio connections", null);
|
||||
event.getChannel().sendMessage(builder.setEmbeds(ebuilder.build()).build()).queue();
|
||||
event.getMessage().getChannel().sendMessage(builder.setEmbeds(ebuilder.build()).build()).queue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.commands.MusicCommand;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -41,15 +41,15 @@ public class NowplayingCmd extends MusicCommand
|
||||
public void doCommand(CommandEvent event)
|
||||
{
|
||||
AudioHandler handler = (AudioHandler)event.getGuild().getAudioManager().getSendingHandler();
|
||||
Message m = handler.getNowPlaying(event.getJDA());
|
||||
MessageCreateData m = handler.getNowPlaying(event.getJDA());
|
||||
if(m==null)
|
||||
{
|
||||
event.reply(handler.getNoMusicPlaying(event.getJDA()));
|
||||
event.getMessage().getChannel().sendMessage(handler.getNoMusicPlaying(event.getJDA())).queue();
|
||||
bot.getNowplayingHandler().clearLastNPMessage(event.getGuild());
|
||||
}
|
||||
else
|
||||
{
|
||||
event.reply(m, msg -> bot.getNowplayingHandler().setLastNPMessage(msg));
|
||||
event.getMessage().getChannel().sendMessage(m).queue(msg -> bot.getNowplayingHandler().setLastNPMessage(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,8 @@ import com.jagrosh.jmusicbot.settings.RepeatMode;
|
||||
import com.jagrosh.jmusicbot.settings.Settings;
|
||||
import com.jagrosh.jmusicbot.utils.FormatUtil;
|
||||
import com.jagrosh.jmusicbot.utils.TimeUtil;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
|
||||
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.exceptions.PermissionException;
|
||||
@@ -75,12 +76,12 @@ public class QueueCmd extends MusicCommand
|
||||
List<QueuedTrack> list = ah.getQueue().getList();
|
||||
if(list.isEmpty())
|
||||
{
|
||||
Message nowp = ah.getNowPlaying(event.getJDA());
|
||||
Message nonowp = ah.getNoMusicPlaying(event.getJDA());
|
||||
Message built = new MessageBuilder()
|
||||
MessageCreateData nowp = ah.getNowPlaying(event.getJDA());
|
||||
MessageCreateData nonowp = ah.getNoMusicPlaying(event.getJDA());
|
||||
MessageCreateData built = new MessageCreateBuilder()
|
||||
.setContent(event.getClient().getWarning() + " There is no music in the queue!")
|
||||
.setEmbeds((nowp==null ? nonowp : nowp).getEmbeds().get(0)).build();
|
||||
event.reply(built, m ->
|
||||
event.getMessage().getChannel().sendMessage(built).queue(m ->
|
||||
{
|
||||
if(nowp!=null)
|
||||
bot.getNowplayingHandler().setLastNPMessage(m);
|
||||
|
||||
@@ -18,10 +18,13 @@ package com.jagrosh.jmusicbot.commands.music;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.audio.AudioHandler;
|
||||
import com.jagrosh.jmusicbot.audio.RequestMetadata;
|
||||
import com.jagrosh.jmusicbot.commands.DJCommand;
|
||||
import com.jagrosh.jmusicbot.commands.MusicCommand;
|
||||
import com.jagrosh.jmusicbot.utils.TimeUtil;
|
||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
@@ -29,6 +32,8 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||
*/
|
||||
public class SeekCmd extends MusicCommand
|
||||
{
|
||||
private final static Logger LOG = LoggerFactory.getLogger("Seeking");
|
||||
|
||||
public SeekCmd(Bot bot)
|
||||
{
|
||||
super(bot);
|
||||
@@ -52,7 +57,7 @@ public class SeekCmd extends MusicCommand
|
||||
}
|
||||
|
||||
|
||||
if (!DJCommand.checkDJPermission(event) && playingTrack.getUserData(Long.class) != event.getAuthor().getIdLong())
|
||||
if (!DJCommand.checkDJPermission(event) && playingTrack.getUserData(RequestMetadata.class).getOwner() != event.getAuthor().getIdLong())
|
||||
{
|
||||
event.replyError("You cannot seek **" + playingTrack.getInfo().title + "** because you didn't add it!");
|
||||
return;
|
||||
@@ -73,19 +78,18 @@ public class SeekCmd extends MusicCommand
|
||||
if (seekMilliseconds > trackDuration)
|
||||
{
|
||||
event.replyError("Cannot seek to `" + TimeUtil.formatTime(seekMilliseconds) + "` because the current track is `" + TimeUtil.formatTime(trackDuration) + "` long!");
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
playingTrack.setPosition(seekMilliseconds);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
event.replyError("An error occurred while trying to seek!");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
playingTrack.setPosition(seekMilliseconds);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
event.replyError("An error occurred while trying to seek: " + e.getMessage());
|
||||
LOG.warn("Failed to seek track " + playingTrack.getIdentifier(), e);
|
||||
return;
|
||||
}
|
||||
event.replySuccess("Successfully seeked to `" + TimeUtil.formatTime(playingTrack.getPosition()) + "/" + TimeUtil.formatTime(playingTrack.getDuration()) + "`!");
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ import com.jagrosh.jmusicbot.utils.OtherUtil;
|
||||
import com.sedmelluq.discord.lavaplayer.tools.PlayerLibrary;
|
||||
import net.dv8tion.jda.api.JDAInfo;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.ChannelType;
|
||||
import net.dv8tion.jda.api.entities.channel.ChannelType;
|
||||
import net.dv8tion.jda.api.utils.FileUpload;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -79,8 +80,8 @@ public class DebugCmd extends OwnerCommand
|
||||
sb.append("\n```");
|
||||
|
||||
if(event.isFromType(ChannelType.PRIVATE)
|
||||
|| event.getSelfMember().hasPermission(event.getTextChannel(), Permission.MESSAGE_ATTACH_FILES))
|
||||
event.getChannel().sendFile(sb.toString().getBytes(), "debug_information.txt").queue();
|
||||
|| event.getSelfMember().hasPermission(event.getGuildChannel(), Permission.MESSAGE_ATTACH_FILES))
|
||||
event.getChannel().sendFiles(FileUpload.fromData(sb.toString().getBytes(), "debug_information.txt")).queue();
|
||||
else
|
||||
event.reply("Debug Information: " + sb.toString());
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import javax.script.ScriptEngineManager;
|
||||
import com.jagrosh.jdautilities.command.CommandEvent;
|
||||
import com.jagrosh.jmusicbot.Bot;
|
||||
import com.jagrosh.jmusicbot.commands.OwnerCommand;
|
||||
import net.dv8tion.jda.api.entities.ChannelType;
|
||||
import net.dv8tion.jda.api.entities.channel.ChannelType;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -20,8 +20,8 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.HashMap;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
@@ -32,6 +33,7 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class SettingsManager implements GuildSettingsManager<Settings>
|
||||
{
|
||||
private final static Logger LOG = LoggerFactory.getLogger("Settings");
|
||||
private final static String SETTINGS_FILE = "serversettings.json";
|
||||
private final HashMap<Long,Settings> settings;
|
||||
|
||||
@@ -63,17 +65,17 @@ public class SettingsManager implements GuildSettingsManager<Settings>
|
||||
} catch (NoSuchFileException e) {
|
||||
// create an empty json file
|
||||
try {
|
||||
LoggerFactory.getLogger("Settings").info("serversettings.json will be created in " + OtherUtil.getPath("serversettings.json").toAbsolutePath());
|
||||
LOG.info("serversettings.json will be created in " + OtherUtil.getPath("serversettings.json").toAbsolutePath());
|
||||
Files.write(OtherUtil.getPath("serversettings.json"), new JSONObject().toString(4).getBytes());
|
||||
} catch(IOException ex) {
|
||||
LoggerFactory.getLogger("Settings").warn("Failed to create new settings file: "+ex);
|
||||
LOG.warn("Failed to create new settings file: "+ex);
|
||||
}
|
||||
return;
|
||||
} catch(IOException | JSONException e) {
|
||||
LoggerFactory.getLogger("Settings").warn("Failed to load server settings: "+e);
|
||||
LOG.warn("Failed to load server settings: "+e);
|
||||
}
|
||||
|
||||
LoggerFactory.getLogger("Settings").info("serversettings.json loaded from " + OtherUtil.getPath("serversettings.json").toAbsolutePath());
|
||||
LOG.info("serversettings.json loaded from " + OtherUtil.getPath("serversettings.json").toAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +129,7 @@ public class SettingsManager implements GuildSettingsManager<Settings>
|
||||
try {
|
||||
Files.write(OtherUtil.getPath(SETTINGS_FILE), obj.toString(4).getBytes());
|
||||
} catch(IOException ex){
|
||||
LoggerFactory.getLogger("Settings").warn("Failed to write to file: "+ex);
|
||||
LOG.warn("Failed to write to file: "+ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,9 @@ package com.jagrosh.jmusicbot.utils;
|
||||
import com.jagrosh.jmusicbot.audio.RequestMetadata.UserInfo;
|
||||
import java.util.List;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.VoiceChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -94,7 +94,7 @@ public class FormatUtil {
|
||||
|
||||
public static String listOfRoles(List<Role> list, String query)
|
||||
{
|
||||
String out = " Multiple text channels found matching \""+query+"\":";
|
||||
String out = " Multiple roles found matching \""+query+"\":";
|
||||
for(int i=0; i<6 && i<list.size(); i++)
|
||||
out+="\n - "+list.get(i).getName()+" (ID:"+list.get(i).getId()+")";
|
||||
if(list.size()>6)
|
||||
|
||||
@@ -43,7 +43,11 @@ public class OtherUtil
|
||||
public final static String NEW_VERSION_AVAILABLE = "There is a new version of JMusicBot available!\n"
|
||||
+ "Current version: %s\n"
|
||||
+ "New Version: %s\n\n"
|
||||
+ "Please visit https://github.com/jagrosh/MusicBot/releases/latest to get the latest release.";
|
||||
+ "Please visit https://github.com/chrisb09/MusicBot/releases to get the latest release."
|
||||
+ "If you are using docker (or docker-compose), please pull the new image with:"
|
||||
+ "Docker: docker pull chrisb09/jmusicbot"
|
||||
+ "Docker-compose: docker-compose pull"+
|
||||
" and don't forget to restart the container.";
|
||||
private final static String WINDOWS_INVALID_PATH = "c:\\windows\\system32\\";
|
||||
|
||||
/**
|
||||
@@ -188,7 +192,7 @@ public class OtherUtil
|
||||
try
|
||||
{
|
||||
Response response = new OkHttpClient.Builder().build()
|
||||
.newCall(new Request.Builder().get().url("https://api.github.com/repos/jagrosh/MusicBot/releases/latest").build())
|
||||
.newCall(new Request.Builder().get().url("https://api.github.com/repos/chrisb09/MusicBot/releases/latest").build())
|
||||
.execute();
|
||||
ResponseBody body = response.body();
|
||||
if(body != null)
|
||||
@@ -224,7 +228,9 @@ public class OtherUtil
|
||||
ApplicationInfo info = jda.retrieveApplicationInfo().complete();
|
||||
if (info.isBotPublic())
|
||||
return "\"Public Bot\" is enabled. Using JMusicBot as a public bot is not supported. Please disable it in the "
|
||||
+ "Developer Dashboard at https://discord.com/developers/applications/" + jda.getSelfUser().getId() + "/bot.";
|
||||
+ "Developer Dashboard at https://discord.com/developers/applications/" + jda.getSelfUser().getId() + "/bot ."
|
||||
+ "You may also need to disable all Installation Contexts at https://discord.com/developers/applications/"
|
||||
+ jda.getSelfUser().getId() + "/installation .";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
package com.jagrosh.jmusicbot.utils;
|
||||
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.planner.*;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.tools.ip.IpBlock;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.tools.ip.Ipv4Block;
|
||||
import com.sedmelluq.lava.extensions.youtuberotator.tools.ip.Ipv6Block;
|
||||
import dev.lavalink.youtube.clients.Web;
|
||||
import org.json.JSONObject;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.chrome.ChromeDriver;
|
||||
import org.openqa.selenium.chrome.ChromeDriverService;
|
||||
import org.openqa.selenium.chrome.ChromeOptions;
|
||||
import org.openqa.selenium.chromium.ChromiumDriverLogLevel;
|
||||
import org.openqa.selenium.devtools.NetworkInterceptor;
|
||||
import org.openqa.selenium.os.ExecutableFinder;
|
||||
import org.openqa.selenium.remote.http.Contents;
|
||||
import org.openqa.selenium.remote.http.Filter;
|
||||
import org.openqa.selenium.remote.http.HttpMethod;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import io.github.bonigarcia.wdm.WebDriverManager;
|
||||
|
||||
public class YouTubeUtil {
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(YouTubeUtil.class);
|
||||
|
||||
public enum RoutingPlanner {
|
||||
NONE,
|
||||
ROTATE_ON_BAN,
|
||||
LOAD_BALANCE,
|
||||
NANO_SWITCH,
|
||||
ROTATING_NANO_SWITCH
|
||||
}
|
||||
|
||||
public static IpBlock parseIpBlock(String cidr) {
|
||||
if (Ipv6Block.isIpv6CidrBlock(cidr))
|
||||
return new Ipv6Block(cidr);
|
||||
|
||||
if (Ipv4Block.isIpv4CidrBlock(cidr))
|
||||
return new Ipv4Block(cidr);
|
||||
|
||||
throw new IllegalArgumentException("Could not parse CIDR " + cidr);
|
||||
}
|
||||
|
||||
public static AbstractRoutePlanner createRouterPlanner(RoutingPlanner routingPlanner, List<IpBlock> ipBlocks) {
|
||||
|
||||
switch (routingPlanner) {
|
||||
case NONE:
|
||||
return null;
|
||||
case ROTATE_ON_BAN:
|
||||
return new RotatingIpRoutePlanner(ipBlocks);
|
||||
case LOAD_BALANCE:
|
||||
return new BalancingIpRoutePlanner(ipBlocks);
|
||||
case NANO_SWITCH:
|
||||
return new NanoIpRoutePlanner(ipBlocks, true);
|
||||
case ROTATING_NANO_SWITCH:
|
||||
return new RotatingNanoIpRoutePlanner(ipBlocks);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown RoutingPlanner value provided");
|
||||
}
|
||||
}
|
||||
|
||||
public static void GetPoTokenAndVisitorData(String userChromePath, String userChromeDriverPath, boolean headless)
|
||||
{
|
||||
//
|
||||
// 1. Find a Chrome install & launch the WebDriver
|
||||
//
|
||||
WebDriverManager wdm = WebDriverManager.chromedriver();
|
||||
if (userChromePath != null) {
|
||||
wdm.browserVersionDetectionCommand(userChromePath + " --version");
|
||||
}
|
||||
else if (wdm.getBrowserPath().isEmpty())
|
||||
{
|
||||
// try finding a Chromium browser instead (Linux users usually install Chromium instead of Google Chrome)
|
||||
wdm = WebDriverManager.chromiumdriver();
|
||||
if (wdm.getBrowserPath().isEmpty()) {
|
||||
LOGGER.error("Could not obtain a PO token for YouTube playback, because no Chrome browser could be found. Please install Google Chrome or Chromium!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (userChromeDriverPath == null)
|
||||
// Automatically download & set up ChromeDriver for the Chrome/Chromium version that the user has installed
|
||||
wdm.setup();
|
||||
else {
|
||||
// Find & use the ChromeDriver executable the user provided
|
||||
String path = new ExecutableFinder().find(userChromeDriverPath);
|
||||
if (path == null) {
|
||||
LOGGER.error("Could not obtain a PO token for YouTube playback, because the specified ChromeDriver could not be found. " +
|
||||
"Please check your config's value of the chromedriverpath, or set it to \"AUTO\" to have JMusicBot automatically download ChromeDriver");
|
||||
return;
|
||||
}
|
||||
LOGGER.info("Using ChromeDriver at {}", path);
|
||||
System.setProperty("webdriver.chrome.driver", path);
|
||||
}
|
||||
|
||||
ChromeOptions chromeOptions = new ChromeOptions();
|
||||
|
||||
chromeOptions.setBinary(userChromePath != null ? userChromePath : wdm.getBrowserPath().get().toString());
|
||||
|
||||
if (!headless)
|
||||
chromeOptions.addArguments("--auto-open-devtools-for-tabs");
|
||||
else
|
||||
chromeOptions.addArguments("--headless=new");
|
||||
|
||||
ChromeDriverService.Builder chromeDriverBuilder = new ChromeDriverService.Builder();
|
||||
if (LOGGER.isDebugEnabled())
|
||||
chromeDriverBuilder.withLogLevel(ChromiumDriverLogLevel.DEBUG);
|
||||
|
||||
WebDriver driver = new ChromeDriver(chromeDriverBuilder.build(), chromeOptions);
|
||||
|
||||
//
|
||||
// 2. Setup a network interceptor to intercept the player API request & obtain po token and visitor data
|
||||
//
|
||||
|
||||
// as the network interceptor below runs on a different thread, we'll have it notify us on this/current thread
|
||||
// whether retrieving the data failed (completes with the Exception) or succeeded (completes with null)
|
||||
CompletableFuture<Exception> interceptorFuture = new CompletableFuture<>();
|
||||
|
||||
NetworkInterceptor interceptor = new NetworkInterceptor(driver,
|
||||
(Filter) next -> req -> {
|
||||
|
||||
if (req.getMethod() != HttpMethod.POST || !req.getUri().contains("/youtubei/v1/player"))
|
||||
return next.execute(req);
|
||||
|
||||
try {
|
||||
String rawBody = Contents.string(req);
|
||||
JSONObject body = new JSONObject(rawBody);
|
||||
|
||||
String visitorData = body
|
||||
.getJSONObject("context")
|
||||
.getJSONObject("client")
|
||||
.getString("visitorData");
|
||||
|
||||
String poToken = body
|
||||
.getJSONObject("serviceIntegrityDimensions")
|
||||
.getString("poToken");
|
||||
|
||||
|
||||
LOGGER.info("Successfully retrieved PO token & visitor data for YouTube playback.");
|
||||
LOGGER.debug("PO token: {}", poToken);
|
||||
LOGGER.debug("Visitor Data: {}", visitorData);
|
||||
|
||||
if (poToken.length() < 160)
|
||||
LOGGER.warn("There is a high chance that the retrieved PO token will not work. Try on a different network.");
|
||||
|
||||
Web.setPoTokenAndVisitorData(poToken, visitorData);
|
||||
|
||||
interceptorFuture.complete(null);
|
||||
} catch (Exception e) {
|
||||
interceptorFuture.complete(e);
|
||||
}
|
||||
|
||||
return next.execute(req);
|
||||
});
|
||||
|
||||
//
|
||||
// 3. Navigate to YouTube & start the player
|
||||
//
|
||||
try {
|
||||
driver.get("https://www.youtube.com/embed/aqz-KE-bpKQ");
|
||||
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(15));
|
||||
WebElement moviePlayer = driver.findElement(By.cssSelector("#movie_player"));
|
||||
moviePlayer.click();
|
||||
|
||||
try {
|
||||
// Wait for the network interceptor to tell us if it got the data
|
||||
Exception result = interceptorFuture.get(20, TimeUnit.SECONDS);
|
||||
if (result != null)
|
||||
throw new Exception("Failed to read YouTube player request body", result);
|
||||
} catch (TimeoutException e) {
|
||||
throw new Exception("Timed out waiting for YouTube player request");
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to obtain PO token for YouTube playback: {}", e.getMessage());
|
||||
LOGGER.debug("Exception:", e);
|
||||
} finally {
|
||||
interceptor.close();
|
||||
// Only quit the browser when not in headless mode. Helps with troubleshooting.
|
||||
if (headless)
|
||||
driver.quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.jagrosh.jmusicbot.utils;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.turbo.TurboFilter;
|
||||
import ch.qos.logback.core.spi.FilterReply;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Marker;
|
||||
|
||||
import java.nio.file.Files;
|
||||
|
||||
/**
|
||||
* A logback turbo filter, used retrieve the YouTube OAuth2 refresh token that gets logged once authorized with YouTube.
|
||||
*
|
||||
* @author Michaili K. <git@michaili.dev>
|
||||
*/
|
||||
public class YoutubeOauth2TokenHandler extends TurboFilter {
|
||||
public final static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(YoutubeOauth2TokenHandler.class);
|
||||
private Data data;
|
||||
|
||||
|
||||
public void init()
|
||||
{
|
||||
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
context.addTurboFilter(this);
|
||||
}
|
||||
|
||||
public Data getData()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t)
|
||||
{
|
||||
if (!logger.getName().equals("dev.lavalink.youtube.http.YoutubeOauth2Handler"))
|
||||
return FilterReply.NEUTRAL;
|
||||
|
||||
if (format.equals("OAUTH INTEGRATION: To give youtube-source access to your account, go to {} and enter code {}"))
|
||||
{
|
||||
this.data = new Data((String) params[0], (String) params[1]);
|
||||
return FilterReply.NEUTRAL;
|
||||
}
|
||||
if (format.equals("OAUTH INTEGRATION: Token retrieved successfully. Store your refresh token as this can be reused. ({})"))
|
||||
{
|
||||
LOGGER.info(
|
||||
"Authorization successful & retrieved token! Storing the token in {}",
|
||||
OtherUtil.getPath("youtubetoken.txt").toAbsolutePath()
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
Files.write(OtherUtil.getPath("youtubetoken.txt"), params[0].toString().getBytes());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error(
|
||||
"Failed to write the YouTube OAuth2 refresh token to storage! You will need to authorize again on the next reboot",
|
||||
e
|
||||
);
|
||||
}
|
||||
return FilterReply.DENY;
|
||||
}
|
||||
|
||||
return FilterReply.NEUTRAL;
|
||||
}
|
||||
|
||||
public static class Data
|
||||
{
|
||||
private final String authorisationUrl;
|
||||
private final String code;
|
||||
|
||||
private Data(String authorisationUrl, String code)
|
||||
{
|
||||
this.authorisationUrl = authorisationUrl;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getAuthorisationUrl()
|
||||
{
|
||||
return authorisationUrl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -48,6 +48,14 @@ game = "DEFAULT"
|
||||
status = ONLINE
|
||||
|
||||
|
||||
// If you set this to true, the bot will use a Google account to play YouTube tracks.
|
||||
// This is only needed if you are experiencing issues with YouTube playback.
|
||||
// Once enabled, instructions for login will be written to the console and DMs.
|
||||
// DO NOT use your main Google account! Use an alternative account.
|
||||
|
||||
youtubeoauth2=false
|
||||
|
||||
|
||||
// If you set this to true, the bot will list the title of the song it is currently playing in its
|
||||
// "Playing" status. Note that this will ONLY work if the bot is playing music on ONE guild;
|
||||
// if the bot is playing on multiple guilds, this will not work.
|
||||
@@ -200,6 +208,49 @@ aliases {
|
||||
loglevel = info
|
||||
|
||||
|
||||
// This sets the executable path of where a Chrome or Chromium installation is located JMusicBot can use.
|
||||
// JMusicBot may launch a web browser to get around anti-bot checks.
|
||||
// Set this to "AUTO" to make JMusicBot attempt to find a Chrome/Chromium installation itself.
|
||||
|
||||
chromepath = "AUTO"
|
||||
|
||||
|
||||
// This sets the executable path of where a ChromeDriver installation is located JMusicBot can use.
|
||||
// Set this to "AUTO" to make JMusicBot automatically download the ChromeDriver version
|
||||
// which matches the installed Chrome version.
|
||||
|
||||
chromedriverpath = "AUTO"
|
||||
|
||||
|
||||
// This sets whether JMusicBot should launch Chrome/Chromium instances without a GUI.
|
||||
// It is recommended to leave this set to true.
|
||||
// If set to false, JMusicBot will not close the browser automatically (even when finished)
|
||||
// and will automatically open DevTools for troubleshooting purposes.
|
||||
|
||||
chromeheadless = true
|
||||
|
||||
|
||||
// This configures the routing planner to use for IP rotation on YouTube.
|
||||
// When set, you need to also set an IP block below.
|
||||
// The following routing strategies are available:
|
||||
// NONE = Disable
|
||||
// ROTATE_ON_BAN = Switch IP when currently used address gets banned.
|
||||
// LOAD_BALANCE = Selects random IP for each track playback.
|
||||
// NANO_SWITCH = Selects IPv6 address based on current nanosecond. Recommended for one /64 IPv6 blocks.
|
||||
// ROTATING_NANO_SWITCH = Same as above, but uses the next /64 IPv6 block in the list in case of a ban.
|
||||
|
||||
ytroutingplanner = NONE
|
||||
|
||||
|
||||
// The IPv4 and IPv6 blocks to use when using the above routing planner.
|
||||
// This does nothing when ytroutingplanner is set to none.
|
||||
// The list accepts a list of IPv4 or IPv6 CIDR blocks (not a mix of them however)
|
||||
// IPv4 example: [ "192.0.2.183", "198.51.100.153/29" ]
|
||||
// IPv6 example: [ "2a02:1234:5678:9abc::/64" ]
|
||||
|
||||
ytipblocks = [ ]
|
||||
|
||||
|
||||
// Transforms are used to modify specific play inputs and convert them to different kinds of inputs
|
||||
// These are quite complicated to use, and have limited use-cases, but in theory allow for rough
|
||||
// whitelists or blacklists, roundabout loading from some sources, and customization of how things are
|
||||
|
||||
Reference in new issue
Block a user