Multiple audio tracks with different codecs and languages

All about user-defined episode / movie / file name format expressions
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Multiple audio tracks with different codecs and languages

Post by devster »

I have a file with multiple audio tracks each with a different codec and language, usually also different channels.
Usually the {channels} and {ac} bindings are enough and for most movies something like:

Code: Select all

{ allOf
  {[channels,ac].join(" ")}
  { def a = audioLanguages
    a.size() > 1 ? a.ISO3.join(", ").upperInitial() : a.ISO3.first() }
  .join(" ") }
is acceptable.
I'm however trying to find a way to access each track separately. The ideal output would be:

Code: Select all

7.1 DTS Eng, 2.0 AC3 Ita
kim already did something which is quite close here @viewtopic.php?f=5&t=2&p=29923#p29923 but it uses another method which does not separate each audio stream.
I only work in black and sometimes very, very dark grey. (Batman)
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

I just found @viewtopic.php?f=8&t=1038, which goes even closer, but the following is only partial and definitely not elegant:

Code: Select all

{ import net.filebot.Language;
  audio.collect { [it['ChannelPositions/String2'], it['Codec'],
    Language.findLanguage(it['Language']).ISO3.upperInitial()] }*.join(' ').join(' + ') }
especially the first part relative to the channels, which I cannot replicate from MediaBindingBean.java#L384 which I presume is the origin of the {channels} binding.
I only work in black and sometimes very, very dark grey. (Batman)
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

it took me a long time to get the last part down to e.g 7.1 so someone else most do that:

here is a semi working format (without the import stuff):

Code: Select all

{
audio.collect { [it['ChannelPositionsString2'], it['Language/String3'].upperInitial(), it['Codec'], ] }*.join(' ').join(' + ');
}
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

Untested, but I went and looked for what filebot actually does to define the bindings and this is as close as I can get, definitely not pretty though

Code: Select all

