New binding: {plex} => built-in Plex format defaults for Episode/Movie/Music objects

This commit is contained in:
Reinhard Pointner 2016-03-28 01:32:12 +00:00
parent 963fb62172
commit 36a02ff457
7 changed files with 123 additions and 2 deletions

View File

@ -45,6 +45,7 @@ import net.filebot.Settings;
import net.filebot.Settings.ApplicationFolder;
import net.filebot.WebServices;
import net.filebot.hash.HashType;
import net.filebot.media.NamingStandard;
import net.filebot.mediainfo.MediaInfo;
import net.filebot.mediainfo.MediaInfo.StreamKind;
import net.filebot.mediainfo.MediaInfoException;
@ -914,6 +915,17 @@ public class MediaBindingBean {
return 1 + identityIndexOf(duplicates, getInfoObject());
}
@Define("plex")
public File getPlexStandardPath() throws Exception {
String path = NamingStandard.Plex.getPath(infoObject);
try {
path = path.concat(getSubtitleTags());
} catch (Exception e) {
// ignore => no language tags
}
return new File(path);
}
@Define("self")
public AssociativeScriptObject getSelf() {
return createBindingObject(mediaFile, infoObject, context);

View File

@ -0,0 +1,93 @@
package net.filebot.media;
import static java.util.Arrays.*;
import static java.util.stream.Collectors.*;
import static net.filebot.WebServices.*;
import static net.filebot.similarity.Normalization.*;
import static net.filebot.util.FileUtilities.*;
import static net.filebot.web.EpisodeFormat.*;
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 enum NamingStandard {
Plex;
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) {
// enforce title length limit by default
String episodeTitle = truncateText(e instanceof MultiEpisode ? SeasonEpisode.formatMultiTitle(((MultiEpisode) e).getEpisodes()) : e.getTitle(), 150);
// Anime
if (isAnime(e)) {
String primaryTitle = e.getSeriesInfo().getName();
String episode = String.join(" - ", primaryTitle, EpisodeFormat.SeasonEpisode.formatSxE(e), episodeTitle);
return path("Anime", primaryTitle, episode);
}
// TV Series
String episode = String.join(" - ", e.getSeriesName(), EpisodeFormat.SeasonEpisode.formatS00E00(e), episodeTitle);
String season = e.getSeason() == null ? null : e.getSpecial() == null ? String.format("Season %02d", e.getSeason()) : "Special";
return path("TV Shows", e.getSeriesName(), season, episode);
}
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("Movies", m.getNameWithYear(), name);
}
public String getPath(AudioTrack a) {
// Music
String name = String.join(" - ", a.getArtist(), first(a.getTrackTitle(), a.getTitle()));
// prepend track number
if (a.getTrack() != null) {
name = String.format("%02d. %s", a.getTrack(), name);
}
return path("Music", first(a.getAlbumArtist(), a.getArtist()), a.getAlbum(), name);
}
private static String path(String... name) {
return stream(name).filter(Objects::nonNull).map(s -> {
s = replacePathSeparators(s, " ");
s = replaceSpace(s, " ");
s = normalizeQuotationMarks(s);
s = trimTrailingPunctuation(s);
return s;
}).collect(joining("/"));
}
private static String first(String... options) {
return stream(options).filter(Objects::nonNull).findFirst().get();
}
private static boolean isAnime(Episode e) {
return AniDB.getIdentifier().equals(e.getSeriesInfo().getDatabase());
}
}

View File

