Prevent downloading songs that are already loaded. (base: fluddokt/opsu/76778f8)

- All beatmap set IDs are now stored in a set in OsuGroupList.
- OsuParser now checks the directory name for beatmap set IDs if the OsuFile doesn't contain one (for older beatmap formats).

Tweaks:
- Clear completed downloads when hitting "Import All".
- Call Download.updateReadSoFar() upon starting downloads instead of waiting for user to hover over the button (causing an unnecessary delay).

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2015-02-09 23:22:58 -05:00
parent f56c02864b
commit be3b94f5db
7 changed files with 72 additions and 8 deletions

View File

@ -392,8 +392,8 @@ public class Options {
RES_1366_768 (1366, 768), RES_1366_768 (1366, 768),
RES_1440_900 (1440, 900), RES_1440_900 (1440, 900),
RES_1600_900 (1600, 900), RES_1600_900 (1600, 900),
RES_1680_1050 (1680, 1050),
RES_1600_1200 (1600, 1200), RES_1600_1200 (1600, 1200),
RES_1680_1050 (1680, 1050),
RES_1920_1080 (1920, 1080), RES_1920_1080 (1920, 1080),
RES_1920_1200 (1920, 1200), RES_1920_1200 (1920, 1200),
RES_2560_1440 (2560, 1440), RES_2560_1440 (2560, 1440),

View File

@ -21,6 +21,7 @@ package itdelatrisu.opsu;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -47,6 +48,9 @@ public class OsuGroupList {
/** Current list of nodes (subset of parsedNodes, used for searches). */ /** Current list of nodes (subset of parsedNodes, used for searches). */
private ArrayList<OsuGroupNode> nodes; private ArrayList<OsuGroupNode> nodes;
/** Set of all beatmap set IDs for the parsed beatmaps. */
private HashSet<Integer> MSIDdb;
/** Index of current expanded node (-1 if no node is expanded). */ /** Index of current expanded node (-1 if no node is expanded). */
private int expandedIndex; private int expandedIndex;
@ -68,6 +72,7 @@ public class OsuGroupList {
*/ */
private OsuGroupList() { private OsuGroupList() {
parsedNodes = new ArrayList<OsuGroupNode>(); parsedNodes = new ArrayList<OsuGroupNode>();
MSIDdb = new HashSet<Integer>();
reset(); reset();
} }
@ -95,6 +100,12 @@ public class OsuGroupList {
OsuGroupNode node = new OsuGroupNode(osuFiles); OsuGroupNode node = new OsuGroupNode(osuFiles);
parsedNodes.add(node); parsedNodes.add(node);
mapCount += osuFiles.size(); mapCount += osuFiles.size();
// add beatmap set ID to set
int msid = osuFiles.get(0).beatmapSetID;
if (msid > 0)
MSIDdb.add(msid);
return node; return node;
} }
@ -335,4 +346,14 @@ public class OsuGroupList {
return true; return true;
} }
/**
* Returns whether or not the list contains the given beatmap set ID.
* <p>
* Note that IDs for older maps might have been improperly parsed, so
* there is no guarantee that this method will return an accurate value.
* @param id the beatmap set ID to check
* @return true if id is in the list
*/
public boolean containsBeatmapSetID(int id) { return MSIDdb.contains(id); }
} }

View File