{ import java.math.RoundingMode
  import net.filebot.Language
  audio.collect {
    def au = it
    def channels = any{ au['ChannelPositions/String2'] }{ au['Channel(s)_Original'] }{ au['Channel(s)'] } 
    def ch = channels.tokenize('\\/')*.toDouble().inject(0, { a, b -> a + b }).findAll { it > 0 }
                     .max().toBigDecimal().setScale(1, RoundingMode.HALF_UP).toString()
    def codec = any{ au['CodecID/Hint'] }{ au['Format'] }.replaceAll(/['`´‘’ʻ\p{Punct}\p{Space}]/, '')
    return [ch, codec, Language.findLanguage(au['Language']).ISO3.upperInitial()]
  }*.join(" ").join(", ") }
EDIT: this should work, still ugly
I only work in black and sometimes very, very dark grey. (Batman)
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

You are adding them together:
ChannelPositions/String2 3/2/2.1 / 3/2/0.1 = 12.2 DTS Eng
= BAD

also:
Expression yields empty value: For input string: "Object Based"
Binding "Language": undefined
with AAC file

Code: Select all

Expression yields empty value: multiple points
with DTS-HD.HRA file
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

Uhm, that's strange, I just renamed 2 animes and a movie and it seems to be working for me using that snippet, but I don't have any files with stuff more complicated than 7.1 DTS.
I slimmed it a little and I'm using more allOf which might fix the undefined bindings at least:

Code: Select all

{ import java.math.RoundingMode
  import net.filebot.Language
  audio.collect { au ->
    def channels = any{ au['ChannelPositions/String2'] }{ au['Channel(s)_Original'] }{ au['Channel(s)'] }
    def ch = channels.tokenize('\\/')*.toDouble()
                  .inject(0, { a, b -> a + b }).findAll { it > 0 }
                  .max().toBigDecimal().setScale(1, RoundingMode.HALF_UP).toString()
   def codec = any{ au['CodecID/Hint'] }{ au['Format'] }.replaceAll(/['`´‘’ʻ\p{Punct}\p{Space}]/, '')
   return allOf{ch}{codec}{Language.findLanguage(au['Language']).ISO3.upperInitial()} }*.join(" ").join(", ") }
I just tried to do what filebot does internally to create the {channels}, {ac} and {lang} bindings.
Last edited by devster on 22 Aug 2017, 18:49, edited 1 time in total.
I only work in black and sometimes very, very dark grey. (Batman)
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

now you only need to fix the adding part
12.2 DTS Eng, 12.2 DTS Eng, 12.2 DTS Eng, 18.3 DTS Eng, 18.3 DTS Eng, 18.3 DTS Eng, 12.2 DTS Eng, 12.2 DTS Eng, 12.2 DTS Eng
12.2 DTS Eng, 7.1 TrueHD Eng, 5.1 AC3 Eng, 5.1 DTS Eng, 5.1 DTS Eng, 5.1 AC3 Eng, 5.1 AC3 Fra, 5.1 AC3 Ita, 5.1 AC3 Spa, 5.1 AC3 Nld, 5.1 AC3 Cat, 5.1 AC3 Spa, 5.1 AC3 Nld

Code: Select all

{ import java.math.RoundingMode
  import net.filebot.Language
  audio.collect { au ->
    def channels = any{ au['ChannelPositions/String2'].replaceAll(/Object\sBased\s\/|0.(?=\d.\d)/, '') }{ au['Channel(s)_Original'] }{ au['Channel(s)'] }
    def ch = channels.tokenize('\\/')*.toDouble()
                  .inject(0, { a, b -> a + b }).findAll { it > 0 }
                  .max().toBigDecimal().setScale(1, RoundingMode.HALF_UP).toString()
   def codec = any{ au['CodecID/Hint'] }{ au['Format'] }.replaceAll(/['`´‘’ʻ\p{Punct}\p{Space}]/, '')
   return allOf{ch}{codec}{Language.findLanguage(au['Language']).ISO3.upperInitial()} }*.join(" ").join(", ") }
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

Thanks. I'll trust you on the actual results as I don't have any files to test it on. Do you happen to know if there are around some test files for Object Based audio streams, like the ones on the Dolby websites?
Also, why do you also match for

Code: Select all

0.(?=\d.\d)
Which kind of edge case does this resolve?
I only work in black and sometimes very, very dark grey. (Batman)
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

[3/2/2.1/3/2/0.1] with 0.(?=\d.\d)
[3/2/0.2.1/3/2/0.1] without
ChannelPositions/String2: 3/2/0.2.1 / 3/2/0.1
aka 7.1 / 5.1
it's not 5.2.1 channels, at least I have never heard of it ;)

from a test test I have:
https://wiki.videolan.org/DTS/
http://streams.videolan.org/misc/DTS-HD ... HD-HRA.mkv
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

devster wrote: now you only need to fix the adding part
12.2 DTS Eng, 12.2 DTS Eng, 12.2 DTS Eng, 18.3 DTS Eng, 18.3 DTS Eng, 18.3 DTS Eng, 12.2 DTS Eng, 12.2 DTS Eng, 12.2 DTS Eng
12.2 DTS Eng, 7.1 TrueHD Eng, 5.1 AC3 Eng, 5.1 DTS Eng, 5.1 DTS Eng, 5.1 AC3 Eng, 5.1 AC3 Fra, 5.1 AC3 Ita, 5.1 AC3 Spa, 5.1 AC3 Nld, 5.1 AC3 Cat, 5.1 AC3 Spa, 5.1 AC3 Nld
@devster
Did you ever fix this problem (because of other user need help) ?
From: BabyRay
Recipient: kim
Hello,

hope you can help and sorry for my bad english :)
I use this for my Movies:

{ny} [{vf}] [{ import java.math.RoundingMode
import net.filebot.Language
audio.collect { au ->
def channels = any{ au['ChannelPositions/String2'].replaceAll(/Object\sBased\s\/|0.(?=\d.\d)/, '') }{ au['Channel(s)_Original'] }{ au['Channel(s)'] }
def ch = channels.tokenize('\\/')*.toDouble()
.inject(0, { a, b -> a + b }).findAll { it > 0 }
.max().toBigDecimal().setScale(1, RoundingMode.HALF_UP).toString()
def codec = any{ au['CodecID/Hint'] }{ au['Format'] }.replaceAll(/['`´‘’ʻ\p{Punct}\p{Space}]/, '')
return allOf{ch}{codec}{Language.findLanguage(au['Language']).ISO3.upperInitial()} }*.join(" ").join(", ") }]{fn =~ /ger|german/ ? '.ger' : fn =~ /eng|english/ ? '.eng' : null}{'.'+fn.match(/forced/)} {group}

When i click on File with DTS 7.1 i get DTS 11.2 !
And the part with the Subs is not correct. I cant explain, sorry.
Hope you can help
for now you can try this:

Code: Select all

{
audio.collect { au ->
def ch  = any{(0.0+audio.'ChannelPositionsString2'*.replaceAll(/Object\sBased\s\/|0.(?=\d.\d)/, '')*.split(' / ')*.collect{ it.split('/')*.toBigDecimal().sum() }*.max().max()).toString()}{channels};
def codec = any{ au['CodecID/Hint'] }{ au['Format'] }.replaceAll(/['`´‘’ʻ\p{Punct}\p{Space}]/, '')
return allOf{ch}{codec}{au['Language/String3'].upper()} }*.join(" ").join(", ")
}
sample output:
7.1 DTS ENG, 7.1 TrueHD ENG, 7.1 AC3 ENG, 7.1 DTS ENG, 7.1 DTS ENG, 7.1 AC3 ENG, 7.1 AC3 FRA, 7.1 AC3 ITA, 7.1 AC3 SPA, 7.1 AC3 DUT, 7.1 AC3 CAT, 7.1 AC3 SPA, 7.1 AC3 DUT
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

I added .take(3) after the tokenize.

Code: Select all

{ import java.math.RoundingMode
  import net.filebot.Language
  // map Codec + Format Profile
  def mCFP = [ "AC3" : "AC3",
               "AC3+" : "E-AC3",
               "AAC LC LC" : "AAC-LC",
               "AAC LC SBR HE AAC LC" : "HE-AAC" ]
  def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ') }
  audio.collect { au ->
    def channels = any{ au['ChannelPositions/String2'] }{ au['Channel(s)_Original'] }{ au['Channel(s)'] } 
    def ch = channels.replaceAll(/Object\sBased\s\/|0.(?=\d.\d)/, '')
                     .tokenize('\\/').take(3)*.toDouble()
                     .inject(0, { a, b -> a + b }).findAll { it > 0 }
                     .max().toBigDecimal().setScale(1, RoundingMode.HALF_UP).toString()
    def codec = audioClean(any{ au['CodecID/String'] }{ au['Codec/String'] }{ au['Codec'] })
    def format = any{ au['CodecID/Hint'] }{ au['Format'] }
    def format_profile = { if ( au['Format_Profile'] != null) audioClean(au['Format_Profile']) else '' }
    def combined = allOf{codec}{format_profile}.join(' ')
    def stream = allOf
                   { ch }
                   { mCFP.get(combined, format) }
                   { Language.findLanguage(au['Language']).ISO3.upperInitial() }
    return stream }*.join(" ").join(", ") }
the audio map is incomplete (work in progress).
I only work in black and sometimes very, very dark grey. (Batman)
BabyRay
Posts: 6
Joined: 10 Jan 2018, 16:23

Re: Multiple audio tracks with different codecs and languages

Post by BabyRay »

Hi Devster,

i use this one to name my series:

Code: Select all

D:\Downloads\{n} - {'S'+s.pad(2)}E{e.pad(2)} - {t} [{vf}] 
[{ import java.math.RoundingMode
  import net.filebot.Language
  // map Codec + Format Profile
  def mCFP = [ "AC3" : "AC3",
               "AC3+" : "E-AC3",
               "AAC LC LC" : "AAC-LC",
               "AAC LC SBR HE AAC LC" : "HE-AAC" ]
  def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ') }
  audio.collect { au ->
    def channels = any{ au['ChannelPositions/String2'] }{ au['Channel(s)_Original'] }{ au['Channel(s)'] } 
    def ch = channels.replaceAll(/Object\sBased\s\/|0.(?=\d.\d)/, '')
                     .tokenize('\\/').take(3)*.toDouble()
                     .inject(0, { a, b -> a + b }).findAll { it > 0 }
                     .max().toBigDecimal().setScale(1, RoundingMode.HALF_UP).toString()
    def codec = audioClean(any{ au['CodecID/String'] }{ au['Codec/String'] }{ au['Codec'] })
    def format = any{ au['CodecID/Hint'] }{ au['Format'] }
    def format_profile = { if ( au['Format_Profile'] != null) audioClean(au['Format_Profile']) else '' }
    def combined = allOf{codec}{format_profile}.join(' ')
    def stream = allOf
                   { ch }
                   { mCFP.get(combined, format) }
                   { Language.findLanguage(au['Language']).ISO3.upperInitial() }
    return stream }*.join(" ").join(", ") }]{fn =~ /ger|german/ ? '.ger' : fn =~ /eng|english/ ? '.eng' : null}{'.'+fn.match(/forced/)} {group}
Still get 6.0,8.0 etc, instead of 5.1 or 7.1.
Can you help me please?
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

Not without a file to test it on.
However, while some files can be misinterpreted as 6.0, I never get 8.0.
I only work in black and sometimes very, very dark grey. (Batman)
BabyRay
Posts: 6
Joined: 10 Jan 2018, 16:23

Re: Multiple audio tracks with different codecs and languages

Post by BabyRay »

my mistake, mean 6.0 E-AC3 and 11.2 DTS.
No Files for testing? :(
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

I don't have that many, you could just pm me a few names and I'll get them. It's relevant because it's highly dependent on mediainfo and the specific file.
E-AC3 can be an issue because mediainfo sees the following:

Code: Select all

Channel positions                        : 3/2/1.0 3/2/0.1
and my format takes the first instead of the second bit. (resulting in 6.0)
I only work in black and sometimes very, very dark grey. (Batman)
User avatar
sighunter
Posts: 22
Joined: 26 Aug 2016, 08:08

Re: Multiple audio tracks with different codecs and languages

Post by sighunter »

thanks for all the work, this was exactly what I needed and could never have done alone
User avatar
sighunter
Posts: 22
Joined: 26 Aug 2016, 08:08

Re: Multiple audio tracks with different codecs and languages

Post by sighunter »

I added some more codecs to the Codec + Format Profile map, if anyone needs.

Code: Select all

  def mCFP = [ "AC3" : "AC3",
               "AC3+" : "E-AC3",
		"TrueHD" : "TrueHD",
		"TrueHD TrueHD+Atmos / TrueHD" : "TrueHD ATMOS",
               "DTS" : "DTS",
               "DTS HD HRA / Core" : "DTS-HD HRA",
               "DTS HD MA / Core" : "DTS-HD MA",
               "DTS HD X / MA / Core" : "DTS-X",
               "PCM" : "PCM",
               "FLAC" : "FLAC",
               "AAC LC LC" : "AAC-LC",
               "AAC LC SBR HE AAC LC" : "HE-AAC" ]
Some are redundant: DTS, PCM, FLAC, TrueHD are just there as reference.
They already show up as "DTS", "PCM", "FLAC", "TrueHD" anyway.
yob
Posts: 3
Joined: 03 Jul 2018, 22:32

Re: Multiple audio tracks with different codecs and languages

Post by yob »

devster wrote: 22 Jan 2018, 23:03 I added .take(3) after the tokenize.

Code: Select all

{ import java.math.RoundingMode
  import net.filebot.Language
  // map Codec + Format Profile
  def mCFP = [ "AC3" : "AC3",
               "AC3+" : "E-AC3",
               "AAC LC LC" : "AAC-LC",
               "AAC LC SBR HE AAC LC" : "HE-AAC" ]
  def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ') }
  audio.collect { au ->
    def channels = any{ au['ChannelPositions/String2'] }{ au['Channel(s)_Original'] }{ au['Channel(s)'] } 
    def ch = channels.replaceAll(/Object\sBased\s\/|0.(?=\d.\d)/, '')
                     .tokenize('\\/').take(3)*.toDouble()
                     .inject(0, { a, b -> a + b }).findAll { it > 0 }
                     .max().toBigDecimal().setScale(1, RoundingMode.HALF_UP).toString()
    def codec = audioClean(any{ au['CodecID/String'] }{ au['Codec/String'] }{ au['Codec'] })
    def format = any{ au['CodecID/Hint'] }{ au['Format'] }
    def format_profile = { if ( au['Format_Profile'] != null) audioClean(au['Format_Profile']) else '' }
    def combined = allOf{codec}{format_profile}.join(' ')
    def stream = allOf
                   { ch }
                   { mCFP.get(combined, format) }
                   { Language.findLanguage(au['Language']).ISO3.upperInitial() }
    return stream }*.join(" ").join(", ") }
the audio map is incomplete (work in progress).
How am I supposed to run this script?
I just installed Filebot for the first time and am a little confused.

So far I have:

Code: Select all

filebot -rename "G:\Meine Ablage\Plexy\DOWNLOAD\Black.Swan.2010.German.DTS.DL.1080p.BluRay.AVC.Remux-iNCEPTiON" --output "G:\Meine Ablage\Plexy\DOWNLOAD\Black.Swan.2010.German.DTS.DL.1080p.BluRay.AVC.Remux-iNCEPTiON" --format "{n.upperInitial().space('.')}.({y}).{'['+source+']'}{'['+vf+']'}{'['+ac+']'}{'['+channels+']'}{'['+vc.replace('Microsoft', 'VC-1')+']'}{any{n.findMatch(group) ? null : '-'+group}{'-'+fn.match(/(?<=[-])\w+$/)}}" --action test
Now I'd like to combine it with your script, so I get better details for audio. But I'm unable to find out how to insert your script.
Is this a groovy file, a arguments file or simple arguments (which would make it unreadable, cause of it's length :D) I tried all of those methods, probably just wrong, but none worked. :(
I'm sorry for the silly question. :)
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

:idea: Use the @file syntax for reading command-line arguments from external text files.
:idea: Please read the FAQ and How to Request Help.
User avatar
sighunter
Posts: 22
Joined: 26 Aug 2016, 08:08

Re: Multiple audio tracks with different codecs and languages

Post by sighunter »

the script does not work for me any more with current filebot version 4.8.5 :(

https://www.reddit.com/r/filebot/comments/bcbs9u/rename_expression_does_not_pick_up_audio_codec/
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

I believe something changed in MediaInfo, without an exact file it's difficult to debug though.
A preliminary analysis seems to tell me that nothing gets found in this line:

Code: Select all

    def codec = audioClean(any{ au['CodecID/String'] }{ au['Codec/String'] }{ au['Codec'] })
which means that on MediaInfo 'CodecID/String', 'Codec/String' and 'Codec' are undefined.
an easy fix should be this:

Code: Select all

def audioClean = { if (it != null) it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ') }
but you're losing information.

Also try with FFMPEG, I'm also having issues with the Dolby Amaze trailer, it seems related to https://forum.serviio.org/viewtopic.php?f=7&t=24790 and how MediaInfo interprets the codec/format info.
I only work in black and sometimes very, very dark grey. (Batman)
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

Code: Select all

{ import java.math.RoundingMode
  import net.filebot.Language
  // map Codec + Format Profile
  def mCFP = [ "AC3" : "AC3",
               "AC3+" : "E-AC3",
               "AAC LC LC" : "AAC-LC",
               "AAC LC SBR HE AAC LC" : "HE-AAC",
               "Dolby TrueHD with Dolby Atmos" : "TrueHD Atmos"]
  def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ') }
  audio.collect { au ->
    def channels = any{ au['ChannelPositions/String2'] }{ au['Channel(s)_Original'] }{ au['Channel(s)'] } 
    def ch = channels.replaceAll(/Object\sBased\s\/|0.(?=\d.\d)/, '')
                     .tokenize('\\/').take(3)*.toDouble()
                     .inject(0, { a, b -> a + b }).findAll { it > 0 }
                     .max().toBigDecimal().setScale(1, RoundingMode.HALF_UP).toString()
    def codec = audioClean(any{ au['CodecID/String'] }{ au['Codec/String'] }{ au['Codec'] }{ au['Format_Commercial'] })
    def format = any{ au['CodecID/Hint'] }{ au['Format'] }
    def format_profile = { if ( au['Format_Profile'] != null) audioClean(au['Format_Profile']) else '' }
    def combined = allOf{codec}{format_profile}.join(' ')
    def stream = allOf
                   { ch }
                   { mCFP.get(combined, format) }
                   { Language.findLanguage(au['Language']).ISO3.upperInitial() }
    return stream }*.join(" ").join(", ") }
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

Which specific binding doesn't work as expected? Can you narrow it down to a simple expression?

Presumably, since you're accessing MediaInfo fields directly, a different version of MediaInfo may give you different fields and values:
viewtopic.php?f=5&t=4285
:idea: Please read the FAQ and How to Request Help.
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

looks like "audio.Codec", "audio.Codec/String" and "audio.CodecID/String" is no longer present... maybe more?

this looks new ?

Code: Select all

media.Audio_Codec_List
media.Audio_Format_WithHint_List
User avatar
sighunter
Posts: 22
Joined: 26 Aug 2016, 08:08

Re: Multiple audio tracks with different codecs and languages

Post by sighunter »

thank you very much kim, devster and rednoah. I went with { au['Format_Commercial'] } like kim suggested and adapted the audio map
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

@Kim, It is not new as they report MLP FBA 16-ch in the codec, it's short for Meridian Lossless Packing with FBA stream, it did however change in the fact that this is not reported in common fields by MediaInfo
I only work in black and sometimes very, very dark grey. (Batman)
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

By the way, I'm not exactly sure if they were already present or were added in more recent versions, however now the {channel} and {aco} bindings are fairly similar to the script.
I'm fairly confident it could be significantly simplified, will post some results.
I only work in black and sometimes very, very dark grey. (Batman)
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

As you can see some bindings are broken with the new MediaInfo

DTS:X
Before:
{ac}=DTS
{aco}= Binding "aco": undefined
{af}=6ch (Wrong)
{channels}=7.1
Format DTS
Format_Commercial DTS
Channel(s) Object Based / 8 / 6
ChannelPositions/String2 Object Based / 3/2/2.1 / 3/2/0.1
CodecID A_DTS
old: Codec DTS-HD
old: Format_Profile X / MA / Core

After:
{ac}=DTS
{aco}= Binding "aco": undefined
{channels}= Binding "channels": No value present
{af}=Binding "af": No value present
Format DTS
Format_Commercial DTS-HD Master Audio
Channel(s) 8
ChannelPositions/String2 Object Based
CodecID A_DTS
new: Format/String DTS XLL X
new: Format_AdditionalFeatures XLL X
****************************************************************************

TrueHD:
Before:
{ac}=TrueHD
{aco}= Binding "aco": undefined
{channels}=7.1
{af}=8ch
Format TrueHD
Format_Commercial TrueHD
ChannelPositions/String2 3/2/2.1
CodecID A_TRUEHD

After:
{ac}=MLPFBA
{aco}= Binding "aco": undefined
{channels}=7.1
{af}=8ch
Format MLP FBA
Format_Commercial Dolby TrueHD
ChannelPositions/String2 3/2/2.1
CodecID A_TRUEHD
****************************************************************************

TrueHD+Atmos:
Before:
{ac}=TrueHD
{aco}= TrueHD+Atmos
{channels}=7.1
{af}=8ch
Format TrueHD
Format_Commercial TrueHD
Format_Profile TrueHD+Atmos / TrueHD
ChannelPositions/String2 Object Based / 3/2/2.1
CodecID A_TRUEHD

After:
{ac}=MLPFBA
{aco}= Binding "aco": undefined
{channels}=7.1
{af}=8ch
Format MLP FBA
Format/String MLP FBA 16-ch
Format_Commercial Dolby TrueHD with Dolby Atmos
Format_AdditionalFeatures 16-ch
ChannelPositions/String2 3/2/2.1
CodecID A_TRUEHD
****************************************************************************
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

So, as MediaInfo changed a bit and I realized how I was needlessly trying to replicate the logic already present in MediaBindingBean.java this is a new version of the snippet

Code: Select all

// somewhere at the top 
import net.filebot.Language

      { // map Codec + Format Profile
        def mCFP = [
          "FLAC" : "FLAC",
          "PCM" : "PCM",
          "MP3": "MP3",
          "E-AC-3 JOC": "E-AC-3",
          "DTS ES XXCH": "DTS-ES Discrete",
          "MLP FBA": "TrueHD",
          "MLP FBA 16-ch": "TrueHD"
        ]
        audio.collect { au ->
          def ac1 = any{ au['CodecID/Hint'] }{au['Format/String']}{ au['Format'] } // extends _ac_ which strips spaces > "CodecID/Hint", "Format"
          def ac2 = any{ au['CodecID/String'] }{ au['Codec/String'] }{ au['Codec'] }
          def atmos = (aco =~ /(?i:atmos)/) ? 'Atmos' : null // _aco_ uses "Codec_Profile", "Format_Profile", "Format_Commercial"
          def combined = allOf{ac1}{ac2}.join(' ')
          def fallback = any{ac1}{ac2}{aco}
          def stream = allOf
            /* _channels_ as it uses "ChannelPositions/String2", "Channel(s)_Original", "Channel(s)"
               compared to _af_ which uses "Channel(s)_Original", "Channel(s)" */
            { allOf{"${channels}"}{au['NumberOfDynamicObjects'] + "obj"}.join('+') }
            { allOf{ mCFP.get(combined, aco) }{atmos}.join('+') } /* bit risky keeping aco as default */
            { Language.findLanguage(au['Language']).ISO3.upperInitial() }
            /* _cf_ not being used > "Codec/Extensions", "Format" */
          return stream
        }.sort{a, b -> a.first() <=> b.first() }*.join(" ").join(", ") }
Unfortunately most of the map is now a bit useless and I only left the ugly MLP FBA.
aco =~ /(?i:atmos)/ is being used as aco.match(/atmos/) fails with Pattern not found: Dolby TrueHD when the string isn't present.
Expected output is:
7.1+15obj TrueHD+Atmos for Dolby Amaze Atmos trailer
5.1 AC-3 for the Amaze regular trailer
5.1 DTS-HD MA Eng, 5.1 PCM Eng, 5.1 AC-3 Eng for Dolby 3D Glass Return Trailer
5.1+11obj E-AC-3+Atmos Eng for Dolby Natures Fury Atmos trailer

I tested it on MacOS, latest version of FileBot available.

Code: Select all

/Applications/FileBot.app//Contents/MacOS/libmediainfo.dylib:
	/usr/local/lib/libmediainfo.0.dylib (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.8)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.60.2)
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 104.1.0)
	/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 489.0.0)
not very informative as version unfortunately.
Feedback welcome.
I only work in black and sometimes very, very dark grey. (Batman)
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

1.
All versions of FileBot come packaged with the latest MediaInfo release, which is currently Version 18.12, but on Linux / Synology / etc FileBot may not package libmediainfo and instead rely on the one provided by your distribution packaging system.


2.
Here's how {aco} is currently implemented:
https://www.filebot.net/docs/api/src-ht ... l#line.414

:?: Any idea how to make it work with newer libmediainfo versions?
:idea: Please read the FAQ and How to Request Help.
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

I don't believe the issue it's not working, default bindings are slightly worse but there still is the option to access raw MediaInfo bindings.
These have shifted around it seems mainly with Codec bindings which now seem deprecated > Codec, Codec/String, Codec/Family, Codec/Info, Codec/Url and Codec_Profile https://github.com/MediaArea/MediaInfoLib/blob/29be23e7bc740e1ba39ce6a231ceb69c254b4401/Source/MediaInfo/MediaInfo_Config_Automatic.cpp#L4864

The nicest output is probably Format_Commercial when available, but it's usually quite verbose, for example in the Dolby Amaze trailer it outputs Dolby TrueHD with Dolby Atmos or something similar, and for DTS-HD MA it returns DTS-HD Master Audio.
I can't recall a single field consistently outputting nice info; all DTS have DTS as format, without distinguishing between variants, however DTS ES-Discrete is actually the commercial name for DTS ES with XCh/XXCh extension (vs DTS ES Matrix with no header).

First try, totally untested:

Code: Select all

af = getMediaInfo(StreamKind.Audio, 0, "Format/String", "Format"); // short version
ac = getMediaInfo(StreamKind.Audio, 0, "CodecID/Hint", "CodecID/String", "CodecID"); // not sure about Hint
afo = getMediaInfo(StreamKind.Audio, 0, "Format_AdditionalFeatures", "Matrix_Format"); // for additional format features (DTS Neural)
aco = getMediaInfo(StreamKind.Audio, 0, "Format_Profile", "Format_Commercial"); // nicelooking
However there are also some other bindings affected, for example the MediaInfo fields used for af used to contain object data, which are now separate, it seems that some relevant changes were introduced here https://github.com/MediaArea/MediaInfoLib/commit/e972a629ce7cbe6e110a0f8bde7c0c43850c0ad0
NumberOfDynamicObjects in Atmos.
I only work in black and sometimes very, very dark grey. (Batman)
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

Ideally, the top-level bindings take care of differences in underlying MediaInfo versions, so it'll just work regardless of MediaInfo version, as best as possible anyway.

I only have one test files for ATMOS, and none for DTS. So MediaInfo dumps + preferences for MI fields to base aco, channels, etc on are appreciated.

{aco} at least uses "Codec_Profile", "Format_Profile", "Format_Commercial" so at least the last one should work reasonably well with the latest release.

"Format_AdditionalFeatures", "Matrix_Format" I haven't really seen before. I guess I could add a binding if it's useful, are have af / channels check that field as well if that makes sense.
:idea: Please read the FAQ and How to Request Help.
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

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?
I only work in black and sometimes very, very dark grey. (Batman)
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

You can view all the MediaInfo tables for each stream via FileBot:
viewtopic.php?f=5&t=4285

You can CTRL+A / CTRL+C to copy & paste a relevant table.
:idea: Please read the FAQ and How to Request Help.
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

4.8.5 on MacOS

DTS HD MA

Code: Select all

Format	DTS
Format/String	DTS XLL
Format/Info	Digital Theater Systems
Format/Url	https://en.wikipedia.org/wiki/DTS_(sound_system)
Format_Commercial	DTS-HD Master Audio
Format_Commercial_IfAny	DTS-HD Master Audio
Format_Settings_Mode	16
Format_Settings_Endianness	Big
Format_AdditionalFeatures	XLL
CodecID	A_DTS
Duration	29536
Duration/String	29 s 536 ms
Duration/String1	29 s 536 ms
Duration/String2	29 s 536 ms
Duration/String3	00:00:29.536
Duration/String5	00:00:29.536
BitRate_Mode	VBR
BitRate_Mode/String	Variable
Channel(s)	6
Channel(s)/String	6 channels
ChannelPositions	Front: L C R, Side: L R, LFE
ChannelPositions/String2	3/2/0.1
ChannelLayout	C L R Ls Rs LFE
SamplesPerFrame	512
SamplingRate	48000
SamplingRate/String	48.0 kHz
FrameRate	93.750
FrameRate/String	93.750 FPS (512 SPF)
BitDepth	24
BitDepth/String	24 bits
Compression_Mode	Lossless
Compression_Mode/String	Lossless
Delay	0
Delay/String3	00:00:00.000
Delay_Source	Container
Delay_Source/String	Container
Video_Delay	0
Video_Delay/String3	00:00:00.000
Title	DTS-HD MA 5.1
Language	en
Language/String	English
Language/String1	English
Language/String2	en
Language/String3	eng
Language/String4	en
Default	Yes
Default/String	Yes
Forced	No
Forced/String	No
DTS-HD HR

Code: Select all

Format	DTS
Format/String	DTS XBR
Format/Info	Digital Theater Systems
Format/Url	https://en.wikipedia.org/wiki/DTS_(sound_system)
Format_Commercial	DTS-HD High Resolution Audio
Format_Commercial_IfAny	DTS-HD High Resolution Audio
Format_Settings_Mode	16
Format_Settings_Endianness	Big
Format_AdditionalFeatures	XBR
CodecID	A_DTS
Duration	16246
Duration/String	16 s 246 ms
Duration/String1	16 s 246 ms
Duration/String2	16 s 246 ms
Duration/String3	00:00:16.246
Duration/String5	00:00:16.246
BitRate_Mode	CBR
BitRate_Mode/String	Constant
BitRate	3018000
BitRate/String	3 018 kb/s
Channel(s)	6
Channel(s)/String	6 channels
Channel(s)_Original	8
Channel(s)_Original/String	8 channels
ChannelPositions	Front: L C R, Side: L R, Back: L R, LFE
ChannelPositions/String2	3/2/2.1
ChannelLayout	C L R LFE Lb Rb Lss Rss
SamplesPerFrame	512
SamplingRate	96000
SamplingRate/String	96.0 kHz
FrameRate	187.500
FrameRate/String	187.500 FPS (512 SPF)
BitDepth	24
BitDepth/String	24 bits
Compression_Mode	Lossy
Compression_Mode/String	Lossy
Delay	0
Delay/String3	00:00:00.000
Delay_Source	Container
Delay_Source/String	Container
Video_Delay	0
Video_Delay/String3	00:00:00.000
StreamSize	6128803
StreamSize/String	5.84 MiB (25%)
StreamSize/String1	6 MiB
StreamSize/String2	5.8 MiB
StreamSize/String3	5.84 MiB
StreamSize/String4	5.845 MiB
StreamSize/String5	5.84 MiB (25%)
StreamSize_Proportion	0.24785
Language	en
Language/String	English
Language/String1	English
Language/String2	en
Language/String3	eng
Language/String4	en
Default	Yes
Default/String	Yes
Forced	No
Forced/String	No
DTS:X

Code: Select all

OriginalSourceMedium_ID	4352
OriginalSourceMedium_ID/String	4352 (0x1100)
Format	DTS
Format/String	DTS XLL X
Format/Info	Digital Theater Systems
Format/Url	https://en.wikipedia.org/wiki/DTS_(sound_system)
Format_Commercial	DTS-HD Master Audio
Format_Commercial_IfAny	DTS-HD Master Audio
Format_Settings_Mode	16
Format_Settings_Endianness	Big
Format_AdditionalFeatures	XLL X
CodecID	A_DTS
Duration	18944.000000
Duration/String	18 s 944 ms
Duration/String1	18 s 944 ms
Duration/String2	18 s 944 ms
Duration/String3	00:00:18.944
Duration/String4	00:00:18:84
Duration/String5	00:00:18.944 (00:00:18:84)
BitRate_Mode	VBR
BitRate_Mode/String	Variable
BitRate	6089277
BitRate/String	6 089 kb/s
Channel(s)	8
Channel(s)/String	8 channels
Channel(s)_Original	Object Based
Channel(s)_Original/String	Object Based
ChannelPositions	Object Based
ChannelPositions/String2	Object Based
ChannelLayout	Object Based
SamplesPerFrame	512
SamplingRate	48000
SamplingRate/String	48.0 kHz
FrameRate	93.750
FrameRate/String	93.750 FPS (512 SPF)
BitDepth	24
BitDepth/String	24 bits
Delay	0
Delay/String3	00:00:00.000
Delay_Source	Container
Delay_Source/String	Container
Video_Delay	0
Video_Delay/String3	00:00:00.000
StreamSize	14419408
StreamSize/String	13.8 MiB (18%)
StreamSize/String1	14 MiB
StreamSize/String2	14 MiB
StreamSize/String3	13.8 MiB
StreamSize/String4	13.75 MiB
StreamSize/String5	13.8 MiB (18%)
StreamSize_Proportion	0.17777
Title	Surround 7.1
Language	en
Language/String	English
Language/String1	English
Language/String2	en
Language/String3	eng
Language/String4	en
Default	Yes
Default/String	Yes
Forced	No
Forced/String	No
OriginalSourceMedium	Blu-ray
Dolby TrueHD + Atmos

Code: Select all

Format	MLP FBA
Format/String	MLP FBA 16-ch
Format/Info	Meridian Lossless Packing FBA with 16-channel presentation
Format_Commercial	Dolby TrueHD with Dolby Atmos
Format_Commercial_IfAny	Dolby TrueHD with Dolby Atmos
Format_AdditionalFeatures	16-ch
CodecID	A_TRUEHD
CodecID/Url	http://www.dolby.com/consumer/technology/trueHD.html
Duration	63500.000000
Duration/String	1 min 3 s
Duration/String1	1 min 3 s 500 ms
Duration/String2	1 min 3 s
Duration/String3	00:01:03.500
Duration/String5	00:01:03.500
BitRate_Mode	VBR
BitRate_Mode/String	Variable
BitRate	6693961
BitRate/String	6 694 kb/s
BitRate_Maximum	9096000
BitRate_Maximum/String	9 096 kb/s
Channel(s)	8
Channel(s)/String	8 channels
ChannelPositions	Front: L C R, Side: L R, Back: L R, LFE
ChannelPositions/String2	3/2/2.1
ChannelLayout	L R C LFE Ls Rs Lb Rb
SamplesPerFrame	40
SamplingRate	48000
SamplingRate/String	48.0 kHz
FrameRate	1200.000
FrameRate/String	1 200.000 FPS (40 SPF)
Compression_Mode	Lossless
Compression_Mode/String	Lossless
Delay	0
Delay/String3	00:00:00.000
Delay_Source	Container
Delay_Source/String	Container
Video_Delay	0
Video_Delay/String3	00:00:00.000
StreamSize	53133320
StreamSize/String	50.7 MiB (36%)
StreamSize/String1	51 MiB
StreamSize/String2	51 MiB
StreamSize/String3	50.7 MiB
StreamSize/String4	50.67 MiB
StreamSize/String5	50.7 MiB (36%)
StreamSize_Proportion	0.36310
Default	Yes
Default/String	Yes
Forced	No
Forced/String	No
NumberOfDynamicObjects	15
BedChannelCount/String	1 channel
BedChannelConfiguration	LFE
Dolby Digital Plus + Atmos

Code: Select all

Format	E-AC-3
Format/String	E-AC-3 JOC
Format/Info	Enhanced AC-3 with Joint Object Coding
Format/Url	https://en.wikipedia.org/wiki/Dolby_Digital_Plus
Format_Commercial	Dolby Digital Plus with Dolby Atmos
Format_Commercial_IfAny	Dolby Digital Plus with Dolby Atmos
Format_Settings_Endianness	Big
Format_AdditionalFeatures	JOC
InternetMediaType	audio/eac3
CodecID	A_EAC3
Duration	110944.000000
Duration/String	1 min 50 s
Duration/String1	1 min 50 s 944 ms
Duration/String2	1 min 50 s
Duration/String3	00:01:50.944
Duration/String4	00:01:51:26
Duration/String5	00:01:50.944 (00:01:51:26)
BitRate_Mode	CBR
BitRate_Mode/String	Constant
BitRate	448000
BitRate/String	448 kb/s
Channel(s)	6
Channel(s)/String	6 channels
ChannelPositions	Front: L C R, Side: L R, LFE
ChannelPositions/String2	3/2/0.1
ChannelLayout	L R C LFE Ls Rs
SamplesPerFrame	1536
SamplingRate	48000
SamplingRate/String	48.0 kHz
FrameRate	31.250
FrameRate/String	31.250 FPS (1536 SPF)
Compression_Mode	Lossy
Compression_Mode/String	Lossy
Delay	0
Delay/String3	00:00:00.000
Delay_Source	Container
Delay_Source/String	Container
Video_Delay	-67
Video_Delay/String	-67 ms
Video_Delay/String1	-67 ms
Video_Delay/String2	-67 ms
Video_Delay/String3	-00:00:00.067
StreamSize	6212864
StreamSize/String	5.93 MiB (5%)
StreamSize/String1	6 MiB
StreamSize/String2	5.9 MiB
StreamSize/String3	5.93 MiB
StreamSize/String4	5.925 MiB
StreamSize/String5	5.93 MiB (5%)
StreamSize_Proportion	0.04884
Language	en
Language/String	English
Language/String1	English
Language/String2	en
Language/String3	eng
Language/String4	en
ServiceKind	CM
ServiceKind/String	Complete Main
Default	Yes
Default/String	Yes
Forced	No
Forced/String	No
ComplexityIndex	12
NumberOfDynamicObjects	11
BedChannelCount/String	1 channel
BedChannelConfiguration	LFE
bsid	16
dialnorm	-31
dialnorm/String	-31 dB
compr	0.53
compr/String	0.53 dB
acmod	7
lfeon	1
dialnorm_Average	-31
dialnorm_Average/String	-31 dB
dialnorm_Minimum	-31
dialnorm_Minimum/String	-31 dB
dialnorm_Maximum	-31
dialnorm_Maximum/String	-31 dB
compr_Average	-2.02
compr_Average/String	-2.02 dB
compr_Minimum	-11.51
compr_Minimum/String	-11.51 dB
compr_Maximum	1.02
compr_Maximum/String	1.02 dB
DTS-HD MA:X

Code: Select all

OriginalSourceMedium_ID	4352
OriginalSourceMedium_ID/String	4352 (0x1100)
Format	DTS
Format/String	DTS XLL X
Format/Info	Digital Theater Systems
Format/Url	https://en.wikipedia.org/wiki/DTS_(sound_system)
Format_Commercial	DTS-HD Master Audio
Format_Commercial_IfAny	DTS-HD Master Audio
Format_Settings_Mode	16
Format_Settings_Endianness	Big
Format_AdditionalFeatures	XLL X
CodecID	A_DTS
Duration	95018.666666
Duration/String	1 min 35 s
Duration/String1	1 min 35 s 19 ms
Duration/String2	1 min 35 s
Duration/String3	00:01:35.019
Duration/String4	00:01:34:72
Duration/String5	00:01:35.019 (00:01:34:72)
BitRate_Mode	VBR
BitRate_Mode/String	Variable
BitRate	4965852
BitRate/String	4 966 kb/s
Channel(s)	8
Channel(s)/String	8 channels
Channel(s)_Original	Object Based
Channel(s)_Original/String	Object Based
ChannelPositions	Object Based
ChannelPositions/String2	Object Based
ChannelLayout	Object Based
SamplesPerFrame	512
SamplingRate	48000
SamplingRate/String	48.0 kHz
FrameRate	93.750
FrameRate/String	93.750 FPS (512 SPF)
BitDepth	24
BitDepth/String	24 bits
Delay	0
Delay/String3	00:00:00.000
Delay_Source	Container
Delay_Source/String	Container
Video_Delay	0
Video_Delay/String3	00:00:00.000
StreamSize	58980676
StreamSize/String	56.2 MiB (14%)
StreamSize/String1	56 MiB
StreamSize/String2	56 MiB
StreamSize/String3	56.2 MiB
StreamSize/String4	56.25 MiB
StreamSize/String5	56.2 MiB (14%)
StreamSize_Proportion	0.13759
Title	Surround 7.1
Language	en
Language/String	English
Language/String1	English
Language/String2	en
Language/String3	eng
Language/String4	en
Default	Yes
Default/String	Yes
Forced	No
Forced/String	No
OriginalSourceMedium	Blu-ray
DTS-ES Discrete

Code: Select all

Audio_Format_List	DTS ES XXCH
Audio_Format_WithHint_List	DTS ES XXCH
Audio_Codec_List	DTS ES XXCH
CompleteName	/Users/devster/Movies/Aquaman.2018.IMAX.Edition.1080p.BluRay.DDP7.1.x264-Geek.mkv
FolderName	/Users/devster/Movies
FileNameExtension	Aquaman.2018.IMAX.Edition.1080p.BluRay.DDP7.1.x264-Geek.mkv
FileName	Aquaman.2018.IMAX.Edition.1080p.BluRay.DDP7.1.x264-Geek
FileExtension	mkv
Format	DTS
Format/String	DTS ES XXCH
Format/Info	Digital Theater Systems
Format/Url	https://en.wikipedia.org/wiki/DTS_(sound_system)
Format/Extensions	dts dtshd
Format_Commercial	DTS-ES Discrete
Format_Commercial_IfAny	DTS-ES Discrete
Format_AdditionalFeatures	ES XXCH
FileSize	5233800
FileSize/String	4.99 MiB
FileSize/String1	5 MiB
FileSize/String2	5.0 MiB
FileSize/String3	4.99 MiB
FileSize/String4	4.991 MiB
Duration	27733
Duration/String	27 s 733 ms
Duration/String1	27 s 733 ms
Duration/String2	27 s 733 ms
Duration/String3	00:00:27.733
Duration/String5	00:00:27.733
OverallBitRate_Mode	CBR
OverallBitRate_Mode/String	Constant
OverallBitRate	1509750
OverallBitRate/String	1 510 kb/s
StreamSize	63
StreamSize/String	63.0 Bytes (0%)
StreamSize/String1	63 Bytes
StreamSize/String2	63 Bytes
StreamSize/String3	63.0 Bytes
StreamSize/String4	63.00 Bytes
StreamSize/String5	63.0 Bytes (0%)
StreamSize_Proportion	0.00001
File_Modified_Date	UTC 2019-04-07 22:55:13
File_Modified_Date_Local	2019-04-08 00:55:13
FileExtension_Invalid	dts dtshd
DTS 96/24

Code: Select all

Format	DTS
Format/String	DTS 96/24
Format/Info	Digital Theater Systems
Format/Url	https://en.wikipedia.org/wiki/DTS_(sound_system)
Format_Commercial	DTS 96/24
Format_Commercial_IfAny	DTS 96/24
Format_Settings_Mode	16
Format_Settings_Endianness	Big
Format_AdditionalFeatures	96/24
Duration	295168
Duration/String	4 min 55 s
Duration/String1	4 min 55 s 168 ms
Duration/String2	4 min 55 s
Duration/String3	00:04:55.168
Duration/String5	00:04:55.168
BitRate_Mode	CBR
BitRate_Mode/String	Constant
BitRate	1509750
BitRate/String	1 510 kb/s
Channel(s)	5
Channel(s)/String	5 channels
ChannelPositions	Front: L C R, Side: L R
ChannelPositions/String2	3/2/0.0
ChannelLayout	C L R Ls Rs
SamplesPerFrame	512
SamplingRate	96000
SamplingRate/String	96.0 kHz
FrameRate	187.500
FrameRate/String	187.500 FPS (512 SPF)
BitDepth	24
BitDepth/String	24 bits
Compression_Mode	Lossy
Compression_Mode/String	Lossy
StreamSize	55703736
StreamSize/String	53.1 MiB (100%)
StreamSize/String1	53 MiB
StreamSize/String2	53 MiB
StreamSize/String3	53.1 MiB
StreamSize/String4	53.12 MiB
StreamSize/String5	53.1 MiB (100%)
StreamSize_Proportion	1.00000
TrueHD

Code: Select all

Format	MLP FBA
Format/String	MLP FBA
Format/Info	Meridian Lossless Packing FBA
Format_Commercial	Dolby TrueHD
Format_Commercial_IfAny	Dolby TrueHD
CodecID	A_TRUEHD
CodecID/Url	http://www.dolby.com/consumer/technology/trueHD.html
Duration	16184
Duration/String	16 s 184 ms
Duration/String1	16 s 184 ms
Duration/String2	16 s 184 ms
Duration/String3	00:00:16.184
Duration/String5	00:00:16.184
BitRate_Mode	VBR
BitRate_Mode/String	Variable
BitRate_Maximum	3153000
BitRate_Maximum/String	3 153 kb/s
Channel(s)	6
Channel(s)/String	6 channels
ChannelPositions	Front: L C R, Side: L R, LFE
ChannelPositions/String2	3/2/0.1
ChannelLayout	L R C LFE Ls Rs
SamplesPerFrame	40
SamplingRate	48000
SamplingRate/String	48.0 kHz
FrameRate	1200.000
FrameRate/String	1 200.000 FPS (40 SPF)
Compression_Mode	Lossless
Compression_Mode/String	Lossless
Delay	0
Delay/String3	00:00:00.000
Delay_Source	Container
Delay_Source/String	Container
Video_Delay	0
Video_Delay/String3	00:00:00.000
Default	Yes
Default/String	Yes
Forced	No
Forced/String	No
I only work in black and sometimes very, very dark grey. (Batman)
User avatar
sighunter
Posts: 22
Joined: 26 Aug 2016, 08:08

Re: Multiple audio tracks with different codecs and languages

Post by sighunter »

devster wrote: 15 Apr 2019, 00:14 So, as MediaInfo changed a bit and I realized how I was needlessly trying to replicate the logic already present in MediaBindingBean.java this is a new version of the snippet

Code: Select all

// somewhere at the top 
import net.filebot.Language

      { // map Codec + Format Profile
        def mCFP = [
          "FLAC" : "FLAC",
          "PCM" : "PCM",
          "MP3": "MP3",
          "E-AC-3 JOC": "E-AC-3",
          "DTS ES XXCH": "DTS-ES Discrete",
          "MLP FBA": "TrueHD",
          "MLP FBA 16-ch": "TrueHD"
        ]
        audio.collect { au ->
          def ac1 = any{ au['CodecID/Hint'] }{au['Format/String']}{ au['Format'] } // extends _ac_ which strips spaces > "CodecID/Hint", "Format"
          def ac2 = any{ au['CodecID/String'] }{ au['Codec/String'] }{ au['Codec'] }
          def atmos = (aco =~ /(?i:atmos)/) ? 'Atmos' : null // _aco_ uses "Codec_Profile", "Format_Profile", "Format_Commercial"
          def combined = allOf{ac1}{ac2}.join(' ')
          def fallback = any{ac1}{ac2}{aco}
          def stream = allOf
            /* _channels_ as it uses "ChannelPositions/String2", "Channel(s)_Original", "Channel(s)"
               compared to _af_ which uses "Channel(s)_Original", "Channel(s)" */
            { allOf{"${channels}"}{au['NumberOfDynamicObjects'] + "obj"}.join('+') }
            { allOf{ mCFP.get(combined, aco) }{atmos}.join('+') } /* bit risky keeping aco as default */
            { Language.findLanguage(au['Language']).ISO3.upperInitial() }
            /* _cf_ not being used > "Codec/Extensions", "Format" */
          return stream
        }.sort{a, b -> a.first() <=> b.first() }*.join(" ").join(", ") }
Unfortunately most of the map is now a bit useless and I only left the ugly MLP FBA.
aco =~ /(?i:atmos)/ is being used as aco.match(/atmos/) fails with Pattern not found: Dolby TrueHD when the string isn't present.
Expected output is:
7.1+15obj TrueHD+Atmos for Dolby Amaze Atmos trailer
5.1 AC-3 for the Amaze regular trailer
5.1 DTS-HD MA Eng, 5.1 PCM Eng, 5.1 AC-3 Eng for Dolby 3D Glass Return Trailer
5.1+11obj E-AC-3+Atmos Eng for Dolby Natures Fury Atmos trailer

I tested it on MacOS, latest version of FileBot available.

Code: Select all

/Applications/FileBot.app//Contents/MacOS/libmediainfo.dylib:
	/usr/local/lib/libmediainfo.0.dylib (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.8)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.60.2)
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 104.1.0)
	/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 489.0.0)
not very informative as version unfortunately.
Feedback welcome.
Hi devster, I want to use your current version but for the life of me can't get it to work. I just pasted it into filebot gui.
I guess I have to add a { at the beginning so the "import net.filebot.Language" is not interpreted as text but that leaves me with:
SyntaxError: missing token: }
but I can't find where to put the }. Tried at the very back but that did not help.
not a programmer, sorry, help pls
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

Code: Select all

{ import net.filebot.Language
        def mCFP = [
          "FLAC" : "FLAC",
          "PCM" : "PCM",
          "MP3": "MP3",
          "E-AC-3 JOC": "E-AC-3",
          "DTS ES XXCH": "DTS-ES Discrete",
          "MLP FBA": "TrueHD",
          "MLP FBA 16-ch": "TrueHD"
        ]
        audio.collect { au ->
          def ac1 = any{ au['CodecID/Hint'] }{au['Format/String']}{ au['Format'] }
          def ac2 = any{ au['CodecID/String'] }{ au['Codec/String'] }{ au['Codec'] }
          def atmos = (aco =~ /(?i:atmos)/) ? 'Atmos' : null
          def combined = allOf{ac1}{ac2}.join(' ')
          def fallback = any{ac1}{ac2}{aco}
          def stream = allOf
            { allOf{"${channels}"}{au['NumberOfDynamicObjects'] + "obj"}.join('+') }
            { allOf{ mCFP.get(combined, aco) }{atmos}.join('+') }
            { Language.findLanguage(au['Language']).ISO3.upperInitial() }
          return stream
        }.sort{a, b -> a.first() <=> b.first() }*.join(" ").join(", ")
}
sample: 7.1 DTS-HD Master Audio Eng


or you can use my version

Code: Select all

{
	// map codec + format_profile
	def mCFP = [ "MP3" : "MP3",
		"AC 3" : "AC3",
		"E AC 3" : "EAC3",
		"E AC 3 JOC" : "EAC3.Atmos",
		"MLP FBA" : "TrueHD",
		"MLP FBA 16 ch" : "TrueHD.Atmos",
		"DTS" : "DTS",
		"DTS ES XXCH XBR" : "DTS-HD.HRA",
		"DTS ES XBR" : "DTS-HD.HRA",
		"DTS XBR" : "DTS-HD.HRA",
		"DTS XLL" : "DTS-HD.MA",
		"DTS ES XXCH" : "DTS-ES",
		"DTS ES" : "DTS-ES",
		"DTS XLL X" : "DTS.X",
		"DTS 96 24" : "DTS 96-24",
		"AAC LC" : "AAC"]
	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/,'5.1').replaceAll(/8/,'7.1') }
	audio.collect { au ->
		def channels = any{ channelClean(au['ChannelPositionsString2'])}{ channelClean(au['ChannelsOriginal'])}{ channelClean(au['Channels']) }
		def ch = channels
			.tokenize('\\/').take(3)*.toDouble()
			.inject(0, { a, b -> a + b })
			.findAll { it > 0 }.max().toString()
		def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
		def format_profile = { ( au['Format_AdditionalFeatures'] != null) ? audioClean(au['Format_AdditionalFeatures']) : '' }
		def combined = allOf{codec}{format_profile}.join(' ')
		def stream = allOf
                   { mCFP.get(combined, 'UNKNOWN_FORMAT--'+combined+'--') }
                   { ch }
                   { au.'LanguageString3'.upperInitial() }
		println "MISSING_mCFP_FORMAT: "+combined
		return stream
	}*.join(".").unique().join(".&.")
}
sample: DTS-HD.MA.7.1.Eng
User avatar
sighunter
Posts: 22
Joined: 26 Aug 2016, 08:08

Re: Multiple audio tracks with different codecs and languages

Post by sighunter »

kim wrote: 29 Apr 2019, 16:10

Code: Select all

{ import net.filebot.Language
        def mCFP = [
          "FLAC" : "FLAC",
          "PCM" : "PCM",
          "MP3": "MP3",
          "E-AC-3 JOC": "E-AC-3",
          "DTS ES XXCH": "DTS-ES Discrete",
          "MLP FBA": "TrueHD",
          "MLP FBA 16-ch": "TrueHD"
        ]
        audio.collect { au ->
          def ac1 = any{ au['CodecID/Hint'] }{au['Format/String']}{ au['Format'] }
          def ac2 = any{ au['CodecID/String'] }{ au['Codec/String'] }{ au['Codec'] }
          def atmos = (aco =~ /(?i:atmos)/) ? 'Atmos' : null
          def combined = allOf{ac1}{ac2}.join(' ')
          def fallback = any{ac1}{ac2}{aco}
          def stream = allOf
            { allOf{"${channels}"}{au['NumberOfDynamicObjects'] + "obj"}.join('+') }
            { allOf{ mCFP.get(combined, aco) }{atmos}.join('+') }
            { Language.findLanguage(au['Language']).ISO3.upperInitial() }
          return stream
        }.sort{a, b -> a.first() <=> b.first() }*.join(" ").join(", ")
}
sample: 7.1 DTS-HD Master Audio Eng


or you can use my version

Code: Select all

{
	// map codec + format_profile
	def mCFP = [ "MP3" : "MP3",
		"AC 3" : "AC3",
		"E AC 3" : "EAC3",
		"E AC 3 JOC" : "EAC3.Atmos",
		"MLP FBA" : "TrueHD",
		"MLP FBA 16 ch" : "TrueHD.Atmos",
		"DTS" : "DTS",
		"DTS ES XXCH XBR" : "DTS-HD.HRA",
		"DTS ES XBR" : "DTS-HD.HRA",
		"DTS XBR" : "DTS-HD.HRA",
		"DTS XLL" : "DTS-HD.MA",
		"DTS ES XXCH" : "DTS-ES",
		"DTS ES" : "DTS-ES",
		"DTS XLL X" : "DTS.X",
		"DTS 96 24" : "DTS 96-24",
		"AAC LC" : "AAC"]
	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/,'5.1').replaceAll(/8/,'7.1') }
	audio.collect { au ->
		def channels = any{ channelClean(au['ChannelPositionsString2'])}{ channelClean(au['ChannelsOriginal'])}{ channelClean(au['Channels']) }
		def ch = channels
			.tokenize('\\/').take(3)*.toDouble()
			.inject(0, { a, b -> a + b })
			.findAll { it > 0 }.max().toString()
		def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
		def format_profile = { ( au['Format_AdditionalFeatures'] != null) ? audioClean(au['Format_AdditionalFeatures']) : '' }
		def combined = allOf{codec}{format_profile}.join(' ')
		def stream = allOf
                   { mCFP.get(combined, 'UNKNOWN_FORMAT--'+combined+'--') }
                   { ch }
                   { au.'LanguageString3'.upperInitial() }
		println "MISSING_mCFP_FORMAT: "+combined
		return stream
	}*.join(".").unique().join(".&.")
}
sample: DTS-HD.MA.7.1.Eng
thank you very much kim, I chose and adapted your version

FYI, I added
"PCM" : "PCM",
"DTS ES XLL" : "DTS-HD MA",
"DTS ES XXCH XLL" : "DTS-HD MA",
"AC 3 Dep" : "E-AC3",
"AAC LC SBR" : "AAC",
which displayed UNKNOWN_FORMAT for some of my movies
Last edited by sighunter on 30 Apr 2019, 14:42, edited 1 time 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 »

I think this is wrong
"DTS ES XXCH XLL" : "DTS-ES",
6.1 ch ?
because XLL is better then ES

should be
"DTS ES XXCH XLL" : "DTS-HD MA",
https://wiki.videolan.org/DTS/

you got more info on "AC 3 Dep" ?
User avatar
sighunter
Posts: 22
Joined: 26 Aug 2016, 08:08

Re: Multiple audio tracks with different codecs and languages

Post by sighunter »

kim wrote: 30 Apr 2019, 14:21 I think this is wrong
"DTS ES XXCH XLL" : "DTS-ES",
6.1 ch ?
because XLL is better then ES

should be
"DTS ES XXCH XLL" : "DTS-HD MA",
https://wiki.videolan.org/DTS/

you got more info on "AC 3 Dep" ?
you are correct of course, XLL stands for lossless, which should therefore be DTS-HD MA

"AC 3 Dep" was the german audio track from "finding dory" bluray. here is the mediainfo

Code: Select all

Audio #1
Count                                    : 305
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                                : 9548324243094778268
Format                                   : AC-3
Format                                   : E-AC-3
Format/Info                              : Enhanced AC-3
Format/Url                               : https://en.wikipedia.org/wiki/AC3
Commercial name                          : Dolby Digital Plus
Commercial name                          : Dolby Digital Plus
Format profile                           : Blu-ray Disc
Format settings, Endianness              : Big
Format_AdditionalFeatures                : Dep
Internet media type                      : audio/eac3
Codec ID                                 : A_EAC3
Duration                                 : 5823648.000000
Duration                                 : 1 h 37 min
Duration                                 : 1 h 37 min 3s 648 ms
Duration                                 : 1 h 37 min
Duration                                 : 01:37:03.648
Duration                                 : 01:37:50:19
Duration                                 : 01:37:03.648 (01:37:50:19)
Bit rate mode                            : CBR
Bit rate mode                            : konstant
Bit rate                                 : 896000
Bit rate                                 : 896 kb/s
Channel(s)                               : 6
Channel(s)                               : 6 Kanäle
Channel(s)_Original                      : 8
Channel(s)_Original                      : 8 Kanäle
Channel positions                        : Front: L C R, Side: L R, Back: L R, LFE
Channel positions                        : 3/2/0.1
Channel layout                           : L R C LFE Ls Rs Lb Rb
Samples per frame                        : 1536
Sampling rate                            : 48000
Sampling rate                            : 48,0 kHz
Samples count                            : 279535104
Frame rate                               : 31.250
Frame rate                               : 31,250 FPS (1536 SPF)
Frame count                              : 181989
Compression mode                         : Lossy
Delay                                    : 0
Delay                                    : 00:00:00.000
Delay, origin                            : Container
Delay relative to video                  : 0
Delay relative to video                  : 00:00:00.000
Stream size                              : 652248576
Stream size                              : 622 MiB (3%)
Stream size                              : 622 MiB
Stream size                              : 622 MiB
Stream size                              : 622 MiB
Stream size                              : 622,0 MiB
Stream size                              : 622 MiB (3%)
Proportion of this stream                : 0.03370
Title                                    : ger
Language                                 : de
Language                                 : Deutsch
Language                                 : Deutsch
Language                                 : de
Language                                 : deu
Language                                 : de
Service kind                             : CM
Service kind                             : Complete Main
Default                                  : Yes
Default                                  : Ja
Forced                                   : No
Forced                                   : Nein
bsid                                     : 16
dialnorm                                 : -31
dialnorm                                 : -31 dB
compr                                    : -4.53
compr                                    : -4.53 dB
acmod                                    : 7 / 5
lfeon                                    : 1 / 0
dialnorm_Average                         : -31
dialnorm_Average                         : -31 dB
dialnorm_Minimum                         : -31
dialnorm_Minimum                         : -31 dB
dialnorm_Maximum                         : -31
dialnorm_Maximum                         : -31 dB
dialnorm_Count                           : 654
compr_Average                            : 2.01
compr_Average                            : 2.01 dB
compr_Minimum                            : -4.53
compr_Minimum                            : -4.53 dB
compr_Maximum                            : 4.22
compr_Maximum                            : 4.22 dB
compr_Count                              : 252
dynrng_Average                           : 0.63
dynrng_Average                           : 0.63 dB
dynrng_Minimum                           : -3.87
dynrng_Minimum                           : -3.87 dB
dynrng_Maximum                           : 4.54
dynrng_Maximum                           : 4.54 dB
dynrng_Count                             : 653
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

kim wrote: 30 Apr 2019, 14:21 you got more info on "AC 3 Dep" ?
https://github.com/MediaArea/MediaInfoL ... l.cpp#L436
seems to be an additional format feature of E-AC-3
I only work in black and sometimes very, very dark grey. (Batman)
stephen147
Donor
Posts: 131
Joined: 01 Sep 2015, 22:40

Re: Multiple audio tracks with different codecs and languages

Post by stephen147 »

I've done my tweak on it using all the codes here as I'm not as good as you lot with coding the base code.

Thanks to all concerned.

:!: This only gets the 1st audio channel.

Code: Select all

{
	def mCFP =
	[
	'AAC LC SBR' : 'AAC',
	'AAC LC' : 'AAC',
	'AC 3 Dep' : 'E-AC3',
	'AC 3' : 'AC3',
	'DTS 96 24' : 'DTS 96-24',
	'DTS ES XBR' : 'DTS-HD HRA',
	'DTS ES XLL' : 'DTS-HD MA',
	'DTS ES XXCH XBR' : 'DTS-HD HRA',
	'DTS ES XXCH XLL' : 'DTS-HD MA',
	'DTS ES XXCH' : 'DTS-ES',
	'DTS ES' : 'DTS-ES',
	'DTS XBR' : 'DTS-HD HRA',
	'DTS XLL X' : 'DTS X',
	'DTS XLL' : 'DTS-HD MA',
	'DTS' : 'DTS',
	'E AC 3 JOC' : 'EAC3 Atmos',
	'E AC 3' : 'EAC3',
	'MLP FBA 16 ch' : 'TrueHD Atmos',
	'MLP FBA' : 'TrueHD',
	'MP3' : 'MP3',
	'PCM' : 'PCM'
	]
	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/,'5.1').replaceAll(/8/,'7.1') }
	audio.collect { au ->
		def channels = any{ channelClean(au['ChannelPositionsString2'])}{ channelClean(au['ChannelsOriginal'])}{ channelClean(au['Channels']) }
		def dynChannel = {au['NumberOfDynamicObjects'] + 'Objs\''};
		def ch = channels
		.tokenize('\\/').take(3)*.toDouble()
		.inject(0, { a, b -> a + b })
		.findAll { it > 0 }.max().toString() + 'ch'
		def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
		def format_profile = { ( au['Format_AdditionalFeatures'] != null) ? audioClean(au['Format_AdditionalFeatures']) : '' }
		def combined = allOf{codec}{format_profile}.join(' ')
		def stream = allOf
		{ mCFP.get(combined, 'UNKNOWN_FORMAT--'+combined+'--') }
		{ dynChannel }
		{ ch }
		//{ au.'LanguageString3'.upperInitial() }
		println "MISSING_mCFP_FORMAT: "+combined
		return stream
		}[0].join( ' ' )
	}
:!: Output from the few files in my collection that contain these audio formats + some others that don't.
Image
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

This took me some time to make, I hope you like it:

All 1 one format, use:

Code: Select all

allStreams.join(' & ').space('.')
or

Code: Select all

bestStream.space('.')
Remember to add or edit the order of "codecList" if you prefer one codec over another
(first to last order)

Code: Select all

{
	def codecList =
	[
	'MP3' : 'MP3',
	'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 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/,'5.1').replaceAll(/8/,'7.1') }
	def combined

	audio.collect{ au ->
		def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
		def format_profile = { ( au['Format_AdditionalFeatures'] != null) ? audioClean(au['Format_AdditionalFeatures']) : '' }
		combined = allOf{codec}{format_profile}.join(' ')
		def channels = any{ channelClean(au['ChannelPositionsString2'])}{ channelClean(au['ChannelsOriginal'])}{ channelClean(au['Channels']) }
		def ch = channels
		.tokenize('\\/').take(3)*.toDouble()
		.inject(0, { a, b -> a + b })
		.findAll { it > 0 }.max().toString()

		audioStreams << ['index' : codecList.findIndexOf {it.key == combined}, 'codec' : codecList.get(combined, 'UNKNOWN_FORMAT'), 'combined' : combined, 'ch' : ch, 'objects' : any{'(' + au['NumberOfDynamicObjects'] + ' Objs)'}{' '}, 'lang' : any{au.'LanguageString3'.upperInitial()}{' '} ]
		return audioStreams
	}

	def allStreams = audioStreams.collect{ it.codec + ' ' + it.ch + ' ' + it.objects + ' ' + it.lang }.unique()
	def bestStream = audioStreams.unique().findAll{ it.index == audioStreams.index.max() }.collect{ it.codec + ' ' + it.ch + ' ' + it.objects + ' ' + it.lang }.find{ it }

	allStreams.join(' & ').space('.')
	bestStream.space('.')
}
stephen147
Donor
Posts: 131
Joined: 01 Sep 2015, 22:40

Re: Multiple audio tracks with different codecs and languages

Post by stephen147 »

kim wrote: 04 May 2019, 03:27 This took me some time to make, I hope you like it:
Cool, thanks for the example. I'll stick with grabbing the [0] stream as this will be the primary one. ;)
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

Well you can just use

Code: Select all

allStreams.first()
Version 2
added

Code: Select all

[allStreams.first(), bestStream].unique().join(' & ').space('.')
e.g.
DTS-HD.MA.7.1.Eng.&.TrueHD.Atmos.7.1.(11.Objs).Eng
if you don't want some of the output just edit

Code: Select all

def filter = { it.codec + ' ' + it.ch + ' ' + it.objects + ' ' + it.lang }
you can also use this to list the first 3

Code: Select all

allStreams.take(3).join(' & ').space('.')

Code: Select all

{
	def codecList =
	[
	'MP3' : 'MP3',
	'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 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/,'5.1').replaceAll(/8/,'7.1') }
	def filter = { it.codec + ' ' + it.ch + ' ' + it.objects + ' ' + it.lang }
	def combined

	audio.collect{ au ->
		def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
		def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
		def channels = any{ channelClean(au['ChannelPositionsString2'])}{ channelClean(au['ChannelsOriginal'])}{ channelClean(au['Channels']) }
		def ch = channels.tokenize('\\/').take(3)*.toDouble().inject(0, { a, b -> a + b }).findAll { it > 0 }.max().toString()

		combined = allOf{codec}{format_profile}.join(' ')
		audioStreams << ['index' : codecList.findIndexOf {it.key == combined}, 'codec' : codecList.get(combined, 'UNKNOWN_FORMAT'), 'combined' : combined, 'ch' : ch, 'objects' : any{'(' + au['NumberOfDynamicObjects'] + ' Objs)'}{' '}, 'lang' : any{au.'LanguageString3'.upperInitial()}{' '} ]
		return audioStreams
	}

	def allStreams = audioStreams.collect{ filter(it) }.unique()
	def bestStream = audioStreams.unique().findAll{ it.index == audioStreams.index.max() }.collect{ filter(it) }.find{ it }

	allStreams.join(' & ').space('.')
	bestStream.space('.')
	[allStreams.first(), bestStream].unique().join(' & ').space('.')
}
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

Version 3
added check for defaultStream

Code: Select all

{
	def codecList =
	[
	'MP3' : 'MP3',
	'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 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/,'5.1').replaceAll(/8/,'7.1') }
	def filter = { it.codec + ' ' + it.ch + ' ' + it.objects + ' ' + it.lang }	

	audio.collect{ au ->
		def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
		def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
		def channels = any{ channelClean(au['ChannelPositionsString2'])}{ channelClean(au['ChannelsOriginal'])}{ channelClean(au['Channels']) }
		def ch = channels.tokenize('\\/').take(3)*.toDouble().inject(0, { a, b -> a + b }).findAll { it > 0 }.max().toString()

		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, 'objects' : any{'(' + au['NumberOfDynamicObjects'] + ' Objs)'}{' '}, 'lang' : any{au.'LanguageString3'.upperInitial()}{' '} ]
		return audioStreams
	}

	def allStreams = audioStreams.collect{ filter(it) }.unique()
	def bestStream = audioStreams.unique().findAll{ it.index == audioStreams.index.max() }.collect{ filter(it) }.find{ it }
	def defaultStream = audioStreams.findAll{it.default == true}.collect{ filter(it) }.find{ it }
	
	allStreams.join(' & ').space('.')
	bestStream.space('.')
	[defaultStream, bestStream].unique().join(' & ').space('.')
}
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

You may try this for all audio streams:

Code: Select all

      { import java.math.RoundingMode
        // audio map, fill in with your preferred one
        def mCFP = []

        audio.collect { au ->
          /* Format seems to be consistently defined and identical to Format/String
             Format_Profile and Format_AdditionalFeatures instead
             seem to be usually mutually exclusive
             Format_Commercial (and _If_Any variant) seem to be defined
             mainly for Dolby/DTS formats */
          def _ac = any
                      { allOf
                        { au["Format"] }
                        { au["Format_Profile"] }
                        { au["Format_AdditionalFeatures"] }
                        .join(" ") }
                      { au["Format_Commercial"] }

          /* original _aco_ binding uses "Codec_Profile", "Format_Profile", "Format_Commercial" */
          def _aco = any{ au["Codec_Profile"] }{ au["Format_Profile"] }{ au["Format_Commercial"] }

          /* def atmos = (_aco =~ /(?i:atmos)/) ? "Atmos" : null */
          def isAtmos = {
            def _fAtmos = any{audio.FormatCommercial =~ /(?i)atmos/}{false}
            def _oAtmos = any{audio.NumberOfDynamicObjects}{false}
            if (_fAtmos || _oAtmos) { return "Atmos" }
          }

          /* _channels_ uses "ChannelPositions/String2", "Channel(s)_Original", "Channel(s)"
             compared to _af_ which uses "Channel(s)_Original", "Channel(s)"
             using another variable allows calculating the output for each audio stream */
          String    _channels = any
                                  { au["ChannelPositions/String2"] }
                                  { au["Channel(s)_Original"] }
                                  { au["Channel(s)"] }
          String    _ch

          /* _channels can contain no numbers */
          Object    splitCh = _channels =~ /^(?i)object.based$/ ? "Object Based" :
                              _channels.tokenize("\\/\\.")
                              /* the below may be needed for 3/2/0.2.1/3/2/0.1 files, of
                                  which I have no examples anymore since MediaInfo 18.12 */
                              // _channels.tokenize("\\/").take(3)*.tokenize("\\.")
                              //          .flatten()*.toInteger()
          switch (splitCh) {
            case { it instanceof String }:
              /* Object Based channels, which usually have also a numeric value */
              def _chDeep = any{ au["Channel(s)"] }{ au["Channel(s)/String"].replaceAll("channels", "") }
              _ch = allOf{ splitCh }{ _chDeep + "ch" }.join(" ")
              break

            case { it.size > 4 }:
              /* format similar to 3/2/0.2.1, coercing the last value to Double fails */
              def wide = splitCh.takeRight(1)
              Double main = splitCh.take(4)*.toDouble().inject(0, { a, b -> a + b })
              Double sub = Double.parseDouble("0." + wide.last())
              _ch = (main + sub).toBigDecimal().setScale(1, RoundingMode.HALF_UP).toString()
              break

            case { it.size > 1 }:
              /* original logic is _mostly_ unchanged if format is like 3/2/0.1 */
              Double sub = Double.parseDouble(splitCh.takeRight(2).join("."))
              _ch = splitCh.take(2)*.toDouble().plus(sub).inject(0, { a, b -> a + b })
                           .toBigDecimal().setScale(1, RoundingMode.HALF_UP).toString()
              break

            default:
              _ch = splitCh.first().toDouble()
          }
I only work in black and sometimes very, very dark grey. (Batman)
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

Version 4
changed: bestStream to preferredStream
added: bestBitRate
added: support for chFilter (change 'ch' : ch, to "'ch' : chFilter,")

Code: Select all

{
	def codecList =
	[
	'MP3' : 'MP3',
	'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 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})

	allStreams.join(' & ').space('.')
	preferredStream.space('.')
	defaultStream.space('.')
	bestBitRate.space('.')
	[bestBitRate, preferredStream].unique().join(' & ').space('.')
	[defaultStream, bestBitRate].unique().join(' & ').space('.')	
}
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

I've got new builds for testing here:
https://get.filebot.net/filebot/BETA/

The new builds come with MediaInfo 19.04 which hopefully makes things work better again.
:idea: Please read the FAQ and How to Request Help.
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

Found a new weird audio.
With MediaInfo 18.12 and 19.04 the result is the following:

Code: Select all

Audio
Count                            : 298
StreamCount                      : 1
StreamKind                       : Audio
StreamKind/String                : Audio
StreamKindID                     : 0
StreamOrder                      : 1
ID                               : 2
ID/String                        : 2
UniqueID                         : 8654701659007087417
Format                           : AC-3
Format/String                    : E-AC-3
Format/Info                      : Enhanced AC-3
Format/Url                       : https://en.wikipedia.org/wiki/AC3
Format_Commercial                : Dolby Digital Plus
Format_Commercial_IfAny          : Dolby Digital Plus
Format_Profile                   : Blu-ray Disc
Format_Settings_Endianness       : Big
Format_AdditionalFeatures        : Dep
InternetMediaType                : audio/eac3
CodecID                          : A_EAC3
Duration                         : 8089088.000000
Duration/String                  : 2h 14mn
Duration/String1                 : 2h 14mn 49s 88ms
Duration/String2                 : 2h 14mn
Duration/String3                 : 02:14:49.088
Duration/String4                 : 02:15:54:10
Duration/String5                 : 02:14:49.088 (02:15:54:10)
BitRate_Mode                     : CBR
BitRate_Mode/String              : CBR
BitRate                          : 1280000
BitRate/String                   : 1280 Kbps
Channel(s)                       : 8
Channel(s)/String                : 8 channel3
ChannelPositions                 : Front: L C R, Side: L R, Back: L R, LFE
ChannelPositions/String2         : 3/2/0.1
ChannelLayout                    : L R C LFE Ls Rs Lb Rb
SamplesPerFrame                  : 1536
SamplingRate                     : 48000
SamplingRate/String              : 48.0 KHz
SamplingCount                    : 388276224
FrameRate                        : 31.250
FrameRate/String                 : 31.250 fps3 (1536 SPF)
FrameCount                       : 252784
Compression_Mode                 : Lossy
Compression_Mode/String          : Lossy
Delay                            : 0
Delay/String3                    : 00:00:00.000
Delay_Source                     : Container
Delay_Source/String              : Container
Video_Delay                      : 0
Video_Delay/String3              : 00:00:00.000
StreamSize                       : 1294254080
StreamSize/String                : 1.21 GiB (6%)
StreamSize/String1               : 1 GiB
StreamSize/String2               : 1.2 GiB
StreamSize/String3               : 1.21 GiB
StreamSize/String4               : 1.205 GiB
StreamSize/String5               : 1.21 GiB (6%)
StreamSize_Proportion            : 0.06499
Title                            : Dolby Digital Plus Audio / 7.1 / 48 kHz / 1280 kbps
Language                         : en
Language/String                  : en
Language/String1                 : en
Language/String2                 : en
Language/String3                 : eng
Language/String4                 : en
ServiceKind                      : CM
ServiceKind/String               : Complete Main
Default                          : Yes
Default/String                   : Yes
Forced                           : No
Forced/String                    : No
bsid                             : 16
dialnorm                         : -31
dialnorm                         : -31 dB
compr                            : -0.28
compr                            : -0.28 dB
acmod                            : 7 / 5
lfeon                            : 1 / 0
dialnorm_Average                 : -31
dialnorm_Average                 : -31 dB
dialnorm_Minimum                 : -31
dialnorm_Minimum                 : -31 dB
dialnorm_Maximum                 : -31
dialnorm_Maximum                 : -31 dB
dialnorm_Count                   : 3476
compr_Average                    : -2.76
compr_Average                    : -2.76 dB
compr_Minimum                    : -6.88
compr_Minimum                    : -6.88 dB
compr_Maximum                    : -0.56
compr_Maximum                    : -0.56 dB
compr_Count                      : 700
Now, a few points:
  • Format/String and Format differ (AC-3 vs E-AC-3) for this I modified my last script by changing the Format into any{au["Format/String"] }{ au["Format"] }
  • never seen Format_Profile: Blu-ray Disc or Format_AdditionalFeatures: Dep, any info on them?
  • channels seem 8, which is consistent with ChannelPositions and ChannelLayout but not with ChannelPositions/String2 which reports 5.1, do I really need to parse raw ChannelPositions to fix this? any smarter ideas?
I'm a bit speechless.
I only work in black and sometimes very, very dark grey. (Batman)
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

I've never seen a Title field for an audio stream:

Code: Select all

Title                            : Dolby Digital Plus Audio / 7.1 / 48 kHz / 1280 kbps
I guess this Title tag is supposed to show up when you select a given audio stream in your media player. Someone thought this is a good display value for this audio stream.

Might be useful, but probably won't be defined for the vast majority of files.
:idea: Please read the FAQ and How to Request Help.
devster
Posts: 417
Joined: 06 Jun 2017, 22:56

Re: Multiple audio tracks with different codecs and languages

Post by devster »

My assumption was that the "title" field is an optional metadata tag and I wouldn't want to rely on it.

For naming purposes I found out that the AdditionalFeatures bascically means a hybrid stream.
In this case there seem to be:
  • "base" 5.1 AC-3 stream, decodable by an AC-3 decoder. (The Format field which represents the "minimal" decoder required)
  • Dependant E-AC-3 stream with 2 additional channels, optional and apparently interleaved with the first one (The Format/String apparently)
It seems to be part of E-AC-3 which allows embedding a core AC-3 stream.

The ChannelPositions/String2 seems a bug, a workaround in this specific case would be to tokenize by comma ChannelPositions (Front: L C R, Side: L R, Back: L R, LFE), strip whatever's before the colon, count number of words in the string (3,2,2,1) with the last one being the Low Frequency Effects.
I only work in black and sometimes very, very dark grey. (Batman)
antisgae
Posts: 13
Joined: 29 Aug 2018, 22:48

Re: Multiple audio tracks with different codecs and languages

Post by antisgae »

Just in case it helps to somebody i modified the code and added also flac audio.
Looks like this: "ESP ac3 2.0 ENG flac 1.0"
./1961 - Homicidal - Homicidio - William Castle/1961 - Homicidal - Homicidio - William Castle BDR 1080p 35.0Mbps ESP ac3 2.0 ENG flac 1.0 SUB ENG ESP.mkv

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

Re: Multiple audio tracks with different codecs and languages

Post by kim »

added bestPreferredLang = to find best stream in your preferred language (preferredLang) or default as backup
e.g. German

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

Re: Multiple audio tracks with different codecs and languages

Post by kim »

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 )

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'}
}
Only use one of these lines:

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}
useChFilter = this line:

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 )
= if AAC/MP3 2.0 OR AC3/EAC3/DTS/TrueHD/MLPFBA 5.1, then don't show the 2.0/5.1 part

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)
nartana
Posts: 37
Joined: 02 May 2019, 22:28

Re: Multiple audio tracks with different codecs and languages

Post by nartana »

I couldn't find an answer (bc it's probably obvious): Kim and others helped evolve the def codecList expression, in this thread, but I'm not sure where/how to use that long expression, that defines all the different possible codecs/formats. I want to make sure any movie with Atmos indicates as much, but that doesn't always happen.

