Skip to content

Commit 97613cc

Browse files
committed
Improve repair playlist process
1 parent 794abb6 commit 97613cc

File tree

5 files changed

+173
-134
lines changed

5 files changed

+173
-134
lines changed

src/main/java/listfix/model/BatchMatchItem.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,17 @@ public class BatchMatchItem
1414
/**
1515
* Playlist position
1616
*/
17-
private final int _entryIx;
1817
private final PlaylistEntry _entry;
1918
private final List<PotentialPlaylistEntryMatch> matches;
2019
private PotentialPlaylistEntryMatch selectedMatch;
2120

22-
public BatchMatchItem(int ix, PlaylistEntry entry, List<PotentialPlaylistEntryMatch> matches)
21+
public BatchMatchItem(PlaylistEntry entry, List<PotentialPlaylistEntryMatch> matches)
2322
{
24-
this._entryIx = ix;
2523
this._entry = entry;
2624
this.matches = matches;
2725
this.selectedMatch = matches.size() > 0 ? matches.get(0) : null;
2826
}
2927

30-
public int getEntryIx()
31-
{
32-
return this._entryIx;
33-
}
34-
3528
public PlaylistEntry getEntry()
3629
{
3730
return _entry;

src/main/java/listfix/model/playlists/Playlist.java

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -578,23 +578,21 @@ public void changeEntryFileName(int ix, String newName)
578578
* @param mediaLibrary Media library used to reference existing media files
579579
* @param observer Progress observer
580580
*/
581-
public List<Integer> repair(IMediaLibrary mediaLibrary, IProgressObserver<String> observer)
581+
public List<PlaylistEntry> repair(IMediaLibrary mediaLibrary, IProgressObserver<String> observer)
582582
{
583583
ProgressAdapter<String> progress = ProgressAdapter.make(observer);
584584
progress.setTotal(this._entries.size());
585585

586-
List<Integer> fixed = new ArrayList<>();
587-
for (int ix = 0; ix < _entries.size(); ix++)
588-
{
586+
final long start = System.currentTimeMillis();
587+
588+
List<PlaylistEntry> fixed = _entries.stream().filter(entry -> {
589589
if (observer.getCancelled())
590590
{
591591
_logger.info(markerPlaylistRepair, "Observer cancelled, quit repair");
592-
return null;
592+
return false;
593593
}
594594
progress.stepCompleted();
595595

596-
PlaylistEntry entry = this._entries.get(ix);
597-
598596
final boolean caseInsensitiveExactMatching = this.playListOptions.getCaseInsensitiveExactMatching();
599597
final boolean relativePaths = this.playListOptions.getSavePlaylistsWithRelativePaths();
600598

@@ -607,8 +605,8 @@ public List<Integer> repair(IMediaLibrary mediaLibrary, IProgressObserver<String
607605
_logger.debug(markerPlaylistRepair, "Found " + fileEntry.getTrackPath());
608606
if (filePlaylistEntry.updatePathToMediaLibraryIfFoundOutside(mediaLibrary, caseInsensitiveExactMatching, relativePaths))
609607
{
610-
fixed.add(ix);
611-
refreshStatus();
608+
this.refreshStatus();
609+
return true;
612610
}
613611
}
614612
else
@@ -618,13 +616,16 @@ public List<Integer> repair(IMediaLibrary mediaLibrary, IProgressObserver<String
618616
if (entry.isFound())
619617
{
620618
_logger.debug(markerPlaylistRepair, "Found & repaired file entry " + fileEntry.getTrackPath());
621-
fixed.add(ix);
622-
refreshStatus();
619+
this.refreshStatus();
620+
return true;
623621
}
624622
}
625623
}
626-
}
627-
_logger.info(markerPlaylistRepair, "Completed.");
624+
return false;
625+
}).collect(Collectors.toList());
626+
627+
long timeElapsed = System.currentTimeMillis() - start;
628+
_logger.info("Repaired playlist in " + timeElapsed + " ms.");
628629
return fixed;
629630
}
630631

