Improves performance and accuracy of the song list.

Most of the problem was sorting stuff.
This commit is contained in:
Markil3
2021-09-14 13:26:25 -06:00
parent 849771853c
commit 2e8b65ca9c
7 changed files with 599 additions and 273 deletions

View File

@@ -4,6 +4,8 @@
package edu.regis.universeplayer.data; package edu.regis.universeplayer.data;
import java.util.Arrays;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
public class Album implements Comparable<Album> public class Album implements Comparable<Album>
@@ -20,13 +22,22 @@ public class Album implements Comparable<Album>
@Override @Override
public int compareTo(Album o) public int compareTo(Album o)
{ {
if (o != null) if (o != null && o.name != null)
{ {
return this.name.compareTo(o.name); return this.name.compareToIgnoreCase(o.name);
} }
else else
{ {
return -1; return -1;
} }
} }
@Override
public String toString()
{
return "Album{" +
"name='" + name + '\'' +
", artists=" + Arrays.toString(artists) +
'}';
}
} }

View File

@@ -4,9 +4,52 @@
package edu.regis.universeplayer.data; package edu.regis.universeplayer.data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.util.Arrays;
public class InternetSong extends Song public class InternetSong extends Song
{ {
private static final Logger logger = LoggerFactory
.getLogger(InternetSong.class);
public URL location; public URL location;
@Override
public int compareTo(Song o)
{
int compare = super.compareTo(o);
if (compare == 0)
{
if (o instanceof LocalSong)
{
try
{
compare =
this.location.toURI()
.compareTo(((InternetSong) o).location
.toURI());
}
catch (URISyntaxException e)
{
logger.error("Could not compare locations {} and {}",
this.location, ((InternetSong) o).location, e);
}
}
}
return compare;
}
@Override
public String toString()
{
return "Song{" +
"title='" + title + '\'' +
", artists=" + Arrays.toString(artists) +
", album=" + album +
", url=" + location +
'}';
}
} }

View File

@@ -5,6 +5,7 @@
package edu.regis.universeplayer.data; package edu.regis.universeplayer.data;
import java.io.File; import java.io.File;
import java.util.Arrays;
/** /**
* This song represents a song found on the local file system. * This song represents a song found on the local file system.
@@ -14,4 +15,29 @@ public class LocalSong extends Song
public File file; public File file;
public String type; public String type;
public String codec; public String codec;
@Override
public int compareTo(Song o)
{
int compare = super.compareTo(o);
if (compare == 0)
{
if (o instanceof LocalSong)
{
compare = this.file.compareTo(((LocalSong) o).file);
}
}
return compare;
}
@Override
public String toString()
{
return "Song{" +
"title='" + title + '\'' +
", artists=" + Arrays.toString(artists) +
", album=" + album +
", url=" + file.getAbsolutePath() +
'}';
}
} }

View File

@@ -5,6 +5,7 @@
package edu.regis.universeplayer.data; package edu.regis.universeplayer.data;
import java.io.Serializable; import java.io.Serializable;
import java.util.Arrays;
/** /**
* Contains data for a song. * Contains data for a song.
@@ -16,18 +17,20 @@ public class Song implements Comparable<Song>, Serializable
public int trackNum; public int trackNum;
public int disc; public int disc;
public long duration; public long duration;
/** /**
* A reference to the album this song is part of. * A reference to the album this song is part of.
*/ */
public Album album; public Album album;
@Override @Override
public int compareTo(Song o) public int compareTo(Song o)
{ {
if (o != null) if (o != null)
{ {
int comp = this.album != null ? this.album.compareTo(o.album) : o.album != null ? 1 : 0; int comp = this.album != null ?
(o.album != null ? this.album.compareTo(o.album) :
-1) : o.album != null ? 1 : 0;
if (comp == 0) if (comp == 0)
{ {
comp = Integer.compare(this.disc, o.disc); comp = Integer.compare(this.disc, o.disc);
@@ -36,7 +39,10 @@ public class Song implements Comparable<Song>, Serializable
comp = Integer.compare(this.trackNum, o.trackNum); comp = Integer.compare(this.trackNum, o.trackNum);
if (comp == 0) if (comp == 0)
{ {
comp = this.title != null ? this.title.compareTo(o.title) : o.title != null ? 1 : 0; comp = this.title != null ?
(o.title != null ?
this.title.compareTo(o.title) :
-1) : o.title != null ? 1 : 0;
} }
} }
} }
@@ -47,4 +53,14 @@ public class Song implements Comparable<Song>, Serializable
return -1; return -1;
} }
} }
@Override
public String toString()
{
return "Song{" +
"title='" + title + '\'' +
", artists=" + Arrays.toString(artists) +
", album=" + album +
'}';
}
} }