I use CLI via SSH to rename media on my Synology (where I have FileBot installed.) It works great. I have a basic understanding of the expressions I've compiled. But is "codecList" a file in my FileBot package that's installed on my Syno? Do I edit that to add the many awesome codecs in the code Kim has evolved, here? Or is that long expression something I add to a CLI command each time I want to process files in my 'unsorted' folder?
nartana
Posts: 37
Joined: 02 May 2019, 22:28

Re: Multiple audio tracks with different codecs and languages

Post by nartana »

Renaming output, CLI via Synology FB install (all packages updated):

Code: Select all

MovieTitle (2019) 118mins [18.0 Mbps] (1920x800) Dolby Digital 5.1 [6ch]
Renaming output, new Windows 10 installation of standalone FB app:

Code: Select all

SameMovieTitle 118mins (18.0 Mbps) (1920x800) TrueHD 7.1 Atmos [8ch]
According to MediaInfo, the second (Windows) output is correct: (8ch Atmos)

I would like to continue using CLI via Synology package - I’ve tried at least ten different expressions I’ve found on the forums, re. audio codec, but it always outputs 5.1 Dolby.

I know I'm not providing all the info you need, but if we know that all the modules are updated to latest, on the Syno server... is there a default reason why outputs differ?
nartana
Posts: 37
Joined: 02 May 2019, 22:28

