Page 1 of 3

Multiple audio tracks with different codecs and languages

Posted: 21 Aug 2017, 23:29
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.

Re: Multiple audio tracks with different codecs and languages

Posted: 21 Aug 2017, 23:54
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.

Re: Multiple audio tracks with different codecs and languages

Posted: 22 Aug 2017, 01:08
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(' + ');
}

Re: Multiple audio tracks with different codecs and languages

Posted: 22 Aug 2017, 09:20
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

Re: Multiple audio tracks with different codecs and languages

Posted: 22 Aug 2017, 17:20
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

Re: Multiple audio tracks with different codecs and languages

Posted: 22 Aug 2017, 17:43
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.

Re: Multiple audio tracks with different codecs and languages

Posted: 22 Aug 2017, 18:07
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(", ") }

Re: Multiple audio tracks with different codecs and languages

Posted: 23 Aug 2017, 20:33
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?

Re: Multiple audio tracks with different codecs and languages

Posted: 23 Aug 2017, 22:50
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

Re: Multiple audio tracks with different codecs and languages

Posted: 22 Jan 2018, 18:01
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

Re: Multiple audio tracks with different codecs and languages

Posted: 22 Jan 2018, 23:03
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).

Re: Multiple audio tracks with different codecs and languages

Posted: 07 Apr 2018, 15:01
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?

Re: Multiple audio tracks with different codecs and languages

Posted: 07 Apr 2018, 23:07
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.

Re: Multiple audio tracks with different codecs and languages

Posted: 08 Apr 2018, 10:01
by BabyRay
my mistake, mean 6.0 E-AC3 and 11.2 DTS.
No Files for testing? :(

Re: Multiple audio tracks with different codecs and languages

Posted: 08 Apr 2018, 11:18
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)

Re: Multiple audio tracks with different codecs and languages

Posted: 13 Jun 2018, 14:45
by sighunter
thanks for all the work, this was exactly what I needed and could never have done alone

Re: Multiple audio tracks with different codecs and languages

Posted: 14 Jun 2018, 11:30
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.

Re: Multiple audio tracks with different codecs and languages

Posted: 03 Jul 2018, 22:37
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. :)

Re: Multiple audio tracks with different codecs and languages

Posted: 04 Jul 2018, 01:50
by rednoah
:idea: Use the @file syntax for reading command-line arguments from external text files.

Re: Multiple audio tracks with different codecs and languages

Posted: 12 Apr 2019, 12:53
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/

Re: Multiple audio tracks with different codecs and languages

Posted: 12 Apr 2019, 18:51
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.

Re: Multiple audio tracks with different codecs and languages

Posted: 12 Apr 2019, 19:54
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(", ") }

Re: Multiple audio tracks with different codecs and languages

Posted: 13 Apr 2019, 03:30
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:
https://www.filebot.net/forums/viewtopic.php?f=5&t=4285

Re: Multiple audio tracks with different codecs and languages

Posted: 13 Apr 2019, 05:23
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

Re: Multiple audio tracks with different codecs and languages

Posted: 13 Apr 2019, 10:15
by sighunter
thank you very much kim, devster and rednoah. I went with { au['Format_Commercial'] } like kim suggested and adapted the audio map