Library now shows the current file being indexed when the library is updating. Disabled view mode switching while updating the library.
This commit is contained in:
parent
45efd42793
commit
ecc789a556
@ -21,7 +21,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
public final class LibraryUtils {
|
public final class LibraryUtils {
|
||||||
|
|
||||||
static final String musicFileExtensionRegex = ".*\\.(mp3|mp4|flac|ogg)";
|
static final String musicFileExtensionRegex = "(?iu).*\\.(mp3|mp4|flac|ogg)";
|
||||||
static final Properties librarySettings = new Properties();
|
static final Properties librarySettings = new Properties();
|
||||||
static final String settingsFilename = "settings.cfg";
|
static final String settingsFilename = "settings.cfg";
|
||||||
static final File propertiesFile = new File(settingsFilename);
|
static final File propertiesFile = new File(settingsFilename);
|
||||||
@ -59,44 +59,23 @@ public final class LibraryUtils {
|
|||||||
|
|
||||||
public static void processSongsWithCallback(List<Path> rootDirectory, LibraryCallbackInterface callbackInterface){
|
public static void processSongsWithCallback(List<Path> rootDirectory, LibraryCallbackInterface callbackInterface){
|
||||||
Thread thread = new Thread(() -> {
|
Thread thread = new Thread(() -> {
|
||||||
try {
|
rootDirectory.forEach(dir -> {
|
||||||
processSongs(rootDirectory);
|
try {
|
||||||
callbackInterface.libraryUpdated(true);
|
Files.walk(dir)
|
||||||
} catch (IOException e) {
|
.filter(f -> f.toString().matches(musicFileExtensionRegex)).map(LibraryUtils::autoParse)
|
||||||
callbackInterface.libraryUpdated(false);
|
.forEach(x -> x.ifPresent(i -> {
|
||||||
}
|
Gateway.addSong(i);
|
||||||
|
callbackInterface.currentlyUpdating(i.toString());
|
||||||
|
}));
|
||||||
|
} catch (IOException e) {
|
||||||
|
callbackInterface.libraryUpdated(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
callbackInterface.libraryUpdated(true);
|
||||||
});
|
});
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void processSongsWithCallback(Path rootDirectory, LibraryCallbackInterface callbackInterface){
|
|
||||||
Thread thread = new Thread(() -> {
|
|
||||||
try {
|
|
||||||
processSongs(rootDirectory);
|
|
||||||
callbackInterface.libraryUpdated(true);
|
|
||||||
} catch (IOException e) {
|
|
||||||
callbackInterface.libraryUpdated(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void processSongs(List<Path> rootDirectories) throws IOException {
|
|
||||||
for(Path rootDirectory: rootDirectories)
|
|
||||||
processSongs(rootDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Walk through all files and directories recursively and index any music files with a correct extension
|
|
||||||
*
|
|
||||||
* @param rootDirectory Directory from which to start searching
|
|
||||||
*/
|
|
||||||
public static void processSongs(Path rootDirectory) throws IOException {
|
|
||||||
Files.walk(rootDirectory)
|
|
||||||
.filter(f -> f.toString().matches(musicFileExtensionRegex))
|
|
||||||
.map(LibraryUtils::autoParse).forEach(x -> x.ifPresent(Gateway::addSong));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract music metadata from the target file.
|
* Extract music metadata from the target file.
|
||||||
*
|
*
|
||||||
|
@ -82,6 +82,7 @@ public class Player {
|
|||||||
playBin.stop();
|
playBin.stop();
|
||||||
internalThread.stop();
|
internalThread.stop();
|
||||||
thread = null;
|
thread = null;
|
||||||
|
callbackInterface.playerStopped();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
private JComboBox libraryDisplayType = new JComboBox();
|
private JComboBox libraryDisplayType = new JComboBox();
|
||||||
private Player player = new Player(this);
|
private Player player = new Player(this);
|
||||||
private PlaylistTableModel playlistTableModel = new PlaylistTableModel(new ArrayList<>());
|
private PlaylistTableModel playlistTableModel = new PlaylistTableModel(new ArrayList<>());
|
||||||
|
private static DefaultMutableTreeNode updatingNode = new DefaultMutableTreeNode();
|
||||||
|
private boolean libraryUpdating = false;
|
||||||
|
|
||||||
private Map<String, Runnable> libraryDisplayVariants = createDisplayVariantMap();
|
private Map<String, Runnable> libraryDisplayVariants = createDisplayVariantMap();
|
||||||
|
|
||||||
@ -91,7 +93,8 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
sortedData.forEach((k, v) -> {
|
sortedData.forEach((k, v) -> {
|
||||||
DefaultMutableTreeNode albumNode = new DefaultMutableTreeNode(k);
|
DefaultMutableTreeNode albumNode = new DefaultMutableTreeNode(k);
|
||||||
addNodeToTreeModel(model, parentNode, albumNode);
|
addNodeToTreeModel(model, parentNode, albumNode);
|
||||||
new TreeSet<>(v).forEach(x -> addNodeToTreeModel(model, albumNode, new DefaultMutableTreeNode(x)));
|
Collections.sort(v);
|
||||||
|
v.forEach(x -> addNodeToTreeModel(model, albumNode, new DefaultMutableTreeNode(x)));
|
||||||
});
|
});
|
||||||
libraryView.setModel(model);
|
libraryView.setModel(model);
|
||||||
}
|
}
|
||||||
@ -152,6 +155,7 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
public void setSongHighlighting(Song playingSong) {
|
public void setSongHighlighting(Song playingSong) {
|
||||||
int index = playlistTableModel.getSongIndex(playingSong);
|
int index = playlistTableModel.getSongIndex(playingSong);
|
||||||
playList.setRowSelectionInterval(index, index);
|
playList.setRowSelectionInterval(index, index);
|
||||||
|
playlistTableModel.setPlayingRow(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,6 +180,8 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
playlistTableModel.removeSong(invalidSong);
|
playlistTableModel.removeSong(invalidSong);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void playerStopped(){ playlistTableModel.setPlayingRow(-1); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the library with songs in the currently selected display format.
|
* Refresh the library with songs in the currently selected display format.
|
||||||
*/
|
*/
|
||||||
@ -200,10 +206,12 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateLibrary(){
|
private void updateLibrary(){
|
||||||
|
libraryUpdating = true;
|
||||||
DefaultTreeModel model = new DefaultTreeModel(new DefaultMutableTreeNode());
|
DefaultTreeModel model = new DefaultTreeModel(new DefaultMutableTreeNode());
|
||||||
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) model.getRoot();
|
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) model.getRoot();
|
||||||
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("Updating Library...");
|
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("Updating Library...");
|
||||||
addNodeToTreeModel(model, parentNode, newNode);
|
addNodeToTreeModel(model, parentNode, newNode);
|
||||||
|
addNodeToTreeModel(model, parentNode, updatingNode);
|
||||||
libraryView.setModel(model);
|
libraryView.setModel(model);
|
||||||
List<Path> dirs = LibraryUtils.getLibraryDirectories().stream().map(File::toPath).collect(Collectors.toList());
|
List<Path> dirs = LibraryUtils.getLibraryDirectories().stream().map(File::toPath).collect(Collectors.toList());
|
||||||
LibraryUtils.processSongsWithCallback(dirs, this);
|
LibraryUtils.processSongsWithCallback(dirs, this);
|
||||||
@ -213,6 +221,13 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
public void libraryUpdated(boolean successful) {
|
public void libraryUpdated(boolean successful) {
|
||||||
if (successful)
|
if (successful)
|
||||||
refreshLibrary();
|
refreshLibrary();
|
||||||
|
libraryUpdating = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void currentlyUpdating(String name) {
|
||||||
|
updatingNode.setUserObject(name);
|
||||||
|
((DefaultTreeModel)libraryView.getModel()).nodeChanged(updatingNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Runnable> createDisplayVariantMap() {
|
private Map<String, Runnable> createDisplayVariantMap() {
|
||||||
@ -247,7 +262,7 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
libraryAndComboboxPane.setLayout(new BorderLayout(0, 0));
|
libraryAndComboboxPane.setLayout(new BorderLayout(0, 0));
|
||||||
libraryAndPlaylistPane.setLeftComponent(libraryAndComboboxPane);
|
libraryAndPlaylistPane.setLeftComponent(libraryAndComboboxPane);
|
||||||
libraryDisplayType.addItemListener(e -> {
|
libraryDisplayType.addItemListener(e -> {
|
||||||
if (e.getStateChange() == ItemEvent.SELECTED)
|
if (!libraryUpdating && e.getStateChange() == ItemEvent.SELECTED)
|
||||||
libraryDisplayVariants.get(libraryDisplayType.getSelectedItem().toString()).run();
|
libraryDisplayVariants.get(libraryDisplayType.getSelectedItem().toString()).run();
|
||||||
});
|
});
|
||||||
libraryAndComboboxPane.add(libraryDisplayType, BorderLayout.NORTH);
|
libraryAndComboboxPane.add(libraryDisplayType, BorderLayout.NORTH);
|
||||||
@ -278,6 +293,9 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf
|
|||||||
JScrollPane playlistScroll = new JScrollPane();
|
JScrollPane playlistScroll = new JScrollPane();
|
||||||
playList.setRowSelectionAllowed(true);
|
playList.setRowSelectionAllowed(true);
|
||||||
playList.setModel(playlistTableModel);
|
playList.setModel(playlistTableModel);
|
||||||
|
playList.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
||||||
|
playList.getColumnModel().getColumn(0).setPreferredWidth(10);
|
||||||
|
playList.getColumnModel().getColumn(0).setMaxWidth(10);
|
||||||
JPopupMenu popupMenu = new JPopupMenu();
|
JPopupMenu popupMenu = new JPopupMenu();
|
||||||
JMenuItem menuItem = new JMenuItem("Remove");
|
JMenuItem menuItem = new JMenuItem("Remove");
|
||||||
menuItem.addActionListener((e) -> playlistTableModel.removeSong(playList.getSelectedRows()));
|
menuItem.addActionListener((e) -> playlistTableModel.removeSong(playList.getSelectedRows()));
|
||||||
|
@ -3,4 +3,6 @@ package musicplayer.callbacks;
|
|||||||
public interface LibraryCallbackInterface {
|
public interface LibraryCallbackInterface {
|
||||||
|
|
||||||
void libraryUpdated(boolean successful);
|
void libraryUpdated(boolean successful);
|
||||||
|
|
||||||
|
void currentlyUpdating(String name);
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,6 @@ public interface PlayerCallbackInterface {
|
|||||||
|
|
||||||
void removeInvalidSong(Song invalidSong);
|
void removeInvalidSong(Song invalidSong);
|
||||||
|
|
||||||
|
void playerStopped();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ public class Album implements Comparable<Album> {
|
|||||||
@Column(name = "name")
|
@Column(name = "name")
|
||||||
private String name;
|
private String name;
|
||||||
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "album")
|
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "album")
|
||||||
@OrderBy("trackNumber ASC")
|
@OrderBy("discNumber ASC, trackNumber ASC")
|
||||||
private Set<Song> songs;
|
private Set<Song> songs;
|
||||||
@Lob
|
@Lob
|
||||||
@Column(name = "art", nullable = true, length = 10000)
|
@Column(name = "art", nullable = true, length = 10000)
|
||||||
|
@ -84,4 +84,9 @@ public class ExtractedMetadata {
|
|||||||
g.dispose();
|
g.dispose();
|
||||||
return newImage;
|
return newImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return title + " - " + artist;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,14 @@ package musicplayer.swingmodels;
|
|||||||
import musicplayer.model.Song;
|
import musicplayer.model.Song;
|
||||||
|
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
public class PlaylistTableModel extends AbstractTableModel {
|
public class PlaylistTableModel extends AbstractTableModel {
|
||||||
|
|
||||||
private List<Song> songList;
|
private List<Song> songList;
|
||||||
|
private int playingRow = -1;
|
||||||
|
|
||||||
public PlaylistTableModel(List<Song> songList){
|
public PlaylistTableModel(List<Song> songList){
|
||||||
this.songList = songList;
|
this.songList = songList;
|
||||||
@ -24,7 +23,7 @@ public class PlaylistTableModel extends AbstractTableModel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getColumnCount() {
|
public int getColumnCount() {
|
||||||
return 4;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -32,10 +31,12 @@ public class PlaylistTableModel extends AbstractTableModel {
|
|||||||
Object o = "?";
|
Object o = "?";
|
||||||
Song song = songList.get(rowIndex);
|
Song song = songList.get(rowIndex);
|
||||||
switch (columnIndex){
|
switch (columnIndex){
|
||||||
case 0: o = song.getTrackNumber(); break;
|
case 0: o = (playingRow == rowIndex) ? "▶" : " "; break;
|
||||||
case 1: o = song.getTitle(); break;
|
case 1: o = song.getTrackNumber(); break;
|
||||||
case 2: o = song.getArtist(); break;
|
case 2: o = song.getTitle(); break;
|
||||||
case 3: o = song.getAlbum(); break;
|
case 3: o = song.getArtist(); break;
|
||||||
|
case 4: o = song.getAlbum(); break;
|
||||||
|
case 5: o = song.getDiscNumber(); break;
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
@ -49,10 +50,12 @@ public class PlaylistTableModel extends AbstractTableModel {
|
|||||||
public String getColumnName(int column) {
|
public String getColumnName(int column) {
|
||||||
String name = "";
|
String name = "";
|
||||||
switch (column){
|
switch (column){
|
||||||
case 0: name = "Track"; break;
|
case 0 : name = " "; break;
|
||||||
case 1: name = "Title"; break;
|
case 1: name = "Track"; break;
|
||||||
case 2: name = "Artist"; break;
|
case 2: name = "Title"; break;
|
||||||
case 3: name = "Album"; break;
|
case 3: name = "Artist"; break;
|
||||||
|
case 4: name = "Album"; break;
|
||||||
|
case 5: name = "DiscNo"; break;
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@ -108,4 +111,9 @@ public class PlaylistTableModel extends AbstractTableModel {
|
|||||||
public Optional<Song> getSong(int index){
|
public Optional<Song> getSong(int index){
|
||||||
return songList.size() > 0 && index >= 0 && index < songList.size() ? Optional.of(songList.get(index)) : Optional.empty();
|
return songList.size() > 0 && index >= 0 && index < songList.size() ? Optional.of(songList.get(index)) : Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPlayingRow(int index){
|
||||||
|
playingRow = index;
|
||||||
|
fireTableDataChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user