Re: Multiple audio tracks with different codecs and languages

Post by nartana »

This is the expression I use via CLI (which produces the incorrect codec/channel output, on rename):

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 copy
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

Compare filebot -script fn:sysinfo output. Different versions of MediaInfo may yield different values.
:idea: Please read the FAQ and How to Request Help.
nartana
Posts: 37
Joined: 02 May 2019, 22:28

Re: Multiple audio tracks with different codecs and languages

Post by nartana »

Thank you @rednoah (also for indulging sloppy question format.)

The output is below — I assume the next step is for me to check the version I'm using vs. the newest version available.

Code: 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********
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

Well, it's not about being newer or older, but about being different. FileBot will bundle the latest version on platform-dependent builds, e.g. MSI package. But on platforms where there is more than one CPU architecture, the FileBot package will only bundle platform-independent components, i.e. SPK package, and rely on 3rd party dependencies for platform-dependent components, i.e. MediaInfo, Chromaprint, etc. These tend to be somewhat outdated on Synology because they're maintained by 3rd party volunteers.

MediaInfo: 19.09 is the latest one though, so that should work exactly the same as the latest beta, which bundles this version of MediaInfo as well:
viewtopic.php?t=1609
:idea: Please read the FAQ and How to Request Help.
nartana
Posts: 37
Joined: 02 May 2019, 22:28

