2014-04-19 02:30:29 -04:00
package net.filebot.format ;
2009-04-04 15:36:12 -04:00
2013-09-11 13:22:00 -04:00
import static java.util.Arrays.* ;
2014-07-29 05:08:35 -04:00
import static java.util.Collections.* ;
2016-02-05 05:49:39 -05:00
import static java.util.stream.Collectors.* ;
2016-04-22 04:05:42 -04:00
import static net.filebot.Logging.* ;
2014-04-19 02:30:29 -04:00
import static net.filebot.MediaTypes.* ;
2016-10-30 14:06:15 -04:00
import static net.filebot.WebServices.* ;
2014-04-19 02:30:29 -04:00
import static net.filebot.format.Define.* ;
2014-06-29 07:04:04 -04:00
import static net.filebot.format.ExpressionFormatMethods.* ;
2014-04-19 02:30:29 -04:00
import static net.filebot.hash.VerificationUtilities.* ;
import static net.filebot.media.MediaDetection.* ;
2016-03-27 12:56:54 -04:00
import static net.filebot.media.XattrMetaInfo.* ;
2014-04-19 02:30:29 -04:00
import static net.filebot.similarity.Normalization.* ;
2016-01-31 11:13:04 -05:00
import static net.filebot.subtitle.SubtitleUtilities.* ;
2014-04-19 02:30:29 -04:00
import static net.filebot.util.FileUtilities.* ;
2016-04-02 05:07:10 -04:00
import static net.filebot.util.RegularExpressions.* ;
2014-04-19 02:30:29 -04:00
import static net.filebot.util.StringUtilities.* ;
2016-05-22 08:50:32 -04:00
import static net.filebot.web.EpisodeUtilities.* ;
2009-04-04 15:36:12 -04:00
import java.io.File ;
import java.io.IOException ;
2016-01-26 13:41:47 -05:00
import java.math.BigDecimal ;
2016-04-07 03:36:51 -04:00
import java.math.RoundingMode ;
2016-12-27 01:23:24 -05:00
import java.time.Instant ;
2016-08-09 12:34:35 -04:00
import java.time.LocalDateTime ;
2016-12-27 01:04:01 -05:00
import java.time.ZoneOffset ;
2016-08-09 11:46:03 -04:00
import java.time.ZonedDateTime ;
import java.time.format.DateTimeFormatter ;
2016-08-09 12:34:35 -04:00
import java.time.temporal.ChronoUnit ;
2012-12-04 04:24:15 -05:00
import java.util.ArrayList ;
2013-02-07 07:25:46 -05:00
import java.util.Iterator ;
2012-03-17 15:02:04 -04:00
import java.util.List ;
2011-11-21 07:24:51 -05:00
import java.util.Locale ;
2012-07-07 23:09:42 -04:00
import java.util.Map ;
2013-01-27 03:17:12 -05:00
import java.util.Map.Entry ;
2014-09-03 00:16:50 -04:00
import java.util.Objects ;
2016-05-29 11:24:54 -04:00
import java.util.Optional ;
2014-01-02 10:49:20 -05:00
import java.util.regex.Pattern ;
2016-10-28 13:16:50 -04:00
import java.util.stream.IntStream ;
import java.util.stream.Stream ;
2009-04-04 15:36:12 -04:00
2016-08-04 03:05:54 -04:00
import net.filebot.ApplicationFolder ;
2016-03-06 13:11:30 -05:00
import net.filebot.Cache ;
import net.filebot.CacheType ;
2014-04-19 02:30:29 -04:00
import net.filebot.Language ;
import net.filebot.MediaTypes ;
2014-11-12 04:56:26 -05:00
import net.filebot.MetaAttributeView ;
2016-10-30 14:18:00 -04:00
import net.filebot.Resource ;
2014-04-19 02:30:29 -04:00
import net.filebot.Settings ;
import net.filebot.hash.HashType ;
2016-10-08 15:55:45 -04:00
import net.filebot.media.MetaAttributes ;
2016-03-27 21:32:12 -04:00
import net.filebot.media.NamingStandard ;
2014-04-19 02:30:29 -04:00
import net.filebot.mediainfo.MediaInfo ;
import net.filebot.mediainfo.MediaInfo.StreamKind ;
2016-03-11 03:16:59 -05:00
import net.filebot.mediainfo.MediaInfoException ;
2016-05-29 11:24:54 -04:00
import net.filebot.similarity.Normalization ;
2014-04-19 02:30:29 -04:00
import net.filebot.similarity.SimilarityComparator ;
import net.filebot.util.FileUtilities ;
2015-11-14 13:24:31 -05:00
import net.filebot.util.WeakValueHashMap ;
2014-04-19 02:30:29 -04:00
import net.filebot.web.AudioTrack ;
import net.filebot.web.Episode ;
2016-05-22 08:50:32 -04:00
import net.filebot.web.EpisodeFormat ;
2014-04-19 02:30:29 -04:00
import net.filebot.web.Movie ;
2017-02-08 10:17:05 -05:00
import net.filebot.web.MovieInfo ;
2014-04-19 02:30:29 -04:00
import net.filebot.web.MoviePart ;
2016-08-23 00:58:27 -04:00
import net.filebot.web.MultiEpisode ;
2014-12-10 13:53:58 -05:00
import net.filebot.web.SeriesInfo ;
2014-04-28 22:15:22 -04:00
import net.filebot.web.SimpleDate ;
2014-12-10 13:53:58 -05:00
import net.filebot.web.SortOrder ;
2014-12-10 15:19:38 -05:00
import net.filebot.web.TheTVDBSeriesInfo ;
2009-04-04 15:36:12 -04:00
2011-09-18 15:08:03 -04:00
public class MediaBindingBean {
2013-09-06 03:55:13 -04:00
2011-09-18 15:08:03 -04:00
private final Object infoObject ;
2009-04-04 15:36:12 -04:00
private final File mediaFile ;
2016-03-20 14:33:31 -04:00
private final Map < File , ? > context ;
2013-09-06 03:55:13 -04:00
2009-04-04 15:36:12 -04:00
private MediaInfo mediaInfo ;
2013-09-06 03:55:13 -04:00
2014-08-22 12:36:12 -04:00
public MediaBindingBean ( Object infoObject , File mediaFile ) {
2016-12-04 11:44:51 -05:00
this ( infoObject , mediaFile , null ) ;
2014-08-22 12:36:12 -04:00
}
2016-03-20 14:33:31 -04:00
public MediaBindingBean ( Object infoObject , File mediaFile , Map < File , ? > context ) {
2011-09-18 15:08:03 -04:00
this . infoObject = infoObject ;
2009-04-04 15:36:12 -04:00
this . mediaFile = mediaFile ;
2013-01-27 03:17:12 -05:00
this . context = context ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2016-05-18 08:44:42 -04:00
@Define ( " object " )
2015-11-29 04:28:54 -05:00
public Object getInfoObject ( ) {
return infoObject ;
}
2016-07-27 11:31:45 -04:00
@Define ( " file " )
2015-11-29 04:28:54 -05:00
public File getFileObject ( ) {
return mediaFile ;
}
2009-04-04 15:36:12 -04:00
@Define ( undefined )
2014-08-09 03:24:01 -04:00
public < T > T undefined ( String name ) {
2009-04-04 15:36:12 -04:00
// omit expressions that depend on undefined values
2015-11-30 01:47:35 -05:00
throw new BindingException ( name , EXCEPTION_UNDEFINED ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2009-04-04 15:36:12 -04:00
@Define ( " n " )
2011-09-18 15:08:03 -04:00
public String getName ( ) {
if ( infoObject instanceof Episode )
return getEpisode ( ) . getSeriesName ( ) ;
2016-02-10 09:31:56 -05:00
else if ( infoObject instanceof Movie )
2011-09-18 15:08:03 -04:00
return getMovie ( ) . getName ( ) ;
2016-02-10 09:31:56 -05:00
else if ( infoObject instanceof AudioTrack )
2016-11-14 05:13:36 -05:00
return getAlbumArtist ( ) ! = null ? getAlbumArtist ( ) : getArtist ( ) ;
2016-02-10 09:31:56 -05:00
else if ( infoObject instanceof File )
2015-07-26 07:46:52 -04:00
return FileUtilities . getName ( ( File ) infoObject ) ;
2013-09-06 03:55:13 -04:00
2015-07-26 07:46:52 -04:00
return null ;
2011-09-18 15:08:03 -04:00
}
2013-09-06 03:55:13 -04:00
2011-09-18 15:08:03 -04:00
@Define ( " y " )
public Integer getYear ( ) {
if ( infoObject instanceof Episode )
2014-12-10 13:53:58 -05:00
return getEpisode ( ) . getSeriesInfo ( ) . getStartDate ( ) . getYear ( ) ;
2011-09-22 08:55:04 -04:00
if ( infoObject instanceof Movie )
2011-09-18 15:08:03 -04:00
return getMovie ( ) . getYear ( ) ;
2013-01-12 10:21:33 -05:00
if ( infoObject instanceof AudioTrack )
2016-10-30 14:06:15 -04:00
return getMusic ( ) . getAlbumReleaseDate ( ) . getYear ( ) ;
2013-09-06 03:55:13 -04:00
2011-09-18 15:08:03 -04:00
return null ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2015-11-05 00:14:07 -05:00
@Define ( " ny " )
public String getNameWithYear ( ) {
String n = getName ( ) . toString ( ) ;
String y = " ( " + getYear ( ) . toString ( ) + " ) " ;
2016-10-30 14:06:15 -04:00
// account for TV Shows that contain the year in the series name, e.g. Doctor Who (2005)
return n . endsWith ( y ) ? n : n + y ;
2015-11-05 00:14:07 -05:00
}
2009-04-04 15:36:12 -04:00
@Define ( " s " )
2010-10-24 08:10:30 -04:00
public Integer getSeasonNumber ( ) {
2016-08-21 21:02:43 -04:00
// look up season numbers via TheTVDB for AniDB episode data
if ( isAnime ( getEpisode ( ) ) ) {
return getSeasonEpisode ( ) . getSeason ( ) ;
}
2011-09-18 15:08:03 -04:00
return getEpisode ( ) . getSeason ( ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2009-04-04 15:36:12 -04:00
@Define ( " e " )
2010-10-24 08:10:30 -04:00
public Integer getEpisodeNumber ( ) {
2011-09-18 15:08:03 -04:00
return getEpisode ( ) . getEpisode ( ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2012-12-04 04:24:15 -05:00
@Define ( " es " )
public List < Integer > getEpisodeNumbers ( ) {
2016-04-30 04:20:28 -04:00
return getEpisodes ( ) . stream ( ) . map ( it - > {
2016-10-14 14:10:47 -04:00
return it . getEpisode ( ) = = null ? it . getSpecial ( ) = = null ? null : it . getSpecial ( ) : it . getEpisode ( ) ;
} ) . filter ( Objects : : nonNull ) . collect ( toList ( ) ) ;
}
@Define ( " e00 " )
public String getE00 ( ) {
2016-10-14 14:16:39 -04:00
if ( isRegularEpisode ( ) )
return getEpisodeNumbers ( ) . stream ( ) . map ( i - > String . format ( " %02d " , i ) ) . collect ( joining ( " - " ) ) ;
else
return " Special " + join ( getEpisodeNumbers ( ) , " - " ) ;
2012-12-04 04:24:15 -05:00
}
2013-09-06 03:55:13 -04:00
2011-11-27 12:04:32 -05:00
@Define ( " sxe " )
2011-11-20 13:38:49 -05:00
public String getSxE ( ) {
2016-05-22 08:50:32 -04:00
return EpisodeFormat . SeasonEpisode . formatSxE ( getSeasonEpisode ( ) ) ; // try to convert absolute numbers to SxE numbers
2011-11-20 13:38:49 -05:00
}
2013-09-06 03:55:13 -04:00
2011-11-27 12:04:32 -05:00
@Define ( " s00e00 " )
2011-11-20 13:38:49 -05:00
public String getS00E00 ( ) {
2016-05-22 08:50:32 -04:00
return EpisodeFormat . SeasonEpisode . formatS00E00 ( getSeasonEpisode ( ) ) ; // try to convert absolute numbers to SxE numbers
2011-11-20 13:38:49 -05:00
}
2013-09-06 03:55:13 -04:00
2009-04-04 15:36:12 -04:00
@Define ( " t " )
public String getTitle ( ) {
2016-11-13 06:12:30 -05:00
String t = null ;
2016-08-23 00:58:27 -04:00
2016-11-13 06:12:30 -05:00
if ( infoObject instanceof Episode ) {
t = infoObject instanceof MultiEpisode ? EpisodeFormat . SeasonEpisode . formatMultiTitle ( getEpisodes ( ) ) : getEpisode ( ) . getTitle ( ) ; // implicit support for multi-episode title formatting
} else if ( infoObject instanceof Movie ) {
t = getMovieInfo ( ) . getTagline ( ) ;
} else if ( infoObject instanceof AudioTrack ) {
t = getMusic ( ) . getTrackTitle ( ) ! = null ? getMusic ( ) . getTrackTitle ( ) : getMusic ( ) . getTitle ( ) ;
2016-08-23 01:07:43 -04:00
}
2016-11-13 06:12:30 -05:00
// enforce title length limit by default
return truncateText ( t , NamingStandard . TITLE_MAX_LENGTH ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2012-11-03 21:17:58 -04:00
@Define ( " d " )
2016-11-13 06:12:30 -05:00
public SimpleDate getReleaseDate ( ) {
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Episode )
2013-07-13 06:01:33 -04:00
return getEpisode ( ) . getAirdate ( ) ;
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Movie )
return getMovieInfo ( ) . getReleased ( ) ;
if ( infoObject instanceof AudioTrack )
2013-01-23 13:15:53 -05:00
return getMusic ( ) . getAlbumReleaseDate ( ) ;
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof File )
2015-07-25 18:47:00 -04:00
return new SimpleDate ( getCreationDate ( ( ( File ) infoObject ) ) ) ;
2013-09-06 03:55:13 -04:00
2012-11-03 21:17:58 -04:00
return null ;
}
2013-09-06 03:55:13 -04:00
2010-11-09 03:04:12 -05:00
@Define ( " airdate " )
2016-05-09 02:56:09 -04:00
public SimpleDate getAirdate ( ) {
2013-07-13 06:01:33 -04:00
return getEpisode ( ) . getAirdate ( ) ;
2010-10-23 08:47:43 -04:00
}
2013-09-06 03:55:13 -04:00
2014-05-12 11:45:19 -04:00
@Define ( " age " )
2016-10-30 14:06:15 -04:00
public Long getAgeInDays ( ) throws Exception {
2014-10-25 05:44:33 -04:00
SimpleDate releaseDate = getReleaseDate ( ) ;
2016-10-30 14:06:15 -04:00
2014-10-25 05:44:33 -04:00
if ( releaseDate ! = null ) {
2016-12-27 01:04:01 -05:00
// avoid time zone issues by interpreting all dates and times as UTC
2016-12-27 01:23:24 -05:00
long days = ChronoUnit . DAYS . between ( releaseDate . toLocalDate ( ) . atStartOfDay ( ZoneOffset . UTC ) . toInstant ( ) , Instant . now ( ) ) ;
2016-12-27 01:04:01 -05:00
2015-05-28 12:39:57 -04:00
if ( days > = 0 ) {
return days ;
}
2014-10-25 05:44:33 -04:00
}
2016-10-30 14:06:15 -04:00
2014-10-25 05:44:33 -04:00
return null ;
2014-05-12 11:45:19 -04:00
}
2011-10-01 00:08:46 -04:00
@Define ( " startdate " )
2016-05-09 02:56:09 -04:00
public SimpleDate getStartDate ( ) {
2014-12-10 13:53:58 -05:00
return getEpisode ( ) . getSeriesInfo ( ) . getStartDate ( ) ;
2011-10-01 00:08:46 -04:00
}
2013-09-06 03:55:13 -04:00
2010-11-09 03:04:12 -05:00
@Define ( " absolute " )
public Integer getAbsoluteEpisodeNumber ( ) {
2011-09-18 15:08:03 -04:00
return getEpisode ( ) . getAbsolute ( ) ;
2010-11-09 03:04:12 -05:00
}
2013-09-06 03:55:13 -04:00
2010-11-09 03:04:12 -05:00
@Define ( " special " )
public Integer getSpecialNumber ( ) {
2011-09-18 15:08:03 -04:00
return getEpisode ( ) . getSpecial ( ) ;
}
2013-09-06 03:55:13 -04:00
2013-07-13 06:01:33 -04:00
@Define ( " series " )
2014-12-10 13:53:58 -05:00
public SeriesInfo getSeriesInfo ( ) {
return getEpisode ( ) . getSeriesInfo ( ) ;
2013-07-13 06:01:33 -04:00
}
2013-09-06 03:55:13 -04:00
@Define ( " alias " )
public List < String > getAliasNames ( ) {
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Movie )
2013-09-06 03:55:13 -04:00
return asList ( getMovie ( ) . getAliasNames ( ) ) ;
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Episode )
2014-12-10 13:53:58 -05:00
return getSeriesInfo ( ) . getAliasNames ( ) ;
2016-10-30 14:06:15 -04:00
return null ;
2013-09-06 03:55:13 -04:00
}
2013-07-13 06:01:33 -04:00
@Define ( " primaryTitle " )
2016-11-13 06:12:30 -05:00
public String getPrimaryTitle ( ) {
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Movie )
return getPrimaryMovieInfo ( ) . getOriginalName ( ) ;
if ( infoObject instanceof Episode )
return getPrimarySeriesInfo ( ) . getName ( ) ; // force English series name for TheTVDB data or default to SeriesInfo name (for AniDB episode data this would be the primary title)
2013-09-06 03:55:13 -04:00
return null ;
2013-07-13 06:01:33 -04:00
}
2013-09-06 03:55:13 -04:00
2016-06-04 00:46:17 -04:00
@Define ( " id " )
2016-10-04 14:11:18 -04:00
public Object getId ( ) throws Exception {
2016-06-04 00:46:17 -04:00
if ( infoObject instanceof Episode )
return getEpisode ( ) . getSeriesInfo ( ) . getId ( ) ;
if ( infoObject instanceof Movie )
return getMovie ( ) . getId ( ) ;
2016-10-04 14:11:18 -04:00
if ( infoObject instanceof AudioTrack )
return getMusic ( ) . getMBID ( ) ;
2016-06-04 00:46:17 -04:00
return null ;
}
2012-12-29 12:41:07 -05:00
@Define ( " tmdbid " )
2016-11-13 06:12:30 -05:00
public String getTmdbId ( ) {
2016-10-30 14:06:15 -04:00
if ( getMovie ( ) . getTmdbId ( ) > 0 )
return String . valueOf ( getMovie ( ) . getTmdbId ( ) ) ;
if ( getMovie ( ) . getImdbId ( ) > 0 )
return getPrimaryMovieInfo ( ) . getId ( ) . toString ( ) ; // lookup IMDbID for TMDbID
2013-09-06 03:55:13 -04:00
2016-10-30 14:06:15 -04:00
return null ;
2012-12-29 12:41:07 -05:00
}
2013-09-06 03:55:13 -04:00
2012-07-22 07:54:49 -04:00
@Define ( " imdbid " )
2016-11-13 06:12:30 -05:00
public String getImdbId ( ) {
2016-10-30 14:06:15 -04:00
if ( getMovie ( ) . getImdbId ( ) > 0 )
return String . format ( " tt%07d " , getMovie ( ) . getImdbId ( ) ) ;
if ( getMovie ( ) . getTmdbId ( ) > 0 )
return String . format ( " tt%07d " , getPrimaryMovieInfo ( ) . getImdbId ( ) ) ; // lookup IMDbID for TMDbID
2013-09-06 03:55:13 -04:00
2016-10-30 14:06:15 -04:00
return null ;
2010-11-09 03:04:12 -05:00
}
2013-09-06 03:55:13 -04:00
2009-04-04 15:36:12 -04:00
@Define ( " vc " )
public String getVideoCodec ( ) {
2009-08-23 11:17:32 -04:00
// e.g. XviD, x264, DivX 5, MPEG-4 Visual, AVC, etc.
2015-10-14 02:13:50 -04:00
String codec = getMediaInfo ( StreamKind . Video , 0 , " Encoded_Library_Name " , " Encoded_Library/Name " , " CodecID/Hint " , " Format " ) ;
2013-09-06 03:55:13 -04:00
2009-08-23 11:17:32 -04:00
// get first token (e.g. DivX 5 => DivX)
2016-11-09 10:02:25 -05:00
return tokenize ( codec ) . findFirst ( ) . get ( ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2009-04-04 15:36:12 -04:00
@Define ( " ac " )
public String getAudioCodec ( ) {
2009-08-23 11:17:32 -04:00
// e.g. AC-3, DTS, AAC, Vorbis, MP3, etc.
String codec = getMediaInfo ( StreamKind . Audio , 0 , " CodecID/Hint " , " Format " ) ;
2013-09-06 03:55:13 -04:00
2009-08-23 11:17:32 -04:00
// remove punctuation (e.g. AC-3 => AC3)
2016-11-09 10:02:25 -05:00
return normalizePunctuation ( codec , " " , " " ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2009-05-02 19:34:04 -04:00
@Define ( " cf " )
public String getContainerFormat ( ) {
2009-08-23 11:17:32 -04:00
// container format extensions (e.g. avi, mkv mka mks, OGG, etc.)
String extensions = getMediaInfo ( StreamKind . General , 0 , " Codec/Extensions " , " Format " ) ;
2013-09-06 03:55:13 -04:00
2009-08-23 11:17:32 -04:00
// get first extension
2016-11-09 10:02:25 -05:00
return tokenize ( extensions ) . map ( String : : toLowerCase ) . findFirst ( ) . get ( ) ;
2009-05-02 19:34:04 -04:00
}
2013-09-06 03:55:13 -04:00
2009-08-23 11:17:32 -04:00
@Define ( " vf " )
public String getVideoFormat ( ) {
2013-03-24 09:37:10 -04:00
int width = Integer . parseInt ( getMediaInfo ( StreamKind . Video , 0 , " Width " ) ) ;
2012-07-08 08:38:34 -04:00
int height = Integer . parseInt ( getMediaInfo ( StreamKind . Video , 0 , " Height " ) ) ;
2013-09-06 03:55:13 -04:00
2014-06-24 22:58:47 -04:00
int [ ] ws = new int [ ] { 15360 , 7680 , 3840 , 1920 , 1280 , 1024 , 854 , 852 , 720 , 688 , 512 , 320 } ;
int [ ] hs = new int [ ] { 8640 , 4320 , 2160 , 1080 , 720 , 576 , 576 , 480 , 480 , 360 , 240 , 240 } ;
2016-11-09 10:02:25 -05:00
int ns = 0 ;
2013-03-24 09:37:10 -04:00
for ( int i = 0 ; i < ws . length - 1 ; i + + ) {
2013-09-23 16:01:11 -04:00
if ( ( width > = ws [ i ] | | height > = hs [ i ] ) | | ( width > ws [ i + 1 ] & & height > hs [ i + 1 ] ) ) {
2012-07-16 07:43:14 -04:00
ns = hs [ i ] ;
break ;
}
}
2016-11-09 10:02:25 -05:00
2012-07-16 07:43:14 -04:00
if ( ns > 0 ) {
// e.g. 720p, nobody actually wants files to be tagged as interlaced, e.g. 720i
return String . format ( " %dp " , ns ) ;
}
2016-11-09 10:02:25 -05:00
2012-07-16 07:43:14 -04:00
return null ; // video too small
2012-07-08 08:38:34 -04:00
}
2013-09-06 03:55:13 -04:00
2012-07-08 08:38:34 -04:00
@Define ( " hpi " )
public String getExactVideoFormat ( ) {
2009-04-04 15:36:12 -04:00
String height = getMediaInfo ( StreamKind . Video , 0 , " Height " ) ;
2009-08-23 11:17:32 -04:00
String scanType = getMediaInfo ( StreamKind . Video , 0 , " ScanType " ) ;
2013-09-06 03:55:13 -04:00
2009-04-04 15:36:12 -04:00
// e.g. 720p
2009-08-23 11:17:32 -04:00
return height + Character . toLowerCase ( scanType . charAt ( 0 ) ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2011-09-18 15:08:03 -04:00
@Define ( " af " )
public String getAudioChannels ( ) {
2013-10-25 14:14:24 -04:00
String channels = getMediaInfo ( StreamKind . Audio , 0 , " Channel(s)_Original " , " Channel(s) " ) ;
2013-09-06 03:55:13 -04:00
2016-01-25 06:10:56 -05:00
// get first number, e.g. 6ch
2016-11-09 10:02:25 -05:00
return String . format ( " %dch " , matchInteger ( channels ) ) ;
2011-09-18 15:08:03 -04:00
}
2013-09-06 03:55:13 -04:00
2016-01-26 13:41:47 -05:00
@Define ( " channels " )
public String getAudioChannelPositions ( ) {
2016-04-02 05:07:10 -04:00
String channels = getMediaInfo ( StreamKind . Audio , 0 , " ChannelPositions/String2 " , " Channel(s)_Original " , " Channel(s) " ) ;
2016-01-26 13:41:47 -05:00
2016-04-06 03:16:27 -04:00
// e.g. ChannelPositions/String2: 3/2/2.1 / 3/2/0.1 (one audio stream may contain multiple multi-channel streams)
2016-11-09 10:02:25 -05:00
double d = tokenize ( channels ) . mapToDouble ( s - > {
2016-10-01 13:10:23 -04:00
try {
2016-11-09 10:02:25 -05:00
return tokenize ( s , SLASH ) . mapToDouble ( Double : : parseDouble ) . reduce ( 0 , ( a , b ) - > a + b ) ;
2016-10-01 13:10:23 -04:00
} catch ( NumberFormatException e ) {
return 0 ;
}
2016-04-07 03:36:51 -04:00
} ) . filter ( it - > it > 0 ) . max ( ) . getAsDouble ( ) ;
2016-04-06 03:16:27 -04:00
2016-04-07 03:36:51 -04:00
return BigDecimal . valueOf ( d ) . setScale ( 1 , RoundingMode . HALF_UP ) . toPlainString ( ) ;
2016-01-26 13:41:47 -05:00
}
2009-04-04 15:36:12 -04:00
@Define ( " resolution " )
public String getVideoResolution ( ) {
2016-10-30 14:06:15 -04:00
return join ( getDimension ( ) , " x " ) ; // e.g. 1280x720
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2016-05-05 07:48:08 -04:00
@Define ( " bitdepth " )
public int getVideoBitDepth ( ) {
String bitdepth = getMediaInfo ( StreamKind . Video , 0 , " BitDepth " ) ;
return Integer . parseInt ( bitdepth ) ;
}
2011-11-20 13:38:49 -05:00
@Define ( " ws " )
public String getWidescreen ( ) {
2012-07-10 02:20:01 -04:00
List < Integer > dim = getDimension ( ) ;
2013-09-06 03:55:13 -04:00
2011-11-20 13:38:49 -05:00
// width-to-height aspect ratio greater than 1.37:1
2016-03-26 03:42:39 -04:00
return ( float ) dim . get ( 0 ) / dim . get ( 1 ) > 1 . 37f ? " WS " : null ;
2011-11-20 13:38:49 -05:00
}
2013-09-06 03:55:13 -04:00
2011-11-02 10:48:23 -04:00
@Define ( " sdhd " )
public String getVideoDefinitionCategory ( ) {
2012-07-10 02:20:01 -04:00
List < Integer > dim = getDimension ( ) ;
2013-09-06 03:55:13 -04:00
2011-11-02 10:48:23 -04:00
// SD (less than 720 lines) or HD (more than 720 lines)
2012-07-10 02:20:01 -04:00
return dim . get ( 0 ) > = 1280 | | dim . get ( 1 ) > = 720 ? " HD " : " SD " ;
}
2013-09-06 03:55:13 -04:00
2012-07-10 02:20:01 -04:00
@Define ( " dim " )
public List < Integer > getDimension ( ) {
String width = getMediaInfo ( StreamKind . Video , 0 , " Width " ) ;
String height = getMediaInfo ( StreamKind . Video , 0 , " Height " ) ;
2013-09-06 03:55:13 -04:00
2014-08-11 03:10:57 -04:00
return asList ( Integer . parseInt ( width ) , Integer . parseInt ( height ) ) ;
2011-11-02 10:48:23 -04:00
}
2013-09-06 03:55:13 -04:00
2012-10-24 07:57:36 -04:00
@Define ( " original " )
2016-04-17 04:44:03 -04:00
public String getOriginalFileName ( ) {
2016-05-29 11:24:54 -04:00
String name = xattr . getOriginalName ( getMediaFile ( ) ) ;
2016-10-30 14:06:15 -04:00
return name ! = null ? getNameWithoutExtension ( name ) : null ;
2012-10-24 07:57:36 -04:00
}
2013-09-06 03:55:13 -04:00
2013-04-01 06:36:32 -04:00
@Define ( " xattr " )
2014-01-25 22:51:47 -05:00
public Object getMetaAttributesObject ( ) throws Exception {
2016-03-27 12:56:54 -04:00
return xattr . getMetaInfo ( getMediaFile ( ) ) ;
2013-04-01 06:36:32 -04:00
}
2013-09-06 03:55:13 -04:00
2009-04-04 15:36:12 -04:00
@Define ( " crc32 " )
2016-03-06 13:11:30 -05:00
public String getCRC32 ( ) throws Exception {
2009-05-26 13:05:05 -04:00
// use inferred media file
File inferredMediaFile = getInferredMediaFile ( ) ;
2013-09-06 03:55:13 -04:00
2009-05-03 11:21:04 -04:00
// try to get checksum from file name
2016-05-29 11:24:54 -04:00
Optional < String > embeddedChecksum = stream ( getFileNames ( inferredMediaFile ) ) . map ( Normalization : : getEmbeddedChecksum ) . filter ( Objects : : nonNull ) . findFirst ( ) ;
if ( embeddedChecksum . isPresent ( ) ) {
return embeddedChecksum . get ( ) ;
2014-07-09 14:55:46 -04:00
}
2013-09-06 03:55:13 -04:00
2009-05-03 11:21:04 -04:00
// try to get checksum from sfv file
2014-07-09 14:55:46 -04:00
String checksum = getHashFromVerificationFile ( inferredMediaFile , HashType . SFV , 3 ) ;
if ( checksum ! = null ) {
2009-05-03 11:21:04 -04:00
return checksum ;
2014-07-09 14:55:46 -04:00
}
2013-09-06 03:55:13 -04:00
2014-11-12 04:56:26 -05:00
// try CRC32 xattr (as stored by verify script)
2014-11-12 12:39:57 -05:00
try {
MetaAttributeView xattr = new MetaAttributeView ( inferredMediaFile ) ;
checksum = xattr . get ( " CRC32 " ) ;
if ( checksum ! = null ) {
return checksum ;
}
} catch ( Exception e ) {
// ignore if xattr metadata is not supported for the given file
2014-11-12 04:56:26 -05:00
}
2009-05-03 11:21:04 -04:00
// calculate checksum from file
2016-03-06 13:11:30 -05:00
Cache cache = Cache . getCache ( " crc32 " , CacheType . Ephemeral ) ;
2016-03-09 14:51:41 -05:00
return ( String ) cache . computeIfAbsent ( inferredMediaFile . getCanonicalPath ( ) , it - > crc32 ( inferredMediaFile ) ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2010-10-24 08:10:30 -04:00
@Define ( " fn " )
public String getFileName ( ) {
2015-11-29 04:28:54 -05:00
// name without file extension
return FileUtilities . getName ( getMediaFile ( ) ) ;
2010-10-24 08:10:30 -04:00
}
2013-09-06 03:55:13 -04:00
2009-05-02 19:34:04 -04:00
@Define ( " ext " )
2009-05-03 12:28:39 -04:00
public String getExtension ( ) {
2009-05-02 19:34:04 -04:00
// file extension
2015-11-29 04:28:54 -05:00
return FileUtilities . getExtension ( getMediaFile ( ) ) ;
2009-05-02 19:34:04 -04:00
}
2013-09-06 03:55:13 -04:00
2011-09-18 15:08:03 -04:00
@Define ( " source " )
public String getVideoSource ( ) {
2016-05-29 11:24:54 -04:00
// look for video source patterns in media file and it's parent folder (use inferred media file)
return releaseInfo . getVideoSource ( getFileNames ( getInferredMediaFile ( ) ) ) ;
2011-09-18 15:08:03 -04:00
}
2013-09-06 03:55:13 -04:00
2014-06-29 07:04:04 -04:00
@Define ( " tags " )
public List < String > getVideoTags ( ) {
2016-05-29 11:24:54 -04:00
// look for video source patterns in media file and it's parent folder (use inferred media file)
List < String > matches = releaseInfo . getVideoTags ( getFileNames ( getInferredMediaFile ( ) ) ) ;
2014-06-29 07:04:04 -04:00
if ( matches . isEmpty ( ) ) {
return null ;
}
2016-05-29 11:24:54 -04:00
// heavy normalization for whatever text was captured with the tags pattern
return matches . stream ( ) . map ( s - > {
2016-11-09 10:02:25 -05:00
return lowerTrail ( upperInitial ( normalizePunctuation ( s ) ) ) ;
2016-05-29 11:24:54 -04:00
} ) . sorted ( ) . distinct ( ) . collect ( toList ( ) ) ;
2015-11-30 03:51:42 -05:00
}
@Define ( " s3d " )
public String getStereoscopic3D ( ) {
2016-05-29 11:24:54 -04:00
return releaseInfo . getStereoscopic3D ( getFileNames ( getInferredMediaFile ( ) ) ) ;
2014-06-29 07:04:04 -04:00
}
2011-09-18 15:08:03 -04:00
@Define ( " group " )
2016-03-08 07:59:24 -05:00
public String getReleaseGroup ( ) throws Exception {
2014-02-19 15:28:00 -05:00
// reduce false positives by removing the know titles from the name
2016-11-09 08:29:03 -05:00
Pattern [ ] nonGroupPattern = { getKeywordExcludePattern ( ) , releaseInfo . getVideoSourcePattern ( ) , releaseInfo . getVideoFormatPattern ( true ) , releaseInfo . getResolutionPattern ( ) , releaseInfo . getStructureRootPattern ( ) } ;
2014-02-19 15:28:00 -05:00
2016-05-29 11:24:54 -04:00
// consider foldername, filename and original filename of inferred media file
2016-11-09 08:29:03 -05:00
String [ ] filenames = stream ( getFileNames ( getInferredMediaFile ( ) ) ) . map ( s - > releaseInfo . clean ( s , nonGroupPattern ) ) . filter ( s - > s . length ( ) > 0 ) . toArray ( String [ ] : : new ) ;
2014-02-19 15:28:00 -05:00
2011-09-18 15:08:03 -04:00
// look for release group names in media file and it's parent folder
2014-02-19 15:28:00 -05:00
return releaseInfo . getReleaseGroup ( filenames ) ;
2011-09-18 15:08:03 -04:00
}
2013-09-06 03:55:13 -04:00
2016-03-24 11:18:01 -04:00
@Define ( " subt " )
2016-03-24 07:13:47 -04:00
public String getSubtitleTags ( ) throws Exception {
if ( ! SUBTITLE_FILES . accept ( getMediaFile ( ) ) ) {
return null ;
}
Language language = getLanguageTag ( ) ;
if ( language ! = null ) {
2016-05-29 11:24:54 -04:00
String tag = '.' + language . getISO3B ( ) ; // Plex only supports ISO 639-2/B language codes
String category = releaseInfo . getSubtitleCategoryTag ( getFileNames ( getMediaFile ( ) ) ) ;
2016-03-24 07:13:47 -04:00
if ( category ! = null ) {
return tag + '.' + category ;
}
return tag ;
}
return null ;
}
2011-11-21 07:24:51 -05:00
@Define ( " lang " )
2016-03-24 07:13:47 -04:00
public Language getLanguageTag ( ) throws Exception {
2016-09-07 22:58:10 -04:00
// grep language from filename
Locale languageTag = releaseInfo . getSubtitleLanguageTag ( getFileNames ( getMediaFile ( ) ) ) ;
if ( languageTag ! = null ) {
return Language . getLanguage ( languageTag ) ;
2016-01-31 11:13:04 -05:00
}
2013-09-06 03:55:13 -04:00
2016-09-07 22:58:10 -04:00
// detect language from subtitle text content
2016-01-31 11:13:04 -05:00
if ( SUBTITLE_FILES . accept ( getMediaFile ( ) ) ) {
try {
2016-09-07 22:58:10 -04:00
return detectSubtitleLanguage ( getMediaFile ( ) ) ;
} catch ( Exception e ) {
throw new RuntimeException ( " Failed to detect subtitle language: " + e , e ) ;
2016-01-31 11:13:04 -05:00
}
2013-02-01 13:06:18 -05:00
}
2013-09-06 03:55:13 -04:00
2014-11-11 12:35:53 -05:00
return null ;
2011-11-21 07:24:51 -05:00
}
2013-09-06 03:55:13 -04:00
2016-02-05 05:49:39 -05:00
@Define ( " languages " )
2016-11-13 06:12:30 -05:00
public List < Language > getSpokenLanguages ( ) {
2016-05-10 06:17:16 -04:00
if ( infoObject instanceof Movie ) {
2016-10-30 14:06:15 -04:00
List < Locale > languages = getMovieInfo ( ) . getSpokenLanguages ( ) ;
2016-10-29 08:14:01 -04:00
return languages . stream ( ) . map ( Language : : getLanguage ) . filter ( Objects : : nonNull ) . collect ( toList ( ) ) ;
2016-05-10 06:17:16 -04:00
}
if ( infoObject instanceof Episode ) {
String language = getSeriesInfo ( ) . getLanguage ( ) ;
2016-10-29 08:14:01 -04:00
return Stream . of ( language ) . map ( Language : : findLanguage ) . filter ( Objects : : nonNull ) . collect ( toList ( ) ) ;
2016-05-10 06:17:16 -04:00
}
return null ;
2016-02-05 05:49:39 -05:00
}
2016-08-06 17:49:42 -04:00
@Define ( " runtime " )
2016-11-13 06:12:30 -05:00
public Integer getRuntime ( ) {
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Movie )
return getMovieInfo ( ) . getRuntime ( ) ;
if ( infoObject instanceof Episode )
return getSeriesInfo ( ) . getRuntime ( ) ;
return null ;
2016-08-06 17:49:42 -04:00
}
2012-02-20 02:07:06 -05:00
@Define ( " actors " )
2016-10-30 14:06:15 -04:00
public List < String > getActors ( ) throws Exception {
if ( infoObject instanceof Movie )
return getMovieInfo ( ) . getActors ( ) ;
if ( infoObject instanceof Episode )
2016-10-30 19:58:27 -04:00
return ExpressionFormatMethods . getActors ( getSeriesInfo ( ) ) ; // use TheTVDB API v2 to retrieve actors info
2016-10-30 14:06:15 -04:00
return null ;
2012-02-20 02:07:06 -05:00
}
2013-09-06 03:55:13 -04:00
2012-02-20 02:07:06 -05:00
@Define ( " genres " )
2016-11-13 06:12:30 -05:00
public List < String > getGenres ( ) {
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Movie )
return getMovieInfo ( ) . getGenres ( ) ;
if ( infoObject instanceof Episode )
return getSeriesInfo ( ) . getGenres ( ) ;
return null ;
2012-02-20 02:07:06 -05:00
}
2013-09-06 03:55:13 -04:00
2014-02-28 11:04:54 -05:00
@Define ( " genre " )
2016-11-13 06:12:30 -05:00
public String getPrimaryGenre ( ) {
2016-10-30 14:06:15 -04:00
return getGenres ( ) . iterator ( ) . next ( ) ;
2014-02-28 11:04:54 -05:00
}
2012-02-20 02:07:06 -05:00
@Define ( " director " )
2016-10-30 19:19:11 -04:00
public String getDirector ( ) throws Exception {
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Movie )
return getMovieInfo ( ) . getDirector ( ) ;
2016-10-30 19:19:11 -04:00
if ( infoObject instanceof Episode )
2016-11-13 06:12:30 -05:00
return ExpressionFormatMethods . getInfo ( getEpisode ( ) ) . getDirector ( ) ; // use TheTVDB API v2 to retrieve extended episode info
2016-10-30 14:06:15 -04:00
return null ;
2012-02-20 02:07:06 -05:00
}
2013-09-06 03:55:13 -04:00
2012-02-20 02:07:06 -05:00
@Define ( " certification " )
2016-11-13 06:12:30 -05:00
public String getCertification ( ) {
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Movie )
return getMovieInfo ( ) . getCertification ( ) ;
if ( infoObject instanceof Episode )
return getSeriesInfo ( ) . getCertification ( ) ;
return null ;
2012-02-20 02:07:06 -05:00
}
2013-09-06 03:55:13 -04:00
2012-02-20 02:07:06 -05:00
@Define ( " rating " )
2016-11-13 06:12:30 -05:00
public Double getRating ( ) {
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Movie )
return getMovieInfo ( ) . getRating ( ) ;
if ( infoObject instanceof Episode )
return getSeriesInfo ( ) . getRating ( ) ;
return null ;
2012-02-20 02:07:06 -05:00
}
2013-09-06 03:55:13 -04:00
2016-10-31 13:52:42 -04:00
@Define ( " votes " )
2016-11-13 06:12:30 -05:00
public Integer getVotes ( ) {
2016-10-31 13:52:42 -04:00
if ( infoObject instanceof Movie )
return getMovieInfo ( ) . getVotes ( ) ;
if ( infoObject instanceof Episode )
return getSeriesInfo ( ) . getRatingCount ( ) ;
return null ;
}
2012-07-24 13:44:54 -04:00
@Define ( " collection " )
2016-11-13 06:12:30 -05:00
public String getCollection ( ) {
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Movie )
return getMovieInfo ( ) . getCollection ( ) ;
return null ;
2012-07-24 13:44:54 -04:00
}
2013-09-06 03:55:13 -04:00
2012-02-09 08:42:14 -05:00
@Define ( " info " )
2016-11-13 06:12:30 -05:00
public synchronized AssociativeScriptObject getMetaInfo ( ) {
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Movie )
return createPropertyBindings ( getMovieInfo ( ) ) ;
if ( infoObject instanceof Episode )
return createPropertyBindings ( getSeriesInfo ( ) ) ;
return null ;
}
@Define ( " omdb " )
public synchronized AssociativeScriptObject getOmdbApiInfo ( ) throws Exception {
if ( infoObject instanceof Movie ) {
if ( getMovie ( ) . getImdbId ( ) > 0 ) {
return createPropertyBindings ( OMDb . getMovieInfo ( getMovie ( ) ) ) ;
}
if ( getMovie ( ) . getTmdbId ( ) > 0 ) {
Integer imdbId = getPrimaryMovieInfo ( ) . getImdbId ( ) ;
return createPropertyBindings ( OMDb . getMovieInfo ( new Movie ( imdbId ) ) ) ;
2012-02-20 02:07:06 -05:00
}
2012-02-08 07:24:36 -05:00
}
2014-12-09 04:58:33 -05:00
2016-10-30 14:06:15 -04:00
if ( infoObject instanceof Episode ) {
TheTVDBSeriesInfo info = ( TheTVDBSeriesInfo ) getPrimarySeriesInfo ( ) ;
int imdbId = matchInteger ( info . getImdbId ( ) ) ;
return createPropertyBindings ( OMDb . getMovieInfo ( new Movie ( imdbId ) ) ) ;
2014-12-09 04:58:33 -05:00
}
2016-10-30 14:06:15 -04:00
return null ;
2012-02-08 07:24:36 -05:00
}
2013-09-06 03:55:13 -04:00
2016-11-22 11:55:11 -05:00
@Define ( " order " )
public DynamicBindings getSortOrderObject ( ) {
return new DynamicBindings ( SortOrder : : names , k - > {
if ( infoObject instanceof Episode ) {
2016-11-22 12:17:59 -05:00
SortOrder order = SortOrder . forName ( k ) ;
2016-11-22 15:34:56 -05:00
Episode episode = fetchEpisode ( getEpisode ( ) , order , null ) ;
2016-11-22 12:17:59 -05:00
return createBindingObject ( null , episode , null ) ;
2016-11-22 11:55:11 -05:00
}
return undefined ( k ) ;
} ) ;
}
2016-10-30 14:06:15 -04:00
@Define ( " localize " )
2016-11-22 11:55:11 -05:00
public DynamicBindings getLocalizedInfoObject ( ) {
2016-10-30 14:06:15 -04:00
return new DynamicBindings ( Language : : availableLanguages , k - > {
Language language = Language . findLanguage ( k ) ;
2016-11-22 12:17:59 -05:00
if ( language ! = null & & infoObject instanceof Movie ) {
2017-01-09 11:14:16 -05:00
Movie movie = TheMovieDB . getMovieDescriptor ( getMovie ( ) , language . getLocale ( ) ) ;
return createBindingObject ( null , movie , null ) ;
2016-10-30 14:06:15 -04:00
}
2013-09-06 03:55:13 -04:00
2016-11-22 12:17:59 -05:00
if ( language ! = null & & infoObject instanceof Episode ) {
2016-11-22 15:34:56 -05:00
Episode episode = fetchEpisode ( getEpisode ( ) , null , language . getLocale ( ) ) ;
2017-01-09 11:14:16 -05:00
return createBindingObject ( null , episode , null ) ;
2012-07-24 13:44:54 -04:00
}
2013-09-06 03:55:13 -04:00
2016-10-30 14:06:15 -04:00
return undefined ( k ) ;
} ) ;
2012-07-22 05:44:08 -04:00
}
2013-09-06 03:55:13 -04:00
2016-01-26 06:29:16 -05:00
@Define ( " az " )
public String getSortInitial ( ) {
try {
return sortInitial ( getCollection ( ) . toString ( ) ) ;
} catch ( Exception e ) {
return sortInitial ( getName ( ) ) ;
}
}
2016-04-30 04:20:28 -04:00
@Define ( " anime " )
public boolean isAnimeEpisode ( ) {
2016-05-22 08:50:32 -04:00
return getEpisodes ( ) . stream ( ) . anyMatch ( it - > isAnime ( it ) ) ;
2016-04-30 04:20:28 -04:00
}
@Define ( " regular " )
public boolean isRegularEpisode ( ) {
2016-05-22 08:50:32 -04:00
return getEpisodes ( ) . stream ( ) . anyMatch ( it - > isRegular ( it ) ) ;
2016-04-30 04:20:28 -04:00
}
2012-03-17 15:02:04 -04:00
@Define ( " episodelist " )
2016-07-22 10:01:05 -04:00
public List < Episode > getEpisodeList ( ) throws Exception {
2016-11-22 15:34:56 -05:00
return fetchEpisodeList ( getEpisode ( ) ) ;
2016-01-17 02:01:53 -05:00
}
2016-07-22 10:01:05 -04:00
@Define ( " sy " )
public List < Integer > getSeasonYears ( ) throws Exception {
2016-08-10 07:11:23 -04:00
return getEpisodeList ( ) . stream ( ) . filter ( e - > isRegular ( e ) & & e . getSeason ( ) . equals ( getSeasonNumber ( ) ) & & e . getAirdate ( ) ! = null ) . map ( e - > e . getAirdate ( ) . getYear ( ) ) . sorted ( ) . distinct ( ) . collect ( toList ( ) ) ;
2016-07-22 10:01:05 -04:00
}
2016-07-22 10:12:53 -04:00
@Define ( " sc " )
public Integer getSeasonCount ( ) throws Exception {
2016-08-10 07:11:23 -04:00
return getEpisodeList ( ) . stream ( ) . filter ( e - > isRegular ( e ) & & e . getSeason ( ) ! = null ) . map ( Episode : : getSeason ) . max ( Integer : : compare ) . get ( ) ;
2016-07-22 10:12:53 -04:00
}
2016-05-29 08:47:06 -04:00
@Define ( " mediaTitle " )
public String getMediaTitle ( ) {
return getMediaInfo ( StreamKind . General , 0 , " Title " , " Movie " ) ;
}
2013-09-06 03:55:13 -04:00
2016-11-17 01:48:24 -05:00
@Define ( " audioLanguages " )
public List < Language > getAudioLanguageList ( ) {
return getMediaInfo ( StreamKind . Audio , " Language " ) . filter ( Objects : : nonNull ) . distinct ( ) . map ( Language : : findLanguage ) . filter ( Objects : : nonNull ) . collect ( toList ( ) ) ;
}
2016-10-28 13:16:50 -04:00
@Define ( " textLanguages " )
2016-10-29 08:14:01 -04:00
public List < Language > getTextLanguageList ( ) {
return getMediaInfo ( StreamKind . Text , " Language " ) . filter ( Objects : : nonNull ) . distinct ( ) . map ( Language : : findLanguage ) . filter ( Objects : : nonNull ) . collect ( toList ( ) ) ;
2016-10-28 13:16:50 -04:00
}
2014-01-08 09:26:39 -05:00
@Define ( " bitrate " )
2016-08-07 16:45:38 -04:00
public Long getOverallBitRate ( ) {
2015-11-14 11:12:03 -05:00
return new Double ( getMediaInfo ( StreamKind . General , 0 , " OverallBitRate " ) ) . longValue ( ) ;
2014-01-08 09:26:39 -05:00
}
2017-02-03 13:56:58 -05:00
@Define ( " kbps " )
public String getKiloBytesPerSecond ( ) {
return String . format ( " %d kbps " , getOverallBitRate ( ) / 1000 ) ;
}
2013-12-19 01:21:45 -05:00
@Define ( " duration " )
2015-10-18 03:51:10 -04:00
public Long getDuration ( ) {
2016-08-07 16:45:38 -04:00
return new Double ( getMediaInfo ( StreamKind . General , 0 , " Duration " ) ) . longValue ( ) ;
2013-12-19 01:21:45 -05:00
}
2013-12-20 00:32:28 -05:00
@Define ( " seconds " )
public Integer getSeconds ( ) {
2015-10-18 03:51:58 -04:00
return ( int ) ( getDuration ( ) / 1000 ) ;
2013-12-20 00:32:28 -05:00
}
2013-12-19 01:21:45 -05:00
@Define ( " minutes " )
public Integer getDurationInMinutes ( ) {
2015-10-18 03:51:58 -04:00
return ( int ) ( getDuration ( ) / 60000 ) ;
2013-12-19 01:21:45 -05:00
}
2009-05-03 12:28:39 -04:00
@Define ( " media " )
2012-02-20 02:07:06 -05:00
public AssociativeScriptObject getGeneralMediaInfo ( ) {
2016-04-07 04:23:17 -04:00
return createMediaInfoBindings ( StreamKind . General ) . get ( 0 ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2015-12-15 22:28:29 -05:00
@Define ( " menu " )
public AssociativeScriptObject getMenuInfo ( ) {
2016-04-07 04:23:17 -04:00
return createMediaInfoBindings ( StreamKind . Menu ) . get ( 0 ) ;
2015-12-15 22:28:29 -05:00
}
@Define ( " image " )
public AssociativeScriptObject getImageInfo ( ) {
2016-04-07 04:23:17 -04:00
return createMediaInfoBindings ( StreamKind . Image ) . get ( 0 ) ;
2015-12-15 22:28:29 -05:00
}
2016-04-07 04:23:17 -04:00
@Define ( " video " )
2013-07-13 13:13:07 -04:00
public List < AssociativeScriptObject > getVideoInfoList ( ) {
2016-04-07 04:23:17 -04:00
return createMediaInfoBindings ( StreamKind . Video ) ;
2013-07-10 05:18:28 -04:00
}
2013-09-06 03:55:13 -04:00
2016-04-07 04:23:17 -04:00
@Define ( " audio " )
2013-07-13 13:13:07 -04:00
public List < AssociativeScriptObject > getAudioInfoList ( ) {
2016-04-07 04:23:17 -04:00
return createMediaInfoBindings ( StreamKind . Audio ) ;
2013-07-10 05:18:28 -04:00
}
2013-09-06 03:55:13 -04:00
2016-04-07 04:23:17 -04:00
@Define ( " text " )
2013-07-13 13:13:07 -04:00
public List < AssociativeScriptObject > getTextInfoList ( ) {
2016-04-07 04:23:17 -04:00
return createMediaInfoBindings ( StreamKind . Text ) ;
2015-12-15 22:28:29 -05:00
}
@Define ( " chapters " )
public List < AssociativeScriptObject > getChaptersInfoList ( ) {
2016-04-07 04:23:17 -04:00
return createMediaInfoBindings ( StreamKind . Chapters ) ;
2015-12-15 22:28:29 -05:00
}
2013-01-10 13:28:46 -05:00
@Define ( " artist " )
public String getArtist ( ) {
return getMusic ( ) . getArtist ( ) ;
}
2013-09-06 03:55:13 -04:00
2013-01-23 13:15:53 -05:00
@Define ( " albumArtist " )
public String getAlbumArtist ( ) {
return getMusic ( ) . getAlbumArtist ( ) ;
2013-01-10 13:28:46 -05:00
}
2013-09-06 03:55:13 -04:00
2013-01-10 13:28:46 -05:00
@Define ( " album " )
public String getAlbum ( ) {
return getMusic ( ) . getAlbum ( ) ;
}
2013-09-06 03:55:13 -04:00
2009-05-02 19:34:04 -04:00
@Define ( " episode " )
2009-04-25 03:59:08 -04:00
public Episode getEpisode ( ) {
2011-09-18 15:08:03 -04:00
return ( Episode ) infoObject ;
}
2013-09-06 03:55:13 -04:00
2012-03-17 15:02:04 -04:00
@Define ( " episodes " )
public List < Episode > getEpisodes ( ) {
2016-05-22 08:50:32 -04:00
return getMultiEpisodeList ( getEpisode ( ) ) ;
2012-03-17 15:02:04 -04:00
}
2013-09-06 03:55:13 -04:00
2011-09-18 15:08:03 -04:00
@Define ( " movie " )
2011-09-22 08:55:04 -04:00
public Movie getMovie ( ) {
return ( Movie ) infoObject ;
2009-04-25 03:59:08 -04:00
}
2013-09-06 03:55:13 -04:00
2013-01-10 13:28:46 -05:00
@Define ( " music " )
public AudioTrack getMusic ( ) {
return ( AudioTrack ) infoObject ;
}
2013-09-06 03:55:13 -04:00
2011-09-18 15:08:03 -04:00
@Define ( " pi " )
public Integer getPart ( ) {
2013-01-12 10:21:33 -05:00
if ( infoObject instanceof AudioTrack )
2015-01-11 18:33:31 -05:00
return getMusic ( ) . getTrack ( ) ;
2013-01-12 10:21:33 -05:00
if ( infoObject instanceof MoviePart )
return ( ( MoviePart ) infoObject ) . getPartIndex ( ) ;
2013-09-06 03:55:13 -04:00
2013-01-12 10:21:33 -05:00
return null ;
2011-09-18 15:08:03 -04:00
}
2013-09-06 03:55:13 -04:00
2011-09-18 15:08:03 -04:00
@Define ( " pn " )
public Integer getPartCount ( ) {
2013-01-23 13:15:53 -05:00
if ( infoObject instanceof AudioTrack )
2015-01-11 18:33:31 -05:00
return getMusic ( ) . getTrackCount ( ) ;
2013-01-23 13:15:53 -05:00
if ( infoObject instanceof MoviePart )
return ( ( MoviePart ) infoObject ) . getPartCount ( ) ;
2013-09-06 03:55:13 -04:00
2013-01-23 13:15:53 -05:00
return null ;
2011-09-18 15:08:03 -04:00
}
2013-09-06 03:55:13 -04:00
2016-07-02 05:48:52 -04:00
@Define ( " type " )
public String getInfoObjectType ( ) {
return infoObject . getClass ( ) . getSimpleName ( ) ;
}
2016-05-18 08:44:42 -04:00
@Define ( " mime " )
2013-12-22 03:33:19 -05:00
public List < String > getMediaType ( ) throws Exception {
2016-04-02 05:07:10 -04:00
// format engine does not allow / in binding value
2017-01-12 09:18:10 -05:00
return SLASH . splitAsStream ( MediaTypes . getMediaType ( getExtension ( ) ) ) . collect ( toList ( ) ) ;
2013-12-22 03:33:19 -05:00
}
2016-10-09 06:40:05 -04:00
@Define ( " mediaPath " )
2016-10-09 06:33:34 -04:00
public File getMediaPath ( ) throws Exception {
return getStructurePathTail ( getMediaFile ( ) ) ;
}
2016-07-27 11:31:45 -04:00
@Define ( " f " )
2011-12-19 01:31:48 -05:00
public File getMediaFile ( ) {
2015-11-29 04:28:54 -05:00
// make sure file is not null, and that it is an existing file
if ( mediaFile = = null ) {
2015-11-30 01:47:35 -05:00
throw new IllegalStateException ( EXCEPTION_SAMPLE_FILE_NOT_SET ) ;
2015-11-29 04:28:54 -05:00
}
2011-12-19 01:31:48 -05:00
return mediaFile ;
2012-02-14 09:16:13 -05:00
}
2013-09-06 03:55:13 -04:00
2012-02-14 09:16:13 -05:00
@Define ( " folder " )
public File getMediaParentFolder ( ) {
2013-01-27 03:17:12 -05:00
return getMediaFile ( ) . getParentFile ( ) ;
2011-12-19 01:31:48 -05:00
}
2013-09-06 03:55:13 -04:00
2015-12-25 07:39:58 -05:00
@Define ( " bytes " )
public Long getFileSize ( ) {
return getInferredMediaFile ( ) . length ( ) ;
}
@Define ( " megabytes " )
public String getFileSizeInMegaBytes ( ) {
return String . format ( " %.0f " , getFileSize ( ) / Math . pow ( 1000 , 2 ) ) ;
}
@Define ( " gigabytes " )
public String getFileSizeInGigaBytes ( ) {
return String . format ( " %.1f " , getFileSize ( ) / Math . pow ( 1000 , 3 ) ) ;
}
2016-08-09 11:46:03 -04:00
@Define ( " encodedDate " )
public SimpleDate getEncodedDate ( ) {
String date = getMediaInfo ( StreamKind . General , 0 , " Encoded_Date " ) ; // e.g. UTC 2008-01-08 19:54:39
ZonedDateTime time = ZonedDateTime . parse ( date , DateTimeFormatter . ofPattern ( " zzz uuuu-MM-dd HH:mm:ss " ) ) ;
return new SimpleDate ( time ) ;
}
@Define ( " today " )
public SimpleDate getToday ( ) {
2016-08-09 12:34:35 -04:00
return new SimpleDate ( LocalDateTime . now ( ) ) ;
2016-08-09 11:46:03 -04:00
}
2011-12-19 01:31:48 -05:00
@Define ( " home " )
2016-03-11 06:14:50 -05:00
public File getUserHome ( ) {
2016-11-25 12:37:09 -05:00
return ApplicationFolder . UserHome . get ( ) ;
2011-12-19 01:31:48 -05:00
}
2013-09-06 03:55:13 -04:00
2014-10-27 17:07:08 -04:00
@Define ( " output " )
public File getUserDefinedOutputFolder ( ) throws IOException {
return new File ( Settings . getApplicationArguments ( ) . output ) . getCanonicalFile ( ) ;
}
2014-04-15 08:26:09 -04:00
@Define ( " defines " )
public Map < String , String > getUserDefinedArguments ( ) throws IOException {
2016-04-26 13:44:21 -04:00
return unmodifiableMap ( Settings . getApplicationArguments ( ) . defines ) ;
2014-04-15 08:26:09 -04:00
}
@Define ( " label " )
public String getUserDefinedLabel ( ) throws IOException {
2016-04-26 13:44:21 -04:00
return getUserDefinedArguments ( ) . entrySet ( ) . stream ( ) . filter ( it - > {
return it . getKey ( ) . endsWith ( " label " ) & & it . getValue ( ) ! = null & & it . getValue ( ) . length ( ) > 0 ;
} ) . map ( it - > it . getValue ( ) ) . findFirst ( ) . orElse ( null ) ;
2014-04-15 08:26:09 -04:00
}
2013-02-07 07:25:46 -05:00
@Define ( " i " )
2017-01-07 11:11:58 -05:00
public Integer getModelIndex ( ) {
2014-08-22 12:36:12 -04:00
return 1 + identityIndexOf ( context . values ( ) , getInfoObject ( ) ) ;
2013-02-07 07:25:46 -05:00
}
2013-09-06 03:55:13 -04:00
2013-02-07 07:25:46 -05:00
@Define ( " di " )
2017-01-07 11:11:58 -05:00
public Integer getDuplicateIndex ( ) {
2016-12-04 11:44:51 -05:00
return 1 + identityIndexOf ( context . values ( ) . stream ( ) . filter ( getInfoObject ( ) : : equals ) . collect ( toList ( ) ) , getInfoObject ( ) ) ;
}
@Define ( " dc " )
2017-01-07 11:11:58 -05:00
public Integer getDuplicateCount ( ) {
return context . values ( ) . stream ( ) . filter ( getInfoObject ( ) : : equals ) . mapToInt ( i - > 1 ) . sum ( ) ;
2013-01-27 03:17:12 -05:00
}
2013-09-06 03:55:13 -04:00
2016-03-27 21:32:12 -04:00
@Define ( " plex " )
public File getPlexStandardPath ( ) throws Exception {
String path = NamingStandard . Plex . getPath ( infoObject ) ;
try {
2016-05-23 03:06:25 -04:00
path = path . concat ( getSubtitleTags ( ) ) ; // NPE if {subt} is undefined
2016-03-27 21:32:12 -04:00
} catch ( Exception e ) {
// ignore => no language tags
}
return new File ( path ) ;
}
2014-08-09 03:35:22 -04:00
@Define ( " self " )
public AssociativeScriptObject getSelf ( ) {
return createBindingObject ( mediaFile , infoObject , context ) ;
}
2013-01-27 03:17:12 -05:00
@Define ( " model " )
2014-08-09 03:35:22 -04:00
public List < AssociativeScriptObject > getModel ( ) {
2014-08-09 03:24:01 -04:00
List < AssociativeScriptObject > result = new ArrayList < AssociativeScriptObject > ( ) ;
2016-03-20 14:33:31 -04:00
for ( Entry < File , ? > it : context . entrySet ( ) ) {
2014-08-09 03:35:22 -04:00
result . add ( createBindingObject ( it . getKey ( ) , it . getValue ( ) , context ) ) ;
2014-08-09 03:24:01 -04:00
}
return result ;
2013-01-27 03:17:12 -05:00
}
2013-09-06 03:55:13 -04:00
2013-07-13 06:01:33 -04:00
@Define ( " json " )
2016-03-20 14:33:31 -04:00
public String getInfoObjectDump ( ) {
2016-10-08 15:55:45 -04:00
return MetaAttributes . toJson ( infoObject ) ;
2013-07-13 06:01:33 -04:00
}
2013-09-06 03:55:13 -04:00
2014-01-22 06:31:55 -05:00
public File getInferredMediaFile ( ) {
2015-11-29 04:28:54 -05:00
if ( getMediaFile ( ) . isDirectory ( ) ) {
2012-07-27 02:59:38 -04:00
// just select the first video file in the folder as media sample
2016-09-29 00:17:34 -04:00
List < File > videos = listFiles ( getMediaFile ( ) , VIDEO_FILES , CASE_INSENSITIVE_PATH_ORDER ) ;
2012-07-27 02:59:38 -04:00
if ( videos . size ( ) > 0 ) {
2016-09-28 11:09:38 -04:00
return videos . get ( 0 ) ;
2012-07-27 02:59:38 -04:00
}
2015-11-29 04:28:54 -05:00
} else if ( SUBTITLE_FILES . accept ( getMediaFile ( ) ) | | ( ( infoObject instanceof Episode | | infoObject instanceof Movie ) & & ! VIDEO_FILES . accept ( getMediaFile ( ) ) ) ) {
2013-01-27 03:17:12 -05:00
// prefer equal match from current context if possible
2014-08-09 03:24:01 -04:00
if ( context ! = null ) {
2016-03-20 14:33:31 -04:00
for ( Entry < File , ? > it : context . entrySet ( ) ) {
2013-01-27 03:17:12 -05:00
if ( infoObject . equals ( it . getValue ( ) ) & & VIDEO_FILES . accept ( it . getKey ( ) ) ) {
return it . getKey ( ) ;
}
}
}
2013-09-06 03:55:13 -04:00
2012-07-27 02:59:38 -04:00
// file is a subtitle, or nfo, etc
2015-11-29 04:28:54 -05:00
String baseName = stripReleaseInfo ( FileUtilities . getName ( getMediaFile ( ) ) ) . toLowerCase ( ) ;
List < File > videos = getChildren ( getMediaFile ( ) . getParentFile ( ) , VIDEO_FILES ) ;
2013-09-06 03:55:13 -04:00
2009-05-03 12:28:39 -04:00
// find corresponding movie file
2012-07-29 08:42:05 -04:00
for ( File movieFile : videos ) {
if ( ! baseName . isEmpty ( ) & & stripReleaseInfo ( FileUtilities . getName ( movieFile ) ) . toLowerCase ( ) . startsWith ( baseName ) ) {
2012-07-21 11:54:39 -04:00
return movieFile ;
2009-05-03 12:28:39 -04:00
}
}
2013-09-06 03:55:13 -04:00
2013-01-27 11:41:33 -05:00
// still no good match found -> just take the most probable video from the same folder
2014-07-28 06:00:27 -04:00
if ( videos . size ( ) > 0 ) {
2016-02-27 00:22:46 -05:00
sort ( videos , SimilarityComparator . compareTo ( FileUtilities . getName ( getMediaFile ( ) ) , FileUtilities : : getName ) ) ;
2014-07-28 06:00:27 -04:00
return videos . get ( 0 ) ;
2012-07-29 08:42:05 -04:00
}
2009-05-03 12:28:39 -04:00
}
2013-09-06 03:55:13 -04:00
2015-11-29 04:28:54 -05:00
return getMediaFile ( ) ;
2009-05-03 11:21:04 -04:00
}
2013-09-06 03:55:13 -04:00
2016-11-22 11:55:11 -05:00
public Episode getSeasonEpisode ( ) {
2017-01-02 00:49:30 -05:00
// magically convert AniDB absolute numbers to TheTVDB SxE numbers if AniDB is selected with airdate SxE episode sort order
2016-11-22 11:55:11 -05:00
if ( getEpisodes ( ) . stream ( ) . allMatch ( it - > isAnime ( it ) & & isRegular ( it ) & & ! isAbsolute ( it ) ) ) {
try {
return getEpisodeByAbsoluteNumber ( getEpisode ( ) , TheTVDB , SortOrder . Airdate ) ;
} catch ( Exception e ) {
debug . warning ( e : : toString ) ;
}
}
return getEpisode ( ) ;
}
2016-11-13 06:12:30 -05:00
public SeriesInfo getPrimarySeriesInfo ( ) {
if ( TheTVDB . getIdentifier ( ) . equals ( getSeriesInfo ( ) . getDatabase ( ) ) ) {
try {
return TheTVDB . getSeriesInfo ( getSeriesInfo ( ) . getId ( ) , Locale . ENGLISH ) ;
} catch ( Exception e ) {
debug . warning ( " Failed to retrieve primary series info: " + e ) ; // default to seriesInfo property
}
}
2016-10-30 14:18:00 -04:00
return getSeriesInfo ( ) ;
}
private final Resource < MovieInfo > primaryMovieInfo = Resource . lazy ( ( ) - > TheMovieDB . getMovieInfo ( getMovie ( ) , Locale . ENGLISH , false ) ) ;
private final Resource < MovieInfo > extendedMovieInfo = Resource . lazy ( ( ) - > getMovieInfo ( getMovie ( ) . getLanguage ( ) , true ) ) ;
2016-11-13 06:12:30 -05:00
public MovieInfo getPrimaryMovieInfo ( ) {
try {
return primaryMovieInfo . get ( ) ;
} catch ( Exception e ) {
throw new BindingException ( " info " , " Failed to retrieve primary movie info: " + e , e ) ;
}
2016-10-30 14:18:00 -04:00
}
2016-11-13 06:12:30 -05:00
public MovieInfo getMovieInfo ( ) {
try {
return extendedMovieInfo . get ( ) ;
} catch ( Exception e ) {
throw new BindingException ( " info " , " Failed to retrieve extended movie info: " + e , e ) ;
}
2016-10-30 14:18:00 -04:00
}
public synchronized MovieInfo getMovieInfo ( Locale locale , boolean extendedInfo ) throws Exception {
Movie m = getMovie ( ) ;
if ( m . getTmdbId ( ) > 0 )
return TheMovieDB . getMovieInfo ( m , locale = = null ? Locale . ENGLISH : locale , extendedInfo ) ;
if ( m . getImdbId ( ) > 0 )
return OMDb . getMovieInfo ( m ) ;
return null ;
}
2016-08-09 15:26:55 -04:00
private static final Map < File , MediaInfo > sharedMediaInfoObjects = synchronizedMap ( new WeakValueHashMap < File , MediaInfo > ( 64 ) ) ;
2013-09-06 03:55:13 -04:00
2015-11-14 12:25:35 -05:00
private synchronized MediaInfo getMediaInfo ( ) {
// lazy initialize
if ( mediaInfo = = null ) {
2015-11-14 13:24:31 -05:00
// use inferred media file (e.g. actual movie file instead of subtitle file)
File inferredMediaFile = getInferredMediaFile ( ) ;
2013-09-06 03:55:13 -04:00
2016-08-09 15:26:55 -04:00
mediaInfo = sharedMediaInfoObjects . computeIfAbsent ( inferredMediaFile , f - > {
try {
return new MediaInfo ( ) . open ( f ) ;
2016-08-09 16:36:38 -04:00
} catch ( IOException e ) {
2016-08-09 15:26:55 -04:00
throw new MediaInfoException ( e . getMessage ( ) ) ;
}
} ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2012-07-21 11:54:39 -04:00
return mediaInfo ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2013-02-07 07:25:46 -05:00
private Integer identityIndexOf ( Iterable < ? > c , Object o ) {
Iterator < ? > itr = c . iterator ( ) ;
for ( int i = 0 ; itr . hasNext ( ) ; i + + ) {
Object next = itr . next ( ) ;
2016-04-26 13:44:21 -04:00
if ( o = = next ) {
2013-02-07 07:25:46 -05:00
return i ;
2016-04-26 13:44:21 -04:00
}
2013-02-07 07:25:46 -05:00
}
return null ;
}
2013-09-06 03:55:13 -04:00
2009-04-04 15:36:12 -04:00
private String getMediaInfo ( StreamKind streamKind , int streamNumber , String . . . keys ) {
2009-04-04 16:19:03 -04:00
for ( String key : keys ) {
String value = getMediaInfo ( ) . get ( streamKind , streamNumber , key ) ;
2014-08-11 03:10:57 -04:00
if ( value . length ( ) > 0 ) {
2009-04-04 16:19:03 -04:00
return value ;
2014-08-11 03:10:57 -04:00
}
2009-04-04 15:36:12 -04:00
}
2014-08-11 03:10:57 -04:00
return undefined ( String . format ( " %s[%d][%s] " , streamKind , streamNumber , join ( keys , " , " ) ) ) ;
2009-04-04 15:36:12 -04:00
}
2013-09-06 03:55:13 -04:00
2016-10-28 13:16:50 -04:00
private Stream < String > getMediaInfo ( StreamKind streamKind , String . . . keys ) {
return IntStream . range ( 0 , getMediaInfo ( ) . streamCount ( streamKind ) ) . mapToObj ( streamNumber - > {
return stream ( keys ) . map ( key - > {
return getMediaInfo ( ) . get ( streamKind , streamNumber , key ) ;
} ) . filter ( s - > s . length ( ) > 0 ) . findFirst ( ) . orElse ( null ) ;
} ) ;
}
2016-03-20 14:33:31 -04:00
private AssociativeScriptObject createBindingObject ( File file , Object info , Map < File , ? > context ) {
2014-08-09 03:35:22 -04:00
MediaBindingBean mediaBindingBean = new MediaBindingBean ( info , file , context ) {
2016-04-07 04:23:17 -04:00
2015-07-25 18:47:19 -04:00
@Override
2014-08-09 03:35:22 -04:00
@Define ( undefined )
public < T > T undefined ( String name ) {
return null ; // never throw exceptions for empty or null values
}
} ;
return new AssociativeScriptObject ( new ExpressionBindings ( mediaBindingBean ) ) ;
}
2016-04-07 04:23:17 -04:00
private AssociativeScriptObject createPropertyBindings ( Object object ) {
return new AssociativeScriptObject ( new PropertyBindings ( object , null ) ) {
2013-09-06 03:55:13 -04:00
2012-07-07 23:09:42 -04:00
@Override
public Object getProperty ( String name ) {
Object value = super . getProperty ( name ) ;
2012-07-26 14:25:44 -04:00
if ( value = = null ) {
2016-04-07 04:23:17 -04:00
return undefined ( name ) ;
2012-07-26 14:25:44 -04:00
}
if ( value instanceof CharSequence ) {
2016-04-07 04:23:17 -04:00
return replacePathSeparators ( value . toString ( ) ) . trim ( ) ; // auto-clean value of path separators
2012-07-26 14:25:44 -04:00
}
2012-07-07 23:09:42 -04:00
return value ;
}
} ;
}
2013-09-06 03:55:13 -04:00
2016-04-07 04:23:17 -04:00
private List < AssociativeScriptObject > createMediaInfoBindings ( StreamKind kind ) {
return getMediaInfo ( ) . snapshot ( ) . get ( kind ) . stream ( ) . map ( AssociativeScriptObject : : new ) . collect ( toList ( ) ) ;
2013-07-13 13:13:07 -04:00
}
2013-09-06 03:55:13 -04:00
2016-05-29 11:24:54 -04:00
private String [ ] getFileNames ( File file ) {
List < String > names = new ArrayList < String > ( 3 ) ;
names . add ( getNameWithoutExtension ( file . getName ( ) ) ) ; // current file name
String original = xattr . getOriginalName ( file ) ;
if ( original ! = null ) {
names . add ( getNameWithoutExtension ( original ) ) ; // original file name
}
File parent = file . getParentFile ( ) ;
if ( parent ! = null & & parent . getParent ( ) ! = null ) {
names . add ( parent . getName ( ) ) ; // current folder name
}
return names . toArray ( new String [ 0 ] ) ;
2013-04-01 06:36:32 -04:00
}
2013-09-06 03:55:13 -04:00
2016-11-09 08:29:03 -05:00
private Pattern getKeywordExcludePattern ( ) {
2015-01-18 03:57:37 -05:00
// collect key information
2016-05-12 11:54:49 -04:00
List < Object > keys = new ArrayList < Object > ( ) ;
2014-09-03 00:16:50 -04:00
keys . add ( getName ( ) ) ;
2015-01-18 03:57:37 -05:00
2016-11-09 08:29:03 -05:00
if ( infoObject instanceof Episode | | infoObject instanceof Movie ) {
keys . addAll ( getAliasNames ( ) ) ;
if ( infoObject instanceof Episode ) {
for ( Episode e : getEpisodes ( ) ) {
keys . add ( e . getTitle ( ) ) ;
}
} else if ( infoObject instanceof Movie ) {
keys . add ( getYear ( ) ) ;
2014-09-03 00:16:50 -04:00
}
}
2015-01-18 03:57:37 -05:00
// word list for exclude pattern
2016-11-09 08:29:03 -05:00
String pattern = keys . stream ( ) . filter ( Objects : : nonNull ) . map ( Objects : : toString ) . map ( s - > {
2016-11-09 10:02:25 -05:00
return normalizePunctuation ( s , " " , " \\ P{Alnum}+ " ) ;
2016-11-09 08:29:03 -05:00
} ) . filter ( s - > s . length ( ) > 0 ) . collect ( joining ( " | " , " \\ b( " , " ) \\ b " ) ) ;
return Pattern . compile ( pattern , Pattern . CASE_INSENSITIVE | Pattern . UNICODE_CHARACTER_CLASS ) ;
2014-09-03 00:16:50 -04:00
}
2014-08-09 03:24:01 -04:00
@Override
public String toString ( ) {
return String . format ( " %s ⇔ %s " , infoObject , mediaFile = = null ? null : mediaFile . getName ( ) ) ;
}
2015-11-30 01:47:35 -05:00
public static final String EXCEPTION_UNDEFINED = " undefined " ;
public static final String EXCEPTION_SAMPLE_FILE_NOT_SET = " Sample file has not been set. Click \" Change Sample \" to select a sample file. " ;
2009-04-04 15:36:12 -04:00
}