Skip to content

Commit

Permalink
started the rewrite (finally)
Browse files Browse the repository at this point in the history
  • Loading branch information
parzival-space committed Aug 26, 2023
0 parents commit b092b32
Show file tree
Hide file tree
Showing 15 changed files with 491 additions and 0 deletions.
33 changes: 33 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Discord Radio Bot

> [!IMPORTANT]
> You are currently viewing the Java rewrite of the bot. I am not done jet and some features are missing. If you are looking for the old Node.js based version, click <a href="//github.com/parzival-space/discord-radio-bot/tree/main-old-node">here</a>.
Plays radio streams directly inside your Discord server.
This bot has no commands, it's for playing radio streams only.
You can specify your own radio stream in the config.
<br>
<b>
Important: The provided url MUST be a link to a DIRECT MEDIA STREAM. This means https://radioXYZ.fm is not a valid url!<br>
Stream urls normally look like https://play.radioXYZ.fm/source.mp3
</b>

## How to
### Requirements
You need this.

1. Create a new Bot User
First you need to create a new bot account. <br />
Head over to the <a href="//discord.com/developers">Discord Developer Portal</a>, create a new bot instance and get the bot token.
2. A working JRE setup
If you do not have one already, get it here: <a href="//adoptopenjdk.net/releases.html">AdoptOpenJDK</a>

### Running the Bot
Download the latest <a href="//github.com/parzival-space/discord-radio-bot/releases">release</a>.

Then you have to create a file called ``application.properties`` in the same directory as the bot.
Fill it like so:
```properties
discord.token=<<your token>>
discord.channel=<<your channel id>>
```

And run it: ``java -jar radiobot.jar``
87 changes: 87 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>space.parzival.discord</groupId>
<artifactId>radiobot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>radiobot</name>
<description>Plays radio streams directly inside your Discord server. </description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>5.0.0-beta.12</version>
</dependency>
<dependency>
<groupId>com.github.walkyst</groupId>
<artifactId>lavaplayer-fork</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.9.4</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>jitpack</id>
<url>https://jitpack.io</url>
</repository>
</repositories>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package space.parzival.discord.radiobot;

import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import space.parzival.discord.radiobot.properties.ClientProperties;

import java.util.List;

@Slf4j
@Component
public class ClientConfiguration {

@Bean
public JDA discordInstance(ClientProperties clientProperties, List<? extends ListenerAdapter> events) {
JDA client = JDABuilder
.createDefault(clientProperties.getToken())
.build();

events.forEach(client::addEventListener);

log.debug("New Discord instance created.");
return client;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package space.parzival.discord.radiobot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import space.parzival.discord.radiobot.properties.ClientProperties;
import space.parzival.discord.radiobot.properties.HttpProperties;
import space.parzival.discord.radiobot.properties.StreamProperties;

@SpringBootApplication
@EnableConfigurationProperties
@Import({
ClientProperties.class,
StreamProperties.class,
HttpProperties.class
})
public class RadioBotApplication {

public static void main(String[] args) {
SpringApplication.run(RadioBotApplication.class, args);
}

}
59 changes: 59 additions & 0 deletions src/main/java/space/parzival/discord/radiobot/VersionCheck.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package space.parzival.discord.radiobot;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.message.BasicHeader;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.info.BuildProperties;
import org.springframework.stereotype.Component;
import org.apache.maven.artifact.versioning.ComparableVersion;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import space.parzival.discord.radiobot.properties.HttpProperties;
import space.parzival.discord.radiobot.model.GitHubRelease;

import java.util.List;

@Slf4j
@Component
public class VersionCheck implements InitializingBean {

@Autowired
private HttpProperties httpProperties;

@Autowired
private BuildProperties buildProperties;

@Override
public void afterPropertiesSet() throws Exception {
ComparableVersion latest = this.getLatestVersion();
ComparableVersion current = new ComparableVersion(buildProperties.getVersion());

if (current.compareTo(latest) > 0) {
log.warn("------------------------------------------------------------------");
log.warn("You are currently running version {}, but {} ", current, latest);
log.warn("is already available. Please consider updating.");
log.warn("------------------------------------------------------------------");
}
}

private ComparableVersion getLatestVersion() {
WebClient githubClient = WebClient.builder()
.defaultHeader("User-Agent", httpProperties.getUserAgent())
.baseUrl("https://api.github.com")
.build();

Mono<GitHubRelease[]> response = githubClient
.get()
.uri(httpProperties.getVersionUrl())
.retrieve()
.bodyToMono(GitHubRelease[].class);

GitHubRelease[] releases = response.block();
if (releases != null && releases.length >= 1)
return new ComparableVersion(releases[0].tag_name);

return new ComparableVersion("0.0.0");
}

}
80 changes: 80 additions & 0 deletions src/main/java/space/parzival/discord/radiobot/events/Ready.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package space.parzival.discord.radiobot.events;

import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.player.event.AudioEvent;
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventListener;
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.audio.AudioSendHandler;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
import net.dv8tion.jda.api.events.session.ReadyEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import space.parzival.discord.radiobot.icecast.IcyAudioLoadResultHandler;
import space.parzival.discord.radiobot.icecast.IcyAudioPlayerManager;
import space.parzival.discord.radiobot.player.AudioPlayerSendHandler;
import space.parzival.discord.radiobot.properties.ClientProperties;

import java.nio.ByteBuffer;

@Slf4j
@Component
public class Ready extends ListenerAdapter {

@Autowired
private IcyAudioPlayerManager playerManager;

@Autowired
private ClientProperties clientProperties;

public void onReady(@NotNull ReadyEvent event) {
log.info("This bot is now ready and connected to {} guilds.", event.getGuildTotalCount());

JDA client = event.getJDA();
VoiceChannel channel = client.getVoiceChannelById(clientProperties.getChannel());
assert channel != null;
Guild guild = channel.getGuild();
guild.getAudioManager().openAudioConnection(channel);

AudioPlayer player = playerManager.createPlayer();
guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player));

playerManager.loadIcyStream("https://play.sas-media.ru/play_256", new IcyAudioLoadResultHandler() {
@Override
public void metadataUpdated(String metadata) {

}

@Override
public void trackLoaded(AudioTrack audioTrack) {
log.info("Playing {} by {}", audioTrack.getInfo().title, audioTrack.getInfo().author);
player.playTrack(audioTrack);
}

@Override
public void playlistLoaded(AudioPlaylist audioPlaylist) {

}

@Override
public void noMatches() {
log.error("No matches.");
}

@Override
public void loadFailed(FriendlyException e) {
log.error("Load failed:", e);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package space.parzival.discord.radiobot.icecast;

import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;

public interface IcyAudioLoadResultHandler extends AudioLoadResultHandler {

void metadataUpdated(String metadata);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package space.parzival.discord.radiobot.icecast;

import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioSourceManager;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;

@Component
public class IcyAudioPlayerManager extends DefaultAudioPlayerManager {

public IcyAudioPlayerManager() {
super();

// we do not need support for YouTube, so only http sources
this.registerSourceManager(new HttpAudioSourceManager());
}


public void loadIcyStream(final String url, final IcyAudioLoadResultHandler resultHandler) {
this.loadItem(url, resultHandler);

// todo: implement logic for current track info
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package space.parzival.discord.radiobot.model;

public class GitHubRelease {
public String tag_name;
}
Loading

0 comments on commit b092b32

Please sign in to comment.