Re: Multiple audio tracks with different codecs and languages

Post by nartana »

Thank you, I didn't know that about Syno packages. Now it makes more sense.

I'll test results running FB on a MacMini that's connected to the Syno (to see if my results differ vs. running the Syno FB build.)

Since I'll be trying FB on a diff. platform, it's a good time to ask:
Is the GUI (app) version of FB the only way to use these long { def codecList... } definitions of audio codecs? Like in the "Filter" field of the GUI version?

Or, if there's a thread, or keywords that'll help me search how to use these w/ the CLI-based FB operations...?

I know it's a real huckleberry question. I'm brain-blocked on the next step with this.

Thanks for helping me better understand these diff results (Syno FB vs. Windows FB.)
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

What makes you think that format expressions work different in the GUI and the CLI? They're the same of course. Format expressions work the same in both GUI and CLI, it's literally the same code.


:idea: Except passing complex multi-line argument values on the command-line might be a little bit troublesome, doable, but annoying. Use the @file syntax for reading command-line arguments from external text files.


:idea: You can use filebot -script fn:mediainfo /files to dump raw media info tables, so you can see and compare the raw data that FileBot is getting back from libmediainfo.
:idea: Please read the FAQ and How to Request Help.
nartana
Posts: 37
Joined: 02 May 2019, 22:28

