throws IOException {
String format;
if (cover) {
- format = Instance.getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER)
- .toLowerCase();
+ format = Instance.getInstance().getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase();
} else {
- format = Instance.getConfig()
- .getString(Config.FILE_FORMAT_IMAGE_FORMAT_CONTENT).toLowerCase();
+ format = Instance.getInstance().getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_CONTENT)
+ .toLowerCase();
}
saveAsImage(img, new File(target.toString() + "." + format), format);
}
* @author niki
*/
public class Instance {
- private static ConfigBundle config;
- private static UiConfigBundle uiconfig;
- private static StringIdBundle trans;
- private static DataLoader cache;
- private static StringIdGuiBundle transGui;
- private static BasicLibrary lib;
- private static File coverDir;
- private static File readerTmp;
- private static File remoteDir;
- private static String configDir;
- private static TraceHandler tracer;
- private static TempFiles tempFiles;
-
- private static boolean init;
+ static private Instance instance;
+ static private Object instancelock = new Object();
+
+ private ConfigBundle config;
+ private UiConfigBundle uiconfig;
+ private StringIdBundle trans;
+ private DataLoader cache;
+ private StringIdGuiBundle transGui;
+ private BasicLibrary lib;
+ private File coverDir;
+ private File readerTmp;
+ private File remoteDir;
+ private String configDir;
+ private TraceHandler tracer;
+ private TempFiles tempFiles;
/**
* Initialise the instance -- if already initialised, nothing will happen.
* <p>
- * Before calling this method, you may call
- * {@link Bundles#setDirectory(String)} if wanted.
+ * Before calling this method, you may call {@link Bundles#setDirectory(String)}
+ * if wanted.
*/
static public void init() {
init(false);
}
/**
- * Initialise the instance -- if already initialised, nothing will happen
- * unless you pass TRUE to <tt>force</tt>.
+ * Initialise the instance -- if already initialised, nothing will happen unless
+ * you pass TRUE to <tt>force</tt>.
* <p>
- * Before calling this method, you may call
- * {@link Bundles#setDirectory(String)} if wanted.
+ * Before calling this method, you may call {@link Bundles#setDirectory(String)}
+ * if wanted.
* <p>
- * Note: forcing the initialisation can be dangerous, so make sure to only
- * make it under controlled circumstances -- for instance, at the start of
- * the program, you could call {@link Instance#init()}, change some settings
- * because you want to force those settings (it will also forbid users to
- * change them!) and then call {@link Instance#init(boolean)} with
- * <tt>force</tt> set to TRUE.
+ * Note: forcing the initialisation can be dangerous, so make sure to only make
+ * it under controlled circumstances -- for instance, at the start of the
+ * program, you could call {@link Instance#init()}, change some settings because
+ * you want to force those settings (it will also forbid users to change them!)
+ * and then call {@link Instance#init(boolean)} with <tt>force</tt> set to TRUE.
*
- * @param force
- * force the initialisation even if already initialised
+ * @param force force the initialisation even if already initialised
*/
static public void init(boolean force) {
- if (init && !force) {
- return;
+ synchronized (instancelock) {
+ if (instance == null || force) {
+ instance = new Instance();
+ }
}
- init = true;
+ }
+
+ /**
+ * Force-initialise the {@link Instance} to a known value.
+ * <p>
+ * Usually for DEBUG/Test purposes.
+ *
+ * @param instance the actual Instance to use
+ */
+ static public void init(Instance instance) {
+ Instance.instance = instance;
+ }
+
+ /**
+ * The (mostly unique) instance of this {@link Instance}.
+ *
+ * @return the (mostly unique) instance
+ */
+ public static Instance getInstance() {
+ return instance;
+ }
+ /**
+ * Actually initialise the instance.
+ * <p>
+ * Before calling this method, you may call {@link Bundles#setDirectory(String)}
+ * if wanted.
+ */
+ protected Instance() {
// Before we can configure it:
Boolean debug = checkEnv("DEBUG");
boolean trace = debug != null && debug;
createConfigs(configDir, false);
// Proxy support
- Proxy.use(Instance.getConfig().getString(Config.NETWORK_PROXY));
+ Proxy.use(config.getString(Config.NETWORK_PROXY));
// update tracer:
if (debug == null) {
- debug = Instance.getConfig().getBoolean(Config.DEBUG_ERR, false);
- trace = Instance.getConfig().getBoolean(Config.DEBUG_TRACE, false);
+ debug = config.getBoolean(Config.DEBUG_ERR, false);
+ trace = config.getBoolean(Config.DEBUG_TRACE, false);
}
tracer = new TraceHandler(true, debug, trace);
int hoursLarge = config.getInteger(Config.CACHE_MAX_TIME_STABLE, 0);
cache = new DataLoader(tmp, ua, hours, hoursLarge);
} catch (IOException e) {
- tracer.error(new IOException(
- "Cannot create cache (will continue without cache)", e));
+ tracer.error(new IOException("Cannot create cache (will continue without cache)", e));
cache = new DataLoader(ua);
}
cache.setTraceHandler(tracer);
// readerTmp / coverDir
- readerTmp = getFile(UiConfig.CACHE_DIR_LOCAL_READER, new File(
- configDir, "tmp-reader"));
+ readerTmp = getFile(UiConfig.CACHE_DIR_LOCAL_READER, new File(configDir, "tmp-reader"));
- coverDir = getFile(Config.DEFAULT_COVERS_DIR, new File(configDir,
- "covers"));
+ coverDir = getFile(Config.DEFAULT_COVERS_DIR, new File(configDir, "covers"));
coverDir.mkdirs();
try {
*
* @return the traces handler (never NULL)
*/
- public static TraceHandler getTraceHandler() {
+ public TraceHandler getTraceHandler() {
return tracer;
}
/**
* The traces handler for this {@link Cache}.
*
- * @param tracer
- * the new traces handler or NULL
+ * @param tracer the new traces handler or NULL
*/
- public static void setTraceHandler(TraceHandler tracer) {
+ public void setTraceHandler(TraceHandler tracer) {
if (tracer == null) {
tracer = new TraceHandler(false, false, false);
}
- Instance.tracer = tracer;
+ this.tracer = tracer;
cache.setTraceHandler(tracer);
}
*
* @return the configuration service
*/
- public static ConfigBundle getConfig() {
+ public ConfigBundle getConfig() {
return config;
}
*
* @return the configuration service
*/
- public static UiConfigBundle getUiConfig() {
+ public UiConfigBundle getUiConfig() {
return uiconfig;
}
/**
* Reset the configuration.
*
- * @param resetTrans
- * also reset the translation files
+ * @param resetTrans also reset the translation files
*/
- public static void resetConfig(boolean resetTrans) {
+ public void resetConfig(boolean resetTrans) {
String dir = Bundles.getDirectory();
Bundles.setDirectory(null);
try {
*
* @return the {@link DataLoader}
*/
- public static DataLoader getCache() {
+ public DataLoader getCache() {
return cache;
}
*
* @return the {link StringIdBundle}
*/
- public static StringIdBundle getTrans() {
+ public StringIdBundle getTrans() {
return trans;
}
*
* @return the {link StringIdGuiBundle}
*/
- public static StringIdGuiBundle getTransGui() {
+ public StringIdGuiBundle getTransGui() {
return transGui;
}
*
* @return the {@link LocalLibrary}
*/
- public static BasicLibrary getLibrary() {
+ public BasicLibrary getLibrary() {
if (lib == null) {
throw new NullPointerException("We don't have a library to return");
}
*
* @return the default covers directory
*/
- public static File getCoverDir() {
+ public File getCoverDir() {
return coverDir;
}
*
* @return the directory
*/
- public static File getReaderDir() {
+ public File getReaderDir() {
return readerTmp;
}
* Return the directory where to store temporary files for the remote
* {@link LocalLibrary}.
*
- * @param host
- * the remote for this host
+ * @param host the remote for this host
*
* @return the directory
*/
- public static File getRemoteDir(String host) {
+ public File getRemoteDir(String host) {
return getRemoteDir(remoteDir, host);
}
* Return the directory where to store temporary files for the remote
* {@link LocalLibrary}.
*
- * @param remoteDir
- * the base remote directory
- * @param host
- * the remote for this host
+ * @param remoteDir the base remote directory
+ * @param host the remote for this host
*
* @return the directory
*/
- private static File getRemoteDir(File remoteDir, String host) {
+ private File getRemoteDir(File remoteDir, String host) {
remoteDir.mkdirs();
if (host != null) {
*
* @return TRUE if we need to
*/
- public static boolean isVersionCheckNeeded() {
+ public boolean isVersionCheckNeeded() {
try {
- long wait = config.getInteger(Config.NETWORK_UPDATE_INTERVAL, 0)
- * 24 * 60 * 60 * 1000;
+ long wait = config.getInteger(Config.NETWORK_UPDATE_INTERVAL, 0) * 24 * 60 * 60 * 1000;
if (wait >= 0) {
- String lastUpString = IOUtils.readSmallFile(new File(configDir,
- "LAST_UPDATE"));
- long delay = new Date().getTime()
- - Long.parseLong(lastUpString);
+ String lastUpString = IOUtils.readSmallFile(new File(configDir, "LAST_UPDATE"));
+ long delay = new Date().getTime() - Long.parseLong(lastUpString);
if (delay > wait) {
return true;
}
/**
* Notify that we checked for a new version of Fanfix.
*/
- public static void setVersionChecked() {
+ public void setVersionChecked() {
try {
- IOUtils.writeSmallFile(new File(configDir), "LAST_UPDATE",
- Long.toString(new Date().getTime()));
+ IOUtils.writeSmallFile(new File(configDir), "LAST_UPDATE", Long.toString(new Date().getTime()));
} catch (IOException e) {
tracer.error(e);
}
*
* @return the facility
*/
- public static TempFiles getTempFiles() {
+ public TempFiles getTempFiles() {
return tempFiles;
}
/**
- * The configuration directory (will check, in order of preference, the
- * system properties, the environment and then defaults to
+ * The configuration directory (will check, in order of preference, the system
+ * properties, the environment and then defaults to
* {@link Instance#getHome()}/.fanfix).
*
* @return the config directory
*/
- private static String getConfigDir() {
+ private String getConfigDir() {
String configDir = System.getProperty("CONFIG_DIR");
if (configDir == null) {
* {@link Instance#uiconfig}, {@link Instance#trans} and
* {@link Instance#transGui}).
*
- * @param configDir
- * the directory where to find the configuration files
- * @param refresh
- * TRUE to reset the configuration files from the default
- * included ones
+ * @param configDir the directory where to find the configuration files
+ * @param refresh TRUE to reset the configuration files from the default
+ * included ones
*/
- private static void createConfigs(String configDir, boolean refresh) {
+ private void createConfigs(String configDir, boolean refresh) {
if (!refresh) {
Bundles.setDirectory(configDir);
}
/**
* Create the default library as specified by the config.
*
- * @param remoteDir
- * the base remote directory if needed
+ * @param remoteDir the base remote directory if needed
*
* @return the default {@link BasicLibrary}
*/
- private static BasicLibrary createDefaultLibrary(File remoteDir) {
+ private BasicLibrary createDefaultLibrary(File remoteDir) {
BasicLibrary lib = null;
- boolean useRemote = config.getBoolean(Config.REMOTE_LIBRARY_ENABLED,
- false);
+ boolean useRemote = config.getBoolean(Config.REMOTE_LIBRARY_ENABLED, false);
if (useRemote) {
String host = null;
tracer.trace("Selecting remote library " + host + ":" + port);
lib = new RemoteLibrary(key, host, port);
- lib = new CacheLibrary(getRemoteDir(remoteDir, host), lib);
+ lib = new CacheLibrary(getRemoteDir(remoteDir, host), lib, uiconfig);
} catch (Exception e) {
- tracer.error(new IOException(
- "Cannot create remote library for: " + host + ":"
- + port, e));
+ tracer.error(new IOException("Cannot create remote library for: " + host + ":" + port, e));
}
} else {
String libDir = System.getenv("BOOKS_DIR");
}
}
try {
- lib = new LocalLibrary(getFile(libDir));
+ lib = new LocalLibrary(getFile(libDir), config);
} catch (Exception e) {
- tracer.error(new IOException(
- "Cannot create library for directory: "
- + getFile(libDir), e));
+ tracer.error(new IOException("Cannot create library for directory: " + getFile(libDir), e));
}
}
/**
* Return a path, but support the special $HOME variable.
*
- * @return the path
+ * @param id the key for the path, which may contain "$HOME"
+ * @param def the default value if none
+ * @return the path, with expanded "$HOME" if needed
*/
- private static File getFile(Config id, File def) {
+ protected File getFile(Config id, File def) {
String path = config.getString(id, def.getPath());
return getFile(path);
}
/**
* Return a path, but support the special $HOME variable.
*
- * @return the path
+ * @param id the key for the path, which may contain "$HOME"
+ * @param def the default value if none
+ * @return the path, with expanded "$HOME" if needed
*/
- private static File getFile(UiConfig id, File def) {
+ protected File getFile(UiConfig id, File def) {
String path = uiconfig.getString(id, def.getPath());
return getFile(path);
}
/**
* Return a path, but support the special $HOME variable.
*
- * @return the path
+ * @param path the path, which may contain "$HOME"
+ * @return the path, with expanded "$HOME" if needed
*/
- private static File getFile(String path) {
+ protected File getFile(String path) {
File file = null;
if (path != null && !path.isEmpty()) {
path = path.replace('/', File.separatorChar);
* properties.
* <p>
* The environment variable is tested first. Then, the custom property
- * "fanfix.home" is tried, followed by the usual "user.home" then
- * "java.io.tmp" if nothing else is found.
+ * "fanfix.home" is tried, followed by the usual "user.home" then "java.io.tmp"
+ * if nothing else is found.
*
* @return the home
*/
- private static String getHome() {
+ protected String getHome() {
String home = System.getenv("FANFIX_DIR");
if (home != null && new File(home).isFile()) {
home = null;
*
* @return the language
*/
- private static String getLang() {
+ protected String getLang() {
String lang = config.getString(Config.LANG);
if (lang == null || lang.isEmpty()) {
- if (System.getenv("LANG") != null
- && !System.getenv("LANG").isEmpty()) {
+ if (System.getenv("LANG") != null && !System.getenv("LANG").isEmpty()) {
lang = System.getenv("LANG");
}
}
/**
* Check that the given environment variable is "enabled".
*
- * @param key
- * the variable to check
+ * @param key the variable to check
*
* @return TRUE if it is
*/
- private static Boolean checkEnv(String key) {
+ protected Boolean checkEnv(String key) {
String value = System.getenv(key);
if (value != null) {
value = value.trim().toLowerCase();
- if ("yes".equals(value) || "true".equals(value)
- || "on".equals(value) || "1".equals(value)
+ if ("yes".equals(value) || "true".equals(value) || "on".equals(value) || "1".equals(value)
|| "y".equals(value)) {
return true;
}
import javax.net.ssl.SSLException;
import be.nikiroo.fanfix.bundles.Config;
- import be.nikiroo.fanfix.bundles.ConfigBundle;
import be.nikiroo.fanfix.bundles.StringId;
- import be.nikiroo.fanfix.bundles.StringIdBundle;
import be.nikiroo.fanfix.data.Chapter;
import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.data.Story;
import be.nikiroo.fanfix.supported.SupportType;
import be.nikiroo.utils.Progress;
import be.nikiroo.utils.Version;
- import be.nikiroo.utils.resources.Bundles;
- import be.nikiroo.utils.resources.TransBundle;
import be.nikiroo.utils.serial.server.ServerObject;
/**
action = MainAction.valueOf(args[i].substring(2)
.toUpperCase().replace("-", "_"));
} catch (Exception e) {
- Instance.getTraceHandler().error(
- new IllegalArgumentException("Unknown action: "
- + args[i], e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IllegalArgumentException("Unknown action: " + args[i], e));
exitCode = 255;
}
}
searchOn = SupportType.valueOfAllOkUC(args[i]);
if (searchOn == null) {
- Instance.getTraceHandler().error(
- "Website not known: <" + args[i] + ">");
+ Instance.getInstance().getTraceHandler().error("Website not known: <" + args[i] + ">");
exitCode = 41;
break;
}
if (BasicSearchable.getSearchable(searchOn) == null) {
- Instance.getTraceHandler().error(
- "Website not supported: " + searchOn);
+ Instance.getInstance().getTraceHandler().error("Website not supported: " + searchOn);
exitCode = 42;
break;
}
searchOn = SupportType.valueOfAllOkUC(args[i]);
if (searchOn == null) {
- Instance.getTraceHandler().error(
- "Website not known: <" + args[i] + ">");
+ Instance.getInstance().getTraceHandler().error("Website not known: <" + args[i] + ">");
exitCode = 255;
}
if (BasicSearchable.getSearchable(searchOn) == null) {
- Instance.getTraceHandler().error(
- "Website not supported: " + searchOn);
+ Instance.getInstance().getTraceHandler().error("Website not supported: " + searchOn);
exitCode = 255;
}
} else if (page == null && item == null) {
int index = Integer.parseInt(args[i]);
tags.add(index);
} catch (NumberFormatException e) {
- Instance.getTraceHandler().error(
- "Invalid tag index: " + args[i]);
+ Instance.getInstance().getTraceHandler().error("Invalid tag index: " + args[i]);
exitCode = 255;
}
}
port = Integer.parseInt(args[i]);
BasicLibrary lib = new RemoteLibrary(key, host, port);
- lib = new CacheLibrary(Instance.getRemoteDir(host), lib);
+ lib = new CacheLibrary(Instance.getInstance().getRemoteDir(host), lib,
+ Instance.getInstance().getUiConfig());
BasicReader.setDefaultLibrary(lib);
break;
case LIST:
if (BasicReader.getReader() == null) {
- Instance.getTraceHandler()
- .error(new Exception(
- "No reader type has been configured"));
+ Instance.getInstance().getTraceHandler().error(new Exception("No reader type has been configured"));
exitCode = 10;
break;
}
break;
case SET_SOURCE:
try {
- Instance.getLibrary().changeSource(luid, sourceString, pg);
+ Instance.getInstance().getLibrary().changeSource(luid, sourceString, pg);
} catch (IOException e1) {
- Instance.getTraceHandler().error(e1);
+ Instance.getInstance().getTraceHandler().error(e1);
exitCode = 21;
}
break;
case SET_TITLE:
try {
- Instance.getLibrary().changeTitle(luid, titleString, pg);
+ Instance.getInstance().getLibrary().changeTitle(luid, titleString, pg);
} catch (IOException e1) {
- Instance.getTraceHandler().error(e1);
+ Instance.getInstance().getTraceHandler().error(e1);
exitCode = 22;
}
break;
case SET_AUTHOR:
try {
- Instance.getLibrary().changeAuthor(luid, authorString, pg);
+ Instance.getInstance().getLibrary().changeAuthor(luid, authorString, pg);
} catch (IOException e1) {
- Instance.getTraceHandler().error(e1);
+ Instance.getInstance().getTraceHandler().error(e1);
exitCode = 23;
}
break;
case READ:
if (BasicReader.getReader() == null) {
- Instance.getTraceHandler()
- .error(new Exception(
- "No reader type has been configured"));
+ Instance.getInstance().getTraceHandler().error(new Exception("No reader type has been configured"));
exitCode = 10;
break;
}
break;
case READ_URL:
if (BasicReader.getReader() == null) {
- Instance.getTraceHandler()
- .error(new Exception(
- "No reader type has been configured"));
+ Instance.getInstance().getTraceHandler().error(new Exception("No reader type has been configured"));
exitCode = 10;
break;
}
case SEARCH:
page = page == null ? 1 : page;
if (page < 0) {
- Instance.getTraceHandler().error("Incorrect page number");
+ Instance.getInstance().getTraceHandler().error("Incorrect page number");
exitCode = 255;
break;
}
item = item == null ? 0 : item;
if (item < 0) {
- Instance.getTraceHandler().error("Incorrect item number");
+ Instance.getInstance().getTraceHandler().error("Incorrect item number");
exitCode = 255;
break;
}
if (BasicReader.getReader() == null) {
- Instance.getTraceHandler()
- .error(new Exception(
- "No reader type has been configured"));
+ Instance.getInstance().getTraceHandler().error(new Exception("No reader type has been configured"));
exitCode = 10;
break;
}
exitCode = 255;
}
} catch (IOException e1) {
- Instance.getTraceHandler().error(e1);
+ Instance.getInstance().getTraceHandler().error(e1);
exitCode = 20;
}
page = page == null ? 1 : page;
if (page < 0) {
- Instance.getTraceHandler().error("Incorrect page number");
+ Instance.getInstance().getTraceHandler().error("Incorrect page number");
exitCode = 255;
break;
}
item = item == null ? 0 : item;
if (item < 0) {
- Instance.getTraceHandler().error("Incorrect item number");
+ Instance.getInstance().getTraceHandler().error("Incorrect item number");
exitCode = 255;
break;
}
if (BasicReader.getReader() == null) {
- Instance.getTraceHandler()
- .error(new Exception(
- "No reader type has been configured"));
+ Instance.getInstance().getTraceHandler().error(new Exception("No reader type has been configured"));
exitCode = 10;
break;
}
BasicReader.getReader().searchTag(searchOn, page, item,
true, tags.toArray(new Integer[] {}));
} catch (IOException e1) {
- Instance.getTraceHandler().error(e1);
+ Instance.getInstance().getTraceHandler().error(e1);
}
break;
break;
case START:
if (BasicReader.getReader() == null) {
- Instance.getTraceHandler()
- .error(new Exception(
- "No reader type has been configured"));
+ Instance.getInstance().getTraceHandler().error(new Exception("No reader type has been configured"));
exitCode = 10;
break;
}
try {
BasicReader.getReader().browse(null);
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
exitCode = 66;
}
break;
case SERVER:
- key = Instance.getConfig().getString(Config.SERVER_KEY);
- port = Instance.getConfig().getInteger(Config.SERVER_PORT);
+ key = Instance.getInstance().getConfig().getString(Config.SERVER_KEY);
+ port = Instance.getInstance().getConfig().getInteger(Config.SERVER_PORT);
if (port == null) {
System.err.println("No port configured in the config file");
exitCode = 15;
}
try {
ServerObject server = new RemoteLibraryServer(key, port);
- server.setTraceHandler(Instance.getTraceHandler());
+ server.setTraceHandler(Instance.getInstance().getTraceHandler());
server.run();
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
return;
case STOP_SERVER:
- key = Instance.getConfig().getString(Config.SERVER_KEY);
- port = Instance.getConfig().getInteger(Config.SERVER_PORT);
+ // Can be given via "--remote XX XX XX"
+ if (key == null)
+ key = Instance.getInstance().getConfig().getString(Config.SERVER_KEY);
+ if (port == null)
+ port = Instance.getInstance().getConfig().getInteger(Config.SERVER_PORT);
+
if (port == null) {
- System.err.println("No port configured in the config file");
+ System.err.println("No port given nor configured in the config file");
exitCode = 15;
break;
}
try {
new RemoteLibrary(key, host, port).exit();
} catch (SSLException e) {
- Instance.getTraceHandler().error(
+ Instance.getInstance().getTraceHandler().error(
"Bad access key for remote library");
exitCode = 43;
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
exitCode = 44;
}
}
try {
- Instance.getTempFiles().close();
+ Instance.getInstance().getTempFiles().close();
} catch (IOException e) {
- Instance.getTraceHandler()
- .error(new IOException(
- "Cannot dispose of the temporary files", e));
+ Instance.getInstance().getTraceHandler().error(new IOException("Cannot dispose of the temporary files", e));
}
if (exitCode == 255) {
*/
public static int imprt(String urlString, Progress pg) {
try {
- MetaData meta = Instance.getLibrary().imprt(
- BasicReader.getUrl(urlString), pg);
- System.out.println(meta.getLuid() + ": \"" + meta.getTitle()
- + "\" imported.");
+ MetaData meta = Instance.getInstance().getLibrary().imprt(BasicReader.getUrl(urlString), pg);
+ System.out.println(meta.getLuid() + ": \"" + meta.getTitle() + "\" imported.");
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
return 1;
}
Progress pg) {
OutputType type = OutputType.valueOfNullOkUC(typeString, null);
if (type == null) {
- Instance.getTraceHandler().error(
- new Exception(trans(StringId.OUTPUT_DESC, typeString)));
+ Instance.getInstance().getTraceHandler().error(new Exception(trans(StringId.OUTPUT_DESC, typeString)));
return 1;
}
try {
- Instance.getLibrary().export(luid, type, target, pg);
+ Instance.getInstance().getLibrary().export(luid, type, target, pg);
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
return 4;
}
try {
BasicReader.getReader().browse(source);
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
return 66;
}
reader.setChapter(Integer.parseInt(chapString));
reader.read(true);
} catch (NumberFormatException e) {
- Instance.getTraceHandler().error(
- new IOException("Chapter number cannot be parsed: "
- + chapString, e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Chapter number cannot be parsed: " + chapString, e));
return 2;
}
} else {
reader.read(true);
}
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
return 1;
}
String target, boolean infoCover, Progress pg) {
int exitCode = 0;
- Instance.getTraceHandler().trace("Convert: " + urlString);
+ Instance.getInstance().getTraceHandler().trace("Convert: " + urlString);
String sourceName = urlString;
try {
URL source = BasicReader.getUrl(urlString);
OutputType type = OutputType.valueOfAllOkUC(typeString, null);
if (type == null) {
- Instance.getTraceHandler().error(
- new IOException(trans(StringId.ERR_BAD_OUTPUT_TYPE,
- typeString)));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException(trans(StringId.ERR_BAD_OUTPUT_TYPE, typeString)));
exitCode = 2;
} else {
BasicSupport support = BasicSupport.getSupport(source);
if (support != null) {
- Instance.getTraceHandler().trace(
- "Support found: " + support.getClass());
+ Instance.getInstance().getTraceHandler().trace("Support found: " + support.getClass());
Progress pgIn = new Progress();
Progress pgOut = new Progress();
if (pg != null) {
Story story = support.process(pgIn);
try {
target = new File(target).getAbsolutePath();
- BasicOutput.getOutput(type, infoCover, infoCover)
- .process(story, target, pgOut);
+ BasicOutput.getOutput(type, infoCover, infoCover).process(story, target, pgOut);
} catch (IOException e) {
- Instance.getTraceHandler().error(
- new IOException(trans(StringId.ERR_SAVING,
- target), e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException(trans(StringId.ERR_SAVING, target), e));
exitCode = 5;
}
} else {
- Instance.getTraceHandler().error(
- new IOException(trans(
- StringId.ERR_NOT_SUPPORTED, source)));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException(trans( StringId.ERR_NOT_SUPPORTED, source)));
exitCode = 4;
}
} catch (IOException e) {
- Instance.getTraceHandler().error(
- new IOException(trans(StringId.ERR_LOADING,
- sourceName), e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException(trans(StringId.ERR_LOADING, sourceName), e));
exitCode = 3;
}
}
} catch (MalformedURLException e) {
- Instance.getTraceHandler()
- .error(new IOException(trans(StringId.ERR_BAD_URL,
- sourceName), e));
+ Instance.getInstance().getTraceHandler().error(new IOException(trans(StringId.ERR_BAD_URL, sourceName), e));
exitCode = 1;
}
* @return the translated result
*/
private static String trans(StringId id, Object... params) {
- return Instance.getTrans().getString(id, params);
+ return Instance.getInstance().getTrans().getString(id, params);
}
/**
BasicReader.setDefaultReaderType(readerType);
return 0;
} catch (IllegalArgumentException e) {
- Instance.getTraceHandler().error(
- new IOException("Unknown reader type: " + readerTypeString,
- e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Unknown reader type: " + readerTypeString, e));
return 1;
}
}
* time has elapsed.
*/
public void ok() {
- Instance.setVersionChecked();
+ Instance.getInstance().setVersionChecked();
}
/**
List<Version> newer = new ArrayList<Version>();
Map<Version, List<String>> changes = new HashMap<Version, List<String>>();
- if (Instance.isVersionCheckNeeded()) {
+ if (Instance.getInstance().isVersionCheckNeeded()) {
try {
// Prepare the URLs according to the user's language
- Locale lang = Instance.getTrans().getLocale();
+ Locale lang = Instance.getInstance().getTrans().getLocale();
String fr = lang.getLanguage();
String BE = lang.getCountry().replace(".UTF8", "");
String urlFrBE = base.replace("${LANG}", "-" + fr + "_" + BE);
InputStream in = null;
for (String url : new String[] { urlFrBE, urlFr, urlDefault }) {
try {
- in = Instance.getCache()
- .open(new URL(url), null, false);
+ in = Instance.getInstance().getCache().open(new URL(url), null, false);
break;
} catch (IOException e) {
}
reader.close();
}
} catch (IOException e) {
- Instance.getTraceHandler()
- .error(new IOException(
- "Cannot download latest changelist on github.com",
- e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Cannot download latest changelist on github.com", e));
}
}
INPUT_DESC_FIMFICTION = Fanfictions devoted to the My Little Pony show
# Description of this input type
# (FORMAT: STRING)
- INPUT_DESC_MANGAFOX = A well filled repository of mangas, or, as their website states: \n\
- \tMost popular manga scanlations read online for free at mangafox, \n\
- \tas well as a close-knit community to chat and make friends.
+ INPUT_DESC_MANGAHUB = A well filled repository of mangas, in English
# Description of this input type
# (FORMAT: STRING)
INPUT_DESC_E621 = Furry website supporting comics, including MLP
INPUT_DESC_FIMFICTION = Fanfictions dévouées à la série My Little Pony
# Description of this input type
# (FORMAT: STRING)
- INPUT_DESC_MANGAFOX = Un site répertoriant une quantité non négligeable de mangas
+ INPUT_DESC_MANGAHUB = Un site répertoriant une quantité non négligeable de mangas, en anglais
# Description of this input type
# (FORMAT: STRING)
INPUT_DESC_E621 = Un site Furry proposant des comics, y compris de MLP
*/
public abstract Image getCover(String luid) throws IOException;
+ // TODO: ensure it is the main used interface
+ public synchronized MetaResultList getList(Progress pg) throws IOException {
+ return new MetaResultList(getMetas(pg));
+ }
+
+ //TODO: make something for (normal and custom) not-story covers
+
/**
* Return the cover image associated to this source.
* <p>
return custom;
}
- List<MetaData> metas = getListBySource(source);
+ List<MetaData> metas = getList().filter(source, null, null);
if (metas.size() > 0) {
return getCover(metas.get(0).getLuid());
}
return custom;
}
- List<MetaData> metas = getListByAuthor(author);
+ List<MetaData> metas = getList().filter(null, author, null);
if (metas.size() > 0) {
return getCover(metas.get(0).getLuid());
}
/**
* Return the list of stories (represented by their {@link MetaData}, which
* <b>MAY</b> not have the cover included).
+ * <p>
+ * The returned list <b>MUST</b> be a copy, not the original one.
*
* @param pg
* the optional {@link Progress}
* @param pg
* the optional progress reporter
*/
- public void refresh(Progress pg) {
+ public synchronized void refresh(Progress pg) {
try {
getMetas(pg);
} catch (IOException e) {
// We will let it fail later
}
}
+
+ /**
+ * Check if the {@link Story} denoted by this Library UID is present in the
+ * cache (if we have no cache, we default to </t>true</tt>).
+ *
+ * @param luid
+ * the Library UID
+ *
+ * @return TRUE if it is
+ */
+ public boolean isCached(String luid) {
+ // By default, everything is cached
+ return true;
+ }
+
+ /**
+ * Clear the {@link Story} from the cache, if needed.
+ * <p>
+ * The next time we try to retrieve the {@link Story}, it may be required to
+ * cache it again.
+ *
+ * @param luid
+ * the story to clear
+ *
+ * @throws IOException
+ * in case of I/O error
+ */
+ public void clearFromCache(String luid) throws IOException {
+ // By default, this is a noop.
+ }
/**
* List all the known types (sources) of stories.
* @throws IOException
* in case of IOException
*/
- public synchronized List<MetaData> getList() throws IOException {
- return getMetas(null);
- }
-
- /**
- * List all the stories of the given source type in the {@link BasicLibrary}
- * , or all the stories if NULL is passed as a type.
- * <p>
- * Cover images not included.
- *
- * @param type
- * the type of story to retrieve, or NULL for all
- *
- * @return the stories
- *
- * @throws IOException
- * in case of IOException
- */
- public synchronized List<MetaData> getListBySource(String type)
- throws IOException {
- List<MetaData> list = new ArrayList<MetaData>();
- for (MetaData meta : getMetas(null)) {
- String storyType = meta.getSource();
- if (type == null || type.equalsIgnoreCase(storyType)) {
- list.add(meta);
- }
- }
-
- Collections.sort(list);
- return list;
- }
-
- /**
- * List all the stories of the given author in the {@link BasicLibrary}, or
- * all the stories if NULL is passed as an author.
- * <p>
- * Cover images not included.
- *
- * @param author
- * the author of the stories to retrieve, or NULL for all
- *
- * @return the stories
- *
- * @throws IOException
- * in case of IOException
- */
- public synchronized List<MetaData> getListByAuthor(String author)
- throws IOException {
- List<MetaData> list = new ArrayList<MetaData>();
- for (MetaData meta : getMetas(null)) {
- String storyAuthor = meta.getAuthor();
- if (author == null || author.equalsIgnoreCase(storyAuthor)) {
- list.add(meta);
- }
- }
-
- Collections.sort(list);
- return list;
+ public MetaResultList getList() throws IOException {
+ return getList(null);
}
/**
} catch (IOException e) {
// We should not have not-supported files in the
// library
- Instance.getTraceHandler().error(
- new IOException(String.format(
- "Cannot load file of type '%s' from library: %s",
- meta.getType(), file), e));
+ Instance.getInstance().getTraceHandler().error(new IOException(
+ String.format("Cannot load file of type '%s' from library: %s", meta.getType(), file), e));
} finally {
pgProcess.done();
pg.done();
public synchronized Story save(Story story, String luid, Progress pg)
throws IOException {
- Instance.getTraceHandler().trace(
- this.getClass().getSimpleName() + ": saving story " + luid);
+ Instance.getInstance().getTraceHandler().trace(this.getClass().getSimpleName() + ": saving story " + luid);
// Do not change the original metadata, but change the original story
MetaData meta = story.getMeta().clone();
updateInfo(story.getMeta());
- Instance.getTraceHandler().trace(
- this.getClass().getSimpleName() + ": story saved (" + luid
- + ")");
+ Instance.getInstance().getTraceHandler()
+ .trace(this.getClass().getSimpleName() + ": story saved (" + luid + ")");
return story;
}
* in case of I/O error
*/
public synchronized void delete(String luid) throws IOException {
- Instance.getTraceHandler().trace(
- this.getClass().getSimpleName() + ": deleting story " + luid);
+ Instance.getInstance().getTraceHandler().trace(this.getClass().getSimpleName() + ": deleting story " + luid);
doDelete(luid);
invalidateInfo(luid);
- Instance.getTraceHandler().trace(
- this.getClass().getSimpleName() + ": story deleted (" + luid
+ Instance.getInstance().getTraceHandler()
+ .trace(this.getClass().getSimpleName() + ": story deleted (" + luid
+ ")");
}
meta.setTitle(newTitle);
meta.setAuthor(newAuthor);
saveMeta(meta, pg);
-
- invalidateInfo(luid);
}
/**
import java.io.File;
import java.io.IOException;
import java.net.URL;
+ import java.util.ArrayList;
import java.util.List;
+ import java.util.TreeSet;
import be.nikiroo.fanfix.Instance;
import be.nikiroo.fanfix.bundles.UiConfig;
+ import be.nikiroo.fanfix.bundles.UiConfigBundle;
import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.data.Story;
+ import be.nikiroo.fanfix.output.BasicOutput.OutputType;
import be.nikiroo.utils.Image;
import be.nikiroo.utils.Progress;
* @author niki
*/
public class CacheLibrary extends BasicLibrary {
- private List<MetaData> metas;
+ private List<MetaData> metasReal;
+ private List<MetaData> metasMixed;
private BasicLibrary lib;
private LocalLibrary cacheLib;
/**
* Create a cache library around the given one.
* <p>
- * It will return the same result, but those will be saved to disk at the
- * same time to be fetched quicker the next time.
+ * It will return the same result, but those will be saved to disk at the same
+ * time to be fetched quicker the next time.
*
- * @param cacheDir
- * the cache directory where to save the files to disk
- * @param lib
- * the original library to wrap
+ * @param cacheDir the cache directory where to save the files to disk
+ * @param lib the original library to wrap
+ * @param config the configuration used to know which kind of default
+ * {@link OutputType} to use for images and non-images stories
*/
- public CacheLibrary(File cacheDir, BasicLibrary lib) {
- this.cacheLib = new LocalLibrary(cacheDir, Instance.getUiConfig()
- .getString(UiConfig.GUI_NON_IMAGES_DOCUMENT_TYPE), Instance
- .getUiConfig().getString(UiConfig.GUI_IMAGES_DOCUMENT_TYPE),
- true);
+ public CacheLibrary(File cacheDir, BasicLibrary lib, UiConfigBundle config) {
+ this.cacheLib = new LocalLibrary(cacheDir, //
+ config.getString(UiConfig.GUI_NON_IMAGES_DOCUMENT_TYPE),
+ config.getString(UiConfig.GUI_IMAGES_DOCUMENT_TYPE), true);
this.lib = lib;
}
}
@Override
- protected List<MetaData> getMetas(Progress pg) throws IOException {
+ protected synchronized List<MetaData> getMetas(Progress pg) throws IOException {
+ // We make sure that cached metas have precedence
+
if (pg == null) {
pg = new Progress();
}
- if (metas == null) {
- metas = lib.getMetas(pg);
+ if (metasMixed == null) {
+ if (metasReal == null) {
+ metasReal = lib.getMetas(pg);
+ }
+
+ metasMixed = new ArrayList<MetaData>();
+ TreeSet<String> cachedLuids = new TreeSet<String>();
+ for (MetaData cachedMeta : cacheLib.getMetas(null)) {
+ metasMixed.add(cachedMeta);
+ cachedLuids.add(cachedMeta.getLuid());
+ }
+ for (MetaData realMeta : metasReal) {
+ if (!cachedLuids.contains(realMeta.getLuid())) {
+ metasMixed.add(realMeta);
+ }
+ }
}
pg.done();
- return metas;
+ return new ArrayList<MetaData>(metasMixed);
}
@Override
- public synchronized MetaData getInfo(String luid) throws IOException {
- MetaData info = cacheLib.getInfo(luid);
- if (info == null) {
- info = lib.getInfo(luid);
- }
-
- return info;
- }
-
- @Override
- public synchronized Story getStory(String luid, MetaData meta, Progress pg)
- throws IOException {
+ public synchronized Story getStory(String luid, MetaData meta, Progress pg) throws IOException {
if (pg == null) {
pg = new Progress();
}
if (!isCached(luid)) {
try {
cacheLib.imprt(lib, luid, pgImport);
- updateInfo(cacheLib.getInfo(luid));
+ updateMetaCache(metasMixed, cacheLib.getInfo(luid));
pgImport.done();
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
pgImport.done();
}
@Override
- public synchronized File getFile(final String luid, Progress pg)
- throws IOException {
+ public synchronized File getFile(final String luid, Progress pg) throws IOException {
if (pg == null) {
pg = new Progress();
}
cacheLib.setAuthorCover(author, getCover(luid));
}
+ /**
+ * Invalidate the {@link Story} cache (when the content has changed, but we
+ * already have it) with the new given meta.
+ * <p>
+ * <b>Make sure to always use {@link MetaData} from the cached library
+ * in priority, here.</b>
+ *
+ * @param meta
+ * the {@link Story} to clear from the cache
+ *
+ * @throws IOException
+ * in case of IOException
+ */
@Override
+ @Deprecated
protected void updateInfo(MetaData meta) throws IOException {
+ throw new IOException(
+ "This method is not supported in a CacheLibrary, please use updateMetaCache");
+ }
+
+ // relplace the meta in Metas by Meta, add it if needed
+ // return TRUE = added
+ private boolean updateMetaCache(List<MetaData> metas, MetaData meta) {
if (meta != null && metas != null) {
boolean changed = false;
for (int i = 0; i < metas.size(); i++) {
if (!changed) {
metas.add(meta);
+ return true;
}
}
-
- cacheLib.updateInfo(meta);
- lib.updateInfo(meta);
+
+ return false;
}
@Override
protected void invalidateInfo(String luid) {
if (luid == null) {
- metas = null;
- } else if (metas != null) {
+ metasReal = null;
+ metasMixed = null;
+ } else {
+ invalidateInfo(metasReal, luid);
+ invalidateInfo(metasMixed, luid);
+ }
+
+ cacheLib.invalidateInfo(luid);
+ lib.invalidateInfo(luid);
+ }
+
+ // luid cannot be null
+ private void invalidateInfo(List<MetaData> metas, String luid) {
+ if (metas != null) {
for (int i = 0; i < metas.size(); i++) {
if (metas.get(i).getLuid().equals(luid)) {
metas.remove(i--);
}
}
}
-
- cacheLib.invalidateInfo(luid);
- lib.invalidateInfo(luid);
}
@Override
- public synchronized Story save(Story story, String luid, Progress pg)
- throws IOException {
+ public synchronized Story save(Story story, String luid, Progress pg) throws IOException {
Progress pgLib = new Progress();
Progress pgCacheLib = new Progress();
pg.addProgress(pgCacheLib, 1);
story = lib.save(story, luid, pgLib);
+ updateMetaCache(metasReal, story.getMeta());
+
story = cacheLib.save(story, story.getMeta().getLuid(), pgCacheLib);
-
- updateInfo(story.getMeta());
+ updateMetaCache(metasMixed, story.getMeta());
return story;
}
}
@Override
- protected synchronized void changeSTA(String luid, String newSource,
- String newTitle, String newAuthor, Progress pg) throws IOException {
+ protected synchronized void changeSTA(String luid, String newSource, String newTitle, String newAuthor, Progress pg)
+ throws IOException {
if (pg == null) {
pg = new Progress();
}
meta.setAuthor(newAuthor);
pg.done();
- invalidateInfo(luid);
+ if (isCached(luid)) {
+ updateMetaCache(metasMixed, meta);
+ updateMetaCache(metasReal, lib.getInfo(luid));
+ } else {
+ updateMetaCache(metasReal, meta);
+ }
}
- /**
- * Check if the {@link Story} denoted by this Library UID is present in the
- * cache.
- *
- * @param luid
- * the Library UID
- *
- * @return TRUE if it is
- */
+ @Override
public boolean isCached(String luid) {
try {
return cacheLib.getInfo(luid) != null;
}
}
- /**
- * Clear the {@link Story} from the cache.
- * <p>
- * The next time we try to retrieve the {@link Story}, it may be required to
- * cache it again.
- *
- * @param luid
- * the story to clear
- *
- * @throws IOException
- * in case of I/O error
- */
+ @Override
public void clearFromCache(String luid) throws IOException {
if (isCached(luid)) {
cacheLib.delete(luid);
}
@Override
- public MetaData imprt(URL url, Progress pg) throws IOException {
+ public synchronized MetaData imprt(URL url, Progress pg) throws IOException {
if (pg == null) {
pg = new Progress();
}
pg.addProgress(pgCache, 3);
MetaData meta = lib.imprt(url, pgImprt);
- updateInfo(meta);
-
+ updateMetaCache(metasReal, meta);
+ metasMixed = null;
clearFromCache(meta.getLuid());
-
+
pg.done();
return meta;
}
import be.nikiroo.fanfix.Instance;
import be.nikiroo.fanfix.bundles.Config;
+ import be.nikiroo.fanfix.bundles.ConfigBundle;
+ import be.nikiroo.fanfix.bundles.UiConfigBundle;
import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.data.Story;
import be.nikiroo.fanfix.output.BasicOutput;
/**
* Create a new {@link LocalLibrary} with the given back-end directory.
*
- * @param baseDir
- * the directory where to find the {@link Story} objects
+ * @param baseDir the directory where to find the {@link Story} objects
+ * @param config the configuration used to know which kind of default
+ * {@link OutputType} to use for images and non-images stories
*/
- public LocalLibrary(File baseDir) {
- this(baseDir, Instance.getConfig().getString(
- Config.FILE_FORMAT_NON_IMAGES_DOCUMENT_TYPE), Instance.getConfig()
- .getString(Config.FILE_FORMAT_IMAGES_DOCUMENT_TYPE), false);
+ public LocalLibrary(File baseDir, ConfigBundle config) {
+ this(baseDir, //
+ config.getString(Config.FILE_FORMAT_NON_IMAGES_DOCUMENT_TYPE),
+ config.getString(Config.FILE_FORMAT_IMAGES_DOCUMENT_TYPE), false);
}
/**
}
@Override
- protected List<MetaData> getMetas(Progress pg) {
+ protected synchronized List<MetaData> getMetas(Progress pg) {
return new ArrayList<MetaData>(getStories(pg).keySet());
}
@Override
public File getFile(String luid, Progress pg) throws IOException {
- Instance.getTraceHandler().trace(
- this.getClass().getSimpleName() + ": get file for " + luid);
+ Instance.getInstance().getTraceHandler().trace(this.getClass().getSimpleName() + ": get file for " + luid);
File file = null;
String mess = "no file found for ";
file = files[1];
}
- Instance.getTraceHandler().trace(
- this.getClass().getSimpleName() + ": " + mess + luid + " ("
- + meta.getTitle() + ")");
+ Instance.getInstance().getTraceHandler()
+ .trace(this.getClass().getSimpleName() + ": " + mess + luid + " (" + meta.getTitle() + ")");
return file;
}
meta = InfoReader.readMeta(infoFile, true);
return meta.getCover();
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
}
}
InfoCover.writeInfo(newDir, name, meta);
relatedFile.getParentFile().delete();
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
} else {
relatedFile.renameTo(new File(newDir, relatedFile.getName()));
}
}
- invalidateInfo();
+ updateInfo(meta);
}
@Override
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
- Instance.getTraceHandler().error(
- new IOException(
- "Cannot load the existing custom source cover: "
- + cover, e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Cannot load the existing custom source cover: " + cover, e));
}
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
- Instance.getTraceHandler().error(
- new IOException(
- "Cannot load the existing custom author cover: "
- + cover, e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Cannot load the existing custom author cover: " + cover, e));
}
}
dir.mkdirs();
File cover = new File(dir, ".cover");
try {
- Instance.getCache().saveAsImage(coverImage, cover, true);
+ Instance.getInstance().getCache().saveAsImage(coverImage, cover, true);
if (sourceCovers != null) {
sourceCovers.put(source, coverImage);
}
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
}
File cover = getAuthorCoverFile(author);
cover.getParentFile().mkdirs();
try {
- Instance.getCache().saveAsImage(coverImage, cover, true);
+ Instance.getInstance().getCache().saveAsImage(coverImage, cover, true);
if (authorCovers != null) {
authorCovers.put(author, coverImage);
}
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
}
private File getAuthorCoverFile(String author) {
File aDir = new File(baseDir, "_AUTHORS");
String hash = StringUtils.getMd5Hash(author);
- String ext = Instance.getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER);
+ String ext = Instance.getInstance().getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER);
return new File(aDir, hash + "." + ext.toLowerCase());
}
}
String coverExt = "."
- + Instance.getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER)
- .toLowerCase();
+ + Instance.getInstance().getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase();
File coverFile = new File(path + coverExt);
if (!coverFile.exists()) {
coverFile = new File(path.substring(0,
} catch (IOException e) {
// We should not have not-supported files in the
// library
- Instance.getTraceHandler().error(
- new IOException("Cannot load file from library: "
- + infoFileOrSubdir, e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Cannot load file from library: " + infoFileOrSubdir, e));
}
}
--- /dev/null
+ package be.nikiroo.fanfix.library;
+
+ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.Collections;
+ import java.util.List;
+
+ import be.nikiroo.fanfix.data.MetaData;
+
+ public class MetaResultList {
+ private List<MetaData> metas;
+
+ // Lazy lists:
+ // TODO: sync-protect them?
+ private List<String> sources;
+ private List<String> authors;
+ private List<String> tags;
+
+ // can be null (will consider it empty)
+ public MetaResultList(List<MetaData> metas) {
+ if (metas == null) {
+ metas = new ArrayList<MetaData>();
+ }
+
+ Collections.sort(metas);
+ this.metas = metas;
+ }
+
+ // not NULL
+ // sorted
+ public List<MetaData> getMetas() {
+ return metas;
+ }
+
+ public List<String> getSources() {
+ if (sources == null) {
+ sources = new ArrayList<String>();
+ for (MetaData meta : metas) {
+ if (!sources.contains(meta.getSource()))
+ sources.add(meta.getSource());
+ }
+ }
+
+ return sources;
+ }
+
+ // A -> (A), A/ -> (A, A/*) if we can find something for "*"
+ public List<String> getSources(String source) {
+ List<String> linked = new ArrayList<String>();
+ if (source != null && !source.isEmpty()) {
+ if (!source.endsWith("/")) {
+ linked.add(source);
+ } else {
+ linked.add(source.substring(0, source.length() - 1));
+ for (String src : getSources()) {
+ if (src.startsWith(source)) {
+ linked.add(src);
+ }
+ }
+ }
+ }
+
+ return linked;
+ }
+
+ public List<String> getAuthors() {
+ if (authors == null) {
+ authors = new ArrayList<String>();
+ for (MetaData meta : metas) {
+ if (!authors.contains(meta.getAuthor()))
+ authors.add(meta.getAuthor());
+ }
+ }
+
+ return authors;
+ }
+
+ public List<String> getTags() {
+ if (tags == null) {
+ tags = new ArrayList<String>();
+ for (MetaData meta : metas) {
+ for (String tag : meta.getTags()) {
+ if (!tags.contains(tag))
+ tags.add(tag);
+ }
+ }
+ }
+
+ return authors;
+ }
+
+ // helper
+ public List<MetaData> filter(String source, String author, String tag) {
+ List<String> sources = source == null ? null : Arrays.asList(source);
+ List<String> authors = author == null ? null : Arrays.asList(author);
+ List<String> tags = tag == null ? null : Arrays.asList(tag);
+
+ return filter(sources, authors, tags);
+ }
+
+ // null or empty -> no check, rest = must be included
+ // source: a source ending in "/" means "this or any source starting with this",
+ // i;e., to enable source hierarchy
+ // + sorted
+ public List<MetaData> filter(List<String> sources, List<String> authors, List<String> tags) {
+ if (sources != null && sources.isEmpty())
+ sources = null;
+ if (authors != null && authors.isEmpty())
+ authors = null;
+ if (tags != null && tags.isEmpty())
+ tags = null;
+
+ // Quick check
+ if (sources == null && authors == null && tags == null) {
+ return metas;
+ }
+
+ // allow "sources/" hierarchy
+ if (sources != null) {
+ List<String> folders = new ArrayList<String>();
+ List<String> leaves = new ArrayList<String>();
+ for (String source : sources) {
+ if (source.endsWith("/")) {
+ if (!folders.contains(source))
+ folders.add(source);
+ } else {
+ if (!leaves.contains(source))
+ leaves.add(source);
+ }
+ }
+
+ sources = leaves;
+ for (String folder : folders) {
+ for (String otherLeaf : getSources(folder)) {
+ if (!sources.contains(otherLeaf)) {
+ sources.add(otherLeaf);
+ }
+ }
+ }
+ }
+
+ List<MetaData> result = new ArrayList<MetaData>();
+ for (MetaData meta : metas) {
+ if (sources != null && !sources.contains(meta.getSource())) {
+ continue;
+ }
+ if (authors != null && !authors.contains(meta.getAuthor())) {
+ continue;
+ }
+
+ if (tags != null) {
+ boolean keep = false;
+ for (String thisTag : meta.getTags()) {
+ if (tags.contains(thisTag))
+ keep = true;
+ }
+
+ if (!keep)
+ continue;
+ }
+
+ result.add(meta);
+ }
+
+ Collections.sort(result);
+ return result;
+ }
+ }
@Override
public Status getStatus() {
- Instance.getTraceHandler().trace("Getting remote lib status...");
+ Instance.getInstance().getTraceHandler().trace("Getting remote lib status...");
Status status = getStatusDo();
- Instance.getTraceHandler().trace("Remote lib status: " + status);
+ Instance.getInstance().getTraceHandler().trace("Remote lib status: " + status);
return status;
}
public void action(ConnectActionClientObject action)
throws Exception {
action.send(new Object[] { subkey, "EXIT" });
+ Thread.sleep(100);
}
});
}
}
@Override
- protected List<MetaData> getMetas(Progress pg) throws IOException {
+ protected synchronized List<MetaData> getMetas(Progress pg) throws IOException {
return getMetasList("*", pg);
}
@Override
protected void onError(Exception e) {
if (!(e instanceof IOException)) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
return;
}
*/
public RemoteLibraryServer(String key, int port) throws IOException {
super("Fanfix remote library", port, key);
- setTraceHandler(Instance.getTraceHandler());
+ setTraceHandler(Instance.getInstance().getTraceHandler());
}
@Override
}
}
- List<String> whitelist = Instance.getConfig().getList(
- Config.SERVER_WHITELIST);
+ List<String> whitelist = Instance.getInstance().getConfig().getList(Config.SERVER_WHITELIST);
if (whitelist == null) {
whitelist = new ArrayList<String>();
}
wl = false;
}
- rw = Instance.getConfig().getBoolean(Config.SERVER_RW, rw);
+ rw = Instance.getInstance().getConfig().getBoolean(Config.SERVER_RW, rw);
if (!subkey.isEmpty()) {
- List<String> allowed = Instance.getConfig().getList(
- Config.SERVER_ALLOWED_SUBKEYS);
+ List<String> allowed = Instance.getInstance().getConfig().getList(Config.SERVER_ALLOWED_SUBKEYS);
if (allowed.contains(subkey)) {
if ((subkey + "|").contains("|rw|")) {
rw = true;
if ("*".equals(args[0])) {
Progress pg = createPgForwarder(action);
- for (MetaData meta : Instance.getLibrary().getMetas(pg)) {
+ for (MetaData meta : Instance.getInstance().getLibrary().getMetas(pg)) {
MetaData light;
if (meta.getCover() == null) {
light = meta;
forcePgDoneSent(pg);
} else {
- MetaData meta = Instance.getLibrary().getInfo((String) args[0]);
+ MetaData meta = Instance.getInstance().getLibrary().getInfo((String) args[0]);
MetaData light;
if (meta.getCover() == null) {
light = meta;
return metas.toArray(new MetaData[0]);
} else if ("GET_STORY".equals(command)) {
- MetaData meta = Instance.getLibrary().getInfo((String) args[0]);
+ MetaData meta = Instance.getInstance().getLibrary().getInfo((String) args[0]);
if (meta == null) {
return null;
}
action.send(meta);
action.rec();
- Story story = Instance.getLibrary()
- .getStory((String) args[0], null);
+ Story story = Instance.getInstance().getLibrary().getStory((String) args[0], null);
for (Object obj : breakStory(story)) {
action.send(obj);
action.rec();
}
Story story = rebuildStory(list);
- Instance.getLibrary().save(story, (String) args[0], null);
+ Instance.getInstance().getLibrary().save(story, (String) args[0], null);
return story.getMeta().getLuid();
} else if ("IMPORT".equals(command)) {
if (!rw) {
}
Progress pg = createPgForwarder(action);
- MetaData meta = Instance.getLibrary().imprt(
- new URL((String) args[0]), pg);
+ MetaData meta = Instance.getInstance().getLibrary().imprt(new URL((String) args[0]), pg);
forcePgDoneSent(pg);
return meta.getLuid();
} else if ("DELETE_STORY".equals(command)) {
+ args[0], false);
}
- Instance.getLibrary().delete((String) args[0]);
+ Instance.getInstance().getLibrary().delete((String) args[0]);
} else if ("GET_COVER".equals(command)) {
- return Instance.getLibrary().getCover((String) args[0]);
+ return Instance.getInstance().getLibrary().getCover((String) args[0]);
} else if ("GET_CUSTOM_COVER".equals(command)) {
if ("SOURCE".equals(args[0])) {
- return Instance.getLibrary().getCustomSourceCover(
- (String) args[1]);
+ return Instance.getInstance().getLibrary().getCustomSourceCover((String) args[1]);
} else if ("AUTHOR".equals(args[0])) {
- return Instance.getLibrary().getCustomAuthorCover(
- (String) args[1]);
+ return Instance.getInstance().getLibrary().getCustomAuthorCover((String) args[1]);
} else {
return null;
}
}
if ("SOURCE".equals(args[0])) {
- Instance.getLibrary().setSourceCover((String) args[1],
- (String) args[2]);
+ Instance.getInstance().getLibrary().setSourceCover((String) args[1], (String) args[2]);
} else if ("AUTHOR".equals(args[0])) {
- Instance.getLibrary().setAuthorCover((String) args[1],
- (String) args[2]);
+ Instance.getInstance().getLibrary().setAuthorCover((String) args[1], (String) args[2]);
}
} else if ("CHANGE_STA".equals(command)) {
if (!rw) {
- throw new RemoteLibraryException("Read-Only remote library: "
- + args[0] + ", " + args[1], false);
+ throw new RemoteLibraryException("Read-Only remote library: " + args[0] + ", " + args[1], false);
}
Progress pg = createPgForwarder(action);
- Instance.getLibrary().changeSTA((String) args[0], (String) args[1],
- (String) args[2], (String) args[3], pg);
+ Instance.getInstance().getLibrary().changeSTA((String) args[0], (String) args[1], (String) args[2],
+ (String) args[3], pg);
forcePgDoneSent(pg);
} else if ("EXIT".equals(command)) {
if (!rw) {
"Read-Only remote library: EXIT", false);
}
- stop(0, false);
+ stop(10000, false);
}
return null;
StringId id = longDesc ? StringId.OUTPUT_DESC
: StringId.OUTPUT_DESC_SHORT;
- String desc = Instance.getTrans().getStringX(id, this.name());
+ String desc = Instance.getInstance().getTrans().getStringX(id, this.name());
if (desc == null) {
- desc = Instance.getTrans().getString(id, this.toString());
+ desc = Instance.getInstance().getTrans().getString(id, this.toString());
}
if (desc == null || desc.isEmpty()) {
File target = new File(targetDir, targetName);
- dir = Instance.getTempFiles().createTempDir("fanfic-reader-cbz-dir");
+ dir = Instance.getInstance().getTempFiles().createTempDir("fanfic-reader-cbz-dir");
try {
// will also save the images! (except the cover -> false)
BasicOutput
String targetNameOrig = targetName;
targetName += getDefaultExtension(false);
- tmpDir = Instance.getTempFiles().createTempDir("fanfic-reader-epub");
+ tmpDir = Instance.getInstance().getTempFiles().createTempDir("fanfic-reader-epub");
tmpDir.delete();
if (!tmpDir.mkdir()) {
if (story.getMeta() != null && story.getMeta().getCover() != null) {
File file = new File(images, "cover");
try {
- Instance.getCache().saveAsImage(story.getMeta().getCover(),
- file, true);
+ Instance.getInstance().getCache().saveAsImage(story.getMeta().getCover(), file, true);
} catch (Exception e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
}
break;
case IMAGE:
File file = new File(images, getCurrentImageBestName(false));
- Instance.getCache().saveAsImage(para.getContentImage(), file,
- nextParaIsCover);
+ Instance.getInstance().getCache().saveAsImage(para.getContentImage(), file, nextParaIsCover);
writer.write(" <img alt='page image' class='page-image' src='images/"
+ getCurrentImageBestName(false) + "'/>");
break;
private void generateNcx(Chapter chap, StringBuilder builder, int navPoint) {
String name;
if (chap.getName() != null && !chap.getName().isEmpty()) {
- name = Instance.getTrans().getString(StringId.CHAPTER_NAMED,
- chap.getNumber(), chap.getName());
+ name = Instance.getInstance().getTrans().getString(StringId.CHAPTER_NAMED, chap.getNumber(),
+ chap.getName());
} else {
- name = Instance.getTrans().getString(StringId.CHAPTER_UNNAMED,
- chap.getNumber());
+ name = Instance.getInstance().getTrans().getString(StringId.CHAPTER_UNNAMED, chap.getNumber());
}
String nnn = String.format("%03d", (navPoint - 2));
builder.append("\n <!-- Images -->");
if (story.getMeta() != null && story.getMeta().getCover() != null) {
- String format = Instance.getConfig()
+ String format = Instance.getInstance().getConfig()
.getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER)
.toLowerCase();
builder.append("\n <item id=\"cover\" href=\"images/cover."
author = meta.getAuthor();
}
- String format = Instance.getConfig()
+ String format = Instance.getInstance().getConfig()
.getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase();
builder.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
.process(story, dir, targetNameOrig);
if (story.getMeta().getCover() != null) {
- Instance.getCache().saveAsImage(story.getMeta().getCover(),
- new File(dir, "cover"), true);
+ Instance.getInstance().getCache().saveAsImage(story.getMeta().getCover(), new File(dir, "cover"), true);
}
return target;
author = meta.getAuthor();
}
- String format = Instance.getConfig()
+ String format = Instance.getInstance().getConfig()
.getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase();
InputStream inStyle = getClass().getResourceAsStream("html.style.css");
meta.isImageDocument() ? "true" : "false");
writeMeta(infoWriter, "TYPE", meta.getType());
if (meta.getCover() != null) {
- String format = Instance.getConfig()
+ String format = Instance.getInstance().getConfig()
.getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase();
writeMeta(infoWriter, "COVER", targetName + "." + format);
} else {
MetaData meta) {
if (meta != null && meta.getCover() != null) {
try {
- Instance.getCache().saveAsImage(meta.getCover(),
- new File(targetDir, targetName), true);
+ Instance.getInstance().getCache().saveAsImage(meta.getCover(), new File(targetDir, targetName), true);
} catch (IOException e) {
// Allow to continue without cover
- Instance.getTraceHandler().error(
- new IOException("Failed to save the cover image", e));
+ Instance.getInstance().getTraceHandler().error(new IOException("Failed to save the cover image", e));
}
}
}
class InfoText extends Text {
// quote chars
- private char openQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_SINGLE_QUOTE);
- private char closeQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_SINGLE_QUOTE);
- private char openDoubleQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_DOUBLE_QUOTE);
- private char closeDoubleQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_DOUBLE_QUOTE);
+ private char openQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_SINGLE_QUOTE);
+ private char closeQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_SINGLE_QUOTE);
+ private char openDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_DOUBLE_QUOTE);
+ private char closeDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_DOUBLE_QUOTE);
@Override
public String getDefaultExtension(boolean readerTarget) {
writer.write("\n");
if (chap.getName() != null && !chap.getName().isEmpty()) {
- writer.write(Instance.getTrans().getString(StringId.CHAPTER_NAMED,
- chap.getNumber(), chap.getName()));
+ writer.write(Instance.getInstance().getTrans().getString(StringId.CHAPTER_NAMED, chap.getNumber(),
+ chap.getName()));
} else {
- writer.write(Instance.getTrans().getString(
- StringId.CHAPTER_UNNAMED, chap.getNumber()));
+ writer.write(Instance.getInstance().getTrans().getString(StringId.CHAPTER_UNNAMED, chap.getNumber()));
}
writer.write("\n\n");
private boolean lastWasQuote = false;
// quote chars
- private char openQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_SINGLE_QUOTE);
- private char closeQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_SINGLE_QUOTE);
- private char openDoubleQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_DOUBLE_QUOTE);
- private char closeDoubleQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_DOUBLE_QUOTE);
+ private char openQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_SINGLE_QUOTE);
+ private char closeQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_SINGLE_QUOTE);
+ private char openDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_DOUBLE_QUOTE);
+ private char closeDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_DOUBLE_QUOTE);
@Override
public File process(Story story, File targetDir, String targetName)
author = "\\author{" + latexEncode(meta.getAuthor()) + "}";
lang = meta.getLang().toLowerCase();
if (lang != null && !lang.isEmpty()) {
- lang = Instance.getConfig().getStringX(Config.CONF_LATEX_LANG, lang);
+ lang = Instance.getInstance().getConfig().getStringX(Config.CONF_LATEX_LANG, lang);
if (lang == null) {
- System.err.println(Instance.getTrans().getString(
- StringId.LATEX_LANG_UNKNOWN, lang));
+ System.err.println(Instance.getInstance().getTrans().getString(StringId.LATEX_LANG_UNKNOWN, lang));
}
}
}
writer.write(title);
writer.write("\n");
if (author != null && !author.isEmpty()) {
- writer.write(Instance.getTrans().getString(StringId.BY) + " "
- + author);
+ writer.write(Instance.getInstance().getTrans().getString(StringId.BY) + " " + author);
}
if (date != null && !date.isEmpty()) {
writer.write(" (");
protected void writeChapterHeader(Chapter chap) throws IOException {
String txt;
if (chap.getName() != null && !chap.getName().isEmpty()) {
- txt = Instance.getTrans().getString(StringId.CHAPTER_NAMED,
- chap.getNumber(), chap.getName());
+ txt = Instance.getInstance().getTrans().getString(StringId.CHAPTER_NAMED, chap.getNumber(), chap.getName());
} else {
- txt = Instance.getTrans().getString(StringId.CHAPTER_UNNAMED,
- chap.getNumber());
+ txt = Instance.getInstance().getTrans().getString(StringId.CHAPTER_UNNAMED, chap.getNumber());
}
writer.write("\n" + txt + "\n");
if (para.getType() == ParagraphType.IMAGE) {
File file = new File(targetDir, getCurrentImageBestName(true));
try {
- Instance.getCache().saveAsImage(para.getContentImage(), file,
- nextParaIsCover);
+ Instance.getInstance().getCache().saveAsImage(para.getContentImage(), file, nextParaIsCover);
} catch (IOException e) {
- Instance.getTraceHandler().error(
- new IOException("Cannot save an image", e));
+ Instance.getInstance().getTraceHandler().error(new IOException("Cannot save an image", e));
}
}
* @author niki
*/
public abstract class BasicReader implements Reader {
- private static BasicLibrary defaultLibrary = Instance.getLibrary();
+ private static BasicLibrary defaultLibrary = Instance.getInstance().getLibrary();
private static ReaderType defaultType = ReaderType.GUI;
private BasicLibrary lib;
* Take the default reader type configuration from the config file.
*/
static {
- String typeString = Instance.getConfig().getString(Config.READER_TYPE);
+ String typeString = Instance.getInstance().getConfig().getString(Config.READER_TYPE);
if (typeString != null && !typeString.isEmpty()) {
try {
ReaderType type = ReaderType.valueOf(typeString.toUpperCase());
.getTypeName());
}
} catch (Exception e) {
- Instance.getTraceHandler().error(
- new Exception("Cannot create a reader of type: "
- + defaultType + " (Not compiled in?)", e));
+ Instance.getInstance().getTraceHandler()
+ .error(new Exception("Cannot create a reader of type: " + defaultType + " (Not compiled in?)", e));
}
return null;
throws IOException {
String program = null;
if (meta.isImageDocument()) {
- program = Instance.getUiConfig().getString(
- UiConfig.IMAGES_DOCUMENT_READER);
+ program = Instance.getInstance().getUiConfig().getString(UiConfig.IMAGES_DOCUMENT_READER);
} else {
- program = Instance.getUiConfig().getString(
- UiConfig.NON_IMAGES_DOCUMENT_READER);
+ program = Instance.getInstance().getUiConfig().getString(UiConfig.NON_IMAGES_DOCUMENT_READER);
}
if (program != null && program.trim().isEmpty()) {
for (String starter : new String[] { "xdg-open", "open", "see",
"start", "run" }) {
try {
- Instance.getTraceHandler().trace(
- "starting external program");
- proc = Runtime.getRuntime().exec(
- new String[] { starter, target.getAbsolutePath() });
+ Instance.getInstance().getTraceHandler().trace("starting external program");
+ proc = Runtime.getRuntime().exec(new String[] { starter, target.getAbsolutePath() });
ok = true;
break;
} catch (IOException e) {
throw new IOException("Cannot find a program to start the file");
}
} else {
- Instance.getTraceHandler().trace("starting external program");
+ Instance.getInstance().getTraceHandler().trace("starting external program");
proc = Runtime.getRuntime().exec(
new String[] { program, target.getAbsolutePath() });
}
* in case of I/O error
*/
protected Document load(URL url, boolean stable) throws IOException {
- return DataUtil.load(Instance.getCache().open(url, support, stable),
- "UTF-8", url.toString());
+ return DataUtil.load(Instance.getInstance().getCache().open(url, support, stable), "UTF-8", url.toString());
}
/**
case FANFICTION:
support = new Fanfiction(type);
break;
- case MANGAFOX:
+ case MANGAHUB:
// TODO
break;
case E621:
String coverUrl = cover.absUrl("src");
try {
- InputStream in = Instance.getCache().open(
- new URL(coverUrl), getSupport(), true);
+ InputStream in = Instance.getInstance().getCache().open(new URL(coverUrl), getSupport(), true);
try {
meta.setCover(new Image(in));
} finally {
}
} catch (Exception e) {
// Should not happen on Fanfiction.net
- Instance.getTraceHandler().error(
- new Exception(
- "Cannot download cover for Fanfiction story in search mode: "
- + meta.getTitle(), e));
+ Instance.getInstance().getTraceHandler().error(new Exception(
+ "Cannot download cover for Fanfiction story in search mode: " + meta.getTitle(), e));
}
}
}
}
meta.setResume(getSupport().makeChapter(new URL(sourceUrl), 0,
- Instance.getTrans().getString(StringId.DESCRIPTION),
- resume));
+ Instance.getInstance().getTrans().getString(StringId.DESCRIPTION), resume));
}
// How are the tags ordered?
private List<MetaData> getResults(String sourceUrl) throws IOException {
List<MetaData> metas = new ArrayList<MetaData>();
- Document doc = DataUtil.load(
- Instance.getCache().open(new URL(sourceUrl), getSupport(),
- false), "UTF-8", sourceUrl);
+ Document doc = DataUtil.load(Instance.getInstance().getCache().open(new URL(sourceUrl), getSupport(), false),
+ "UTF-8", sourceUrl);
for (Element result : doc.getElementsByClass("rechercheAffichage")) {
Element a = result.getElementsByTag("a").first();
meta.setAuthor(getVal(tab, 1));
meta.setTags(Arrays.asList(getVal(tab, 2).split(" ")));
- meta.setResume(getSupport()
- .makeChapter(
- new URL(sourceUrl),
- 0,
- Instance.getTrans().getString(
- StringId.DESCRIPTION),
- getVal(tab, 5)));
+ meta.setResume(getSupport().makeChapter(new URL(sourceUrl), 0,
+ Instance.getInstance().getTrans().getString(StringId.DESCRIPTION), getVal(tab, 5)));
}
Element img = result.getElementsByTag("img").first();
String coverUrl = img.absUrl("src");
try {
- InputStream in = Instance.getCache().open(
- new URL(coverUrl), getSupport(), true);
+ InputStream in = Instance.getInstance().getCache().open(new URL(coverUrl), getSupport(),
+ true);
try {
meta.setCover(new Image(in));
} finally {
}
} catch (Exception e) {
// Happen often on MangaLEL...
- Instance.getTraceHandler().trace(
- "Cannot download cover for MangaLEL story in search mode: "
- + meta.getTitle());
+ Instance.getInstance().getTraceHandler().trace(
+ "Cannot download cover for MangaLEL story in search mode: " + meta.getTitle());
}
} catch (Exception e) {
// no project id... cannot use the story :(
- Instance.getTraceHandler().error(
- "Cannot find ProjectId for MangaLEL story in search mode: "
- + meta.getTitle());
+ Instance.getInstance().getTraceHandler()
+ .error("Cannot find ProjectId for MangaLEL story in search mode: " + meta.getTitle());
}
}
*/
protected Document loadDocument(URL source) throws IOException {
String url = getCanonicalUrl(source).toString();
- return DataUtil.load(Instance.getCache().open(source, this, false),
- "UTF-8", url.toString());
+ return DataUtil.load(Instance.getInstance().getCache().open(source, this, false), "UTF-8", url.toString());
}
/**
pg.setProgress(60);
if (getDesc) {
- String descChapterName = Instance.getTrans().getString(
- StringId.DESCRIPTION);
- story.getMeta().setResume(
- bsPara.makeChapter(this, source, 0,
- descChapterName, //
- getDesc(), isHtml(), null));
+ String descChapterName = Instance.getInstance().getTrans().getString(StringId.DESCRIPTION);
+ story.getMeta().setResume(bsPara.makeChapter(this, source, 0, descChapterName, //
+ getDesc(), isHtml(), null));
}
pg.done();
case TEXT:
support = new Text();
break;
- case MANGAFOX:
- support = new MangaFox();
+ case MANGAHUB:
+ support = new MangaHub();
break;
case E621:
support = new E621();
* @return the cover if any, or NULL
*/
public Image getDefaultCover(String subject) {
- if (subject != null && !subject.isEmpty()
- && Instance.getCoverDir() != null) {
+ if (subject != null && !subject.isEmpty() && Instance.getInstance().getCoverDir() != null) {
try {
- File fileCover = new File(Instance.getCoverDir(), subject);
+ File fileCover = new File(Instance.getInstance().getCoverDir(), subject);
return getImage(null, fileCover.toURI().toURL(), subject);
} catch (MalformedURLException e) {
}
}
InputStream in = null;
try {
- in = Instance.getCache().open(url, support, true);
+ in = Instance.getInstance().getCache().open(url, support, true);
return new Image(in);
} catch (IOException e) {
} finally {
// try for URLs
try {
for (String ext : getImageExt(true)) {
- if (Instance.getCache()
- .check(new URL(line + ext), true)) {
+ if (Instance.getInstance().getCache().check(new URL(line + ext), true)) {
url = new URL(line + ext);
break;
}
for (String ext : getImageExt(true)) {
try {
url = new URL(line + ext);
- Instance.getCache().refresh(url, support, true);
+ Instance.getInstance().getCache().refresh(url, support, true);
break;
} catch (IOException e) {
// no image with this ext
// refresh the cached file
if (url != null) {
try {
- Instance.getCache().refresh(url, support, true);
+ Instance.getInstance().getCache().refresh(url, support, true);
} catch (IOException e) {
// woops, broken image
url = null;
public String fixAuthor(String author) {
if (author != null) {
for (String suffix : new String[] { " ", ":" }) {
- for (String byString : Instance.getConfig().getList(Config.CONF_BYS)) {
+ for (String byString : Instance.getInstance().getConfig().getList(Config.CONF_BYS)) {
byString += suffix;
if (author.toUpperCase().startsWith(byString.toUpperCase())) {
author = author.substring(byString.length()).trim();
* Check if the given resource can be a local image or a remote image, then
* refresh the cache with it if it is.
*
+ * @param support
+ * the support to use to download the resource (can be NULL)
* @param dir
* the local directory to search, if any
* @param line
* the resource to check
*
* @return the image if found, or NULL
- *
*/
public Image getImage(BasicSupport support, File dir, String line) {
URL url = getImageUrl(support, dir, line);
+ return getImage(support,url);
+ }
+
+ /**
+ * Check if the given resource can be a local image or a remote image, then
+ * refresh the cache with it if it is.
+ *
+ * @param support
+ * the support to use to download the resource (can be NULL)
+ * @param url
+ * the actual URL to check (file or remote, can be NULL)
+ *
+ * @return the image if found, or NULL
+ */
+ public Image getImage(BasicSupport support, URL url) {
if (url != null) {
if ("file".equals(url.getProtocol())) {
if (new File(url.getPath()).isDirectory()) {
}
InputStream in = null;
try {
- in = Instance.getCache().open(url, support, true);
+ in = Instance.getInstance().getCache().open(url, support, true);
return new Image(in);
} catch (IOException e) {
} finally {
* Check if the given resource can be a local image or a remote image, then
* refresh the cache with it if it is.
*
+ * @param support
+ * the support to use to download the resource (can be NULL)
* @param dir
* the local directory to search, if any
* @param line
// try for URLs
try {
for (String ext : getImageExt(true)) {
- if (Instance.getCache()
+ if (Instance.getInstance().getCache()
.check(new URL(line + ext), true)) {
url = new URL(line + ext);
break;
for (String ext : getImageExt(true)) {
try {
url = new URL(line + ext);
- Instance.getCache().refresh(url, support, true);
+ Instance.getInstance().getCache().refresh(url, support, true);
break;
} catch (IOException e) {
// no image with this ext
// refresh the cached file
if (url != null) {
try {
- Instance.getCache().refresh(url, support, true);
+ Instance.getInstance().getCache().refresh(url, support, true);
} catch (IOException e) {
// woops, broken image
url = null;
*/
public class BasicSupportPara {
// quote chars
- private static char openQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_SINGLE_QUOTE);
- private static char closeQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_SINGLE_QUOTE);
- private static char openDoubleQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_DOUBLE_QUOTE);
- private static char closeDoubleQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_DOUBLE_QUOTE);
+ private static char openQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_SINGLE_QUOTE);
+ private static char closeQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_SINGLE_QUOTE);
+ private static char openDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_DOUBLE_QUOTE);
+ private static char closeDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_DOUBLE_QUOTE);
// used by this class:
BasicSupportHelper bsHelper;
// "Chapter 5: - Fun!" after the ": " was automatically added)
String chapterName = processPara(name, false)
.getContent().trim();
- for (String lang : Instance.getConfig().getList(Config.CONF_CHAPTER)) {
- String chapterWord = Instance.getConfig().getStringX(
- Config.CONF_CHAPTER, lang);
+ for (String lang : Instance.getInstance().getConfig().getList(Config.CONF_CHAPTER)) {
+ String chapterWord = Instance.getInstance().getConfig().getStringX(Config.CONF_CHAPTER, lang);
if (chapterName.startsWith(chapterWord)) {
chapterName = chapterName.substring(chapterWord.length())
.trim();
private InputStream in;
// quote chars
- private char openQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_SINGLE_QUOTE);
- private char closeQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_SINGLE_QUOTE);
- private char openDoubleQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_DOUBLE_QUOTE);
- private char closeDoubleQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_DOUBLE_QUOTE);
+ private char openQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_SINGLE_QUOTE);
+ private char closeQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_SINGLE_QUOTE);
+ private char openDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_DOUBLE_QUOTE);
+ private char closeDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_DOUBLE_QUOTE);
// New methods not used in Deprecated mode
@Override
pg.setProgress(60);
if (getDesc) {
- String descChapterName = Instance.getTrans().getString(
- StringId.DESCRIPTION);
- story.getMeta().setResume(
- makeChapter(url, 0, descChapterName,
- getDesc(url, getInput()), null));
+ String descChapterName = Instance.getInstance().getTrans().getString(StringId.DESCRIPTION);
+ story.getMeta().setResume(makeChapter(url, 0, descChapterName, getDesc(url, getInput()), null));
}
pg.setProgress(100);
InputStream chapIn = null;
if (chap.getValue() != null) {
setCurrentReferer(chap.getValue());
- chapIn = Instance.getCache().open(chap.getValue(),
- this, false);
+ chapIn = Instance.getInstance().getCache().open(chap.getValue(), this, false);
}
pgChaps.setProgress(i * 100);
try {
// redundant "Chapter x: " in front of it, or "-" (as in
// "Chapter 5: - Fun!" after the ": " was automatically added)
String chapterName = processPara(name).getContent().trim();
- for (String lang : Instance.getConfig().getList(Config.CONF_CHAPTER)) {
- String chapterWord = Instance.getConfig().getStringX(
- Config.CONF_CHAPTER, lang);
+ for (String lang : Instance.getInstance().getConfig().getList(Config.CONF_CHAPTER)) {
+ String chapterWord = Instance.getInstance().getConfig().getStringX(Config.CONF_CHAPTER, lang);
if (chapterName.startsWith(chapterWord)) {
chapterName = chapterName.substring(chapterWord.length())
.trim();
* @return the cover if any, or NULL
*/
static Image getDefaultCover(String subject) {
- if (subject != null && !subject.isEmpty()
- && Instance.getCoverDir() != null) {
+ if (subject != null && !subject.isEmpty() && Instance.getInstance().getCoverDir() != null) {
try {
- File fileCover = new File(Instance.getCoverDir(), subject);
+ File fileCover = new File(Instance.getInstance().getCoverDir(), subject);
return getImage(null, fileCover.toURI().toURL(), subject);
} catch (MalformedURLException e) {
}
}
InputStream in = null;
try {
- in = Instance.getCache().open(url, getSupport(url), true);
+ in = Instance.getInstance().getCache().open(url, getSupport(url), true);
return new Image(in);
} catch (IOException e) {
} finally {
// try for URLs
try {
for (String ext : getImageExt(true)) {
- if (Instance.getCache()
- .check(new URL(line + ext), true)) {
+ if (Instance.getInstance().getCache().check(new URL(line + ext), true)) {
url = new URL(line + ext);
break;
}
for (String ext : getImageExt(true)) {
try {
url = new URL(line + ext);
- Instance.getCache().refresh(url, support, true);
+ Instance.getInstance().getCache().refresh(url, support, true);
break;
} catch (IOException e) {
// no image with this ext
// refresh the cached file
if (url != null) {
try {
- Instance.getCache().refresh(url, support, true);
+ Instance.getInstance().getCache().refresh(url, support, true);
} catch (IOException e) {
// woops, broken image
url = null;
* in case of I/O error
*/
protected InputStream openInput(URL source) throws IOException {
- return Instance.getCache().open(source, this, false);
+ return Instance.getInstance().getCache().open(source, this, false);
}
/**
pgMeta.done(); // 10%
- File tmpDir = Instance.getTempFiles().createTempDir("info-text");
+ File tmpDir = Instance.getInstance().getTempFiles().createTempDir("info-text");
String basename = null;
Map<String, Image> images = new HashMap<String, Image>();
try {
images.put(uuid, new Image(zipIn));
} catch (Exception e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
if (pg.getProgress() < 85) {
}
String ext = "."
- + Instance.getConfig()
- .getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER)
- .toLowerCase();
+ + Instance.getInstance().getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase();
String coverName = meta.getUuid() + "_" + basename + ext;
Image cover = images.get(coverName);
images.remove(coverName);
chap.getParagraphs().add(
new Paragraph(images.get(uuid)));
} catch (Exception e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
}
}
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
+ import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
- import java.util.Scanner;
+
+ import org.jsoup.helper.DataUtil;
+ import org.jsoup.nodes.Document;
+ import org.jsoup.nodes.Element;
import be.nikiroo.fanfix.Instance;
- import be.nikiroo.fanfix.data.Chapter;
import be.nikiroo.fanfix.data.MetaData;
- import be.nikiroo.fanfix.data.Story;
+ import be.nikiroo.utils.IOUtils;
import be.nikiroo.utils.Image;
import be.nikiroo.utils.Progress;
import be.nikiroo.utils.StringUtils;
/**
- * Support class for <a href="http://e621.net/">e621.net</a> and <a
- * href="http://e926.net/">e926.net</a>, a Furry website supporting comics,
+ * Support class for <a href="http://e621.net/">e621.net</a> and
+ * <a href="http://e926.net/">e926.net</a>, a Furry website supporting comics,
* including some of MLP.
* <p>
* <a href="http://e926.net/">e926.net</a> only shows the "clean" images and
*
* @author niki
*/
- class E621 extends BasicSupport_Deprecated {
+ class E621 extends BasicSupport {
+ @Override
+ protected boolean supports(URL url) {
+ String host = url.getHost();
+ if (host.startsWith("www.")) {
+ host = host.substring("www.".length());
+ }
+
+ return ("e621.net".equals(host) || "e926.net".equals(host)) && (isPool(url) || isSearchOrSet(url));
+ }
+
@Override
- protected MetaData getMeta(URL source, InputStream in) throws IOException {
+ protected boolean isHtml() {
+ return true;
+ }
+
+ @Override
+ protected MetaData getMeta() throws IOException {
MetaData meta = new MetaData();
- meta.setTitle(getTitle(reset(in)));
- meta.setAuthor(getAuthor(source, reset(in)));
+ meta.setTitle(getTitle());
+ meta.setAuthor(getAuthor());
meta.setDate("");
- meta.setTags(getTags(source, reset(in), false));
+ meta.setTags(getTags());
meta.setSource(getType().getSourceName());
- meta.setUrl(source.toString());
+ meta.setUrl(getSource().toString());
meta.setPublisher(getType().getSourceName());
- meta.setUuid(source.toString());
+ meta.setUuid(getSource().toString());
meta.setLuid("");
meta.setLang("en");
meta.setSubject("Furry");
meta.setType(getType().toString());
meta.setImageDocument(true);
- meta.setCover(getCover(source, reset(in)));
+ meta.setCover(getCover());
meta.setFakeCover(true);
return meta;
}
- private List<String> getTags(URL source, InputStream in, boolean authors) {
- List<String> tags = new ArrayList<String>();
-
- if (isSearch(source)) {
- String tagLine = getLine(in, "id=\"tag-sidebar\"", 1);
- if (tagLine != null) {
- String key = "href=\"";
- for (int pos = tagLine.indexOf(key); pos >= 0; pos = tagLine
- .indexOf(key, pos + 1)) {
- int end = tagLine.indexOf("\"", pos + key.length());
- if (end >= 0) {
- String href = tagLine.substring(pos, end);
- String subkey;
- if (authors)
- subkey = "?name=";
- else
- subkey = "?title=";
- if (href.contains(subkey)) {
- String tag = href.substring(href.indexOf(subkey)
- + subkey.length());
- try {
- tags.add(URLDecoder.decode(tag, "UTF-8"));
- } catch (UnsupportedEncodingException e) {
- // supported JVMs must have UTF-8 support
- e.printStackTrace();
- }
- }
- }
- }
-
- }
- }
-
- return tags;
- }
-
@Override
- public Story process(URL url, Progress pg) throws IOException {
- // There is no chapters on e621, just pagination...
- Story story = super.process(url, pg);
+ protected String getDesc() throws IOException {
+ if (isSearchOrSet(getSource())) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("A collection of images from ").append(getSource().getHost()).append("\n") //
+ .append("\tTime of creation: " + StringUtils.fromTime(new Date().getTime())).append("\n") //
+ .append("\tTags: ");//
+ for (String tag : getTags()) {
+ builder.append("\t\t").append(tag);
+ }
- Chapter only = new Chapter(1, null);
- for (Chapter chap : story) {
- only.getParagraphs().addAll(chap.getParagraphs());
+ return builder.toString();
}
- story.getChapters().clear();
- story.getChapters().add(only);
-
- return story;
- }
-
- @Override
- protected boolean supports(URL url) {
- String host = url.getHost();
- if (host.startsWith("www.")) {
- host = host.substring("www.".length());
+ if (isPool(getSource())) {
+ Element el = getSourceNode().getElementById("description");
+ if (el != null) {
+ return el.text();
+ }
}
- return ("e621.net".equals(host) || "e926.net".equals(host))
- && (isPool(url) || isSearch(url));
+ return null;
}
@Override
- protected boolean isHtml() {
- return true;
- }
-
- private Image getCover(URL source, InputStream in) throws IOException {
- URL urlForCover = source;
- if (isPool(source)) {
- urlForCover = new URL(source.toString() + "?page=1");
- }
-
- String images = getChapterContent(urlForCover, in, 1, null);
- if (!images.isEmpty()) {
- int pos = images.indexOf("<br/>");
- if (pos >= 0) {
- images = images.substring(1, pos - 1);
- return getImage(this, null, images);
- }
+ protected List<Entry<String, URL>> getChapters(Progress pg) throws IOException {
+ if (isPool(getSource())) {
+ String baseUrl = "https://e621.net/" + getSource().getPath() + "?page=";
+ return getChapters(getSource(), pg, baseUrl, "");
+ } else if (isSearchOrSet(getSource())) {
+ String baseUrl = "https://e621.net/posts/?page=";
+ String search = "&tags=" + getTagsFromUrl(getSource());
+ return getChapters(getSource(), pg, baseUrl, search);
}
- return null;
+ return new LinkedList<Entry<String, URL>>();
}
- private String getAuthor(URL source, InputStream in) {
- if (isSearch(source)) {
- StringBuilder builder = new StringBuilder();
- for (String author : getTags(source, in, true)) {
- if (builder.length() > 0)
- builder.append(", ");
- builder.append(author);
- }
+ private List<Entry<String, URL>> getChapters(URL source, Progress pg, String baseUrl, String parameters)
+ throws IOException {
+ List<Entry<String, URL>> urls = new ArrayList<Entry<String, URL>>();
- return builder.toString();
+ if (source.getHost().contains("e926")) {
+ baseUrl = baseUrl.replace("e621", "e926");
}
- String author = getLine(in, "href=\"/post/show/", 0);
- if (author != null) {
- String key = "href=\"";
- int pos = author.indexOf(key);
- if (pos >= 0) {
- author = author.substring(pos + key.length());
- pos = author.indexOf("\"");
- if (pos >= 0) {
- author = author.substring(0, pos - 1);
- String page = source.getProtocol() + "://"
- + source.getHost() + author;
- try {
- InputStream pageIn = Instance.getCache().open(
- new URL(page), this, false);
- try {
- key = "class=\"tag-type-artist\"";
- author = getLine(pageIn, key, 0);
- if (author != null) {
- pos = author.indexOf("<a href=\"");
- if (pos >= 0) {
- author = author.substring(pos);
- pos = author.indexOf("</a>");
- if (pos >= 0) {
- author = author.substring(0, pos);
- return StringUtils.unhtml(author);
- }
- }
- }
- } finally {
- pageIn.close();
- }
- } catch (Exception e) {
- // No author found
+ for (int i = 1; true; i++) {
+ URL url = new URL(baseUrl + i + parameters);
+ try {
+ InputStream pageI = Instance.getInstance().getCache().open(url, this, false);
+ try {
+ if (IOUtils.readSmallStream(pageI).contains("Nobody here but us chickens!")) {
+ break;
}
+ urls.add(new AbstractMap.SimpleEntry<String, URL>("Page " + Integer.toString(i), url));
+ } finally {
+ pageI.close();
}
+ } catch (Exception e) {
+ break;
}
}
- return null;
+ // They are sorted in reverse order on the website
+ Collections.reverse(urls);
+ return urls;
}
- private String getTitle(InputStream in) {
- String title = getLine(in, "<title>", 0);
- if (title != null) {
- int pos = title.indexOf('>');
- if (pos >= 0) {
- title = title.substring(pos + 1);
- pos = title.indexOf('<');
- if (pos >= 0) {
- title = title.substring(0, pos);
- }
- }
-
- if (title.startsWith("Pool:")) {
- title = title.substring("Pool:".length());
- }
-
- title = StringUtils.unhtml(title).trim();
+ @Override
+ protected String getChapterContent(URL chapUrl, int number, Progress pg) throws IOException {
+ StringBuilder builder = new StringBuilder();
+ Document chapterNode = loadDocument(chapUrl);
+ for (Element el : chapterNode.getElementsByTag("article")) {
+ builder.append("[");
+ builder.append(el.attr("data-file-url"));
+ builder.append("]<br/>");
}
- return title;
+ return builder.toString();
}
@Override
- protected String getDesc(URL source, InputStream in) throws IOException {
- String desc = getLine(in, "margin-bottom: 2em;", 0);
-
- if (desc != null) {
- StringBuilder builder = new StringBuilder();
-
- boolean inTags = false;
- for (char car : desc.toCharArray()) {
- if ((inTags && car == '>') || (!inTags && car == '<')) {
- inTags = !inTags;
- }
-
- if (inTags) {
- builder.append(car);
+ protected URL getCanonicalUrl(URL source) {
+ if (isSetOriginalUrl(source)) {
+ try {
+ Document doc = DataUtil.load(Instance.getInstance().getCache().open(source, this, false), "UTF-8", source.toString());
+ for (Element shortname : doc.getElementsByClass("set-shortname")) {
+ for (Element el : shortname.getElementsByTag("a")) {
+ if (!el.attr("href").isEmpty())
+ return new URL(el.absUrl("href"));
+ }
}
+ } catch (IOException e) {
+ Instance.getInstance().getTraceHandler().error(e);
}
-
- return builder.toString().trim();
}
- return null;
- }
-
- @Override
- protected List<Entry<String, URL>> getChapters(URL source, InputStream in,
- Progress pg) throws IOException {
if (isPool(source)) {
- return getChaptersPool(source, in, pg);
- } else if (isSearch(source)) {
- return getChaptersSearch(source, in, pg);
+ try {
+ return new URL(source.toString().replace("/pool/show/", "/pools/"));
+ } catch (MalformedURLException e) {
+ }
}
- return new LinkedList<Entry<String, URL>>();
+ return super.getCanonicalUrl(source);
}
- private List<Entry<String, URL>> getChaptersSearch(URL source,
- InputStream in, Progress pg) throws IOException {
- List<Entry<String, URL>> urls = new ArrayList<Entry<String, URL>>();
+ // returns "xxx+ddd+ggg" if "tags=xxx+ddd+ggg" was present in the query
+ private String getTagsFromUrl(URL url) {
+ String tags = url == null ? "" : url.getQuery();
+ int pos = tags.indexOf("tags=");
- String search = source.getPath();
- if (search.endsWith("/")) {
- search = search.substring(0, search.length() - 1);
+ if (pos >= 0) {
+ tags = tags.substring(pos).substring("tags=".length());
+ } else {
+ return "";
}
- int pos = search.lastIndexOf('/');
- if (pos >= 0) {
- search = search.substring(pos + 1);
+ pos = tags.indexOf('&');
+ if (pos > 0) {
+ tags = tags.substring(0, pos);
+ }
+ pos = tags.indexOf('/');
+ if (pos > 0) {
+ tags = tags.substring(0, pos);
}
- String baseUrl = "https://e621.net/post/index/";
- if (source.getHost().contains("e926")) {
- baseUrl = baseUrl.replace("e621", "e926");
+ return tags;
+ }
+
+ private String getTitle() {
+ String title = "";
+
+ Element el = getSourceNode().getElementsByTag("title").first();
+ if (el != null) {
+ title = el.text().trim();
}
- for (int i = 1; true; i++) {
- URL url = new URL(baseUrl + i + "/" + search + "/");
- try {
- InputStream pageI = Instance.getCache().open(url, this, false);
- try {
- if (getLine(pageI, "No posts matched your search.", 0) != null)
- break;
- urls.add(new AbstractMap.SimpleEntry<String, URL>("Page "
- + Integer.toString(i), url));
- } finally {
- pageI.close();
- }
- } catch (Exception e) {
- break;
+ for (String s : new String[] { "e621", "-", "e621" }) {
+ if (title.startsWith(s)) {
+ title = title.substring(s.length()).trim();
+ }
+ if (title.endsWith(s)) {
+ title = title.substring(0, title.length() - s.length()).trim();
}
+
}
- // They are sorted in reverse order on the website
- Collections.reverse(urls);
- return urls;
+ if (isSearchOrSet(getSource())) {
+ title = title.isEmpty() ? "e621" : "[e621] " + title;
+ }
+ return title;
}
- private List<Entry<String, URL>> getChaptersPool(URL source,
- InputStream in, Progress pg) throws IOException {
- List<Entry<String, URL>> urls = new ArrayList<Entry<String, URL>>();
- int last = 1; // no pool/show when only one page
-
- @SuppressWarnings("resource")
- Scanner scan = new Scanner(in, "UTF-8");
- scan.useDelimiter("\\n");
- while (scan.hasNext()) {
- String line = scan.next();
- for (int pos = line.indexOf(source.getPath()); pos >= 0; pos = line
- .indexOf(source.getPath(), pos + source.getPath().length())) {
- int equalPos = line.indexOf("=", pos);
- int quotePos = line.indexOf("\"", pos);
- if (equalPos >= 0 && quotePos > equalPos) {
- String snum = line.substring(equalPos + 1, quotePos);
- try {
- int num = Integer.parseInt(snum);
- if (num > last) {
- last = num;
- }
- } catch (NumberFormatException e) {
+ private String getAuthor() throws IOException {
+ StringBuilder builder = new StringBuilder();
+
+ if (isSearchOrSet(getSource())) {
+ for (Element el : getSourceNode().getElementsByClass("search-tag")) {
+ if (el.attr("itemprop").equals("author")) {
+ if (builder.length() > 0) {
+ builder.append(", ");
}
+ builder.append(el.text().trim());
}
}
}
- for (int i = 1; i <= last; i++) {
- urls.add(new AbstractMap.SimpleEntry<String, URL>(Integer
- .toString(i), new URL(source.toString() + "?page=" + i)));
- }
+ if (isPool(getSource())) {
+ String desc = getDesc();
+ String descL = desc.toLowerCase();
- return urls;
- }
-
- @Override
- protected String getChapterContent(URL source, InputStream in, int number,
- Progress pg) throws IOException {
- StringBuilder builder = new StringBuilder();
- String staticSite = "https://static1.e621.net";
- if (source.getHost().contains("e926")) {
- staticSite = staticSite.replace("e621", "e926");
- }
+ if (descL.startsWith("by:") || descL.startsWith("by ")) {
+ desc = desc.substring(3).trim();
+ desc = desc.split("\n")[0];
- String key = staticSite + "/data/preview/";
-
- @SuppressWarnings("resource")
- Scanner scan = new Scanner(in, "UTF-8");
- scan.useDelimiter("\\n");
- while (scan.hasNext()) {
- String line = scan.next();
- if (line.contains("class=\"preview")) {
- for (int pos = line.indexOf(key); pos >= 0; pos = line.indexOf(
- key, pos + key.length())) {
- int endPos = line.indexOf("\"", pos);
- if (endPos >= 0) {
- String id = line.substring(pos + key.length(), endPos);
- id = staticSite + "/data/" + id;
-
- int dotPos = id.lastIndexOf(".");
- if (dotPos >= 0) {
- id = id.substring(0, dotPos);
- builder.append("[");
- builder.append(id);
- builder.append("]<br/>");
- }
- }
+ String tab[] = desc.split(" ");
+ for (int i = 0; i < Math.min(tab.length, 5); i++) {
+ if (tab[i].startsWith("http"))
+ break;
+ builder.append(" ").append(tab[i]);
}
}
}
return builder.toString();
}
- @Override
- protected URL getCanonicalUrl(URL source) {
- if (isSearch(source)) {
- // /post?tags=tag1+tag2 -> ../post/index/1/tag1%32tag2
- String key = "?tags=";
- if (source.toString().contains(key)) {
- int pos = source.toString().indexOf(key);
- String tags = source.toString().substring(pos + key.length());
- tags = tags.replace("+", "%20");
-
- String base = source.toString().substring(0, pos);
- if (!base.endsWith("/")) {
- base += "/";
- }
- if (base.endsWith("/search/")) {
- base = base.substring(0, base.indexOf("/search/") + 1);
- }
-
+ // no tags for pools
+ private List<String> getTags() {
+ List<String> tags = new ArrayList<String>();
+ if (isSearchOrSet(getSource())) {
+ String str = getTagsFromUrl(getSource());
+ for (String tag : str.split("\\+")) {
try {
- return new URL(base + "index/1/" + tags);
- } catch (MalformedURLException e) {
- Instance.getTraceHandler().error(e);
+ tags.add(URLDecoder.decode(tag.trim(), "UTF-8").trim());
+ } catch (UnsupportedEncodingException e) {
}
}
}
- return super.getCanonicalUrl(source);
+ return tags;
+ }
+
+ private Image getCover() throws IOException {
+ Image image = null;
+ List<Entry<String, URL>> chapters = getChapters(null);
+ if (!chapters.isEmpty()) {
+ URL chap1Url = chapters.get(0).getValue();
+ String imgsChap1 = getChapterContent(chap1Url, 1, null);
+ if (!imgsChap1.isEmpty()) {
+ imgsChap1 = imgsChap1.split("]")[0].substring(1).trim();
+ image = bsImages.getImage(this, new URL(imgsChap1));
+ }
+ }
+
+ return image;
+ }
+
+ // note: will be removed at getCanonicalUrl()
+ private boolean isSetOriginalUrl(URL originalUrl) {
+ return originalUrl.getPath().startsWith("/post_sets/");
}
private boolean isPool(URL url) {
- return url.getPath().startsWith("/pool/");
+ return url.getPath().startsWith("/pools/") || url.getPath().startsWith("/pool/show/");
}
- private boolean isSearch(URL url) {
- return url.getPath().startsWith("/post/index/")
- || (url.getPath().equals("/post/search") && url.getQuery()
- .startsWith("tags="));
+ // set will be renamed into search by canonical url
+ private boolean isSearchOrSet(URL url) {
+ return
+ // search:
+ (url.getPath().equals("/posts") && url.getQuery().contains("tags="))
+ // or set:
+ || isSetOriginalUrl(url);
}
}
try {
pages.add(new URL(line));
} catch (MalformedURLException e) {
- Instance.getTraceHandler().error(
- new IOException(
- "Parsing error, a link is not correctly parsed: "
- + line, e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Parsing error, a link is not correctly parsed: " + line, e));
}
}
}
StringBuilder builder = new StringBuilder();
for (URL page : pages) {
- InputStream pageIn = Instance.getCache().open(page, this, false);
+ InputStream pageIn = Instance.getInstance().getCache().open(page, this, false);
try {
String link = getKeyLine(pageIn, "id=\"img\"", "src=\"", "\"");
if (link != null && !link.isEmpty()) {
try {
return new File(fakeSource.toURI());
} catch (URISyntaxException e) {
- Instance.getTraceHandler()
- .error(new IOException(
- "Cannot get the source file from the info-text URL",
- e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Cannot get the source file from the info-text URL", e));
}
return null;
try {
fakeIn.reset();
} catch (IOException e) {
- Instance.getTraceHandler()
- .error(new IOException(
- "Cannot reset the Epub Text stream", e));
+ Instance.getInstance().getTraceHandler().error(new IOException("Cannot reset the Epub Text stream", e));
}
return fakeIn;
ZipInputStream zipIn = null;
try {
zipIn = new ZipInputStream(in);
- tmpDir = Instance.getTempFiles().createTempDir(
- "fanfic-reader-parser");
+ tmpDir = Instance.getInstance().getTempFiles().createTempDir("fanfic-reader-parser");
File tmp = new File(tmpDir, "file.txt");
File tmpInfo = new File(tmpDir, "file.info");
try {
cover = new Image(zipIn);
} catch (Exception e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
}
} else if (entry.getName().equals(getDataPrefix() + "URL")) {
return sdf
.format(new Date(1000 * Long.parseLong(line)));
} catch (NumberFormatException e) {
- Instance.getTraceHandler().error(
- new IOException(
- "Cannot convert publication date: "
- + line, e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Cannot convert publication date: " + line, e));
}
}
}
urls.add(new AbstractMap.SimpleEntry<String, URL>(
name.trim(), new URL(base + i + suffix)));
} catch (MalformedURLException e) {
- Instance.getTraceHandler()
- .error(new IOException(
- "Cannot parse chapter " + i
- + " url: "
- + (base + i + suffix), e));
+ Instance.getInstance().getTraceHandler().error(
+ new IOException("Cannot parse chapter " + i + " url: " + (base + i + suffix), e));
}
}
}
int pos = line.indexOf("<hr");
if (pos >= 0) {
boolean chaptered = false;
- for (String lang : Instance.getConfig().getList(
- Config.CONF_CHAPTER)) {
- String chapterWord = Instance.getConfig()
- .getStringX(Config.CONF_CHAPTER, lang);
+ for (String lang : Instance.getInstance().getConfig().getList(Config.CONF_CHAPTER)) {
+ String chapterWord = Instance.getInstance().getConfig().getStringX(Config.CONF_CHAPTER,
+ lang);
int posChap = line.indexOf(chapterWord + " ");
if (posChap < pos) {
chaptered = true;
urls.add(new AbstractMap.SimpleEntry<String, URL>(name,
new URL("http://www.fimfiction.net" + line)));
} catch (MalformedURLException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
}
}
private Map<Integer, String> chapterContents;
public FimfictionApi() throws IOException {
- if (Instance.getConfig().getBoolean(
- Config.LOGIN_FIMFICTION_APIKEY_FORCE_HTML, false)) {
- throw new IOException(
- "Configuration is set to force HTML scrapping");
+ if (Instance.getInstance().getConfig().getBoolean(Config.LOGIN_FIMFICTION_APIKEY_FORCE_HTML, false)) {
+ throw new IOException("Configuration is set to force HTML scrapping");
}
- String oauth = Instance.getConfig().getString(
- Config.LOGIN_FIMFICTION_APIKEY_TOKEN);
+ String oauth = Instance.getInstance().getConfig().getString(Config.LOGIN_FIMFICTION_APIKEY_TOKEN);
if (oauth == null || oauth.isEmpty()) {
- String clientId = Instance.getConfig().getString(
- Config.LOGIN_FIMFICTION_APIKEY_CLIENT_ID)
- + "";
- String clientSecret = Instance.getConfig().getString(
- Config.LOGIN_FIMFICTION_APIKEY_CLIENT_SECRET)
+ String clientId = Instance.getInstance().getConfig().getString(Config.LOGIN_FIMFICTION_APIKEY_CLIENT_ID)
+ "";
+ String clientSecret = Instance.getInstance().getConfig()
+ .getString(Config.LOGIN_FIMFICTION_APIKEY_CLIENT_SECRET) + "";
if (clientId.trim().isEmpty() || clientSecret.trim().isEmpty()) {
throw new IOException("API key required for the beta API v2");
oauth = generateOAuth(clientId, clientSecret);
- Instance.getConfig().setString(
- Config.LOGIN_FIMFICTION_APIKEY_TOKEN, oauth);
- Instance.getConfig().updateFile();
+ Instance.getInstance().getConfig().setString(Config.LOGIN_FIMFICTION_APIKEY_TOKEN, oauth);
+ Instance.getInstance().getConfig().updateFile();
}
this.oauth = oauth;
urlString = urlString.replace("[", "%5B").replace("]", "%5D");
URL url = new URL(urlString);
- InputStream jsonIn = Instance.getCache().open(url, this, false);
+ InputStream jsonIn = Instance.getInstance().getCache().open(url, this, false);
try {
return IOUtils.readSmallStream(jsonIn);
} finally {
// No need to use the oauth, cookies... for the cover
// Plus: it crashes on Android because of the referer
try {
- InputStream in = Instance.getCache().open(coverImageUrl, null,
- true);
+ InputStream in = Instance.getInstance().getCache().open(coverImageUrl, null, true);
try {
meta.setCover(new Image(in));
} finally {
in.close();
}
} catch (IOException e) {
- Instance.getTraceHandler().error(
- new IOException(
- "Cannot get the story cover, ignoring...", e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Cannot get the story cover, ignoring...", e));
}
}
params.put("client_id", clientId);
params.put("client_secret", clientSecret);
params.put("grant_type", "client_credentials");
- InputStream in = Instance.getCache().openNoCache(url, null, params,
- null, null);
+ InputStream in = Instance.getInstance().getCache().openNoCache(url, null, params, null, null);
String jsonToken = IOUtils.readSmallStream(in);
in.close();
try {
source = txt.toURI().toURL();
} catch (MalformedURLException e) {
- Instance.getTraceHandler().error(
- new IOException("Cannot convert the right URL for "
- + source, e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Cannot convert the right URL for " + source, e));
}
}
File basefile = new File(sourceInfoFile.getFile());
String ext = "."
- + Instance.getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER)
- .toLowerCase();
+ + Instance.getInstance().getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase();
// Without removing ext
cover = bsHelper.getImage(null, sourceInfoFile,
--- /dev/null
+ package be.nikiroo.fanfix.supported;
+
+ import java.io.IOException;
+ import java.net.HttpURLConnection;
+ import java.net.MalformedURLException;
+ import java.net.URL;
+ import java.util.AbstractMap;
+ import java.util.ArrayList;
+ import java.util.Collections;
+ import java.util.List;
+ import java.util.Map.Entry;
+
+ import org.jsoup.nodes.Element;
+
+ import be.nikiroo.fanfix.Instance;
+ import be.nikiroo.fanfix.bundles.Config;
+ import be.nikiroo.fanfix.data.MetaData;
+ import be.nikiroo.utils.Image;
+ import be.nikiroo.utils.Progress;
+ import be.nikiroo.utils.StringUtils;
+
+ /**
+ * Support class for <a href="https://mangahub.io/">MangaHub</a>, a website
+ * dedicated to Manga.
+ *
+ * @author niki
+ */
+ class MangaHub extends BasicSupport {
+ @Override
+ protected boolean isHtml() {
+ return true;
+ }
+
+ @Override
+ protected MetaData getMeta() throws IOException {
+ MetaData meta = new MetaData();
+
+ meta.setTitle(getTitle());
+ meta.setDate("");
+ meta.setAuthor(getAuthor());
+ meta.setTags(getTags());
+ meta.setSource(getType().getSourceName());
+ meta.setUrl(getSource().toString());
+ meta.setPublisher(getType().getSourceName());
+ meta.setUuid(getSource().toString());
+ meta.setLuid("");
+ meta.setLang("en");
+ meta.setSubject("manga");
+ meta.setType(getType().toString());
+ meta.setImageDocument(true);
+ meta.setCover(getCover());
+
+ return meta;
+ }
+
+ private String getTitle() {
+ Element doc = getSourceNode();
+
+ Element el = doc.getElementsByTag("h1").first();
+ if (el != null) {
+ return StringUtils.unhtml(el.text()).trim();
+ }
+
+ return null;
+ }
+
+ private String getAuthor() {
+ String author = "";
+
+ Element el = getSourceNode().select("h1+div span:not([class])").first();
+ if (el != null)
+ author = StringUtils.unhtml(el.text()).trim();
+ return author;
+ }
+
+ private List<String> getTags() {
+ return getListA("genre-label");
+ }
+
+ private List<String> getListA(String uniqueClass) {
+ List<String> list = new ArrayList<String>();
+
+ Element doc = getSourceNode();
+ Element el = doc.getElementsByClass(uniqueClass).first();
+ if (el != null) {
+ for (Element valueA : el.getElementsByTag("a")) {
+ list.add(StringUtils.unhtml(valueA.text()).trim());
+ }
+ }
+
+ return list;
+ }
+
+ @Override
+ protected String getDesc() {
+ Element doc = getSourceNode();
+ Element title = doc.getElementsByClass("fullcontent").first();
+ if (title != null) {
+ return StringUtils.unhtml(title.text()).trim();
+ }
+
+ return null;
+ }
+
+ private Image getCover() {
+ Element doc = getSourceNode();
+ Element cover = doc.getElementsByClass("manga-thumb").first();
+ if (cover != null) {
+ try {
+ return bsImages.getImage(this, new URL(cover.absUrl("src")));
+ } catch (MalformedURLException e) {
+ Instance.getInstance().getTraceHandler().error(e);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected List<Entry<String, URL>> getChapters(Progress pg) {
+ List<Entry<String, URL>> urls = new ArrayList<Entry<String, URL>>();
+
+ Element doc = getSourceNode();
+ for (Element el : doc.getElementsByClass("list-group-item")) {
+ Element urlEl = el.getElementsByTag("a").first();
+ if (urlEl == null)
+ continue;
+
+ String url = urlEl.absUrl("href");
+
+ String title = "";
+ el = el.getElementsByClass("text-secondary").first();
+ if (el != null) {
+ title = StringUtils.unhtml(el.text()).trim();
+ }
+
+ try {
+ urls.add(new AbstractMap.SimpleEntry<String, URL>(title, new URL(url)));
+ } catch (Exception e) {
+ Instance.getInstance().getTraceHandler().error(e);
+ }
+ }
+
+ // by default, the chapters are in reversed order
+ Collections.reverse(urls);
+
+ return urls;
+ }
+
+ @Override
+ protected String getChapterContent(URL chapUrl, int number, Progress pg) throws IOException {
+ if (pg == null) {
+ pg = new Progress();
+ }
+
+ // 1. Get the title and chapter url part
+ String path = chapUrl.getPath();
+ if (path.endsWith("/")) {
+ path = path.substring(0, path.length() - "/".length());
+ }
+ String tab[] = path.split("/");
+ String chap = tab[tab.length - 1];
+ String title = tab[tab.length - 2];
+
+ if (chap.startsWith("chapter-")) {
+ chap = chap.substring("chapter-".length());
+ }
+
+ // 2. generate an image base
+ String base = "https://img.mghubcdn.com/file/imghub/" + title + "/" + chap + "/";
+
+ // 3. add each chapter
+ StringBuilder builder = new StringBuilder();
+
+ int i = 1;
+ String url = base + i + ".jpg";
+ while (getHttpStatus(new URL(url)) != 404) {
+ builder.append("[");
+ builder.append(url);
+ builder.append("]<br/>");
+
+ i++;
+ url = base + i + ".jpg";
+ }
+
+ return builder.toString();
+ }
+
+ // HTTP response code, or -1 if other error
+ // TODO: move that to Downloader?
+ private int getHttpStatus(URL url) {
+ try {
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ try {
+ conn.setRequestMethod("HEAD");
+ conn.setRequestProperty("User-Agent", Instance.getInstance().getConfig().getString(Config.NETWORK_USER_AGENT));
+ conn.setRequestProperty("Accept-Encoding", "gzip");
+ conn.setRequestProperty("Accept", "*/*");
+ conn.setRequestProperty("Charset", "utf-8");
+
+ return conn.getResponseCode();
+ } finally {
+ conn.disconnect();
+ }
+ } catch (Exception e) {
+ return -1;
+ }
+ }
+
+ @Override
+ protected boolean supports(URL url) {
+ return "mangahub.io".equals(url.getHost()) || "www.mangahub.io".equals(url.getHost());
+ }
+ }
InputStream coverIn;
try {
- coverIn = Instance.getCache().open(new URL(coverUrl), this,
- true);
+ coverIn = Instance.getInstance().getCache().open(new URL(coverUrl), this, true);
try {
return new Image(coverIn);
} finally {
coverIn.close();
}
} catch (IOException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
}
}
StringBuilder builder = new StringBuilder();
- InputStream in = Instance.getCache().open(chapUrl, this, false);
+ InputStream in = Instance.getInstance().getCache().open(chapUrl, this, false);
try {
Element pageDoc = DataUtil.load(in, "UTF-8", chapUrl.toString());
Element content = pageDoc.getElementById("content");
/** Fanfictions from a lot of different universes */
FANFICTION,
/** Website with lots of Mangas */
- MANGAFOX,
+ MANGAHUB,
/** Furry website with comics support */
E621,
/** Furry website with stories */
return "info-text";
case MANGA_LEL:
return "MangaLEL";
- case MANGAFOX:
- return "MangaFox.me";
+ case MANGAHUB:
+ return "MangaHub.io";
case TEXT:
return "text";
case YIFFSTAR:
* @return the description
*/
public String getDesc() {
- String desc = Instance.getTrans().getStringX(StringId.INPUT_DESC,
- this.name());
+ String desc = Instance.getInstance().getTrans().getStringX(StringId.INPUT_DESC, this.name());
if (desc == null) {
- desc = Instance.getTrans().getString(StringId.INPUT_DESC, this);
+ desc = Instance.getInstance().getTrans().getString(StringId.INPUT_DESC, this);
}
return desc;
try {
in.reset();
} catch (IOException e) {
- Instance.getTraceHandler().error(
- new IOException("Cannot reset the Text stream", e));
+ Instance.getInstance().getTraceHandler().error(new IOException("Cannot reset the Text stream", e));
}
return in;
Image cover = bsImages.getImage(this, sourceFile.getParentFile(), path);
if (cover != null) {
try {
- File tmp = Instance.getTempFiles().createTempFile(
- "test_cover_image");
+ File tmp = Instance.getInstance().getTempFiles().createTempFile("test_cover_image");
ImageUtils.getInstance().saveAsImage(cover, tmp, "png");
tmp.delete();
} catch (IOException e) {
try {
in.close();
} catch (IOException e) {
- Instance.getTraceHandler().error(
- new IOException(
- "Cannot close the text source file input", e));
+ Instance.getInstance().getTraceHandler()
+ .error(new IOException("Cannot close the text source file input", e));
}
}
file = assureNoTxt(file);
file = new File(file.getPath() + ".info");
} catch (URISyntaxException e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
file = null;
}
*/
static private String detectChapter(String line, int number) {
line = line.toUpperCase();
- for (String lang : Instance.getConfig().getList(Config.CONF_CHAPTER)) {
- String chapter = Instance.getConfig().getStringX(
- Config.CONF_CHAPTER, lang);
+ for (String lang : Instance.getInstance().getConfig().getList(Config.CONF_CHAPTER)) {
+ String chapter = Instance.getInstance().getConfig().getStringX(Config.CONF_CHAPTER, lang);
if (chapter != null && !chapter.isEmpty()) {
chapter = chapter.toUpperCase() + " ";
if (line.startsWith(chapter)) {
public void login() throws IOException {
// Note: this should not be necessary anymore
// (the "/guest" trick is enough)
- String login = Instance.getConfig().getString(
- Config.LOGIN_YIFFSTAR_USER);
- String password = Instance.getConfig().getString(
- Config.LOGIN_YIFFSTAR_PASS);
+ String login = Instance.getInstance().getConfig().getString(Config.LOGIN_YIFFSTAR_USER);
+ String password = Instance.getInstance().getConfig().getString(Config.LOGIN_YIFFSTAR_PASS);
if (login != null && !login.isEmpty() && password != null
&& !password.isEmpty()) {
// Cookies will actually be retained by the cache manager once
// logged in
- Instance.getCache()
- .openNoCache(new URL("https://www.sofurry.com/user/login"),
- this, post, null, null).close();
+ Instance.getInstance().getCache()
+ .openNoCache(new URL("https://www.sofurry.com/user/login"), this, post, null, null).close();
}
}
if (source.getPath().startsWith("/view")) {
source = guest(source.toString());
// NO CACHE because we don't want the NotLoggedIn message later
- InputStream in = Instance.getCache().openNoCache(source, this,
- null, null, null);
+ InputStream in = Instance.getInstance().getCache().openNoCache(source, this, null, null, null);
String line = getLine(in, "/browse/folder/", 0);
if (line != null) {
String[] tab = line.split("\"");
}
}
} catch (Exception e) {
- Instance.getTraceHandler().error(e);
+ Instance.getInstance().getTraceHandler().error(e);
}
return super.getCanonicalUrl(source);
List<Entry<String, URL>> chaps = getChapters(source, in, null);
if (!chaps.isEmpty()) {
- in = Instance.getCache().open(chaps.get(0).getValue(), this, true);
+ in = Instance.getInstance().getCache().open(chaps.get(0).getValue(), this, true);
String line = getLine(in, " name=\"og:image\"", 0);
if (line != null) {
int pos = -1;
class BasicSupportDeprecatedTest extends TestLauncher {
// quote chars
- private char openQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_SINGLE_QUOTE);
- private char closeQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_SINGLE_QUOTE);
- private char openDoubleQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_DOUBLE_QUOTE);
- private char closeDoubleQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_DOUBLE_QUOTE);
+ private char openQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_SINGLE_QUOTE);
+ private char closeQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_SINGLE_QUOTE);
+ private char openDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_DOUBLE_QUOTE);
+ private char closeDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_DOUBLE_QUOTE);
public BasicSupportDeprecatedTest(String[] args) {
super("BasicSupportDeprecated", args);
public void test() throws Exception {
BasicSupportEmpty support = new BasicSupportEmpty();
- char openDoubleQuote = Instance.getTrans()
+ char openDoubleQuote = Instance.getInstance().getTrans()
.getCharacter(StringId.OPEN_DOUBLE_QUOTE);
- char closeDoubleQuote = Instance.getTrans()
+ char closeDoubleQuote = Instance.getInstance().getTrans()
.getCharacter(StringId.CLOSE_DOUBLE_QUOTE);
String content = null;
class BasicSupportUtilitiesTest extends TestLauncher {
// quote chars
- private char openQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_SINGLE_QUOTE);
- private char closeQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_SINGLE_QUOTE);
- private char openDoubleQuote = Instance.getTrans().getCharacter(
- StringId.OPEN_DOUBLE_QUOTE);
- private char closeDoubleQuote = Instance.getTrans().getCharacter(
- StringId.CLOSE_DOUBLE_QUOTE);
+ private char openQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_SINGLE_QUOTE);
+ private char closeQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_SINGLE_QUOTE);
+ private char openDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.OPEN_DOUBLE_QUOTE);
+ private char closeDoubleQuote = Instance.getInstance().getTrans().getCharacter(StringId.CLOSE_DOUBLE_QUOTE);
public BasicSupportUtilitiesTest(String[] args) {
super("BasicSupportUtilities", args);
public void test() throws Exception {
BasicSupportParaPublic support = new BasicSupportParaPublic();
- char openDoubleQuote = Instance.getTrans()
+ char openDoubleQuote = Instance.getInstance().getTrans()
.getCharacter(StringId.OPEN_DOUBLE_QUOTE);
- char closeDoubleQuote = Instance.getTrans()
+ char closeDoubleQuote = Instance.getInstance().getTrans()
.getCharacter(StringId.CLOSE_DOUBLE_QUOTE);
String content = null;
BasicOutput.OutputType type) throws Exception {
final List<String> errors = new ArrayList<String>();
- TraceHandler previousTraceHandler = Instance.getTraceHandler();
- Instance.setTraceHandler(new TraceHandler(true, true, 0) {
+ TraceHandler previousTraceHandler = Instance.getInstance().getTraceHandler();
+ Instance.getInstance().setTraceHandler(new TraceHandler(true, true, 0) {
@Override
public void error(String message) {
errors.add(message);
return target;
} finally {
- Instance.setTraceHandler(previousTraceHandler);
+ Instance.getInstance().setTraceHandler(previousTraceHandler);
}
}
addTest(new TestCase("getList") {
@Override
public void test() throws Exception {
- List<MetaData> metas = lib.getList();
+ List<MetaData> metas = lib.getList().getMetas();
assertEquals(errMess, Arrays.asList(),
titlesAsList(metas));
}
lib.save(story(luid1, name1, source1, author1), luid1,
null);
- List<MetaData> metas = lib.getList();
+ List<MetaData> metas = lib.getList().getMetas();
assertEquals(errMess, Arrays.asList(name1),
titlesAsList(metas));
}
lib.save(story(luid2, name2, source2, author1), luid2,
null);
- metas = lib.getList();
+ metas = lib.getList().getMetas();
assertEquals(errMess, Arrays.asList(name1, name2),
titlesAsList(metas));
lib.save(story(luid3, name3, source2, author1), luid3,
null);
- metas = lib.getList();
+ metas = lib.getList().getMetas();
assertEquals(errMess,
Arrays.asList(name1, name2, name3),
titlesAsList(metas));
lib.save(story(luid3, name3ex, source2, author2),
luid3, null);
- List<MetaData> metas = lib.getList();
+ List<MetaData> metas = lib.getList().getMetas();
assertEquals(errMess,
Arrays.asList(name1, name2, name3ex),
titlesAsList(metas));
addTest(new TestCase("getList with results") {
@Override
public void test() throws Exception {
- List<MetaData> metas = lib.getList();
+ List<MetaData> metas = lib.getList().getMetas();
assertEquals(3, metas.size());
}
});
public void test() throws Exception {
List<MetaData> metas = null;
- metas = lib.getListBySource(source1);
+ metas = lib.getList().filter(source1, null, null);
assertEquals(1, metas.size());
- metas = lib.getListBySource(source2);
+ metas = lib.getList().filter(source2, null, null);
assertEquals(2, metas.size());
- metas = lib.getListBySource(null);
+ metas = lib.getList().filter((String)null, null, null);
assertEquals(3, metas.size());
}
});
public void test() throws Exception {
List<MetaData> metas = null;
- metas = lib.getListByAuthor(author1);
+ metas = lib.getList().filter(null, author1, null);
assertEquals(2, metas.size());
- metas = lib.getListByAuthor(author2);
+ metas = lib.getList().filter(null, author2, null);
assertEquals(1, metas.size());
- metas = lib.getListByAuthor(null);
+ metas = lib.getList().filter((String)null, null, null);
assertEquals(3, metas.size());
}
});
lib.changeSource(luid3, source1, null);
- metas = lib.getListBySource(source1);
+ metas = lib.getList().filter(source1, null, null);
assertEquals(2, metas.size());
- metas = lib.getListBySource(source2);
+ metas = lib.getList().filter(source2, null, null);
assertEquals(1, metas.size());
- metas = lib.getListBySource(null);
+ metas = lib.getList().filter((String)null, null, null);
assertEquals(3, metas.size());
}
});
lib.save(story(luid3, "My story 3", source2, author2),
luid3, null);
- metas = lib.getListBySource(source1);
+ metas = lib.getList().filter(source1, null, null);
assertEquals(1, metas.size());
- metas = lib.getListBySource(source2);
+ metas = lib.getList().filter(source2, null, null);
assertEquals(2, metas.size());
- metas = lib.getListBySource(null);
+ metas = lib.getList().filter((String)null, null, null);
assertEquals(3, metas.size());
}
});
*/
public Test(String[] args, boolean urlsAllowed) throws IOException {
super("Fanfix", args);
- Instance.setTraceHandler(null);
+ Instance.getInstance().setTraceHandler(null);
addSeries(new BasicSupportUtilitiesTest(args));
addSeries(new BasicSupportDeprecatedTest(args));
addSeries(new LibraryTest(args));
// Only download files if allowed:
boolean offline = new File("test/OFFLINE").exists();
- Instance.getCache().setOffline(offline);
+ Instance.getInstance().getCache().setOffline(offline);
System.setProperty("CONFIG_DIR", tmpConfig.getAbsolutePath());
Instance.init(true);
- Instance.getCache().setOffline(offline);
+ Instance.getInstance().getCache().setOffline(offline);
TestLauncher tests = new Test(args, urlsAllowed);
tests.setDetails(verbose);
tempFiles.close();
// This is usually done in Fanfix.Main:
- Instance.getTempFiles().close();
+ Instance.getInstance().getTempFiles().close();
}
System.exit(result);