Code: Select all
Title : Dolby Digital Plus Audio / 7.1 / 48 kHz / 1280 kbpsMight be useful, but probably won't be defined for the vast majority of files.
Code: Select all
Title : Dolby Digital Plus Audio / 7.1 / 48 kHz / 1280 kbpsCode: Select all
{
def codecList =
[
'MP3' : 'mp3',
'FLAC' : 'flac',
'PCM' : 'pcm',
'AAC LC' : 'aac',
'AAC LC SBR' : 'aac',
'AC 3' : 'ac3',
'AC 3 Dep' : 'eac3',
'E AC 3' : 'eac3',
'E AC 3 JOC' : 'eac3 Atmos',
'DTS' : 'dts',
'DTS 96 24' : 'dts',
'DTS ES' : 'dtses',
'DTS ES XXCH' : 'dtses',
'DTS XBR' : 'dts',
'DTS ES XBR' : 'dtses',
'DTS ES XXCH XBR' : 'dtses',
'DTS XLL' : 'dts',
'DTS ES XLL' : 'dtses',
'DTS ES XXCH XLL' : 'dtses',
'DTS XLL X' : 'dtsx',
'MLP FBA' : 'truehd',
'MLP FBA 16 ch' : 'truehd Atmos'
]
def filter = { [it.lang, it.codec, it.ch, it.objects] }
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1')}
def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = (( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null)
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf {it.key == combined}, 'default' : au['default'][0].toBoolean(),
'codec' : codecList.get(combined, 'UNKNOWN_FORMAT'), 'combined' : combined, 'ch' : ch,
'bitrate' : any{toInt(au.BitRate)}{toInt(au.BitRate_Maximum)}{au.FrameRate.toDouble()}{null},
'objects' : any{'[' + au['NumberOfDynamicObjects'] + ' Objs]'}{null}, 'lang' : any{au.'LanguageString3'.upper().replaceAll("SPA","ESP")}{null} ]
return audioStreams
}
def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' ')
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = oneStream(audioStreams.findAll{it.default == true})
allStreams.join(' ').space(' ')
preferredStream.space(' ')
defaultStream.space(' ')
bestBitRate.space(' ')
[bestBitRate, preferredStream].unique().join(' ')
[defaultStream, bestBitRate].unique().join(' ')
}Code: Select all
{
def preferredLang = 'Deu'
def codecList =
[
'MP3' : 'MP3',
'PCM' : 'PCM',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def filter = { [it.codec, it.ch, it.objects, it.lang] }
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1')}
def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = (( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null)
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf {it.key == combined}, 'default' : au['default'][0].toBoolean(),
'codec' : codecList.get(combined, 'UNKNOWN_FORMAT'), 'combined' : combined, 'ch' : ch,
'bitrate' : any{toInt(au.BitRate)}{toInt(au.BitRate_Maximum)}{au.FrameRate.toDouble()}{null},
'objects' : any{'[' + au['NumberOfDynamicObjects'] + ' Objs]'}{null}, 'lang' : any{au.'LanguageString3'.upperInitial()}{null} ]
return audioStreams
}
def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' ')
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = oneStream(audioStreams.findAll{it.default == true})
def bestPreferredLang = any{audioStreams.findAll{it.lang == preferredLang }.sort{a, b -> b.bitrate <=> a.bitrate}.collect{ filter(it) }*.minus(null).unique().get(0).join(' ')}{defaultStream}
bestPreferredLang.space('.')
}Code: Select all
{
def preferredLang = 'Eng'
def useChFilter = false
def filter = { [it.codec, it.ch, it.objects, it.lang] }
def codecList =
[
'MP3' : 'MP3',
'PCM' : 'PCM',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}, 'lang' : any{ au.'LanguageString3'.upperInitial() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' ')
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = oneStream(audioStreams.findAll{ it.default == true })
def bestPreferredLang = any{ audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }*.minus(null).unique().get(0).join(' ') }{}
allStreams.join(' & ').space('.')
preferredStream.space('.')
defaultStream.space('.')
bestBitRate.space('.')
[defaultStream, bestBitRate].unique().join(' & ').space('.')
[bestBitRate, preferredStream].unique().join(' & ').space('.')
any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}
}Code: Select all
allStreams.join(' & ').space('.')
preferredStream.space('.')
defaultStream.space('.')
bestBitRate.space('.')
[defaultStream, bestBitRate].unique().join(' & ').space('.')
[bestBitRate, preferredStream].unique().join(' & ').space('.')
any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}Code: Select all
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )Code: Select all
MovieTitle (2019) 118mins [18.0 Mbps] (1920x800) Dolby Digital 5.1 [6ch]
Code: Select all
SameMovieTitle 118mins (18.0 Mbps) (1920x800) TrueHD 7.1 Atmos [8ch]
Code: Select all
filebot -rename -r /volume1/Media/UNSORTED/Movies/ --db TheMovieDB -non-strict --conflict auto --output /volume1/Media/SORTED/ --format "Movies/{certification}/{n} ({y})/{n} ({y}) {minutes}mins [{mbps}] ({resolution}) {aco} {channels} [{af}]/{ny} @{mbps} {tags.upper[]} {' CD'+pi}" --action copyCode: Select all
FileBot 4.8.5 (r6224)
JNA Native: 5.2.2
MediaInfo: 19.09
7-Zip-JBinding: 9.20
Chromaprint: fpcalc version 1.4.3
Extended Attributes: OK
Unicode Filesystem: OK
Script Bundle: 2019-05-15 (r565)
Groovy: 2.5.6
JRE: Java(TM) SE Runtime Environment 1.8.0_201
JVM: 64-bit Java HotSpot(TM) 64-Bit Server VM
CPU/MEM: 4 Core / 1 GB Max Memory / 40 MB Used Memory
OS: Linux (amd64)
HW: Linux ******** 3.10.105 #24922 SMP Wed Jul 3 16:37:24 CST 2019 x86_64 GNU/Linux synology_avoton_1815+
DATA: /volume1/@appstore/filebot/data/admin
Package: SPK
License: FileBot License P75********Keep the good ideas coming. I might not always implement exactly what you want, but it might inspire me to implement something even more interesting.nartana wrote: 15 Mar 2020, 00:19 Even in the short year I've been using FileBot, it has been really cool to see how you continuously evolve it, based on input.
this what i ' m looking for many days, now my search is over. <3kim wrote: 05 Mar 2020, 22:11 Added addToList = to make it more user friendly ( output e.g. [Add to "DTS XBR" codecList] )
Added useChFilter = to make it more user friendly ( true or false, makes it more "scene" like )
Only use one of these lines:Code: Select all
{ def preferredLang = 'Eng' def useChFilter = false def filter = { [it.codec, it.ch, it.objects, it.lang] } def codecList = [ 'MP3' : 'MP3', 'PCM' : 'PCM', 'AAC LC' : 'AAC', 'AAC LC SBR' : 'AAC', 'AAC LC SBR PS' : 'AAC', 'AC 3' : 'AC3', 'AC 3 Dep' : 'EAC3', 'E AC 3' : 'EAC3', 'E AC 3 JOC' : 'EAC3 Atmos', 'AC 3 Dep JOC' : 'EAC3 Atmos', 'DTS' : 'DTS', 'DTS 96 24' : 'DTS 96-24', 'DTS ES' : 'DTS-ES', 'DTS ES XXCH' : 'DTS-ES', 'DTS XBR' : 'DTS-HD HRA', 'DTS ES XBR' : 'DTS-HD HRA', 'DTS ES XXCH XBR' : 'DTS-HD HRA', 'DTS XLL' : 'DTS-HD MA', 'DTS ES XLL' : 'DTS-HD MA', 'DTS ES XXCH XLL' : 'DTS-HD MA', 'DTS XLL X' : 'DTS X', 'MLP FBA' : 'TrueHD', 'MLP FBA 16 ch' : 'TrueHD Atmos' ] def audioStreams = [] def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') } def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') } def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') } def dString = { it.toDouble().toString() } def toInt = { it.toInteger() } any{audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }) def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{} def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() } { channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) } def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null ) def combined = allOf{codec}{format_profile}.join(' ') audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null}, 'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}, 'lang' : any{ au.'LanguageString3'.upperInitial() }{null} ] return audioStreams } def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort() def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' ') def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() }) def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }) def defaultStream = oneStream(audioStreams.findAll{ it.default == true }) def bestPreferredLang = any{ audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }*.minus(null).unique().get(0).join(' ') }{} allStreams.join(' & ').space('.') preferredStream.space('.') defaultStream.space('.') bestBitRate.space('.') [defaultStream, bestBitRate].unique().join(' & ').space('.') [bestBitRate, preferredStream].unique().join(' & ').space('.') any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream} }{'NO_AUDIO'} }useChFilter = this line:Code: Select all
allStreams.join(' & ').space('.') preferredStream.space('.') defaultStream.space('.') bestBitRate.space('.') [defaultStream, bestBitRate].unique().join(' & ').space('.') [bestBitRate, preferredStream].unique().join(' & ').space('.') any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}= if AAC/MP3 2.0 OR AC3/EAC3/DTS/TrueHD/MLPFBA 5.1, then don't show the 2.0/5.1 partCode: Select all
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
allStreams = All Audio Streams
preferredStream = The last (best) match from codecList (order matters, from low to high quality / or what you prefer)
defaultStream = The Audio Stream tagged "default=Yes" or if only one Stream
bestBitRate = The Audio Stream with the highest BitRate (with BitRate_Maximum/FrameRate as backup)
Can this awesome bit of wizardry be tweaked to prefer the stream in the language matching the one from info.OriginalLanguage? Cheers for this snippet kim it's quite amazing.kim wrote: 05 Mar 2020, 22:11 Added addToList = to make it more user friendly ( output e.g. [Add to "DTS XBR" codecList] )
Added useChFilter = to make it more user friendly ( true or false, makes it more "scene" like )
Only use one of these lines:Code: Select all
{ def preferredLang = 'Eng' def useChFilter = false def filter = { [it.codec, it.ch, it.objects, it.lang] } def codecList = [ 'MP3' : 'MP3', 'PCM' : 'PCM', 'AAC LC' : 'AAC', 'AAC LC SBR' : 'AAC', 'AAC LC SBR PS' : 'AAC', 'AC 3' : 'AC3', 'AC 3 Dep' : 'EAC3', 'E AC 3' : 'EAC3', 'E AC 3 JOC' : 'EAC3 Atmos', 'AC 3 Dep JOC' : 'EAC3 Atmos', 'DTS' : 'DTS', 'DTS 96 24' : 'DTS 96-24', 'DTS ES' : 'DTS-ES', 'DTS ES XXCH' : 'DTS-ES', 'DTS XBR' : 'DTS-HD HRA', 'DTS ES XBR' : 'DTS-HD HRA', 'DTS ES XXCH XBR' : 'DTS-HD HRA', 'DTS XLL' : 'DTS-HD MA', 'DTS ES XLL' : 'DTS-HD MA', 'DTS ES XXCH XLL' : 'DTS-HD MA', 'DTS XLL X' : 'DTS X', 'MLP FBA' : 'TrueHD', 'MLP FBA 16 ch' : 'TrueHD Atmos' ] def audioStreams = [] def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') } def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') } def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') } def dString = { it.toDouble().toString() } def toInt = { it.toInteger() } any{audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }) def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{} def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() } { channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) } def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null ) def combined = allOf{codec}{format_profile}.join(' ') audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null}, 'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}, 'lang' : any{ au.'LanguageString3'.upperInitial() }{null} ] return audioStreams } def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort() def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' ') def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() }) def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }) def defaultStream = oneStream(audioStreams.findAll{ it.default == true }) def bestPreferredLang = any{ audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }*.minus(null).unique().get(0).join(' ') }{} allStreams.join(' & ').space('.') preferredStream.space('.') defaultStream.space('.') bestBitRate.space('.') [defaultStream, bestBitRate].unique().join(' & ').space('.') [bestBitRate, preferredStream].unique().join(' & ').space('.') any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream} }{'NO_AUDIO'} }useChFilter = this line:Code: Select all
allStreams.join(' & ').space('.') preferredStream.space('.') defaultStream.space('.') bestBitRate.space('.') [defaultStream, bestBitRate].unique().join(' & ').space('.') [bestBitRate, preferredStream].unique().join(' & ').space('.') any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}= if AAC/MP3 2.0 OR AC3/EAC3/DTS/TrueHD/MLPFBA 5.1, then don't show the 2.0/5.1 partCode: Select all
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
allStreams = All Audio Streams
preferredStream = The last (best) match from codecList (order matters, from low to high quality / or what you prefer)
defaultStream = The Audio Stream tagged "default=Yes" or if only one Stream
bestBitRate = The Audio Stream with the highest BitRate (with BitRate_Maximum/FrameRate as backup)
Code: Select all
{
import net.filebot.Language;
def preferredLang = Language.findLanguage(info.OriginalLanguage).ISO3.upperInitial()Code: Select all
{
import net.filebot.Language;
def preferredLang = Language.findLanguage(info.OriginalLanguage).iso_639_2B.upperInitial()Code: Select all
{
import net.filebot.Language;
def preferredLang = Language.findLanguage(info.OriginalLanguage).ISO3B.upperInitial()How could I add this to my existing naming convention?kim wrote: 05 Mar 2020, 22:11 Added addToList = to make it more user friendly ( output e.g. [Add to "DTS XBR" codecList] )
Added useChFilter = to make it more user friendly ( true or false, makes it more "scene" like )
Only use one of these lines:Code: Select all
{ def preferredLang = 'Eng' def useChFilter = false def filter = { [it.codec, it.ch, it.objects, it.lang] } def codecList = [ 'MP3' : 'MP3', 'PCM' : 'PCM', 'AAC LC' : 'AAC', 'AAC LC SBR' : 'AAC', 'AAC LC SBR PS' : 'AAC', 'AC 3' : 'AC3', 'AC 3 Dep' : 'EAC3', 'E AC 3' : 'EAC3', 'E AC 3 JOC' : 'EAC3 Atmos', 'AC 3 Dep JOC' : 'EAC3 Atmos', 'DTS' : 'DTS', 'DTS 96 24' : 'DTS 96-24', 'DTS ES' : 'DTS-ES', 'DTS ES XXCH' : 'DTS-ES', 'DTS XBR' : 'DTS-HD HRA', 'DTS ES XBR' : 'DTS-HD HRA', 'DTS ES XXCH XBR' : 'DTS-HD HRA', 'DTS XLL' : 'DTS-HD MA', 'DTS ES XLL' : 'DTS-HD MA', 'DTS ES XXCH XLL' : 'DTS-HD MA', 'DTS XLL X' : 'DTS X', 'MLP FBA' : 'TrueHD', 'MLP FBA 16 ch' : 'TrueHD Atmos' ] def audioStreams = [] def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') } def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') } def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') } def dString = { it.toDouble().toString() } def toInt = { it.toInteger() } any{audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }) def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{} def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() } { channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) } def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null ) def combined = allOf{codec}{format_profile}.join(' ') audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null}, 'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}, 'lang' : any{ au.'LanguageString3'.upperInitial() }{null} ] return audioStreams } def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort() def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' ') def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() }) def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }) def defaultStream = oneStream(audioStreams.findAll{ it.default == true }) def bestPreferredLang = any{ audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }*.minus(null).unique().get(0).join(' ') }{} allStreams.join(' & ').space('.') preferredStream.space('.') defaultStream.space('.') bestBitRate.space('.') [defaultStream, bestBitRate].unique().join(' & ').space('.') [bestBitRate, preferredStream].unique().join(' & ').space('.') any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream} }{'NO_AUDIO'} }useChFilter = this line:Code: Select all
allStreams.join(' & ').space('.') preferredStream.space('.') defaultStream.space('.') bestBitRate.space('.') [defaultStream, bestBitRate].unique().join(' & ').space('.') [bestBitRate, preferredStream].unique().join(' & ').space('.') any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}= if AAC/MP3 2.0 OR AC3/EAC3/DTS/TrueHD/MLPFBA 5.1, then don't show the 2.0/5.1 partCode: Select all
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
allStreams = All Audio Streams
preferredStream = The last (best) match from codecList (order matters, from low to high quality / or what you prefer)
defaultStream = The Audio Stream tagged "default=Yes" or if only one Stream
bestBitRate = The Audio Stream with the highest BitRate (with BitRate_Maximum/FrameRate as backup)
Code: Select all
movieFormat={plex.derive{' ' + tags.join(' ')}{' [' + allOf{vs}{vf}{hdr}{ac}{channels}{vc.replace('AVC','x264').replace('ATEME', 'H.265').replace('Microsoft', 'VC-1').replace('HEVC','x265')}{fn.match(/REMUX/).upper()}.join(' ') + ']' + {'-' + group}}.tail}
seriesFormat={plex.derive{' ' + tags.join(' ')}{' [' + allOf{vs}{vf}{hdr}{ac}{channels}{vc.replace('AVC','x264').replace('ATEME', 'H.265').replace('Microsoft', 'VC-1').replace('HEVC','x265')}{fn.match(/REMUX/).upper()}.join(' ') + ']' + {'-' + group}}.tail}
animeFormat={plex.derive{' ' + tags.join(' ')}{' [' + allOf{vs}{vf}{hdr}{ac}{channels}{vc.replace('AVC','x264').replace('ATEME', 'H.265').replace('Microsoft', 'VC-1').replace('HEVC','x265')}{fn.match(/REMUX/).upper()}.join(' ') + ']' + {'-' + group}}.tail}Code: Select all
{ac}{channels}Code: Select all
{plex.derive{' ' + tags.join(' ')}{' [' + allOf{vs}{vf}{hdr}{
def preferredLang = 'Eng'
def useChFilter = false
def filter = { [it.codec, it.ch, it.objects, it.lang] }
def codecList =
[
'MP3' : 'MP3',
'PCM' : 'PCM',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}, 'lang' : any{ au.'LanguageString3'.upperInitial() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' ')
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = oneStream(audioStreams.findAll{ it.default == true })
def bestPreferredLang = any{ audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }*.minus(null).unique().get(0).join(' ') }{}
any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}
}{vc.replace('AVC','x264').replace('ATEME', 'H.265').replace('Microsoft', 'VC-1').replace('HEVC','x265')}{fn.match(/REMUX/).upper()}.join(' ') + ']' + {'-' + group}}.tail}Code: Select all
{ def preferredLang = 'Eng'; def useChFilter = false; def filter = { [it.codec, it.ch, it.objects, it.lang] };Code: Select all
{plex.derive{' ' + tags.join(' ')}{' [' + allOf{vs}{vf}{hdr}{def preferredLang = 'Eng'; def useChFilter = false; def filter = { [it.codec, it.ch, it.objects, it.lang] }; def codecList = ['MP3' : 'MP3','PCM' : 'PCM','AAC LC' : 'AAC','AAC LC SBR' : 'AAC','AAC LC SBR PS' : 'AAC','AC 3' : 'AC3','AC 3 Dep' : 'EAC3','E AC 3' : 'EAC3','E AC 3 JOC' : 'EAC3 Atmos','AC 3 Dep JOC' : 'EAC3 Atmos','DTS' : 'DTS','DTS 96 24' : 'DTS 96-24','DTS ES' : 'DTS-ES','DTS ES XXCH' : 'DTS-ES','DTS XBR' : 'DTS-HD HRA','DTS ES XBR' : 'DTS-HD HRA','DTS ES XXCH XBR' : 'DTS-HD HRA','DTS XLL' : 'DTS-HD MA','DTS ES XLL' : 'DTS-HD MA','DTS ES XXCH XLL' : 'DTS-HD MA','DTS XLL X' : 'DTS X','MLP FBA' : 'TrueHD','MLP FBA 16 ch' : 'TrueHD Atmos']; def audioStreams = []; def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }; def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }; def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') }; def dString = { it.toDouble().toString() }; def toInt = { it.toInteger() }; any{audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }); def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}; def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }; def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null ); def combined = allOf{codec}{format_profile}.join(' '); audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}, 'lang' : any{ au.'LanguageString3'.upperInitial() }{null} ]; return audioStreams}; def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort(); def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' '); def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() }); def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }); def defaultStream = oneStream(audioStreams.findAll{ it.default == true }); def bestPreferredLang = any{ audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }*.minus(null).unique().get(0).join(' ') }{}; any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}}{'NO_AUDIO'}}{vc.replace('AVC','x264').replace('ATEME', 'H.265').replace('Microsoft', 'VC-1').replace('HEVC','x265')}{fn.match(/REMUX/).upper()}.join(' ') + ']' + {'-' + group}}.tail}Code: Select all
{vc}{ac}Wow, thank you so much for the help! This helps a lot!kim wrote: 30 Jul 2020, 17:45 very easy just replace thelike so:Code: Select all
{ac}{channels}if you really want is on one line just add a ; after all the "def blocks"e.g.Code: Select all
{plex.derive{' ' + tags.join(' ')}{' [' + allOf{vs}{vf}{hdr}{ def preferredLang = 'Eng' def useChFilter = false def filter = { [it.codec, it.ch, it.objects, it.lang] } def codecList = [ 'MP3' : 'MP3', 'PCM' : 'PCM', 'AAC LC' : 'AAC', 'AAC LC SBR' : 'AAC', 'AAC LC SBR PS' : 'AAC', 'AC 3' : 'AC3', 'AC 3 Dep' : 'EAC3', 'E AC 3' : 'EAC3', 'E AC 3 JOC' : 'EAC3 Atmos', 'AC 3 Dep JOC' : 'EAC3 Atmos', 'DTS' : 'DTS', 'DTS 96 24' : 'DTS 96-24', 'DTS ES' : 'DTS-ES', 'DTS ES XXCH' : 'DTS-ES', 'DTS XBR' : 'DTS-HD HRA', 'DTS ES XBR' : 'DTS-HD HRA', 'DTS ES XXCH XBR' : 'DTS-HD HRA', 'DTS XLL' : 'DTS-HD MA', 'DTS ES XLL' : 'DTS-HD MA', 'DTS ES XXCH XLL' : 'DTS-HD MA', 'DTS XLL X' : 'DTS X', 'MLP FBA' : 'TrueHD', 'MLP FBA 16 ch' : 'TrueHD Atmos' ] def audioStreams = [] def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') } def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') } def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') } def dString = { it.toDouble().toString() } def toInt = { it.toInteger() } any{audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }) def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{} def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() } { channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) } def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null ) def combined = allOf{codec}{format_profile}.join(' ') audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null}, 'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}, 'lang' : any{ au.'LanguageString3'.upperInitial() }{null} ] return audioStreams } def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort() def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' ') def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() }) def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }) def defaultStream = oneStream(audioStreams.findAll{ it.default == true }) def bestPreferredLang = any{ audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }*.minus(null).unique().get(0).join(' ') }{} any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream} }{'NO_AUDIO'} }{vc.replace('AVC','x264').replace('ATEME', 'H.265').replace('Microsoft', 'VC-1').replace('HEVC','x265')}{fn.match(/REMUX/).upper()}.join(' ') + ']' + {'-' + group}}.tail}Code: Select all
{ def preferredLang = 'Eng'; def useChFilter = false; def filter = { [it.codec, it.ch, it.objects, it.lang] };btw: the normal way is video before audioCode: Select all
{plex.derive{' ' + tags.join(' ')}{' [' + allOf{vs}{vf}{hdr}{def preferredLang = 'Eng'; def useChFilter = false; def filter = { [it.codec, it.ch, it.objects, it.lang] }; def codecList = ['MP3' : 'MP3','PCM' : 'PCM','AAC LC' : 'AAC','AAC LC SBR' : 'AAC','AAC LC SBR PS' : 'AAC','AC 3' : 'AC3','AC 3 Dep' : 'EAC3','E AC 3' : 'EAC3','E AC 3 JOC' : 'EAC3 Atmos','AC 3 Dep JOC' : 'EAC3 Atmos','DTS' : 'DTS','DTS 96 24' : 'DTS 96-24','DTS ES' : 'DTS-ES','DTS ES XXCH' : 'DTS-ES','DTS XBR' : 'DTS-HD HRA','DTS ES XBR' : 'DTS-HD HRA','DTS ES XXCH XBR' : 'DTS-HD HRA','DTS XLL' : 'DTS-HD MA','DTS ES XLL' : 'DTS-HD MA','DTS ES XXCH XLL' : 'DTS-HD MA','DTS XLL X' : 'DTS X','MLP FBA' : 'TrueHD','MLP FBA 16 ch' : 'TrueHD Atmos']; def audioStreams = []; def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }; def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }; def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') }; def dString = { it.toDouble().toString() }; def toInt = { it.toInteger() }; any{audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }); def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}; def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }; def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null ); def combined = allOf{codec}{format_profile}.join(' '); audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}, 'lang' : any{ au.'LanguageString3'.upperInitial() }{null} ]; return audioStreams}; def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort(); def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' '); def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() }); def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }); def defaultStream = oneStream(audioStreams.findAll{ it.default == true }); def bestPreferredLang = any{ audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }*.minus(null).unique().get(0).join(' ') }{}; any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}}{'NO_AUDIO'}}{vc.replace('AVC','x264').replace('ATEME', 'H.265').replace('Microsoft', 'VC-1').replace('HEVC','x265')}{fn.match(/REMUX/).upper()}.join(' ') + ']' + {'-' + group}}.tail}Code: Select all
{vc}{ac}
Tried to edit it as you said. How does that look and how would you do it?btw: the normal way is video before audioCode: Select all
{vc}{ac}
Code: Select all
{plex.derive{' ' + tags.join(' ')}{' [' + allOf{vs}{vf}{hdr}{vc.replace('AVC','x264').replace('ATEME', 'H.265').replace('Microsoft', 'VC-1').replace('HEVC','x265')}{fn.match(/REMUX/).upper()}{def preferredLang = 'Eng'; def useChFilter = false; def filter = { [it.codec, it.ch, it.objects, it.lang] }; def codecList = ['MP3' : 'MP3','PCM' : 'PCM','AAC LC' : 'AAC','AAC LC SBR' : 'AAC','AAC LC SBR PS' : 'AAC','AC 3' : 'AC3','AC 3 Dep' : 'EAC3','E AC 3' : 'EAC3','E AC 3 JOC' : 'EAC3 Atmos','AC 3 Dep JOC' : 'EAC3 Atmos','DTS' : 'DTS','DTS 96 24' : 'DTS 96-24','DTS ES' : 'DTS-ES','DTS ES XXCH' : 'DTS-ES','DTS XBR' : 'DTS-HD HRA','DTS ES XBR' : 'DTS-HD HRA','DTS ES XXCH XBR' : 'DTS-HD HRA','DTS XLL' : 'DTS-HD MA','DTS ES XLL' : 'DTS-HD MA','DTS ES XXCH XLL' : 'DTS-HD MA','DTS XLL X' : 'DTS X','MLP FBA' : 'TrueHD','MLP FBA 16 ch' : 'TrueHD Atmos']; def audioStreams = []; def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }; def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }; def oneStream = { it.collect{ filter(it) }*.minus(null).unique().flatten().join(' ') }; def dString = { it.toDouble().toString() }; def toInt = { it.toInteger() }; any{audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }); def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}; def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }; def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null ); def combined = allOf{codec}{format_profile}.join(' '); audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}, 'lang' : any{ au.'LanguageString3'.upperInitial() }{null} ]; return audioStreams}; def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort(); def allStreams = audioStreams.collect{ filter(it) }*.minus(null).unique()*.join(' '); def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() }); def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }); def defaultStream = oneStream(audioStreams.findAll{ it.default == true }); def bestPreferredLang = any{ audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }*.minus(null).unique().get(0).join(' ') }{}; any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}}{'NO_AUDIO'}}.join(' ') + ']' + {'-' + group}}.tail}
Code: Select all
{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}Code: Select all
Audio #1
Count : 294
Count of stream of this kind : 3
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 0
Stream identifier : 1
StreamOrder : 1
ID : 2
ID : 2
Unique ID : 2
Format : AC-3
Format : AC-3
Format/Info : Audio Coding 3
Format/Url : https://en.wikipedia.org/wiki/AC3
Commercial name : Dolby Digital
Commercial name : Dolby Digital
Format settings, Endianness : Big
Codec ID : A_AC3
Duration : 6054117
Duration : 1 h 40 min
Duration : 1 h 40 min 54 s 117 ms
Duration : 1 h 40 min
Duration : 01:40:54.117
Duration : 01:40:54.117
Bit rate mode : CBR
Bit rate mode : Constant
Bit rate : 384000
Bit rate : 384 kb/s
Channel(s) : 6
Channel(s) : 6 channels
Channel positions : Front: L C R, Side: L R, LFE
Channel positions : 3/2/0.1
Channel layout : L R C LFE Ls Rs
Samples per frame : 1536
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 290597616
Frame rate : 31.250
Frame rate : 31.250 FPS (1536 SPF)
Compression mode : Lossy
Compression mode : Lossy
Delay : 78
Delay : 78 ms
Delay : 78 ms
Delay : 78 ms
Delay : 00:00:00.078
Delay, origin : Container
Delay, origin : Container
Delay relative to video : -5
Delay relative to video : -5 ms
Delay relative to video : -5 ms
Delay relative to video : -5 ms
Delay relative to video : -00:00:00.005
Stream size : 290597616
Stream size : 277 MiB (12%)
Stream size : 277 MiB
Stream size : 277 MiB
Stream size : 277 MiB
Stream size : 277.1 MiB
Stream size : 277 MiB (12%)
Proportion of this stream : 0.12196
Title : VFF AC3 5.1
Language : fr
Language : French
Language : French
Language : fr
Language : fra
Language : fr
Service kind : CM
Service kind : Complete Main
Default : Yes
Default : Yes
Forced : No
Forced : No
bsid : 8
Dialog Normalization : -31
Dialog Normalization : -31 dB
acmod : 7
lfeon : 1
dialnorm_Average : -31
dialnorm_Average : -31 dB
dialnorm_Minimum : -31
dialnorm_Minimum : -31 dB
dialnorm_Maximum : -31
dialnorm_Maximum : -31 dB
dialnorm_Count : 1002
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Audio #2
Count : 294
Count of stream of this kind : 3
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 1
Stream identifier : 2
StreamOrder : 2
ID : 3
ID : 3
Unique ID : 3
Format : AC-3
Format : AC-3
Format/Info : Audio Coding 3
Format/Url : https://en.wikipedia.org/wiki/AC3
Commercial name : Dolby Digital
Commercial name : Dolby Digital
Format settings, Endianness : Big
Codec ID : A_AC3
Duration : 6054117
Duration : 1 h 40 min
Duration : 1 h 40 min 54 s 117 ms
Duration : 1 h 40 min
Duration : 01:40:54.117
Duration : 01:40:54.117
Bit rate mode : CBR
Bit rate mode : Constant
Bit rate : 384000
Bit rate : 384 kb/s
Channel(s) : 6
Channel(s) : 6 channels
Channel positions : Front: L C R, Side: L R, LFE
Channel positions : 3/2/0.1
Channel layout : L R C LFE Ls Rs
Samples per frame : 1536
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 290597616
Frame rate : 31.250
Frame rate : 31.250 FPS (1536 SPF)
Compression mode : Lossy
Compression mode : Lossy
Delay : 78
Delay : 78 ms
Delay : 78 ms
Delay : 78 ms
Delay : 00:00:00.078
Delay, origin : Container
Delay, origin : Container
Delay relative to video : -5
Delay relative to video : -5 ms
Delay relative to video : -5 ms
Delay relative to video : -5 ms
Delay relative to video : -00:00:00.005
Stream size : 290597616
Stream size : 277 MiB (12%)
Stream size : 277 MiB
Stream size : 277 MiB
Stream size : 277 MiB
Stream size : 277.1 MiB
Stream size : 277 MiB (12%)
Proportion of this stream : 0.12196
Title : Anglais AC3 5.1
Language : en
Language : English
Language : English
Language : en
Language : eng
Language : en
Service kind : CM
Service kind : Complete Main
Default : No
Default : No
Forced : No
Forced : No
bsid : 8
Dialog Normalization : -31
Dialog Normalization : -31 dB
acmod : 7
lfeon : 1
dialnorm_Average : -31
dialnorm_Average : -31 dB
dialnorm_Minimum : -31
dialnorm_Minimum : -31 dB
dialnorm_Maximum : -31
dialnorm_Maximum : -31 dB
dialnorm_Count : 1002
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Audio #3
Count : 282
Count of stream of this kind : 3
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 2
Stream identifier : 3
StreamOrder : 3
ID : 4
ID : 4
Unique ID : 4
Format : AAC
Format : AAC LC
Format/Info : Advanced Audio Codec Low Complexity
Commercial name : AAC
Format_AdditionalFeatures : LC
Codec ID : A_AAC-2
Duration : 6054117
Duration : 1 h 40 min
Duration : 1 h 40 min 54 s 117 ms
Duration : 1 h 40 min
Duration : 01:40:54.117
Duration : 01:40:54.117
Channel(s) : 2
Channel(s) : 2 channels
Channel positions : Front: L R
Channel positions : 2/0/0
Channel layout : L R
Samples per frame : 1024
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 290597616
Frame rate : 46.875
Frame rate : 46.875 FPS (1024 SPF)
Compression mode : Lossy
Compression mode : Lossy
Delay : 41
Delay : 41 ms
Delay : 41 ms
Delay : 41 ms
Delay : 00:00:00.041
Delay, origin : Container
Delay, origin : Container
Delay relative to video : -42
Delay relative to video : -42 ms
Delay relative to video : -42 ms
Delay relative to video : -42 ms
Delay relative to video : -00:00:00.042
Title : VFF AAC 2.0
Language : fr
Language : French
Language : French
Language : fr
Language : fra
Language : fr
Default : No
Default : No
Forced : No
Forced : No
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Code: Select all
Audio #1
Count : 282
Count of stream of this kind : 2
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 0
Stream identifier : 1
StreamOrder : 1
ID : 2
ID : 2
Unique ID : 17475167537096227729
Format : AAC
Format : AAC LC
Format/Info : Advanced Audio Codec Low Complexity
Commercial name : AAC
Format_AdditionalFeatures : LC
Codec ID : A_AAC-2
Duration : 5115584
Duration : 1 h 25 min
Duration : 1 h 25 min 15 s 584 ms
Duration : 1 h 25 min
Duration : 01:25:15.584
Duration : 01:25:15.584
Channel(s) : 2
Channel(s) : 2 channels
Channel positions : Front: L R
Channel positions : 2/0/0
Channel layout : L R
Samples per frame : 1024
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 245548032
Frame rate : 46.875
Frame rate : 46.875 FPS (1024 SPF)
Compression mode : Lossy
Compression mode : Lossy
Delay : 0
Delay : 00:00:00.000
Delay, origin : Container
Delay, origin : Container
Delay relative to video : -83
Delay relative to video : -83 ms
Delay relative to video : -83 ms
Delay relative to video : -83 ms
Delay relative to video : -00:00:00.083
Title : VFF AAC 2.0
Language : fr
Language : French
Language : French
Language : fr
Language : fra
Language : fr
Default : Yes
Default : Yes
Forced : No
Forced : No
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Audio #2
Count : 294
Count of stream of this kind : 2
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 1
Stream identifier : 2
StreamOrder : 2
ID : 3
ID : 3
Unique ID : 3
Format : AC-3
Format : AC-3
Format/Info : Audio Coding 3
Format/Url : https://en.wikipedia.org/wiki/AC3
Commercial name : Dolby Digital
Commercial name : Dolby Digital
Format settings, Endianness : Big
Codec ID : A_AC3
Duration : 5115584
Duration : 1 h 25 min
Duration : 1 h 25 min 15 s 584 ms
Duration : 1 h 25 min
Duration : 01:25:15.584
Duration : 01:25:15.584
Bit rate mode : CBR
Bit rate mode : Constant
Bit rate : 384000
Bit rate : 384 kb/s
Channel(s) : 6
Channel(s) : 6 channels
Channel positions : Front: L C R, Side: L R, LFE
Channel positions : 3/2/0.1
Channel layout : L R C LFE Ls Rs
Samples per frame : 1536
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 245548032
Frame rate : 31.250
Frame rate : 31.250 FPS (1536 SPF)
Compression mode : Lossy
Compression mode : Lossy
Delay : 78
Delay : 78 ms
Delay : 78 ms
Delay : 78 ms
Delay : 00:00:00.078
Delay, origin : Container
Delay, origin : Container
Delay relative to video : -5
Delay relative to video : -5 ms
Delay relative to video : -5 ms
Delay relative to video : -5 ms
Delay relative to video : -00:00:00.005
Stream size : 245548032
Stream size : 234 MiB (14%)
Stream size : 234 MiB
Stream size : 234 MiB
Stream size : 234 MiB
Stream size : 234.2 MiB
Stream size : 234 MiB (14%)
Proportion of this stream : 0.13658
Title : Anglais AC3 5.1
Language : en
Language : English
Language : English
Language : en
Language : eng
Language : en
Service kind : CM
Service kind : Complete Main
Default : No
Default : No
Forced : No
Forced : No
bsid : 8
Dialog Normalization : -31
Dialog Normalization : -31 dB
acmod : 7
lfeon : 1
dialnorm_Average : -31
dialnorm_Average : -31 dB
dialnorm_Minimum : -31
dialnorm_Minimum : -31 dB
dialnorm_Maximum : -31
dialnorm_Maximum : -31 dB
dialnorm_Count : 1504
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Code: Select all
Audio #1
Count : 282
Count of stream of this kind : 6
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 0
Stream identifier : 1
StreamOrder : 1
ID : 2
ID : 2
Unique ID : 1810417575
Format : DTS
Format : DTS
Format/Info : Digital Theater Systems
Format/Url : https://en.wikipedia.org/wiki/DTS_(sound_system)
Commercial name : DTS
Mode : 16
Format settings, Endianness : Big
Codec ID : A_DTS
Duration : 7501909
Duration : 2 h 5 min
Duration : 2 h 5 min 1 s 909 ms
Duration : 2 h 5 min
Duration : 02:05:01.909
Duration : 02:05:01.909
Bit rate mode : CBR
Bit rate mode : Constant
Bit rate : 754500
Bit rate : 754 kb/s
Channel(s) : 6
Channel(s) : 6 channels
Channel positions : Front: L C R, Side: L R, LFE
Channel positions : 3/2/0.1
Channel layout : C L R Ls Rs LFE
Samples per frame : 512
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 360091632
Frame rate : 93.750
Frame rate : 93.750 FPS (512 SPF)
Bit depth : 24
Bit depth : 24 bits
Compression mode : Lossy
Compression mode : Lossy
Delay : 0
Delay : 00:00:00.000
Delay, origin : Container
Delay, origin : Container
Delay relative to video : 0
Delay relative to video : 00:00:00.000
Stream size : 707523792
Stream size : 675 MiB (9%)
Stream size : 675 MiB
Stream size : 675 MiB
Stream size : 675 MiB
Stream size : 674.7 MiB
Stream size : 675 MiB (9%)
Proportion of this stream : 0.09197
Language : en
Language : English
Language : English
Language : en
Language : eng
Language : en
Default : No
Default : No
Forced : No
Forced : No
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Audio #2
Count : 282
Count of stream of this kind : 6
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 1
Stream identifier : 2
StreamOrder : 2
ID : 3
ID : 3
Unique ID : 4936
Format : AAC
Format : AAC LC
Format/Info : Advanced Audio Codec Low Complexity
Commercial name : AAC
Format_AdditionalFeatures : LC
Codec ID : A_AAC-2
Duration : 7501909
Duration : 2 h 5 min
Duration : 2 h 5 min 1 s 909 ms
Duration : 2 h 5 min
Duration : 02:05:01.909
Duration : 02:05:01.909
Channel(s) : 2
Channel(s) : 2 channels
Channel positions : Front: L R
Channel positions : 2/0/0
Channel layout : L R
Samples per frame : 1024
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 360091632
Frame rate : 46.875
Frame rate : 46.875 FPS (1024 SPF)
Compression mode : Lossy
Compression mode : Lossy
Delay : 0
Delay : 00:00:00.000
Delay, origin : Container
Delay, origin : Container
Delay relative to video : 0
Delay relative to video : 00:00:00.000
Language : fr
Language : French
Language : French
Language : fr
Language : fra
Language : fr
Default : No
Default : No
Forced : No
Forced : No
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Audio #3
Count : 282
Count of stream of this kind : 6
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 2
Stream identifier : 3
StreamOrder : 3
ID : 4
ID : 4
Unique ID : 15050
Format : AAC
Format : AAC LC
Format/Info : Advanced Audio Codec Low Complexity
Commercial name : AAC
Format_AdditionalFeatures : LC
Codec ID : A_AAC-2
Duration : 7501909
Duration : 2 h 5 min
Duration : 2 h 5 min 1 s 909 ms
Duration : 2 h 5 min
Duration : 02:05:01.909
Duration : 02:05:01.909
Channel(s) : 2
Channel(s) : 2 channels
Channel positions : Front: L R
Channel positions : 2/0/0
Channel layout : L R
Samples per frame : 1024
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 360091632
Frame rate : 46.875
Frame rate : 46.875 FPS (1024 SPF)
Compression mode : Lossy
Compression mode : Lossy
Delay : 0
Delay : 00:00:00.000
Delay, origin : Container
Delay, origin : Container
Delay relative to video : 0
Delay relative to video : 00:00:00.000
Language : pt
Language : Portuguese
Language : Portuguese
Language : pt
Language : por
Language : pt
Default : No
Default : No
Forced : No
Forced : No
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Audio #4
Count : 282
Count of stream of this kind : 6
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 3
Stream identifier : 4
StreamOrder : 4
ID : 5
ID : 5
Unique ID : 25636
Format : AAC
Format : AAC LC
Format/Info : Advanced Audio Codec Low Complexity
Commercial name : AAC
Format_AdditionalFeatures : LC
Codec ID : A_AAC-2
Duration : 7501909
Duration : 2 h 5 min
Duration : 2 h 5 min 1 s 909 ms
Duration : 2 h 5 min
Duration : 02:05:01.909
Duration : 02:05:01.909
Channel(s) : 2
Channel(s) : 2 channels
Channel positions : Front: L R
Channel positions : 2/0/0
Channel layout : L R
Samples per frame : 1024
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 360091632
Frame rate : 46.875
Frame rate : 46.875 FPS (1024 SPF)
Compression mode : Lossy
Compression mode : Lossy
Delay : 0
Delay : 00:00:00.000
Delay, origin : Container
Delay, origin : Container
Delay relative to video : 0
Delay relative to video : 00:00:00.000
Language : ru
Language : Russian
Language : Russian
Language : ru
Language : rus
Language : ru
Default : No
Default : No
Forced : No
Forced : No
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Audio #5
Count : 282
Count of stream of this kind : 6
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 4
Stream identifier : 5
StreamOrder : 5
ID : 6
ID : 6
Unique ID : 384
Format : AAC
Format : AAC LC
Format/Info : Advanced Audio Codec Low Complexity
Commercial name : AAC
Format_AdditionalFeatures : LC
Codec ID : A_AAC-2
Duration : 7501909
Duration : 2 h 5 min
Duration : 2 h 5 min 1 s 909 ms
Duration : 2 h 5 min
Duration : 02:05:01.909
Duration : 02:05:01.909
Channel(s) : 2
Channel(s) : 2 channels
Channel positions : Front: L R
Channel positions : 2/0/0
Channel layout : L R
Samples per frame : 1024
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 360091632
Frame rate : 46.875
Frame rate : 46.875 FPS (1024 SPF)
Compression mode : Lossy
Compression mode : Lossy
Delay : 0
Delay : 00:00:00.000
Delay, origin : Container
Delay, origin : Container
Delay relative to video : 0
Delay relative to video : 00:00:00.000
Language : es
Language : Spanish
Language : Spanish
Language : es
Language : spa
Language : es
Default : No
Default : No
Forced : No
Forced : No
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Audio #6
Count : 282
Count of stream of this kind : 6
Kind of stream : Audio
Kind of stream : Audio
Stream identifier : 5
Stream identifier : 6
StreamOrder : 6
ID : 7
ID : 7
Unique ID : 9511
Format : AAC
Format : AAC LC
Format/Info : Advanced Audio Codec Low Complexity
Commercial name : AAC
Format_AdditionalFeatures : LC
Codec ID : A_AAC-2
Duration : 7501909
Duration : 2 h 5 min
Duration : 2 h 5 min 1 s 909 ms
Duration : 2 h 5 min
Duration : 02:05:01.909
Duration : 02:05:01.909
Channel(s) : 2
Channel(s) : 2 channels
Channel positions : Front: L R
Channel positions : 2/0/0
Channel layout : L R
Samples per frame : 1024
Sampling rate : 48000
Sampling rate : 48.0 kHz
Samples count : 360091632
Frame rate : 46.875
Frame rate : 46.875 FPS (1024 SPF)
Compression mode : Lossy
Compression mode : Lossy
Delay : 0
Delay : 00:00:00.000
Delay, origin : Container
Delay, origin : Container
Delay relative to video : 0
Delay relative to video : 00:00:00.000
Language : uk
Language : Ukrainian
Language : Ukrainian
Language : uk
Language : ukr
Language : uk
Default : No
Default : No
Forced : No
Forced : No
SamplingCount_Source : General_Duration
Duration_Source : General_Duration
Code: Select all
'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}Code: Select all
{
def preferredLang = 'Fra'
def useChFilter = false
def filter = { [it.codec, it.ch, it.objects, it.lang].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/\p{Punct}/, ' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
def oneStream = { listStream(it)[0] }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().sum() }
{ channelClean(au.ChannelLayout_Original).split().collect{ it == 'LFE' ? 0.1 : 1 }.sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ au.FrameRate.toDouble() }{null},
'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString3'.upperInitial() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = listStream(audioStreams)
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams.findAll{ !it.default }) }
def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}
}Code: Select all
{bestPreferredLang}Code: Select all
{[bestPreferredLang, bestBitRate].findAll().unique().join(' & ')}Code: Select all
any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}Code: Select all
{[bestPreferredLang, bestBitRate].findAll().unique().join(' & ')}Code: Select all
any{addToList}{[bestPreferredLang, bestBitRate].findAll().unique().join(' & ')}{defaultStream}{bestBitRate}{preferredStream}What is the "best" and "NOT the Best" ?(it gives me a result but not the "best bitrate").
Code: Select all
audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }same result... to confirm remove unique partI only get 1 result even if there should be 2 independent results for some movies
Code: Select all
def bestBitRateCode: Select all
{[bestPreferredLang, bestBitRate]...}Code: Select all
[bestPreferredLang, bestBitRate]...Code: Select all
{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }Code: Select all
{ toInt(au.BitRate_Maximum) }{ toInt(au.BitRate) }



