[AB-98] adding twitch support

upgrading to java 17
upgrade of dependencies
This commit is contained in:
Sheldan
2023-07-06 23:05:51 +02:00
parent 346e462185
commit 6409bbaa1d
167 changed files with 3964 additions and 489 deletions

View File

@@ -0,0 +1,26 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>twitch</artifactId>
<version>1.4.27-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>twitch-int</artifactId>
<dependencies>
<dependency>
<groupId>com.github.twitch4j</groupId>
<artifactId>twitch4j</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>

View File

@@ -0,0 +1,28 @@
package dev.sheldan.abstracto.twitch.config;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.config.PostTargetEnum;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class TwitchFeatureConfig implements FeatureConfig {
@Override
public FeatureDefinition getFeature() {
return TwitchFeatureDefinition.TWITCH;
}
@Override
public List<PostTargetEnum> getRequiredPostTargets() {
return Arrays.asList(TwitchPostTarget.TWITCH_LIVE_NOTIFICATION);
}
@Override
public List<FeatureMode> getAvailableModes() {
return Arrays.asList(TwitchFeatureMode.DELETE_NOTIFICATION, TwitchFeatureMode.UPDATE_NOTIFICATION);
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.twitch.config;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import lombok.Getter;
@Getter
public enum TwitchFeatureDefinition implements FeatureDefinition {
TWITCH("twitch");
private String key;
TwitchFeatureDefinition(String key) {
this.key = key;
}
}

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.twitch.config;
import dev.sheldan.abstracto.core.config.FeatureMode;
import lombok.Getter;
@Getter
public enum TwitchFeatureMode implements FeatureMode {
DELETE_NOTIFICATION("deleteNotification"), UPDATE_NOTIFICATION("updateNotification");
private final String key;
TwitchFeatureMode(String key) {
this.key = key;
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.twitch.config;
import dev.sheldan.abstracto.core.config.PostTargetEnum;
import lombok.Getter;
@Getter
public enum TwitchPostTarget implements PostTargetEnum {
TWITCH_LIVE_NOTIFICATION("twitchLiveNotification");
private String key;
TwitchPostTarget(String key) {
this.key = key;
}
}

View File

@@ -0,0 +1,8 @@
package dev.sheldan.abstracto.twitch.config;
public class TwitchSlashCommandNames {
private TwitchSlashCommandNames() {
}
public static final String TWITCH = "twitch";
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.twitch.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class StreamerExistsException extends AbstractoRunTimeException implements Templatable {
public StreamerExistsException() {
super("Streamer is already setup in server.");
}
@Override
public String getTemplateName() {
return "streamer_already_exists_in_server_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.twitch.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class StreamerNotFoundException extends AbstractoRunTimeException implements Templatable {
public StreamerNotFoundException() {
super("Streamer was not found on Twitch..");
}
@Override
public String getTemplateName() {
return "streamer_not_exists_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.twitch.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class StreamerNotFoundInServerException extends AbstractoRunTimeException implements Templatable {
public StreamerNotFoundInServerException() {
super("Streamer was not set up in server.");
}
@Override
public String getTemplateName() {
return "streamer_not_exists_in_server_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,52 @@
package dev.sheldan.abstracto.twitch.model.database;
import dev.sheldan.abstracto.core.models.database.AChannel;
import lombok.*;
import jakarta.persistence.*;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name="stream_session")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
public class StreamSession {
@Id
@Column(name = "id", nullable = false)
private Long id;
@EqualsAndHashCode.Exclude
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "streamer_id", nullable = false)
private Streamer streamer;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "channel_id", nullable = false)
private AChannel channel;
@Column(name = "stream_id", nullable = false)
private String streamId;
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
@Column(name = "startTime", nullable = false)
private Instant startTime;
@EqualsAndHashCode.Exclude
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
mappedBy = "session")
@Builder.Default
private List<StreamSessionSection> sections = new ArrayList<>();
}

View File

@@ -0,0 +1,51 @@
package dev.sheldan.abstracto.twitch.model.database;
import jakarta.persistence.*;
import lombok.*;
import java.time.Instant;
@Entity
@Table(name="stream_session_section")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
public class StreamSessionSection {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
@EqualsAndHashCode.Exclude
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "streamer_id", nullable = false)
private Streamer streamer;
@EqualsAndHashCode.Exclude
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "stream_session_id", nullable = false)
private StreamSession session;
@Column(name = "game_id", nullable = false)
private String gameId;
@Column(name = "game_name", nullable = false)
private String gameName;
@Column(name = "viewer_count", nullable = false)
private Integer viewerCount;
@Column(name = "title", nullable = false)
private String title;
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
}

View File

@@ -0,0 +1,79 @@
package dev.sheldan.abstracto.twitch.model.database;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import lombok.*;
import jakarta.persistence.*;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name="streamer")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
public class Streamer {
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id", nullable = false)
private String userId;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "template_key")
private String templateKey;
@Column(name = "current_game_id")
private String currentGameId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "notification_channel_id")
private AChannel notificationChannel;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "creator_user_in_server_id", nullable = false)
private AUserInAServer creator;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "server_id", nullable = false)
private AServer server;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "streamer_user_in_server_id")
private AUserInAServer streamerUser;
@EqualsAndHashCode.Exclude
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "current_session_id")
private StreamSession currentSession;
@Column(name = "show_notifications", nullable = false)
private Boolean showNotifications;
@Column(name = "online", nullable = false)
private Boolean online;
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
@EqualsAndHashCode.Exclude
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
mappedBy = "streamer")
@Builder.Default
private List<StreamSession> sessions = new ArrayList<>();
}