@@ -694,7 +695,6 @@ public List<BatchMatchItem> findClosestMatches(List<PlaylistEntry> entries, Coll
694695
progress.setTotal(entries.size());
695696

696697
List<BatchMatchItem> fixed = new ArrayList<>();
697-
int ix = 0;
698698
for (PlaylistEntry entry : entries)
699699
{
700700
if (observer.getCancelled()) return null;
@@ -703,10 +703,9 @@ public List<BatchMatchItem> findClosestMatches(List<PlaylistEntry> entries, Coll
703703
List<PotentialPlaylistEntryMatch> matches = entry.findClosestMatches(libraryFiles, null, this.playListOptions);
704704
if (!matches.isEmpty())
705705
{
706-
fixed.add(new BatchMatchItem(ix, entry, matches));
706+
fixed.add(new BatchMatchItem(entry, matches));
707707
}
708708
}
709-
ix++;
710709
progress.stepCompleted();
711710
}
712711

src/main/java/listfix/view/controls/PlaylistEditCtrl.java

Lines changed: 48 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import listfix.view.IListFixGui;
1818
import listfix.view.dialogs.*;
1919
import listfix.view.support.IPlaylistModifiedListener;
20-
import listfix.view.support.ImageIcons;
20+
2121
import listfix.view.support.ProgressWorker;
2222
import listfix.view.support.ZebraJTable;
2323
import org.apache.commons.io.FilenameUtils;
@@ -58,6 +58,7 @@ public class PlaylistEditCtrl extends JPanel
5858
private final FolderChooser _destDirFileChooser = new FolderChooser();
5959
private Playlist _playlist;
6060
protected final IListFixGui listFixGui;
61+
private boolean refreshPending = false;
6162

6263
private final IPlaylistModifiedListener listener = this::onPlaylistModified;
6364

@@ -90,7 +91,25 @@ private void onPlaylistModified(Playlist list)
9091
_btnPlay.setEnabled(_playlist != null);
9192
_btnNextMissing.setEnabled(_playlist != null && _playlist.getMissingCount() > 0);
9293
_btnPrevMissing.setEnabled(_playlist != null && _playlist.getMissingCount() > 0);
93-
getTableModel().fireTableDataChanged();
94+
this.fireTableDataChanged();
95+
}
96+
97+
/**
98+
* Call fireTableDataChanged() on the GUI thread, and do not call when a pending call is present
99+
*/
100+
private void fireTableDataChanged() {
101+
if (!refreshPending) {
102+
synchronized (this.playlistTableModel) {
103+
refreshPending = true;
104+
SwingUtilities.invokeLater(() -> {
105+
synchronized (this.playlistTableModel)
106+
{
107+
refreshPending = false;
108+
}
109+
getTableModel().fireTableDataChanged();
110+
});
111+
}
112+
}
94113
}
95114

96115
private void addItems()
@@ -222,19 +241,19 @@ private void moveSelectedRowsDown()
222241
}
223242

224243
/**
225-
* Locate missing files
244+
* Repair playlist
226245
* @return false if cancelled, otherwise true
227246
*/
228247
public boolean locateMissingFiles()
229248
{
230249
_logger.debug(markerRepair, "Start locateMissingFiles()");
231-
ProgressWorker<List<Integer>, String> worker = new ProgressWorker<>()
250+
ProgressWorker<List<PlaylistEntry>, String> worker = new ProgressWorker<>()
232251
{
233252
@Override
234-
protected List<Integer> doInBackground()
253+
protected List<PlaylistEntry> doInBackground()
235254
{
236255
_logger.debug(markerRepairWorker, "Start repairing in background....");
237-
List<Integer> result = _playlist.repair(PlaylistEditCtrl.this.getMediaLibrary(), this);
256+
List<PlaylistEntry> result = _playlist.repair(PlaylistEditCtrl.this.getMediaLibrary(), this);
238257
_logger.debug(markerRepairWorker, "Repair completed.");
239258
return result;
240259
}
@@ -247,12 +266,13 @@ protected void done()
247266
{
248267
_logger.debug(markerRepair, "Updating UI-table...");
249268
_uiTable.clearSelection();
250-
List<Integer> fixed = this.get();
251-
for (Integer fixIx : fixed)
269+
270+
for (Integer fixIx : this.getIndexList(this.get()))
252271
{
253272
int viewIx = _uiTable.convertRowIndexToView(fixIx);
254273
_uiTable.addRowSelectionInterval(viewIx, viewIx);
255274
}
275+
playlistTableModel.fireTableDataChanged();
256276
_logger.debug(markerRepair, "Completed updating UI-table");
257277
}
258278
catch (CancellationException | InterruptedException exception)
@@ -264,13 +284,29 @@ protected void done()
264284
_logger.error(markerRepair, "Error processing missing files", ex);
265285
}
266286
}
287+
288+
private List<Integer> getIndexList(List<PlaylistEntry> fixedEntries) {
289+
final List<Integer> fixedIndexes = new LinkedList<>();
290+
final List<PlaylistEntry> copiedList = new LinkedList<>(fixedEntries);
291+
292+
// Lookup the playlist index of the fixed playlist entries
293+
for (int fixIx = 0; fixIx < _playlist.size() && !copiedList.isEmpty(); ++fixIx) {
294+
if (_playlist.get(fixIx) == copiedList.get(0)) {
295+
copiedList.remove(0);
296+
fixedIndexes.add(fixIx);
297+
}
298+
}
299+
assert fixedIndexes.size() == fixedEntries.size();
300+
return fixedIndexes;
301+
}
267302
};
268303

