--- /dev/null
+package be.nikiroo.fanfix;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.data.Story;
+import be.nikiroo.fanfix.output.BasicOutput;
+import be.nikiroo.fanfix.output.BasicOutput.OutputType;
+import be.nikiroo.fanfix.supported.BasicSupport;
+import be.nikiroo.fanfix.supported.BasicSupport.SupportType;
+import be.nikiroo.utils.Progress;
+
+/**
+ * Manage a library of Stories: import, export, list, modify.
+ * <p>
+ * Each {@link Story} object will be associated with a (local to the library)
+ * unique ID, the LUID, which will be used to identify the {@link Story}.
+ * <p>
+ * Most of the {@link BasicLibrary} functions work on a partial (cover
+ * <b>MAY</b> not be included) {@link MetaData} object.
+ *
+ * @author niki
+ */
+abstract public class BasicLibrary {
+ /**
+ * Retrieve the main {@link File} corresponding to the given {@link Story},
+ * which can be passed to an external reader or instance.
+ * <p>
+ * Do <b>NOT</b> alter this file.
+ *
+ * @param luid
+ * the Library UID of the story
+ *
+ * @return the corresponding {@link Story}
+ */
+ public abstract File getFile(String luid);
+
+ /**
+ * Return the cover image associated to this story.
+ *
+ * @param luid
+ * the Library UID of the story
+ *
+ * @return the cover image
+ */
+ public abstract BufferedImage getCover(String luid);
+
+ /**
+ * Return the list of stories (represented by their {@link MetaData}, which
+ * <b>MAY</b> not have the cover included).
+ *
+ * @param pg
+ * the optional {@link Progress}
+ *
+ * @return the list (can be empty but not NULL)
+ */
+ protected abstract List<MetaData> getMetas(Progress pg);
+
+ /**
+ * Invalidate the {@link Story} cache (when the content should be re-read
+ * because it was changed).
+ */
+ protected abstract void clearCache();
+
+ /**
+ * Return the next LUID that can be used.
+ *
+ * @return the next luid
+ */
+ protected abstract int getNextId();
+
+ /**
+ * Delete the target {@link Story}.
+ *
+ * @param luid
+ * the LUID of the {@link Story}
+ *
+ * @throws IOException
+ * in case of I/O error or if the {@link Story} wa not found
+ */
+ protected abstract void doDelete(String luid) throws IOException;
+
+ /**
+ * Actually save the story to the back-end.
+ *
+ * @param story
+ * the {@link Story} to save
+ * @param pg
+ * the optional {@link Progress}
+ *
+ * @return the saved {@link Story} (which may have changed, especially
+ * regarding the {@link MetaData})
+ *
+ * @throws IOException
+ * in case of I/O error
+ */
+ protected abstract Story doSave(Story story, Progress pg)
+ throws IOException;
+
+ /**
+ * Refresh the {@link BasicLibrary}, that is, make sure all stories are
+ * loaded.
+ *
+ * @param full
+ * force the full content of the stories to be loaded, not just
+ * the {@link MetaData}
+ *
+ * @param pg
+ * the optional progress reporter
+ */
+ public void refresh(boolean full, Progress pg) {
+ if (full) {
+ // TODO: progress
+ List<MetaData> metas = getMetas(pg);
+ for (MetaData meta : metas) {
+ getStory(meta.getLuid(), null);
+ }
+ } else {
+ getMetas(pg);
+ }
+ }
+
+ /**
+ * List all the known types (sources) of stories.
+ *
+ * @return the sources
+ */
+ public synchronized List<String> getSources() {
+ List<String> list = new ArrayList<String>();
+ for (MetaData meta : getMetas(null)) {
+ String storySource = meta.getSource();
+ if (!list.contains(storySource)) {
+ list.add(storySource);
+ }
+ }
+
+ Collections.sort(list);
+ return list;
+ }
+
+ /**
+ * List all the known authors of stories.
+ *
+ * @return the authors
+ */
+ public synchronized List<String> getAuthors() {
+ List<String> list = new ArrayList<String>();
+ for (MetaData meta : getMetas(null)) {
+ String storyAuthor = meta.getAuthor();
+ if (!list.contains(storyAuthor)) {
+ list.add(storyAuthor);
+ }
+ }
+
+ Collections.sort(list);
+ return list;
+ }
+
+ /**
+ * List all the stories in the {@link BasicLibrary}.
+ * <p>
+ * Cover images not included.
+ *
+ * @return the stories
+ */
+ public synchronized List<MetaData> getList() {
+ 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
+ */
+ public synchronized List<MetaData> getListBySource(String type) {
+ 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
+ */
+ public synchronized List<MetaData> getListByAuthor(String author) {
+ 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;
+ }
+
+ /**
+ * Retrieve a {@link MetaData} corresponding to the given {@link Story},
+ * cover image <b>MAY</b> not be included.
+ *
+ * @param luid
+ * the Library UID of the story
+ *
+ * @return the corresponding {@link Story}
+ */
+ public synchronized MetaData getInfo(String luid) {
+ if (luid != null) {
+ for (MetaData meta : getMetas(null)) {
+ if (luid.equals(meta.getLuid())) {
+ return meta;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Retrieve a specific {@link Story}.
+ *
+ * @param luid
+ * the Library UID of the story
+ * @param pg
+ * the optional progress reporter
+ *
+ * @return the corresponding {@link Story} or NULL if not found
+ */
+ public synchronized Story getStory(String luid, Progress pg) {
+ // TODO: pg
+ if (pg == null) {
+ pg = new Progress();
+ }
+
+ Story story = null;
+ for (MetaData meta : getMetas(null)) {
+ if (meta.getLuid().equals(luid)) {
+ File file = getFile(luid);
+ try {
+ SupportType type = SupportType.valueOfAllOkUC(meta
+ .getType());
+ URL url = file.toURI().toURL();
+ if (type != null) {
+ story = BasicSupport.getSupport(type).process(url, pg);
+ } else {
+ throw new IOException("Unknown type: " + meta.getType());
+ }
+ } catch (IOException e) {
+ // We should not have not-supported files in the
+ // library
+ Instance.syserr(new IOException(
+ "Cannot load file from library: " + file, e));
+ } finally {
+ pg.done();
+ }
+
+ break;
+ }
+ }
+
+ return story;
+ }
+
+ /**
+ * Import the {@link Story} at the given {@link URL} into the
+ * {@link BasicLibrary}.
+ *
+ * @param url
+ * the {@link URL} to import
+ * @param pg
+ * the optional progress reporter
+ *
+ * @return the imported {@link Story}
+ *
+ * @throws IOException
+ * in case of I/O error
+ */
+ public Story imprt(URL url, Progress pg) throws IOException {
+ BasicSupport support = BasicSupport.getSupport(url);
+ if (support == null) {
+ throw new IOException("URL not supported: " + url.toString());
+ }
+
+ return save(support.process(url, pg), null);
+ }
+
+ /**
+ * Export the {@link Story} to the given target in the given format.
+ *
+ * @param luid
+ * the {@link Story} ID
+ * @param type
+ * the {@link OutputType} to transform it to
+ * @param target
+ * the target to save to
+ * @param pg
+ * the optional progress reporter
+ *
+ * @return the saved resource (the main saved {@link File})
+ *
+ * @throws IOException
+ * in case of I/O error
+ */
+ public File export(String luid, OutputType type, String target, Progress pg)
+ throws IOException {
+ Progress pgGetStory = new Progress();
+ Progress pgOut = new Progress();
+ if (pg != null) {
+ pg.setMax(2);
+ pg.addProgress(pgGetStory, 1);
+ pg.addProgress(pgOut, 1);
+ }
+
+ BasicOutput out = BasicOutput.getOutput(type, true);
+ if (out == null) {
+ throw new IOException("Output type not supported: " + type);
+ }
+
+ Story story = getStory(luid, pgGetStory);
+ if (story == null) {
+ throw new IOException("Cannot find story to export: " + luid);
+ }
+
+ return out.process(story, target, pgOut);
+ }
+
+ /**
+ * Save a {@link Story} to the {@link BasicLibrary}.
+ *
+ * @param story
+ * the {@link Story} to save
+ * @param pg
+ * the optional progress reporter
+ *
+ * @return the same {@link Story}, whose LUID may have changed
+ *
+ * @throws IOException
+ * in case of I/O error
+ */
+ public Story save(Story story, Progress pg) throws IOException {
+ return save(story, null, pg);
+ }
+
+ /**
+ * Save a {@link Story} to the {@link BasicLibrary} -- the LUID <b>must</b>
+ * be correct, or NULL to get the next free one.
+ * <p>
+ * Will override any previous {@link Story} with the same LUID.
+ *
+ * @param story
+ * the {@link Story} to save
+ * @param luid
+ * the <b>correct</b> LUID or NULL to get the next free one
+ * @param pg
+ * the optional progress reporter
+ *
+ * @return the same {@link Story}, whose LUID may have changed
+ *
+ * @throws IOException
+ * in case of I/O error
+ */
+ public synchronized Story save(Story story, String luid, Progress pg)
+ throws IOException {
+ // Do not change the original metadata, but change the original story
+ MetaData meta = story.getMeta().clone();
+ story.setMeta(meta);
+
+ if (luid == null || luid.isEmpty()) {
+ meta.setLuid(String.format("%03d", getNextId()));
+ } else {
+ meta.setLuid(luid);
+ }
+
+ if (getInfo(luid) != null) {
+ delete(luid);
+ }
+ doSave(story, pg);
+
+ clearCache();
+
+ return story;
+ }
+
+ /**
+ * Delete the given {@link Story} from this {@link BasicLibrary}.
+ *
+ * @param luid
+ * the LUID of the target {@link Story}
+ *
+ * @throws IOException
+ * in case of I/O error
+ */
+ public synchronized void delete(String luid) throws IOException {
+ doDelete(luid);
+ clearCache();
+ }
+
+ /**
+ * Change the type (source) of the given {@link Story}.
+ *
+ * @param luid
+ * the {@link Story} LUID
+ * @param newSource
+ * the new source
+ * @param pg
+ * the optional progress reporter
+ *
+ * @throws IOException
+ * in case of I/O error or if the {@link Story} was not found
+ */
+ public synchronized void changeSource(String luid, String newSource,
+ Progress pg) throws IOException {
+ MetaData meta = getInfo(luid);
+ if (meta == null) {
+ throw new IOException("Story not found: " + luid);
+ }
+
+ meta.setSource(newSource);
+ saveMeta(meta, pg);
+ }
+
+ /**
+ * Save back the current state of the {@link MetaData} (LUID <b>MUST NOT</b>
+ * change) for this {@link Story}.
+ * <p>
+ * By default, delete the old {@link Story} then recreate a new
+ * {@link Story}.
+ * <p>
+ * Note that this behaviour can lead to data loss.
+ *
+ * @param meta
+ * the new {@link MetaData} (LUID <b>MUST NOT</b> change)
+ * @param pg
+ * the optional {@link Progress}
+ *
+ * @throws IOException
+ * in case of I/O error or if the {@link Story} was not found
+ */
+ protected synchronized void saveMeta(MetaData meta, Progress pg)
+ throws IOException {
+ if (pg == null) {
+ pg = new Progress();
+ }
+
+ Progress pgGet = new Progress();
+ Progress pgSet = new Progress();
+ pg.addProgress(pgGet, 50);
+ pg.addProgress(pgSet, 50);
+
+ Story story = getStory(meta.getLuid(), pgGet);
+ if (story == null) {
+ throw new IOException("Story not found: " + meta.getLuid());
+ }
+
+ delete(meta.getLuid());
+
+ story.setMeta(meta);
+ save(story, meta.getLuid(), pgSet);
+
+ pg.done();
+ }
+}
private static UiConfigBundle uiconfig;
private static StringIdBundle trans;
private static Cache cache;
- private static Library lib;
+ private static LocalLibrary lib;
private static boolean debug;
private static File coverDir;
private static File readerTmp;
uiconfig = new UiConfigBundle();
trans = new StringIdBundle(getLang());
try {
- lib = new Library(getFile(Config.LIBRARY_DIR),
+ lib = new LocalLibrary(getFile(Config.LIBRARY_DIR),
OutputType.INFO_TEXT, OutputType.CBZ);
} catch (Exception e) {
syserr(new IOException("Cannot create library for directory: "
}
/**
- * Get the (unique) {@link Library} for the program.
+ * Get the (unique) {@link LocalLibrary} for the program.
*
- * @return the {@link Library}
+ * @return the {@link LocalLibrary}
*/
- public static Library getLibrary() {
+ public static BasicLibrary getLibrary() {
return lib;
}
/**
* Return the directory where to store temporary files for the remote
- * {@link Library}.
+ * {@link LocalLibrary}.
*
* @param host
* the remote for this host
+++ /dev/null
-package be.nikiroo.fanfix;
-
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import be.nikiroo.fanfix.bundles.Config;
-import be.nikiroo.fanfix.data.MetaData;
-import be.nikiroo.fanfix.data.Story;
-import be.nikiroo.fanfix.output.BasicOutput;
-import be.nikiroo.fanfix.output.BasicOutput.OutputType;
-import be.nikiroo.fanfix.output.InfoCover;
-import be.nikiroo.fanfix.supported.BasicSupport;
-import be.nikiroo.fanfix.supported.BasicSupport.SupportType;
-import be.nikiroo.fanfix.supported.InfoReader;
-import be.nikiroo.utils.IOUtils;
-import be.nikiroo.utils.Progress;
-
-/**
- * Manage a library of Stories: import, export, list.
- * <p>
- * Each {@link Story} object will be associated with a (local to the library)
- * unique ID, the LUID, which will be used to identify the {@link Story}.
- * <p>
- * Most of the {@link Library} functions work on either the LUID or a partial
- * (cover not included) {@link MetaData} object.
- *
- * @author niki
- */
-public class Library {
- protected File baseDir;
- protected boolean localSpeed;
- protected Map<MetaData, File> stories;
-
- private int lastId;
- private OutputType text;
- private OutputType image;
-
- /**
- * Create a new {@link Library} with the given backend directory.
- *
- * @param dir
- * the directory where to find the {@link Story} objects
- * @param text
- * the {@link OutputType} to save the text-focused stories into
- * @param image
- * the {@link OutputType} to save the images-focused stories into
- */
- public Library(File dir, OutputType text, OutputType image) {
- this();
-
- this.baseDir = dir;
-
- this.lastId = 0;
- this.text = text;
- this.image = image;
-
- dir.mkdirs();
- }
-
- /**
- * Create a new {@link Library} with no link to the local machine.
- * <p>
- * Reserved for extensions.
- */
- protected Library() {
- this.stories = new HashMap<MetaData, File>();
- }
-
- /**
- * Refresh the {@link Library}, that is, make sure all stories are loaded.
- *
- * @param pg
- * the optional progress reporter
- */
- public void refresh(Progress pg) {
- getStories(pg);
- }
-
- /**
- * List all the known types (sources) of stories.
- *
- * @return the types
- */
- public synchronized List<String> getTypes() {
- List<String> list = new ArrayList<String>();
- for (Entry<MetaData, File> entry : getStories(null).entrySet()) {
- String storyType = entry.getKey().getSource();
- if (!list.contains(storyType)) {
- list.add(storyType);
- }
- }
-
- Collections.sort(list);
- return list;
- }
-
- /**
- * List all the known authors of stories.
- *
- * @return the authors
- */
- public synchronized List<String> getAuthors() {
- List<String> list = new ArrayList<String>();
- for (Entry<MetaData, File> entry : getStories(null).entrySet()) {
- String storyAuthor = entry.getKey().getAuthor();
- if (!list.contains(storyAuthor)) {
- list.add(storyAuthor);
- }
- }
-
- Collections.sort(list);
- return list;
- }
-
- /**
- * List all the stories of the given author in the {@link Library}, 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
- */
- public synchronized List<MetaData> getListByAuthor(String author) {
- List<MetaData> list = new ArrayList<MetaData>();
- for (Entry<MetaData, File> entry : getStories(null).entrySet()) {
- String storyAuthor = entry.getKey().getAuthor();
- if (author == null || author.equalsIgnoreCase(storyAuthor)) {
- list.add(entry.getKey());
- }
- }
-
- Collections.sort(list);
- return list;
- }
-
- /**
- * List all the stories of the given source type in the {@link Library}, 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
- */
- public synchronized List<MetaData> getListBySource(String type) {
- List<MetaData> list = new ArrayList<MetaData>();
- for (MetaData meta : getStories(null).keySet()) {
- String storyType = meta.getSource();
- if (type == null || type.equalsIgnoreCase(storyType)) {
- list.add(meta);
- }
- }
-
- Collections.sort(list);
- return list;
- }
-
- /**
- * Retrieve a {@link MetaData} corresponding to the given {@link Story},
- * cover image <b>MAY</b> not be included.
- *
- * @param luid
- * the Library UID of the story
- *
- * @return the corresponding {@link Story}
- */
- public synchronized MetaData getInfo(String luid) {
- if (luid != null) {
- for (Entry<MetaData, File> entry : getStories(null).entrySet()) {
- if (luid.equals(entry.getKey().getLuid())) {
- return entry.getKey();
- }
- }
- }
-
- return null;
- }
-
- /**
- * Retrieve a {@link File} corresponding to the given {@link Story}.
- *
- * @param luid
- * the Library UID of the story
- *
- * @return the corresponding {@link Story}
- */
- public synchronized File getFile(String luid) {
- if (luid != null) {
- for (Entry<MetaData, File> entry : getStories(null).entrySet()) {
- if (luid.equals(entry.getKey().getLuid())) {
- return entry.getValue();
- }
- }
- }
-
- return null;
- }
-
- /**
- * Return the cover image associated to this story.
- *
- * @param luid
- * the Library UID of the story
- *
- * @return the cover image
- */
- public synchronized BufferedImage getCover(String luid) {
- MetaData meta = getInfo(luid);
- if (meta != null) {
- getFile(luid); // to help remote implementation
- try {
- File infoFile = new File(getExpectedFile(meta).getPath()
- + ".info");
- meta = readMeta(infoFile, true).getKey();
- return meta.getCover();
- } catch (IOException e) {
- Instance.syserr(e);
- }
- }
-
- return null;
- }
-
- /**
- * Retrieve a specific {@link Story}.
- *
- * @param luid
- * the Library UID of the story
- * @param pg
- * the optional progress reporter
- *
- * @return the corresponding {@link Story} or NULL if not found
- */
- public synchronized Story getStory(String luid, Progress pg) {
- if (luid != null) {
- for (Entry<MetaData, File> entry : getStories(null).entrySet()) {
- if (luid.equals(entry.getKey().getLuid())) {
- MetaData meta = entry.getKey();
- File file = getFile(luid); // to help remote implementation
- try {
- SupportType type = SupportType.valueOfAllOkUC(meta
- .getType());
- URL url = file.toURI().toURL();
- if (type != null) {
- return BasicSupport.getSupport(type).process(url,
- pg);
- } else {
- throw new IOException("Unknown type: "
- + meta.getType());
- }
- } catch (IOException e) {
- // We should not have not-supported files in the
- // library
- Instance.syserr(new IOException(
- "Cannot load file from library: " + file, e));
- }
- }
- }
- }
-
- if (pg != null) {
- pg.setMinMax(0, 1);
- pg.setProgress(1);
- }
-
- return null;
- }
-
- /**
- * Import the {@link Story} at the given {@link URL} into the
- * {@link Library}.
- *
- * @param url
- * the {@link URL} to import
- * @param pg
- * the optional progress reporter
- *
- * @return the imported {@link Story}
- *
- * @throws IOException
- * in case of I/O error
- */
- public Story imprt(URL url, Progress pg) throws IOException {
- BasicSupport support = BasicSupport.getSupport(url);
- if (support == null) {
- throw new IOException("URL not supported: " + url.toString());
- }
-
- return save(support.process(url, pg), null);
- }
-
- /**
- * Export the {@link Story} to the given target in the given format.
- *
- * @param luid
- * the {@link Story} ID
- * @param type
- * the {@link OutputType} to transform it to
- * @param target
- * the target to save to
- * @param pg
- * the optional progress reporter
- *
- * @return the saved resource (the main saved {@link File})
- *
- * @throws IOException
- * in case of I/O error
- */
- public File export(String luid, OutputType type, String target, Progress pg)
- throws IOException {
- Progress pgGetStory = new Progress();
- Progress pgOut = new Progress();
- if (pg != null) {
- pg.setMax(2);
- pg.addProgress(pgGetStory, 1);
- pg.addProgress(pgOut, 1);
- }
-
- BasicOutput out = BasicOutput.getOutput(type, true);
- if (out == null) {
- throw new IOException("Output type not supported: " + type);
- }
-
- Story story = getStory(luid, pgGetStory);
- if (story == null) {
- throw new IOException("Cannot find story to export: " + luid);
- }
-
- return out.process(story, target, pgOut);
- }
-
- /**
- * Save a {@link Story} to the {@link Library}.
- *
- * @param story
- * the {@link Story} to save
- * @param pg
- * the optional progress reporter
- *
- * @return the same {@link Story}, whose LUID may have changed
- *
- * @throws IOException
- * in case of I/O error
- */
- public Story save(Story story, Progress pg) throws IOException {
- return save(story, null, pg);
- }
-
- /**
- * Save a {@link Story} to the {@link Library} -- the LUID <b>must</b> be
- * correct, or NULL to get the next free one.
- *
- * @param story
- * the {@link Story} to save
- * @param luid
- * the <b>correct</b> LUID or NULL to get the next free one
- * @param pg
- * the optional progress reporter
- *
- * @return the same {@link Story}, whose LUID may have changed
- *
- * @throws IOException
- * in case of I/O error
- */
- public synchronized Story save(Story story, String luid, Progress pg)
- throws IOException {
- // Do not change the original metadata, but change the original story
- MetaData key = story.getMeta().clone();
- story.setMeta(key);
-
- if (luid == null || luid.isEmpty()) {
- getStories(null); // refresh lastId if needed
- key.setLuid(String.format("%03d", (++lastId)));
- } else {
- key.setLuid(luid);
- }
-
- getExpectedDir(key.getSource()).mkdirs();
- if (!getExpectedDir(key.getSource()).exists()) {
- throw new IOException("Cannot create library dir");
- }
-
- OutputType out;
- if (key != null && key.isImageDocument()) {
- out = image;
- } else {
- out = text;
- }
-
- BasicOutput it = BasicOutput.getOutput(out, true);
- it.process(story, getExpectedFile(key).getPath(), pg);
-
- // empty cache
- stories.clear();
-
- return story;
- }
-
- /**
- * Delete the given {@link Story} from this {@link Library}.
- *
- * @param luid
- * the LUID of the target {@link Story}
- *
- * @return TRUE if it was deleted
- */
- public synchronized boolean delete(String luid) {
- boolean ok = false;
-
- List<File> files = getFiles(luid);
- if (!files.isEmpty()) {
- for (File file : files) {
- IOUtils.deltree(file);
- }
-
- ok = true;
-
- // clear cache
- stories.clear();
- }
-
- return ok;
- }
-
- /**
- * Change the type (source) of the given {@link Story}.
- *
- * @param luid
- * the {@link Story} LUID
- * @param newType
- * the new type
- *
- * @return TRUE if the {@link Story} was found
- */
- public synchronized boolean changeType(String luid, String newType) {
- MetaData meta = getInfo(luid);
- if (meta != null) {
- meta.setSource(newType);
- File newDir = getExpectedDir(meta.getSource());
- if (!newDir.exists()) {
- newDir.mkdir();
- }
-
- List<File> files = getFiles(luid);
- for (File file : files) {
- if (file.getName().endsWith(".info")) {
- try {
- String name = file.getName().replaceFirst("\\.info$",
- "");
- InfoCover.writeInfo(newDir, name, meta);
- file.delete();
- } catch (IOException e) {
- Instance.syserr(e);
- }
- } else {
- file.renameTo(new File(newDir, file.getName()));
- }
- }
-
- // clear cache
- stories.clear();
-
- return true;
- }
-
- return false;
- }
-
- /**
- * The library is accessed locally or at local speed (for operations like
- * {@link Library#getFile(String)}).
- * <p>
- * It could be cached, too, it is only about the access speed.
- *
- * @return TRUE if it is accessed locally
- */
- public boolean isLocalSpeed() {
- return localSpeed;
- }
-
- /**
- * Return the list of files/dirs on disk for this {@link Story}.
- * <p>
- * If the {@link Story} is not found, and empty list is returned.
- *
- * @param luid
- * the {@link Story} LUID
- *
- * @return the list of {@link File}s
- */
- private List<File> getFiles(String luid) {
- List<File> files = new ArrayList<File>();
-
- MetaData meta = getInfo(luid);
- File file = getFile(luid); // to help remote implementation
-
- if (file != null) {
- files.add(file);
-
- String readerExt = getOutputType(meta).getDefaultExtension(true);
- String fileExt = getOutputType(meta).getDefaultExtension(false);
-
- String path = file.getAbsolutePath();
- if (readerExt != null && !readerExt.equals(fileExt)) {
- path = path.substring(0, path.length() - readerExt.length())
- + fileExt;
- file = new File(path);
-
- if (file.exists()) {
- files.add(file);
- }
- }
-
- File infoFile = new File(path + ".info");
- if (!infoFile.exists()) {
- infoFile = new File(path.substring(0,
- path.length() - fileExt.length())
- + ".info");
- }
-
- if (infoFile.exists()) {
- files.add(infoFile);
- }
-
- String coverExt = "."
- + Instance.getConfig().getString(Config.IMAGE_FORMAT_COVER);
- File coverFile = new File(path + coverExt);
- if (!coverFile.exists()) {
- coverFile = new File(path.substring(0,
- path.length() - fileExt.length())
- + coverExt);
- }
-
- if (coverFile.exists()) {
- files.add(coverFile);
- }
- }
-
- return files;
- }
-
- /**
- * The directory (full path) where the {@link Story} related to this
- * {@link MetaData} should be located on disk.
- *
- * @param type
- * the type (source)
- *
- * @return the target directory
- */
- private File getExpectedDir(String type) {
- String source = type.replaceAll("[^a-zA-Z0-9._+-]", "_");
- return new File(baseDir, source);
- }
-
- /**
- * The target (full path) where the {@link Story} related to this
- * {@link MetaData} should be located on disk.
- *
- * @param key
- * the {@link Story} {@link MetaData}
- *
- * @return the target
- */
- private File getExpectedFile(MetaData key) {
- String title = key.getTitle();
- if (title == null) {
- title = "";
- }
- title = title.replaceAll("[^a-zA-Z0-9._+-]", "_");
- return new File(getExpectedDir(key.getSource()), key.getLuid() + "_"
- + title);
- }
-
- /**
- * Return all the known stories in this {@link Library} object.
- *
- * @param pg
- * the optional progress reporter
- *
- * @return the stories
- */
- protected synchronized Map<MetaData, File> getStories(Progress pg) {
- if (pg == null) {
- pg = new Progress();
- } else {
- pg.setMinMax(0, 100);
- }
-
- if (stories.isEmpty()) {
- lastId = 0;
-
- File[] dirs = baseDir.listFiles(new FileFilter() {
- public boolean accept(File file) {
- return file != null && file.isDirectory();
- }
- });
-
- Progress pgDirs = new Progress(0, 100 * dirs.length);
- pg.addProgress(pgDirs, 100);
-
- for (File dir : dirs) {
- File[] files = dir.listFiles(new FileFilter() {
- public boolean accept(File file) {
- return file != null
- && file.getPath().toLowerCase()
- .endsWith(".info");
- }
- });
-
- Progress pgFiles = new Progress(0, files.length);
- pgDirs.addProgress(pgFiles, 100);
- pgDirs.setName("Loading from: " + dir.getName());
-
- for (File file : files) {
- pgFiles.setName(file.getName());
- try {
- Entry<MetaData, File> entry = readMeta(file, false);
- try {
- int id = Integer.parseInt(entry.getKey().getLuid());
- if (id > lastId) {
- lastId = id;
- }
-
- stories.put(entry.getKey(), entry.getValue());
- } catch (Exception e) {
- // not normal!!
- throw new IOException(
- "Cannot understand the LUID of "
- + file.getPath() + ": "
- + entry.getKey().getLuid(), e);
- }
- } catch (IOException e) {
- // We should not have not-supported files in the
- // library
- Instance.syserr(new IOException(
- "Cannot load file from library: "
- + file.getPath(), e));
- }
- pgFiles.add(1);
- }
-
- pgFiles.setName(null);
- }
-
- pgDirs.setName("Loading directories");
- }
-
- return stories;
- }
-
- private Entry<MetaData, File> readMeta(File infoFile, boolean withCover)
- throws IOException {
-
- final MetaData meta = InfoReader.readMeta(infoFile, withCover);
-
- // Replace .info with whatever is needed:
- String path = infoFile.getPath();
- path = path.substring(0, path.length() - ".info".length());
-
- String newExt = getOutputType(meta).getDefaultExtension(true);
-
- File targetFile = new File(path + newExt);
-
- final File ffile = targetFile;
- return new Entry<MetaData, File>() {
- public File setValue(File value) {
- return null;
- }
-
- public File getValue() {
- return ffile;
- }
-
- public MetaData getKey() {
- return meta;
- }
- };
- }
-
- /**
- * Return the {@link OutputType} for this {@link Story}.
- *
- * @param meta
- * the {@link Story} {@link MetaData}
- *
- * @return the type
- */
- private OutputType getOutputType(MetaData meta) {
- if (meta != null && meta.isImageDocument()) {
- return image;
- } else {
- return text;
- }
- }
-}
--- /dev/null
+package be.nikiroo.fanfix;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import be.nikiroo.fanfix.bundles.Config;
+import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.data.Story;
+import be.nikiroo.fanfix.output.BasicOutput;
+import be.nikiroo.fanfix.output.BasicOutput.OutputType;
+import be.nikiroo.fanfix.output.InfoCover;
+import be.nikiroo.fanfix.supported.InfoReader;
+import be.nikiroo.utils.IOUtils;
+import be.nikiroo.utils.Progress;
+
+/**
+ * This {@link BasicLibrary} will store the stories locally on disk.
+ *
+ * @author niki
+ */
+public class LocalLibrary extends BasicLibrary {
+ private int lastId;
+ private Map<MetaData, File[]> stories; // Files: [ infoFile, TargetFile ]
+
+ private File baseDir;
+ private OutputType text;
+ private OutputType image;
+
+ /**
+ * Create a new {@link LocalLibrary} with the given back-end directory.
+ *
+ * @param baseDir
+ * the directory where to find the {@link Story} objects
+ * @param text
+ * the {@link OutputType} to save the text-focused stories into
+ * @param image
+ * the {@link OutputType} to save the images-focused stories into
+ */
+ public LocalLibrary(File baseDir, OutputType text, OutputType image) {
+ this.baseDir = baseDir;
+ this.text = text;
+ this.image = image;
+
+ this.lastId = 0;
+ this.stories = null;
+
+ baseDir.mkdirs();
+ }
+
+ @Override
+ protected List<MetaData> getMetas(Progress pg) {
+ return new ArrayList<MetaData>(getStories(pg).keySet());
+ }
+
+ @Override
+ public File getFile(String luid) {
+ File[] files = getStories(null).get(getInfo(luid));
+ if (files != null) {
+ return files[1];
+ }
+
+ return null;
+ }
+
+ @Override
+ public BufferedImage getCover(String luid) {
+ MetaData meta = getInfo(luid);
+ if (meta != null) {
+ File[] files = getStories(null).get(meta);
+ if (files != null) {
+ File infoFile = files[0];
+
+ try {
+ meta = InfoReader.readMeta(infoFile, true);
+ return meta.getCover();
+ } catch (IOException e) {
+ Instance.syserr(e);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void clearCache() {
+ stories = null;
+ }
+
+ @Override
+ protected synchronized int getNextId() {
+ return ++lastId;
+ }
+
+ @Override
+ protected void doDelete(String luid) throws IOException {
+ for (File file : getRelatedFiles(luid)) {
+ // TODO: throw an IOException if we cannot delete the files?
+ IOUtils.deltree(file);
+ }
+ }
+
+ @Override
+ protected Story doSave(Story story, Progress pg) throws IOException {
+ MetaData meta = story.getMeta();
+
+ File expectedTarget = getExpectedFile(meta);
+ expectedTarget.getParentFile().mkdirs();
+
+ BasicOutput it = BasicOutput.getOutput(getOutputType(meta), true);
+ it.process(story, expectedTarget.getPath(), pg);
+
+ return story;
+ }
+
+ @Override
+ protected synchronized void saveMeta(MetaData meta, Progress pg)
+ throws IOException {
+ File newDir = getExpectedDir(meta.getSource());
+ if (!newDir.exists()) {
+ newDir.mkdir();
+ }
+
+ List<File> relatedFiles = getRelatedFiles(meta.getLuid());
+ for (File relatedFile : relatedFiles) {
+ // TODO: this is not safe at all.
+ // We should copy all the files THEN delete them
+ // Maybe also adding some rollback cleanup if possible
+ if (relatedFile.getName().endsWith(".info")) {
+ try {
+ String name = relatedFile.getName().replaceFirst(
+ "\\.info$", "");
+ InfoCover.writeInfo(newDir, name, meta);
+ relatedFile.delete();
+ } catch (IOException e) {
+ Instance.syserr(e);
+ }
+ } else {
+ relatedFile.renameTo(new File(newDir, relatedFile.getName()));
+ }
+ }
+
+ clearCache();
+ }
+
+ /**
+ * Return the {@link OutputType} for this {@link Story}.
+ *
+ * @param meta
+ * the {@link Story} {@link MetaData}
+ *
+ * @return the type
+ */
+ private OutputType getOutputType(MetaData meta) {
+ if (meta != null && meta.isImageDocument()) {
+ return image;
+ } else {
+ return text;
+ }
+ }
+
+ /**
+ * Get the target {@link File} related to the given <tt>.info</tt>
+ * {@link File} and {@link MetaData}.
+ *
+ * @param meta
+ * the meta
+ * @param infoFile
+ * the <tt>.info</tt> {@link File}
+ *
+ * @return the target {@link File}
+ */
+ private File getTargetFile(MetaData meta, File infoFile) {
+ // Replace .info with whatever is needed:
+ String path = infoFile.getPath();
+ path = path.substring(0, path.length() - ".info".length());
+ String newExt = getOutputType(meta).getDefaultExtension(true);
+
+ return new File(path + newExt);
+ }
+
+ /**
+ * The target (full path) where the {@link Story} related to this
+ * {@link MetaData} should be located on disk for a new {@link Story}.
+ *
+ * @param key
+ * the {@link Story} {@link MetaData}
+ *
+ * @return the target
+ */
+ private File getExpectedFile(MetaData key) {
+ String title = key.getTitle();
+ if (title == null) {
+ title = "";
+ }
+ title = title.replaceAll("[^a-zA-Z0-9._+-]", "_");
+ return new File(getExpectedDir(key.getSource()), key.getLuid() + "_"
+ + title);
+ }
+
+ /**
+ * The directory (full path) where the new {@link Story} related to this
+ * {@link MetaData} should be located on disk.
+ *
+ * @param type
+ * the type (source)
+ *
+ * @return the target directory
+ */
+ private File getExpectedDir(String type) {
+ String source = type.replaceAll("[^a-zA-Z0-9._+-]", "_");
+ return new File(baseDir, source);
+ }
+
+ /**
+ * Return the list of files/directories on disk for this {@link Story}.
+ * <p>
+ * If the {@link Story} is not found, and empty list is returned.
+ *
+ * @param luid
+ * the {@link Story} LUID
+ *
+ * @return the list of {@link File}s
+ *
+ * @throws IOException
+ * if the {@link Story} was not found
+ */
+ private List<File> getRelatedFiles(String luid) throws IOException {
+ List<File> files = new ArrayList<File>();
+
+ MetaData meta = getInfo(luid);
+ if (meta == null) {
+ throw new IOException("Story not found: " + luid);
+ } else {
+ File infoFile = getStories(null).get(meta)[0];
+ File targetFile = getStories(null).get(meta)[1];
+
+ files.add(infoFile);
+ files.add(targetFile);
+
+ String readerExt = getOutputType(meta).getDefaultExtension(true);
+ String fileExt = getOutputType(meta).getDefaultExtension(false);
+
+ String path = targetFile.getAbsolutePath();
+ if (readerExt != null && !readerExt.equals(fileExt)) {
+ path = path.substring(0, path.length() - readerExt.length())
+ + fileExt;
+ File relatedFile = new File(path);
+
+ if (relatedFile.exists()) {
+ files.add(relatedFile);
+ }
+ }
+
+ String coverExt = "."
+ + Instance.getConfig().getString(Config.IMAGE_FORMAT_COVER);
+ File coverFile = new File(path + coverExt);
+ if (!coverFile.exists()) {
+ coverFile = new File(path.substring(0,
+ path.length() - fileExt.length())
+ + coverExt);
+ }
+
+ if (coverFile.exists()) {
+ files.add(coverFile);
+ }
+ }
+
+ return files;
+ }
+
+ /**
+ * Fill the list of stories by reading the content of the local directory
+ * {@link LocalLibrary#baseDir}.
+ * <p>
+ * Will use a cached list when possible (see
+ * {@link BasicLibrary#clearCache()}).
+ *
+ * @param pg
+ * the optional {@link Progress}
+ *
+ * @return the list of stories
+ */
+ private synchronized Map<MetaData, File[]> getStories(Progress pg) {
+ if (pg == null) {
+ pg = new Progress();
+ } else {
+ pg.setMinMax(0, 100);
+ }
+
+ if (stories == null) {
+ stories = new HashMap<MetaData, File[]>();
+
+ lastId = 0;
+
+ File[] dirs = baseDir.listFiles(new FileFilter() {
+ public boolean accept(File file) {
+ return file != null && file.isDirectory();
+ }
+ });
+
+ Progress pgDirs = new Progress(0, 100 * dirs.length);
+ pg.addProgress(pgDirs, 100);
+
+ for (File dir : dirs) {
+ File[] infoFiles = dir.listFiles(new FileFilter() {
+ public boolean accept(File file) {
+ return file != null
+ && file.getPath().toLowerCase()
+ .endsWith(".info");
+ }
+ });
+
+ Progress pgFiles = new Progress(0, infoFiles.length);
+ pgDirs.addProgress(pgFiles, 100);
+ pgDirs.setName("Loading from: " + dir.getName());
+
+ for (File infoFile : infoFiles) {
+ pgFiles.setName(infoFile.getName());
+ try {
+ MetaData meta = InfoReader.readMeta(infoFile, false);
+ try {
+ int id = Integer.parseInt(meta.getLuid());
+ if (id > lastId) {
+ lastId = id;
+ }
+
+ stories.put(meta, new File[] { infoFile,
+ getTargetFile(meta, infoFile) });
+ } catch (Exception e) {
+ // not normal!!
+ throw new IOException(
+ "Cannot understand the LUID of "
+ + infoFile
+ + ": "
+ + (meta == null ? "[meta is NULL]"
+ : meta.getLuid()), e);
+ }
+ } catch (IOException e) {
+ // We should not have not-supported files in the
+ // library
+ Instance.syserr(new IOException(
+ "Cannot load file from library: " + infoFile, e));
+ }
+ pgFiles.add(1);
+ }
+
+ pgFiles.setName(null);
+ }
+
+ pgDirs.setName("Loading directories");
+ }
+
+ return stories;
+ }
+}
host = args[i];
} else if (port == null) {
port = Integer.parseInt(args[i]);
- try {
- BasicReader.setDefaultLibrary(new RemoteLibrary(host,
- port));
- } catch (IOException e) {
- Instance.syserr(e);
- }
+ BasicReader
+ .setDefaultLibrary(new RemoteLibrary(host, port));
action = MainAction.START;
} else {
exitCode = 255;
}
/**
- * Import the given resource into the {@link Library}.
+ * Import the given resource into the {@link LocalLibrary}.
*
* @param urlString
* the resource to import
}
/**
- * Export the {@link Story} from the {@link Library} to the given target.
+ * Export the {@link Story} from the {@link LocalLibrary} to the given
+ * target.
*
* @param luid
* the story LUID
}
/**
- * List the stories of the given source from the {@link Library} (unless
- * NULL is passed, in which case all stories will be listed).
+ * List the stories of the given source from the {@link LocalLibrary}
+ * (unless NULL is passed, in which case all stories will be listed).
*
* @param source
* the source to list the known stories of, or NULL to list all
* Start the CLI reader for this {@link Story}.
*
* @param story
- * the LUID of the {@link Story} in the {@link Library} <b>or</b>
- * the {@link Story} {@link URL}
+ * the LUID of the {@link Story} in the {@link LocalLibrary}
+ * <b>or</b> the {@link Story} {@link URL}
* @param chapString
* which {@link Chapter} to read (starting at 1), or NULL to get
* the {@link Story} description
package be.nikiroo.fanfix;
+import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.data.Story;
import be.nikiroo.utils.Version;
import be.nikiroo.utils.serial.ConnectActionClient;
-public class RemoteLibrary extends Library {
+/**
+ * This {@link BasicLibrary} will access a remote server to list the available
+ * stories, and download the one you try to load to the local directory
+ * specified in the configuration.
+ *
+ * @author niki
+ */
+public class RemoteLibrary extends BasicLibrary {
private String host;
private int port;
-
- private Library lib;
-
- public RemoteLibrary(String host, int port) throws IOException {
+ private File baseDir;
+
+ private LocalLibrary lib;
+ private List<MetaData> metas;
+
+ /**
+ * Create a {@link RemoteLibrary} linked to the given server.
+ *
+ * @param host
+ * the host to contact or NULL for localhost
+ * @param port
+ * the port to contact it on
+ */
+ public RemoteLibrary(String host, int port) {
this.host = host;
this.port = port;
- this.localSpeed = false;
this.baseDir = Instance.getRemoteDir(host);
this.baseDir.mkdirs();
- this.lib = new Library(baseDir, OutputType.INFO_TEXT, OutputType.CBZ);
+ this.lib = new LocalLibrary(baseDir, OutputType.INFO_TEXT,
+ OutputType.CBZ);
}
@Override
- public synchronized Story save(Story story, String luid, Progress pg)
- throws IOException {
- throw new java.lang.InternalError(
- "No write support allowed on remote Libraries");
- }
+ protected List<MetaData> getMetas(Progress pg) {
+ // TODO: progress
- @Override
- public synchronized boolean delete(String luid) {
- throw new java.lang.InternalError(
- "No write support allowed on remote Libraries");
- }
+ if (metas == null) {
+ metas = new ArrayList<MetaData>();
- @Override
- public synchronized boolean changeType(String luid, String newType) {
- throw new java.lang.InternalError(
- "No write support allowed on remote Libraries");
- }
-
- @Override
- protected synchronized Map<MetaData, File> getStories(Progress pg) {
- // TODO: progress
- if (stories.isEmpty()) {
try {
new ConnectActionClient(host, port, true, null) {
public void action(Version serverVersion) throws Exception {
try {
Object rep = send("GET_METADATA *");
for (MetaData meta : (MetaData[]) rep) {
- stories.put(meta, null);
+ metas.add(meta);
}
} catch (Exception e) {
- e.printStackTrace();
+ Instance.syserr(e);
}
}
}.connect();
}
}
- return stories;
+ return metas;
}
@Override
if (file != null) {
MetaData meta = getInfo(luid);
- stories.put(meta, file);
+ metas.add(meta);
}
return file;
}
+
+ @Override
+ public BufferedImage getCover(String luid) {
+ // Retrieve it from the network if needed:
+ if (lib.getInfo(luid) == null) {
+ getFile(luid);
+ }
+
+ return lib.getCover(luid);
+ }
+
+ @Override
+ protected void clearCache() {
+ metas = null;
+ lib.clearCache();
+ }
+
+ @Override
+ public synchronized Story save(Story story, String luid, Progress pg)
+ throws IOException {
+ throw new java.lang.InternalError(
+ "No write support allowed on remote Libraries");
+ }
+
+ @Override
+ protected int getNextId() {
+ throw new java.lang.InternalError(
+ "No write support allowed on remote Libraries");
+ }
+
+ @Override
+ protected void doDelete(String luid) throws IOException {
+ throw new java.lang.InternalError(
+ "No write support allowed on remote Libraries");
+ }
+
+ @Override
+ protected Story doSave(Story story, Progress pg) throws IOException {
+ throw new java.lang.InternalError(
+ "No write support allowed on remote Libraries");
+ }
}
import java.io.File;
import java.io.IOException;
+import java.util.List;
import java.util.Map;
import be.nikiroo.fanfix.data.MetaData;
if (command != null) {
if (command.equals("GET_METADATA")) {
if (args != null && args.equals("*")) {
- Map<MetaData, File> stories = Instance.getLibrary()
- .getStories(null);
- return stories.keySet().toArray(new MetaData[] {});
+ List<MetaData> metas = Instance.getLibrary().getMetas(null);
+ return metas.toArray(new MetaData[] {});
}
} else if (command.equals("GET_STORY")) {
if (args != null) {
* which to retrieve stories, then process them into <tt>epub</tt> (or other)
* files that you can read anywhere.
* <p>
- * It has support for a {@link be.nikiroo.fanfix.Library} system, too.
+ * It has support for a {@link be.nikiroo.fanfix.BasicLibrary} system, too.
*
* @author niki
*/
import java.net.MalformedURLException;
import java.net.URL;
+import be.nikiroo.fanfix.BasicLibrary;
import be.nikiroo.fanfix.Instance;
-import be.nikiroo.fanfix.Library;
+import be.nikiroo.fanfix.LocalLibrary;
import be.nikiroo.fanfix.bundles.Config;
import be.nikiroo.fanfix.bundles.UiConfig;
import be.nikiroo.fanfix.data.MetaData;
}
}
- private static Library defaultLibrary = Instance.getLibrary();
+ private static BasicLibrary defaultLibrary = Instance.getLibrary();
private static ReaderType defaultType = ReaderType.GUI;
- private Library lib;
+ private BasicLibrary lib;
private Story story;
private ReaderType type;
}
/**
- * The {@link Library} to load the stories from (by default, takes the
- * default {@link Library}).
+ * The {@link LocalLibrary} to load the stories from (by default, takes the
+ * default {@link LocalLibrary}).
*
- * @return the {@link Library}
+ * @return the {@link LocalLibrary}
*/
- public Library getLibrary() {
+ public BasicLibrary getLibrary() {
if (lib == null) {
lib = defaultLibrary;
}
}
/**
- * Change the {@link Library} that will be managed by this
+ * Change the {@link LocalLibrary} that will be managed by this
* {@link BasicReader}.
*
* @param lib
- * the new {@link Library}
+ * the new {@link LocalLibrary}
*/
- public void setLibrary(Library lib) {
+ public void setLibrary(LocalLibrary lib) {
this.lib = lib;
}
/**
* Create a new {@link BasicReader} for a {@link Story} in the
- * {@link Library}.
+ * {@link LocalLibrary}.
*
* @param luid
* the {@link Story} ID
}
/**
- * Change the default {@link Library} to open with the {@link BasicReader}s.
+ * Change the default {@link LocalLibrary} to open with the
+ * {@link BasicReader}s.
*
* @param lib
- * the new {@link Library}
+ * the new {@link LocalLibrary}
*/
- public static void setDefaultLibrary(Library lib) {
+ public static void setDefaultLibrary(BasicLibrary lib) {
BasicReader.defaultLibrary = lib;
}
}
// open with external player the related file
- public static void open(Library lib, String luid) throws IOException {
+ public static void open(BasicLibrary lib, String luid) throws IOException {
MetaData meta = lib.getInfo(luid);
File target = lib.getFile(luid);
import javax.swing.event.HyperlinkListener;
import be.nikiroo.fanfix.Instance;
-import be.nikiroo.fanfix.Library;
+import be.nikiroo.fanfix.LocalLibrary;
import be.nikiroo.fanfix.VersionCheck;
import be.nikiroo.fanfix.bundles.UiConfig;
import be.nikiroo.fanfix.data.Story;
class LocalReader extends BasicReader {
static private boolean nativeLookLoaded;
- private Library localLibrary;
+ private LocalLibrary localLibrary;
public LocalReader() throws IOException {
if (!nativeLookLoaded) {
key, value), e);
}
- localLibrary = new Library(dir, text, images);
+ localLibrary = new LocalLibrary(dir, text, images);
}
@Override
// delete from local reader library
void clearLocalReaderCache(String luid) {
- localLibrary.delete(luid);
+ try {
+ localLibrary.delete(luid);
+ } catch (IOException e) {
+ Instance.syserr(e);
+ }
}
// delete from main library
void delete(String luid) {
- localLibrary.delete(luid);
- Instance.getLibrary().delete(luid);
+ try {
+ localLibrary.delete(luid);
+ Instance.getLibrary().delete(luid);
+ } catch (IOException e) {
+ Instance.syserr(e);
+ }
}
// open the given book
}
void changeType(String luid, String newType) {
- localLibrary.changeType(luid, newType);
- Instance.getLibrary().changeType(luid, newType);
+ try {
+ localLibrary.changeSource(luid, newType, null);
+ Instance.getLibrary().changeSource(luid, newType, null);
+ } catch (IOException e) {
+ Instance.syserr(e);
+ }
}
}
import javax.swing.filechooser.FileNameExtensionFilter;
import be.nikiroo.fanfix.Instance;
-import be.nikiroo.fanfix.Library;
+import be.nikiroo.fanfix.LocalLibrary;
import be.nikiroo.fanfix.bundles.Config;
import be.nikiroo.fanfix.bundles.UiConfig;
import be.nikiroo.fanfix.data.MetaData;
*
* @param reader
* the associated {@link LocalReader} to forward some commands
- * and access its {@link Library}
+ * and access its {@link LocalLibrary}
* @param type
* the type of {@link Story} to load, or NULL for all types
*/
final String typeF = type;
outOfUi(pg, new Runnable() {
public void run() {
- Instance.getLibrary().refresh(pg);
+ Instance.getLibrary().refresh(false, pg);
invalidate();
setJMenuBar(createMenu());
addBookPane(typeF, true);
private void addBookPane(String value, boolean type) {
if (value == null) {
if (type) {
- for (String tt : Instance.getLibrary().getTypes()) {
+ for (String tt : Instance.getLibrary().getSources()) {
if (tt != null) {
addBookPane(tt, type);
}
JMenu sources = new JMenu("Sources");
sources.setMnemonic(KeyEvent.VK_S);
- List<String> tt = Instance.getLibrary().getTypes();
+ List<String> tt = Instance.getLibrary().getSources();
tt.add(0, null);
for (final String type : tt) {
JMenuItem item = new JMenuItem(type == null ? "All" : type);
List<String> types = new ArrayList<String>();
types.add(null);
- types.addAll(Instance.getLibrary().getTypes());
+ types.addAll(Instance.getLibrary().getSources());
for (String type : types) {
JMenuItem item = new JMenuItem(type == null ? "New type..." : type);
}
/**
- * Import a {@link Story} into the main {@link Library}.
+ * Import a {@link Story} into the main {@link LocalLibrary}.
* <p>
* Should be called inside the UI thread.
*
}
/**
- * Actually import the {@link Story} into the main {@link Library}.
+ * Actually import the {@link Story} into the main {@link LocalLibrary}.
* <p>
* Should be called inside the UI thread.
*
import java.util.List;
import be.nikiroo.fanfix.Instance;
-import be.nikiroo.fanfix.Library;
+import be.nikiroo.fanfix.LocalLibrary;
import be.nikiroo.fanfix.data.MetaData;
class TuiReader extends BasicReader {
import jexer.TText;
import jexer.TWindow;
import jexer.event.TResizeEvent;
+import be.nikiroo.fanfix.BasicLibrary;
import be.nikiroo.fanfix.Instance;
-import be.nikiroo.fanfix.Library;
+import be.nikiroo.fanfix.LocalLibrary;
import be.nikiroo.fanfix.data.Chapter;
import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.data.Paragraph;
import be.nikiroo.fanfix.data.Story;
public class TuiReaderStoryWindow extends TWindow {
- private Library lib;
+ private BasicLibrary lib;
private MetaData meta;
private Story story;
private TText textField;
private List<TButton> navigationButtons;
private TLabel chapterName;
- public TuiReaderStoryWindow(TApplication app, Library lib, MetaData meta) {
+ public TuiReaderStoryWindow(TApplication app, BasicLibrary lib,
+ MetaData meta) {
this(app, lib, meta, 0);
}
- public TuiReaderStoryWindow(TApplication app, Library lib, MetaData meta,
- int chapter) {
+ public TuiReaderStoryWindow(TApplication app, BasicLibrary lib,
+ MetaData meta, int chapter) {
super(app, desc(meta), 0, 0, 60, 18, CENTERED | RESIZABLE);
-
+
this.lib = lib;
this.meta = meta;
import java.util.ArrayList;
import java.util.List;
-import be.nikiroo.fanfix.Library;
+import be.nikiroo.fanfix.BasicLibrary;
+import be.nikiroo.fanfix.LocalLibrary;
import be.nikiroo.fanfix.data.Chapter;
import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.data.Paragraph;
import be.nikiroo.utils.test.TestLauncher;
public class LibraryTest extends TestLauncher {
- private Library lib;
+ private BasicLibrary lib;
private File tmp;
public LibraryTest(String[] args) {
addTest(new TestCase("getList") {
@Override
public void test() throws Exception {
- // TODO: getList
- List<MetaData> metas = lib.getListBySource(null);
+ List<MetaData> metas = lib.getList();
assertEquals(0, metas.size());
}
});
lib.save(story(luid1, "My story 1", source1, author1),
luid1, null);
- // TODO: getList
- List<MetaData> metas = lib.getListBySource(null);
+ List<MetaData> metas = lib.getList();
assertEquals(1, metas.size());
}
});
lib.save(story(luid2, "My story 2", source2, author1),
luid2, null);
- // TODO: getList
- metas = lib.getListBySource(null);
+ metas = lib.getList();
assertEquals(2, metas.size());
lib.save(story(luid3, "My story 3", source2, author1),
luid3, null);
- // TODO: getList
- metas = lib.getListBySource(null);
+ metas = lib.getList();
assertEquals(3, metas.size());
}
});
@Override
public void test() throws Exception {
// same luid as a previous one
- lib.save(story(luid3, "My story 3", source2, author2),
- luid3, null);
+ lib.save(
+ story(luid3, "My story 3 [edited]", source2,
+ author2), luid3, null);
- // TODO: getList
- List<MetaData> metas = lib.getListBySource(null);
+ List<MetaData> metas = lib.getList();
assertEquals(3, metas.size());
}
});
addTest(new TestCase("getList with results") {
@Override
public void test() throws Exception {
- // TODO: getList
- List<MetaData> metas = lib.getListBySource(null);
+ List<MetaData> metas = lib.getList();
assertEquals(3, metas.size());
}
});
public void test() throws Exception {
List<MetaData> metas = null;
- lib.changeType(luid3, source1);
+ lib.changeSource(luid3, source1, null);
metas = lib.getListBySource(source1);
assertEquals(2, metas.size());
tmp.delete();
tmp.mkdir();
- lib = new Library(tmp, OutputType.INFO_TEXT, OutputType.CBZ);
+ lib = new LocalLibrary(tmp, OutputType.INFO_TEXT, OutputType.CBZ);
}
@Override