com.moviejukebox.scanner.MovieNFOScanner.java Source code

Java tutorial

Introduction

Here is the source code for com.moviejukebox.scanner.MovieNFOScanner.java

Source

/*
 *      Copyright (c) 2004-2016 YAMJ Members
 *      https://github.com/orgs/YAMJ/people
 *
 *      This file is part of the Yet Another Movie Jukebox (YAMJ) project.
 *
 *      YAMJ is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      any later version.
 *
 *      YAMJ is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with YAMJ.  If not, see <http://www.gnu.org/licenses/>.
 *
 *      Web: https://github.com/YAMJ/yamj-v2
 *
 */
package com.moviejukebox.scanner;

import com.moviejukebox.model.Movie;
import com.moviejukebox.model.MovieFile;
import com.moviejukebox.model.enumerations.DirtyFlag;
import com.moviejukebox.reader.MovieNFOReader;
import com.moviejukebox.tools.FileTools;
import com.moviejukebox.tools.GenericFileFilter;
import com.moviejukebox.tools.PropertiesUtil;
import com.moviejukebox.tools.StringTools;
import static com.moviejukebox.tools.StringTools.appendToPath;
import static com.moviejukebox.tools.StringTools.isValidString;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FilenameUtils;
import org.pojava.datetime.DateTimeConfigBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * NFO file parser.
 *
 * Search a NFO file for IMDb URL.
 *
 * @author jjulien
 */
public final class MovieNFOScanner {

    private static final Logger LOG = LoggerFactory.getLogger(MovieNFOScanner.class);
    // Other properties
    private static final String XBMC_TV_NFO_NAME = "tvshow";
    // For now, this is deprecated and we should see if there are issues before looking at a solution as the DOM Parser seems a lot more stable
    private static final String NFO_DIR = PropertiesUtil.getProperty("filename.nfo.directory", "");
    private static final boolean ACCEPT_ALL_NFO = PropertiesUtil.getBooleanProperty("filename.nfo.acceptAllNfo",
            Boolean.FALSE);
    private static final String NFO_EXT_REGEX;
    private static final String[] NFO_EXTENSIONS = PropertiesUtil.getProperty("filename.nfo.extensions", "NFO")
            .split(",");
    private static final Pattern PART_PATTERN = Pattern
            .compile("(?i)(?:(?:CD)|(?:DISC)|(?:DISK)|(?:PART))([0-9]+)");
    private static final boolean ARCHIVE_SCAN_RAR = PropertiesUtil.getBooleanProperty("mjb.scanner.archivescan.rar",
            Boolean.FALSE);
    private static final boolean SKIP_TV_NFO_FILES = PropertiesUtil
            .getBooleanProperty("filename.nfo.skipTVNFOFiles", Boolean.FALSE);

    static {
        if (ACCEPT_ALL_NFO) {
            LOG.info("Accepting all NFO files in the directory");
        }

        // Construct regex for filtering NFO files
        // Target format is: ".*\\(ext1|ext2|ext3|..|extN)"
        {
            boolean first = Boolean.TRUE;
            StringBuilder regexBuilder = new StringBuilder("(?i).*\\.("); // Start of REGEX
            for (String ext : NFO_EXTENSIONS) {
                if (first) {
                    first = Boolean.FALSE;
                } else {
                    regexBuilder.append("|"); // Add seperator
                }
                regexBuilder.append(ext).append("$"); // Add extension
            }
            regexBuilder.append(")"); // End of REGEX
            NFO_EXT_REGEX = regexBuilder.toString();
        }

        // Set the date format to dd-MM-yyyy
        //        DateTimeConfig.globalEuropeanDateFormat();
        DateTimeConfigBuilder.newInstance().setDmyOrder(true);
    }

    private MovieNFOScanner() {
        throw new UnsupportedOperationException("Class cannot be instantiated");
    }