269304
ProgressDialog pd = new ProgressDialog(getParentFrame(), true, worker, "Repairing...");
270305
pd.setVisible(true); // Wait until the worker completed
271306
return !worker.isCancelled();
272307
}
273308

309+
274310
private void reorderList()
275311
{
276312
Playlist.SortIx sortIx = Playlist.SortIx.None;
@@ -771,7 +807,8 @@ public void mouseClicked(MouseEvent evt)
771807
_uiTableScrollPane.setBorder(BorderFactory.createEtchedBorder());
772808

773809
_uiTable.setAutoCreateRowSorter(true);
774-
_uiTable.setModel(new PlaylistTableModel());
810+
811+
_uiTable.setModel(playlistTableModel);
775812
_uiTable.setDragEnabled(true);
776813
_uiTable.setFillsViewportHeight(true);
777814
_uiTable.setGridColor(new Color(153, 153, 153));
@@ -1113,6 +1150,7 @@ private void _miNewPlaylistFromSelectedActionPerformed()
11131150
private JMenuItem _miFindClosest;
11141151
private JMenuItem _miReplace;
11151152
private JPopupMenu _playlistEntryRightClickMenu;
1153+
private final PlaylistTableModel playlistTableModel= new PlaylistTableModel();
11161154
private ZebraJTable _uiTable;
11171155
private JScrollPane _uiTableScrollPane;
11181156

@@ -1134,7 +1172,7 @@ public void setPlaylist(Playlist list, boolean force)
11341172
}
11351173
_playlist = list;
11361174

1137-
((PlaylistTableModel) _uiTable.getModel()).fireTableDataChanged();
1175+
this.playlistTableModel.changePlaylist(_playlist);
11381176

11391177
boolean hasPlaylist = _playlist != null;
11401178

@@ -1695,96 +1733,6 @@ private void initFolderChooser()
16951733
_destDirFileChooser.setDialogTitle("Choose a destination directory...");
16961734
}
16971735

1698-
private class PlaylistTableModel extends AbstractTableModel
1699-
{
1700-
@Override
1701-
public int getRowCount()
1702-
{
1703-
if (_playlist != null)
1704-
{
1705-
return _playlist.size();
1706-
}
1707-
else
1708-
{
1709-
return 0;
1710-
}
1711-
}
1712-
1713-
@Override
1714-
public int getColumnCount()
1715-
{
1716-
return 4;
1717-
}
1718-
1719-
@Override
1720-
public Object getValueAt(int rowIndex, int columnIndex)
1721-
{
1722-
PlaylistEntry entry = _playlist.get(rowIndex);
1723-
switch (columnIndex)
1724-
{
1725-
case 0 ->
1726-
{
1727-
return rowIndex + 1;
1728-
}
1729-
case 1 ->
1730-
{
1731-
if (entry.isURL())
1732-
{
1733-
return ImageIcons.IMG_URL;
1734-
}
1735-
else if (entry.isFixed())
1736-
{
1737-
return ImageIcons.IMG_FIXED;
1738-
}
1739-
else if (entry.isFound())
1740-
{
1741-
return ImageIcons.IMG_FOUND;
1742-
}
1743-
else
1744-
{
1745-
return ImageIcons.IMG_MISSING;
1746-
}
1747-
}
1748-
case 2 ->
1749-
{
1750-
return entry.getTrackFileName();
1751-
}
1752-
case 3 ->
1753-
{
1754-
return entry.getTrackFolder();
1755-
}
1756-
default ->
1757-
{
1758-
return null;
1759-
}
1760-
}
1761-
}
1762-
1763-
@Override
1764-
public String getColumnName(int column)
1765-
{
1766-
return switch (column)
1767-
{
1768-
case 0 -> "#";
1769-
case 1 -> "";
1770-
case 2 -> "File Name";
1771-
case 3 -> "Location";
1772-
default -> null;
1773-
};
1774-
}
1775-
1776-
@Override
1777-
public Class<?> getColumnClass(int columnIndex)
1778-
{
1779-
return switch (columnIndex)
1780-
{
1781-
case 0 -> Integer.class;
1782-
case 1 -> ImageIcon.class;
1783-
default -> Object.class;
1784-
};
1785-
}
1786-
}
1787-
17881736
private static class IntRenderer extends DefaultTableCellRenderer
17891737
{
17901738
IntRenderer()

0 commit comments

Comments
 (0)