Re: Multiple audio tracks with different codecs and languages

Post by nartana »

Thanks again — that makes so much sense, that the interface is the interface (and expressions work the same, underneath.)

And thank you for the tools. Time to learn about syntax and to compare the data FileBot is getting back from libmediainfo.

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.

Cheers @rednoah.

-Erin
User avatar
rednoah
The Source
Posts: 24644
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Multiple audio tracks with different codecs and languages

Post by rednoah »

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.
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. :lol:
:idea: Please read the FAQ and How to Request Help.
Keven07
Posts: 22
Joined: 13 Apr 2020, 08:39

Re: Multiple audio tracks with different codecs and languages

Post by Keven07 »

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 )

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'}
}
Only use one of these lines:

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}
useChFilter = this line:

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 )
= if AAC/MP3 2.0 OR AC3/EAC3/DTS/TrueHD/MLPFBA 5.1, then don't show the 2.0/5.1 part

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)
this what i ' m looking for many days, now my search is over. <3
Thanks for this format, Really appreciate your work
AbedlaPaille
Posts: 107
Joined: 12 Apr 2020, 04:02

Re: Multiple audio tracks with different codecs and languages

Post by AbedlaPaille »

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 )

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'}
}
Only use one of these lines:

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}
useChFilter = this line:

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 )
= if AAC/MP3 2.0 OR AC3/EAC3/DTS/TrueHD/MLPFBA 5.1, then don't show the 2.0/5.1 part

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

