List of usage examples for java.lang ThreadLocal get
public T get()
From source file:ch.cyberduck.core.sftp.SFTPQuotaFeature.java
@Override public Space get() throws BackgroundException { final ThreadLocal<Space> quota = new ThreadLocal<Space>() { @Override/* www . ja v a 2 s. c o m*/ protected Space initialValue() { return new Space(0L, Long.MAX_VALUE); } }; final Path home = new SFTPHomeDirectoryService(session).find(); new SFTPCommandFeature(session).send(String.format("df -Pk %s | awk '{print $3, $4}'", home.getAbsolute()), new DisabledProgressListener(), new TranscriptListener() { @Override public void log(final Type request, final String output) { switch (request) { case response: final String[] numbers = StringUtils.split(output, ' '); if (numbers.length == 2) { try { quota.set(new Space(Long.valueOf(numbers[0]) * 1000L, Long.valueOf(numbers[1]) * 1000L)); } catch (NumberFormatException e) { log.warn(String.format("Ignore line %s", output)); } } else { log.warn(String.format("Ignore line %s", output)); } } } }); return quota.get(); }
From source file:com.qrmedia.commons.persistence.hibernate.clone.HibernateEntityGraphClonerTest.java
@SuppressWarnings("unchecked") @Test/*from ww w .j a v a 2s. co m*/ public void clone_entities() throws IllegalAccessException { final StubHibernateEntity entity1 = new StubHibernateEntity(); String property = "007"; final StubHibernateEntity relatedEntity = new SimplePropertyEqualStubHibernateEntity(property); entity1.setNonSimpleBeanProperty(relatedEntity); Set<StubHibernateEntity> nonSimpleCollectionBeanProperty = new HashSet<StubHibernateEntity>(); // reuse relatedEntity to check if its clone is used in both places nonSimpleCollectionBeanProperty.add(relatedEntity); entity1.setNonSimpleCollectionBeanProperty(nonSimpleCollectionBeanProperty); // the first call to the bean cloner creates a clone, adds a new entity and some commands final GraphWiringCommand graphWiringCommand1 = createMock(GraphWiringCommand.class); final GraphPostProcessingCommand graphPostProcessingCommand = createMock(GraphPostProcessingCommand.class); final StubHibernateEntity clone1 = new StubHibernateEntity(); entityBeanCloner.visitNode(eq(new EntityPreserveIdFlagPair(entity1, false)), same(entityGraphCloner), (IdentityHashMap<Object, Object>) anyObject()); expectLastCall() .andAnswer(new HibernateEntityBeanClonerActions(entity1, clone1, Arrays.asList(relatedEntity), Arrays.asList(graphWiringCommand1), Arrays.asList(graphPostProcessingCommand))); // note that entity2 is equal to (but not identical to) relatedEntity! final GraphWiringCommand graphWiringCommand2 = createMock(GraphWiringCommand.class); final StubHibernateEntity entity2 = new SimplePropertyEqualStubHibernateEntity(property); entity2.setNonSimpleBeanProperty(entity1); final StubHibernateEntity clone2 = new SimplePropertyEqualStubHibernateEntity(property); entityBeanCloner.visitNode(eq(new EntityPreserveIdFlagPair(entity2, false)), same(entityGraphCloner), (IdentityHashMap<Object, Object>) anyObject()); expectLastCall().andAnswer(new HibernateEntityBeanClonerActions(entity2, clone2, null, Arrays.asList(graphWiringCommand2), null)); final StubHibernateEntity relatedEntityClone = new SimplePropertyEqualStubHibernateEntity(property); entityBeanCloner.visitNode(eq(new EntityPreserveIdFlagPair(relatedEntity, false)), same(entityGraphCloner), (IdentityHashMap<Object, Object>) anyObject()); expectLastCall().andAnswer(new HibernateEntityBeanClonerActions(relatedEntity, relatedEntityClone)); // use flags mutable for the mocks to track the order of calls final ThreadLocal<Integer> numGraphWiringCommandExecuted = new ThreadLocal<Integer>(); numGraphWiringCommandExecuted.set(0); // the entity graph cloner should call the commands in the order they were added graphWiringCommand1.forEntities(); expectLastCall().andReturn(Arrays.asList(entity1)); graphWiringCommand1.execute(MapUtils.toMap(new IdentityHashMap<Object, Object>(), entity1, clone1)); expectLastCall().andAnswer(new NumGraphWiringCommandsExecutedVerifier(numGraphWiringCommandExecuted, 0)); graphWiringCommand2.forEntities(); expectLastCall().andReturn(Arrays.asList(relatedEntity)); graphWiringCommand2 .execute(MapUtils.toMap(new IdentityHashMap<Object, Object>(), relatedEntity, relatedEntityClone)); expectLastCall().andAnswer(new NumGraphWiringCommandsExecutedVerifier(numGraphWiringCommandExecuted, 1)); // this *must* be called after all the wiring commands have been completed graphPostProcessingCommand.execute(); expectLastCall().andAnswer(new IAnswer<Object>() { public Object answer() throws Throwable { if (!(numGraphWiringCommandExecuted.get() == 2)) { fail("Graph post-processing command executed before wiring was complete."); } return null; } }); replay(entityBeanCloner, graphWiringCommand1, graphWiringCommand2, graphPostProcessingCommand); Map<StubHibernateEntity, StubHibernateEntity> clones = entityGraphCloner .clone(Arrays.asList(entity1, entity2)); assertEquals(MapUtils.<StubHibernateEntity, StubHibernateEntity>toMap(entity1, clone1, entity2, clone2), clones); verify(entityBeanCloner, graphWiringCommand1, graphWiringCommand2, graphPostProcessingCommand); // check that any internal state maintained during the cloning has been cleaned up assertTrue(ReflectionUtils.<List<?>>getValue(entityGraphCloner, "graphWiringCommands").isEmpty()); assertTrue(ReflectionUtils.<List<?>>getValue(entityGraphCloner, "graphPostProcessingCommands").isEmpty()); /* * The actual wiring of the objects is *not* checked because that is the function * of the command objects, *not* the entity graph cloner. * As such, this is not within the scope of a unit test. */ }
From source file:com.blackducksoftware.integration.hub.jenkins.gradle.GradleBuildWrapper.java
@Override public Environment setUp(final AbstractBuild build, final Launcher launcher, final BuildListener listener) throws IOException, InterruptedException { // no failure to report yet final HubJenkinsLogger buildLogger = new HubJenkinsLogger(listener); buildLogger.setLogLevel(LogLevel.TRACE); Gradle gradleBuilder = null;/*from w ww .j a va 2 s . c o m*/ if (build.getProject() instanceof FreeStyleProject) { // Project should always be a FreeStyleProject, thats why we have the isApplicable() method final List<Builder> builders = ((FreeStyleProject) build.getProject()).getBuilders(); if (builders == null || builders.isEmpty()) { // User didn't configure the job with a Builder buildLogger.error("No Builder found for this job."); buildLogger.error("Will not run the Hub Gradle Build wrapper."); build.setResult(Result.UNSTABLE); return new Environment() { }; // Continue with the rest of the Build } for (final Builder builder : builders) { if (builder instanceof Gradle) { gradleBuilder = (Gradle) builder; } } if (gradleBuilder == null) { // User didn't configure the job with a Gradle Builder buildLogger.error("This Wrapper should be run with a Gradle Builder"); buildLogger.error("Will not run the Hub Gradle Build wrapper."); build.setResult(Result.UNSTABLE); return new Environment() { }; // Continue with the rest of the Build } } else { buildLogger.error("Cannot run the Hub Gradle Build Wrapper for this type of Project."); build.setResult(Result.UNSTABLE); return new Environment() { }; // Continue with the rest of the Build } if (validateConfiguration(buildLogger)) { buildLogger.info("Build Recorder enabled"); buildLogger.info("Hub Jenkins Plugin version : " + getDescriptor().getPluginVersion()); } else { build.setResult(Result.UNSTABLE); return new Environment() { }; // Continue with the rest of the Build } final ThreadLocal<String> originalSwitches = new ThreadLocal<String>(); final ThreadLocal<String> originalTasks = new ThreadLocal<String>(); if (gradleBuilder != null) { originalSwitches.set(gradleBuilder.getSwitches() + ""); originalTasks.set(gradleBuilder.getTasks() + ""); final BDGradleInitScriptWriter writer = new BDGradleInitScriptWriter(build, buildLogger); final FilePath workspace = build.getWorkspace(); FilePath initScript; String initScriptPath; try { if (workspace == null) { buildLogger.error("Workspace: null"); } else { initScript = workspace.createTextTempFile("init-blackduck", "gradle", writer.generateInitScript(), false); if (initScript != null) { initScriptPath = initScript.getRemote(); initScriptPath = initScriptPath.replace('\\', '/'); String newSwitches = originalSwitches.get(); String newTasks = originalTasks.get(); if (!originalSwitches.get().contains("--init-script ") && !originalSwitches.get().contains("init-blackduck")) { newSwitches = newSwitches + " --init-script " + initScriptPath; } if (!originalSwitches.get().contains(" -D" + BDGradleUtil.BUILD_ID_PROPERTY)) { newSwitches = newSwitches + " -D" + BDGradleUtil.BUILD_ID_PROPERTY + "=" + build.getId(); } if (!originalSwitches.get() .contains(" -D" + BDGradleUtil.INCLUDED_CONFIGURATIONS_PROPERTY)) { String configurations = getUserScopesToInclude(); configurations = configurations.replaceAll(" ", ""); newSwitches = newSwitches + " -D" + BDGradleUtil.INCLUDED_CONFIGURATIONS_PROPERTY + "=" + configurations; } // // Following used to generate the dependency tree // // written to a file // if (!originalSwitches.get().contains(" -D" + // BDGradleUtil.DEPENDENCY_REPORT_OUTPUT)) { // FilePath dependencyTreeFile = new FilePath(workspace, "dependencyTree.txt"); // newSwitches = newSwitches + " -D" + // BDGradleUtil.DEPENDENCY_REPORT_OUTPUT + "='" + // dependencyTreeFile.getRemote() + "'"; // } if (!originalTasks.get().contains("bdCustomTask")) { newTasks = newTasks + " bdCustomTask"; } if (!originalTasks.get().contains("bdDependencyTree")) { newTasks = newTasks + " bdDependencyTree"; } setField(gradleBuilder, "switches", newSwitches); setField(gradleBuilder, "tasks", newTasks); } } } catch (final Exception e) { listener.getLogger().println("Error occurred while writing Gradle Init Script: " + e.getMessage()); build.setResult(Result.FAILURE); } } final ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); boolean changed = false; try { if (GradleBuildWrapper.class.getClassLoader() != originalClassLoader) { changed = true; Thread.currentThread().setContextClassLoader(GradleBuildWrapper.class.getClassLoader()); } return new Environment() { @Override public boolean tearDown(final AbstractBuild build, final BuildListener listener) throws IOException, InterruptedException { final HubJenkinsLogger buildLogger = new HubJenkinsLogger(listener); Gradle gradleBuilder = null; try { if (build.getProject() instanceof FreeStyleProject) { // Project should always be a FreeStyleProject, thats why we have the isApplicable() method final List<Builder> builders = ((FreeStyleProject) build.getProject()).getBuilders(); for (final Builder builder : builders) { if (builder instanceof Gradle) { gradleBuilder = (Gradle) builder; } } } if (gradleBuilder != null) { String rootBuildScriptDir = gradleBuilder.getRootBuildScriptDir(); if (StringUtils.startsWithIgnoreCase(rootBuildScriptDir, "${WORKSPACE}") || StringUtils.startsWithIgnoreCase(rootBuildScriptDir, "$WORKSPACE")) { final EnvVars variables = build.getEnvironment(listener); rootBuildScriptDir = BuildHelper.handleVariableReplacement(variables, rootBuildScriptDir); } String fileSeparator = null; try { final VirtualChannel channel = build.getBuiltOn().getChannel(); if (channel == null) { buildLogger.error("Channel build on: null"); } else { fileSeparator = channel.call(new GetSeparator()); } } catch (final IOException e) { buildLogger.error(e.toString(), e); } catch (final InterruptedException e) { buildLogger.error(e.toString(), e); } if (StringUtils.isEmpty(fileSeparator)) { fileSeparator = File.separator; } File workspaceFile = null; if (build.getWorkspace() == null) { // might be using custom workspace workspaceFile = new File(build.getProject().getCustomWorkspace()); } else { workspaceFile = new File(build.getWorkspace().getRemote()); } String workingDirectory = ""; try { workingDirectory = build.getBuiltOn().getChannel() .call(new GetCanonicalPath(workspaceFile)); } catch (final IOException e) { buildLogger.error("Problem getting the working directory on this node. Error : " + e.getMessage(), e); } if (!StringUtils.startsWithIgnoreCase(rootBuildScriptDir, workingDirectory)) { if (workingDirectory.endsWith(fileSeparator)) { rootBuildScriptDir = workingDirectory + rootBuildScriptDir; } else { rootBuildScriptDir = workingDirectory + fileSeparator + rootBuildScriptDir; } } FilePath buildInfo = null; final Node buildOn = build.getBuiltOn(); if (buildOn == null) { buildLogger.error("Node build on: null"); } else { final VirtualChannel channel = buildOn.getChannel(); if (channel == null) { buildLogger.error("Channel build on: null"); } else { // buildInfoFile = new FilePath(channel, workspacePath); buildInfo = new FilePath(channel, rootBuildScriptDir); buildInfo = new FilePath(buildInfo, "build"); buildInfo = new FilePath(buildInfo, "BlackDuck"); buildInfo = new FilePath(buildInfo, BuildInfo.OUTPUT_FILE_NAME); } } if (buildInfo != null) { if (buildInfo.exists()) { return universalTearDown(build, buildLogger, buildInfo, getDescriptor(), BuilderType.GRADLE); } else { buildLogger.error( "The " + BuildInfo.OUTPUT_FILE_NAME + " file does not exist at : " + buildInfo.getRemote() + ", on machine : " + (buildOn == null ? "null" : buildOn.getDisplayName())); build.setResult(Result.UNSTABLE); return true; } } // } } else { buildLogger.error("[WARNING] no gradle build step found"); build.setResult(Result.UNSTABLE); return true; } } catch (final BDJenkinsHubPluginException e) { buildLogger.error(e.getMessage(), e); build.setResult(Result.UNSTABLE); return true; } catch (final Exception e) { buildLogger.error(e.getMessage(), e); build.setResult(Result.UNSTABLE); return true; } finally { if (gradleBuilder != null) { synchronized (this) { try { // restore the original configuration setField(gradleBuilder, "switches", originalSwitches.get()); setField(gradleBuilder, "tasks", originalTasks.get()); } catch (final Exception e) { buildLogger.error(e.getMessage(), e); build.setResult(Result.UNSTABLE); return true; } } } } return true; } }; } finally { if (changed) { Thread.currentThread().setContextClassLoader(originalClassLoader); } } }
From source file:org.jsweet.transpiler.JSweetTranspiler.java
private Map<String, Object> getExportedVarMap() throws Exception { Field f = Thread.currentThread().getContextClassLoader().loadClass("jsweet.util.Globals") .getDeclaredField("EXPORTED_VARS"); f.setAccessible(true);/*from ww w. j a v a 2 s. c om*/ @SuppressWarnings("unchecked") ThreadLocal<Map<String, Object>> exportedVars = (ThreadLocal<Map<String, Object>>) f.get(null); return new HashMap<>(exportedVars.get()); }
From source file:org.exoplatform.social.core.storage.impl.ActivityStreamStorageImpl.java
@Override public void update(ProcessContext ctx) { final ReentrantLock lock = new ReentrantLock(); ThreadLocal<Set<String>> idLocal = new ThreadLocal<Set<String>>(); try {/*from w ww. j a v a 2s . c om*/ StreamProcessContext streamCtx = ObjectHelper.cast(StreamProcessContext.class, ctx); ExoSocialActivity activity = streamCtx.getActivity(); ActivityEntity activityEntity = _findById(ActivityEntity.class, activity.getId()); lock.lock(); // block until condition holds Collection<ActivityRef> references = activityEntity.getActivityRefs(); Set<String> ids = new ConcurrentSkipListSet<String>(); for (ActivityRef ref : references) { ids.add(ref.getId()); } idLocal.set(ids); Set<String> idList = idLocal.get(); if (idList.size() > 0) { for (String id : idList) { ActivityRef old = _findById(ActivityRef.class, id); LOG.debug("ActivityRef will be deleted: " + old.toString()); ActivityRefListEntity refList = old.getDay().getMonth().getYear().getList(); // if (refList.isOnlyUpdate(old, activity.getUpdated().getTime())) { old.setName("" + activity.getUpdated().getTime()); old.setLastUpdated(activity.getUpdated().getTime()); } else { ActivityRef newRef = refList.getOrCreated(activity.getUpdated().getTime()); newRef.setLastUpdated(activity.getUpdated().getTime()); newRef.setActivityEntity(activityEntity); getSession().remove(old); } } } // mentioners addMentioner(streamCtx.getMentioners(), activityEntity); //turnOffLock to get increase perf //turnOnUpdateLock = false; } catch (NodeNotFoundException ex) { LOG.warn("Probably was updated activity reference by another session"); LOG.debug(ex.getMessage(), ex); //turnOnLock to avoid next exception } catch (ChromatticException ex) { Throwable throwable = ex.getCause(); if (throwable instanceof ItemExistsException || throwable instanceof InvalidItemStateException || throwable instanceof PathNotFoundException) { LOG.warn("Probably was updated activity reference by another session"); LOG.debug(ex.getMessage(), ex); //turnOnLock to avoid next exception } else { LOG.warn("Probably was updated activity reference by another session", ex); LOG.debug(ex.getMessage(), ex); } } finally { getSession().save(); lock.unlock(); } }
From source file:de.tudarmstadt.lt.seg.app.Segmenter.java
private void run_parallel() throws Exception { InputStream in = System.in; if (!"-".equals(_filename_in)) in = new FileInputStream(_filename_in); Stream<String> liter = new BufferedReader(new InputStreamReader(in, Charset.defaultCharset())).lines(); ThreadLocal<ISentenceSplitter> sentenceSplitter = ThreadLocal.withInitial(() -> { try {//from ww w. ja v a 2 s . c o m return newSentenceSplitter(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } }); ThreadLocal<ITokenizer> tokenizer = ThreadLocal.withInitial(() -> { try { return newTokenizer(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } }); final PrintWriter[] w = new PrintWriter[_parallelism]; // init writers for (int i = 0; i < _parallelism; i++) { OutputStream out = System.out; if (!"-".equals(_filename_out)) { out = new FileOutputStream(String.format("%s_%d", _filename_out, i)); } w[i] = new PrintWriter(new OutputStreamWriter(out, Charset.defaultCharset())); } BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(_parallelism * 2, true); ExecutorService es = new ThreadPoolExecutor(_parallelism, _parallelism, 0L, TimeUnit.MILLISECONDS, queue); AtomicLong lc = new AtomicLong(0); liter.forEach((line) -> { // don't try to submit new threads, wait until the thread queue has some capacity again while (queue.remainingCapacity() == 0) try { Thread.sleep(10); } catch (InterruptedException e) { /**/} es.submit(() -> { final long docid = lc.incrementAndGet(); if (docid % 1000 == 0) System.err.format("Processing line %d ('%s')%n", docid, _filename_in); final int w_i = (int) (docid % _parallelism); split_and_tokenize(new StringReader(line.trim()), String.format("%s:%d", _filename_in, docid), sentenceSplitter.get(), tokenizer.get(), _level_filter, _level_normalize, _merge_types, _merge_tokens, _separator_sentence, _separator_token, _separator_desc, w[w_i]); }); }); es.shutdown(); es.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS); // TODO: the stream parallelism version does not work because it submits too many threads at once // AtomicLong lc = new AtomicLong(0); // ForkJoinPool forkJoinPool = new ForkJoinPool(_parallelism); // forkJoinPool.submit(() -> // liter.parallel().forEach((line) -> { // final long docid = lc.incrementAndGet(); // if(docid % 1000 == 0) // System.err.format("Processing line %d ('%s')%n", docid, _filename_in); // // String l = line.replace("\\t", "\t").replace("\\n", "\n"); // split_and_tokenize( // new StringReader(l), // String.format("%s:%d", _filename_in, docid), // sentenceSplitter.get(), // tokenizer.get(), // _level_filter, // _level_normalize, // _merge_types, // _merge_tokens, // _separator_sentence, // _separator_token, // _separator_desc, // w); // })).get(); }
From source file:org.exoplatform.social.core.storage.impl.RelationshipStorageImpl.java
private String[] getRelationships(String id) { ThreadLocal<String[]> identityIdsLocal = new ThreadLocal<String[]>(); String[] relationshipIds = new String[0]; identityIdsLocal.set(relationshipIds); try {//ww w . j a va 2 s . c o m IdentityEntity identityEntity = _findById(IdentityEntity.class, id); StringBuffer sb = new StringBuffer().append("SELECT * FROM soc:relationshipdefinition WHERE "); sb.append(JCRProperties.path.getName()).append(" LIKE '") .append(identityEntity.getPath() + StorageUtils.SLASH_STR + StorageUtils.PERCENT_STR) .append("'"); // sb.append(" ORDER BY ").append(RelationshipEntity.createdTime.getName()).append(" DESC "); synchronized (lock) { NodeIterator it = nodes(sb.toString()); while (it.hasNext()) { Node node = (Node) it.next(); RelationshipEntity currentRelationshipEntity = _findById(RelationshipEntity.class, node.getUUID()); IdentityEntity gotIdentityEntity; if (currentRelationshipEntity.isReceiver()) { gotIdentityEntity = currentRelationshipEntity.getFrom(); } else { gotIdentityEntity = currentRelationshipEntity.getTo(); } identityIdsLocal .set((String[]) ArrayUtils.add(identityIdsLocal.get(), gotIdentityEntity.getId())); } } } catch (Exception e) { throw new RelationshipStorageException(RelationshipStorageException.Type.FAILED_TO_GET_RELATIONSHIP, e.getMessage()); } return identityIdsLocal.get(); }
From source file:com.moviejukebox.MovieJukebox.java
private void generateLibrary() throws Throwable { /**// w w w . j ava 2 s.co m * ****************************************************************************** * @author Gabriel Corneanu * * The tools used for parallel processing are NOT thread safe (some operations are, but not all) therefore all are added to * a container which is instantiated one per thread * * - xmlWriter looks thread safe<br> * - htmlWriter was not thread safe<br> * - getTransformer is fixed (simple workaround)<br> * - MovieImagePlugin : not clear, made thread specific for safety<br> * - MediaInfoScanner : not sure, made thread specific * * Also important: <br> * The library itself is not thread safe for modifications (API says so) it could be adjusted with concurrent versions, but * it needs many changes it seems that it is safe for subsequent reads (iterators), so leave for now... * * - DatabasePluginController is also fixed to be thread safe (plugins map for each thread) * */ class ToolSet { private final MovieImagePlugin imagePlugin = MovieJukebox .getImagePlugin(getProperty("mjb.image.plugin", "com.moviejukebox.plugin.DefaultImagePlugin")); private final MovieImagePlugin backgroundPlugin = MovieJukebox.getBackgroundPlugin( getProperty("mjb.background.plugin", "com.moviejukebox.plugin.DefaultBackgroundPlugin")); private final MediaInfoScanner miScanner = new MediaInfoScanner(); private final OpenSubtitlesPlugin subtitlePlugin = new OpenSubtitlesPlugin(); private final TrailerScanner trailerScanner = new TrailerScanner(); // FANART.TV TV Artwork Scanners private final ArtworkScanner clearArtScanner = new FanartTvScanner(ArtworkType.CLEARART); private final ArtworkScanner clearLogoScanner = new FanartTvScanner(ArtworkType.CLEARLOGO); private final ArtworkScanner tvThumbScanner = new FanartTvScanner(ArtworkType.TVTHUMB); private final ArtworkScanner seasonThumbScanner = new FanartTvScanner(ArtworkType.SEASONTHUMB); // FANART.TV Movie Artwork Scanners private final ArtworkScanner movieArtScanner = new FanartTvScanner(ArtworkType.MOVIEART); private final ArtworkScanner movieLogoScanner = new FanartTvScanner(ArtworkType.MOVIELOGO); private final ArtworkScanner movieDiscScanner = new FanartTvScanner(ArtworkType.MOVIEDISC); } final ThreadLocal<ToolSet> threadTools = new ThreadLocal<ToolSet>() { @Override protected ToolSet initialValue() { return new ToolSet(); } }; final MovieJukeboxXMLReader xmlReader = new MovieJukeboxXMLReader(); final MovieJukeboxXMLWriter xmlWriter = new MovieJukeboxXMLWriter(); final MovieJukeboxHTMLWriter htmlWriter = new MovieJukeboxHTMLWriter(); File mediaLibraryRoot = new File(movieLibraryRoot); final File jukeboxDetailsRootFile = new FileTools.FileEx(jukebox.getJukeboxRootLocationDetails()); MovieListingPlugin listingPlugin = getListingPlugin( getProperty("mjb.listing.plugin", "com.moviejukebox.plugin.MovieListingPluginBase")); videoimageDownload = PropertiesUtil.getBooleanProperty("mjb.includeVideoImages", Boolean.FALSE); bannerDownload = PropertiesUtil.getBooleanProperty("mjb.includeWideBanners", Boolean.FALSE); photoDownload = PropertiesUtil.getBooleanProperty("mjb.includePhoto", Boolean.FALSE); backdropDownload = PropertiesUtil.getBooleanProperty("mjb.includeBackdrop", Boolean.FALSE); boolean processExtras = PropertiesUtil.getBooleanProperty("filename.extras.process", Boolean.TRUE); boolean moviejukeboxListing = PropertiesUtil.getBooleanProperty("mjb.listing.generate", Boolean.FALSE); // Multi-thread: Processing thread settings maxThreadsProcess = Integer.parseInt(getProperty("mjb.MaxThreadsProcess", "0")); if (maxThreadsProcess <= 0) { maxThreadsProcess = Runtime.getRuntime().availableProcessors(); } maxThreadsDownload = Integer.parseInt(getProperty("mjb.MaxThreadsDownload", "0")); if (maxThreadsDownload <= 0) { maxThreadsDownload = maxThreadsProcess; } LOG.info("Using {} processing threads and {} downloading threads...", maxThreadsProcess, maxThreadsDownload); if (maxThreadsDownload + maxThreadsProcess == 2) { // Display the note about the performance, otherwise assume that the user knows how to change // these parameters as they aren't set to the minimum LOG.info("See README.TXT for increasing performance using these settings."); } /* * ****************************************************************************** * * PART 1 : Preparing the temporary environment * */ SystemTools.showMemory(); LOG.info("Preparing environment..."); // create the ".mjbignore" and ".no_photo.nmj" file in the jukebox folder try { FileTools.makeDirs(jukebox.getJukeboxRootLocationDetailsFile()); new File(jukebox.getJukeboxRootLocationDetailsFile(), ".mjbignore").createNewFile(); FileTools.addJukeboxFile(".mjbignore"); if (getBooleanProperty("mjb.nmjCompliant", Boolean.FALSE)) { new File(jukebox.getJukeboxRootLocationDetailsFile(), ".no_photo.nmj").createNewFile(); FileTools.addJukeboxFile(".no_photo.nmj"); } } catch (IOException error) { LOG.error("Failed creating jukebox directory. Ensure this directory is read/write!"); LOG.error(SystemTools.getStackTrace(error)); return; } // Delete the existing filecache.txt try { (new File("filecache.txt")).delete(); } catch (Exception error) { LOG.error("Failed to delete the filecache.txt file."); LOG.error(SystemTools.getStackTrace(error)); return; } // Save the current state of the preferences to the skin directory for use by the skin // The forceHtmlOverwrite is set by the user or by the JukeboxProperties if there has been a skin change if (PropertiesUtil.getBooleanProperty("mjb.forceHTMLOverwrite", Boolean.FALSE) || !(new File(PropertiesUtil.getPropertiesFilename(Boolean.TRUE))).exists()) { PropertiesUtil.writeProperties(); } SystemTools.showMemory(); LOG.info("Initializing..."); try { FileTools.deleteDir(jukebox.getJukeboxTempLocation()); } catch (Exception error) { LOG.error( "Failed deleting the temporary jukebox directory ({}), please delete this manually and try again", jukebox.getJukeboxTempLocation()); return; } // Try and create the temp directory LOG.debug("Creating temporary jukebox location: {}", jukebox.getJukeboxTempLocation()); FileTools.makeDirs(jukebox.getJukeboxTempLocationDetailsFile()); /* * ****************************************************************************** * * PART 2 : Scan movie libraries for files... * */ SystemTools.showMemory(); LOG.info("Scanning library directory {}", mediaLibraryRoot); LOG.info("Jukebox output goes to {}", jukebox.getJukeboxRootLocation()); if (PropertiesUtil.getBooleanProperty("mjb.dirHash", Boolean.FALSE)) { // Add all folders 2 deep to the fileCache FileTools.fileCache.addDir(jukeboxDetailsRootFile, 2); /* * TODO: Need to watch for any issues when we have scanned the whole * jukebox, such as the watched folder, NFO folder, etc now existing * in the cache */ } else { // If the dirHash is not needed, just scan to the root level plus the watched and people folders FileTools.fileCache.addDir(jukeboxDetailsRootFile, 0); // Add the watched folder File watchedFileHandle = new FileTools.FileEx( jukebox.getJukeboxRootLocationDetails() + File.separator + "Watched"); FileTools.fileCache.addDir(watchedFileHandle, 0); // Add the people folder if needed if (isValidString(peopleFolder)) { File peopleFolderHandle = new FileTools.FileEx( jukebox.getJukeboxRootLocationDetails() + File.separator + peopleFolder); FileTools.fileCache.addDir(peopleFolderHandle, 0); } } ThreadExecutor<Void> tasks = new ThreadExecutor<>(maxThreadsProcess, maxThreadsDownload); final Library library = new Library(); for (final MediaLibraryPath mediaLibraryPath : mediaLibraryPaths) { // Multi-thread parallel processing tasks.submit(new Callable<Void>() { @Override public Void call() { LOG.debug("Scanning media library {}", mediaLibraryPath.getPath()); MovieDirectoryScanner mds = new MovieDirectoryScanner(); // scan uses synchronized method Library.addMovie mds.scan(mediaLibraryPath, library); System.out.print("\n"); return null; } }); } tasks.waitFor(); SystemTools.showMemory(); // If the user asked to preserve the existing movies, scan the output directory as well if (isJukeboxPreserve()) { LOG.info("Scanning output directory for additional videos"); OutputDirectoryScanner ods = new OutputDirectoryScanner(jukebox.getJukeboxRootLocationDetails()); ods.scan(library); } // Now that everything's been scanned, add all extras to library library.mergeExtras(); LOG.info("Found {} videos in your media library", library.size()); LOG.info("Stored {} files in the info cache", FileTools.fileCache.size()); if (enableWatchTraktTv) { // if Trakt.TV watched is enabled then refresh if necessary and preLoad watched data TraktTV.getInstance().initialize().refreshIfNecessary().preloadWatched(); } JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.SCAN_END, System.currentTimeMillis()); JukeboxStatistics.setStatistic(JukeboxStatistic.VIDEOS, library.size()); tasks.restart(); if (!library.isEmpty()) { // Issue 1882: Separate index files for each category boolean separateCategories = PropertiesUtil.getBooleanProperty("mjb.separateCategories", Boolean.FALSE); LOG.info("Searching for information on the video files..."); int movieCounter = 0; for (final Movie movie : library.values()) { // Issue 997: Skip the processing of extras if not required if (movie.isExtra() && !processExtras) { continue; } final int count = ++movieCounter; final String movieTitleExt = movie.getOriginalTitle() + (movie.isTVShow() ? (" [Season " + movie.getSeason() + "]") : "") + (movie.isExtra() ? " [Extra]" : ""); if (movie.isTVShow()) { JukeboxStatistics.increment(JukeboxStatistic.TVSHOWS); } else { JukeboxStatistics.increment(JukeboxStatistic.MOVIES); } // Multi-thread parallel processing tasks.submit(new Callable<Void>() { @Override public Void call() throws FileNotFoundException, XMLStreamException { ToolSet tools = threadTools.get(); // Change the output message depending on the existance of the XML file boolean xmlExists = FileTools.fileCache .fileExists(StringTools.appendToPath(jukebox.getJukeboxRootLocationDetails(), movie.getBaseName()) + EXT_DOT_XML); if (xmlExists) { LOG.info("Checking existing video: {}", movieTitleExt); JukeboxStatistics.increment(JukeboxStatistic.EXISTING_VIDEOS); } else { LOG.info("Processing new video: {}", movieTitleExt); JukeboxStatistics.increment(JukeboxStatistic.NEW_VIDEOS); } if (ScanningLimit.getToken()) { // First get movie data (title, year, director, genre, etc...) library.toggleDirty( updateMovieData(xmlReader, tools.miScanner, jukebox, movie, library)); if (!movie.getMovieType().equals(Movie.REMOVE)) { // Check for watched and unwatched files if (enableWatchScanner || enableWatchTraktTv) { // Issue 1938 library.toggleDirty(WatchedScanner.checkWatched(jukebox, movie)); } // Get subtitle tools.subtitlePlugin.generate(movie); // Get Trailers if (trailersScannerEnable) { tools.trailerScanner.getTrailers(movie); } // Then get this movie's poster LOG.debug("Updating poster for: {}", movieTitleExt); updateMoviePoster(jukebox, movie); // Download episode images if required if (videoimageDownload) { VideoImageScanner.scan(tools.imagePlugin, jukebox, movie); } // Get FANART only if requested // Note that the FanartScanner will check if the file is newer / different if ((fanartMovieDownload && !movie.isTVShow()) || (fanartTvDownload && movie.isTVShow())) { FanartScanner.scan(tools.backgroundPlugin, jukebox, movie); } // Get BANNER if requested and is a TV show if (bannerDownload && movie.isTVShow()) { if (!BannerScanner.scan(tools.imagePlugin, jukebox, movie)) { updateTvBanner(jukebox, movie, tools.imagePlugin); } } // Get ClearART/LOGOS/etc if (movie.isTVShow()) { // Only scan using the TV Show artwork scanners tools.clearArtScanner.scan(jukebox, movie); tools.clearLogoScanner.scan(jukebox, movie); tools.tvThumbScanner.scan(jukebox, movie); tools.seasonThumbScanner.scan(jukebox, movie); } else { // Only scan using the Movie artwork scanners tools.movieArtScanner.scan(jukebox, movie); tools.movieDiscScanner.scan(jukebox, movie); tools.movieLogoScanner.scan(jukebox, movie); } for (int i = 0; i < footerCount; i++) { if (FOOTER_ENABLE.get(i)) { updateFooter(jukebox, movie, tools.imagePlugin, i, forceFooterOverwrite || movie.isDirty()); } } // If we are multipart, we need to make sure all archives have expanded names. if (PropertiesUtil.getBooleanProperty("mjb.scanner.mediainfo.rar.extended.url", Boolean.FALSE)) { Collection<MovieFile> partsFiles = movie.getFiles(); for (MovieFile mf : partsFiles) { String filename; filename = mf.getFile().getAbsolutePath(); // Check the filename is a mediaInfo extension (RAR, ISO) ? if (tools.miScanner.extendedExtension(filename) == Boolean.TRUE) { if (mf.getArchiveName() == null) { LOG.debug("MovieJukebox: Attempting to get archive name for {}", filename); String archive = tools.miScanner.archiveScan(filename); if (archive != null) { LOG.debug("MovieJukebox: Setting archive name to {}", archive); mf.setArchiveName(archive); } // got archivename } // not already set } // is extension } // for all files } // property is set if (!movie.isDirty()) { ScanningLimit.releaseToken(); } } else { ScanningLimit.releaseToken(); library.remove(movie); } LOG.info(LOG_FINISHED, movieTitleExt, count, library.size()); } else { movie.setSkipped(true); JukeboxProperties.setScanningLimitReached(Boolean.TRUE); LOG.info("Skipped: {} ({}/{})", movieTitleExt, count, library.size()); } // Show memory every (processing count) movies if (showMemory && (count % maxThreadsProcess) == 0) { SystemTools.showMemory(); } return null; } }); } tasks.waitFor(); // Add the new extra files (like trailers that were downloaded) to the library and to the corresponding movies library.mergeExtras(); OpenSubtitlesPlugin.logOut(); AniDbPlugin.anidbClose(); JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.PROCESSING_END, System.currentTimeMillis()); if (peopleScan && peopleScrape && !ScanningLimit.isLimitReached()) { LOG.info("Searching for people information..."); int peopleCounter = 0; Map<String, Person> popularPeople = new TreeMap<>(); for (Movie movie : library.values()) { // Issue 997: Skip the processing of extras if not required if (movie.isExtra() && !processExtras) { continue; } if (popularity > 0) { for (Filmography person : movie.getPeople()) { boolean exists = Boolean.FALSE; String name = person.getName(); for (Map.Entry<String, Person> entry : popularPeople.entrySet()) { if (entry.getKey().substring(3).equalsIgnoreCase(name)) { entry.getValue().addDepartment(person.getDepartment()); entry.getValue().popularityUp(movie); exists = Boolean.TRUE; } } if (!exists) { Person p = new Person(person); p.addDepartment(p.getDepartment()); String key = String.format("%03d", person.getOrder()) + person.getName(); popularPeople.put(key, p); popularPeople.get(key).popularityUp(movie); } } } else { peopleCounter += movie.getPeople().size(); } } tasks.restart(); if (popularity > 0) { List<Person> as = new ArrayList<>(popularPeople.values()); Collections.sort(as, new PersonComparator()); List<Person> stars = new ArrayList<>(); Iterator<Person> itr = as.iterator(); while (itr.hasNext()) { if (peopleCounter >= peopleMax) { break; } Person person = itr.next(); if (popularity > person.getPopularity()) { break; } stars.add(person); peopleCounter++; } final int peopleCount = peopleCounter; peopleCounter = 0; for (final Person person : stars) { final int count = ++peopleCounter; final String personName = person.getName(); final Person p = new Person(person); // Multi-thread parallel processing tasks.submit(new Callable<Void>() { @Override public Void call() throws FileNotFoundException, XMLStreamException { ToolSet tools = threadTools.get(); // Get person data (name, birthday, etc...), download photo updatePersonData(xmlReader, jukebox, p, tools.imagePlugin); library.addPerson(p); LOG.info(LOG_FINISHED, personName, count, peopleCount); // Show memory every (processing count) movies if (showMemory && (count % maxThreadsProcess) == 0) { SystemTools.showMemory(); } return null; } }); } } else { final int peopleCount = peopleCounter; peopleCounter = 0; for (Movie movie : library.values()) { // Issue 997: Skip the processing of extras if not required if (movie.isExtra() && !processExtras) { continue; } Map<String, Integer> typeCounter = new TreeMap<>(); for (Filmography person : movie.getPeople()) { final int count = ++peopleCounter; String job = person.getJob(); if (!typeCounter.containsKey(job)) { typeCounter.put(job, 1); } else if (typeCounter.get(job) == peopleMax) { continue; } else { typeCounter.put(job, typeCounter.get(job) + 1); } final Person p = new Person(person); final String personName = p.getName(); // Multi-thread parallel processing tasks.submit(new Callable<Void>() { @Override public Void call() throws FileNotFoundException, XMLStreamException { ToolSet tools = threadTools.get(); // Get person data (name, birthday, etc...), download photo and put to library updatePersonData(xmlReader, jukebox, p, tools.imagePlugin); library.addPerson(p); LOG.info(LOG_FINISHED, personName, count, peopleCount); // Show memory every (processing count) movies if (showMemory && (count % maxThreadsProcess) == 0) { SystemTools.showMemory(); } return null; } }); } } } tasks.waitFor(); LOG.info("Add/update people information to the videos..."); boolean dirty; for (Movie movie : library.values()) { // Issue 997: Skip the processing of extras if not required if (movie.isExtra() && !processExtras) { continue; } for (Filmography person : movie.getPeople()) { dirty = Boolean.FALSE; for (Person p : library.getPeople()) { if (Filmography.comparePersonName(person, p) || comparePersonId(person, p)) { if (!person.getFilename().equals(p.getFilename()) && isValidString(p.getFilename())) { person.setFilename(p.getFilename()); dirty = Boolean.TRUE; } if (!person.getUrl().equals(p.getUrl()) && isValidString(p.getUrl())) { person.setUrl(p.getUrl()); dirty = Boolean.TRUE; } for (Map.Entry<String, String> e : p.getIdMap().entrySet()) { if (isNotValidString(e.getValue())) { continue; } if (person.getId(e.getKey()).equals(e.getValue())) { continue; } person.setId(e.getKey(), e.getValue()); dirty = Boolean.TRUE; } if (!person.getPhotoFilename().equals(p.getPhotoFilename()) && isValidString(p.getPhotoFilename())) { person.setPhotoFilename(p.getPhotoFilename()); dirty = Boolean.TRUE; } break; } } if (dirty) { movie.setDirty(DirtyFlag.INFO, Boolean.TRUE); } } for (Person p : library.getPeople()) { for (Filmography film : p.getFilmography()) { if (Filmography.compareMovieAndFilm(movie, film)) { film.setFilename(movie.getBaseName()); film.setTitle(movie.getTitle()); if (film.isDirty()) { p.setDirty(); } break; } } } } for (Person p : library.getPeople()) { for (Filmography film : p.getFilmography()) { if (film.isDirty() || StringTools.isNotValidString(film.getFilename())) { continue; } dirty = Boolean.FALSE; for (Movie movie : library.values()) { if (movie.isExtra() && !processExtras) { continue; } dirty = Filmography.compareMovieAndFilm(movie, film); if (dirty) { break; } } if (!dirty) { film.clearFilename(); p.setDirty(); } } } JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.PEOPLE_END, System.currentTimeMillis()); } /* * ****************************************************************************** * * PART 3 : Indexing the library * */ SystemTools.showMemory(); // This is for programs like NMTServer where they don't need the indexes. if (skipIndexGeneration) { LOG.info("Indexing of libraries skipped."); } else { LOG.info("Indexing libraries..."); library.buildIndex(tasks); JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.INDEXING_END, System.currentTimeMillis()); SystemTools.showMemory(); } /* * ****************************************************************************** * * PART 3B - Indexing masters */ LOG.info("Indexing masters..."); /* * This is kind of a hack -- library.values() are the movies that * were found in the library and library.getMoviesList() are the * ones that are there now. So the movies that are in getMoviesList * but not in values are the index masters. */ List<Movie> indexMasters = new ArrayList<>(library.getMoviesList()); indexMasters.removeAll(library.values()); JukeboxStatistics.setStatistic(JukeboxStatistic.SETS, indexMasters.size()); // Multi-thread: Parallel Executor tasks.restart(); final boolean autoCollection = PropertiesUtil.getBooleanProperty("themoviedb.collection", Boolean.FALSE); final TheMovieDbPlugin tmdb = new TheMovieDbPlugin(); for (final Movie movie : indexMasters) { // Multi-tread: Start Parallel Processing tasks.submit(new Callable<Void>() { @Override public Void call() throws FileNotFoundException, XMLStreamException { ToolSet tools = threadTools.get(); String safeSetMasterBaseName = FileTools.makeSafeFilename(movie.getBaseName()); /* * The master's movie XML is used for generating the * playlist it will be overwritten by the index XML */ LOG.debug("Updating set artwork for: {}...", movie.getOriginalTitle()); // If we can find a set artwork file, use it; otherwise, stick with the first movie's artwork String oldArtworkFilename = movie.getPosterFilename(); // Set a default poster name in case it's not found during the scan movie.setPosterFilename(safeSetMasterBaseName + "." + posterExtension); if (isNotValidString(PosterScanner.scan(jukebox, movie))) { LOG.debug("Local set poster ({}) not found.", safeSetMasterBaseName); String collectionId = movie.getId(TheMovieDbPlugin.CACHE_COLLECTION); if (autoCollection && StringUtils.isNumeric(collectionId)) { LOG.debug("MovieDb Collection detected with ID {}", collectionId); movie.setPosterURL(tmdb.getCollectionPoster(Integer.parseInt(collectionId))); movie.setFanartURL(tmdb.getCollectionFanart(Integer.parseInt(collectionId))); updateMoviePoster(jukebox, movie); } else { movie.setPosterFilename(oldArtworkFilename); } } // If this is a TV Show and we want to download banners, then also check for a banner Set file if (movie.isTVShow() && bannerDownload) { // Set a default banner filename in case it's not found during the scan movie.setBannerFilename(safeSetMasterBaseName + bannerToken + "." + bannerExtension); movie.setWideBannerFilename( safeSetMasterBaseName + wideBannerToken + "." + bannerExtension); if (!BannerScanner.scan(tools.imagePlugin, jukebox, movie)) { updateTvBanner(jukebox, movie, tools.imagePlugin); LOG.debug("Local set banner ({}{}.*) not found.", safeSetMasterBaseName, bannerToken); } else { LOG.debug("Local set banner found, using {}", movie.getBannerFilename()); } } // Check for Set FANART if (setIndexFanart) { // Set a default fanart filename in case it's not found during the scan movie.setFanartFilename(safeSetMasterBaseName + fanartToken + "." + fanartExtension); if (!FanartScanner.scan(tools.backgroundPlugin, jukebox, movie)) { LOG.debug("Local set fanart ({}{}.*) not found.", safeSetMasterBaseName, fanartToken); } else { LOG.debug("Local set fanart found, using {}", movie.getFanartFilename()); } } StringBuilder artworkFilename = new StringBuilder(safeSetMasterBaseName); artworkFilename.append(thumbnailToken).append(".").append(thumbnailExtension); movie.setThumbnailFilename(artworkFilename.toString()); artworkFilename = new StringBuilder(safeSetMasterBaseName); artworkFilename.append(posterToken).append(".").append(posterExtension); movie.setDetailPosterFilename(artworkFilename.toString()); // Generate footer filenames for (int inx = 0; inx < footerCount; inx++) { if (FOOTER_ENABLE.get(inx)) { artworkFilename = new StringBuilder(safeSetMasterBaseName); if (FOOTER_NAME.get(inx).contains("[")) { artworkFilename.append(footerToken).append("_").append(inx); } else { artworkFilename.append(".").append(FOOTER_NAME.get(inx)); } artworkFilename.append(".").append(FOOTER_EXTENSION.get(inx)); movie.setFooterFilename(artworkFilename.toString(), inx); } } // No playlist for index masters // htmlWriter.generatePlaylist(jukeboxDetailsRoot, tempJukeboxDetailsRoot, movie); // Add all the movie files to the exclusion list FileTools.addMovieToJukeboxFilenames(movie); return null; } }); } tasks.waitFor(); // Clear the cache if we've used it CacheMemory.clear(); JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.MASTERS_END, System.currentTimeMillis()); SystemTools.showMemory(); // Issue 1886: Html indexes recreated every time StringBuilder indexFilename; for (Movie setMovie : library.getMoviesList()) { if (setMovie.isSetMaster()) { indexFilename = new StringBuilder(jukebox.getJukeboxRootLocationDetails()); indexFilename.append(File.separator).append(setMovie.getBaseName()).append(EXT_DOT_XML); File xmlFile = FileTools.fileCache.getFile(indexFilename.toString()); if (xmlFile.exists()) { xmlReader.parseSetXML(xmlFile, setMovie, library.getMoviesList()); } } } // Issue 1882: Separate index files for each category List<String> categoriesList = Arrays.asList( getProperty("mjb.categories.indexList", "Other,Genres,Title,Certification,Year,Library,Set") .split(",")); if (!skipIndexGeneration) { LOG.info("Writing Indexes XML..."); xmlWriter.writeIndexXML(jukebox, library, tasks); // Issue 2235: Update artworks after masterSet changed ToolSet tools = threadTools.get(); StringBuilder idxName; boolean createPosters = PropertiesUtil.getBooleanProperty("mjb.sets.createPosters", Boolean.FALSE); for (IndexInfo idx : library.getGeneratedIndexes()) { if (!idx.canSkip && idx.categoryName.equals(Library.INDEX_SET)) { idxName = new StringBuilder(idx.categoryName); idxName.append("_").append(FileTools.makeSafeFilename(idx.key)).append("_1"); for (Movie movie : indexMasters) { if (!movie.getBaseName().equals(idxName.toString())) { continue; } if (createPosters) { // Create/update a detail poster for setMaster LOG.debug("Create/update detail poster for set: {}", movie.getBaseName()); createPoster(tools.imagePlugin, jukebox, SkinProperties.getSkinHome(), movie, Boolean.TRUE); } // Create/update a thumbnail for setMaster LOG.debug("Create/update thumbnail for set: {}, isTV: {}, isHD: {}", movie.getBaseName(), movie.isTVShow(), movie.isHD()); createThumbnail(tools.imagePlugin, jukebox, SkinProperties.getSkinHome(), movie, Boolean.TRUE); for (int inx = 0; inx < footerCount; inx++) { if (FOOTER_ENABLE.get(inx)) { LOG.debug("Create/update footer for set: {}, footerName: {}", movie.getBaseName(), FOOTER_NAME.get(inx)); updateFooter(jukebox, movie, tools.imagePlugin, inx, Boolean.TRUE); } } } } } LOG.info("Writing Category XML..."); library.setDirty(library.isDirty() || forceIndexOverwrite); xmlWriter.writeCategoryXML(jukebox, library, "Categories", library.isDirty()); // Issue 1882: Separate index files for each category if (separateCategories) { for (String categoryName : categoriesList) { xmlWriter.writeCategoryXML(jukebox, library, categoryName, library.isDirty()); } } } SystemTools.showMemory(); LOG.info("Writing Library data..."); // Multi-thread: Parallel Executor tasks.restart(); int totalCount = library.values().size(); int currentCount = 1; for (final Movie movie : library.values()) { System.out.print("\r Processing library #" + currentCount++ + "/" + totalCount); // Issue 997: Skip the processing of extras if not required if (movie.isExtra() && !processExtras) { continue; } if (movie.isSkipped()) { continue; } // Multi-tread: Start Parallel Processing tasks.submit(new Callable<Void>() { @Override public Void call() throws FileNotFoundException, XMLStreamException { ToolSet tools = threadTools.get(); // Update movie XML files with computed index information LOG.debug("Writing index data to movie: {}", movie.getBaseName()); xmlWriter.writeMovieXML(jukebox, movie, library); // Create a detail poster for each movie LOG.debug("Creating detail poster for movie: {}", movie.getBaseName()); createPoster(tools.imagePlugin, jukebox, SkinProperties.getSkinHome(), movie, forcePosterOverwrite); // Create a thumbnail for each movie LOG.debug("Creating thumbnails for movie: {}", movie.getBaseName()); createThumbnail(tools.imagePlugin, jukebox, SkinProperties.getSkinHome(), movie, forceThumbnailOverwrite); if (!skipIndexGeneration && !skipHtmlGeneration) { // write the movie details HTML LOG.debug("Writing detail HTML to movie: {}", movie.getBaseName()); htmlWriter.generateMovieDetailsHTML(jukebox, movie); // write the playlist for the movie if needed if (!skipPlaylistGeneration) { FileTools.addJukeboxFiles(htmlWriter.generatePlaylist(jukebox, movie)); } } // Add all the movie files to the exclusion list FileTools.addMovieToJukeboxFilenames(movie); return null; } }); } tasks.waitFor(); System.out.print("\n"); SystemTools.showMemory(); JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.WRITE_INDEX_END, System.currentTimeMillis()); if (peopleScan) { LOG.info("Writing people data..."); // Multi-thread: Parallel Executor tasks.restart(); totalCount = library.getPeople().size(); currentCount = 1; for (final Person person : library.getPeople()) { // Multi-tread: Start Parallel Processing System.out.print("\r Processing person #" + currentCount++ + "/" + totalCount); tasks.submit(new Callable<Void>() { @Override public Void call() throws FileNotFoundException, XMLStreamException { // ToolSet tools = threadTools.get(); // Update person XML files with computed index information LOG.debug("Writing index data to person: {}", person.getName()); xmlWriter.writePersonXML(jukebox, person); if (!skipIndexGeneration && !skipHtmlGeneration) { // write the person details HTML htmlWriter.generatePersonDetailsHTML(jukebox, person); } return null; } }); } tasks.waitFor(); System.out.print("\n"); SystemTools.showMemory(); JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.WRITE_PEOPLE_END, System.currentTimeMillis()); } if (!skipIndexGeneration) { if (!skipHtmlGeneration) { LOG.info("Writing Indexes HTML..."); LOG.info(" Video indexes..."); htmlWriter.generateMoviesIndexHTML(jukebox, library, tasks); LOG.info(" Category indexes..."); htmlWriter.generateMoviesCategoryHTML(jukebox, "Categories", "categories.xsl", library.isDirty()); // Issue 1882: Separate index files for each category if (separateCategories) { LOG.info(" Separate category indexes..."); for (String categoryName : categoriesList) { htmlWriter.generateMoviesCategoryHTML(jukebox, categoryName, "category.xsl", library.isDirty()); } } } /* * Generate the index file. * * Do not skip this part as it's the index that starts the jukebox */ htmlWriter.generateMainIndexHTML(jukebox, library); JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.WRITE_HTML_END, System.currentTimeMillis()); /* Generate extra pages if required */ String pageList = PropertiesUtil.getProperty("mjb.customPages", ""); if (StringUtils.isNotBlank(pageList)) { List<String> newPages = new ArrayList<>(Arrays.asList(pageList.split(","))); for (String page : newPages) { LOG.info("Transforming skin custom page '{}'", page); htmlWriter.transformXmlFile(jukebox, page); } } } if (enableCompleteMovies) { CompleteMoviesWriter.generate(library, jukebox); } /** * ****************************************************************************** * * PART 4 : Copy files to target directory * */ SystemTools.showMemory(); LOG.info("Copying new files to Jukebox directory..."); String index = getProperty("mjb.indexFile", "index.htm"); FileTools.copyDir(jukebox.getJukeboxTempLocationDetails(), jukebox.getJukeboxRootLocationDetails(), Boolean.TRUE); FileTools.copyFile(new File(jukebox.getJukeboxTempLocation() + File.separator + index), new File(jukebox.getJukeboxRootLocation() + File.separator + index)); String skinDate = jukebox.getJukeboxRootLocationDetails() + File.separator + "pictures" + File.separator + "skin.date"; File skinFile = new File(skinDate); File propFile = new File(userPropertiesName); // Only check the property file date if the jukebox properties are not being monitored. boolean copySkin = JukeboxProperties.isMonitor() ? Boolean.FALSE : FileTools.isNewer(propFile, skinFile); // If forceSkinOverwrite is set, the skin file doesn't exist, the user properties file doesn't exist or is newer than the skin.date file if (forceSkinOverwrite || !skinFile.exists() || !propFile.exists() || (SkinProperties.getFileDate() > skinFile.lastModified()) || copySkin) { if (forceSkinOverwrite) { LOG.info("Copying skin files to Jukebox directory (forceSkinOverwrite)..."); } else if (SkinProperties.getFileDate() > skinFile.lastModified()) { LOG.info("Copying skin files to Jukebox directory (Skin is newer)..."); } else if (!propFile.exists()) { LOG.info("Copying skin files to Jukebox directory (No property file)..."); } else if (FileTools.isNewer(propFile, skinFile)) { LOG.info("Copying skin files to Jukebox directory ({} is newer)...", propFile.getName()); } else { LOG.info("Copying skin files to Jukebox directory..."); } StringTokenizer st = new StringTokenizer(PropertiesUtil.getProperty("mjb.skin.copyDirs", "html"), " ,;|"); while (st.hasMoreTokens()) { String skinDirName = st.nextToken(); String skinDirFull = StringTools.appendToPath(SkinProperties.getSkinHome(), skinDirName); if ((new File(skinDirFull).exists())) { LOG.info("Copying the {} directory...", skinDirName); FileTools.copyDir(skinDirFull, jukebox.getJukeboxRootLocationDetails(), Boolean.TRUE); } } if (skinFile.exists()) { skinFile.setLastModified(JukeboxStatistics.getTime(JukeboxStatistics.JukeboxTimes.START)); } else { FileTools.makeDirsForFile(skinFile); skinFile.createNewFile(); } } else { LOG.info("Skin copying skipped."); LOG.debug("Use mjb.forceSkinOverwrite=true to force the overwitting of the skin files"); } FileTools.fileCache.saveFileList("filecache.txt"); JukeboxStatistics.setJukeboxTime(JukeboxStatistics.JukeboxTimes.COPYING_END, System.currentTimeMillis()); /** * ****************************************************************************** * * PART 5: Clean-up the jukebox directory * */ SystemTools.showMemory(); // Clean the jukebox folder of unneeded files cleanJukeboxFolder(); if (moviejukeboxListing) { LOG.info("Generating listing output..."); listingPlugin.generate(jukebox, library); } LOG.info("Clean up temporary files"); File rootIndex = new File(appendToPath(jukebox.getJukeboxTempLocation(), index)); rootIndex.delete(); FileTools.deleteDir(jukebox.getJukeboxTempLocation()); // clean up extracted attachments AttachmentScanner.cleanUp(); } // Set the end time JukeboxStatistics.setTimeEnd(System.currentTimeMillis()); // Write the jukebox details file at the END of the run (Issue 1830) JukeboxProperties.writeFile(jukebox, library, mediaLibraryPaths); // Output the statistics JukeboxStatistics.writeFile(jukebox, library, mediaLibraryPaths); LOG.info(""); LOG.info("MovieJukebox process completed at {}", new Date()); LOG.info("Processing took {}", JukeboxStatistics.getProcessingTime()); }