forked from I2P_Developers/i2p.i2p
This commit is contained in:
@ -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)
|
||||
|
@ -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>");
|
||||
|
@ -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 + '"');
|
||||
}
|
||||
}
|
||||
****/
|
||||
}
|
||||
|
13
history.txt
13
history.txt
@ -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
|
||||
|
||||
|
@ -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 = "";
|
||||
|
Reference in New Issue
Block a user