Code: Select all
any{addToList}{[bestPreferredLang, bestBitRate].findAll().unique().join(' & ')}{defaultStream}{bestBitRate}{preferredStream}Code: Select all
[bestPreferredLang, bestBitRate].findAll().unique().join(' & ')Code: Select all
audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }.codec == audioStreams.findAll{ it.lang == preferredLang }.codec ? bestPreferredLang:[bestPreferredLang, bestBitRate].join(' & ')Code: Select all
audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() || it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.sort{ it.lang != preferredLang }.unique{ it.lang }.unique{ it.bitrate }.collect{ filter(it) }*.join(' ').join(' & ')Code: Select all
audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() || it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate ?: preferredLang <=> b.lang}.unique{ it.lang }.unique{ it.bitrate }.collect{ filter(it) }*.join(' ').join(' & ')Code: Select all
audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() || it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.sort{ it.lang != preferredLang }.unique{ it.lang }.unique{ it.bitrate }.collect{ filter(it) }*.join(' ').join(' & ')
Code: Select all
audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() || it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate ?: preferredLang <=> b.lang}.unique{ it.lang }.unique{ it.bitrate }.collect{ filter(it) }*.join(' ').join(' & ')
Code: Select all
( audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate } 999 audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }.sort{ a, b -> b.default <=> a.default }.unique{ it.bitrate } ).unique{ it.lang }.collect{ filter(it) }*.join(' ').join(' 777 ')Me too... Might need to move custom format talk to the Discord channel.
Code: Select all
( audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate } + audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }.sort{ a, b -> b.default <=> a.default }.unique{ it.bitrate } ).unique{ it.lang }.collect{ filter(it) }*.join(' ').join(' 777 ')
Code: Select all
.unique{ it.codec }Code: Select all
.unique{ it.lang }.unique{ it.codec }.collect{ filter(it) }*.join(' ').join(' & ')Code: Select all
audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() || it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.sort{ it.lang != preferredLang }.unique{ it.lang }.unique{ it.codec }.collect{ filter(it) }*.join(' ').join(' & ')Code: Select all
def preferredLang = 'FR'
def useChFilter = false
//def filter = { [it.codec, it.ch, it.objects, it.lang].findAll() }
def filter = { [it.codec, it.ch, it.lang].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ au.FrameRate.toDouble() }{null},
'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
return audioStreams
}
audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() || it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate }.sort{ it.lang != preferredLang }.unique{ it.lang }.unique{ it.codec }.collect{ filter(it) }*.join(' ').join(' & ')
}{'NO_AUDIO'}Code: Select all
{
def preferredLang = 'FR'
def filter = { [it.codec, it.ch, it.lang].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/\p{Punct}/, ' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
def oneStream = { listStream(it)[0] }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().sum() }
{ channelClean(au.ChannelLayout_Original).split().collect{ it == 'LFE' ? 0.1 : 1 }.sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add "' + combined + '" to codecList'), 'combined' : combined, 'ch' : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ au.FrameRate.toDouble() }{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
}
def addToList = audioStreams.codec.findAll{ it.contains('to codecList') }.unique().sort()
any{addToList}{( audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate } + audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }.sort{ a, b -> b.default <=> a.default }.unique{ it.bitrate } ).unique{ it.lang }.unique{ it.codec }.collect{ filter(it) }*.join(' ').join(' & ')}
}{'NO_AUDIO'}
}Hello, I would like you to add all the audios, but only the ones with the highest rate, that is, imagine that I have a video with these audios:kim wrote: 08 Feb 2021, 04:28 e.g. addToList = [Add "AC 3" to codecList, Add "DTS XLL" to codecList, Add "DTS" to codecList]
This is the final result:Code: Select all
{ def preferredLang = 'FR' def filter = { [it.codec, it.ch, it.lang].findAll() } def codecList = [ 'MPEG Audio' : 'MP2', 'MP3' : 'MP3', 'PCM' : 'PCM', 'FLAC' : 'FLAC', 'AAC LC' : 'AAC', 'AAC LC SBR' : 'AAC', 'AAC LC SBR PS' : 'AAC', 'AC 3' : 'AC3', 'AC 3 Dep' : 'EAC3', 'E AC 3' : 'EAC3', 'E AC 3 JOC' : 'EAC3 Atmos', 'AC 3 Dep JOC' : 'EAC3 Atmos', 'DTS' : 'DTS', 'DTS 96 24' : 'DTS 96-24', 'DTS ES' : 'DTS-ES', 'DTS ES XXCH' : 'DTS-ES', 'DTS XBR' : 'DTS-HD HRA', 'DTS ES XBR' : 'DTS-HD HRA', 'DTS ES XXCH XBR' : 'DTS-HD HRA', 'DTS XLL' : 'DTS-HD MA', 'DTS ES XLL' : 'DTS-HD MA', 'DTS ES XXCH XLL' : 'DTS-HD MA', 'DTS XLL X' : 'DTS X', 'MLP FBA' : 'TrueHD', 'MLP FBA 16 ch' : 'TrueHD Atmos' ] def audioStreams = [] def audioClean = { it.replaceAll(/\p{Punct}/, ' ') } def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') } def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') } def oneStream = { listStream(it)[0] } def dString = { it.toDouble().toString() } def toInt = { it.toInteger() } any{audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }) def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{} def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().sum() } { channelClean(au.ChannelLayout_Original).split().collect{ it == 'LFE' ? 0.1 : 1 }.sum() } { channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) } def combined = allOf{codec}{format_profile}.join(' ') audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'codec' : codecList.get(combined, 'Add "' + combined + '" to codecList'), 'combined' : combined, 'ch' : ch, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ au.FrameRate.toDouble() }{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ] } def addToList = audioStreams.codec.findAll{ it.contains('to codecList') }.unique().sort() any{addToList}{( audioStreams.findAll{ it.lang == preferredLang }.sort{ a, b -> b.bitrate <=> a.bitrate } + audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }.sort{ a, b -> b.default <=> a.default }.unique{ it.bitrate } ).unique{ it.lang }.unique{ it.codec }.collect{ filter(it) }*.join(' ').join(' & ')} }{'NO_AUDIO'} }
Code: Select all
{
def preferredLang = 'FR'
def useChFilter = false
def filter = { [it.lang, it.codec, it.ch, it.objects].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
def oneStream = { listStream(it)[0] }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = listStream(audioStreams)
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
any{addToList}{bestBitRateAllLang}{[bestPreferredLang, bestBitRate].findAll().join(' & ')}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}
}EN DTS-HD MA 7.1 - FR AC3 5.1 - IT AC3 5.1 - ES AC3 5.1 - NL AC3 5.1 - CA AC3 5.1
Code: Select all
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')Code: Select all
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).toString().split(', ').join(' - ')Code: Select all
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).joining(' - ', ' [', ']')[EN DTS-HD MA 7.1 - FR AC3 5.1 - IT AC3 5.1 - ES AC3 5.1 - NL AC3 5.1 - CA AC3 5.1]
The desired result:EN EAC Atmos 5.1 - ES EAC3 5.1 - FR EAC3 5.1 - EN EAC3 5.1
Another feature I find interesting would be to be able to choose a 'default' audio language in the same way you allow to define the preferreded language.EN EAC Atmos 5.1 - ES|FR|EN EAC3 5.1
The desired result:MP3 2.0
Although this could be manually achieved by changing 'null' in this line for 'EN' or any other language string.EN MP3 2.0
Code: Select all
'lang' : any{ au.'LanguageString3'.upper() }{null} ]warning you cant use pipes in filename on windows... change "pipes" inEN DTS-HD MA 7.1 - EN TrueHD Atmos 7.1 - EN DTS 5.1 - EN|FR|IT|ES|NL|CA AC3 5.1
Code: Select all
it.unique{it.lang}.lang.join('|')Code: Select all
{
def preferredLang = 'FR'
def useChFilter = false
def filter = { [it.lang, it.codec, it.ch, it.objects].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
def oneStream = { listStream(it)[0] }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = listStream(audioStreams)
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
def groupCodec = audioStreams.sort{ a, b -> b.bitrate <=> a.bitrate }.groupBy{ it.codec }.values().collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.collect{ "${it.lang.replace('null', 'EN')} ${it.codec} ${it.ch}" }.join(' - ')
any{addToList}{groupCodec}{bestBitRateAllLang}{[bestPreferredLang, bestBitRate].findAll().join(' & ')}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}
}Code: Select all
it.lang.replace('null', 'EN')Code: Select all
{
def preferredLang = 'FR'
def fallbackLang = any{languages*.ISO2*.upper().join('-')}{'YourDefaultLandHere'}
def useChFilter = false
def filter = { [it.lang, it.codec, it.ch, it.objects].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
def oneStream = { listStream(it)[0] }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = listStream(audioStreams)
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
def groupCodec = audioStreams.sort{ a, b -> b.bitrate <=> a.bitrate }.groupBy{ it.codec }.values().collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.collect{ "${it.lang.replace('null', fallbackLang)} ${it.codec} ${it.ch}" }.join(' - ')
any{addToList}{groupCodec}{bestBitRateAllLang}{[bestPreferredLang, bestBitRate].findAll().join(' & ')}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}
}
Code: Select all
Rocketman (2019) (UHD.Dolby.Vision.10.IT.AC3.5.1).mkvCode: Select all
Rocketman (2019) UHD Dolby Vision 10 EN TrueHD Atmos 7.1 - IT AC3 5.1.mkvCode: Select all
Rocketman (2019) DV UHD/Rocketman (2019) (UHD.Dolby.Vision.10.IT.AC3.5.1).mkvCode: Select all
{plex} {vs} {hd} {hdr} {bitdepth}
{
def preferredLang = ‘IT’
def fallbackLang = any{languages*.ISO2*.upper().join('-')}{'YourDefaultLandHere'}
def useChFilter = false
def filter = { [it.lang, it.codec, it.ch, it.objects].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
def oneStream = { listStream(it)[0] }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = listStream(audioStreams)
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
def groupCodec = audioStreams.sort{ a, b -> b.bitrate <=> a.bitrate }.groupBy{ it.codec }.values().collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.collect{ "${it.lang.replace('null', fallbackLang)} ${it.codec} ${it.ch}" }.join(' - ')
any{addToList}{groupCodec}{bestBitRateAllLang}{[bestPreferredLang, bestBitRate].findAll().join(' & ')}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}
}Code: Select all
{plex.derive{" $hdr"}{" $hd"}.name}/{plex.name}{allOf{vs}{hd}{hdr}{bitdepth}.joining('.', ' (', '.') }
{
def preferredLang = 'IT'
def fallbackLang = any{languages*.ISO2*.upper().join('-')}{'YourDefaultLandHere'}
def useChFilter = false
def filter = { [it.lang, it.codec, it.ch].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
def oneStream = { listStream(it)[0] }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = listStream(audioStreams)
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
def groupCodec = audioStreams.sort{ a, b -> b.bitrate <=> a.bitrate }.groupBy{ it.codec }.values().collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.collect{ "${it.lang.replace('null', fallbackLang)} ${it.codec} ${it.ch}" }.join(' - ')
any{addToList}{bestPreferredLang.space('.')}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}+')'
}Thank you very much!
Code: Select all
{drive}/{n.colon(' - ')} ({y}) {" {tmdb-$id}"}/{n.colon(' - ')} ({y}) {any{fn.match(/Director.?s|director|dir(?=\s)|dir(?=\W)/) ? '[Version Director]' : ''} {fn.match(/Extended|extendida|ext(?=\s)|ext(?=\W)/)? '[V. Extendida]' : ''} {fn.match(/Cine|cinema|cinematográfica|cinematografica|cin(?=\s)|cin(?=\W)/)? '[V. Cine]' : ''} {fn.match(/unrated/)? '- UNRATED' : ''}{fn.match(/uncut/)? '- UNCUT' : ''} {'[Ed. ' + fn.match(/(\d+)(?i:th|º)?.(?i:aniversario|Anniversary|anniv(?=\s)|anniv(?=\W) aniv(?=\s)|aniv(?=\W))/) + " aniversario]"} {fn.match(/Criterion/)? '[Ed. Criterion]' : ''} {fn. match (/remastered|remasterizada|remast(?=\s)|remast(?=\W)/) ? '[Remasterizada]' : ''}} {fn.match(/rotulado castellano|Rotulado Castellano|Rotulado Español|rotulado castellano|ROTULADO CASTELLANO/) && vf=~ /1080|720/ ? '[Rotulado Castellano]': ''}{fn.match(/rotulado castellano|Rotulado Castellano|Rotulado Español|rotulado castellano|ROTULADO CASTELLANO/) && vf=~ 2160 ? '[Rotulado Castellano]': ''} [{ fn.match(/A3P/) + ' ' }{ fn.match(/ATVP/) + ' ' }{ fn.match(/ATVP[+]/) + ' ' }{ fn.match(/ATV/) + ' ' }{ fn.match(/AMZN/) + ' ' }{ fn.match(/DSNP[+]/) + ' ' }{ fn.match(/DSN[+]/) + ' ' }{ fn.match(/DSNP/) + ' ' }{ fn.match(/DSNY/) + ' ' }{ fn.match(/Disney[+]/) + ' ' }{ fn.match(/DisneyPlus/) + ' ' }{ fn.match(/STARZ/) + ' ' }{ fn.match(/HBO/) + ' ' }{ fn.match(/HMAX/) + ' ' }{ fn.match(/HULU/) + ' ' }{ fn.match(/M[+]/) + ' ' }{ fn.match(/NF/) + ' ' }{ fn.match(/IMAX/) + ' ' }{ fn.match(/FLMN/) + ' ' }{allOf {any{any{fn.match(/uhdremux|remux/) && vf=~ 2160 ? 'UHDRemux': ''}{if (megabytes>=26500 && bitrate >= 37000000 && vf=~ 2160) 'UHDRemux'}{fn.match(/uhdrip|UHDrip|mUHD|UHDrip|UHD BluRay/) && vf=~ /1080|720|2160/ ? 'UHDRip': ''}{fn.match(/bdremux|BDRemux|BDremux|BluRay Remux|remux/) && vf=~ /1080|720/ ? 'BDRemux': ''}{if (megabytes>= 915769.6 && bitrate >= 917301504 && vf=~ /1080|720/) 'BDRemux'}}{fn.match(/bluray|Bluray|BluRay|BLURAYRIP|BLURAY/) && vf=~ /1080|720/ ? 'BDRip': ''}{fn.match(/bluray|Bluray|BluRay|BLURAYRIP|BLURAY|BDRip|bdrip/) && vf=~ /2160/ ? 'UHDRip': ''}{fn.match(/microuhd|Microuhd|MICROUHD|microUHD|MICROuhd|MHD|micro/) && vf=~ /2160/ ? 'MicroUHD': ''}{any{fn=~ (/m1080|m720|m480|brm|mhd|M1080|M720|M480|BRM|MHD|MicroHD|micro|Micro|MICROHD/) ? /MicroHD/ : null} {vs.match (/BluRay|WEB-DL/) ? {source.replace ('WEBDL', 'WEB-DL') .replace('webdl', 'WEB-DL') .replace('Webdl', 'WEB-DL') .replace('Web-dl', 'WEB-DL') .replace('web-dl', 'WEB-DL') .replace('WEB-dl', 'WEB-DL') .replace ('WEBrip', 'WEBRip') .replace ('webrip', 'WEBRip') .replace ('WEBRIP', 'WEBRip') .replace ('WEB-rip', 'WEBRip') .replace ('web-rip', 'WEBRip') .replace ('WEB-RIP', 'WEBRip') .replace ('WEB-Rip', 'WEBRip') .replace ('BDRIP', 'BDRip').replace ('bdrip', 'BDRip') .replace ('BDrip', 'BDRip') .replace ('Bdrip', 'BDRip') .replace ('bd-rip', 'BDRip') .replace ('BDRIP', 'BDRip') .replace ('BD-rip', 'BDRip') .replace ('BD-Rip', 'BDRip') .replace ('brrip', 'BRRip') .replace ('Brrip', 'BRRip') .replace ('BRrip', 'BRRip') .replace ('br-rip', 'BRRip') .replace ('BR-rip', 'BRRip') .replace ('BR-Rip', 'BRRip')} : ''}{vs}}}{vf}{hdr.replace('Dolby Vision', 'DV').replace ('Dovi','DV') .replace ('DOVI','DV') .replace ('dovi','DV')} {vc.replace('Microsoft', 'VC-1').replace ('x264','AVC') .replace ('x265','HEVC') .replace ('ATEME','HEVC')} {audio[0].formatString =~ (/DTS XBR|AC-3|MLP FBA 16-ch|MLP FBA|DTS XLL|E-AC-3 JOC|DTS ES XLL|DTS ES XXCH/) ? {audio[0].formatString.replace ('DTS XBR', ' DTS-HD HR').replace ('AC-3', 'AC3') .replace ('DTS XLL', 'DTS-HD MA') .replace ('MLP FBA 16-ch', 'TrueHD(Atmos)') .replace ('MLP FBA', 'TrueHD').replace ('DTS ES XLL', 'DTS-HD MA').replace ('DTS XLL X', 'DTS X') .replace ('E-AC-3 JOC', 'EAC3(Atmos)') .replace ('DTS ES XXCH', 'DTS-ES Discrete')}: {ac}} {audio[0].channels.replace('1','Mono').replace('2','2.0').replace('6','5.1').replace('7','6.1').replace('8','7.1').replace('9','8.1').replace('10','9.1')} {audio[1].formatString =~ (/DTS XBR|AC-3|MLP FBA 16-ch|MLP FBA|DTS XLL|E-AC-3 JOC|DTS ES XLL|DTS ES XXCH/) ? {audio[1].formatString.replace ('DTS XBR', ' DTS-HD HR').replace ('AC-3', 'AC3') .replace ('DTS XLL', 'DTS-HD MA') .replace ('MLP FBA 16-ch', 'TrueHD(Atmos)') .replace ('MLP FBA', 'TrueHD').replace ('DTS ES XLL', 'DTS-HD MA').replace ('DTS XLL X', 'DTS X') .replace ('E-AC-3 JOC', 'EAC3(Atmos)') .replace ('DTS ES XXCH', 'DTS-ES Discrete')}: {ac}} {audio[1].channels.replace('1','Mono').replace('2','2.0').replace('6','5.1').replace('7','6.1').replace('8','7.1').replace('9','8.1').replace('10','9.1')} {allOf{audioLanguages}{textLanguages} =~ /spa/ ? null : ' VO'}{textLanguages =~ /spa/ && !(audioLanguages =~ /spa/) ? ' VOSE ' : null}{textLanguages.size() > 0 ? ' Subs' : 'null'}.join(' ')}] {" {tmdb-$id}"}Hi!çdeejayexe wrote: 03 Nov 2022, 01:29 Hi
I see that post to improve my filebot expression, the current code is:With this code I have verified that the audios only select [0] and [1], but I have seen this post and I would like to be able to adapt it to my code in the following way:Code: Select all
{drive}/{n.colon(' - ')} ({y}) {" {tmdb-$id}"}/{n.colon(' - ')} ({y}) {any{fn.match(/Director.?s|director|dir(?=\s)|dir(?=\W)/) ? '[Version Director]' : ''} {fn.match(/Extended|extendida|ext(?=\s)|ext(?=\W)/)? '[V. Extendida]' : ''} {fn.match(/Cine|cinema|cinematográfica|cinematografica|cin(?=\s)|cin(?=\W)/)? '[V. Cine]' : ''} {fn.match(/unrated/)? '- UNRATED' : ''}{fn.match(/uncut/)? '- UNCUT' : ''} {'[Ed. ' + fn.match(/(\d+)(?i:th|º)?.(?i:aniversario|Anniversary|anniv(?=\s)|anniv(?=\W) aniv(?=\s)|aniv(?=\W))/) + " aniversario]"} {fn.match(/Criterion/)? '[Ed. Criterion]' : ''} {fn. match (/remastered|remasterizada|remast(?=\s)|remast(?=\W)/) ? '[Remasterizada]' : ''}} {fn.match(/rotulado castellano|Rotulado Castellano|Rotulado Español|rotulado castellano|ROTULADO CASTELLANO/) && vf=~ /1080|720/ ? '[Rotulado Castellano]': ''}{fn.match(/rotulado castellano|Rotulado Castellano|Rotulado Español|rotulado castellano|ROTULADO CASTELLANO/) && vf=~ 2160 ? '[Rotulado Castellano]': ''} [{ fn.match(/A3P/) + ' ' }{ fn.match(/ATVP/) + ' ' }{ fn.match(/ATVP[+]/) + ' ' }{ fn.match(/ATV/) + ' ' }{ fn.match(/AMZN/) + ' ' }{ fn.match(/DSNP[+]/) + ' ' }{ fn.match(/DSN[+]/) + ' ' }{ fn.match(/DSNP/) + ' ' }{ fn.match(/DSNY/) + ' ' }{ fn.match(/Disney[+]/) + ' ' }{ fn.match(/DisneyPlus/) + ' ' }{ fn.match(/STARZ/) + ' ' }{ fn.match(/HBO/) + ' ' }{ fn.match(/HMAX/) + ' ' }{ fn.match(/HULU/) + ' ' }{ fn.match(/M[+]/) + ' ' }{ fn.match(/NF/) + ' ' }{ fn.match(/IMAX/) + ' ' }{ fn.match(/FLMN/) + ' ' }{allOf {any{any{fn.match(/uhdremux|remux/) && vf=~ 2160 ? 'UHDRemux': ''}{if (megabytes>=26500 && bitrate >= 37000000 && vf=~ 2160) 'UHDRemux'}{fn.match(/uhdrip|UHDrip|mUHD|UHDrip|UHD BluRay/) && vf=~ /1080|720|2160/ ? 'UHDRip': ''}{fn.match(/bdremux|BDRemux|BDremux|BluRay Remux|remux/) && vf=~ /1080|720/ ? 'BDRemux': ''}{if (megabytes>= 915769.6 && bitrate >= 917301504 && vf=~ /1080|720/) 'BDRemux'}}{fn.match(/bluray|Bluray|BluRay|BLURAYRIP|BLURAY/) && vf=~ /1080|720/ ? 'BDRip': ''}{fn.match(/bluray|Bluray|BluRay|BLURAYRIP|BLURAY|BDRip|bdrip/) && vf=~ /2160/ ? 'UHDRip': ''}{fn.match(/microuhd|Microuhd|MICROUHD|microUHD|MICROuhd|MHD|micro/) && vf=~ /2160/ ? 'MicroUHD': ''}{any{fn=~ (/m1080|m720|m480|brm|mhd|M1080|M720|M480|BRM|MHD|MicroHD|micro|Micro|MICROHD/) ? /MicroHD/ : null} {vs.match (/BluRay|WEB-DL/) ? {source.replace ('WEBDL', 'WEB-DL') .replace('webdl', 'WEB-DL') .replace('Webdl', 'WEB-DL') .replace('Web-dl', 'WEB-DL') .replace('web-dl', 'WEB-DL') .replace('WEB-dl', 'WEB-DL') .replace ('WEBrip', 'WEBRip') .replace ('webrip', 'WEBRip') .replace ('WEBRIP', 'WEBRip') .replace ('WEB-rip', 'WEBRip') .replace ('web-rip', 'WEBRip') .replace ('WEB-RIP', 'WEBRip') .replace ('WEB-Rip', 'WEBRip') .replace ('BDRIP', 'BDRip').replace ('bdrip', 'BDRip') .replace ('BDrip', 'BDRip') .replace ('Bdrip', 'BDRip') .replace ('bd-rip', 'BDRip') .replace ('BDRIP', 'BDRip') .replace ('BD-rip', 'BDRip') .replace ('BD-Rip', 'BDRip') .replace ('brrip', 'BRRip') .replace ('Brrip', 'BRRip') .replace ('BRrip', 'BRRip') .replace ('br-rip', 'BRRip') .replace ('BR-rip', 'BRRip') .replace ('BR-Rip', 'BRRip')} : ''}{vs}}}{vf}{hdr.replace('Dolby Vision', 'DV').replace ('Dovi','DV') .replace ('DOVI','DV') .replace ('dovi','DV')} {vc.replace('Microsoft', 'VC-1').replace ('x264','AVC') .replace ('x265','HEVC') .replace ('ATEME','HEVC')} {audio[0].formatString =~ (/DTS XBR|AC-3|MLP FBA 16-ch|MLP FBA|DTS XLL|E-AC-3 JOC|DTS ES XLL|DTS ES XXCH/) ? {audio[0].formatString.replace ('DTS XBR', ' DTS-HD HR').replace ('AC-3', 'AC3') .replace ('DTS XLL', 'DTS-HD MA') .replace ('MLP FBA 16-ch', 'TrueHD(Atmos)') .replace ('MLP FBA', 'TrueHD').replace ('DTS ES XLL', 'DTS-HD MA').replace ('DTS XLL X', 'DTS X') .replace ('E-AC-3 JOC', 'EAC3(Atmos)') .replace ('DTS ES XXCH', 'DTS-ES Discrete')}: {ac}} {audio[0].channels.replace('1','Mono').replace('2','2.0').replace('6','5.1').replace('7','6.1').replace('8','7.1').replace('9','8.1').replace('10','9.1')} {audio[1].formatString =~ (/DTS XBR|AC-3|MLP FBA 16-ch|MLP FBA|DTS XLL|E-AC-3 JOC|DTS ES XLL|DTS ES XXCH/) ? {audio[1].formatString.replace ('DTS XBR', ' DTS-HD HR').replace ('AC-3', 'AC3') .replace ('DTS XLL', 'DTS-HD MA') .replace ('MLP FBA 16-ch', 'TrueHD(Atmos)') .replace ('MLP FBA', 'TrueHD').replace ('DTS ES XLL', 'DTS-HD MA').replace ('DTS XLL X', 'DTS X') .replace ('E-AC-3 JOC', 'EAC3(Atmos)') .replace ('DTS ES XXCH', 'DTS-ES Discrete')}: {ac}} {audio[1].channels.replace('1','Mono').replace('2','2.0').replace('6','5.1').replace('7','6.1').replace('8','7.1').replace('9','8.1').replace('10','9.1')} {allOf{audioLanguages}{textLanguages} =~ /spa/ ? null : ' VO'}{textLanguages =~ /spa/ && !(audioLanguages =~ /spa/) ? ' VOSE ' : null}{textLanguages.size() > 0 ? ' Subs' : 'null'}.join(' ')}] {" {tmdb-$id}"}
Movie (2022) {tmdb-XXXXXX}/Movie (2022) [UHDRemux 2160p DV HEVC ES DTS-HD MA 7.1 - EN TrueHD Atmos 7.1 Subs] {tmdb-XXXXXX}
Where I choose the best audio in my example language ES and the best audio in the next available language only one option EN/FR...
Example: ES DTS-HD MA 7.1 - EN TrueHD Atmos 7.1
I have tried to adapt the code but I have not had any luck with this example post viewtopic.php?p=55273#p55273 but i want only best audio for ES audio and next audio only one audio language
I just need a little push to get it right, thanks
ES AC3 5.1 - EN DTS-HD MA 7.1
Code: Select all
{
def preferredLang = 'ES'
def fallbackLang = any{languages*.ISO2*.upper().join('-')}{'YourDefaultLandHere'}
def useChFilter = false
def filter = { [it.lang, it.codec, it.ch].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
def oneStream = { listStream(it)[0] }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = listStream(audioStreams)
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
def groupCodec = audioStreams.sort{ a, b -> b.bitrate <=> a.bitrate }.groupBy{ it.codec }.values().collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.collect{ "${it.lang.replace('null', fallbackLang)} ${it.codec} ${it.ch}" }.join(' - ')
any{addToList}{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}
}Code: Select all
{audio[0].formatString =~ (/DTS XBR|AC-3|MLP FBA 16-ch|MLP FBA|DTS XLL|E-AC-3 JOC|DTS ES XLL|DTS ES XXCH/) ? {audio[0].formatString.replace ('DTS XBR', ' DTS-HD HR').replace ('AC-3', 'AC3') .replace ('DTS XLL', 'DTS-HD MA') .replace ('MLP FBA 16-ch', 'TrueHD(Atmos)') .replace ('MLP FBA', 'TrueHD').replace ('DTS ES XLL', 'DTS-HD MA').replace ('DTS XLL X', 'DTS X') .replace ('E-AC-3 JOC', 'EAC3(Atmos)') .replace ('DTS ES XXCH', 'DTS-ES Discrete')}: {ac}} {audio[0].channels.replace('1','Mono').replace('2','2.0').replace('6','5.1').replace('7','6.1').replace('8','7.1').replace('9','8.1').replace('10','9.1')} {audio[1].formatString =~ (/DTS XBR|AC-3|MLP FBA 16-ch|MLP FBA|DTS XLL|E-AC-3 JOC|DTS ES XLL|DTS ES XXCH/) ? {audio[1].formatString.replace ('DTS XBR', ' DTS-HD HR').replace ('AC-3', 'AC3') .replace ('DTS XLL', 'DTS-HD MA') .replace ('MLP FBA 16-ch', 'TrueHD(Atmos)') .replace ('MLP FBA', 'TrueHD').replace ('DTS ES XLL', 'DTS-HD MA').replace ('DTS XLL X', 'DTS X') .replace ('E-AC-3 JOC', 'EAC3(Atmos)') .replace ('DTS ES XXCH', 'DTS-ES Discrete')}: {ac}} {audio[1].channels.replace('1','Mono').replace('2','2.0').replace('6','5.1').replace('7','6.1').replace('8','7.1').replace('9','8.1').replace('10','9.1')}I have been testing it and now it is correct not as I had it, but I see a detail, if the audio is the same in my language ES and in English EN for example it only shows it once like this ES EAC3 5.1 when it should be if the audio is the same same ES-EN EAC3 5.1 or ES|EN with def preferredLang = 'ES'kim wrote: 21 Nov 2022, 20:09 sampleES AC3 5.1 - EN DTS-HD MA 7.1replaceCode: Select all
{ def preferredLang = 'ES' def fallbackLang = any{languages*.ISO2*.upper().join('-')}{'YourDefaultLandHere'} def useChFilter = false def filter = { [it.lang, it.codec, it.ch].findAll() } def codecList = [ 'MPEG Audio' : 'MP2', 'MP3' : 'MP3', 'PCM' : 'PCM', 'FLAC' : 'FLAC', 'AAC LC' : 'AAC', 'AAC LC SBR' : 'AAC', 'AAC LC SBR PS' : 'AAC', 'AC 3' : 'AC3', 'AC 3 Dep' : 'EAC3', 'E AC 3' : 'EAC3', 'E AC 3 JOC' : 'EAC3 Atmos', 'AC 3 Dep JOC' : 'EAC3 Atmos', 'DTS' : 'DTS', 'DTS 96 24' : 'DTS 96-24', 'DTS ES' : 'DTS-ES', 'DTS ES XXCH' : 'DTS-ES', 'DTS XBR' : 'DTS-HD HRA', 'DTS ES XBR' : 'DTS-HD HRA', 'DTS ES XXCH XBR' : 'DTS-HD HRA', 'DTS XLL' : 'DTS-HD MA', 'DTS ES XLL' : 'DTS-HD MA', 'DTS ES XXCH XLL' : 'DTS-HD MA', 'DTS XLL X' : 'DTS X', 'MLP FBA' : 'TrueHD', 'MLP FBA 16 ch' : 'TrueHD Atmos' ] def audioStreams = [] def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') } def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') } def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') } def oneStream = { listStream(it)[0] } def dString = { it.toDouble().toString() } def toInt = { it.toInteger() } any{audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }) def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{} def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() } { channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) } def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null ) def combined = allOf{codec}{format_profile}.join(' ') audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null}, 'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ] return audioStreams } def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort() def allStreams = listStream(audioStreams) def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() }) def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }) def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) } def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{} def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ') def groupCodec = audioStreams.sort{ a, b -> b.bitrate <=> a.bitrate }.groupBy{ it.codec }.values().collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.collect{ "${it.lang.replace('null', fallbackLang)} ${it.codec} ${it.ch}" }.join(' - ') any{addToList}{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}{defaultStream}{bestBitRate}{preferredStream} }{'NO_AUDIO'} }Code: Select all
{audio[0].formatString =~ (/DTS XBR|AC-3|MLP FBA 16-ch|MLP FBA|DTS XLL|E-AC-3 JOC|DTS ES XLL|DTS ES XXCH/) ? {audio[0].formatString.replace ('DTS XBR', ' DTS-HD HR').replace ('AC-3', 'AC3') .replace ('DTS XLL', 'DTS-HD MA') .replace ('MLP FBA 16-ch', 'TrueHD(Atmos)') .replace ('MLP FBA', 'TrueHD').replace ('DTS ES XLL', 'DTS-HD MA').replace ('DTS XLL X', 'DTS X') .replace ('E-AC-3 JOC', 'EAC3(Atmos)') .replace ('DTS ES XXCH', 'DTS-ES Discrete')}: {ac}} {audio[0].channels.replace('1','Mono').replace('2','2.0').replace('6','5.1').replace('7','6.1').replace('8','7.1').replace('9','8.1').replace('10','9.1')} {audio[1].formatString =~ (/DTS XBR|AC-3|MLP FBA 16-ch|MLP FBA|DTS XLL|E-AC-3 JOC|DTS ES XLL|DTS ES XXCH/) ? {audio[1].formatString.replace ('DTS XBR', ' DTS-HD HR').replace ('AC-3', 'AC3') .replace ('DTS XLL', 'DTS-HD MA') .replace ('MLP FBA 16-ch', 'TrueHD(Atmos)') .replace ('MLP FBA', 'TrueHD').replace ('DTS ES XLL', 'DTS-HD MA').replace ('DTS XLL X', 'DTS X') .replace ('E-AC-3 JOC', 'EAC3(Atmos)') .replace ('DTS ES XXCH', 'DTS-ES Discrete')}: {ac}} {audio[1].channels.replace('1','Mono').replace('2','2.0').replace('6','5.1').replace('7','6.1').replace('8','7.1').replace('9','8.1').replace('10','9.1')}
Code: Select all
.unique()Code: Select all
{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}Ok I have eliminated that function from the code but now in many examples the same language appears repeated like this:kim wrote: 25 Nov 2022, 15:38 cant you just remove thefromCode: Select all
.unique()?Code: Select all
{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}
Code: Select all
def custom = audioStreams.groupBy{ it.lang }.values()*.findAll{ it.lang == preferredLang || it.bitrate == audioStreams.bitrate.max() }.findAll { it }.collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.sort{ it.lang != preferredLang }.collect{ "${it.lang.replace('null', '')} ${it.codec} ${it.ch}" }.join(' - ')
any{addToList}{custom}{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}{defaultStream}{bestBitRate}{preferredStream}ES AC3 5.1 - EN DTS-HD MA 7.1
Ok I have verified it by removing the last part and adding as it says, but it is not correct, you can see the image with few examples:kim wrote: 27 Nov 2022, 14:41 try this:
replace the last partsample:Code: Select all
def custom = audioStreams.groupBy{ it.lang }.values()*.findAll{ it.lang == preferredLang || it.bitrate == audioStreams.bitrate.max() }.findAll { it }.collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.sort{ it.lang != preferredLang }.collect{ "${it.lang.replace('null', '')} ${it.codec} ${it.ch}" }.join(' - ') any{addToList}{custom}{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}{defaultStream}{bestBitRate}{preferredStream}ES AC3 5.1 - EN DTS-HD MA 7.1