View File

@@ -0,0 +1,17 @@
package dev.sheldan.abstracto.twitch.model.template;
import lombok.Builder;
import lombok.Getter;
import java.util.List;
@Builder
@Getter
public class GoLiveNotificationModel {
private String channelName;
private StreamSectionDisplay currentSection;
private List<StreamSectionDisplay> pastSections;
private Boolean mature;
private String streamURL;
private String streamerAvatarURL;
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.twitch.model.template;
import lombok.Builder;
import lombok.Getter;
import java.util.List;
@Builder
@Getter
public class GoOfflineNotificationModel {
private String channelName;
private List<StreamSectionDisplay> pastSections;
private String offlineImageURL;
private String avatarURL;
}

View File

@@ -0,0 +1,12 @@
package dev.sheldan.abstracto.twitch.model.template;
import lombok.Builder;
import lombok.Getter;
import java.util.List;
@Getter
@Builder
public class ListTwitchStreamerResponseModel {
private List<TwitchStreamerDisplayModel> streamers;
}

View File

@@ -0,0 +1,42 @@
package dev.sheldan.abstracto.twitch.model.template;
import com.github.twitch4j.helix.domain.Stream;
import dev.sheldan.abstracto.twitch.model.database.StreamSessionSection;
import lombok.Builder;
import lombok.Getter;
import java.time.Instant;
@Builder
@Getter
public class StreamSectionDisplay {
private String gameName;
private String gameId;
private String title;
private Integer viewerCount;
private Instant startedAt;
private String thumbnailURL;
public static StreamSectionDisplay fromStream(Stream stream) {
return StreamSectionDisplay
.builder()
.startedAt(stream.getStartedAtInstant())
.gameName(stream.getGameName())
.thumbnailURL(stream.getThumbnailUrl(1280, 720))
.viewerCount(stream.getViewerCount())
.title(stream.getTitle())
.gameId(stream.getGameId())
.build();
}
public static StreamSectionDisplay fromSection(StreamSessionSection section) {
return StreamSectionDisplay
.builder()
.startedAt(section.getCreated())
.gameName(section.getGameName())
.viewerCount(section.getViewerCount())
.title(section.getTitle())
.gameId(section.getGameId())
.build();
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.twitch.model.template;
import dev.sheldan.abstracto.core.models.template.display.ChannelDisplay;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class TwitchStreamerDisplayModel {
private String name;
private ChannelDisplay targetChannel;
private Boolean deleteNotifications;
private Boolean showNotifications;
private String streamerURL;
}

View File

@@ -0,0 +1,9 @@
package dev.sheldan.abstracto.twitch.service;
import com.github.twitch4j.helix.domain.Stream;
import dev.sheldan.abstracto.twitch.model.database.StreamSession;
import dev.sheldan.abstracto.twitch.model.database.StreamSessionSection;
public interface StreamSessionSectionService {
StreamSessionSection createSectionFromStream(StreamSession session, Stream stream);
}

View File

@@ -0,0 +1,23 @@
package dev.sheldan.abstracto.twitch.service;
import com.github.twitch4j.helix.domain.Stream;
import com.github.twitch4j.helix.domain.User;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
import dev.sheldan.abstracto.twitch.model.database.Streamer;
import dev.sheldan.abstracto.twitch.model.template.ListTwitchStreamerResponseModel;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
public interface StreamerService {
void createStreamer(String name, GuildMessageChannel targetChannel, Member creator, Member streamerMember);
void removeStreamer(String name, Guild guild);
CompletableFutureList<Message> notifyAboutOnlineStream(Stream stream, Streamer streamer, User streamerUser);
void changeStreamerNotificationToChannel(Streamer streamer, Long channelId);
void disableNotificationsForStreamer(Streamer streamer, Boolean newState);
void changeStreamerMemberToUserId(Streamer streamer, Long userId);
void changeTemplateKeyTo(Streamer streamer, String templateKey);
ListTwitchStreamerResponseModel getStreamersFromServer(Guild guild);
void checkAndNotifyAboutOnlineStreamers();
}

View File

@@ -0,0 +1,18 @@
package dev.sheldan.abstracto.twitch.service;
import com.github.twitch4j.helix.domain.Stream;
import com.github.twitch4j.helix.domain.User;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public interface TwitchService {
User getStreamerByName(String name);
Optional<User> getStreamerByNameOptional(String name);
User getStreamerById(String userId);
List<Stream> getStreamsByUserIds(List<String> userIds);
Optional<Stream> getStreamOfUser(String userId);
Map<String, Stream> getStreamsByUserIdsMapped(List<String> userIds);
void refreshToken();
}

View File

@@ -0,0 +1,12 @@
package dev.sheldan.abstracto.twitch.service.management;
import com.github.twitch4j.helix.domain.Stream;
import dev.sheldan.abstracto.twitch.model.database.StreamSession;
import dev.sheldan.abstracto.twitch.model.database.Streamer;
public interface StreamSessionManagementService {
StreamSession startSession(Streamer streamer, Long messageId, Long channelId, Stream stream);
void deleteSessionsOfStreamer(Streamer streamer);
void deleteSession(StreamSession session);
void deleteSession(Streamer streamer, Long messageId);
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.twitch.service.management;
import dev.sheldan.abstracto.twitch.model.database.StreamSession;
import dev.sheldan.abstracto.twitch.model.database.StreamSessionSection;
import dev.sheldan.abstracto.twitch.model.database.Streamer;
import java.time.Instant;
public interface StreamSessionSectionManagementService {
StreamSessionSection addSection(StreamSession session, String gameId, String gameName, Instant startTime, String title, Integer viewerCount);
void deleteSectionsOfSession(StreamSession session);
void deleteSectionsOfStreamer(Streamer streamer);
}

View File

@@ -0,0 +1,23 @@
package dev.sheldan.abstracto.twitch.service.management;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.twitch.model.database.Streamer;
import java.util.List;
import java.util.Optional;
public interface StreamerManagementService {
Streamer createStreamer(String id, String name, AChannel targetChannel, AUserInAServer creator, AUserInAServer member, Boolean isOnline);
void removeStreamer(String id);
Optional<Streamer> getStreamerById(Long id);
void removeStreamer(Streamer streamer);
void saveStreamer(Streamer streamer);
Streamer getStreamerInServerById(String id, Long serverId);
List<Streamer> getStreamerInServers(String id);
boolean streamerExistsInServerByID(String id, AServer server);
boolean streamerExistsInServerByName(String name, AServer server);
Optional<Streamer> getStreamerInServerByName(String name, AServer server);
List<Streamer> getStreamersForServer(AServer server);
}