@ -37,6 +37,12 @@ import org.newdawn.slick.util.Log;
* Parser for OSU files. * Parser for OSU files.
*/ */
public class OsuParser { public class OsuParser {
/** The string lookup database. */
private static HashMap<String, String> stringdb = new HashMap<String, String>();
/** The expected pattern for beatmap directories, used to find beatmap set IDs. */
private static final String DIR_MSID_PATTERN = "^\\d+ .*";
/** The current file being parsed. */ /** The current file being parsed. */
private static File currentFile; private static File currentFile;
@ -46,9 +52,6 @@ public class OsuParser {
/** The total number of directories to parse. */ /** The total number of directories to parse. */
private static int totalDirectories = -1; private static int totalDirectories = -1;
/** The string lookup database. */
private static HashMap<String, String> stringdb = new HashMap<String, String>();
// This class should not be instantiated. // This class should not be instantiated.
private OsuParser() {} private OsuParser() {}
@ -100,7 +103,7 @@ public class OsuParser {
// Parse hit objects only when needed to save time/memory. // Parse hit objects only when needed to save time/memory.
// Change boolean to 'true' to parse them immediately. // Change boolean to 'true' to parse them immediately.
parseFile(file, osuFiles, false); parseFile(file, dir, osuFiles, false);
} }
if (!osuFiles.isEmpty()) { // add entry if non-empty if (!osuFiles.isEmpty()) { // add entry if non-empty
osuFiles.trimToSize(); osuFiles.trimToSize();
@ -125,11 +128,12 @@ public class OsuParser {
/** /**
* Parses an OSU file. * Parses an OSU file.
* @param file the file to parse * @param file the file to parse
* @param dir the directory containing the beatmap
* @param osuFiles the song group * @param osuFiles the song group
* @param parseObjects if true, hit objects will be fully parsed now * @param parseObjects if true, hit objects will be fully parsed now
* @return the new OsuFile object * @return the new OsuFile object
*/ */
public static OsuFile parseFile(File file, ArrayList<OsuFile> osuFiles, boolean parseObjects) { private static OsuFile parseFile(File file, File dir, ArrayList<OsuFile> osuFiles, boolean parseObjects) {
OsuFile osu = new OsuFile(file); OsuFile osu = new OsuFile(file);
try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) { try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
@ -295,6 +299,13 @@ public class OsuParser {
Log.warn(String.format("Failed to read metadata '%s' for file '%s'.", Log.warn(String.format("Failed to read metadata '%s' for file '%s'.",
line, file.getAbsolutePath()), e); line, file.getAbsolutePath()), e);
} }
if (osu.beatmapSetID <= 0) { // try to determine MSID from directory name
if (dir != null && dir.isDirectory()) {
String dirName = dir.getName();
if (!dirName.isEmpty() && dirName.matches(DIR_MSID_PATTERN))
osu.beatmapSetID = Integer.parseInt(dirName.substring(0, dirName.indexOf(' ')));
}
}
} }
break; break;
case "[Difficulty]": case "[Difficulty]":

View File

@ -165,6 +165,7 @@ public class Download {
rbc = new ReadableByteChannelWrapper(readableByteChannel); rbc = new ReadableByteChannelWrapper(readableByteChannel);
fos = fileOutputStream; fos = fileOutputStream;
status = Status.DOWNLOADING; status = Status.DOWNLOADING;
updateReadSoFar();
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
if (status == Status.DOWNLOADING) { // not interrupted if (status == Status.DOWNLOADING) { // not interrupted
status = Status.COMPLETE; status = Status.COMPLETE;

View File

@ -19,6 +19,7 @@
package itdelatrisu.opsu.downloads; package itdelatrisu.opsu.downloads;
import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.downloads.Download.Status;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -143,6 +144,23 @@ public class DownloadList {
} }
} }
/**
* Removes all downloads with the given status from the list.
* @param status the download status
*/
public void clearDownloads(Status status) {
Iterator<DownloadNode> iter = nodes.iterator();
while (iter.hasNext()) {
DownloadNode node = iter.next();
Download dl = node.getDownload();
if (dl != null && dl.getStatus() == status) {
node.clearDownload();
iter.remove();
map.remove(node.getID());
}
}
}
/** /**
* Shows a confirmation dialog (used before exiting the game). * Shows a confirmation dialog (used before exiting the game).
* @return true if user selects "yes", false otherwise * @return true if user selects "yes", false otherwise

View File

@ -21,6 +21,7 @@ package itdelatrisu.opsu.downloads;
import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.Download.Status; import itdelatrisu.opsu.downloads.Download.Status;
@ -296,6 +297,12 @@ public class DownloadNode {
g.setColor((focus) ? BG_FOCUS : (hover) ? BG_HOVER : BG_NORMAL); g.setColor((focus) ? BG_FOCUS : (hover) ? BG_HOVER : BG_NORMAL);
g.fillRect(buttonBaseX, y, buttonWidth, buttonHeight); g.fillRect(buttonBaseX, y, buttonWidth, buttonHeight);
// map is already loaded
if (OsuGroupList.get().containsBeatmapSetID(beatmapSetID)) {
g.setColor(Utils.COLOR_BLUE_BUTTON);
g.fillRect(buttonBaseX, y, buttonWidth, buttonHeight);
}
// download progress // download progress
if (dl != null) { if (dl != null) {
float progress = dl.getProgress(); float progress = dl.getProgress();
@ -349,7 +356,7 @@ public class DownloadNode {
else if (status == Download.Status.WAITING) else if (status == Download.Status.WAITING)
info = String.format("%s...", status.getName()); info = String.format("%s...", status.getName());
else { else {
if (hover) if (hover && status == Download.Status.DOWNLOADING)
info = String.format("%s: %s left (%s)", status.getName(), download.getTimeRemaining(), download.getDownloadSpeed()); info = String.format("%s: %s left (%s)", status.getName(), download.getTimeRemaining(), download.getDownloadSpeed());
else else
info = String.format("%s: %.1f%% (%s/%s)", status.getName(), progress, info = String.format("%s: %.1f%% (%s/%s)", status.getName(), progress,

View File

@ -438,6 +438,12 @@ public class DownloadsMenu extends BasicGameState {
if (index >= nodes.length) if (index >= nodes.length)
break; break;
if (DownloadNode.resultContains(x, y, i)) { if (DownloadNode.resultContains(x, y, i)) {
DownloadNode node = nodes[index];
// check if map is already loaded
if (OsuGroupList.get().containsBeatmapSetID(node.getID()))
return;
SoundController.playSound(SoundEffect.MENUCLICK); SoundController.playSound(SoundEffect.MENUCLICK);
if (index == focusResult) { if (index == focusResult) {
if (focusTimer >= FOCUS_DELAY) { if (focusTimer >= FOCUS_DELAY) {
@ -445,7 +451,6 @@ public class DownloadsMenu extends BasicGameState {
focusTimer = 0; focusTimer = 0;
} else { } else {
// start download // start download
DownloadNode node = nodes[index];
if (!DownloadList.get().contains(node.getID())) { if (!DownloadList.get().contains(node.getID())) {
DownloadList.get().addNode(node); DownloadList.get().addNode(node);
node.createDownload(server); node.createDownload(server);
@ -515,6 +520,7 @@ public class DownloadsMenu extends BasicGameState {
} }
} }
DownloadList.get().clearDownloads(Download.Status.COMPLETE);
importThread = null; importThread = null;
} }
}; };