From 916e73eebdebcad52fe6199f4d3b1ecbb1410e48 Mon Sep 17 00:00:00 2001 From: Nekojimi Date: Mon, 20 Jun 2022 14:38:10 +0100 Subject: [PATCH] Add playlist playback support, loading & saving. --- src/main/java/moe/nekojimi/chords/Main.java | 61 +++++++++++++++-- .../java/moe/nekojimi/chords/Playlist.java | 67 +++++++++++++++++-- .../moe/nekojimi/chords/QueueManager.java | 18 ----- src/main/java/moe/nekojimi/chords/Song.java | 1 + .../java/moe/nekojimi/chords/TrackPlayer.java | 2 +- 5 files changed, 118 insertions(+), 31 deletions(-) diff --git a/src/main/java/moe/nekojimi/chords/Main.java b/src/main/java/moe/nekojimi/chords/Main.java index e281c2f..5e9e33d 100644 --- a/src/main/java/moe/nekojimi/chords/Main.java +++ b/src/main/java/moe/nekojimi/chords/Main.java @@ -5,22 +5,27 @@ */ package moe.nekojimi.chords; +import com.amihaiemil.eoyaml.Yaml; +import com.amihaiemil.eoyaml.YamlMapping; import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.Files; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.security.auth.login.LoginException; import moe.nekojimi.chords.commands.*; -import moe.nekojimi.musicsearcher.Result; import moe.nekojimi.musicsearcher.providers.MetaSearcher; import moe.nekojimi.musicsearcher.providers.Searcher; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; -import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; @@ -34,9 +39,12 @@ import net.dv8tion.jda.api.utils.cache.CacheFlag; * * @author jimj316 */ -public class Main extends ListenerAdapter +public final class Main extends ListenerAdapter { + private final File dataDirectory; + private final File playlistsDirectory; + private MusicHandler musicHandler; private final Downloader downloader; private final Searcher searcher; @@ -51,10 +59,12 @@ public class Main extends ListenerAdapter private int trackNumber = 1; + private final Map playlists = new HashMap<>(); + /** * @param args the command line arguments */ - public static void main(String[] args) throws LoginException + public static void main(String[] args) throws LoginException, IOException { // We only need 2 gateway intents enabled for this example: EnumSet intents = EnumSet.of( @@ -125,11 +135,19 @@ public class Main extends ListenerAdapter }; - public Main() + public Main() throws IOException { log("INFO", "Starting up..."); + + // init dirs + dataDirectory = new File(System.getProperty("user.dir")); + playlistsDirectory = initDirectory(dataDirectory, "playlists"); + + // init downloader downloader = new Downloader(); downloader.setMessageHandler(downloaderMessageHandler); + + // init searcher searcher = MetaSearcher.loadYAML(new File("searchproviders.yml")); // init queue manager @@ -147,6 +165,9 @@ public class Main extends ListenerAdapter helpCommand = new HelpCommand(this); addCommand(helpCommand); + // load playlists + loadPlaylists(); + log("INFO", "Started OK!"); } @@ -329,6 +350,35 @@ public class Main extends ListenerAdapter System.out.println(type + " " + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME) + "\t" + message); } + public File initDirectory(File parent, String name) throws IOException + { + File ret = new File(parent, name); + if (!ret.exists()) + Files.createDirectories(ret.toPath()); + if (!ret.canRead()) + throw new RuntimeException("Cannot read directory " + ret.getAbsolutePath() + "!"); + if (!ret.canWrite()) + throw new RuntimeException("Cannot write to directory " + ret.getAbsolutePath() + "!"); + return ret; + } + + private void loadPlaylists() + { + File[] files = playlistsDirectory.listFiles((File file, String name) -> name.endsWith(".yaml")); + for (File file : files) + { + try + { + YamlMapping map = Yaml.createYamlInput(file).readYamlMapping(); + Playlist playlist = Playlist.fromYaml(map); + playlists.put(playlist.getName(), playlist); + } catch (IOException ex) + { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + public MusicHandler getMusicHandler() { return musicHandler; @@ -363,4 +413,5 @@ public class Main extends ListenerAdapter return trackNumber; } + } diff --git a/src/main/java/moe/nekojimi/chords/Playlist.java b/src/main/java/moe/nekojimi/chords/Playlist.java index 2ba65d0..2863d35 100644 --- a/src/main/java/moe/nekojimi/chords/Playlist.java +++ b/src/main/java/moe/nekojimi/chords/Playlist.java @@ -16,19 +16,28 @@ */ package moe.nekojimi.chords; +import com.amihaiemil.eoyaml.Yaml; import com.amihaiemil.eoyaml.YamlMapping; -import java.util.ArrayList; -import java.util.List; +import com.amihaiemil.eoyaml.YamlSequence; +import com.amihaiemil.eoyaml.YamlSequenceBuilder; +import java.net.MalformedURLException; +import java.util.*; +import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; /** * * @author jimj316 */ -public class Playlist +public class Playlist implements Consumer { + private static final int SHUFFLE_DONT_REPEAT_LAST = 3; + private final String name; private final List songs = new ArrayList<>(); + private final LinkedList playHistory = new LinkedList<>(); public Playlist(String name) { @@ -37,12 +46,31 @@ public class Playlist public YamlMapping toYaml() { - throw new UnsupportedOperationException("Not supported yet."); + YamlSequenceBuilder songList = Yaml.createYamlSequenceBuilder(); + for (Song song : songs) + songList = songList.add(song.toYaml()); + + return Yaml.createYamlMappingBuilder() + .add("name", name) + .add("songs", songList.build()) + .build(); } public static Playlist fromYaml(YamlMapping yaml) { - throw new UnsupportedOperationException("Not supported yet."); + Playlist ret = new Playlist(yaml.string("name")); + YamlSequence songList = yaml.value("songs").asSequence(); + for (int i = 0; i < songList.size(); i++) + { + try + { + ret.addSong(Song.fromYaml(songList.yamlMapping(i))); + } catch (MalformedURLException ex) + { + Logger.getLogger(Playlist.class.getName()).log(Level.SEVERE, null, ex); + } + } + return ret; } public void addSong(Song song) @@ -61,9 +89,34 @@ public class Playlist return songs; } - Song getNextSong() + public Song getNextSong() + { + Song ret; + + // copy the song list + List toShuffle = new LinkedList<>(songs); + + // remove play history from candidates, latest first, unless we'd have less than 2 options + for (int i = playHistory.size() - 1; i >= 0; i--) + { + if (toShuffle.size() <= 2) + break; + toShuffle.remove(playHistory.get(i)); + } + + Collections.shuffle(toShuffle); + ret = toShuffle.get(0); + + playHistory.add(ret); + if (playHistory.size() > SHUFFLE_DONT_REPEAT_LAST) + playHistory.remove(); + return ret; + } + + @Override + public void accept(Song t) { - throw new UnsupportedOperationException("Not supported yet."); + addSong(t); } } diff --git a/src/main/java/moe/nekojimi/chords/QueueManager.java b/src/main/java/moe/nekojimi/chords/QueueManager.java index 14e46e2..2200392 100644 --- a/src/main/java/moe/nekojimi/chords/QueueManager.java +++ b/src/main/java/moe/nekojimi/chords/QueueManager.java @@ -26,8 +26,6 @@ import java.util.function.Consumer; */ public class QueueManager implements Consumer { - - private Mode mode; private final Queue jukeboxQueue; private Playlist playlist; private MusicHandler handler; @@ -118,24 +116,8 @@ public class QueueManager implements Consumer this.playlist = playlist; } - public Mode getMode() - { - return mode; - } - - public void setMode(Mode mode) - { - this.mode = mode; - } - public boolean restartSong() { throw new UnsupportedOperationException("Not supported yet."); } - - public enum Mode - { - JUKEBOX, - PLAYLIST; - } } diff --git a/src/main/java/moe/nekojimi/chords/Song.java b/src/main/java/moe/nekojimi/chords/Song.java index 45c44ea..3b2a0e6 100644 --- a/src/main/java/moe/nekojimi/chords/Song.java +++ b/src/main/java/moe/nekojimi/chords/Song.java @@ -60,6 +60,7 @@ public class Song { Song song = new Song(new URL(map.string("url"))); song.setArtist(map.string("artist")); + song.setTitle(map.string("title")); song.setLocation(new File(map.string("location"))); song.setNumber(map.integer("num")); song.setKept(Boolean.parseBoolean(map.string("kept"))); diff --git a/src/main/java/moe/nekojimi/chords/TrackPlayer.java b/src/main/java/moe/nekojimi/chords/TrackPlayer.java index 1162136..a77b445 100644 --- a/src/main/java/moe/nekojimi/chords/TrackPlayer.java +++ b/src/main/java/moe/nekojimi/chords/TrackPlayer.java @@ -132,7 +132,7 @@ public class TrackPlayer implements Closeable public void close() throws IOException { - input.close(); + input.close(); //q }