i2psnark: Add "smart sort" option, set sort based on language (tickets #637, #1303)

This commit is contained in:
zzz
2015-10-16 19:45:23 +00:00
parent 39b218b216
commit ba1488bcce
5 changed files with 175 additions and 13 deletions

View File

@ -126,6 +126,7 @@ public class SnarkManager implements CompleteListener {
public static final String PROP_OPENTRACKERS = "i2psnark.opentrackers";
public static final String PROP_PRIVATETRACKERS = "i2psnark.privatetrackers";
private static final String PROP_USE_DHT = "i2psnark.enableDHT";
private static final String PROP_SMART_SORT = "i2psnark.smartSort";
public static final int MIN_UP_BW = 10;
public static final int DEFAULT_MAX_UP_BW = 25;
@ -340,6 +341,17 @@ public class SnarkManager implements CompleteListener {
public boolean shouldAutoStart() {
return Boolean.parseBoolean(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START));
}
/**
* @return default true
* @since 0.9.23
*/
public boolean isSmartSortEnabled() {
String val = _config.getProperty(PROP_SMART_SORT);
if (val == null)
return true;
return Boolean.parseBoolean(val);
}
/****
public String linkPrefix() {
@ -736,19 +748,19 @@ public class SnarkManager implements CompleteListener {
/**
* all params may be null or need trimming
*/
public void updateConfig(String dataDir, boolean filesPublic, boolean autoStart, String refreshDelay,
public void updateConfig(String dataDir, boolean filesPublic, boolean autoStart, boolean smartSort, String refreshDelay,
String startDelay, String pageSize, String seedPct, String eepHost,
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
String upLimit, String upBW, boolean useOpenTrackers, boolean useDHT, String theme) {
synchronized(_configLock) {
locked_updateConfig(dataDir, filesPublic, autoStart, refreshDelay,
locked_updateConfig(dataDir, filesPublic, autoStart, smartSort,refreshDelay,
startDelay, pageSize, seedPct, eepHost,
eepPort, i2cpHost, i2cpPort, i2cpOpts,
upLimit, upBW, useOpenTrackers, useDHT, theme);
}
}
private void locked_updateConfig(String dataDir, boolean filesPublic, boolean autoStart, String refreshDelay,
private void locked_updateConfig(String dataDir, boolean filesPublic, boolean autoStart, boolean smartSort, String refreshDelay,
String startDelay, String pageSize, String seedPct, String eepHost,
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
String upLimit, String upBW, boolean useOpenTrackers, boolean useDHT, String theme) {
@ -966,6 +978,16 @@ public class SnarkManager implements CompleteListener {
addMessage(_t("Disabled autostart"));
changed = true;
}
if (isSmartSortEnabled() != smartSort) {
_config.setProperty(PROP_SMART_SORT, Boolean.toString(smartSort));
if (smartSort)
addMessage(_t("Enabled smart sort"));
else
addMessage(_t("Disabled smart sort"));
changed = true;
}
if (_util.shouldUseOpenTrackers() != useOpenTrackers) {
_config.setProperty(PROP_USE_OPENTRACKERS, useOpenTrackers + "");
if (useOpenTrackers)

View File

@ -32,6 +32,7 @@ import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.util.Log;
import net.i2p.util.SecureFile;
import net.i2p.util.Translate;
import org.klomp.snark.I2PSnarkUtil;
import org.klomp.snark.MagnetURI;
@ -1118,6 +1119,7 @@ public class I2PSnarkServlet extends BasicServlet {
String dataDir = req.getParameter("nofilter_dataDir");
boolean filesPublic = req.getParameter("filesPublic") != null;
boolean autoStart = req.getParameter("autoStart") != null;
boolean smartSort = req.getParameter("smartSort") != null;
String seedPct = req.getParameter("seedPct");
String eepHost = req.getParameter("eepHost");
String eepPort = req.getParameter("eepPort");
@ -1133,7 +1135,7 @@ public class I2PSnarkServlet extends BasicServlet {
boolean useDHT = req.getParameter("useDHT") != null;
//String openTrackers = req.getParameter("openTrackers");
String theme = req.getParameter("theme");
_manager.updateConfig(dataDir, filesPublic, autoStart, refreshDel, startupDel, pageSize,
_manager.updateConfig(dataDir, filesPublic, autoStart, smartSort, refreshDel, startupDel, pageSize,
seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts,
upLimit, upBW, useOpenTrackers, useDHT, theme);
// update servlet
@ -1401,6 +1403,10 @@ public class I2PSnarkServlet extends BasicServlet {
sort = Integer.parseInt(ssort);
} catch (NumberFormatException nfe) {}
}
if (_manager.isSmartSortEnabled())
Sorters.setPattern(Translate.getLanguage(_manager.util().getContext()));
else
Sorters.setPattern(null);
try {
Collections.sort(rv, Sorters.getComparator(sort, this));
} catch (IllegalArgumentException iae) {
@ -2144,6 +2150,7 @@ public class I2PSnarkServlet extends BasicServlet {
String dataDir = _manager.getDataDir().getAbsolutePath();
boolean filesPublic = _manager.areFilesPublic();
boolean autoStart = _manager.shouldAutoStart();
boolean smartSort = _manager.isSmartSortEnabled();
boolean useOpenTrackers = _manager.util().shouldUseOpenTrackers();
//String openTrackers = _manager.util().getOpenTrackerString();
boolean useDHT = _manager.util().shouldUseDHT();
@ -2177,6 +2184,14 @@ public class I2PSnarkServlet extends BasicServlet {
+ (autoStart ? "checked " : "")
+ "title=\"");
out.write(_t("If checked, automatically start torrents that are added"));
out.write("\" >" +
"<tr><td>");
out.write(_t("Smart torrent sorting"));
out.write(": <td><input type=\"checkbox\" class=\"optbox\" name=\"smartSort\" value=\"true\" "
+ (smartSort ? "checked " : "")
+ "title=\"");
out.write(_t("If checked, ignore words such as 'the' when sorting"));
out.write("\" >" +
"<tr><td>");

View File

@ -6,6 +6,8 @@ import java.text.Collator;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.klomp.snark.MetaInfo;
import org.klomp.snark.Snark;
@ -18,6 +20,13 @@ import org.klomp.snark.Storage;
*/
class Sorters {
/**
* See below
*/
private static final Pattern PATTERN_DE, PATTERN_EN, PATTERN_ES, PATTERN_FR,
PATTERN_IT, PATTERN_NL, PATTERN_PT;
private static Pattern _pattern;
/**
* Negative is reverse
*
@ -113,8 +122,8 @@ class Sorters {
/**
* Sort alphabetically in current locale, ignore case, ignore leading "the "
* (I guess this is worth it, a lot of torrents start with "The "
* Sort alphabetically in current locale, ignore case, ignore leading
* articles such as "the" if the pattern is set by setPattern()
* @since 0.7.14
*/
private static class TorrentNameComparator implements Comparator<Snark>, Serializable {
@ -130,13 +139,16 @@ class Sorters {
if (l.getStorage() != null && r.getStorage() == null)
return 1;
String ls = l.getBaseName();
String llc = ls.toLowerCase(Locale.US);
if (llc.startsWith("the ") || llc.startsWith("the.") || llc.startsWith("the_"))
ls = ls.substring(4);
String rs = r.getBaseName();
String rlc = rs.toLowerCase(Locale.US);
if (rlc.startsWith("the ") || rlc.startsWith("the.") || rlc.startsWith("the_"))
rs = rs.substring(4);
Pattern p = _pattern;
if (p != null) {
Matcher m = p.matcher(ls);
if (m.matches())
ls = ls.substring(m.group(1).length());
m = p.matcher(rs);
if (m.matches())
rs = rs.substring(m.group(1).length());
}
return Collator.getInstance().compare(ls, rs);
}
}
@ -528,4 +540,104 @@ class Sorters {
return r.priority - l.priority;
}
}
/*
* Match an indefinite or definite article in the language,
* followed by one or more whitespace, '.', or '_'.
* Does not match "partitive" articles.
*
* https://en.wikipedia.org/wiki/Article_%28grammar%29
* http://www.loc.gov/marc/bibliographic/bdapndxf.html
*/
static {
PATTERN_DE = Pattern.compile(
// can't make the non-capturing innner group work
//"^((?:" +
"^((" +
"der|die|das|des|dem|den|ein|eine|einer|eines|einem|einen" +
")[\\s\\._]+).*",
Pattern.CASE_INSENSITIVE);
PATTERN_EN = Pattern.compile(
"^((" +
"a|an|the" +
")[\\s\\._]+).*",
Pattern.CASE_INSENSITIVE);
PATTERN_ES = Pattern.compile(
"^((" +
"el|la|lo|los|las|un|una|unos|unas" +
")[\\s\\._]+).*",
Pattern.CASE_INSENSITIVE);
PATTERN_FR = Pattern.compile(
// note l' doesn't require whitespace after
"^(l'|((" +
"le|la|les|un|une|des" +
")[\\s\\._]+)).*",
Pattern.CASE_INSENSITIVE);
PATTERN_IT = Pattern.compile(
// note l' and un' don't require whitespace after
"^(l'|un'|((" +
"il|lo|la|i|gli|le|uno|una|un" +
")[\\s\\._]+)).*",
Pattern.CASE_INSENSITIVE);
PATTERN_NL = Pattern.compile(
"^((" +
"de|het|het'n|een|een'n" +
")[\\s\\._]+).*",
Pattern.CASE_INSENSITIVE);
PATTERN_PT = Pattern.compile(
"^((" +
"o|a|os|as|um|uma|uns|umas" +
")[\\s\\._]+).*",
Pattern.CASE_INSENSITIVE);
}
/**
* Sets static field, oh well
* @param lang null for none
* @since 0.9.23
*/
public static void setPattern(String lang) {
Pattern p;
if (lang == null)
p = null;
else if (lang.equals("de"))
p = PATTERN_DE;
else if (lang.equals("en"))
p = PATTERN_EN;
else if (lang.equals("es"))
p = PATTERN_ES;
else if (lang.equals("fr"))
p = PATTERN_FR;
else if (lang.equals("it"))
p = PATTERN_IT;
else if (lang.equals("nl"))
p = PATTERN_NL;
else if (lang.equals("pt"))
p = PATTERN_PT;
else
p = null;
_pattern = p;
}
/****
public static final void main(String[] args) {
if (args.length != 2) {
System.out.println("Usage: Sorters lang 'string'");
System.exit(1);
}
String lang = args[0];
setPattern(lang);
if (_pattern == null) {
System.out.println("Unsupported " + lang);
System.exit(1);
}
String s = args[1];
Matcher m = _pattern.matcher(s);
if (m.matches()) {
System.out.println("Match is \"" + m.group(1) + '"');
} else {
System.out.println("No match for \"" + s + '"');
}
}
****/
}

View File

@ -1,3 +1,16 @@
2015-10-16 zzz
* i2psnark:
- Fix deadlock (ticket #1432)
- Add "smart sort" option, set sort based on language (tickets #637, #1303)
2015-10-14 zzz
* Update:
- Require Java 7 to download dev builds (ticket #1669)
- Fix persistence of the available dev version
2015-10-13 zzz
* Startup: Delete our old RI from netDB when rekeying
2015-10-11 zzz
* Crypto: Test for broken Gentoo ECDSA support

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 17;
public final static long BUILD = 18;
/** for example "-test" */
public final static String EXTRA = "";