Multiple audio tracks with different codecs and languages

All about user-defined episode / movie / file name format expressions
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

(it gives me a result but not the "best bitrate").
What is the "best" and "NOT the Best" ?

output with ?:

Code: Select all

audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }
(FYI: in GUI you can click on result to copy the output)
I only get 1 result even if there should be 2 independent results for some movies
same result... to confirm remove unique part

e.g. "bestBitRate" is from line

Code: Select all

def bestBitRate
btw:
FAIL =

Code: Select all

{[bestPreferredLang, bestBitRate]...}
OK =

Code: Select all

[bestPreferredLang, bestBitRate]...
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

maybe you like this better
from

Code: Select all

{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }
to

Code: Select all

{ toInt(au.BitRate_Maximum) }{ toInt(au.BitRate) }
looks like it will prefer e.g. TrueHD Atmos 7.1 [11 Objs] over DTS-HD MA 7.1 even if StreamSize and BitRate is smaller

I'm not sure what is the "Best" ?
RudyBzh
Posts: 23
Joined: 31 Mar 2013, 14:05

Re: Multiple audio tracks with different codecs and languages

Post by RudyBzh »

Thanks a lot.
My bad. I was just using "{}" and the results was not as expected... and I'm not dealing with limit cases where order can be discussed.

Exemple when comparing "FR AC3@384kb/s" vs "EN EAC3@1024kb/s" :
Image

Strange result when using {bestBitRate}, the reason I was not understanding what was "BestBitRate" (how AC3@384 can be considered better than EAC3@1024) :
Image
The fact is that {} shouldn't be there...

I just want to notice here that the result is the same if you remove everything (you choose nothing and you have a result...) :
Image
I still don't understand why... and it didn't help me to troubleshoot myself (now we know the problem is myself :lol: )
Perhaps there's a way to return null if no option is chosen at the end (and so switch to "no_audio") ? Well, it's not really important.

And the working test I was looking for, removing the {} (not sure it's the "good way" to do for someone wanting only the higher bitrate as result) :
Image


To talk about "what is the best", I totally agree that it's not that simple to order things, because it could be sorted by :
  • Codec from the codecList (but hard to organize) : MP2 < MP3 < PCM < AAC < AC3 < EAC3 < ... But which one is better from AAC/AC3 or TrueHD Atmos/DTS-X or ... and what between AC3 5.1 & EAC3 2.0 (don't know if it exists but you get the idea...)
  • Bitrate (what is done actually). Must be the most relevant even if, in some rare cases, bitrate can be lower but quality higher due to better compression of the algorithm...
  • Max bitrate, thanks for the idea... but average must be better
  • Number of channels : 2.0 < 5.1 < 7.1 < 9.1
Well, really hard to find a way to sort.

Now, it's working as expected with this (even if I don't know what is "addToList" which can be preferred by the "any" because it's at the front :

Code: Select all

any{addToList}{[bestPreferredLang, bestBitRate].findAll().unique().join(' & ')}{defaultStream}{bestBitRate}{preferredStream}
Also working with this, that I shoud propably use, because I think I understood (more or less... :roll: ) :

Code: Select all

[bestPreferredLang, bestBitRate].findAll().unique().join(' & ')
Well, to be honest it's really cool & good enough to me, even if it could be even better. Let's take some cases :
  • For a movie, like above, with AC3@384 FR & EAC3@1024 EN => Show both (best FR then best "other/foreign").
  • For a movie with AC3@384 FR & DTS@1500 FR & AC3@384 EN => Show only DTS FR (the best of all available) ;
    Is it sure that "bestPreferredLang" will always take DTS@1500 FR over AC3@384 FR ? I mean select the highest bitrate of all FR, because it's only selecting against "preferedLang", not best bitrate. I guess it's because listStream is sorted by bitrate... (but if so, why not only taking the first of the list for bestBitRate ? ; bestBitRate = listStream(it)[0])
  • For a movie with AC3@350 FR & AC3@340 EN => Show only AC3 FR (best of the best)
  • For a movie with AC3@340 FR & AC3@350 EN => I would prefer to only display FR, but it's not working this way now (350 > 340...). Would it be possible/easy to display the alternative audio (other that French) IF bitrate is higher (already done) but also codec is different ?
Something like :
bestPreferredLang.codec <> bestBitRate.codec ? Show both : show bestPreferredLang only.
Just not sure we can play with bestPreferredLang & bestBitRate like this because they are Strings as I understand... probably needed to take it from audioStreams like :
def betterForeign = ?!? I could probably try things but it will not probably be ideal...
seems working :

Code: Select all

audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() }.codec == audioStreams.findAll{ it.lang == preferredLang }.codec ? bestPreferredLang:[bestPreferredLang, bestBitRate].join(' & ')
Thanks again for your answers and for the time you take to read all of this :oops:
RudyBzh
Posts: 23
Joined: 31 Mar 2013, 14:05

Re: Multiple audio tracks with different codecs and languages

Post by RudyBzh »

Well, it's not working as expected...
Because
"audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max()" can contain multiple results (if differents bitrates are equals)
And also because "audioStreams.findAll{ it.lang == preferredLang }" can contain multiple results and, not yet sorted by bitrate (to have the bestPreferrendLang...)
So comparing both may result of strange things ^^

The solution could be to :
1) construct the array : audioStreams << ... as it is actually
2) Sort the array by bitrate (but keep it as an array), to replace the all in one "listStream" who sort and convert as String list... loosing the ability to do things...
3) Next, we can use this sorted array to find things... The 1st in the array, without any filter, is bestBitRate ; The 1st in the array, with lang filter, is bestPreferredLang ; The first with default ... and so on.

