1 package be
.nikiroo
.fanfix
;
4 import java
.io
.IOException
;
7 import be
.nikiroo
.fanfix
.bundles
.Config
;
8 import be
.nikiroo
.fanfix
.bundles
.ConfigBundle
;
9 import be
.nikiroo
.fanfix
.bundles
.StringId
;
10 import be
.nikiroo
.fanfix
.bundles
.StringIdBundle
;
11 import be
.nikiroo
.fanfix
.bundles
.UiConfig
;
12 import be
.nikiroo
.fanfix
.bundles
.UiConfigBundle
;
13 import be
.nikiroo
.fanfix
.library
.BasicLibrary
;
14 import be
.nikiroo
.fanfix
.library
.CacheLibrary
;
15 import be
.nikiroo
.fanfix
.library
.LocalLibrary
;
16 import be
.nikiroo
.fanfix
.library
.RemoteLibrary
;
17 import be
.nikiroo
.utils
.Cache
;
18 import be
.nikiroo
.utils
.IOUtils
;
19 import be
.nikiroo
.utils
.TraceHandler
;
20 import be
.nikiroo
.utils
.resources
.Bundles
;
23 * Global state for the program (services and singletons).
27 public class Instance
{
28 private static ConfigBundle config
;
29 private static UiConfigBundle uiconfig
;
30 private static StringIdBundle trans
;
31 private static DataLoader cache
;
32 private static BasicLibrary lib
;
33 private static File coverDir
;
34 private static File readerTmp
;
35 private static File remoteDir
;
36 private static String configDir
;
37 private static TraceHandler tracer
;
40 // Before we can configure it:
41 tracer
= new TraceHandler(true, checkEnv("DEBUG"), checkEnv("DEBUG"));
44 configDir
= getConfigDir();
45 if (!new File(configDir
).exists()) {
46 new File(configDir
).mkdirs();
49 // Most of the rest is dependent upon this:
50 createConfigs(configDir
, false);
53 boolean debug
= Instance
.getConfig()
54 .getBoolean(Config
.DEBUG_ERR
, false);
55 boolean trace
= Instance
.getConfig().getBoolean(Config
.DEBUG_TRACE
,
58 if (checkEnv("DEBUG")) {
63 tracer
= new TraceHandler(true, debug
, trace
);
66 remoteDir
= new File(configDir
, "remote");
67 lib
= createDefaultLibrary(remoteDir
);
70 File tmp
= getFile(Config
.CACHE_DIR
);
72 // Could have used: System.getProperty("java.io.tmpdir")
73 tmp
= new File(configDir
, "tmp");
75 String ua
= config
.getString(Config
.USER_AGENT
);
77 int hours
= config
.getInteger(Config
.CACHE_MAX_TIME_CHANGING
, -1);
78 int hoursLarge
= config
79 .getInteger(Config
.CACHE_MAX_TIME_STABLE
, -1);
80 cache
= new DataLoader(tmp
, ua
, hours
, hoursLarge
);
81 } catch (IOException e
) {
82 tracer
.error(new IOException(
83 "Cannot create cache (will continue without cache)", e
));
84 cache
= new DataLoader(ua
);
87 cache
.setTraceHandler(tracer
);
89 // readerTmp / coverDir
90 readerTmp
= getFile(UiConfig
.CACHE_DIR_LOCAL_READER
);
91 if (readerTmp
== null) {
92 readerTmp
= new File(configDir
, "tmp-reader");
95 coverDir
= getFile(Config
.DEFAULT_COVERS_DIR
);
96 if (coverDir
!= null && !coverDir
.exists()) {
97 tracer
.error(new IOException(
98 "The 'default covers' directory does not exists: "
105 * The traces handler for this {@link Cache}.
109 * @return the traces handler (never NULL)
111 public static TraceHandler
getTraceHandler() {
116 * The traces handler for this {@link Cache}.
119 * the new traces handler or NULL
121 public static void setTraceHandler(TraceHandler tracer
) {
122 if (tracer
== null) {
123 tracer
= new TraceHandler(false, false, false);
126 Instance
.tracer
= tracer
;
127 cache
.setTraceHandler(tracer
);
131 * Get the (unique) configuration service for the program.
133 * @return the configuration service
135 public static ConfigBundle
getConfig() {
140 * Get the (unique) UI configuration service for the program.
142 * @return the configuration service
144 public static UiConfigBundle
getUiConfig() {
149 * Reset the configuration.
152 * also reset the translation files
154 public static void resetConfig(boolean resetTrans
) {
155 String dir
= Bundles
.getDirectory();
156 Bundles
.setDirectory(null);
159 ConfigBundle config
= new ConfigBundle();
160 config
.updateFile(configDir
);
161 } catch (IOException e
) {
165 UiConfigBundle uiconfig
= new UiConfigBundle();
166 uiconfig
.updateFile(configDir
);
167 } catch (IOException e
) {
173 StringIdBundle trans
= new StringIdBundle(null);
174 trans
.updateFile(configDir
);
175 } catch (IOException e
) {
180 Bundles
.setDirectory(dir
);
185 * Get the (unique) {@link DataLoader} for the program.
187 * @return the {@link DataLoader}
189 public static DataLoader
getCache() {
194 * Get the (unique) {link StringIdBundle} for the program.
196 * @return the {link StringIdBundle}
198 public static StringIdBundle
getTrans() {
203 * Get the (unique) {@link LocalLibrary} for the program.
205 * @return the {@link LocalLibrary}
207 public static BasicLibrary
getLibrary() {
209 throw new NullPointerException("We don't have a library to return");
216 * Return the directory where to look for default cover pages.
218 * @return the default covers directory
220 public static File
getCoverDir() {
225 * Return the directory where to store temporary files for the local reader.
227 * @return the directory
229 public static File
getReaderDir() {
234 * Return the directory where to store temporary files for the remote
235 * {@link LocalLibrary}.
238 * the remote for this host
240 * @return the directory
242 public static File
getRemoteDir(String host
) {
243 return getRemoteDir(remoteDir
, host
);
247 * Return the directory where to store temporary files for the remote
248 * {@link LocalLibrary}.
251 * the base remote directory
253 * the remote for this host
255 * @return the directory
257 private static File
getRemoteDir(File remoteDir
, String host
) {
261 return new File(remoteDir
, host
);
268 * Check if we need to check that a new version of Fanfix is available.
270 * @return TRUE if we need to
272 public static boolean isVersionCheckNeeded() {
274 long wait
= config
.getInteger(Config
.UPDATE_INTERVAL
, 1) * 24 * 60
277 String lastUpString
= IOUtils
.readSmallFile(new File(configDir
,
279 long delay
= new Date().getTime()
280 - Long
.parseLong(lastUpString
);
287 } catch (Exception e
) {
288 // No file or bad file:
296 * Notify that we checked for a new version of Fanfix.
298 public static void setVersionChecked() {
300 IOUtils
.writeSmallFile(new File(configDir
), "LAST_UPDATE",
301 Long
.toString(new Date().getTime()));
302 } catch (IOException e
) {
308 * The configuration directory (will check, in order of preference,
309 * {@link Bundles#getDirectory()}, the system properties, the environment
310 * and then defaults to $HOME/.fanfix).
312 * @return the config directory
314 private static String
getConfigDir() {
315 String configDir
= Bundles
.getDirectory();
317 if (configDir
== null) {
318 configDir
= System
.getProperty("CONFIG_DIR");
321 if (configDir
== null) {
322 configDir
= System
.getenv("CONFIG_DIR");
325 if (configDir
== null) {
326 configDir
= new File(getHome(), ".fanfix").getPath();
333 * Create the config variables ({@link Instance#config},
334 * {@link Instance#uiconfig} and {@link Instance#trans}).
337 * the directory where to find the configuration files
339 * TRUE to reset the configuration files from the default
342 private static void createConfigs(String configDir
, boolean refresh
) {
344 Bundles
.setDirectory(configDir
);
348 config
= new ConfigBundle();
349 config
.updateFile(configDir
);
350 } catch (IOException e
) {
355 uiconfig
= new UiConfigBundle();
356 uiconfig
.updateFile(configDir
);
357 } catch (IOException e
) {
361 // No updateFile for this one! (we do not want the user to have custom
362 // translations that won't accept updates from newer versions)
363 trans
= new StringIdBundle(getLang());
365 // Fix an old bug (we used to store custom translation files by
367 if (trans
.getString(StringId
.INPUT_DESC_CBZ
) == null) {
368 trans
.deleteFile(configDir
);
371 if (checkEnv("NOUTF")) {
372 trans
.setUnicode(false);
375 Bundles
.setDirectory(configDir
);
379 * Create the default library as specified by the config.
382 * the base remote directory if needed
384 * @return the default {@link BasicLibrary}
386 private static BasicLibrary
createDefaultLibrary(File remoteDir
) {
387 BasicLibrary lib
= null;
389 String remoteLib
= config
.getString(Config
.DEFAULT_LIBRARY
);
390 if (remoteLib
== null || remoteLib
.trim().isEmpty()) {
391 String libDir
= System
.getProperty("fanfix.libdir");
392 if (libDir
== null || libDir
.isEmpty()) {
393 libDir
= config
.getString(Config
.LIBRARY_DIR
);
396 lib
= new LocalLibrary(getFile(libDir
));
397 } catch (Exception e
) {
398 tracer
.error(new IOException(
399 "Cannot create library for directory: "
400 + getFile(libDir
), e
));
403 int pos
= remoteLib
.lastIndexOf(":");
405 String port
= remoteLib
.substring(pos
+ 1).trim();
406 remoteLib
= remoteLib
.substring(0, pos
);
407 pos
= remoteLib
.lastIndexOf(":");
409 String host
= remoteLib
.substring(pos
+ 1).trim();
410 String key
= remoteLib
.substring(0, pos
).trim();
413 tracer
.trace("Selecting remote library " + host
+ ":"
415 lib
= new RemoteLibrary(key
, host
,
416 Integer
.parseInt(port
));
417 lib
= new CacheLibrary(getRemoteDir(remoteDir
, host
),
420 } catch (Exception e
) {
426 tracer
.error(new IOException(
427 "Cannot create remote library for: " + remoteLib
));
435 * Return a path, but support the special $HOME variable.
439 private static File
getFile(Config id
) {
440 return getFile(config
.getString(id
));
444 * Return a path, but support the special $HOME variable.
448 private static File
getFile(UiConfig id
) {
449 return getFile(uiconfig
.getString(id
));
453 * Return a path, but support the special $HOME variable.
457 private static File
getFile(String path
) {
459 if (path
!= null && !path
.isEmpty()) {
460 path
= path
.replace('/', File
.separatorChar
);
461 if (path
.contains("$HOME")) {
462 path
= path
.replace("$HOME", getHome());
465 file
= new File(path
);
472 * Return the home directory from the system properties.
476 private static String
getHome() {
477 String home
= System
.getProperty("fanfix.home");
478 if (home
!= null && new File(home
).isFile()) {
482 if (home
== null || home
.trim().isEmpty()) {
483 home
= System
.getProperty("user.home");
484 if (!new File(home
).isDirectory()) {
489 if (home
== null || home
.trim().isEmpty()) {
490 home
= System
.getProperty("java.io.tmpdir");
491 if (!new File(home
).isDirectory()) {
504 * The language to use for the application (NULL = default system language).
506 * @return the language
508 private static String
getLang() {
509 String lang
= config
.getString(Config
.LANG
);
511 if (System
.getenv("LANG") != null && !System
.getenv("LANG").isEmpty()) {
512 lang
= System
.getenv("LANG");
515 if (lang
!= null && lang
.isEmpty()) {
523 * Check that the given environment variable is "enabled".
526 * the variable to check
528 * @return TRUE if it is
530 private static boolean checkEnv(String key
) {
531 String value
= System
.getenv(key
);
533 value
= value
.trim().toLowerCase();
534 if ("yes".equals(value
) || "true".equals(value
)
535 || "on".equals(value
) || "1".equals(value
)
536 || "y".equals(value
)) {