package moviescraper.doctord.controller;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import moviescraper.doctord.controller.siteparsingprofile.SiteParsingProfile;
import moviescraper.doctord.model.Movie;
import moviescraper.doctord.model.dataitem.Actor;
import moviescraper.doctord.model.dataitem.Genre;
import moviescraper.doctord.model.dataitem.Title;
import moviescraper.doctord.model.preferences.MoviescraperPreferences;
public class Renamer {
private String fileNameRenameString;
private String folderNameRenameString;
private Movie movie;
private Title originalTitle;
private String sanitizer;
private File oldFile;
private String extension;
private String filename;
private String path;
private static final int maxFileNameLength = 248;
private static final int extraFlexForFileNameLength = 25; //a folder can't be so long in name that it can't have a reasonable file inside it, so we're giving ourselves some extra flex
//file tags
private final static String ID = "<ID>";
private final static String TITLE = "<TITLE>";
private final static String ACTORS = "<ACTORS>";
private final static String YEAR = "<YEAR>";
private final static String RELEASEDATE = "<RELEASEDATE>";
private final static String ORIGINALTITLE = "<ORIGINALTITLE>";
private final static String SET = "<SET>";
private final static String STUDIO = "<STUDIO>";
private final static String GENRES = "<GENRES>";
private final static String period = ".";
private final static String[] availableRenameTags = {ID, TITLE, ACTORS, GENRES, SET, STUDIO, YEAR, RELEASEDATE, ORIGINALTITLE};
//folder tags
private final static String BASEDIRECTORY = "<BASEDIRECTORY>";
private final static String PATHSEPERATOR = "<PATHSEPERATOR>";
private final static String[] availableFolderRenameTags = {BASEDIRECTORY, PATHSEPERATOR, ID, TITLE, ACTORS, GENRES, SET, STUDIO, YEAR, RELEASEDATE, ORIGINALTITLE};
public Renamer(String fileNameRenameString, String folderNameRenameString, String sanitizer, Movie toRename, File oldFile) {
this.fileNameRenameString = fileNameRenameString;
this.folderNameRenameString = folderNameRenameString;
this.sanitizer = sanitizer;
this.movie = toRename;
this.originalTitle = movie.getTitle();
this.oldFile = oldFile;
}
/**
* Returns the new name given by the constructed renamer string used from the movie scraper preferences and arguments passed into the renamer object
* @param isFolderName - if true will remove the extension and enders such as -poster and -trailer from the filename. otherwise leaves them on
*/
public String getNewFileName(boolean isFolderName) {
extension = FilenameUtils.getExtension(oldFile.toString());
if(oldFile.isDirectory())
extension = "";
filename = FilenameUtils.getBaseName(oldFile.toString());
path = FilenameUtils.getFullPath(oldFile.toString());
path = getRenamedFolderPath(path);
String dot = ".";
if(oldFile.isDirectory())
dot = "";
String newName = getSanitizedString (replace(fileNameRenameString));
if(isFolderName)
{
newName = path + newName;
}
else
{
newName = path + newName + getAppendix() + getPosterFanartTrailerEnder() + dot + extension;
System.out.println("Was file, new name = " + newName);
}
//shorten the string if it still doesn't fit
while((newName.length() + extraFlexForFileNameLength) > maxFileNameLength)
{
//Cut the title down by one character and try again
System.out.println("Potential filename was too long. Cutting letters off title");
Title newTitle = new Title(movie.getTitle().getTitle().substring(0, movie.getTitle().getTitle().length()-1));
System.out.println("New truncated title is = " + newTitle.getTitle());
movie.setTitle(newTitle);
return getNewFileName(isFolderName);
}
//if we messed with the title above because it was too short, restore us back to our original title to get the file length in the movie object
movie.setTitle(originalTitle);
return newName;
}
private String getRenamedFolderPath(String path) {
//System.out.println("Old Path: " + path);
String newPath = replace(folderNameRenameString);
//Make sure we don't have any double path separators caused by things like an empty field.
//However, if this is a network share, it's OK for the path to start with \\, so we will add it back in later
String doublePathSeperator = File.separator + File.separator;
String cutPath = "";
if(newPath.startsWith(doublePathSeperator))
{
cutPath = doublePathSeperator;
newPath = newPath.substring(2,newPath.length());
}
while(newPath.contains(doublePathSeperator))
{
newPath = newPath.replace(doublePathSeperator, File.separator);
}
newPath = cutPath + newPath;
//System.out.println("New path: " + newPath);
return newPath;
}
private String replace(String target) {
String movieID = movie.getId().getId();
String movieTitle = movie.getTitle().getTitle();
List<Actor> movieActorsList = movie.getActors();
String movieActors = combineActorList(movieActorsList);
String movieYear = movie.getYear().getYear();
String movieReleaseDate = movie.getReleaseDate().getReleaseDate();
String movieOriginalTitle = movie.getOriginalTitle().getOriginalTitle();
String movieSet = movie.getSet().getSet();
String movieStudio = movie.getStudio().getStudio();
String movieGenres = combineGenreList(movie.getGenres());
String baseDirectory = oldFile.getParent();
String pathSeperator = File.separator;
String newName = target;
//path stuff
newName = renameReplaceAll(newName, BASEDIRECTORY, baseDirectory);
newName = renameReplaceAll(newName, PATHSEPERATOR, pathSeperator);
//metadata stuff
newName = renameReplaceAll(newName, ID, movieID);
newName = renameReplaceAll(newName, TITLE, movieTitle);
newName = renameReplaceAll(newName, YEAR, movieYear);
newName = renameReplaceAll(newName, RELEASEDATE, movieReleaseDate);
newName = renameReplaceAll(newName, ORIGINALTITLE, movieOriginalTitle);
newName = renameReplaceAll(newName, SET, movieSet);
newName = renameReplaceAll(newName, STUDIO, movieStudio);
newName = renameReplaceAll(newName, GENRES, movieGenres);
//we need to watch out when renaming a file that a large number of actors doesn't create
//a movie name that is too long
String potentialNameWithActors = renameReplaceAll(newName, ACTORS, movieActors);
if(potentialNameWithActors.length() + path.length() + getAppendix().length() + getPosterFanartTrailerEnder().length() + period.length() + extension.length() < maxFileNameLength )
newName = potentialNameWithActors;
else
newName = renameReplaceAll(newName, ACTORS, "");
return newName.trim();
}
private String renameReplaceAll(String replacementString, String tagName, String movieContentOfTag)
{
String replacedString = replacementString;
//Remove's stuff like <RELEASEDATE> when this field is null
if(movieContentOfTag == null)
{
replacedString = replacedString.replace(tagName, "");
}
if(replacedString.contains(tagName)){
replacedString = StringUtils.replace(replacedString, tagName, movieContentOfTag);
}
//Get rid of empty parens that are left over from blank field replacements like these : ()
if(movieContentOfTag == null || movieContentOfTag.trim().equals(""))
{
replacedString = replacedString.replaceAll("\\[\\]|\\(\\)", "");
}
return replacedString;
}
private String combineActorList(List<Actor> actors) {
String actorsString = "";
for (int i = 0; i < movie.getActors().size(); i++) {
actorsString += movie.getActors().get(i).getName();
if (i + 1 < movie.getActors().size())
actorsString += ", ";
}
return actorsString;
}
public static void rename(File fileToRename, MoviescraperPreferences preferences) throws IOException
{
File nfoFile = new File(Movie.getFileNameOfNfo(fileToRename, preferences.getNfoNamedMovieDotNfo()));
File posterFile = new File(Movie.getFileNameOfPoster(fileToRename, preferences.getNoMovieNameInImageFiles()));
File fanartFile = new File(Movie.getFileNameOfFanart(fileToRename, preferences.getNoMovieNameInImageFiles()));
File trailerFile = new File(Movie.getFileNameOfTrailer(fileToRename));
if(nfoFile.exists() && fileToRename.exists())
{
Movie movieReadFromNfo = Movie.createMovieFromNfo(nfoFile);
if(movieReadFromNfo != null && movieReadFromNfo.getTitle() != null)
{
Renamer renamer = new Renamer(MoviescraperPreferences.getRenamerString(), MoviescraperPreferences.getRenamerString(), MoviescraperPreferences.getSanitizerForFilename(), movieReadFromNfo, fileToRename);
//Figure out all the new names
File newMovieFilename = new File(renamer.getNewFileName(fileToRename.isDirectory()));
renamer.setOldFilename(nfoFile);
File newNfoFilename = new File(renamer.getNewFileName(false));
renamer.setOldFilename(posterFile);
File newPosterFilename = new File(renamer.getNewFileName(false));
renamer.setOldFilename(fanartFile);
File newFanartFilename = new File(renamer.getNewFileName(false));
renamer.setOldFilename(trailerFile);
File newTrailerFilename = new File(renamer.getNewFileName(false));
//Do All the Renames
if(fileToRename.exists())
{
System.out.println("Renaming " + fileToRename.getPath() + " to " + newMovieFilename);
fileToRename.renameTo(newMovieFilename);
}
if(nfoFile.exists())
{
System.out.println("Renaming " + nfoFile.getPath() + " to " + newNfoFilename);
FileUtils.moveFile(nfoFile, newNfoFilename);
}
if(posterFile.exists())
{
System.out.println("Renaming " + posterFile.getPath() + " to " + newPosterFilename);
FileUtils.moveFile(posterFile, newPosterFilename);
}
if(fanartFile.exists())
{
System.out.println("Renaming " + fanartFile.getPath() + " to " + newFanartFilename);
FileUtils.moveFile(fanartFile, newFanartFilename);
}
if(trailerFile.exists())
{
System.out.println("Renaming " + trailerFile.getPath() + " to " + newTrailerFilename);
FileUtils.moveFile(trailerFile, newTrailerFilename);
}
//In case of stacked movie files (Movies which are split into multiple files such AS CD1, CD2, etc) get the list of all files
//which are part of this movie's stack
File currentDirectory = fileToRename.getParentFile();
String currentlySelectedMovieFileWihoutStackSuffix = SiteParsingProfile.stripDiscNumber(FilenameUtils.removeExtension(fileToRename.getName()));
if(currentDirectory != null)
{
for(File currentFile : currentDirectory.listFiles())
{
String currentFileNameWithoutStackSuffix = SiteParsingProfile.stripDiscNumber(FilenameUtils.removeExtension(currentFile.getName()));
if(currentFile.isFile() && currentFileNameWithoutStackSuffix.equals(currentlySelectedMovieFileWihoutStackSuffix))
{
renamer.setOldFilename(currentFile);
File newStackedFilename = new File(renamer.getNewFileName(false));
System.out.println("Renaming " + currentFile.getPath() + " to " + newStackedFilename);
FileUtils.moveFile(currentFile, newStackedFilename);
}
}
}
}
}
else if(!nfoFile.exists())
{
System.err.println("No scraped nfo file found for: " + fileToRename + " - skipping rename.");
}
}
private String combineGenreList(List<Genre> genres) {
String genresString = "";
for (int i = 0; i < movie.getGenres().size(); i++) {
genresString += movie.getGenres().get(i).getGenre();
if (i + 1 < movie.getGenres().size())
genresString += ", ";
}
return genresString;
}
private String getAppendix() {
//TODO: make this method more flexible to check all the possible types of disc names
//(I already have a method somewhere else in this project which has a good regular expression to use)
String appendix = "";
boolean hasAppendix = filename.matches(".*CD\\s?1.*");
if (hasAppendix)
appendix = " CD1";
hasAppendix = filename.matches(".*CD\\s?2.*");
if (hasAppendix)
appendix = " CD2";
hasAppendix = filename.matches(".*CD\\s?3.*");
if (hasAppendix)
appendix = " CD3";
hasAppendix = filename.matches(".*CD\\s?4.*");
if (hasAppendix)
appendix = " CD4";
hasAppendix = filename.matches(".*CD\\s?5.*");
if (hasAppendix)
appendix = " CD5";
hasAppendix = filename.matches(".*CD\\s?6.*");
if (hasAppendix)
appendix = " CD6";
hasAppendix = filename.matches(".*CD\\s?7.*");
if (hasAppendix)
appendix = " CD7";
hasAppendix = filename.matches(".*CD\\s?8.*");
if (hasAppendix)
appendix = " CD8";
hasAppendix = filename.matches(".*CD\\s?9.*");
if (hasAppendix)
appendix = " CD9";
hasAppendix = filename.matches(".*CD\\s?10.*");
if (hasAppendix)
appendix = " CD10";
hasAppendix = filename.matches(".*CD\\s?11.*");
if (hasAppendix)
appendix = " CD11";
hasAppendix = filename.matches(".*CD\\s?12.*");
if (hasAppendix)
appendix = " CD12";
hasAppendix = filename.matches(".*CD\\s?13.*");
if (hasAppendix)
appendix = " CD13";
hasAppendix = filename.matches(".*CD\\s?14.*");
if (hasAppendix)
appendix = " CD14";
return appendix;
}
private String getPosterFanartTrailerEnder(){
String fileNameEnder = "";
boolean hasFileNameEnder = oldFile.getPath().matches(".*-poster[\\.].+");
if (hasFileNameEnder)
fileNameEnder = "-poster";
hasFileNameEnder = oldFile.getPath().matches(".*-trailer[\\.].+");
if (hasFileNameEnder)
fileNameEnder = "-trailer";
hasFileNameEnder = oldFile.getPath().matches(".*-fanart[\\.].+");
if (hasFileNameEnder)
fileNameEnder = "-fanart";
return fileNameEnder;
}
private String getSanitizedString(String fileName) {
final Pattern ILLEGAL_CHARACTERS = Pattern.compile(sanitizer);
fileName = ILLEGAL_CHARACTERS.matcher(fileName).replaceAll("").replaceAll("\\s+", " ").trim();
return fileName;
}
public static String getAvailableFileTags()
{
String tags = "";
for (String tag : availableRenameTags)
{
tags= tags + " " + tag;
}
return tags.trim();
}
public static String getAvailableFolderTags()
{
String tags = "";
for (String tag : availableFolderRenameTags)
{
tags= tags + " " + tag;
}
return tags.trim();
}
public String getOldFilename() {
return filename;
}
public void setOldFilename(File oldFile) {
this.oldFile = oldFile;
}
}