Rearranged where the uuid was stored.

#5 Added event handlers back
This commit is contained in:
Isaac Parenteau
2019-10-06 23:38:15 -05:00
parent f9b45581e2
commit fe4c25cc4c
10 changed files with 97 additions and 204 deletions

View File

@ -1,30 +1,3 @@
/**
*
* Project: Eight Track, File: DiscordGuild.java
*
* Copyright 2019-2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates

View File

@ -1,30 +1,3 @@
/**
*
* Project: Eight Track, File: GuildPlaylist.java
*
* Copyright 2019-2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates

View File

@ -1,30 +1,3 @@
/**
*
* Project: Eight Track, File: GuildPlaylistSong.java
*
* Copyright 2019-2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates

View File

@ -1,30 +1,3 @@
/**
*
* Project: Eight Track, File: GuildSong.java
*
* Copyright 2019-2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
@ -67,6 +40,9 @@ public class GuildSong implements Serializable {
@Basic(optional = false)
@Column(name = "id")
private Long id;
@Basic(optional = false)
@Column(name = "uuid")
private String uuid;
@Column(name = "date_added")
@Temporal(TemporalType.TIMESTAMP)
private Date dateAdded;
@ -86,6 +62,11 @@ public class GuildSong implements Serializable {
this.id = id;
}
public GuildSong(Long id, String uuid) {
this.id = id;
this.uuid = uuid;
}
public Long getId() {
return id;
}
@ -94,6 +75,14 @@ public class GuildSong implements Serializable {
this.id = id;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public Date getDateAdded() {
return dateAdded;
}

View File

@ -1,30 +1,3 @@
/**
*
* Project: Eight Track, File: Song.java
*
* Copyright 2019-2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
@ -67,9 +40,6 @@ public class Song implements Serializable {
@Column(name = "id")
private Long id;
@Basic(optional = false)
@Column(name = "uuid")
private String uuid;
@Basic(optional = false)
@Column(name = "title")
private String title;
@Column(name = "artist")
@ -105,9 +75,8 @@ public class Song implements Serializable {
this.id = id;
}
public Song(Long id, String uuid, String title, String filePath, String fileHash) {
public Song(Long id, String title, String filePath, String fileHash) {
this.id = id;
this.uuid = uuid;
this.title = title;
this.filePath = filePath;
this.fileHash = fileHash;
@ -121,14 +90,6 @@ public class Song implements Serializable {
this.id = id;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getTitle() {
return title;
}

View File

@ -38,6 +38,8 @@ import net.locusworks.discord.eighttrack.database.entities.Song;
public interface GuildSongRepository extends CrudRepository<GuildSong, Long> {
GuildSong findByUuid(String uuid);
GuildSong findByGuildAndSong(DiscordGuild guild, Song song);
@Query("SELECT gs FROM GuildSong gs WHERE gs.guild.guildId = ?1 AND gs.song.fileHash = ?2")

View File

@ -32,8 +32,6 @@ import net.locusworks.discord.eighttrack.database.entities.Song;
public interface SongRepository extends CrudRepository<Song, Long> {
Song findByUuid(String uuid);
Song findByFileHash(String fileHash);
}

View File

@ -110,7 +110,8 @@ public class DiscordEventHandler extends ListenerAdapter {
private void onGuildMessageReceivedHelper(GuildMessageReceivedEvent event) throws IOException {
if (!musicService.containsKey(event.getGuild().getIdLong())) {
musicService.put(event.getGuild().getIdLong(), new GuildMusicHandler(musicDir, uploadHandler, guildSongRepoService));
musicService.put(event.getGuild().getIdLong(),
new GuildMusicHandler(musicDir, event.getGuild().getIdLong(), uploadHandler, guildSongRepoService));
}
GuildMusicHandler gmh = musicService.get(event.getGuild().getIdLong());
gmh.accept((id) -> musicService.remove(id));
@ -121,10 +122,6 @@ public class DiscordEventHandler extends ListenerAdapter {
case "-upload":
gmh.upload(event);
return;
}
/*
switch (command) {
case "-play":
gmh.isPlaying(true);
gmh.play(event);
@ -149,6 +146,5 @@ public class DiscordEventHandler extends ListenerAdapter {
default:
return;
}
*/
}
}

View File