What do you think ?
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

This was not easy ;)

Try it out:

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(' & ')
or

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(' & ')

maybe you can reduce the unique's and sort's ?
do rednoah have any advanced info ?
RudyBzh
Posts: 23
Joined: 31 Mar 2013, 14:05

Re: Multiple audio tracks with different codecs and languages

Post by RudyBzh »

Thanks a lot.
Looking at the lines, it's effectively not easy :o
Also, unfortunately, it's not working.

With 1st expression

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(' & ')
Image
OK on lines 1,2,3
KO on lines 4,5,6

With 2nd expression :

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(' & ')
Image
OK on lines 1,2,3 (but I'd prefer FR first as previously)
KO on lines 4,5,6
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

Try:

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 ')
change:
999 to +
777 to &

@rednoah
PS: I'm super annoyed at the "WAF"
User avatar
rednoah
The Source
Posts: 22898
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

kim wrote: 06 Feb 2021, 04:20 PS: I'm super annoyed at the "WAF"
Me too... Might need to move custom format talk to the Discord channel.



EDIT:

Created a dedicated channel for this kind of discussion:
https://discord.com/channels/2287231828 ... 5177269290

Discord will sharing code and upload screenshots easier, plus it allows for real-time messaging, so it should make the experience better in this regard as well.
:idea: Please read the FAQ and How to Request Help.
RudyBzh
Posts: 23
Joined: 31 Mar 2013, 14:05

Re: Multiple audio tracks with different codecs and languages

Post by RudyBzh »

Here is the result with this formula :

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 ')
Had to change "999" to "+" for it to work. If not, I get an error "SyntaxError: expecting ')', found '999'"

Image

Thanks
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

put in and you all set:

Code: Select all

.unique{ it.codec }

Code: Select all

.unique{ it.lang }.unique{ it.codec }.collect{ filter(it) }*.join(' ').join(' & ')
RudyBzh
Posts: 23
Joined: 31 Mar 2013, 14:05

Re: Multiple audio tracks with different codecs and languages

Post by RudyBzh »

Thank you so much & sorry for the disturb on the forum :oops:
As you told, I'm all set with this :

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(' & ')
The full piece of code after a little bit of cleaning, for those who are interested :

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'}
It's possible to remove more useless things in this example but I keep it for those who are interested :
- the useChFilter parts (cleaning a little bit the output, removing the nb of channels if it's "standard" values)
- I still didn't get the goal of "return audioStreams" & "Add To" parts, so keep it ^^

Thanks a lot to Kim for his time ^^
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

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'}
}
Vittatus
Posts: 4
Joined: 12 May 2019, 09:01

Re: Multiple audio tracks with different codecs and languages

Post by Vittatus »

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'}
}
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:

Spanish AC3 5.1
Spanish DTS-HD 5.1
English AC3 5.1
English TrueHD 7.1

let it be like this:

[ES DTS-HD 5.1 - EN TrueHD 7.1]

I would only add the best audios of each language.

Is it possible to do this? What would I have to modify in the code?

Thank you.
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

this was not easy... but give it a try:

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'}
}
sample:
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 replace

Code: Select all

def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
with

Code: Select all

def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).toString().split(', ').join(' - ')
or

Code: Select all

def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).joining(' - ', ' [', ']')
sample:
[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]
lazar0ps
Posts: 2
Joined: 28 Nov 2021, 18:14

Re: Multiple audio tracks with different codecs and languages

