diff --git a/interface/src/main/java/edu/regis/universeplayer/data/LocalSongProvider.java b/interface/src/main/java/edu/regis/universeplayer/data/LocalSongProvider.java index c186f65..682c78f 100644 --- a/interface/src/main/java/edu/regis/universeplayer/data/LocalSongProvider.java +++ b/interface/src/main/java/edu/regis/universeplayer/data/LocalSongProvider.java @@ -108,7 +108,7 @@ public class LocalSongProvider implements SongProvider */ public static Set getCodecs() { - final Pattern FILEPAT = Pattern.compile("^\\s*D[E.]A[I.][L.][S.]\\s*([a-z1-9_]{2,})\\s*[A-Za-z1-9 \\(\\)-/'\\.\":]+$"); + final Pattern FILEPAT = Pattern.compile("^\\s*D[E.]A[I.][L.][S.]\\s*([a-z1-9_]{2,})\\s*.+$"); final Pattern FILEPAT2 = Pattern.compile("[a-z1-9_]{2,}"); Matcher matcher; String ffmpegData; @@ -427,16 +427,7 @@ public class LocalSongProvider implements SongProvider try { - if (file.isDirectory()) - { - totalUpdate--; - List tasks = Arrays.stream(Objects.requireNonNullElse(file.listFiles(), new File[0])) - .map(SongScanner::new).collect(Collectors.toList()); - totalUpdate += tasks.size(); - triggerUpdateListeners(); - invokeAll(tasks); - } - else if (file.getName().lastIndexOf(".") < file.getName().length() - 1) + if (file.getName().lastIndexOf(".") < file.getName().length() - 1) { type = file.getName().substring(file.getName().lastIndexOf('.') + 1).toLowerCase(); if (getFormats().contains(type)) @@ -454,6 +445,7 @@ public class LocalSongProvider implements SongProvider /* * No modifications needed */ + logger.debug("No update needed for {}", file); updatedSongs++; triggerUpdateListeners(); return; @@ -465,7 +457,6 @@ public class LocalSongProvider implements SongProvider } } currentFolder = file.getPath(); - triggerUpdateListeners(); codec = null; process = Runtime.getRuntime().exec(new String[] {"ffprobe", "-hide_banner", file.getAbsolutePath()}); process.waitFor(); @@ -656,11 +647,11 @@ public class LocalSongProvider implements SongProvider sql.append("type='").append(codec).append("', "); if (title != null && !title.isEmpty()) { - sql.append("title='").append(title).append("', "); + sql.append("title='").append(title.replaceAll("'", "''")).append("', "); } else { - sql.append("title='").append(file.getName()).append("', "); + sql.append("title='").append(file.getName().replaceAll("'", "''")).append("', "); } if (artist != null && !artist.isEmpty()) { @@ -722,7 +713,7 @@ public class LocalSongProvider implements SongProvider if (title != null && !title.isEmpty()) { columns.append("title,"); - values.append('\'').append(title).append("',"); + values.append('\'').append(title.replaceAll("'", "''")).append("',"); } if (artist != null && !artist.isEmpty()) { @@ -830,6 +821,7 @@ public class LocalSongProvider implements SongProvider ResultSet result; Album album; LocalSong song; + int numAlbums = 0, numSongs = 0; try { @@ -839,6 +831,22 @@ public class LocalSongProvider implements SongProvider */ synchronized (db) { + /* + * 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 = getDb().createStatement(); result = state.executeQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='LOCAL_ALBUMS';"); if (!result.next()) @@ -872,6 +880,7 @@ public class LocalSongProvider implements SongProvider 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='LOCAL_SONGS';"); @@ -898,6 +907,10 @@ public class LocalSongProvider implements SongProvider result = state.executeQuery("SELECT * FROM LOCAL_SONGS;"); while (result.next()) { + if (result.getString("file") == null) + { + continue; + } song = songs.get(new File(result.getString("file"))); if (song == null) { @@ -912,7 +925,8 @@ public class LocalSongProvider implements SongProvider 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(null); + song.album = Optional.ofNullable(result.getString("album")).map(albums::get).orElse(albums.get("Unknown")); + numSongs++; } } state.close(); @@ -922,16 +936,41 @@ public class LocalSongProvider implements SongProvider { logger.error("Could not query SQL database.", e); } - logger.debug("Query complete."); + logger.debug("Query complete, retrieved {} albums and {} songs", numAlbums, numSongs); updatedSongs = 0; totalUpdate = 0; triggerUpdateListeners(); if (scan) { - logger.debug("Scanning for changes..."); - totalUpdate = 1; - invokeAll(new SongScanner(source), new ScanCompletion()); + LinkedList scanners = new LinkedList<>(); + this.invokeFolder(source, scanners); + triggerUpdateListeners(); + logger.debug("Scanning for changes in {} files...", totalUpdate); + invokeAll(scanners.toArray(SongScanner[]::new)); + invokeAll(new ScanCompletion()); + } + } + + /** + * Searches for all files and scans them + * + * @param dir - The file to scan + * @param scanners - The list to add the scanners to + */ + private void invokeFolder(File dir, List scanners) + { + if (dir.isDirectory()) + { + for (File file : Objects.requireNonNullElse(dir.listFiles(), new File[0])) + { + this.invokeFolder(file, scanners); + } + } + else + { + totalUpdate++; + scanners.add(new SongScanner(dir)); } } } @@ -948,6 +987,7 @@ public class LocalSongProvider implements SongProvider break; } } + logger.debug("Scan complete. Researching database"); SongScanner.currentFolder = ""; updatedSongs = 0; totalUpdate = 0; diff --git a/interface/src/main/java/edu/regis/universeplayer/data/Song.java b/interface/src/main/java/edu/regis/universeplayer/data/Song.java index eea8716..5a3e03f 100644 --- a/interface/src/main/java/edu/regis/universeplayer/data/Song.java +++ b/interface/src/main/java/edu/regis/universeplayer/data/Song.java @@ -21,13 +21,13 @@ public abstract class Song implements Comparable, Serializable * A reference to the album this song is part of. */ public Album album; - + @Override public int compareTo(Song o) { if (o != null) { - int comp = this.album.compareTo(o.album); + int comp = this.album != null ? this.album.compareTo(o.album) : o.album != null ? 1 : 0; if (comp == 0) { comp = Integer.compare(this.disc, o.disc); @@ -36,7 +36,7 @@ public abstract class Song implements Comparable, Serializable comp = Integer.compare(this.trackNum, o.trackNum); if (comp == 0) { - comp = this.title.compareTo(o.title); + comp = this.title != null ? this.title.compareTo(o.title) : o.title != null ? 1 : 0; } } } diff --git a/interface/src/main/java/edu/regis/universeplayer/player/CollectionList.java b/interface/src/main/java/edu/regis/universeplayer/player/CollectionList.java index 8839d3d..bfc41ef 100644 --- a/interface/src/main/java/edu/regis/universeplayer/player/CollectionList.java +++ b/interface/src/main/java/edu/regis/universeplayer/player/CollectionList.java @@ -48,11 +48,13 @@ public class CollectionList extends ScrollablePanel public CollectionList() { super(); - + FlowLayout layout = new FlowLayout(); this.setLayout(layout); this.setFocusCycleRoot(true); // this.setFocusable(true); + this.setScrollableWidth(ScrollableSizeHint.FIT); + this.setScrollableHeight(ScrollableSizeHint.STRETCH); this.addFocusListener(new FocusAdapter() { @Override diff --git a/interface/src/main/java/edu/regis/universeplayer/player/Interface.java b/interface/src/main/java/edu/regis/universeplayer/player/Interface.java index 62c9439..f2f6e11 100644 --- a/interface/src/main/java/edu/regis/universeplayer/player/Interface.java +++ b/interface/src/main/java/edu/regis/universeplayer/player/Interface.java @@ -228,12 +228,8 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL { this.songList.listAlbums(songs); this.centerView.setViewportView(this.songList); -// this.songList.setPreferredSize(new Dimension(this.centerView.getViewport() -// .getExtentSize().width, Integer.MAX_VALUE)); - this.songList.setPreferredSize(new Dimension(this.centerView.getViewport() - .getExtentSize().width, this.songList - .getMinimumSize().height)); - this.centerView.validate(); + this.songList.revalidate(); + this.centerView.revalidate(); } @Override @@ -241,27 +237,13 @@ public class Interface extends JFrame implements SongDisplayListener, ComponentL { this.collectionList.listCollection(type, collections); this.centerView.setViewportView(this.collectionList); -// this.collectionList.setPreferredSize(new Dimension(this.centerView.getViewport() -// .getExtentSize().width, Integer.MAX_VALUE)); - this.collectionList.setPreferredSize(new Dimension(this.centerView.getViewport() - .getExtentSize().width, this.collectionList - .getMinimumSize().height)); - this.centerView.validate(); + this.collectionList.revalidate(); + this.centerView.revalidate(); } @Override public void componentResized(ComponentEvent event) { - this.songList.setPreferredSize(new Dimension(this.centerView.getViewport() - .getExtentSize().width, Integer.MAX_VALUE)); - this.songList.setPreferredSize(new Dimension(this.centerView.getViewport() - .getExtentSize().width, this.songList - .getMinimumSize().height)); - this.collectionList.setPreferredSize(new Dimension(this.centerView.getViewport() - .getExtentSize().width, Integer.MAX_VALUE)); - this.collectionList.setPreferredSize(new Dimension(this.centerView.getViewport() - .getExtentSize().width, this.collectionList - .getMinimumSize().height)); } @Override diff --git a/interface/src/main/java/edu/regis/universeplayer/player/SongList.java b/interface/src/main/java/edu/regis/universeplayer/player/SongList.java index 10b6b93..0256e1a 100644 --- a/interface/src/main/java/edu/regis/universeplayer/player/SongList.java +++ b/interface/src/main/java/edu/regis/universeplayer/player/SongList.java @@ -37,6 +37,7 @@ public class SongList extends ScrollablePanel this.listAlbums(provider.getSongs()); this.setScrollableWidth(ScrollableSizeHint.FIT); + this.setScrollableHeight(ScrollableSizeHint.STRETCH); this.setFocusTraversalPolicy(new SongListPolicy()); this.addFocusListener(new FocusAdapter() { diff --git a/interface/src/main/resources/log4j2.xml b/interface/src/main/resources/log4j2.xml index bb59faf..8a77aee 100644 --- a/interface/src/main/resources/log4j2.xml +++ b/interface/src/main/resources/log4j2.xml @@ -14,12 +14,15 @@ - + - + + + +