Re: Multiple audio tracks with different codecs and languages

Post by kim »

try replacing the top part with:

Code: Select all

{
	import net.filebot.Language;	
	def preferredLang = Language.findLanguage(info.OriginalLanguage).ISO3.upperInitial()
but because of e.g.
iso_639_1=nl iso_639_3=nld iso_639_2B=dut tag=nl-NL names=[Dutch]

Code: Select all

{
	import net.filebot.Language;	
	def preferredLang = Language.findLanguage(info.OriginalLanguage).iso_639_2B.upperInitial()
or

Code: Select all

{
	import net.filebot.Language;	
	def preferredLang = Language.findLanguage(info.OriginalLanguage).ISO3B.upperInitial()
haveabreak
Posts: 6
Joined: 05 Jul 2020, 21:35

Re: Multiple audio tracks with different codecs and languages

Post by haveabreak »

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 )

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'}
}
Only use one of these lines:

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}
useChFilter = this line:

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 )
= if AAC/MP3 2.0 OR AC3/EAC3/DTS/TrueHD/MLPFBA 5.1, then don't show the 2.0/5.1 part

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)
How could I add this to my existing naming convention?

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}
Would gladly send some money for help because I'm a total noob. Either here or on Discord jezal#5787
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

very easy just replace the

Code: Select all

