filebot/source/net/filebot/media/NamingStandard.java

169 lines
4.0 KiB
Java

package net.filebot.media;
import static java.util.Arrays.*;
import static java.util.stream.Collectors.*;
import static net.filebot.similarity.Normalization.*;
import static net.filebot.util.FileUtilities.*;
import java.util.Objects;
import net.filebot.web.AudioTrack;
import net.filebot.web.Episode;
import net.filebot.web.EpisodeFormat;
import net.filebot.web.Movie;
import net.filebot.web.MoviePart;
import net.filebot.web.MultiEpisode;
public class NamingStandard {
/**
* Plex Naming Standard (i.e. Default Implementation)
*
* https://support.plex.tv/articles/categories/media-preparation/
*/
public static final NamingStandard PLEX = new NamingStandard();
/**
* Kodi Naming Standard (i.e. same as Plex, but with SxE and non-range based multi-episode formatting)
*
* https://kodi.wiki/view/Naming_video_files
*/
public static final NamingStandard KODI = new NamingStandard() {
@Override
public String formatEpisodeNumbers(Episode e) {
if (e instanceof MultiEpisode) {
return EpisodeFormat.SeasonEpisode.formatMultiSxE((MultiEpisode) e);
}
return EpisodeFormat.SeasonEpisode.formatSxE(e);
}
};
public String getPath(Object o) {
if (o instanceof Episode)
return getPath((Episode) o);
if (o instanceof Movie)
return getPath((Movie) o);
if (o instanceof AudioTrack)
return getPath((AudioTrack) o);
return null;
}
public String getPath(Episode e) {
if (e.isAnime()) {
// Anime
return path(getAnimeFolder(), getSeriesFolder(e), getEpisodeName(e));
} else {
// TV Series
return path(getSeriesFolder(), getSeriesFolder(e), getSeasonFolder(e), getEpisodeName(e));
}
}
public String getPath(Movie m) {
// Movie
String name = m.getNameWithYear();
// Movie (multi-part)
if (m instanceof MoviePart) {
name = String.format("%s CD%d", name, ((MoviePart) m).getPartIndex());
}
return path(getMovieFolder(), m.getNameWithYear(), name);
}
public String getPath(AudioTrack a) {
// Music
String name = first(a.getTrackTitle(), a.getTitle());
// prepend track number
if (a.getTrack() != null) {
name = String.format("%02d - %s", a.getTrack(), name);
}
return path(getMusicFolder(), a.getArtist(), a.getAlbum(), name);
}
private static String path(String... name) {
return stream(name).filter(Objects::nonNull).map(s -> {
return replaceColon(s, ".", " - ");
}).map(s -> {
return replacePathSeparators(s, " ");
}).map(s -> {
return normalizeQuotationMarks(s);
}).map(s -> {
return trimTrailingPunctuation(s);
}).map(s -> {
return validateFileName(s);
}).filter(s -> s.length() > 0).collect(joining("/"));
}
private static String first(String... options) {
return stream(options).filter(Objects::nonNull).findFirst().get();
}
public String getMovieFolder() {
return "Movies";
}
public String getSeriesFolder() {
return "TV Shows";
}
public String getAnimeFolder() {
return "Anime";
}
public String getMusicFolder() {
return "Music";
}
public String getSeriesFolder(Episode e) {
return formatSeriesName(e);
}
public String getSeasonFolder(Episode e) {
if (e.getSpecial() != null) {
return "Specials";
}
if (e.getSeason() != null) {
return String.format("Season %02d", e.getSeason());
}
return null;
}
public String getEpisodeName(Episode e) {
return String.join(" - ", formatSeriesName(e), formatEpisodeNumbers(e), formatEpisodeTitle(e));
}
public String formatSeriesName(Episode e) {
if (e.isAnime()) {
// Anime
return e.getSeriesInfo().getName(); // series info name is the primary Anime name
} else {
// TV Series
return e.getSeriesName();
}
}
public String formatEpisodeNumbers(Episode e) {
if (e.isAnime()) {
// Anime
return EpisodeFormat.SeasonEpisode.formatSxE(e);
} else {
// TV Series
return EpisodeFormat.SeasonEpisode.formatS00E00(e);
}
}
public String formatEpisodeTitle(Episode e) {
// enforce title length limit by default
return truncateText(EpisodeFormat.SeasonEpisode.formatMultiTitle(e), TITLE_MAX_LENGTH);
}
public static final int TITLE_MAX_LENGTH = 150;
}