Adds the ability to add internet songs to the library.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package edu.regis.universeplayer.data;
|
||||
|
||||
import edu.regis.universeplayer.player.Interface;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
|
||||
/**
|
||||
* Manages the application song database
|
||||
*/
|
||||
public class DatabaseManager
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(DatabaseManager.class);
|
||||
private static Connection db;
|
||||
|
||||
public static synchronized Connection getDb()
|
||||
{
|
||||
SQLWarning warning;
|
||||
try
|
||||
{
|
||||
if (db == null || db.isClosed())
|
||||
{
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
db = DriverManager.getConnection("jdbc:sqlite:" + new File(Interface.getDataDir().getAbsolutePath(), "universalmusic.db").getAbsolutePath());
|
||||
}
|
||||
warning = db.getWarnings();
|
||||
while (warning != null)
|
||||
{
|
||||
logger.warn("SQL Warning: ", warning);
|
||||
warning = warning.getNextWarning();
|
||||
}
|
||||
db.clearWarnings();
|
||||
}
|
||||
catch (SQLException | ClassNotFoundException e)
|
||||
{
|
||||
logger.error("Could not store caching DIR.");
|
||||
}
|
||||
return db;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package edu.regis.universeplayer.data;
|
||||
|
||||
import edu.regis.universeplayer.browser.InternetSong;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class InternetSongProvider implements SongProvider<InternetSong>
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(InternetSongProvider.class);
|
||||
private static final ExecutorService service = Executors.newSingleThreadExecutor();
|
||||
private static InternetSongProvider INSTANCE;
|
||||
|
||||
public static InternetSongProvider getInstance()
|
||||
{
|
||||
if (INSTANCE == null)
|
||||
{
|
||||
INSTANCE = new InternetSongProvider();
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private final HashMap<URL, InternetSong> songs = new HashMap<>();
|
||||
private final HashMap<String, Album> albums = new HashMap<>();
|
||||
/**
|
||||
* A cache of all song artists.
|
||||
*/
|
||||
private final HashSet<String> artists = new HashSet<>();
|
||||
/**
|
||||
* A cache of all album genres.
|
||||
*/
|
||||
private final HashSet<String> genres = new HashSet<>();
|
||||
/**
|
||||
* A cache of all album artists.
|
||||
*/
|
||||
private final HashSet<String> albumArtists = new HashSet<>();
|
||||
/**
|
||||
* A cache of all album release years.
|
||||
*/
|
||||
private final HashSet<Integer> years = new HashSet<>();
|
||||
|
||||
private int updatedSongs;
|
||||
private int totalUpdate;
|
||||
private final LinkedList<UpdateListener> listeners = new LinkedList<>();
|
||||
|
||||
private InternetSongProvider()
|
||||
{
|
||||
this.getSongCache();
|
||||
}
|
||||
|
||||
private void getSongCache()
|
||||
{
|
||||
service.submit(new SongQuery());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all albums within the collection.
|
||||
*
|
||||
* @return A list of albums.
|
||||
*/
|
||||
@Override
|
||||
public Collection<Album> getAlbums()
|
||||
{
|
||||
return this.albums.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all songs within the collection.
|
||||
*
|
||||
* @return A list of songs.
|
||||
*/
|
||||
@Override
|
||||
public Collection<InternetSong> getSongs()
|
||||
{
|
||||
synchronized (this.songs)
|
||||
{
|
||||
return Collections.unmodifiableCollection(this.songs.values());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a list of all artists.
|
||||
*
|
||||
* @return All artists.
|
||||
*/
|
||||
@Override
|
||||
public Collection<String> getArtists()
|
||||
{
|
||||
return this.artists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a list of all album artists.
|
||||
*
|
||||
* @return All album artists.
|
||||
*/
|
||||
@Override
|
||||
public Collection<String> getAlbumArtists()
|
||||
{
|
||||
return this.albumArtists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a list of all genres.
|
||||
*
|
||||
* @return All genres.
|
||||
*/
|
||||
@Override
|
||||
public Collection<String> getGenres()
|
||||
{
|
||||
return this.genres;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a list of all years that have albums.
|
||||
*
|
||||
* @return All years.
|
||||
*/
|
||||
@Override
|
||||
public Collection<Integer> getYears()
|
||||
{
|
||||
return this.years;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all songs from an album.
|
||||
*
|
||||
* @param album - The album to obtain
|
||||
* @return All songs from the requested album, or null if that album is not in the database.
|
||||
*/
|
||||
@Override
|
||||
public Collection<InternetSong> getSongsFromAlbum(Album album)
|
||||
{
|
||||
synchronized (this.songs)
|
||||
{
|
||||
return this.songs.values().stream().filter(song -> song.album.equals(album)).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all songs written by a given artist.
|
||||
*
|
||||
* @param artist - The artist to search for
|
||||
* @return A list of all songs from the specified artist, or null if that artist is not in the
|
||||
* database.
|
||||
*/
|
||||
@Override
|
||||
public Collection<InternetSong> getSongsFromArtist(String artist)
|
||||
{
|
||||
synchronized (this.songs)
|
||||
{
|
||||
return this.songs.values().stream().filter(song -> Arrays.asList(song.artists).contains(artist)).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an album by a specific name.
|
||||
*
|
||||
* @param name - The name to search for.
|
||||
* @return - The first album that matches the given name, or null if that album name is not in
|
||||
* the database.
|
||||
*/
|
||||
@Override
|
||||
public Album getAlbumByName(String name)
|
||||
{
|
||||
synchronized (this.albums)
|
||||
{
|
||||
return this.albums.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all albums that were written by a certain artist.
|
||||
*
|
||||
* @param artist - The artist to search for.
|
||||
* @return - The collection on matching albums.
|
||||
*/
|
||||
@Override
|
||||
public Collection<Album> getAlbumsFromArtist(String artist)
|
||||
{
|
||||
synchronized (this.albums)
|
||||
{
|
||||
return this.albums.values().stream().filter(album -> Arrays.asList(album.artists).contains(artist)).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all albums that match a certain genre
|
||||
*
|
||||
* @param genre - The genre to search for.
|
||||
* @return - The collection on matching albums.
|
||||
*/
|
||||
@Override
|
||||
public Collection<Album> getAlbumsFromGenre(String genre)
|
||||
{
|
||||
synchronized (this.albums)
|
||||
{
|
||||
return this.albums.values().stream().filter(album -> Arrays.asList(album.genres).contains(genre)).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all albums that were released a certain year.
|
||||
*
|
||||
* @param year - The year to search for.
|
||||
* @return - The collection on matching albums.
|
||||
*/
|
||||
@Override
|
||||
public Collection<Album> getAlbumsFromYear(int year)
|
||||
{
|
||||
synchronized (this.albums)
|
||||
{
|
||||
return this.albums.values().stream().filter(album -> album.year == year).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateProgress()
|
||||
{
|
||||
return this.updatedSongs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalUpdateSongs()
|
||||
{
|
||||
return this.totalUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUpdateText()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUpdateListener(UpdateListener listener)
|
||||
{
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdateListener(UpdateListener listener)
|
||||
{
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
|
||||
protected void triggerUpdateListeners()
|
||||
{
|
||||
this.listeners.forEach(listener -> listener.onUpdate(this.getUpdateProgress(), this.getTotalUpdateSongs(), this.getUpdateText()));
|
||||
}
|
||||
|
||||
public Future<InternetSong> addSong(URL url, String title, String albumName, String artists, String genres)
|
||||
{
|
||||
return service.submit(() -> {
|
||||
Album album = albums.get(albumName);
|
||||
Statement state = DatabaseManager.getDb().createStatement();
|
||||
if (album == null)
|
||||
{
|
||||
album = new Album();
|
||||
album.name = albumName;
|
||||
albums.put(albumName, album);
|
||||
synchronized (DatabaseManager.getDb())
|
||||
{
|
||||
state.executeUpdate("INSERT INTO internet_albums (album) VALUES ('" + albumName + "');");
|
||||
}
|
||||
}
|
||||
album.artists = Arrays.stream(artists.split(";")).map(String::trim).toArray(String[]::new);
|
||||
album.genres = Arrays.stream(genres.split(";")).map(String::trim).toArray(String[]::new);
|
||||
synchronized (DatabaseManager.getDb())
|
||||
{
|
||||
state.executeUpdate("UPDATE internet_albums SET artists='" + String.join(";", album.artists) + "' WHERE album='" + albumName + "';");
|
||||
state.executeUpdate("UPDATE internet_albums SET genres='" + String.join(";", album.genres) + "' WHERE album='" + albumName + "';");
|
||||
}
|
||||
InternetSong song = new InternetSong();
|
||||
song.location = url;
|
||||
song.title = title;
|
||||
song.album = album;
|
||||
song.artists = album.artists.clone();
|
||||
|
||||
// TODO - Evaluate the song
|
||||
|
||||
songs.put(url, song);
|
||||
|
||||
StringBuilder sql = new StringBuilder("INSERT INTO internet_songs ");
|
||||
StringBuilder columns = new StringBuilder("(");
|
||||
StringBuilder values = new StringBuilder("(");
|
||||
|
||||
columns.append("url,");
|
||||
values.append('\'').append(url.toString().replaceAll("'", "''")).append("',");
|
||||
if (title != null && !title.isEmpty())
|
||||
{
|
||||
columns.append("title,");
|
||||
values.append('\'').append(title.replaceAll("'", "''")).append("',");
|
||||
}
|
||||
if (song.artists != null)
|
||||
{
|
||||
columns.append("artists,");
|
||||
values.append('\'').append(String.join(";", song.artists)).append("',");
|
||||
}
|
||||
columns.append("album");
|
||||
values.append('\'').append(albumName).append("'");
|
||||
|
||||
columns.append(") VALUES ");
|
||||
values.append(");");
|
||||
sql.append(columns);
|
||||
sql.append(values);
|
||||
synchronized (DatabaseManager.getDb())
|
||||
{
|
||||
state.executeUpdate(sql.toString());
|
||||
}
|
||||
this.triggerUpdateListeners();
|
||||
return song;
|
||||
});
|
||||
}
|
||||
|
||||
private class SongQuery implements Runnable
|
||||
{
|
||||
SongQuery()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
Statement state;
|
||||
ResultSet result;
|
||||
Album album;
|
||||
InternetSong song;
|
||||
int numAlbums = 0, numSongs = 0;
|
||||
|
||||
try
|
||||
{
|
||||
logger.debug("Querying database.");
|
||||
/*
|
||||
* Check if the table exists
|
||||
*/
|
||||
synchronized (DatabaseManager.getDb())
|
||||
{
|
||||
/*
|
||||
* Make sure that a "null" album is available
|
||||
*/
|
||||
|
||||
if (albums.get(null) == null)
|
||||
{
|
||||
album = new Album();
|
||||
album.name = "Unknown";
|
||||
albums.put(null, album);
|
||||
}
|
||||
|
||||
if (albums.get("Unknown") == null)
|
||||
{
|
||||
albums.put("Unknown", albums.get(null));
|
||||
}
|
||||
|
||||
state = DatabaseManager.getDb().createStatement();
|
||||
result = state.executeQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='INTERNET_ALBUMS';");
|
||||
if (!result.next())
|
||||
{
|
||||
logger.debug("Creating album table.");
|
||||
/*
|
||||
* Create the table
|
||||
*/
|
||||
state.executeUpdate("CREATE TABLE INTERNET_ALBUMS" +
|
||||
"(ALBUM TEXT PRIMARY KEY NOT NULL," +
|
||||
"ARTISTS TEXT," +
|
||||
"YEAR INTEGER," +
|
||||
"GENRES TEXT," +
|
||||
"TRACKS INTEGER," +
|
||||
"DISCS INTEGER);");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = state.executeQuery("SELECT * FROM INTERNET_ALBUMS;");
|
||||
while (result.next())
|
||||
{
|
||||
album = albums.get(result.getString("album"));
|
||||
if (album == null)
|
||||
{
|
||||
album = new Album();
|
||||
album.name = result.getString("album");
|
||||
albums.put(album.name, album);
|
||||
}
|
||||
album.artists = Optional.ofNullable(result.getString("artists")).map(s -> s.split(";")).orElse(new String[0]);
|
||||
album.year = result.getInt("year");
|
||||
album.genres = Optional.ofNullable(result.getString("genres")).map(s -> s.split(";")).orElse(new String[0]);
|
||||
album.totalTracks = result.getInt("tracks");
|
||||
album.totalDiscs = result.getInt("discs");
|
||||
numAlbums++;
|
||||
}
|
||||
}
|
||||
result = state.executeQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='INTERNET_SONGS';");
|
||||
if (!result.next())
|
||||
{
|
||||
logger.debug("Creating song table.");
|
||||
/*
|
||||
* Create the table
|
||||
*/
|
||||
state.executeUpdate("CREATE TABLE INTERNET_SONGS" +
|
||||
"(URL TEXT PRIMARY KEY NOT NULL," +
|
||||
"TITLE TEXT," +
|
||||
"ARTISTS TEXT," +
|
||||
"TRACK INTEGER," +
|
||||
"DISC INTEGER," +
|
||||
"DURATION BIGINT," +
|
||||
"ALBUM TEXT);");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = state.executeQuery("SELECT * FROM INTERNET_SONGS;");
|
||||
while (result.next())
|
||||
{
|
||||
if (result.getString("url") == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
URL url;
|
||||
try
|
||||
{
|
||||
url = new URL(result.getString("url"));
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
logger.error("Could not parse URL " + result.getString("url"), e);
|
||||
continue;
|
||||
}
|
||||
song = songs.get(url);
|
||||
if (song == null)
|
||||
{
|
||||
song = new InternetSong();
|
||||
song.location = url;
|
||||
songs.put(song.location, song);
|
||||
}
|
||||
song.title = result.getString("title");
|
||||
song.artists = Optional.ofNullable(result.getString("artists")).map(s -> s.split(";")).orElse(new String[0]);
|
||||
song.trackNum = result.getInt("track");
|
||||
song.disc = result.getInt("disc");
|
||||
song.duration = result.getLong("duration");
|
||||
song.album = Optional.ofNullable(result.getString("album")).map(albums::get).orElse(albums.get("Unknown"));
|
||||
numSongs++;
|
||||
}
|
||||
}
|
||||
state.close();
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
logger.error("Could not query SQL database.", e);
|
||||
}
|
||||
logger.debug("Query complete, retrieved {} albums and {} songs", numAlbums, numSongs);
|
||||
updatedSongs = 0;
|
||||
totalUpdate = 0;
|
||||
triggerUpdateListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ public class LocalSongProvider implements SongProvider<LocalSong>
|
||||
private static final HashSet<String> codecs = new HashSet<>();
|
||||
|
||||
private final File source;
|
||||
private Connection db;
|
||||
|
||||
private final HashMap<File, LocalSong> songs = new HashMap<>();
|
||||
private final HashMap<String, Album> albums = new HashMap<>();
|
||||
@@ -152,31 +151,6 @@ public class LocalSongProvider implements SongProvider<LocalSong>
|
||||
return codecs;
|
||||
}
|
||||
|
||||
private Connection getDb()
|
||||
{
|
||||
SQLWarning warning;
|
||||
try
|
||||
{
|
||||
if (this.db == null || this.db.isClosed())
|
||||
{
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
this.db = DriverManager.getConnection("jdbc:sqlite:" + new File(Interface.getDataDir().getAbsolutePath(), "universalmusic.db").getAbsolutePath());
|
||||
}
|
||||
warning = this.db.getWarnings();
|
||||
while (warning != null)
|
||||
{
|
||||
logger.warn("SQL Warning: ", warning);
|
||||
warning = warning.getNextWarning();
|
||||
}
|
||||
this.db.clearWarnings();
|
||||
}
|
||||
catch (SQLException | ClassNotFoundException e)
|
||||
{
|
||||
logger.error("Could not store caching DIR.");
|
||||
}
|
||||
return this.db;
|
||||
}
|
||||
|
||||
public LocalSongProvider(File source)
|
||||
{
|
||||
Connection dbL = null;
|
||||
@@ -185,8 +159,6 @@ public class LocalSongProvider implements SongProvider<LocalSong>
|
||||
{
|
||||
throw new IllegalArgumentException("File source must be existing directory");
|
||||
}
|
||||
|
||||
this.getDb();
|
||||
getSongCache();
|
||||
}
|
||||
|
||||
@@ -434,9 +406,9 @@ public class LocalSongProvider implements SongProvider<LocalSong>
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized (db)
|
||||
synchronized (DatabaseManager.getDb())
|
||||
{
|
||||
state = getDb().createStatement();
|
||||
state = DatabaseManager.getDb().createStatement();
|
||||
result = state.executeQuery("SELECT mod FROM local_songs WHERE file='" + this.file.getAbsolutePath().replaceAll("'", "''") + "';");
|
||||
if (result.next())
|
||||
{
|
||||
@@ -603,7 +575,7 @@ public class LocalSongProvider implements SongProvider<LocalSong>
|
||||
/*
|
||||
* Update album information.
|
||||
*/
|
||||
synchronized (db)
|
||||
synchronized (DatabaseManager.getDb())
|
||||
{
|
||||
/*
|
||||
* This part in particular is prone to thread-safety issues.
|
||||
@@ -829,7 +801,7 @@ public class LocalSongProvider implements SongProvider<LocalSong>
|
||||
/*
|
||||
* Check if the table exists
|
||||
*/
|
||||
synchronized (db)
|
||||
synchronized (DatabaseManager.getDb())
|
||||
{
|
||||
/*
|
||||
* Make sure that a "null" album is available
|
||||
@@ -847,7 +819,7 @@ public class LocalSongProvider implements SongProvider<LocalSong>
|
||||
albums.put("Unknown", albums.get(null));
|
||||
}
|
||||
|
||||
state = getDb().createStatement();
|
||||
state = DatabaseManager.getDb().createStatement();
|
||||
result = state.executeQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='LOCAL_ALBUMS';");
|
||||
if (!result.next())
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ public interface SongProvider<T extends Song>
|
||||
/**
|
||||
* A SongProvider instance designed to
|
||||
*/
|
||||
SongProvider<Song> INSTANCE = new CompiledSongProvider(new LocalSongProvider(new File(System.getProperty("user.home"), "Music")));
|
||||
SongProvider<Song> INSTANCE = new CompiledSongProvider(new LocalSongProvider(new File(System.getProperty("user.home"), "Music")), InternetSongProvider.getInstance());
|
||||
|
||||
/**
|
||||
* Obtains all albums within the collection.
|
||||
|
||||
@@ -71,6 +71,10 @@ public class Collections extends JPanel
|
||||
this.add(new JLabel("\u23AF".repeat(6)));
|
||||
this.add(label = this.createButton("Playlists"));
|
||||
label.setMnemonic('P');
|
||||
this.add(new JLabel("\u23AF".repeat(6)));
|
||||
this.add(label = this.createButton("Add External Song"));
|
||||
label.setMnemonic('E');
|
||||
label.addActionListener(mouseEvent -> this.addNewSong());
|
||||
|
||||
addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@@ -106,6 +110,16 @@ public class Collections extends JPanel
|
||||
});
|
||||
}
|
||||
|
||||
private void addNewSong()
|
||||
{
|
||||
Container parent = this.getParent();
|
||||
while (!(parent instanceof JFrame) && parent != null)
|
||||
{
|
||||
parent = parent.getParent();
|
||||
}
|
||||
new InternetSongDialog((JFrame) parent).setVisible(true);
|
||||
}
|
||||
|
||||
private JButton createButton(String text)
|
||||
{
|
||||
JButton label = new JButton(text);
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2021 William Hubbard. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package edu.regis.universeplayer.player;
|
||||
|
||||
import edu.regis.universeplayer.browser.InternetSong;
|
||||
import edu.regis.universeplayer.data.InternetSongProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* This dialog is used to add songs
|
||||
*/
|
||||
public class InternetSongDialog extends JDialog
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(InternetSongDialog.class);
|
||||
|
||||
private final JTextField urlBox;
|
||||
private final JTextField titleBox;
|
||||
private final JTextField albumBox;
|
||||
private final JTextField artistBox;
|
||||
private final JTextField genreBox;
|
||||
|
||||
public InternetSongDialog(Frame owner)
|
||||
{
|
||||
super(owner, true);
|
||||
|
||||
JLabel label;
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
this.getContentPane().setLayout(new GridBagLayout());
|
||||
|
||||
int y = 0;
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = y;
|
||||
c.gridwidth = 2;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.anchor = GridBagConstraints.WEST;
|
||||
c.insets = new Insets(0, 2, 5, 2);
|
||||
|
||||
this.getContentPane().add(label = new JLabel("URL"), c);
|
||||
this.urlBox = new JTextField();
|
||||
this.urlBox.addFocusListener(new FocusAdapter()
|
||||
{
|
||||
@Override
|
||||
public void focusLost(FocusEvent e)
|
||||
{
|
||||
try
|
||||
{
|
||||
new URL(((JTextField) e.getSource()).getText());
|
||||
((JTextField) e.getSource()).setForeground(Color.BLACK);
|
||||
}
|
||||
catch (MalformedURLException ex)
|
||||
{
|
||||
((JTextField) e.getSource()).requestFocusInWindow();
|
||||
((JTextField) e.getSource()).setForeground(Color.RED);
|
||||
}
|
||||
}
|
||||
});
|
||||
c.gridy = ++y;
|
||||
this.getContentPane().add(this.urlBox, c);
|
||||
label.setLabelFor(this.urlBox);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = ++y;
|
||||
this.getContentPane().add(label = new JLabel("Song Title"), c);
|
||||
this.titleBox = new JTextField();
|
||||
c.gridy = ++y;
|
||||
this.getContentPane().add(this.titleBox, c);
|
||||
label.setLabelFor(this.titleBox);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = ++y;
|
||||
this.getContentPane().add(label = new JLabel("Album"), c);
|
||||
this.albumBox = new JTextField();
|
||||
c.gridy = ++y;
|
||||
this.getContentPane().add(this.albumBox, c);
|
||||
label.setLabelFor(this.albumBox);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = ++y;
|
||||
this.getContentPane().add(label = new JLabel("Artists"), c);
|
||||
this.artistBox = new JTextField();
|
||||
c.gridy = ++y;
|
||||
this.getContentPane().add(this.artistBox, c);
|
||||
label.setLabelFor(this.artistBox);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = ++y;
|
||||
this.getContentPane().add(label = new JLabel("Genre"), c);
|
||||
this.genreBox = new JTextField();
|
||||
c.gridy = ++y;
|
||||
this.getContentPane().add(this.genreBox, c);
|
||||
label.setLabelFor(this.genreBox);
|
||||
|
||||
c.gridwidth = 1;
|
||||
c.gridx = 0;
|
||||
c.gridy = ++y;
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
cancelButton.addActionListener(e -> this.dispose());
|
||||
this.getContentPane().add(cancelButton, c);
|
||||
c.gridx = 1;
|
||||
JButton addButton = new JButton("Add");
|
||||
addButton.addActionListener(e -> this.confirm());
|
||||
this.getContentPane().add(addButton, c);
|
||||
|
||||
this.pack();
|
||||
}
|
||||
|
||||
private void confirm()
|
||||
{
|
||||
URL url;
|
||||
if (this.urlBox.getText().isEmpty())
|
||||
{
|
||||
this.urlBox.requestFocusInWindow();
|
||||
this.urlBox.setForeground(Color.RED);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
url = new URL(this.urlBox.getText());
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
this.urlBox.requestFocusInWindow();
|
||||
return;
|
||||
}
|
||||
|
||||
for (Component comp: this.getContentPane().getComponents())
|
||||
{
|
||||
comp.setEnabled(false);
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
Future<InternetSong> future = InternetSongProvider.getInstance().addSong(url, this.titleBox.getText(), this.albumBox.getText(), this.artistBox.getText(), this.genreBox.getText());
|
||||
InternetSong song = null;
|
||||
try
|
||||
{
|
||||
song = future.get();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException e)
|
||||
{
|
||||
logger.error("Could not evaluate song", e);
|
||||
JOptionPane.showMessageDialog(InternetSongDialog.this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (song != null)
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Component comp: this.getContentPane().getComponents())
|
||||
{
|
||||
comp.setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -290,9 +290,12 @@ public class PlayerControls extends JPanel implements Queue.SongChangeListener,
|
||||
public void onSongChange(Queue queue)
|
||||
{
|
||||
if (this.currentSong != null)
|
||||
{
|
||||
if (this.currentPlayer != null)
|
||||
{
|
||||
this.currentPlayer.stopSong();
|
||||
}
|
||||
}
|
||||
this.currentSong = queue.getCurrentSong();
|
||||
this.playButton.setIcon(PLAY_ICON);
|
||||
if (this.currentSong != null)
|
||||
|
||||
Reference in New Issue
Block a user