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: 22899
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: 22899
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
Post Reply