@ -38,7 +38,6 @@ import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
@ -72,58 +71,59 @@ public class GuildMusicHandler {
private AudioPlayer player;
private AtomicBoolean playing;
private Long voiceChannelId;
private OffsetDateTime lastPlayed;
private Consumer<Long> callback;
private Mp3UploadHandler uploadHandler;
private GuildSongRepoService guildSongRepoService;
public GuildMusicHandler(Path musicDir, Mp3UploadHandler uploadHandler, GuildSongRepoService guildSongRepoService) throws IOException {
private long guildId;
public GuildMusicHandler(Path musicDir, long guildId, Mp3UploadHandler uploadHandler, GuildSongRepoService guildSongRepoService) throws IOException {
this.logger = ApplicationLoggerFactory.getLogger(GuildMusicHandler.class);
this.playing = new AtomicBoolean(false);
this.musicDir = musicDir;
this.lastPlayed = OffsetDateTime.now();
this.uploadHandler = uploadHandler;
this.guildSongRepoService = guildSongRepoService;
this.guildId = guildId;
this.apm = new DefaultAudioPlayerManager();
AudioSourceManagers.registerLocalSource(apm);
this.player = apm.createPlayer();
this.ts = new TrackScheduler();
player.addListener(ts);
indexFiles();
}
public OffsetDateTime getLastPlayed() {
return lastPlayed;
}
public void accept(Consumer<Long> callback) {
this.callback = callback;
}
public void isPlaying(boolean playing) {
this.playing.set(playing);
}
public void indexFiles() throws IOException {
List<Path> songs = Files.walk(musicDir)
.filter(p-> p.getFileName().toString().endsWith(".mp3"))
.collect(Collectors.toList());
List<GuildSong> songs = guildSongRepoService.getGuildSongRepo().findByGuild(guildId);
logger.info("Adding %d songs from directory %s", songs.size(), musicDir);
for (Path song : songs) {
logger.debug("Loading song: %s", song);
for (GuildSong song : songs) {
logger.debug("Loading song: %s", song.getSong().getFilePath());
try {
apm.loadItem(song.toAbsolutePath().toString(), ts);
apm.loadItem(song.getSong().getFilePath(), ts);
} catch (IllegalStateException ex) {
logger.warn("Unable to load song :%s -> %s", song.toAbsolutePath().toString(), ex.getMessage());
logger.warn("Unable to load song :%s -> %s", song.getSong().getFilePath(), ex.getMessage());
}
}
}
public void index(GuildMessageReceivedEvent event) {
event.getChannel().sendMessage(String.format("<@%s>, Please wait as i reindex the music files", event.getAuthor().getId())).queue();
try {
@ -156,7 +156,7 @@ public class GuildMusicHandler {
}
public void next(GuildMessageReceivedEvent event) {
GuildChannel gc = event.getGuild().getGuildChannelById(ChannelType.VOICE, voiceChannelId);
if (gc != null && gc.getMembers().size() == 1) {
event.getChannel().sendMessage("Going silent since no one is currently listening to the channel").queue();
@ -164,7 +164,7 @@ public class GuildMusicHandler {
if (callback != null) callback.accept(event.getGuild().getIdLong());
return;
}
playing.set(false);
stop(event);
play(event);
@ -181,13 +181,13 @@ public class GuildMusicHandler {
event.getChannel().sendMessage(String.format("<@%s> you are not in a voice channel to play music", event.getMember().getId())).queue();
return;
}
if (!event.getGuild().getSelfMember().hasPermission(vc, Permission.VOICE_CONNECT, Permission.VOICE_SPEAK)) {
event.getChannel().sendMessage(String.format("<@%s>, I cannot play my music in channel %s as I dont have permission to",
event.getMember().getId(), vc.getName())).queue();
return;
}
voiceChannelId = vc.getIdLong();
AudioManager manager = event.getGuild().getAudioManager();
@ -197,9 +197,9 @@ public class GuildMusicHandler {
if (ts.hasTracks()) {
lastPlayed = OffsetDateTime.now();
AudioTrack track = ts.getNextTrack();
MessageEmbed embed = new EmbedBuilder()
.setAuthor(event.getMember().getEffectiveName(), null, event.getAuthor().getAvatarUrl())
.setTitle("Now Playing:")
@ -218,39 +218,67 @@ public class GuildMusicHandler {
event.getChannel().sendMessage(String.format("Sorry <@%s> i can't do that. *psst: you have to have manage server, or administrator role*", event.getMember().getIdLong())).queue();
return;
}
for(Attachment attachment : event.getMessage().getAttachments()) {
attachment.retrieveInputStream().thenAccept((in) -> {
Mp3UploadResults res = null;
MessageEmbed embed = null;
try {
MessageEmbed embed = null;
res = uploadHandler.parse(in);
if (res.validFile()) {
embed =persistSong(res, event, attachment.getFileName());
embed = persistSong(res, event, attachment.getFileName());
} else {
embed = wrongFile(event, attachment.getFileName());
}
event.getChannel().sendMessage(embed).queue();
} catch (Exception ex) {
logger.error("Unable to get file information: %s", ex.getMessage());
logger.error(ex);
embed = error(event, ex, attachment.getFileName());
} finally {
event.getMessage().delete().queue();
if (res != null) res.clear();
if (embed != null) event.getChannel().sendMessage(embed).queue();
}
}).exceptionally((err) ->{
}).exceptionally((err) -> {
event.getMessage().delete().queue();
MessageEmbed embed = error(event, err, attachment.getFileName());
if (embed != null) event.getChannel().sendMessage(embed).queue();
return null;
});
}
}
private MessageEmbed error(GuildMessageReceivedEvent event, Throwable ex, String fileName) {
return new EmbedBuilder()
.setTitle("Unable to upload file: " + fileName)
.setDescription("There was an error uploading your file: " + ex.getMessage() + ". Please contact admin")
.setColor(Color.RED)
.setTimestamp(OffsetDateTime.now())
.setFooter(event.getGuild().getSelfMember().getEffectiveName(), event.getGuild().getSelfMember().getUser().getAvatarUrl())
.build();
}
private MessageEmbed wrongFile(GuildMessageReceivedEvent event, String fileName) {
return new EmbedBuilder()
.setTitle("Invalid File: " + fileName)
.setDescription("Only music type files are allowed to be uploaded")
.setColor(Color.RED)
.setTimestamp(OffsetDateTime.now())
.setFooter(event.getGuild().getSelfMember().getEffectiveName(), event.getGuild().getSelfMember().getUser().getAvatarUrl())
.build();
}
private MessageEmbed persistSong(Mp3UploadResults result, GuildMessageReceivedEvent event, String fileName) throws Exception {
DiscordGuild guild = guildSongRepoService.getGuildRepo().findByGuildId(event.getGuild().getIdLong());
if(guild == null) {
throw new IOException("Unable to find guild in database. Please contact administrator");
}
Path output = musicDir;
if (result.getArtist() != null) {
output = output.resolve(result.getArtist());
@ -259,13 +287,13 @@ public class GuildMusicHandler {
}
}
output = output.resolve(fileName);
if (!Files.exists(output.toAbsolutePath().getParent())) {
Files.createDirectories(output.toAbsolutePath().getParent());
}
Files.write(output, result.getData());
Song song = new Song();
song.setAlbum(result.getAlbum());
song.setArtist(result.getArtist());
@ -279,19 +307,19 @@ public class GuildMusicHandler {
song.setReleaseYear(result.getReleaseDate());
song.setTitle(result.getTitle());
song.setTrackNumber(result.getTrackNumber());
song.setUuid(UUID.nameUUIDFromBytes(result.getData()).toString());
guildSongRepoService.getSongRepo().save(song);
GuildSong gs = new GuildSong();
gs.setDateAdded(new Date());
gs.setGuild(guild);
gs.setSong(song);
gs.setUuid(UUID.randomUUID().toString());
guildSongRepoService.getGuildSongRepo().save(gs);
String out = String.format("```%s%n%-10s: %s```", result, "UUID", song.getUuid());
String out = String.format("```%s%n%-10s: %s```", result, "UUID", gs.getUuid());
MessageEmbed embed = new EmbedBuilder()
.setColor(Color.GREEN)
.setTitle("Upload Results for " + fileName)
@ -299,8 +327,8 @@ public class GuildMusicHandler {
.setTimestamp(OffsetDateTime.now())
.setFooter(event.getGuild().getSelfMember().getEffectiveName(), event.getGuild().getSelfMember().getUser().getAvatarUrl())
.build();
return embed;
}
}

View File

@ -9,7 +9,6 @@ CREATE TABLE eighttrack.discord_guild (
CREATE TABLE eighttrack.song (
id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
uuid varchar(100) NOT NULL COMMENT 'Unique Identifier',
title varchar(500) NOT NULL COMMENT 'title of song',
artist varchar(500) DEFAULT NULL COMMENT 'songs artist',
album varchar(500) DEFAULT NULL COMMENT 'songs album',
@ -22,17 +21,18 @@ CREATE TABLE eighttrack.song (
file_hash varchar(40) NOT NULL COMMENT 'sha1 hash of file',
date_added timestamp NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY song_uuid_UN (uuid),
UNIQUE KEY song_file_hash_UN (file_hash)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE eighttrack.guild_song (
id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'primary key',
uuid varchar(100) NOT NULL COMMENT 'Unique Identifier',
guild bigint(20) NOT NULL COMMENT 'guild the song belongs to',
song bigint(20) NOT NULL COMMENT 'the song',
date_added timestamp NULL DEFAULT NULL COMMENT 'date added',
PRIMARY KEY (id),
UNIQUE KEY guild_song_UN (guild,song),
UNIQUE KEY guild_song_UN2 (uuid),
KEY guild_song_FK_1 (song),
CONSTRAINT guild_song_FK FOREIGN KEY (guild) REFERENCES eighttrack.discord_guild (id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT guild_song_FK_1 FOREIGN KEY (song) REFERENCES eighttrack.song (id) ON DELETE CASCADE ON UPDATE CASCADE