View File

@@ -833,11 +833,13 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL
this.controls.setUpdateProgress(updated, totalUpdate, updating); this.controls.setUpdateProgress(updated, totalUpdate, updating);
if (updated == totalUpdate || totalUpdate == 0) if (updated == totalUpdate || totalUpdate == 0)
{ {
logger.debug("Resetting the song provider."); Collection<Song> songs = SongProvider.INSTANCE.getSongs();
logger.debug("Resetting the song provider with {} songs.",
songs.size());
/* /*
* TODO - Add some way to get back to the current view, just updated * TODO - Add some way to get back to the current view, just updated
*/ */
this.updateSongs(SongProvider.INSTANCE.getSongs()); this.updateSongs(songs);
} }
} }

View File

@@ -5,15 +5,21 @@
package edu.regis.universeplayer.player; package edu.regis.universeplayer.player;
import com.wordpress.tips4java.ScrollablePanel; import com.wordpress.tips4java.ScrollablePanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.regis.universeplayer.ClickListener; import edu.regis.universeplayer.ClickListener;
import edu.regis.universeplayer.data.Queue; import edu.regis.universeplayer.data.Queue;
import edu.regis.universeplayer.data.*; import edu.regis.universeplayer.data.*;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.util.List; import java.util.List;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -21,6 +27,11 @@ import java.util.stream.Collectors;
*/ */
public class SongList extends ScrollablePanel public class SongList extends ScrollablePanel
{ {
private static final Logger logger = LoggerFactory
.getLogger(SongList.class);
private static final ResourceBundle langs = ResourceBundle
.getBundle("lang.interface", Locale.getDefault());
private Map<Album, List<Song>> currentAlbums; private Map<Album, List<Song>> currentAlbums;
private Map<JComponent, Song> labelMap = new HashMap<>(); private Map<JComponent, Song> labelMap = new HashMap<>();
private Map<AlbumInfo, Album> artMap = new HashMap<>(); private Map<AlbumInfo, Album> artMap = new HashMap<>();
@@ -35,7 +46,7 @@ public class SongList extends ScrollablePanel
SongProvider<?> provider = SongProvider.INSTANCE; SongProvider<?> provider = SongProvider.INSTANCE;
this.listAlbums(provider.getSongs()); this.listAlbums(provider.getSongs());
this.setScrollableWidth(ScrollableSizeHint.FIT); this.setScrollableWidth(ScrollableSizeHint.FIT);
this.setScrollableHeight(ScrollableSizeHint.STRETCH); this.setScrollableHeight(ScrollableSizeHint.STRETCH);
this.setFocusTraversalPolicy(new SongListPolicy()); this.setFocusTraversalPolicy(new SongListPolicy());
@@ -45,7 +56,8 @@ public class SongList extends ScrollablePanel
public void focusGained(FocusEvent e) public void focusGained(FocusEvent e)
{ {
int index = -1; int index = -1;
Component[] children = ((Container) e.getComponent()).getComponents(); Component[] children = ((Container) e.getComponent())
.getComponents();
for (int i = 0, l = children.length; index == -1 && i < l; i++) for (int i = 0, l = children.length; index == -1 && i < l; i++)
{ {
if (children[i] == e.getOppositeComponent()) if (children[i] == e.getOppositeComponent())
@@ -55,10 +67,11 @@ public class SongList extends ScrollablePanel
} }
if (index == -1) if (index == -1)
{ {
artMap.keySet().stream().findFirst().ifPresent(albumInfo -> { artMap.keySet().stream().findFirst()
albumInfo.requestFocusInWindow(); .ifPresent(albumInfo -> {
scrollRectToVisible(albumInfo.getBounds()); albumInfo.requestFocusInWindow();
}); scrollRectToVisible(albumInfo.getBounds());
});
} }
} }
}); });
@@ -71,28 +84,27 @@ public class SongList extends ScrollablePanel
*/ */
public void listAlbums(Collection<? extends Song> songs) public void listAlbums(Collection<? extends Song> songs)
{ {
logger.debug("Sorting {} songs...", songs.size());
Map<Album, List<Song>> albums = songs.stream().sorted().collect(Collectors Map<Album, List<Song>> albums = songs.stream().sorted().collect(Collectors
.groupingBy(song -> song.album, Collectors .groupingBy(song -> song.album, Collectors
.mapping(song -> (Song) song, Collectors.toList()))); .mapping(song -> (Song) song, Collectors.toList())));
logger.debug("Listing {} albums ({} songs)",
albums.size(), songs.size());
GridBagConstraints c = new GridBagConstraints(); GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL; c.fill = GridBagConstraints.HORIZONTAL;
int i = 0; AtomicInteger i = new AtomicInteger(0);
List<Song> songCollection;
JLabel songNum;
JButton songTitle;
this.labelMap.clear(); this.labelMap.clear();
this.artMap.clear(); this.artMap.clear();
this.removeAll(); this.removeAll();
this.currentAlbums = albums; this.currentAlbums = albums;
for (Album album : albums.keySet()) albums.keySet().stream().sorted().forEach((album) -> {
{ List<Song> songCollection = albums.get(album);
songCollection = albums.get(album);
AlbumInfo albumInfo = new AlbumInfo(album); AlbumInfo albumInfo = new AlbumInfo(album);
c.gridx = 0; c.gridx = 0;
c.gridy = i; c.gridy = i.get();
c.gridwidth = 1; c.gridwidth = 1;
c.gridheight = songCollection.size(); c.gridheight = songCollection.size();
c.weightx = 0; c.weightx = 0;
@@ -113,10 +125,12 @@ public class SongList extends ScrollablePanel
{ {
inter = inter.getParent(); inter = inter.getParent();
} }
while (!(inter instanceof Interface) && inter.getParent() != null); while (!(inter instanceof Interface) && inter
.getParent() != null);
if (inter instanceof Interface) if (inter instanceof Interface)
{ {
((Interface) inter).updateSongs(SongProvider.INSTANCE.getSongsFromAlbum(albumInfo.album)); ((Interface) inter).updateSongs(SongProvider.INSTANCE
.getSongsFromAlbum(albumInfo.album));
} }
} }
}); });
@@ -128,10 +142,17 @@ public class SongList extends ScrollablePanel
{ {
inter = inter.getParent(); inter = inter.getParent();
} }
while (!(inter instanceof Interface) && inter.getParent() != null); while (!(inter instanceof Interface) && inter
.getParent() != null);
if (inter instanceof Interface) if (inter instanceof Interface)
{ {
((Interface) inter).updateCollections(CollectionType.album, Arrays.stream(albumInfo.album.artists).flatMap(s -> SongProvider.INSTANCE.getAlbumsFromArtist(s).stream()).collect(Collectors.toList())); ((Interface) inter)
.updateCollections(CollectionType.album, Arrays
.stream(albumInfo.album.artists)
.flatMap(s -> SongProvider.INSTANCE
.getAlbumsFromArtist(s)
.stream())
.collect(Collectors.toList()));
} }
} }
}); });
@@ -143,10 +164,16 @@ public class SongList extends ScrollablePanel
{ {
inter = inter.getParent(); inter = inter.getParent();
} }
while (!(inter instanceof Interface) && inter.getParent() != null); while (!(inter instanceof Interface) && inter
.getParent() != null);
if (inter instanceof Interface) if (inter instanceof Interface)
{ {
((Interface) inter).updateCollections(CollectionType.album, Arrays.stream(albumInfo.album.genres).flatMap(s -> SongProvider.INSTANCE.getAlbumsFromGenre(s).stream()).collect(Collectors.toList())); ((Interface) inter)
.updateCollections(CollectionType.album, Arrays
.stream(albumInfo.album.genres)
.flatMap(s -> SongProvider.INSTANCE
.getAlbumsFromGenre(s).stream())
.collect(Collectors.toList()));
} }
} }
}); });
@@ -158,10 +185,13 @@ public class SongList extends ScrollablePanel
{ {
inter = inter.getParent(); inter = inter.getParent();
} }
while (!(inter instanceof Interface) && inter.getParent() != null); while (!(inter instanceof Interface) && inter
.getParent() != null);
if (inter instanceof Interface) if (inter instanceof Interface)
{ {
((Interface) inter).updateCollections(CollectionType.album, SongProvider.INSTANCE.getAlbumsFromYear(albumInfo.album.year)); ((Interface) inter)
.updateCollections(CollectionType.album, SongProvider.INSTANCE
.getAlbumsFromYear(albumInfo.album.year));
} }
} }
}); });
@@ -169,13 +199,15 @@ public class SongList extends ScrollablePanel
this.artMap.put(albumInfo, album); this.artMap.put(albumInfo, album);
JButton firstSong = null; JButton firstSong = null;
JLabel songNum;
JButton songTitle;
for (Song song : songCollection) for (Song song : songCollection)
{ {
songNum = new JLabel(String.valueOf(song.trackNum)); songNum = new JLabel(String.valueOf(song.trackNum));
songNum.setFocusable(false); songNum.setFocusable(false);
c.gridx = 1; c.gridx = 1;
c.gridy = i; c.gridy = i.get();
c.gridheight = 1; c.gridheight = 1;
c.weightx = 0; c.weightx = 0;
c.anchor = GridBagConstraints.NORTHEAST; c.anchor = GridBagConstraints.NORTHEAST;
@@ -184,6 +216,13 @@ public class SongList extends ScrollablePanel
this.labelMap.put(songNum, song); this.labelMap.put(songNum, song);
songTitle = new JButton(song.title); songTitle = new JButton(song.title);
if (song.title == null || song.title.isEmpty())
{
if (song instanceof LocalSong)
{
songTitle.setText(((LocalSong) song).file.getName());
}
}
songTitle.setHorizontalAlignment(JButton.LEFT); songTitle.setHorizontalAlignment(JButton.LEFT);
songTitle.setFocusPainted(true); songTitle.setFocusPainted(true);
songTitle.setMargin(new Insets(0, 0, 0, 0)); songTitle.setMargin(new Insets(0, 0, 0, 0));
@@ -196,11 +235,12 @@ public class SongList extends ScrollablePanel
public void actionPerformed(ActionEvent e) public void actionPerformed(ActionEvent e)
{ {
Queue.getInstance().add(song); Queue.getInstance().add(song);
Queue.getInstance().skipToSong(Queue.getInstance().size() - 1); Queue.getInstance()
.skipToSong(Queue.getInstance().size() - 1);
} }
}); });
c.gridx = 2; c.gridx = 2;
c.gridy = i; c.gridy = i.get();
c.weightx = 1.0; c.weightx = 1.0;
c.anchor = GridBagConstraints.NORTHWEST; c.anchor = GridBagConstraints.NORTHWEST;
c.insets = new Insets(0, 10, 0, 0); c.insets = new Insets(0, 10, 0, 0);
@@ -228,25 +268,27 @@ public class SongList extends ScrollablePanel
{ {
if (e.getKeyCode() == KeyEvent.VK_ENTER) if (e.getKeyCode() == KeyEvent.VK_ENTER)
{ {
Queue.getInstance().addAll(finalSongCollection1); Queue.getInstance()
.addAll(finalSongCollection1);
} }
} }
}); });
} }
i++; i.getAndIncrement();
} }
// this.add(new JLabel(new ImageIcon(this.getClass().getResource("/gui/icons/defaultart.png"), "Default")), c); // this.add(new JLabel(new ImageIcon(this.getClass().getResource("/gui/icons/defaultart.png"), "Default")), c);
c.gridx = 0; c.gridx = 0;
c.gridy = i++; c.gridy = i.getAndIncrement();
c.gridwidth = 3; c.gridwidth = 3;
c.anchor = GridBagConstraints.NORTH; c.anchor = GridBagConstraints.NORTH;
this.add(new JSeparator(SwingConstants.HORIZONTAL), c); this.add(new JSeparator(SwingConstants.HORIZONTAL), c);
i++; i.getAndIncrement();
} });
logger.debug("Song list built");
} }
private class SongListPolicy extends FocusTraversalPolicy private class SongListPolicy extends FocusTraversalPolicy
{ {
@Override @Override
@@ -254,7 +296,8 @@ public class SongList extends ScrollablePanel
{ {
Component[] children = aContainer.getComponents(); Component[] children = aContainer.getComponents();
int index = -1; int index = -1;
for (int i = 0, l = aContainer.getComponentCount(); index == -1 && i < l; i++) for (int i = 0, l = aContainer
.getComponentCount(); index == -1 && i < l; i++)
{ {
if (children[i] == aComponent) if (children[i] == aComponent)
{ {
@@ -265,7 +308,8 @@ public class SongList extends ScrollablePanel
{ {
if (aComponent instanceof AlbumInfo) if (aComponent instanceof AlbumInfo)
{ {
for (int i = index + 1, l = aContainer.getComponentCount(); i < l; i++) for (int i = index + 1, l = aContainer
.getComponentCount(); i < l; i++)
{ {
if (children[i] instanceof AlbumInfo) if (children[i] instanceof AlbumInfo)
{ {
@@ -276,7 +320,8 @@ public class SongList extends ScrollablePanel
} }
else if (aComponent instanceof JButton) else if (aComponent instanceof JButton)
{ {
for (int i = index + 1, l = aContainer.getComponentCount(); i < l; i++) for (int i = index + 1, l = aContainer
.getComponentCount(); i < l; i++)
{ {
if (children[i].isFocusable()) if (children[i].isFocusable())
{ {
@@ -288,13 +333,14 @@ public class SongList extends ScrollablePanel
} }
return null; return null;
} }
@Override @Override
public Component getComponentBefore(Container aContainer, Component aComponent) public Component getComponentBefore(Container aContainer, Component aComponent)
{ {
Component[] children = aContainer.getComponents(); Component[] children = aContainer.getComponents();
int index = -1; int index = -1;
for (int i = 0, l = aContainer.getComponentCount(); index == -1 && i < l; i++) for (int i = 0, l = aContainer
.getComponentCount(); index == -1 && i < l; i++)
{ {
if (children[i] == aComponent) if (children[i] == aComponent)
{ {
@@ -328,22 +374,26 @@ public class SongList extends ScrollablePanel
} }
return null; return null;
} }
@Override @Override
public Component getFirstComponent(Container aContainer) public Component getFirstComponent(Container aContainer)
{ {
Component comp = Arrays.stream(aContainer.getComponents()).filter(a -> a instanceof AlbumInfo).findFirst().orElse(null); Component comp = Arrays.stream(aContainer.getComponents())
.filter(a -> a instanceof AlbumInfo)
.findFirst().orElse(null);
if (comp != null) if (comp != null)
{ {
scrollRectToVisible(comp.getBounds()); scrollRectToVisible(comp.getBounds());
} }
return comp; return comp;
} }
@Override @Override
public Component getLastComponent(Container aContainer) public Component getLastComponent(Container aContainer)
{ {
Component[] matching = Arrays.stream(aContainer.getComponents()).filter(a -> a instanceof JButton).toArray(Component[]::new); Component[] matching = Arrays.stream(aContainer.getComponents())
.filter(a -> a instanceof JButton)
.toArray(Component[]::new);
if (matching.length > 0) if (matching.length > 0)
{ {
scrollRectToVisible(matching[matching.length - 1].getBounds()); scrollRectToVisible(matching[matching.length - 1].getBounds());
@@ -354,7 +404,7 @@ public class SongList extends ScrollablePanel
return null; return null;
} }
} }
@Override @Override
public Component getDefaultComponent(Container aContainer) public Component getDefaultComponent(Container aContainer)
{ {