@ -14,6 +14,7 @@ public class Normalization {
private static final Pattern[] brackets = new Pattern[] { compile("\\([^\\(]*\\)"), compile("\\[[^\\[]*\\]"), compile("\\{[^\\{]*\\}") };
private static final Pattern trailingParentheses = compile("(?<!^)[(]([^)]*)[)]$");
private static final Pattern trailingPunctuation = compile("[!?.]+$");
private static final Pattern checksum = compile("[\\(\\[]\\p{XDigit}{8}[\\]\\)]");
@ -29,6 +30,10 @@ public class Normalization {
return name;
}
public static String trimTrailingPunctuation(String name) {
return trailingPunctuation.matcher(name).replaceAll("").trim();
}
public static String normalizePunctuation(String name) {
// remove/normalize special characters
name = apostrophe.matcher(name).replaceAll("");

View File

@ -2,4 +2,4 @@
parameter.exclude: ^StreamKind|^UniqueID|^StreamOrder|^ID|Count$
# preview expressions (keys are tagged so they can be sorted alphabetically)
expressions: n,y,s,e,es,sxe,s00e00,t,d,startdate,absolute,special,episode,series,primaryTitle,alias,movie,tmdbid,imdbid,pi,pn,lang,subt,az,music,album,artist,albumArtist,actors,director,collection,genre,genres,languages,certification,rating,vc,ac,cf,vf,hpi,af,channels,resolution,dim,ws,sdhd,source,tags,s3d,group,original,fn,ext,mediaType,file,file.name,folder,folder.name,gigabytes,crc32,info,info.runtime,info.status,omdb.rating,omdb.votes,localize.German.title,age,duration,seconds,minutes,media,media.title,media.overallBitRateString,video,video.codecID,video.frameRate,video.displayAspectRatioString,video.scanType,audio,audio.bitRateString,audio.language,audios,audios.language,text,text.codecInfo,text.language,texts,texts.language
expressions: n,y,s,e,es,sxe,s00e00,t,d,startdate,absolute,special,episode,series,primaryTitle,alias,movie,tmdbid,imdbid,pi,pn,lang,subt,plex,az,music,album,artist,albumArtist,actors,director,collection,genre,genres,languages,certification,rating,vc,ac,cf,vf,hpi,af,channels,resolution,dim,ws,sdhd,source,tags,s3d,group,original,fn,ext,mediaType,file,file.name,folder,folder.name,gigabytes,crc32,info,info.runtime,info.status,omdb.rating,omdb.votes,localize.German.title,age,duration,seconds,minutes,media,media.title,media.overallBitRateString,video,video.codecID,video.frameRate,video.displayAspectRatioString,video.scanType,audio,audio.bitRateString,audio.language,audios,audios.language,text,text.codecInfo,text.language,texts,texts.language

View File

@ -270,7 +270,7 @@ public class FormatDialog extends JDialog {
// initialize window properties
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
setMinimumSize(new Dimension(650, 470));
setMinimumSize(new Dimension(650, 500));
// initialize data
setState(initMode, lockOnBinding != null ? lockOnBinding : restoreSample(initMode), lockOnBinding != null);

View File

@ -19,6 +19,8 @@ episode.example[2]: {n} [{airdate}] {t}
episode.example[3]: {n.space('.').lower()}.{s}{e.pad(2)}
# organize folder structure
episode.example[4]: {n}/{'Season '+s}/{n} - {s00e00} - {t}
# plex standard
episode.example[5]: {home}/Media/{plex}
# simple name/year
movie.example[0]: {n} ({y}){' CD'+pi}{subt}
@ -30,6 +32,8 @@ movie.example[2]: {n} {[y, certification, rating]}
movie.example[3]: {n.space('.')}.{y}{'.'+source}.{vc}
# organize folder structure
movie.example[4]: {n} ({y})/{n} ({y}){' CD'+pi}
# plex standard
movie.example[5]: {home}/Media/{plex}
# simple artist - title
music.example[0]: {artist} - {t}
@ -41,6 +45,8 @@ music.example[2]: {n} - {t} {[audio.SamplingRateString]}
music.example[3]: {pi.pad(2)} {n} - {t} {[af, audio.BitRate]}
# organize folder structure
music.example[4]: {n}/{album+'/'}{pi.pad(2)+'. '} {t}
# plex standard
music.example[5]: {home}/Media/{plex}
# simple filename without extension
file.example[0]: {i.pad(3)} - {fn}

View File

@ -188,6 +188,11 @@
<td>season / episode numbers</td>
<td>S01E01</td>
</tr>
<tr>
<td>plex</td>
<td><a href="https://support.plex.tv/hc/en-us/sections/200059498-Naming-and-Organizing-TV-Shows" target="_blank">Plex Naming Standard</a></td>
<td>&lt;path&gt;</td>
</tr>
<tr>
<td>imdbid</td>
<td>imdb id</td>