    /**
     * Process the NFO file.
     *
     * Will either process the file as an XML NFO file or just pick out the
     * poster and fanart URLs
     *
     * Scanning for site specific URLs should be done by each plugin
     *
     * @param movie
     * @param nfoFiles
     */
    public static void scan(Movie movie, List<File> nfoFiles) {
        for (File nfoFile : nfoFiles) {
            LOG.debug("Scanning NFO file for information: {}", nfoFile.getName());
            // Set the NFO as dirty so that the information will be re-scanned at the appropriate points.
            movie.setDirty(DirtyFlag.NFO);
            MovieNFOReader.readNfoFile(nfoFile, movie);
        }
    }

    /**
     * Search for the NFO file in the library structure
     *
     * @param movie The movie bean to locate the NFO for
     * @return A List structure of all the relevant NFO files
     */
    public static List<File> locateNFOs(Movie movie) {
        List<File> nfoFiles = new ArrayList<>();
        GenericFileFilter fFilter;

        File currentDir = movie.getFirstFile().getFile();

        if (currentDir == null) {
            return nfoFiles;
        }

        String baseFileName = currentDir.getName();
        String pathFileName = currentDir.getAbsolutePath();

        // Get the folder if it's a BluRay disk
        if (pathFileName.toUpperCase().contains(File.separator + "BDMV" + File.separator)) {
            currentDir = new File(FileTools.getParentFolder(currentDir));
            baseFileName = currentDir.getName();
            pathFileName = currentDir.getAbsolutePath();
        }

        if (ARCHIVE_SCAN_RAR && pathFileName.toLowerCase().contains(".rar")) {
            currentDir = new File(FileTools.getParentFolder(currentDir));
            baseFileName = currentDir.getName();
            pathFileName = currentDir.getAbsolutePath();
        }

        // If "pathFileName" is a file then strip the extension from the file.
        if (currentDir.isFile()) {
            pathFileName = FilenameUtils.removeExtension(pathFileName);
            baseFileName = FilenameUtils.removeExtension(baseFileName);
        } else {
            // *** First step is to check for VIDEO_TS
            // The movie is a directory, which indicates that this is a VIDEO_TS file
            // So, we should search for the file moviename.nfo in the sub-directory
            checkNFO(nfoFiles, pathFileName + pathFileName.substring(pathFileName.lastIndexOf(File.separator)));
        }

        // TV Show specific scanning
        if (movie.isTVShow()) {
            String nfoFilename;

            // Check for the "tvshow.nfo" filename in the parent directory
            if (movie.getFile().getParentFile().getParent() != null) {
                nfoFilename = StringTools.appendToPath(movie.getFile().getParentFile().getParent(),
                        XBMC_TV_NFO_NAME);
                checkNFO(nfoFiles, nfoFilename);
            }

            // Check for the "tvshow.nfo" filename in the current directory
            nfoFilename = StringTools.appendToPath(movie.getFile().getParent(), XBMC_TV_NFO_NAME);
            checkNFO(nfoFiles, nfoFilename);

            // Check for individual episode files
            if (!SKIP_TV_NFO_FILES) {
                for (MovieFile mf : movie.getMovieFiles()) {
                    nfoFilename = mf.getFile().getParent().toUpperCase();

                    if (nfoFilename.contains("BDMV")) {
                        nfoFilename = FileTools.getParentFolder(mf.getFile());
                        nfoFilename = nfoFilename.substring(nfoFilename.lastIndexOf(File.separator) + 1);
                    } else {
                        nfoFilename = FilenameUtils.removeExtension(mf.getFile().getName());
                    }

                    checkNFO(nfoFiles, StringTools.appendToPath(mf.getFile().getParent(), nfoFilename));
                }
            }
        }

        // *** Second step is to check for the filename.nfo file
        // This file should be named exactly the same as the video file with an extension of "nfo" or "NFO"
        // E.G. C:\Movies\Bladerunner.720p.avi => Bladerunner.720p.nfo
        checkNFO(nfoFiles, pathFileName);

        if (isValidString(NFO_DIR)) {
            // *** Next step if we still haven't found the nfo file is to
            // search the NFO directory as specified in the moviejukebox.properties file
            String sNFOPath = FileTools.getDirPathWithSeparator(movie.getLibraryPath()) + NFO_DIR;
            checkNFO(nfoFiles, sNFOPath + File.separator + baseFileName);
        }

        // *** Next step is to check for a directory wide NFO file.
        if (ACCEPT_ALL_NFO) {
            /*
             * If any NFO file in this directory will do, then we search for all we can find
             *
             * NOTE: for scanning efficiency, it is better to first search for specific filenames before we start doing
             * filtered "listfiles" which scans all the files;
             *
             * A movie collection with all moviefiles in one directory could take tremendously longer if for each
             * moviefile found, the entire directory must be listed!!
             *
             * Therefore, we first check for specific filenames (cfr. old behaviour) before doing an entire scan of the
             * directory -- and only if the user has decided to accept any NFO file!
             */

            // Check the current directory
            fFilter = new GenericFileFilter(NFO_EXT_REGEX);
            checkRNFO(nfoFiles, currentDir.getParentFile(), fFilter);

            // Also check the directory above, for the case where movies are in a multi-part named directory (CD/PART/DISK/Etc.)
            Matcher allNfoMatch = PART_PATTERN.matcher(currentDir.getAbsolutePath());
            if (allNfoMatch.find()) {
                LOG.debug("Found multi-part directory, checking parent directory for NFOs");
                checkRNFO(nfoFiles, currentDir.getParentFile().getParentFile(), fFilter);
            }
        } else {
            // This file should be named the same as the directory that it is in
            // E.G. C:\TV\Chuck\Season 1\Season 1.nfo
            // We search up through all containing directories up to the library root

            // Check the current directory for the video filename
            fFilter = new GenericFileFilter("(?i)" + movie.getBaseFilename() + NFO_EXT_REGEX);
            checkRNFO(nfoFiles, currentDir, fFilter);
        }

        // Recurse through the directories to the library root looking for NFO files
        String libraryRootPath = new File(movie.getLibraryPath()).getAbsolutePath();
        while (currentDir != null && !currentDir.getAbsolutePath().equals(libraryRootPath)) {
            //fFilter.setPattern("(?i)" + currentDir.getName() + nfoExtRegex);
            //checkRNFO(nfos, currentDir, fFilter);
            currentDir = currentDir.getParentFile();
            if (currentDir != null) {
                final String path = currentDir.getPath();
                // Path is not empty & is not the root
                if (!path.isEmpty() && !path.endsWith(File.separator)) {
                    checkNFO(nfoFiles, appendToPath(path, currentDir.getName()));
                }
            }
        }

        // we added the most specific ones first, and we want to parse those the last,
        // so nfo files in sub-directories can override values in directories above.
        Collections.reverse(nfoFiles);

        return nfoFiles;
    }

    /**
     * Search the current directory for all NFO files using a file filter
     *
     * @param nfoFiles
     * @param currentDir
     * @param fFilter
     */
    private static void checkRNFO(List<File> nfoFiles, File currentDir, GenericFileFilter fFilter) {
        File[] fFiles = currentDir.listFiles(fFilter);
        if (fFiles != null && fFiles.length > 0) {
            for (File foundFile : fFiles) {
                LOG.debug("Found {}", foundFile.getName());
                nfoFiles.add(foundFile);
            }
        }
    }

    /**
     * Check to see if the passed filename exists with nfo extensions
     *
     * @param checkNFOfilename (NO EXTENSION)
     * @return blank string if not found, filename if found
     */
    private static void checkNFO(List<File> nfoFiles, String checkNFOfilename) {
        File nfoFile;

        for (String ext : NFO_EXTENSIONS) {
            nfoFile = FileTools.fileCache.getFile(checkNFOfilename + "." + ext);
            if (nfoFile.exists()) {
                LOG.debug("Found {}", nfoFile.getAbsolutePath());
                nfoFiles.add(nfoFile);
            }
        }
    }
}