```./configure.sh && make build test run-test```
+Si vous faites tourner les tests unitaires, sachez que certains fichiers flags peuvent les impacter:
+
+- ```test/VERBOSE``` : active le mode verbeux pour les erreurs
+- ```test/OFFLINE``` : ne permet pas au programme de télécharger des données
+- ```test/URLS``` : permet au programme de tester des URLs
+- ```test/FORCE_REFRESH```: force le nettoyage du cache
+
+Notez que le répertoire ```test/CACHE``` peut rester en place; il contient tous les fichiers téléchargés au moins une fois depuis le réseau par les tests unitaires (si vous autorisez les tests d'URLs, lancez les tests au moins une fois pour peupler le CACHE, puis activez le mode OFFLINE, ça marchera toujours).
+
+Les fichiers de test seront:
+
+- ```test/*.url``` : des URLs à télécharger en fichier texte (le contenu du fichier est l'URL)
+- ```test/*.story```: des histoires en mode texte (le contenu du fichier est l'histoire)
+
### Librairies dépendantes (incluses)
Nécessaires :
```./configure.sh && make build test run-test```
+If you run the unit tests, note that some flag files can impact them:
+
+- ```test/VERBOSE``` : enable verbose mode
+- ```test/OFFLINE``` : to forbid any downloading
+- ```test/URLS``` : to allow testing URLs
+- ```test/FORCE_REFRESH```: to force a clear of the cache
+
+Note that ```test/CACHE``` can be kept, as it will contain all internet related files you need (if you allow URLs, run the test once which will populate the CACHE then go OFFLINE, it will still work).
+
+The test files will be:
+
+- ```test/*.url``` : URL to download in text format, content = URL
+- ```test/*.story```: text mode story, content = story
+
+
### Dependant libraries (included)
Required:
- [ ] Add the resume in the Properties page (maybe a second tab?)
- [ ] Bugs
- [x] Fix "Redownload also reset the source"
- - [ ] Fix "Redownload remote does not show the new item before restart of client app"
+ - [x] Fix "Redownload remote does not show the new item before restart of client app"
- [x] Fix eHentai "content warning" access (see 455)
- [ ] Fix the configuration system (for new or changed options, new or changed languages)
- - [ ] remote import also download the file in cache, why?
+ - [x] remote import also download the file in cache, why?
- [x] import file in remote mode tries to import remote file!!
- [ ] import file does not find author in cbz with SUMMARY file
- [x] import file:// creates a tmp without auto-deletion in /tmp/fanfic-...
- new: support d'un proxy
- fix: support des CBZ contenant du texte
- fix: correction de DEBUG=0
+- fix: correction des histoires importées qui n'arrivent pas immédiatement à l'affichage
- gui: correction pour le focus
- gui: fix pour la couleur d'arrière plan
- gui: fix pour la navigation au clavier (haut et bas)
- gui: configuration beaucoup plus facile
+- gui: peut maintenant télécharger toutes les histoires d'un groupe en cache en une fois
- MangaLEL: site web changé
- search: supporte MangaLEL
- search: supporte Fanfiction.net
- new: proxy support
- fix: support hybrid CBZ (with text)
- fix: fix DEBUG=0
+- fix: fix imported stories that don't immediatly appear on screen
- gui: focus fix
- gui: bg colour fix
- gui: fix keyboard navigation support (up and down)
- gui: configuration is now much easier
+- gui: can now prefetch to cache all the sories of a group at once
- MangaLEL: website has changed
- search: Fanfiction.net support
- search: MangaLEL support
import be.nikiroo.fanfix.bundles.Config;
import be.nikiroo.fanfix.bundles.StringId;
import be.nikiroo.fanfix.data.Chapter;
+import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.data.Story;
import be.nikiroo.fanfix.library.BasicLibrary;
import be.nikiroo.fanfix.library.CacheLibrary;
*/
public static int imprt(String urlString, Progress pg) {
try {
- Story story = Instance.getLibrary().imprt(
+ MetaData meta = Instance.getLibrary().imprt(
BasicReader.getUrl(urlString), pg);
- System.out.println(story.getMeta().getLuid() + ": \""
- + story.getMeta().getTitle() + "\" imported.");
+ System.out.println(meta.getLuid() + ": \"" + meta.getTitle()
+ + "\" imported.");
} catch (IOException e) {
Instance.getTraceHandler().error(e);
return 1;
MENU_FILE_OPEN, //
@Meta(def = "Edit", format = Format.STRING, description = "the edit menu")
MENU_EDIT, //
+ @Meta(def = "Download to cache", format = Format.STRING, description = "the edit/send to cache menu button, to download the story into the cache if not already done")
+ MENU_EDIT_DOWNLOAD_TO_CACHE, //
@Meta(def = "Clear cache", format = Format.STRING, description = "the clear cache menu button, to clear the cache for a single book")
MENU_EDIT_CLEAR_CACHE, //
@Meta(def = "Redownload", format = Format.STRING, description = "the edit/redownload menu button, to download the latest version of the book")
-# United Kingdom (en_GB) resources translation file (UTF-8)
+# United Kingdom (en_GB) resources_core translation file (UTF-8)
#
# Note that any key can be doubled with a _NOUTF suffix
# to use when the NOUTF env variable is set to 1
# help message for the syntax
-# (FORMAT: STRING) %s = supported input, %s = supported output
+# (FORMAT: STRING)
HELP_SYNTAX = Valid options:\n\
\t--import [URL]: import into library\n\
\t--export [id] [output_type] [target]: export story to target\n\
\n\
Supported output types:\n\
%s
-# syntax error message (FORMAT: STRING)
+# syntax error message
+# (FORMAT: STRING)
ERR_SYNTAX = Syntax error (try "--help")
# an input or output support type description
-# (FORMAT: STRING) %s = support name, %s = support desc
+# (FORMAT: STRING)
ERR_SYNTAX_TYPE = > %s: %s
# Error when retrieving data
-# (FORMAT: STRING) %s = input string
+# (FORMAT: STRING)
ERR_LOADING = Error when retrieving data from: %s
# Error when saving to given target
-# (FORMAT: STRING) %s = save target
+# (FORMAT: STRING)
ERR_SAVING = Error when saving to target: %s
# Error when unknown output format
-# (FORMAT: STRING) %s = bad output format
+# (FORMAT: STRING)
ERR_BAD_OUTPUT_TYPE = Unknown output type: %s
# Error when converting input to URL/File
-# (FORMAT: STRING) %s = input string
+# (FORMAT: STRING)
ERR_BAD_URL = Cannot understand file or protocol: %s
# URL/File not supported
-# (FORMAT: STRING) %s = input url
+# (FORMAT: STRING)
ERR_NOT_SUPPORTED = URL not supported: %s
# Failed to download cover : %s
-# (FORMAT: STRING) %s = cover URL
+# (FORMAT: STRING)
ERR_BS_NO_COVER = Failed to download cover: %s
# Canonical OPEN SINGLE QUOTE char (for instance: ‘)
-# (FORMAT: STRING) single char
+# (FORMAT: STRING)
OPEN_SINGLE_QUOTE = ‘
# Canonical CLOSE SINGLE QUOTE char (for instance: ’)
-# (FORMAT: STRING) single char
+# (FORMAT: STRING)
CLOSE_SINGLE_QUOTE = ’
# Canonical OPEN DOUBLE QUOTE char (for instance: “)
-# (FORMAT: STRING) single char
+# (FORMAT: STRING)
OPEN_DOUBLE_QUOTE = “
# Canonical CLOSE DOUBLE QUOTE char (for instance: ”)
-# (FORMAT: STRING) single char
+# (FORMAT: STRING)
CLOSE_DOUBLE_QUOTE = ”
# Name of the description fake chapter
# (FORMAT: STRING)
DESCRIPTION = Description
# Name of a chapter with a name
-# (FORMAT: STRING) %d = number, %s = name
+# (FORMAT: STRING)
CHAPTER_NAMED = Chapter %d: %s
# Name of a chapter without name
-# (FORMAT: STRING) %d = number, %s = name
+# (FORMAT: STRING)
CHAPTER_UNNAMED = Chapter %d
# Default description when the type is not known by i18n
-# (FORMAT: STRING) %s = type
+# (FORMAT: STRING)
INPUT_DESC = Unknown type: %s
# Description of this input type
# (FORMAT: STRING)
# (FORMAT: STRING)
INPUT_DESC_HTML = HTML files coming from this very program
# Default description when the type is not known by i18n
-# (FORMAT: STRING) %s = type
+# (FORMAT: STRING)
OUTPUT_DESC = Unknown type: %s
# Description of this output type
# (FORMAT: STRING)
# (FORMAT: STRING)
OUTPUT_DESC_SYSOUT = A simple DEBUG console output
# Default description when the type is not known by i18n
-#This item is used as a group, its content is not expected to be used.
+# This item is used as a group, its content is not expected to be used.
OUTPUT_DESC_SHORT = %s
# Short description of this output type
# (FORMAT: STRING)
# (FORMAT: STRING)
OUTPUT_DESC_SHORT_HTML = HTML files with resources (directory, .html)
# Error message for unknown 2-letter LaTeX language code
-# (FORMAT: STRING) %s = the unknown 2-code language
+# (FORMAT: STRING)
LATEX_LANG_UNKNOWN = Unknown language: %s
# 'by' prefix before author name used to output the author, make sure it is covered by Config.BYS for input detection
# (FORMAT: STRING)
-# français (fr) resources translation file (UTF-8)
+# français (fr) resources_core translation file (UTF-8)
#
# Note that any key can be doubled with a _NOUTF suffix
# to use when the NOUTF env variable is set to 1
# help message for the syntax
-# (FORMAT: STRING) %s = supported input, %s = supported output
+# (FORMAT: STRING)
HELP_SYNTAX = Options reconnues :\n\
\t--import [URL]: importer une histoire dans la librairie\n\
\t--export [id] [output_type] [target]: exporter l'histoire "id" vers le fichier donné\n\
\n\
Types supportés en sortie :\n\
%s
-# syntax error message (FORMAT: STRING)
+# syntax error message
+# (FORMAT: STRING)
ERR_SYNTAX = Erreur de syntaxe (essayez "--help")
# an input or output support type description
-# (FORMAT: STRING) %s = support name, %s = support desc
+# (FORMAT: STRING)
ERR_SYNTAX_TYPE = > %s : %s
# Error when retrieving data
-# (FORMAT: STRING) %s = input string
+# (FORMAT: STRING)
ERR_LOADING = Erreur de récupération des données depuis : %s
# Error when saving to given target
-# (FORMAT: STRING) %s = save target
+# (FORMAT: STRING)
ERR_SAVING = Erreur lors de la sauvegarde sur : %s
# Error when unknown output format
-# (FORMAT: STRING) %s = bad output format
+# (FORMAT: STRING)
ERR_BAD_OUTPUT_TYPE = Type de sortie inconnu : %s
# Error when converting input to URL/File
-# (FORMAT: STRING) %s = input string
+# (FORMAT: STRING)
ERR_BAD_URL = Protocole ou type de fichier inconnu : %s
# URL/File not supported
-# (FORMAT: STRING) %s = input url
+# (FORMAT: STRING)
ERR_NOT_SUPPORTED = Site web non supporté : %s
# Failed to download cover : %s
-# (FORMAT: STRING) %s = cover URL
+# (FORMAT: STRING)
ERR_BS_NO_COVER = Échec de la récupération de la page de couverture : %s
# Canonical OPEN SINGLE QUOTE char (for instance: ‘)
-# (FORMAT: STRING) single char
+# (FORMAT: STRING)
OPEN_SINGLE_QUOTE = ‘
# Canonical CLOSE SINGLE QUOTE char (for instance: ’)
-# (FORMAT: STRING) single char
+# (FORMAT: STRING)
CLOSE_SINGLE_QUOTE = ’
# Canonical OPEN DOUBLE QUOTE char (for instance: “)
-# (FORMAT: STRING) single char
+# (FORMAT: STRING)
OPEN_DOUBLE_QUOTE = “
# Canonical CLOSE DOUBLE QUOTE char (for instance: ”)
-# (FORMAT: STRING) single char
+# (FORMAT: STRING)
CLOSE_DOUBLE_QUOTE = ”
# Name of the description fake chapter
# (FORMAT: STRING)
DESCRIPTION = Description
# Name of a chapter with a name
-# (FORMAT: STRING) %d = number, %s = name
+# (FORMAT: STRING)
CHAPTER_NAMED = Chapitre %d : %s
# Name of a chapter without name
-# (FORMAT: STRING) %d = number, %s = name
+# (FORMAT: STRING)
CHAPTER_UNNAMED = Chapitre %d
# Default description when the type is not known by i18n
-# (FORMAT: STRING) %s = type
+# (FORMAT: STRING)
INPUT_DESC = Type d'entrée inconnu : %s
# Description of this input type
# (FORMAT: STRING)
# (FORMAT: STRING)
INPUT_DESC_HTML = Les fichiers HTML que vous pouvez ouvrir avec n'importe quel navigateur ; remarquez que Fanfix créera un répertoire pour y mettre les fichiers nécessaires, dont un fichier "index.html" pour afficher le tout -- nous ne supportons en entrée que les fichiers HTML créés par Fanfix
# Default description when the type is not known by i18n
-# (FORMAT: STRING) %s = type
+# (FORMAT: STRING)
OUTPUT_DESC = Type de sortie inconnu : %s
# Description of this output type
# (FORMAT: STRING)
# (FORMAT: STRING)
OUTPUT_DESC_SYSOUT = A simple DEBUG console output
# Default description when the type is not known by i18n
-#This item is used as a group, its content is not expected to be used.
+# This item is used as a group, its content is not expected to be used.
OUTPUT_DESC_SHORT = %s
# Short description of this output type
# (FORMAT: STRING)
# (FORMAT: STRING)
OUTPUT_DESC_SHORT_HTML = HTML files with resources (directory, .html)
# Error message for unknown 2-letter LaTeX language code
-# (FORMAT: STRING) %s = the unknown 2-code language
+# (FORMAT: STRING)
LATEX_LANG_UNKNOWN = Unknown language: %s
# 'by' prefix before author name used to output the author, make sure it is covered by Config.BYS for input detection
# (FORMAT: STRING)
-# United States (en_US) resources_gui translation file (UTF-8)
+# United Kingdom (en_GB) resources_gui translation file (UTF-8)
#
# Note that any key can be doubled with a _NOUTF suffix
# to use when the NOUTF env variable is set to 1
# the title of the main window of Fanfix, the library
-# (FORMAT: STRING) %s = current Fanfix version
+# (FORMAT: STRING)
TITLE_LIBRARY = Fanfix %s
# the title of the main window of Fanfix, the library, when the library has a name (i.e., is not local)
-# (FORMAT: STRING) %s = current Fanfix version, %s = library name
+# (FORMAT: STRING)
TITLE_LIBRARY_WITH_NAME = Fanfix %s
# the title of the configuration window of Fanfix, also the name of the menu button
# (FORMAT: STRING)
# (FORMAT: STRING)
TITLE_DELETE = Delete story
# the subtitle of the 'delete' window of Fanfix
-# (FORMAT: STRING) %s = LUID of the story, %s = title of the story
+# (FORMAT: STRING)
SUBTITLE_DELETE = Delete %s: %s
# the title of the 'library error' dialogue
# (FORMAT: STRING)
# (FORMAT: STRING)
TITLE_ERROR = Error
# the title of a story for the properties dialogue, the viewers...
-# (FORMAT: STRING) %s = LUID of the story, %s = title of the story
+# (FORMAT: STRING)
TITLE_STORY = %s: %s
# HTML text used to notify of a new version
-# (FORMAT: STRING) %s = url link in HTML
+# (FORMAT: STRING)
NEW_VERSION_AVAILABLE = A new version of the program is available at %s
# text used as title for the update dialogue
# (FORMAT: STRING)
NEW_VERSION_TITLE = Updates available
# HTML text used to specify a newer version title and number, used for each version newer than the current one
-# (FORMAT: STRING) %s = the newer version number
+# (FORMAT: STRING)
NEW_VERSION_VERSION = Version %s
# show the number of words of a book
-# (FORMAT: STRING) %s = the number
+# (FORMAT: STRING)
BOOK_COUNT_WORDS = %s words
# show the number of images of a book
-# (FORMAT: STRING) %s = the number
+# (FORMAT: STRING)
BOOK_COUNT_IMAGES = %s images
# show the number of stories of a meta-book (a book representing allthe types/sources or all the authors present)
-# (FORMAT: STRING) %s = the number
+# (FORMAT: STRING)
BOOK_COUNT_STORIES = %s stories
-# the file menu (FORMAT: STRING)
+# the file menu
+# (FORMAT: STRING)
MENU_FILE = File
# the file/exit menu button
# (FORMAT: STRING)
# the file/open menu item, that will open the story or fake-story (an author or a source/type)
# (FORMAT: STRING)
MENU_FILE_OPEN = Open
-# the edit menu (FORMAT: STRING)
+# the edit menu
+# (FORMAT: STRING)
MENU_EDIT = Edit
+# the edit/send to cache menu button, to download the story into the cache if not already done
+# (FORMAT: STRING)
+MENU_EDIT_DOWNLOAD_TO_CACHE = Download to cache
# the clear cache menu button, to clear the cache for a single book
# (FORMAT: STRING)
MENU_EDIT_CLEAR_CACHE = Clear cache
# the search menu to open the earch stories on one of the searchable websites
# (FORMAT: STRING)
MENU_SEARCH = Search
-# the view menu (FORMAT: STRING)
+# the view menu
+# (FORMAT: STRING)
MENU_VIEW = View
# the view/word_count menu button, to show the word/image/story count as secondary info
# (FORMAT: STRING)
# (FORMAT: STRING)
PROGRESS_OUT_OF_UI_RELOAD_BOOKS = Reload books
# progress bar caption for the 'change source' step of the ReDownload operation
-# (FORMAT: STRING) %s = new source name
+# (FORMAT: STRING)
PROGRESS_CHANGE_SOURCE = Change the source of the book to %s
# default description if the error is not known
# (FORMAT: STRING)
# (FORMAT: STRING)
ERROR_CANNOT_OPEN = Cannot open the selected book
# URL is not supported by Fanfix
-# (FORMAT: STRING) %s = URL
+# (FORMAT: STRING)
ERROR_URL_NOT_SUPPORTED = URL not supported: %s
# cannot import the URL
-# (FORMAT: STRING) %s = URL, %s = reasons
+# (FORMAT: STRING)
ERROR_URL_IMPORT_FAILED = Failed to import %s:\n\
%s
# (html) the chapter progression value used on the viewers
-# (FORMAT: STRING) %d = chapter number, %d = total chapters
+# (FORMAT: STRING)
CHAPTER_HTML_UNNAMED = <B>Chapter <SPAN COLOR='#7777DD'>%d</SPAN>/%d</B>
# (html) the chapter progression value used on the viewers
-# (FORMAT: STRING) %d = chapter number, %d = total chapters, %s = chapter name
+# (FORMAT: STRING)
CHAPTER_HTML_NAMED = <B>Chapter <SPAN COLOR='#7777DD'>%d</SPAN>/%d</B>: %s
# (NO html) the chapter progression value used on the viewers
-# (FORMAT: STRING) %d = current image number, %d = total images
+# (FORMAT: STRING)
IMAGE_PROGRESSION = Image %d / %d
# the title of the main window of Fanfix, the library
-# (FORMAT: STRING) %s = current Fanfix version
+# (FORMAT: STRING)
TITLE_LIBRARY = Fanfix %s
# the title of the main window of Fanfix, the library, when the library has a name (i.e., is not local)
-# (FORMAT: STRING) %s = current Fanfix version, %s = library name
+# (FORMAT: STRING)
TITLE_LIBRARY_WITH_NAME = Fanfix %s
# the title of the configuration window of Fanfix, also the name of the menu button
# (FORMAT: STRING)
# (FORMAT: STRING)
TITLE_DELETE = Supprimer le livre
# the subtitle of the 'delete' window of Fanfix
-# (FORMAT: STRING) %s = LUID of the story, %s = title of the story
+# (FORMAT: STRING)
SUBTITLE_DELETE = Supprimer %s : %s
# the title of the 'library error' dialogue
# (FORMAT: STRING)
# (FORMAT: STRING)
TITLE_ERROR = Error
# the title of a story for the properties dialogue, the viewers...
-# (FORMAT: STRING) %s = LUID of the story, %s = title of the story
+# (FORMAT: STRING)
TITLE_STORY = %s: %s
# HTML text used to notify of a new version
-# (FORMAT: STRING) %s = url link in HTML
+# (FORMAT: STRING)
NEW_VERSION_AVAILABLE = Une nouvelle version du programme est disponible sur %s
# text used as title for the update dialogue
# (FORMAT: STRING)
NEW_VERSION_TITLE = Mise-à-jour disponible
# HTML text used to specify a newer version title and number, used for each version newer than the current one
-# (FORMAT: STRING) %s = the newer version number
+# (FORMAT: STRING)
NEW_VERSION_VERSION = Version %s
# show the number of words of a book
-# (FORMAT: STRING) %s = the number
+# (FORMAT: STRING)
BOOK_COUNT_WORDS = %s mots
# show the number of images of a book
-# (FORMAT: STRING) %s = the number
+# (FORMAT: STRING)
BOOK_COUNT_IMAGES = %s images
# show the number of stories of a meta-book (a book representing allthe types/sources or all the authors present)
-# (FORMAT: STRING) %s = the number
+# (FORMAT: STRING)
BOOK_COUNT_STORIES = %s livres
-# the file menu (FORMAT: STRING)
+# the file menu
+# (FORMAT: STRING)
MENU_FILE = Fichier
# the file/exit menu button
# (FORMAT: STRING)
# the file/open menu item, that will open the story or fake-story (an author or a source/type)
# (FORMAT: STRING)
MENU_FILE_OPEN = Ouvrir
-# the edit menu (FORMAT: STRING)
+# the edit menu
+# (FORMAT: STRING)
MENU_EDIT = Edition
+# the edit/send to cache menu button, to download the story into the cache if not already done
+# (FORMAT: STRING)
+MENU_EDIT_DOWNLOAD_TO_CACHE = Charger en cache
# the clear cache menu button, to clear the cache for a single book
# (FORMAT: STRING)
MENU_EDIT_CLEAR_CACHE = Nettoyer le cache
# the search menu to open the earch stories on one of the searchable websites
# (FORMAT: STRING)
MENU_SEARCH = Recherche
-# the view menu (FORMAT: STRING)
+# the view menu
+# (FORMAT: STRING)
MENU_VIEW = Affichage
# the view/word_count menu button, to show the word/image/story count as secondary info
# (FORMAT: STRING)
# (FORMAT: STRING)
PROGRESS_OUT_OF_UI_RELOAD_BOOKS = Recharger les livres
# progress bar caption for the 'change source' step of the ReDownload operation
-# (FORMAT: STRING) %s = new source name
+# (FORMAT: STRING)
PROGRESS_CHANGE_SOURCE = Change la source du livre en %s
# default description if the error is not known
# (FORMAT: STRING)
# (FORMAT: STRING)
ERROR_CANNOT_OPEN = Impossible d'ouvrir le livre sélectionné
# URL is not supported by Fanfix
-# (FORMAT: STRING) %s = URL
+# (FORMAT: STRING)
ERROR_URL_NOT_SUPPORTED = URL non supportée : %s
# cannot import the URL
-# (FORMAT: STRING) %s = URL, %s = reasons
+# (FORMAT: STRING)
ERROR_URL_IMPORT_FAILED = Erreur lors de l'import de %s:\n\
%s
# (html) the chapter progression value used on the viewers
-# (FORMAT: STRING) %d = chapter number, %d = total chapters
+# (FORMAT: STRING)
CHAPTER_HTML_UNNAMED = <B>Chapitre <SPAN COLOR='#444466'>%d</SPAN> / %d</B>
# (html) the chapter progression value used on the viewers
-# (FORMAT: STRING) %d = chapter number, %d = total chapters, %s = chapter name
+# (FORMAT: STRING)
CHAPTER_HTML_NAMED = <B>Chapitre <SPAN COLOR='#444466'>%d</SPAN> / %d</B>: %s
# (NO html) the chapter progression value used on the viewers
-# (FORMAT: STRING) %d = current image number, %d = total images
+# (FORMAT: STRING)
IMAGE_PROGRESSION = Image %d / %d
* @param pg
* the optional progress reporter
*
- * @return the imported {@link Story}
+ * @return the imported Story {@link MetaData}
*
* @throws UnknownHostException
* if the host is not supported
* @throws IOException
* in case of I/O error
*/
- public Story imprt(URL url, Progress pg) throws IOException {
+ public MetaData imprt(URL url, Progress pg) throws IOException {
if (pg == null)
pg = new Progress();
Story story = save(support.process(pgProcess), pgSave);
pg.done();
- return story;
+ return story.getMeta();
}
/**
@Override
protected void updateInfo(MetaData meta) throws IOException {
if (meta != null && metas != null) {
+ boolean changed = false;
for (int i = 0; i < metas.size(); i++) {
if (metas.get(i).getLuid().equals(meta.getLuid())) {
metas.set(i, meta);
+ changed = true;
}
}
+
+ if (!changed) {
+ metas.add(meta);
+ }
}
cacheLib.updateInfo(meta);
}
@Override
- public Story imprt(URL url, Progress pg) throws IOException {
+ public MetaData imprt(URL url, Progress pg) throws IOException {
if (pg == null) {
pg = new Progress();
}
pg.addProgress(pgImprt, 7);
pg.addProgress(pgCache, 3);
- Story story = lib.imprt(url, pgImprt);
- cacheLib.save(story, story.getMeta().getLuid(), pgCache);
-
- updateInfo(story.getMeta());
-
+ MetaData meta = lib.imprt(url, pgImprt);
+ updateInfo(meta);
+
+ clearFromCache(meta.getLuid());
+
pg.done();
- return story;
+ return meta;
}
// All the following methods are only used by Save and Delete in
* <li><b>wl</b>: flag to allow access to all the stories (bypassing the
* whitelist if it exists)</li>
* </ul>
- *
+ * <p>
* Some examples:
* <ul>
* <li><b>my_key</b>: normal connection, will take the default server
@Override
// Could work (more slowly) without it
- public Story imprt(final URL url, Progress pg) throws IOException {
+ public MetaData imprt(final URL url, Progress pg) throws IOException {
// Import the file locally if it is actually a file
+
if (url == null || url.getProtocol().equalsIgnoreCase("file")) {
return super.imprt(url, pg);
}
pg = new Progress();
}
- pg.setMinMax(0, 2);
- Progress pgImprt = new Progress();
- Progress pgGet = new Progress();
- pg.addProgress(pgImprt, 1);
- pg.addProgress(pgGet, 1);
-
- final Progress pgF = pgImprt;
+ final Progress pgF = pg;
final String[] luid = new String[1];
connectRemoteAction(new RemoteAction() {
throw new IOException("Remote failure");
}
- Story story = getStory(luid[0], pgGet);
- pgGet.done();
-
pg.done();
- return story;
+ return getInfo(luid[0]);
}
@Override
}
Progress pg = createPgForwarder(action);
- Story story = Instance.getLibrary().imprt(
+ MetaData meta = Instance.getLibrary().imprt(
new URL((String) args[0]), pg);
forcePgDoneSent(pg);
- return story.getMeta().getLuid();
+ return meta.getLuid();
} else if ("DELETE_STORY".equals(command)) {
if (!rw) {
throw new RemoteLibraryException("Read-Only remote library: "
/**
* "Open" the given {@link Story}. It usually involves starting an external
* program adapted to the given file type.
- * <p>
- * Asynchronous method.
*
* @param luid
* the luid of the {@link Story} to open
}
}
+
+ /**
+ * "Prefetch" the given {@link Story}.
+ * <p>
+ * Synchronous method.
+ *
+ * @param luid
+ * the luid of the {@link Story} to prefetch
+ * @param pg
+ * the optional progress (we may need to prepare the
+ * {@link Story} for reading
+ *
+ * @throws IOException
+ * in case of I/O errors
+ */
+ void prefetch(String luid, Progress pg) throws IOException {
+ cacheLib.getFile(luid, pg);
+ }
/**
* Change the source of the given {@link Story} (the source is the main
* information used to group the stories together).
/**
* A book item presented in a {@link GuiReaderFrame}.
+ * <p>
+ * Can be a story, or a comic or... a group.
*
* @author niki
*/
this.id = id;
this.value = value;
}
+
+ /**
+ * The type of {@link GuiReaderBookInfo}.
+ *
+ * @return the type
+ */
+ public Type getType() {
+ return type;
+ }
/**
* Get the main info to display for this book (a title, an author, a
import be.nikiroo.fanfix.output.BasicOutput.OutputType;
import be.nikiroo.fanfix.reader.BasicReader;
import be.nikiroo.fanfix.reader.ui.GuiReaderMainPanel.FrameHelper;
-import be.nikiroo.fanfix.reader.ui.GuiReaderMainPanel.StoryRunnable;
+import be.nikiroo.fanfix.reader.ui.GuiReaderMainPanel.MetaDataRunnable;
import be.nikiroo.fanfix.searchable.BasicSearchable;
import be.nikiroo.fanfix.supported.SupportType;
import be.nikiroo.utils.Progress;
popup.add(createMenuItemSetCoverForSource());
popup.add(createMenuItemSetCoverForAuthor());
}
+ popup.add(createMenuItemDownloadToCache());
popup.add(createMenuItemClearCache());
if (status.isWritable()) {
popup.add(createMenuItemRedownload());
edit.add(createMenuItemSetCoverForSource());
edit.add(createMenuItemSetCoverForAuthor());
+ edit.add(createMenuItemDownloadToCache());
edit.add(createMenuItemClearCache());
edit.add(createMenuItemRedownload());
edit.addSeparator();
final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
if (selectedBook != null) {
final MetaData meta = selectedBook.getInfo().getMeta();
- mainPanel.imprt(meta.getUrl(), new StoryRunnable() {
+ mainPanel.imprt(meta.getUrl(), new MetaDataRunnable() {
@Override
- public void run(Story story) {
- MetaData newMeta = story.getMeta();
+ public void run(MetaData newMeta) {
if (!newMeta.getSource().equals(meta.getSource())) {
reader.changeSource(newMeta.getLuid(),
meta.getSource());
return refresh;
}
+
+ /**
+ * Create the download to cache menu item.
+ *
+ * @return the item
+ */
+ private JMenuItem createMenuItemDownloadToCache() {
+ JMenuItem refresh = new JMenuItem(
+ GuiReader.trans(StringIdGui.MENU_EDIT_DOWNLOAD_TO_CACHE),
+ KeyEvent.VK_T);
+ refresh.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ final GuiReaderBook selectedBook = mainPanel.getSelectedBook();
+ if (selectedBook != null) {
+ mainPanel.prefetchBook(selectedBook);
+ }
+ }
+ });
+
+ return refresh;
+ }
+
/**
* Create the delete menu item.
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import be.nikiroo.fanfix.library.LocalLibrary;
import be.nikiroo.fanfix.reader.BasicReader;
import be.nikiroo.fanfix.reader.ui.GuiReaderBook.BookActionListener;
+import be.nikiroo.fanfix.reader.ui.GuiReaderBookInfo.Type;
import be.nikiroo.utils.Progress;
import be.nikiroo.utils.ui.ProgressBar;
}
/**
- * A {@link Runnable} with a {@link Story} parameter.
+ * A {@link Runnable} with a {@link MetaData} parameter.
*
* @author niki
*/
- public interface StoryRunnable {
+ public interface MetaDataRunnable {
/**
* Run the action.
*
- * @param story
- * the story
+ * @param meta
+ * the meta of the story
*/
- public void run(Story story);
+ public void run(MetaData meta);
}
/**
}
});
}
+
+ /**
+ * Prefetch a {@link GuiReaderBook} item (which can be a group, in which
+ * case we prefetch all its members).
+ *
+ * @param book
+ * the {@link GuiReaderBook} to open
+ */
+ public void prefetchBook(final GuiReaderBook book) {
+ final List<String> luids = new LinkedList<String>();
+ try {
+ switch (book.getInfo().getType()) {
+ case STORY:
+ luids.add(book.getInfo().getMeta().getLuid());
+ break;
+ case SOURCE:
+ for (MetaData meta : helper.getReader().getLibrary()
+ .getListBySource(book.getInfo().getMainInfo())) {
+ luids.add(meta.getLuid());
+ }
+ break;
+ case AUTHOR:
+ for (MetaData meta : helper.getReader().getLibrary()
+ .getListByAuthor(book.getInfo().getMainInfo())) {
+ luids.add(meta.getLuid());
+ }
+ break;
+ }
+ } catch (IOException e) {
+ Instance.getTraceHandler().error(e);
+ }
+
+ final Progress pg = new Progress();
+ pg.setMax(luids.size());
+
+ outOfUi(pg, false, new Runnable() {
+ @Override
+ public void run() {
+ try {
+ for (String luid : luids) {
+ Progress pgStep = new Progress();
+ pg.addProgress(pgStep, 1);
+
+ helper.getReader().prefetch(luid, pgStep);
+ }
+
+ // TODO: also set the green button on sources/authors?
+ // requires to do the same when all stories inside are green
+ if (book.getInfo().getType() == Type.STORY) {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ book.setCached(true);
+ }
+ });
+ }
+ } catch (IOException e) {
+ Instance.getTraceHandler().error(e);
+ error(GuiReader.trans(StringIdGui.ERROR_CANNOT_OPEN),
+ GuiReader.trans(StringIdGui.TITLE_ERROR), e);
+ }
+ }
+ });
+ }
/**
* Process the given action out of the Swing UI thread and link the given
// No data will be handled
}
- if (clipboard == null || !clipboard.startsWith("http")) {
+ if (clipboard == null || !(clipboard.startsWith("http://") || //
+ clipboard.startsWith("https://"))) {
clipboard = "";
}
* @param onSuccessPgName
* the name to use for the onSuccess progress bar
*/
- public void imprt(final String url, final StoryRunnable onSuccess,
+ public void imprt(final String url, final MetaDataRunnable onSuccess,
String onSuccessPgName) {
final Progress pg = new Progress();
final Progress pgImprt = new Progress();
@Override
public void run() {
Exception ex = null;
- Story story = null;
+ MetaData meta = null;
try {
- story = helper.getReader().getLibrary()
+ meta = helper.getReader().getLibrary()
.imprt(BasicReader.getUrl(url), pgImprt);
} catch (IOException e) {
ex = e;
}
} else {
if (onSuccess != null) {
- onSuccess.run(story);
+ onSuccess.run(meta);
}
}
pgOnSuccess.done();
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
-import javax.swing.plaf.basic.BasicArrowButton;
import be.nikiroo.fanfix.Instance;
import be.nikiroo.fanfix.bundles.StringIdGui;
*/
public class Test extends TestLauncher {
//
- // 3 files can control the test:
+ // 4 files can control the test:
// - test/VERBOSE: enable verbose mode
// - test/OFFLINE: to forbid any downloading
+ // - test/URLS: to allow testing URLs
// - test/FORCE_REFRESH: to force a clear of the cache
//
+ // Note that test/CACHE can be kept, as it will contain all internet related
+ // files you need (if you allow URLs, run the test once which will populate
+ // the CACHE then go OFFLINE, it will still work).
+ //
// The test files will be:
// - test/*.url: URL to download in text format, content = URL
// - test/*.story: text mode story, content = story
* @param args
* the arguments to configure the number of columns and the ok/ko
* {@link String}s
+ * @param urlsAllowed
+ * allow testing URLs (<tt>.url</tt> files)
*
* @throws IOException
*/
- public Test(String[] args) throws IOException {
+ public Test(String[] args, boolean urlsAllowed) throws IOException {
super("Fanfix", args);
Instance.setTraceHandler(null);
addSeries(new BasicSupportUtilitiesTest(args));
addSeries(new BasicSupportDeprecatedTest(args));
addSeries(new LibraryTest(args));
-
+
File sources = new File("test/");
if (sources.isDirectory()) {
for (File file : sources.listFiles()) {
+ file.getName()).getAbsolutePath();
String uri;
- if (file.getName().endsWith(".url")) {
+ if (urlsAllowed && file.getName().endsWith(".url")) {
uri = IOUtils.readSmallFile(file).trim();
} else if (file.getName().endsWith(".story")) {
uri = file.getAbsolutePath();
// Can force refresh
boolean forceRefresh = new File("test/FORCE_REFRESH").exists();
+ // Allow URLs:
+ boolean urlsAllowed = new File("test/URLS").exists();
+
+
// Only download files if allowed:
boolean offline = new File("test/OFFLINE").exists();
Instance.getCache().setOffline(offline);
+
+
int result = 0;
tempFiles = new TempFiles("fanfix-test");
try {
File tmpConfig = tempFiles.createTempDir("fanfix-config");
File localCache = new File("test/CACHE");
- if (forceRefresh) {
- IOUtils.deltree(localCache);
- }
- localCache.mkdirs();
+ prepareCache(localCache, forceRefresh);
ConfigBundle config = new ConfigBundle();
Bundles.setDirectory(tmpConfig.getAbsolutePath());
Instance.init(true);
Instance.getCache().setOffline(offline);
- TestLauncher tests = new Test(args);
+ TestLauncher tests = new Test(args, urlsAllowed);
tests.setDetails(verbose);
result = tests.launch();
IOUtils.deltree(tmpConfig);
+ prepareCache(localCache, forceRefresh);
} finally {
// Test temp files
tempFiles.close();
System.exit(result);
}
+
+ /**
+ * Prepare the cache (or clean it up).
+ * <p>
+ * The cache directory will always exist if this method succeed
+ *
+ * @param localCache
+ * the cache directory
+ * @param forceRefresh
+ * TRUE to force acache refresh (delete all files)
+ *
+ * @throw IOException if the cache cannot be created
+ */
+ private static void prepareCache(File localCache, boolean forceRefresh)
+ throws IOException {
+ // if needed
+ localCache.mkdirs();
+
+ if (!localCache.isDirectory()) {
+ throw new IOException("Cannot get a cache");
+ }
+
+ // delete local cached files (_*) or all files if forceRefresh
+ for (File f : localCache.listFiles()) {
+ if (forceRefresh || f.getName().startsWith("_")) {
+ IOUtils.deltree(f);
+ }
+ }
+ }
}