Post by lazar0ps »

Thank you for this great piece of code, it's perfect to me.

I would like to ask if there is an easy way to adapt it to group audio languages by audio codec and channel.
I think this would be interesting to shorten file names but keeping all the info.

Sample of how current code works:
EN EAC Atmos 5.1 - ES EAC3 5.1 - FR EAC3 5.1 - EN EAC3 5.1
The desired result:
EN EAC Atmos 5.1 - ES|FR|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.
This way, you could group in a folder all those movies or episodes ripped from VHS or DVB, that maybe don't contain language info but that you know they are in English or Spanish, and rename them all at the same time, knowing that if any of them do not have language information, the file will be renamed using the default desired language.

Sample of how current code works:
MP3 2.0
The desired result:
EN MP3 2.0
Although this could be manually achieved by changing 'null' in this line for 'EN' or any other language string.

Code: Select all

'lang' : any{ au.'LanguageString3'.upper() }{null} ]

Thank you again!
Last edited by lazar0ps on 28 Nov 2021, 19:57, edited 8 times in total.
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

Try it out (Not pretty, Not easy):

sample:
EN DTS-HD MA 7.1 - EN TrueHD Atmos 7.1 - EN DTS 5.1 - EN|FR|IT|ES|NL|CA AC3 5.1
warning you cant use pipes in filename on windows... change "pipes" in

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'}
}
change this to your "default" lang

Code: Select all

it.lang.replace('null', 'EN')

Or maybe more like this ?

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'}
}
lazar0ps
Posts: 2
Joined: 28 Nov 2021, 18:14

Re: Multiple audio tracks with different codecs and languages

Post by lazar0ps »

Wow, you did it kim, that's exactly what I was looking for, and it works like a charm!

Thank you so much :)
finchalex
Posts: 1
Joined: 26 Jan 2022, 21:34

Re: Multiple audio tracks with different codecs and languages

Post by finchalex »

How can I provide MediaInfo dumps?

Meaning, which format, I don't believe MacOS version exports to anything else besides text, and a slew of XML formats.

By the way, the Dolby files are freely available on their website, in addition to those there are a few examples on https://streams.videolan.org/samples/ for all tastes.

I believe the most consistent across version is CodecID, which, however, isn't particularly pleasing (it usually has A_<codecname> and is allcaps)

Also which kind of output should I aim for to keep compatibility?
User avatar
rednoah
The Source
Posts: 22898
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

You can dump MediaInfo information from FileBot (for the specific version of libmediainfo that is bundled with FileBot) with both GUI and CLI:
viewtopic.php?t=4285

Image
:idea: Please read the FAQ and How to Request Help.
Nox
Posts: 2
Joined: 04 Sep 2022, 09:01

Re: Multiple audio tracks with different codecs and languages

Post by Nox »

Hi,

I am trying to make your script you posted above go but I would like to make some changes if possible, keeping only the Italian language for the audio codec result.

I would like a result like this :

Code: Select all

Rocketman (2019) (UHD.Dolby.Vision.10.IT.AC3.5.1).mkv
And not like this one that currently comes out

Code: Select all

Rocketman (2019) UHD Dolby Vision 10 EN TrueHD Atmos 7.1 - IT AC3 5.1.mkv

Would it also be possible to change the name of the directory in this way?

Code: Select all

Rocketman (2019) DV UHD/Rocketman (2019) (UHD.Dolby.Vision.10.IT.AC3.5.1).mkv

the script I am trying to use is the one posted above:

Code: 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'}
}
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

try this (make a new dif. post about the DV in folder) :

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'}+')'
}
Nox
Posts: 2
Joined: 04 Sep 2022, 09:01

Re: Multiple audio tracks with different codecs and languages

Post by Nox »

kim wrote: 08 Sep 2022, 19:23
Thank you very much!
It is just what I was looking for and it works perfectly.

Thanks again!
deejayexe
Posts: 8
Joined: 19 Jun 2022, 23:41

Re: Multiple audio tracks with different codecs and languages

Post by deejayexe »

Hi
I see that post to improve my filebot expression, the current code is:

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}"}
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:

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
deejayexe
Posts: 8
Joined: 19 Jun 2022, 23:41

Re: Multiple audio tracks with different codecs and languages

Post by deejayexe »

deejayexe wrote: 03 Nov 2022, 01:29 Hi
I see that post to improve my filebot expression, the current code is:

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}"}
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:

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
Hi!ç
Maybe @rednoah @kim can help me?

Thanks
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

sample
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'}
}
replace

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')}
Post Reply