Code: Select all
{
def preferredLang = 'ES'
def fallbackLang = any{languages*.ISO2*.upper().join('-')}{'YourDefaultLandHere'}
def useChFilter = false
def filter = { [it.lang, it.codec, it.ch].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
def oneStream = { listStream(it)[0] }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = listStream(audioStreams)
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
def custom = audioStreams.groupBy{ it.lang }.values()*.findAll{ it.lang == preferredLang || it.bitrate == audioStreams.bitrate.max() }.findAll { it }.collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.sort{ it.lang != preferredLang }.collect{ "${it.lang.replace('null', '')} ${it.codec} ${it.ch}" }.join(' - ')
any{addToList}{custom}{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}
}Code: Select all
{
def preferredLang = 'ES'
def fallbackLang = any{languages*.ISO2*.upper().join('-')}{'YourDefaultLandHere'}
def useChFilter = false
def filter = { [it.lang, it.codec, it.ch, it.objects].findAll() }
def codecList =
[
'MPEG Audio' : 'MP2',
'MP3' : 'MP3',
'PCM' : 'PCM',
'FLAC' : 'FLAC',
'AAC LC' : 'AAC',
'AAC LC SBR' : 'AAC',
'AAC LC SBR PS' : 'AAC',
'AC 3' : 'AC3',
'AC 3 Dep' : 'EAC3',
'E AC 3' : 'EAC3',
'E AC 3 JOC' : 'EAC3 Atmos',
'AC 3 Dep JOC' : 'EAC3 Atmos',
'DTS' : 'DTS',
'DTS 96 24' : 'DTS 96-24',
'DTS ES' : 'DTS-ES',
'DTS ES XXCH' : 'DTS-ES',
'DTS XBR' : 'DTS-HD HRA',
'DTS ES XBR' : 'DTS-HD HRA',
'DTS ES XXCH XBR' : 'DTS-HD HRA',
'DTS XLL' : 'DTS-HD MA',
'DTS ES XLL' : 'DTS-HD MA',
'DTS ES XXCH XLL' : 'DTS-HD MA',
'DTS XLL X' : 'DTS X',
'MLP FBA' : 'TrueHD',
'MLP FBA 16 ch' : 'TrueHD Atmos'
]
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
def oneStream = { listStream(it)[0] }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
any{audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
def combined = allOf{codec}{format_profile}.join(' ')
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
def allStreams = listStream(audioStreams)
def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
def groupCodec = audioStreams.sort{ a, b -> b.bitrate <=> a.bitrate }.groupBy{ it.codec }.values().collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.collect{ "${it.lang.replace('null', fallbackLang)} ${it.codec} ${it.ch}" }.join(' - ')
any{addToList}{groupCodec}{bestBitRateAllLang}{[bestPreferredLang, bestBitRate].findAll().join(' & ')}{defaultStream}{bestBitRate}{preferredStream}
}{'NO_AUDIO'}
}
Code: Select all
{
types = ['lang', 'codec', 'ch'] /* ['lang','codec', 'ch', 'objects'] */
replaceSpaces = ' ' /* EN?DTS-HD?MA?7.1?-?EN?DTS?5.1 */
joinWithin = '.' /* ENG?DTS-HD?MA?7.1 */
joinStreams = ' - ' /* ENG DTS-HD MA 7.1 ? FRA AC3 5.1 */
joinLangs = '-' /* ENG?FRA */
objectsText = 'Objs' /* [11 Objs] */
typeLang = 'ISO2' /* ISO2, ISO3 or name (linked to preferredLang and fallbackLang) */
preferredLang = 'EN' /* 'EN', 'ENG' or 'ENGLISH' (linked to typeLang) */
secondLang = 'ES' /* 'EN', 'ENG' or 'ENGLISH' */
fallbackLang = 'EN' /* 'EN', 'ENG' or 'ENGLISH' */
prefOrder = 'bitrate' /* bitrate, index or default */
groupByType = 'codec' /* codec, lang or bitrate */
useChFilter = false /* false or true (hide default ch count e.g. AC3 5.1 vs AC3) */
excludeCommentary = false /* false or true */
CommentaryText = '(Commentary)'
def codecList = /* [Add "DTS XLL" to codecList] = 'DTS XLL':'DTS-HD MA' */
[ 'MPEG Audio':'MP2', 'MP3':'MP3',
'PCM':'PCM', 'FLAC':'FLAC',
'AAC LC':'AAC', 'AAC LC SBR':'AAC', 'AAC LC SBR PS':'AAC',
'AC 3':'AC3', 'AC 3 Dep':'EAC3', 'E AC 3':'EAC3', 'E AC 3 JOC':'EAC3 Atmos', 'AC 3 Dep JOC':'EAC3 Atmos',
'DTS':'DTS', 'DTS 96 24':'DTS 96-24',
'DTS ES':'DTS-ES', 'DTS ES XXCH':'DTS-ES',
'DTS XBR':'DTS-HD HRA', 'DTS ES XBR':'DTS-HD HRA', 'DTS ES XXCH XBR':'DTS-HD HRA',
'DTS XLL':'DTS-HD MA', 'DTS ES XLL':'DTS-HD MA', 'DTS ES XXCH XLL':'DTS-HD MA',
'DTS XLL X':'DTS X',
'MLP FBA':'TrueHD', 'MLP FBA 16 ch':'TrueHD Atmos' ]
// Collect Language
def getLangCode(lang) {
lang = lang[0].toString().upper()
def langDB = []
def languages = Locale.getISOLanguages()
for (String langCode : languages) {
Locale locale = new Locale(langCode,langCode)
langDB << [ISO2: locale.getCountry(), ISO3: locale.getISO3Language().upper(), name: locale.getDisplayLanguage().upper()]
}
return any{langDB.find{it.ISO2 == lang}}{langDB.find{it.ISO3 == lang}}{langDB.find{it.name == lang}}
}
def fetchLang = any{ getLangCode(omdb.SpokenLanguages)[typeLang]}{getLangCode(info.SpokenLanguages)[typeLang]}{getLangCode(languages)[typeLang]}{getLangCode([fallbackLang])[typeLang]}{' '}
def getLang = { !it.lang ? it.lang.toString().replace(/null/, fetchLang) : it.lang.toString() }
def joinSameLang = { it.toUnique{it.lang}.findResults{ getLang(it) }.join([joinLangs]) }
def auLang = { [ISO2: it.'LanguageString2', ISO3: it.'LanguageString3', name: it.'LanguageString'] }
def prefLang(lang, streams) { streams.findAll{ it.lang == getLangCode([lang])[typeLang] } }
// Filters and Sorters
getObjText = { '['+[it.num, it.text].flatten().join(joinWithin)+']' }
def onOff(type, types = types) { types.contains(type) }
def filter = { [it.lang, it.codec, it.ch, it.objects ? getObjText(it.objects) : null, it.commentary ? CommentaryText : null].findAll() }
def filterLang = { it.findAll{ it.lang == preferredLang || it.lang == secondLang }.sort{ it.lang != preferredLang } }
def listStream = { it.unique(false).findResults{ filter(it) }*.join(joinWithin) }
def oneStream = { listStream(it)[0] }
def sortByType(streams, type = 'bitrate'){ streams.sort{ a, b -> b[type] <=> a[type] } }
def findBest(streams, type = 'bitrate'){ streams.findAll{ it[type] == streams[type].max() } }
def noCom = { it.findAll{ !it.commentary } }
def groupType = { it.groupBy{ it[groupByType] }.findResults{ k,v ->
allOf{ types.contains('lang') ? joinSameLang(v) : null}{ v.codec[0] }{ v.ch[0] }{ v.objects[0] ? getObjText(v.objects[0]) : null }
.join(joinWithin) }.join(joinStreams) }
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{P}\p{C}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
def separator = { it.replaceAll(/\s/,replaceSpaces) }
any{ audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def combined = allOf{codec}{format_profile}.join(' ')
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().sum().toString() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'combined' : combined,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'codec' : onOff('codec') ? codecList.get(combined, 'Add "' + combined + '" to codecList').space(joinWithin) : null,
'ch' : onOff('ch') ? useChFilter ? chFilter : ch : null, 'lang' : onOff('lang') ? any{ auLang(au)[typeLang].upper() }{ au.StreamCount == '1' ? fetchLang : null }{null} : null,
'objects' : onOff('objects') ? (any{def objects = au['NumberOfDynamicObjects']; objects ? [num: toInt(objects), text: objectsText] : ''}{null}) : null, 'commentary' : any {au['Title'].lower() ==~ /.*commentary.*/} {false}]
excludeCommentary ? audioStreams = noCom(audioStreams) : null
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('codecList') }.unique().sort()
def allStreams = separator(listStream(sortByType(audioStreams, prefOrder)).join(joinStreams))
def groupAllStreams = separator(groupType(sortByType(audioStreams, prefOrder)))
def bestPrefLang = any{ separator(oneStream(prefLang(preferredLang, audioStreams))) }{}
def bestPrefSecLang = any{ separator(oneStream(prefLang(secondLang, audioStreams))) }{}
def customBestPrefOrder = any{ separator(oneStream(findBest(audioStreams, prefOrder))) }{}
def customGroupBestLang = separator(groupType(sortByType(audioStreams, prefOrder).toUnique{ it.lang }))
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def customGroupLangFilter = any{ groupType(filterLang(sortByType(audioStreams, prefOrder))) }{}
def custom = groupType([(prefLang(preferredLang, audioStreams)), prefLang(secondLang, audioStreams), findBest(audioStreams, prefOrder)].flatten().toUnique{it.lang})
any{addToList}{custom}{customBestPrefOrder}{defaultStream}
}{'NO_AUDIO'}
}Code: Select all
types = ['lang', 'codec', 'ch'] /* ['lang','codec', 'ch', 'objects'] */
replaceSpaces = ' ' /* EN?DTS-HD?MA?7.1?-?EN?DTS?5.1 */
joinWithin = '.' /* ENG?DTS-HD?MA?7.1 */
joinStreams = ' - ' /* ENG DTS-HD MA 7.1 ? FRA AC3 5.1 */
joinLangs = '-' /* ENG?FRA */
objectsText = 'Objs' /* [11 Objs] */
typeLang = 'ISO2' /* ISO2, ISO3 or name (linked to preferredLang and fallbackLang) */
preferredLang = 'EN' /* 'EN', 'ENG' or 'ENGLISH' (linked to typeLang) */
secondLang = 'ES' /* 'EN', 'ENG' or 'ENGLISH' */
fallbackLang = 'EN' /* 'EN', 'ENG' or 'ENGLISH' */
prefOrder = 'bitrate' /* bitrate, index or default */
groupByType = 'codec' /* codec, lang or bitrate */
useChFilter = false /* false or true (hide default ch count e.g. AC3 5.1 vs AC3) */
excludeCommentary = false /* false or true */
CommentaryText = '(Commentary)'Code: Select all
{allStreams} = EN.DTS-HD.MA.7.1 - EN.TrueHD.Atmos.7.1 - EN.DTS-HD.MA.5.1 - EN.DTS.5.1 - EN.AC3.5.1 - FR.AC3.5.1 - IT.AC3.5.1 - ES.AC3.5.1 - NL.AC3.5.1 - CA.AC3.5.1
{groupAllStreams} = EN.DTS-HD.MA.7.1 - EN.TrueHD.Atmos.7.1 - EN.DTS.5.1 - EN-FR-IT-ES-NL-CA.AC3.5.1
{bestPrefLang} = EN.DTS-HD.MA.7.1
{bestPrefSecLang} = ES.AC3.5.1
{customBestPrefOrder} = EN.DTS-HD.MA.7.1
{customGroupBestLang} = EN.DTS-HD.MA.7.1 - FR-IT-ES-NL-CA.AC3.5.1
{defaultStream} = EN.DTS-HD.MA.7.1
{customGroupLangFilter} = EN.DTS-HD.MA.7.1 - EN.TrueHD.Atmos.7.1 - EN.DTS.5.1 - EN-ES.AC3.5.1
{custom} = EN.DTS-HD.MA.7.1 - ES.AC3.5.1Code: Select all
any{addToList}{custom}{customBestPrefOrder}{defaultStream}Good evening.kim wrote: 21 Dec 2022, 02:19 Hi All
I finally had the energy...
I have tried to make it easy to use and customize...
It should also be better to detect the language if missing tag in file
give it a try:
to customize edit top part:Code: Select all
{ types = ['lang', 'codec', 'ch'] /* ['lang','codec', 'ch', 'objects'] */ replaceSpaces = ' ' /* EN?DTS-HD?MA?7.1?-?EN?DTS?5.1 */ joinWithin = '.' /* ENG?DTS-HD?MA?7.1 */ joinStreams = ' - ' /* ENG DTS-HD MA 7.1 ? FRA AC3 5.1 */ joinLangs = '-' /* ENG?FRA */ objectsText = 'Objs' /* [11 Objs] */ typeLang = 'ISO2' /* ISO2, ISO3 or name (linked to preferredLang and fallbackLang) */ preferredLang = 'EN' /* 'EN', 'ENG' or 'ENGLISH' (linked to typeLang) */ secondLang = 'ES' /* 'EN', 'ENG' or 'ENGLISH' */ fallbackLang = 'EN' /* 'EN', 'ENG' or 'ENGLISH' */ prefOrder = 'bitrate' /* bitrate, index or default */ groupByType = 'codec' /* codec, lang or bitrate */ useChFilter = false /* false or true (hide default ch count e.g. AC3 5.1 vs AC3) */ excludeCommentary = false /* false or true */ CommentaryText = '(Commentary)' def codecList = /* [Add "DTS XLL" to codecList] = 'DTS XLL':'DTS-HD MA' */ [ 'MPEG Audio':'MP2', 'MP3':'MP3', 'PCM':'PCM', 'FLAC':'FLAC', 'AAC LC':'AAC', 'AAC LC SBR':'AAC', 'AAC LC SBR PS':'AAC', 'AC 3':'AC3', 'AC 3 Dep':'EAC3', 'E AC 3':'EAC3', 'E AC 3 JOC':'EAC3 Atmos', 'AC 3 Dep JOC':'EAC3 Atmos', 'DTS':'DTS', 'DTS 96 24':'DTS 96-24', 'DTS ES':'DTS-ES', 'DTS ES XXCH':'DTS-ES', 'DTS XBR':'DTS-HD HRA', 'DTS ES XBR':'DTS-HD HRA', 'DTS ES XXCH XBR':'DTS-HD HRA', 'DTS XLL':'DTS-HD MA', 'DTS ES XLL':'DTS-HD MA', 'DTS ES XXCH XLL':'DTS-HD MA', 'DTS XLL X':'DTS X', 'MLP FBA':'TrueHD', 'MLP FBA 16 ch':'TrueHD Atmos' ] // Collect Language def getLangCode(lang) { lang = lang[0].toString().upper() def langDB = [] def languages = Locale.getISOLanguages() for (String langCode : languages) { Locale locale = new Locale(langCode,langCode) langDB << [ISO2: locale.getCountry(), ISO3: locale.getISO3Language().upper(), name: locale.getDisplayLanguage().upper()] } return any{langDB.find{it.ISO2 == lang}}{langDB.find{it.ISO3 == lang}}{langDB.find{it.name == lang}} } def fetchLang = any{ getLangCode(omdb.SpokenLanguages)[typeLang]}{getLangCode(info.SpokenLanguages)[typeLang]}{getLangCode(languages)[typeLang]}{getLangCode([fallbackLang])[typeLang]}{' '} def getLang = { !it.lang ? it.lang.toString().replace(/null/, fetchLang) : it.lang.toString() } def joinSameLang = { it.toUnique{it.lang}.findResults{ getLang(it) }.join([joinLangs]) } def auLang = { [ISO2: it.'LanguageString2', ISO3: it.'LanguageString3', name: it.'LanguageString'] } def prefLang(lang, streams) { streams.findAll{ it.lang == getLangCode([lang])[typeLang] } } // Filters and Sorters getObjText = { '['+[it.num, it.text].flatten().join(joinWithin)+']' } def onOff(type, types = types) { types.contains(type) } def filter = { [it.lang, it.codec, it.ch, it.objects ? getObjText(it.objects) : null, it.commentary ? CommentaryText : null].findAll() } def filterLang = { it.findAll{ it.lang == preferredLang || it.lang == secondLang }.sort{ it.lang != preferredLang } } def listStream = { it.unique(false).findResults{ filter(it) }*.join(joinWithin) } def oneStream = { listStream(it)[0] } def sortByType(streams, type = 'bitrate'){ streams.sort{ a, b -> b[type] <=> a[type] } } def findBest(streams, type = 'bitrate'){ streams.findAll{ it[type] == streams[type].max() } } def noCom = { it.findAll{ !it.commentary } } def groupType = { it.groupBy{ it[groupByType] }.findResults{ k,v -> allOf{ types.contains('lang') ? joinSameLang(v) : null}{ v.codec[0] }{ v.ch[0] }{ v.objects[0] ? getObjText(v.objects[0]) : null } .join(joinWithin) }.join(joinStreams) } def audioStreams = [] def audioClean = { it.replaceAll(/[\p{P}\p{C}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ') } def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') } def dString = { it.toDouble().toString() } def toInt = { it.toInteger() } def separator = { it.replaceAll(/\s/,replaceSpaces) } any{ audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }) def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{} def combined = allOf{codec}{format_profile}.join(' ') def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().sum().toString() } { channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) } def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null ) audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'combined' : combined, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null}, 'codec' : onOff('codec') ? codecList.get(combined, 'Add "' + combined + '" to codecList').space(joinWithin) : null, 'ch' : onOff('ch') ? useChFilter ? chFilter : ch : null, 'lang' : onOff('lang') ? any{ auLang(au)[typeLang].upper() }{ au.StreamCount == '1' ? fetchLang : null }{null} : null, 'objects' : onOff('objects') ? (any{def objects = au['NumberOfDynamicObjects']; objects ? [num: toInt(objects), text: objectsText] : ''}{null}) : null, 'commentary' : any {au['Title'].lower() ==~ /.*commentary.*/} {false}] excludeCommentary ? audioStreams = noCom(audioStreams) : null return audioStreams } def addToList = audioStreams.codec.findAll{ it.contains('codecList') }.unique().sort() def allStreams = separator(listStream(sortByType(audioStreams, prefOrder)).join(joinStreams)) def groupAllStreams = separator(groupType(sortByType(audioStreams, prefOrder))) def bestPrefLang = any{ separator(oneStream(prefLang(preferredLang, audioStreams))) }{} def bestPrefSecLang = any{ separator(oneStream(prefLang(secondLang, audioStreams))) }{} def customBestPrefOrder = any{ separator(oneStream(findBest(audioStreams, prefOrder))) }{} def customGroupBestLang = separator(groupType(sortByType(audioStreams, prefOrder).toUnique{ it.lang })) def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) } def customGroupLangFilter = any{ groupType(filterLang(sortByType(audioStreams, prefOrder))) }{} def custom = groupType([(prefLang(preferredLang, audioStreams)), prefLang(secondLang, audioStreams), findBest(audioStreams, prefOrder)].flatten().toUnique{it.lang}) any{addToList}{custom}{customBestPrefOrder}{defaultStream} }{'NO_AUDIO'} }ANDCode: Select all
types = ['lang', 'codec', 'ch'] /* ['lang','codec', 'ch', 'objects'] */ replaceSpaces = ' ' /* EN?DTS-HD?MA?7.1?-?EN?DTS?5.1 */ joinWithin = '.' /* ENG?DTS-HD?MA?7.1 */ joinStreams = ' - ' /* ENG DTS-HD MA 7.1 ? FRA AC3 5.1 */ joinLangs = '-' /* ENG?FRA */ objectsText = 'Objs' /* [11 Objs] */ typeLang = 'ISO2' /* ISO2, ISO3 or name (linked to preferredLang and fallbackLang) */ preferredLang = 'EN' /* 'EN', 'ENG' or 'ENGLISH' (linked to typeLang) */ secondLang = 'ES' /* 'EN', 'ENG' or 'ENGLISH' */ fallbackLang = 'EN' /* 'EN', 'ENG' or 'ENGLISH' */ prefOrder = 'bitrate' /* bitrate, index or default */ groupByType = 'codec' /* codec, lang or bitrate */ useChFilter = false /* false or true (hide default ch count e.g. AC3 5.1 vs AC3) */ excludeCommentary = false /* false or true */ CommentaryText = '(Commentary)'
add or remove (e.g. output)on last part:Code: Select all
{allStreams} = EN.DTS-HD.MA.7.1 - EN.TrueHD.Atmos.7.1 - EN.DTS-HD.MA.5.1 - EN.DTS.5.1 - EN.AC3.5.1 - FR.AC3.5.1 - IT.AC3.5.1 - ES.AC3.5.1 - NL.AC3.5.1 - CA.AC3.5.1 {groupAllStreams} = EN.DTS-HD.MA.7.1 - EN.TrueHD.Atmos.7.1 - EN.DTS.5.1 - EN-FR-IT-ES-NL-CA.AC3.5.1 {bestPrefLang} = EN.DTS-HD.MA.7.1 {bestPrefSecLang} = ES.AC3.5.1 {customBestPrefOrder} = EN.DTS-HD.MA.7.1 {customGroupBestLang} = EN.DTS-HD.MA.7.1 - FR-IT-ES-NL-CA.AC3.5.1 {defaultStream} = EN.DTS-HD.MA.7.1 {customGroupLangFilter} = EN.DTS-HD.MA.7.1 - EN.TrueHD.Atmos.7.1 - EN.DTS.5.1 - EN-ES.AC3.5.1 {custom} = EN.DTS-HD.MA.7.1 - ES.AC3.5.1Code: Select all
any{addToList}{custom}{customBestPrefOrder}{defaultStream}
Code: Select all
{drive}/{n.colon(' - ')} ({y}) {" {tmdb-$id}"}/{n.colon(' - ')} ({y}) {any{fn.match(/Director.?s|director|dir(?=\s)|dir(?=\W)/) ? '[Version Director]' : ''} {fn.match(/Extended|extendida|ext(?=\s)|ext(?=\W)/)? '[V. Extendida]' : ''} {fn.match(/Cine|cinema|cinematográfica|cinematografica|cin(?=\s)|cin(?=\W)/)? '[V. Cine]' : ''} {fn.match(/unrated/)? '- UNRATED' : ''}{fn.match(/uncut/)? '- UNCUT' : ''} {'[Ed. ' + fn.match(/(\d+)(?i:th|º)?.(?i:aniversario|Anniversary|anniv(?=\s)|anniv(?=\W) aniv(?=\s)|aniv(?=\W))/) + " aniversario]"} {fn.match(/Criterion/)? '[Ed. Criterion]' : ''} {fn. match (/remastered|remasterizada|remast(?=\s)|remast(?=\W)/) ? '[Remasterizada]' : ''}} {fn.match(/rotulado castellano|Rotulado Castellano|Rotulado Español|rotulado castellano|ROTULADO CASTELLANO/) && vf=~ /1080|720/ ? '[Rotulado Castellano]': ''}{fn.match(/rotulado castellano|Rotulado Castellano|Rotulado Español|rotulado castellano|ROTULADO CASTELLANO/) && vf=~ 2160 ? '[Rotulado Castellano]': ''} [{ fn.match(/A3P/) + ' ' }{ fn.match(/ATVP/) + ' ' }{ fn.match(/ATVP[+]/) + ' ' }{ fn.match(/ATV/) + ' ' }{ fn.match(/AMZN/) + ' ' }{ fn.match(/DSNP[+]/) + ' ' }{ fn.match(/DSN[+]/) + ' ' }{ fn.match(/DSNP/) + ' ' }{ fn.match(/DSNY/) + ' ' }{ fn.match(/Disney[+]/) + ' ' }{ fn.match(/DisneyPlus/) + ' ' }{ fn.match(/STARZ/) + ' ' }{ fn.match(/HBO/) + ' ' }{ fn.match(/HMAX/) + ' ' }{ fn.match(/HULU/) + ' ' }{ fn.match(/M[+]/) + ' ' }{ fn.match(/NF/) + ' ' }{ fn.match(/IMAX/) + ' ' }{ fn.match(/FLMN/) + ' ' }{allOf {any{any{fn.match(/uhdremux|remux/) && vf=~ 2160 ? 'UHDRemux': ''}{if (megabytes>=26500 && bitrate >= 37000000 && vf=~ 2160) 'UHDRemux'}{fn.match(/uhdrip|UHDrip|mUHD|UHDrip|UHD BluRay/) && vf=~ /1080|720|2160/ ? 'UHDRip': ''}{fn.match(/bdremux|BDRemux|BDremux|BluRay Remux|remux/) && vf=~ /1080|720/ ? 'BDRemux': ''}{if (megabytes>= 915769.6 && bitrate >= 917301504 && vf=~ /1080|720/) 'BDRemux'}}{fn.match(/bluray|Bluray|BluRay|BLURAYRIP|BLURAY/) && vf=~ /1080|720/ ? 'BDRip': ''}{fn.match(/bluray|Bluray|BluRay|BLURAYRIP|BLURAY|BDRip|bdrip/) && vf=~ /2160/ ? 'UHDRip': ''}{fn.match(/microuhd|Microuhd|MICROUHD|microUHD|MICROuhd|MHD|micro/) && vf=~ /2160/ ? 'MicroUHD': ''}{any{fn=~ (/m1080|m720|m480|brm|mhd|M1080|M720|M480|BRM|MHD|MicroHD|micro|Micro|MICROHD/) ? /MicroHD/ : null} {vs.match (/BluRay|WEB-DL/) ? {source.replace ('WEBDL', 'WEB-DL') .replace('webdl', 'WEB-DL') .replace('Webdl', 'WEB-DL') .replace('Web-dl', 'WEB-DL') .replace('web-dl', 'WEB-DL') .replace('WEB-dl', 'WEB-DL') .replace ('WEBrip', 'WEBRip') .replace ('webrip', 'WEBRip') .replace ('WEBRIP', 'WEBRip') .replace ('WEB-rip', 'WEBRip') .replace ('web-rip', 'WEBRip') .replace ('WEB-RIP', 'WEBRip') .replace ('WEB-Rip', 'WEBRip') .replace ('BDRIP', 'BDRip').replace ('bdrip', 'BDRip') .replace ('BDrip', 'BDRip') .replace ('Bdrip', 'BDRip') .replace ('bd-rip', 'BDRip') .replace ('BDRIP', 'BDRip') .replace ('BD-rip', 'BDRip') .replace ('BD-Rip', 'BDRip') .replace ('brrip', 'BRRip') .replace ('Brrip', 'BRRip') .replace ('BRrip', 'BRRip') .replace ('br-rip', 'BRRip') .replace ('BR-rip', 'BRRip') .replace ('BR-Rip', 'BRRip')} : ''}{vs}}}{vf}{hdr.replace('Dolby Vision', 'DV').replace ('Dovi','DV') .replace ('DOVI','DV') .replace ('dovi','DV')} {vc.replace('Microsoft', 'VC-1').replace ('x264','AVC') .replace ('x265','HEVC') .replace ('ATEME','HEVC')} {
types = ['lang', 'codec', 'ch'] /* ['lang','codec', 'ch', 'objects'] */
replaceSpaces = ' ' /* EN?DTS-HD?MA?7.1?-?EN?DTS?5.1 */
joinWithin = ' ' /* ENG?DTS-HD?MA?7.1 */
joinStreams = ' - ' /* ENG DTS-HD MA 7.1 ? FRA AC3 5.1 */
joinLangs = '-' /* ENG?FRA */
objectsText = 'Objs' /* [11 Objs] */
typeLang = 'ISO2' /* ISO2, ISO3 or name (linked to preferredLang and fallbackLang) */
preferredLang = 'ES' /* 'EN', 'ENG' or 'ENGLISH' (linked to typeLang) */
secondLang = 'EN' /* 'EN', 'ENG' or 'ENGLISH' */
fallbackLang = 'ES' /* 'EN', 'ENG' or 'ENGLISH' */
prefOrder = 'bitrate' /* bitrate, index or default */
groupByType = 'codec' /* codec, lang or bitrate */
useChFilter = false /* false or true (hide default ch count e.g. AC3 5.1 vs AC3) */
excludeCommentary = false /* false or true */
CommentaryText = '(Commentary)'
def codecList = /* [Add "DTS XLL" to codecList] = 'DTS XLL':'DTS-HD MA' */
[ 'MPEG Audio':'MP2', 'MP3':'MP3',
'PCM':'PCM', 'FLAC':'FLAC',
'AAC LC':'AAC', 'AAC LC SBR':'AAC', 'AAC LC SBR PS':'AAC',
'AC 3':'AC3', 'AC 3 Dep':'EAC3', 'E AC 3':'EAC3', 'E AC 3 JOC':'EAC3 Atmos', 'AC 3 Dep JOC':'EAC3 Atmos',
'DTS':'DTS', 'DTS 96 24':'DTS 96-24',
'DTS ES':'DTS-ES', 'DTS ES XXCH':'DTS-ES',
'DTS XBR':'DTS-HD HRA', 'DTS ES XBR':'DTS-HD HRA', 'DTS ES XXCH XBR':'DTS-HD HRA',
'DTS XLL':'DTS-HD MA', 'DTS ES XLL':'DTS-HD MA', 'DTS ES XXCH XLL':'DTS-HD MA',
'DTS XLL X':'DTS X',
'MLP FBA':'TrueHD', 'MLP FBA 16 ch':'TrueHD Atmos' ]
// Collect Language
def getLangCode(lang) {
lang = lang[0].toString().upper()
def langDB = []
def languages = Locale.getISOLanguages()
for (String langCode : languages) {
Locale locale = new Locale(langCode,langCode)
langDB << [ISO2: locale.getCountry(), ISO3: locale.getISO3Language().upper(), name: locale.getDisplayLanguage().upper()]
}
return any{langDB.find{it.ISO2 == lang}}{langDB.find{it.ISO3 == lang}}{langDB.find{it.name == lang}}
}
def fetchLang = any{ getLangCode(omdb.SpokenLanguages)[typeLang]}{getLangCode(info.SpokenLanguages)[typeLang]}{getLangCode(languages)[typeLang]}{getLangCode([fallbackLang])[typeLang]}{' '}
def getLang = { !it.lang ? it.lang.toString().replace(/null/, fetchLang) : it.lang.toString() }
def joinSameLang = { it.toUnique{it.lang}.findResults{ getLang(it) }.join([joinLangs]) }
def auLang = { [ISO2: it.'LanguageString2', ISO3: it.'LanguageString3', name: it.'LanguageString'] }
def prefLang(lang, streams) { streams.findAll{ it.lang == getLangCode([lang])[typeLang] } }
// Filters and Sorters
getObjText = { '['+[it.num, it.text].flatten().join(joinWithin)+']' }
def onOff(type, types = types) { types.contains(type) }
def filter = { [it.lang, it.codec, it.ch, it.objects ? getObjText(it.objects) : null, it.commentary ? CommentaryText : null].findAll() }
def filterLang = { it.findAll{ it.lang == preferredLang || it.lang == secondLang }.sort{ it.lang != preferredLang } }
def listStream = { it.unique(false).findResults{ filter(it) }*.join(joinWithin) }
def oneStream = { listStream(it)[0] }
def sortByType(streams, type = 'bitrate'){ streams.sort{ a, b -> b[type] <=> a[type] } }
def findBest(streams, type = 'bitrate'){ streams.findAll{ it[type] == streams[type].max() } }
def noCom = { it.findAll{ !it.commentary } }
def groupType = { it.groupBy{ it[groupByType] }.findResults{ k,v ->
allOf{ types.contains('lang') ? joinSameLang(v) : null}{ v.codec[0] }{ v.ch[0] }{ v.objects[0] ? getObjText(v.objects[0]) : null }
.join(joinWithin) }.join(joinStreams) }
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{P}\p{C}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
def separator = { it.replaceAll(/\s/,replaceSpaces) }
any{ audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def combined = allOf{codec}{format_profile}.join(' ')
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().sum().toString() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'combined' : combined,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'codec' : onOff('codec') ? codecList.get(combined, 'Add "' + combined + '" to codecList').space(joinWithin) : null,
'ch' : onOff('ch') ? useChFilter ? chFilter : ch : null, 'lang' : onOff('lang') ? any{ auLang(au)[typeLang].upper() }{ au.StreamCount == '1' ? fetchLang : null }{null} : null,
'objects' : onOff('objects') ? (any{def objects = au['NumberOfDynamicObjects']; objects ? [num: toInt(objects), text: objectsText] : ''}{null}) : null, 'commentary' : any {au['Title'].lower() ==~ /.*commentary.*/} {false}]
excludeCommentary ? audioStreams = noCom(audioStreams) : null
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('codecList') }.unique().sort()
def allStreams = separator(listStream(sortByType(audioStreams, prefOrder)).join(joinStreams))
def groupAllStreams = separator(groupType(sortByType(audioStreams, prefOrder)))
def bestPrefLang = any{ separator(oneStream(prefLang(preferredLang, audioStreams))) }{}
def bestPrefSecLang = any{ separator(oneStream(prefLang(secondLang, audioStreams))) }{}
def customBestPrefOrder = any{ separator(oneStream(findBest(audioStreams, prefOrder))) }{}
def customGroupBestLang = separator(groupType(sortByType(audioStreams, prefOrder).toUnique{ it.lang }))
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def customGroupLangFilter = any{ groupType(filterLang(sortByType(audioStreams, prefOrder))) }{}
def custom = groupType([(prefLang(preferredLang, audioStreams)), prefLang(secondLang, audioStreams), findBest(audioStreams, prefOrder)].flatten().toUnique{it.lang})
any{addToList}{custom}{customBestPrefOrder}{defaultStream}
}{'NO_AUDIO'}
} {allOf{audioLanguages}{textLanguages} =~ /spa/ ? null : ' VO'}{textLanguages =~ /spa/ && !(audioLanguages =~ /spa/) ? ' VOSE ' : null}{textLanguages.size() > 0 ? ' Subs' : 'null'}.join(' ')}] {" {tmdb-$id}"}Code: Select all
{drive}{'/' + n.colon(' - ')}{' (' + y + ')'}{'/' + n.colon(' - ')}{' (' + y + ')'}
{ any{ fn.match(/Director.?s|director|dir(?=\s)|dir(?=\W)/) ? '[Version Director]' : ''}
{ fn.match(/Extended|extendida|ext(?=\s)|ext(?=\W)/) ? '[V. Extendida]' : '' }
{ fn.match(/Cine|cinema|cinematográfica|cinematografica|cin(?=\s)|cin(?=\W)/) ? '[V. Cine]' : '' }
{ '- ' + fn.match(/unrated|uncut/).upper() }
{ '[Ed. ' + fn.match(/(\d+)(?i:th|º)?.(?i:aniversario|Anniversary|anniv(?=\s)|anniv(?=\W) aniv(?=\s)|aniv(?=\W))/) + ' aniversario]' }
{ fn.match(/Criterion/) ? '[Ed. Criterion]' : '' }
{ fn.match (/remastered|remasterizada|remast(?=\s)|remast(?=\W)/) ? '[Remasterizada]' : ''}
{ fn =~ /(?i)rotulado castellano|Rotulado Español/ && vf=~ /2160|1080|720/ ? '[Rotulado Castellano]' : '' }
}
{ allOf{ fn.match(/A3P|ATVP|ATVP[+]|ATV|AMZN|DSNP[+]|DSN[+]|DSNP|DSNY|Disney[+]|DisneyPlus|STARZ|HBO|HMAX|HULU|M[+]|NF|IMAX|FLMN/) }
{any{ fn =~ /(?i)uhdremux|remux/ && vf=~ 2160 ? 'UHDRemux': '' }
{ if (megabytes >= 26500 && bitrate >= 37000000 && vf=~ 2160) 'UHDRemux' }
{ fn =~ /(?i)UHDrip|mUHD|UHD BluRay/ && vf=~ /1080|720|2160/ ? 'UHDRip': '' }
{ fn =~ /(?i)BDRemux|BluRay Remux|remux/ && vf=~ /1080|720/ ? 'BDRemux': '' }
{ if (megabytes >= 915769.6 && bitrate >= 917301504 && vf=~ /1080|720/) 'BDRemux' }
{ fn =~ /(?i)BluRay|BLURAYRIP/ && vf=~ /1080|720/ ? 'BDRip': '' }
{ fn =~ /(?i)BluRay|BLURAYRIP|BDRip/ && vf=~ /2160/ ? 'UHDRip': '' }
{ fn =~ /(?i)microUHD|MHD|micro/ && vf=~ /2160/ ? 'MicroUHD': '' }
{ fn =~ (/m1080|m720|m480|BRM|MHD|MicroHD|Micro/) ? /MicroHD/ : null }
{ vs.match(/BluRay|WEB-DL/) ? source.replaceFirst(/(?i)WEB-?DL/, 'WEB-DL').replaceFirst(/(?i)WEB-?Rip/, 'WEB-DL').replaceFirst(/(?i)BD-?Rip/, 'BDRip').replaceFirst(/(?i)BR-?Rip/, 'BDRip') : '' }
{vs}
}
{vf}
{ hdr.replaceFirst(/(?i)Dolby Vision|Dovi/, 'DV') }
{ vc.replace('Microsoft', 'VC-1').replaceFirst(/(?i)x264|x265|ATEME/, 'HEVC') }
}
{
types = ['lang', 'codec', 'ch']
replaceSpaces = ' '
joinWithin = ' '
joinStreams = ' - '
joinLangs = '-'
objectsText = 'Objs'
typeLang = 'ISO2'
preferredLang = 'ES'
secondLang = 'EN'
fallbackLang = 'ES'
prefOrder = 'bitrate'
groupByType = 'codec'
useChFilter = false
excludeCommentary = false
CommentaryText = '(Commentary)'
def codecList =
[ 'MPEG Audio':'MP2', 'MP3':'MP3',
'PCM':'PCM', 'FLAC':'FLAC',
'AAC LC':'AAC', 'AAC LC SBR':'AAC', 'AAC LC SBR PS':'AAC',
'AC 3':'AC3', 'AC 3 Dep':'EAC3', 'E AC 3':'EAC3', 'E AC 3 JOC':'EAC3 Atmos', 'AC 3 Dep JOC':'EAC3 Atmos',
'DTS':'DTS', 'DTS 96 24':'DTS 96-24',
'DTS ES':'DTS-ES', 'DTS ES XXCH':'DTS-ES',
'DTS XBR':'DTS-HD HRA', 'DTS ES XBR':'DTS-HD HRA', 'DTS ES XXCH XBR':'DTS-HD HRA',
'DTS XLL':'DTS-HD MA', 'DTS ES XLL':'DTS-HD MA', 'DTS ES XXCH XLL':'DTS-HD MA',
'DTS XLL X':'DTS X',
'MLP FBA':'TrueHD', 'MLP FBA 16 ch':'TrueHD Atmos' ]
// Collect Language
def getLangCode(lang) {
lang = lang[0].toString().upper()
def langDB = []
def languages = Locale.getISOLanguages()
for (String langCode : languages) {
Locale locale = new Locale(langCode,langCode)
langDB << [ISO2: locale.getCountry(), ISO3: locale.getISO3Language().upper(), name: locale.getDisplayLanguage().upper()]
}
return any{langDB.find{it.ISO2 == lang}}{langDB.find{it.ISO3 == lang}}{langDB.find{it.name == lang}}
}
def fetchLang = any{ getLangCode(omdb.SpokenLanguages)[typeLang]}{getLangCode(info.SpokenLanguages)[typeLang]}{getLangCode(languages)[typeLang]}{getLangCode([fallbackLang])[typeLang]}{' '}
def getLang = { !it.lang ? it.lang.toString().replace(/null/, fetchLang) : it.lang.toString() }
def joinSameLang = { it.toUnique{it.lang}.findResults{ getLang(it) }.join([joinLangs]) }
def auLang = { [ISO2: it.'LanguageString2', ISO3: it.'LanguageString3', name: it.'LanguageString'] }
def prefLang(lang, streams) { streams.findAll{ it.lang == getLangCode([lang])[typeLang] } }
// Filters and Sorters
getObjText = { '['+[it.num, it.text].flatten().join(joinWithin)+']' }
def onOff(type, types = types) { types.contains(type) }
def filter = { [it.lang, it.codec, it.ch, it.objects ? getObjText(it.objects) : null, it.commentary ? CommentaryText : null].findAll() }
def filterLang = { it.findAll{ it.lang == preferredLang || it.lang == secondLang }.sort{ it.lang != preferredLang } }
def listStream = { it.unique(false).findResults{ filter(it) }*.join(joinWithin) }
def oneStream = { listStream(it)[0] }
def sortByType(streams, type = 'bitrate'){ streams.sort{ a, b -> b[type] <=> a[type] } }
def findBest(streams, type = 'bitrate'){ streams.findAll{ it[type] == streams[type].max() } }
def noCom = { it.findAll{ !it.commentary } }
def groupType = { it.groupBy{ it[groupByType] }.findResults{ k,v ->
allOf{ types.contains('lang') ? joinSameLang(v) : null}{ v.codec[0] }{ v.ch[0] }{ v.objects[0] ? getObjText(v.objects[0]) : null }
.join(joinWithin) }.join(joinStreams) }
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{P}\p{C}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
def separator = { it.replaceAll(/\s/,replaceSpaces) }
any{ audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def combined = allOf{codec}{format_profile}.join(' ')
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().sum().toString() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'combined' : combined,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'codec' : onOff('codec') ? codecList.get(combined, 'Add "' + combined + '" to codecList').space(joinWithin) : null,
'ch' : onOff('ch') ? useChFilter ? chFilter : ch : null, 'lang' : onOff('lang') ? any{ auLang(au)[typeLang].upper() }{ au.StreamCount == '1' ? fetchLang : null }{null} : null,
'objects' : onOff('objects') ? (any{def objects = au['NumberOfDynamicObjects']; objects ? [num: toInt(objects), text: objectsText] : ''}{null}) : null, 'commentary' : any {au['Title'].lower() ==~ /.*commentary.*/} {false}]
excludeCommentary ? audioStreams = noCom(audioStreams) : null
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('codecList') }.unique().sort()
def allStreams = separator(listStream(sortByType(audioStreams, prefOrder)).join(joinStreams))
def groupAllStreams = separator(groupType(sortByType(audioStreams, prefOrder)))
def bestPrefLang = any{ separator(oneStream(prefLang(preferredLang, audioStreams))) }{}
def bestPrefSecLang = any{ separator(oneStream(prefLang(secondLang, audioStreams))) }{}
def customBestPrefOrder = any{ separator(oneStream(findBest(audioStreams, prefOrder))) }{}
def customGroupBestLang = separator(groupType(sortByType(audioStreams, prefOrder).toUnique{ it.lang }))
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def customGroupLangFilter = any{ groupType(filterLang(sortByType(audioStreams, prefOrder))) }{}
def custom = groupType([(prefLang(preferredLang, audioStreams)), prefLang(secondLang, audioStreams), findBest(audioStreams, prefOrder)].flatten().toUnique{it.lang})
'[' + any{addToList}{bestPrefLang}{customBestPrefOrder}{defaultStream} + ']'
}{'NO_AUDIO'}
}{' ' + (allOf{textLanguages}
{textLanguages =~ /spa/ ? null : ' VO'}
{textLanguages =~ /spa/ && !(audioLanguages =~ /spa/) ? ' VOSE ' : null}
{textLanguages.size() > 0 ? ' Subs' : 'null'}.join(' '))
}Thanks for the code, but when I try to rename I get [No_Audio]kim wrote: 11 Aug 2021, 18:08 this was not easy... but give it a try:
sample:Code: Select all
{ def preferredLang = 'FR' def useChFilter = false def filter = { [it.lang, it.codec, it.ch, it.objects].findAll() } def codecList = [ 'MPEG Audio' : 'MP2', 'MP3' : 'MP3', 'PCM' : 'PCM', 'FLAC' : 'FLAC', 'AAC LC' : 'AAC', 'AAC LC SBR' : 'AAC', 'AAC LC SBR PS' : 'AAC', 'AC 3' : 'AC3', 'AC 3 Dep' : 'EAC3', 'E AC 3' : 'EAC3', 'E AC 3 JOC' : 'EAC3 Atmos', 'AC 3 Dep JOC' : 'EAC3 Atmos', 'DTS' : 'DTS', 'DTS 96 24' : 'DTS 96-24', 'DTS ES' : 'DTS-ES', 'DTS ES XXCH' : 'DTS-ES', 'DTS XBR' : 'DTS-HD HRA', 'DTS ES XBR' : 'DTS-HD HRA', 'DTS ES XXCH XBR' : 'DTS-HD HRA', 'DTS XLL' : 'DTS-HD MA', 'DTS ES XLL' : 'DTS-HD MA', 'DTS ES XXCH XLL' : 'DTS-HD MA', 'DTS XLL X' : 'DTS X', 'MLP FBA' : 'TrueHD', 'MLP FBA 16 ch' : 'TrueHD Atmos' ] def audioStreams = [] def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') } def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') } def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') } def oneStream = { listStream(it)[0] } def dString = { it.toDouble().toString() } def toInt = { it.toInteger() } any{audio.collect{ au -> def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] }) def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{} def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() } { channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) } def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null ) def combined = allOf{codec}{format_profile}.join(' ') audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch, 'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null}, 'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ] return audioStreams } def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort() def allStreams = listStream(audioStreams) def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() }) def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }) def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) } def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{} def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ') any{addToList}{bestBitRateAllLang}{[bestPreferredLang, bestBitRate].findAll().join(' & ')}{defaultStream}{bestBitRate}{preferredStream} }{'NO_AUDIO'} }EN DTS-HD MA 7.1 - FR AC3 5.1 - IT AC3 5.1 - ES AC3 5.1 - NL AC3 5.1 - CA AC3 5.1
EDIT:
if you really want with the [...]
you can replacewithCode: Select all
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')orCode: Select all
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).toString().split(', ').join(' - ')sample:Code: Select all
def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).joining(' - ', ' [', ']')[EN DTS-HD MA 7.1 - FR AC3 5.1 - IT AC3 5.1 - ES AC3 5.1 - NL AC3 5.1 - CA AC3 5.1]

