Multiple audio tracks with different codecs and languages

All about user-defined episode / movie format expressions
deejayexe
Posts: 6
Joined: 19 Jun 2022, 23:41

Re: Multiple audio tracks with different codecs and languages

Post by deejayexe »

kim wrote: 21 Nov 2022, 20:09 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')}
I have been testing it and now it is correct not as I had it, but I see a detail, if the audio is the same in my language ES and in English EN for example it only shows it once like this ES EAC3 5.1 when it should be if the audio is the same same ES-EN EAC3 5.1 or ES|EN with def preferredLang = 'ES'
I tried the code a few posts back but it doesn't work for me, could you indicate what is missing?
Sample:
ES AC3 5.1 - EN DTS-HD MA 7.1 (better audio for both languages)
ES-EN AC3 5.1 if audio it is same


Thanks for your time
kim
Power User
Posts: 1243
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

cant you just remove the

Code: Select all

.unique()
from

Code: Select all

{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}
?
deejayexe
Posts: 6
Joined: 19 Jun 2022, 23:41

Re: Multiple audio tracks with different codecs and languages

Post by deejayexe »

kim wrote: 25 Nov 2022, 15:38 cant you just remove the

Code: Select all

.unique()
from

Code: Select all

{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}
?
Ok I have eliminated that function from the code but now in many examples the same language appears repeated like this:

ES EAC3 5.1 - ES EAC3 5.1

And checking the media info has ES and EN.

When what I get should be ES-EN EAC3 5.1
or ES|EN EAC3 5.1 Or if they are different audios ES EAC3 5.1 - EN AC3 5.1
kim
Power User
Posts: 1243
Joined: 15 May 2014, 16:17

Re: Multiple audio tracks with different codecs and languages

Post by kim »

try this:
replace the last part

Code: Select all

	def custom = audioStreams.groupBy{ it.lang }.values()*.findAll{ it.lang == preferredLang || it.bitrate == audioStreams.bitrate.max() }.findAll { it }.collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.sort{ it.lang != preferredLang }.collect{ "${it.lang.replace('null', '')} ${it.codec} ${it.ch}" }.join(' - ')

	any{addToList}{custom}{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}{defaultStream}{bestBitRate}{preferredStream}
sample:
ES AC3 5.1 - EN DTS-HD MA 7.1
deejayexe
Posts: 6
Joined: 19 Jun 2022, 23:41

Re: Multiple audio tracks with different codecs and languages

Post by deejayexe »

kim wrote: 27 Nov 2022, 14:41 try this:
replace the last part

Code: Select all

	def custom = audioStreams.groupBy{ it.lang }.values()*.findAll{ it.lang == preferredLang || it.bitrate == audioStreams.bitrate.max() }.findAll { it }.collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.sort{ it.lang != preferredLang }.collect{ "${it.lang.replace('null', '')} ${it.codec} ${it.ch}" }.join(' - ')

	any{addToList}{custom}{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}{defaultStream}{bestBitRate}{preferredStream}
sample:
ES AC3 5.1 - EN DTS-HD MA 7.1
Ok I have verified it by removing the last part and adding as it says, but it is not correct, you can see the image with few examples:
Image

This code that u said me with last changes in the end of code

Code: Select all

{
	def preferredLang = 'ES'
	def fallbackLang = any{languages*.ISO2*.upper().join('-')}{'YourDefaultLandHere'}
	def useChFilter = false
	def filter = { [it.lang, it.codec, it.ch].findAll() }

	def codecList =
	[
	'MPEG Audio' : 'MP2',
	'MP3' : 'MP3',
	'PCM' : 'PCM',
	'FLAC' : 'FLAC',
	'AAC LC' : 'AAC',
	'AAC LC SBR' : 'AAC',
	'AAC LC SBR PS' : 'AAC',
	'AC 3' : 'AC3',
	'AC 3 Dep' : 'EAC3',
	'E AC 3' : 'EAC3',
	'E AC 3 JOC' : 'EAC3 Atmos',
	'AC 3 Dep JOC' : 'EAC3 Atmos',
	'DTS' : 'DTS',
	'DTS 96 24' : 'DTS 96-24',
	'DTS ES' : 'DTS-ES',
	'DTS ES XXCH' : 'DTS-ES',
	'DTS XBR' : 'DTS-HD HRA',
	'DTS ES XBR' : 'DTS-HD HRA',
	'DTS ES XXCH XBR' : 'DTS-HD HRA',
	'DTS XLL' : 'DTS-HD MA',
	'DTS ES XLL' : 'DTS-HD MA',
	'DTS ES XXCH XLL' : 'DTS-HD MA',
	'DTS XLL X' : 'DTS X',
	'MLP FBA' : 'TrueHD',
	'MLP FBA 16 ch' : 'TrueHD Atmos'
	]

	def audioStreams = []
	def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
	def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
	def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
	def oneStream = { listStream(it)[0] }
	def dString = { it.toDouble().toString() }
	def toInt = { it.toInteger() }

	any{audio.collect{ au ->
		def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
		def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
		def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
			{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }

		def chFilter =	( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )

		def combined = allOf{codec}{format_profile}.join(' ')

		audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
		'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
		'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
		'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
		return audioStreams
	}

	def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
	def allStreams = listStream(audioStreams)
	def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
	def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
	def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
	def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
	def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
	def custom = audioStreams.groupBy{ it.lang }.values()*.findAll{ it.lang == preferredLang || it.bitrate == audioStreams.bitrate.max() }.findAll { it }.collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.sort{ it.lang != preferredLang }.collect{ "${it.lang.replace('null', '')} ${it.codec} ${it.ch}" }.join(' - ')

	any{addToList}{custom}{[bestPreferredLang, bestBitRate].unique().findAll().join(' - ')}{defaultStream}{bestBitRate}{preferredStream}
	}{'NO_AUDIO'}
}
But i was testing a old post from u https://www.filebot.net/forums/viewtop ... 178#p56178 and here with this code:

Code: Select all

{
	def preferredLang = 'ES'
	def fallbackLang = any{languages*.ISO2*.upper().join('-')}{'YourDefaultLandHere'}
	def useChFilter = false
	def filter = { [it.lang, it.codec, it.ch, it.objects].findAll() }

	def codecList =
	[
	'MPEG Audio' : 'MP2',
	'MP3' : 'MP3',
	'PCM' : 'PCM',
	'FLAC' : 'FLAC',
	'AAC LC' : 'AAC',
	'AAC LC SBR' : 'AAC',
	'AAC LC SBR PS' : 'AAC',
	'AC 3' : 'AC3',
	'AC 3 Dep' : 'EAC3',
	'E AC 3' : 'EAC3',
	'E AC 3 JOC' : 'EAC3 Atmos',
	'AC 3 Dep JOC' : 'EAC3 Atmos',
	'DTS' : 'DTS',
	'DTS 96 24' : 'DTS 96-24',
	'DTS ES' : 'DTS-ES',
	'DTS ES XXCH' : 'DTS-ES',
	'DTS XBR' : 'DTS-HD HRA',
	'DTS ES XBR' : 'DTS-HD HRA',
	'DTS ES XXCH XBR' : 'DTS-HD HRA',
	'DTS XLL' : 'DTS-HD MA',
	'DTS ES XLL' : 'DTS-HD MA',
	'DTS ES XXCH XLL' : 'DTS-HD MA',
	'DTS XLL X' : 'DTS X',
	'MLP FBA' : 'TrueHD',
	'MLP FBA 16 ch' : 'TrueHD Atmos'
	]

	def audioStreams = []
	def audioClean = { it.replaceAll(/[\p{Pd}\p{Space}]/, ' ').replaceAll(/\p{Space}{2,}/, ' ').slash(' ') }
	def channelClean = { it.replaceAll(/Debug.+|Object\sBased\s?\/?|(\d+)?\sobjects\s\/\s|0.(?=\d.\d)|20/).replaceAll(/6.0/,'5.1').replaceAll(/8.0/,'7.1') }
	def listStream = { it.sort{ a, b -> b.bitrate <=> a.bitrate }.collect{ filter(it) }.unique()*.join(' ') }
	def oneStream = { listStream(it)[0] }
	def dString = { it.toDouble().toString() }
	def toInt = { it.toInteger() }

	any{audio.collect{ au ->
		def codec = audioClean(any{ au['CodecID/Hint'] }{ au['Format'] })
		def format_profile = any{ audioClean(au['Format_AdditionalFeatures'])}{}
		def String ch = any{ channelClean(au.ChannelPositionsString2).tokenize('\\/')*.toDouble().toString().sum() }
			{ channelClean(dString(au.ChannelsOriginal)) } { channelClean(dString(au.Channels)) }

		def chFilter =	( ( ( (ac == 'AAC'||ac == 'MP3') && ch != '2.0') || ( (ac == 'AC3'||ac == 'EAC3'||ac == 'DTS'||ac == 'TrueHD'||ac == 'MLPFBA') && ch != '5.1' ) ) ? ch : null )

		def combined = allOf{codec}{format_profile}.join(' ')
		audioStreams << ['index' : codecList.findIndexOf { it.key == combined }, 'default' : any {au['default'][0].toBoolean() }{ audio.size == 1 ? true : '' },
		'codec' : codecList.get(combined, 'Add to "' + combined + '" codecList'), 'combined' : combined, 'ch' : useChFilter ? chFilter : ch,
		'bitrate' : any{ toInt(au.BitRate) }{ toInt(au.BitRate_Maximum) }{ dString(au.FrameRate) }{null},
		'objects' : any{def objects = au['NumberOfDynamicObjects']; objects ? "[$objects Objs]" : ''}{null}, 'lang' : any{ au.'LanguageString2'.upper() }{null} ]
		return audioStreams
	}

	def addToList = audioStreams.codec.findAll{ it.contains('Add to') }.unique().sort()
	def allStreams = listStream(audioStreams)
	def preferredStream = oneStream(audioStreams.findAll{ it.index == audioStreams.index.max() })
	def bestBitRate = oneStream(audioStreams.findAll{ it.bitrate == audioStreams.bitrate.max() })
	def defaultStream = any{ oneStream(audioStreams.findAll{ it.default == true }) }{ oneStream(audioStreams) }
	def bestPreferredLang = any{ oneStream(audioStreams.findAll{ it.lang == preferredLang }) }{}
	def bestBitRateAllLang = listStream(audioStreams.groupBy{ it.lang }.values()*.sort{ a, b -> b.bitrate <=> a.bitrate }*.find { it }).join(' - ')
	def groupCodec = audioStreams.sort{ a, b -> b.bitrate <=> a.bitrate }.groupBy{ it.codec }.values().collect{ [lang: it.unique{it.lang}.lang.join('|'), codec: it.unique{it.codec}.codec.join(), ch: it.unique{it.ch}.ch.join()] }.collect{ "${it.lang.replace('null', fallbackLang)} ${it.codec} ${it.ch}" }.join(' - ')

	any{addToList}{groupCodec}{bestBitRateAllLang}{[bestPreferredLang, bestBitRate].findAll().join(' & ')}{defaultStream}{bestBitRate}{preferredStream}
	}{'NO_AUDIO'}
}
Image

I have managed to see this, what I want is to choose the best audio in ES And the following best audio language and in the event that ES and for example EN are the same audio, express it like this, for example ES|EN EAC3 5.1
Post Reply