{ac}{channels}
like so:

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}
if you really want is on one line just add a ; after all the "def blocks"e.g.

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}
btw: the normal way is video before audio

Code: Select all

{vc}{ac}
haveabreak
Posts: 6
Joined: 05 Jul 2020, 21:35

Re: Multiple audio tracks with different codecs and languages

Post by haveabreak »

kim wrote: 30 Jul 2020, 17:45 very easy just replace the

Code: Select all

{ac}{channels}
like so:

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}
if you really want is on one line just add a ; after all the "def blocks"e.g.

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}
btw: the normal way is video before audio

Code: Select all

{vc}{ac}
Wow, thank you so much for the help! This helps a lot!
btw: the normal way is video before audio

Code: Select all

{vc}{ac}
Tried to edit it as you said. How does that look and how would you do it?

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}
Thanks again, I really appreciate your help!
kim
Power User
Posts: 1251
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

looks ok

the only thing is choice one and maybe one more as backup

Code: Select all

{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}
RudyBzh
Posts: 23
Joined: 31 Mar 2013, 14:05

Re: Multiple audio tracks with different codecs and languages

Post by RudyBzh »

Hi,
I'm trying to include this complex piece of code but have some movies not matching (NO_AUDIO).
How can I troubleshoot this ?

Here are some exemples with "mediainfo -f" results of audio parts.

Exemple 1

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
Exemple 2

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
Example 3 :

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
Also, this part never throws "null" if there is no "NumberOfDynamicObjets"

Code: Select all

'objects' : any{ '[' + au['NumberOfDynamicObjects'] + ' Objs]' }{null}
So I have a lot of movies with "[null.Objs]"


I don't understand the "AddToList" option ? What is it made for and how to use it.


Lastly, idealy, I would like to rename my file with this result :
Best French language available & Best quality if different ; So 2 results max but could be 1 if all the same (unique). Something like :
[AC3 5.1 Fra] // with hidden [AAC 2.0 Fra & AC3 5.1 Eng] (not better qualities)
[AC3 5.1 Fra & DTS-ES 7.0 Eng] ; Because Eng version is better

I tried this without success : [bestPreferredLang, bestBitRate].unique().join(' & ')
It shows more than 2 results for a lot of movies.

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

Re: Multiple audio tracks with different codecs and languages

Post by kim »

Version 5

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

e.g. replace

Code: Select all

{bestPreferredLang}
with

Code: Select all

{[bestPreferredLang, bestBitRate].findAll().unique().join(' & ')}
sample "AC3 5.1 Fra & DTS-HD MA 7.1 Eng"
RudyBzh
Posts: 23
Joined: 31 Mar 2013, 14:05

Re: Multiple audio tracks with different codecs and languages

Post by RudyBzh »

Thanks a lot kim. Seems to perfectly makes the job.
I tried to change the last line :

Code: Select all

any{addToList}{bestPreferredLang}{defaultStream}{bestBitRate}{preferredStream}
with this :

Code: Select all

{[bestPreferredLang, bestBitRate].findAll().unique().join(' & ')}
But it's not working (I only get 1 result even if there should be 2 independent results for some movies...).
But doing like this, as you told, is working :

Code: Select all

any{addToList}{[bestPreferredLang, bestBitRate].findAll().unique().join(' & ')}{defaultStream}{bestBitRate}{preferredStream}
I'm just confused & really don't understand why ?!

If I take attributes "one by one", like only "{bestBitRate}", I can't get it to work (it gives me a result but not the "best bitrate").
I'm surely missing something like dealing with lists & findAll...
Also, if I remove the last line, as if I don't want to get anything, except "NO_AUDIO", I still get a result... I don't know from where : The "return audiostream" ?! The "any{audio.collect..." ?!

Well, the good thing is that it seems to be working. The bad thing is that I don't understand... but the problem is... me ;)
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: 24644
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: 24644
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