Code: Select all
{
types = ['lang', 'codec', 'ch'] /* ['lang','codec', 'ch', 'objects'] */
replaceSpaces = ' ' /* EN?DTS-HD?MA?7.1?-?EN?DTS?5.1 */
joinWithin = '.' /* ENG?DTS-HD?MA?7.1 */
joinStreams = '.' /* ENG DTS-HD MA 7.1 ? FRA AC3 5.1 */
joinLangs = '.' /* ENG?FRA */
objectsText = 'Objs' /* [11 Objs] */
typeLang = 'ISO3' /* ISO2, ISO3 or name (linked to preferredLang and fallbackLang) */
preferredLang = 'iTA' /* 'EN', 'ENG' or 'ENGLISH' (linked to typeLang) */
secondLang = 'ENG' /* 'EN', 'ENG' or 'ENGLISH' */
fallbackLang = 'iTA' /* 'EN', 'ENG' or 'ENGLISH' */
prefOrder = 'bitrate' /* bitrate, index or default */
groupByType = 'codec' /* codec, lang or bitrate */
useChFilter = false /* false or true (hide default ch count e.g. AC3 5.1 vs AC3) */
excludeCommentary = false /* false or true */
CommentaryText = '(Commentary)'
def codecList = /* [Add "DTS XLL" to codecList] = 'DTS XLL':'DTS-HD MA' */
[ 'MPEG Audio':'MP2', 'MP3':'MP3',
'PCM':'PCM', 'FLAC':'FLAC',
'AAC LC':'AAC', 'AAC LC SBR':'AAC', 'AAC LC SBR PS':'AAC',
'AC 3':'AC3', 'AC 3 Dep':'EAC3', 'E AC 3':'EAC3', 'E AC 3 JOC':'EAC3 Atmos', 'AC 3 Dep JOC':'EAC3 Atmos',
'DTS':'DTS', 'DTS 96 24':'DTS 96-24',
'DTS ES':'DTS-ES', 'DTS ES XXCH':'DTS-ES',
'DTS XBR':'DTS-HD HRA', 'DTS ES XBR':'DTS-HD HRA', 'DTS ES XXCH XBR':'DTS-HD HRA',
'DTS XLL':'DTS-HD MA', 'DTS ES XLL':'DTS-HD MA', 'DTS ES XXCH XLL':'DTS-HD MA',
'DTS XLL X':'DTS X',
'MLP FBA':'TrueHD', 'MLP FBA 16 ch':'TrueHD Atmos' ]
// Collect Language
def getLangCode(lang) {
lang = lang[0].toString().upper()
def langDB = []
def languages = Locale.getISOLanguages()
for (String langCode : languages) {
Locale locale = new Locale(langCode,langCode)
langDB << [ISO2: locale.getCountry(), ISO3: locale.getISO3Language().upper(), name: locale.getDisplayLanguage().upper()]
}
return any{langDB.find{it.ISO2 == lang}}{langDB.find{it.ISO3 == lang}}{langDB.find{it.name == lang}}
}
def fetchLang = any{ getLangCode(omdb.SpokenLanguages)[typeLang]}{getLangCode(info.SpokenLanguages)[typeLang]}{getLangCode(languages)[typeLang]}{getLangCode([fallbackLang])[typeLang]}{' '}
def getLang = { !it.lang ? it.lang.toString().replace(/null/, fetchLang) : it.lang.toString() }
def joinSameLang = { it.toUnique{it.lang}.findResults{ getLang(it) }.join([joinLangs]) }
def auLang = { [ISO2: it.'LanguageString2', ISO3: it.'LanguageString3', name: it.'LanguageString'] }
def prefLang(lang, streams) { streams.findAll{ it.lang == getLangCode([lang])[typeLang] } }
// Filters and Sorters
getObjText = { '['+[it.num, it.text].flatten().join(joinWithin)+']' }
def onOff(type, types = types) { types.contains(type) }
def filter = { [it.lang, it.codec, it.ch, it.objects ? getObjText(it.objects) : null, it.commentary ? CommentaryText : null].findAll() }
def filterLang = { it.findAll{ it.lang == preferredLang || it.lang == secondLang }.sort{ it.lang != preferredLang } }
def listStream = { it.unique(false).findResults{ filter(it) }*.join(joinWithin) }
def oneStream = { listStream(it)[0] }
def sortByType(streams, type = 'bitrate'){ streams.sort{ a, b -> b[type] <=> a[type] } }
def findBest(streams, type = 'bitrate'){ streams.findAll{ it[type] == streams[type].max() } }
def noCom = { it.findAll{ !it.commentary } }
def groupType = { it.groupBy{ it[groupByType] }.findResults{ k,v ->
allOf{ types.contains('lang') ? joinSameLang(v) : null}{ v.codec[0] }{ v.ch[0] }{ v.objects[0] ? getObjText(v.objects[0]) : null }
.join(joinWithin) }.join(joinStreams) }
def audioStreams = []
def audioClean = { it.replaceAll(/[\p{P}\p{C}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ') }
def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
def dString = { it.toDouble().toString() }
def toInt = { it.toInteger() }
def separator = { it.replaceAll(/\s/,replaceSpaces) }
any{ audio.collect{ au ->
def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
def combined = allOf{codec}{format_profile}.join(' ')
def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().sum().toString() }
{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }
def chFilter = ( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )
audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' }, 'combined' : combined,
'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
'codec' : onOff('codec') ? codecList.get(combined, 'Add "' + combined + '" to codecList').space(joinWithin) : null,
'ch' : onOff('ch') ? useChFilter ? chFilter : ch : null, 'lang' : onOff('lang') ? any{ auLang(au)[typeLang].upper() }{ au.StreamCount == '1' ? fetchLang : null }{null} : null,
'objects' : onOff('objects') ? (any{def objects = au['NumberOfDynamicObjects']; objects ? [num: toInt(objects), text: objectsText] : ''}{null}) : null, 'commentary' : any {au['Title'].lower() ==~ /.*commentary.*/} {false}]
excludeCommentary ? audioStreams = noCom(audioStreams) : null
return audioStreams
}
def addToList = audioStreams.codec.findAll{ it.contains('codecList') }.unique().sort()
def allStreams = separator(listStream(sortByType(audioStreams, prefOrder)).join(joinStreams))
def groupAllStreams = separator(groupType(sortByType(audioStreams, prefOrder)))
def bestPrefLang = any{ separator(oneStream(prefLang(preferredLang, audioStreams))) }{}
def bestPrefSecLang = any{ separator(oneStream(prefLang(secondLang, audioStreams))) }{}
def customBestPrefOrder = any{ separator(oneStream(findBest(audioStreams, prefOrder))) }{}
def customGroupBestLang = separator(groupType(sortByType(audioStreams, prefOrder).toUnique{ it.lang }))
def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
def customGroupLangFilter = any{ groupType(filterLang(sortByType(audioStreams, prefOrder))) }{}
def custom = groupType([(prefLang(preferredLang, audioStreams)), prefLang(secondLang, audioStreams), findBest(audioStreams, prefOrder)].flatten().toUnique{it.lang})
any{addToList}{custom}{customBestPrefOrder}{defaultStream}
}{'NO_AUDIO'}
}