Help on custom scheme and syntaxerror "\" (i.e. String-escape FileBot Format in JS)

Any questions? Need some help?
Post Reply
ping
Posts: 6
Joined: 17 Jul 2014, 11:51

Help on custom scheme and syntaxerror "\" (i.e. String-escape FileBot Format in JS)

Post by ping »

Hi folks,

I run into a syntaxerror with my renaming scheme.

Here is the output I get :

Code: Select all

stderr : SyntaxError: unexpected char: '\'
javax.script.ScriptException: SyntaxError: unexpected char: '\'
        at net.filebot.format.ExpressionFormat.compile(ExpressionFormat.java:85)
        at net.filebot.format.ExpressionFormat.<init>(ExpressionFormat.java:43)
        at net.filebot.format.ExpressionFileFormat.<init>(ExpressionFileFormat.java:13)
        at net.filebot.cli.ArgumentBean.getExpressionFileFormat(ArgumentBean.java:255)
        at net.filebot.cli.ArgumentProcessor.runCommand(ArgumentProcessor.java:124)
        at net.filebot.cli.ArgumentProcessor.run(ArgumentProcessor.java:33)
        at net.filebot.Main.main(Main.java:132)


stdout : Error (o_O)
Unfortunatly this message doesn't show me where the character is from.

Some context :
I use filebot v4.8.5 on comandline call.
I made a nodejs app that call filebot throug bash (linux).
I was able to use my custom scheme to rename some tvshows befor getting this error.
I can't manage to remember, if or what, has changed and led me to this issue..

One of my scheme (tvshows) :

Code: Select all

{'_FOLDER/'}
{norm={it.upperInitial().lowerTrail().replaceTrailingBrackets().replaceAll(/[\`´‘’?\"\"“”!?,<<>>]/,'').replaceAll(/[:|]/,'-').replaceAll(/[|:*\s]+/,'_').replaceAll(/\b[IiVvXx]+\b/,{it.upper()}).replaceAll(/\b[0-9](?i:th|nd|rd)\b/,{it.lower()}).ascii()};norm(n)}
/
{episode.special?'Special':'Season_'+s.pad(2)}
_
({episodelist.findAll{it.season==s}.airdate.year[0,-1].unique().join('-')})
/
{norm(n)}
-
{episode.special?'S00E'+special.pad(2):s00e00.replaceAll(/[|:*\s]+/,'')}
-
{norm(t).ascii().replaceAll(/[*\s]+/,'').replaceAll('\'','’')}
[{allOf{vf}{vc}{source}{hd} join '-'}]
{
	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]}
	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},'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('')
}
{'['+text.language.flatten().join('-')+']'}
(yes it's ugly, but it do what I want)

Example a sample of the result (using GUI) :
Treadstone\Season_01_(2019)\Treadstone-S01E04-The_Kentucky_Contract[720p-x264-WEBRip-HD][aac-2.0][fr]
It works fine with the GUI !

Find below the "comandline" version with extra escaping characters (json format) :

Code: Select all

"thetvdb": "\"{'_FOLDER/'}\n{norm={it.upperInitial().lowerTrail().replaceTrailingBrackets().replaceAll(/[\\`´‘’?\\\"\\\"“”!?,<<>>]/,'').replaceAll(/[:|]/,'-').replaceAll(/[|:*\\s]+/,'_').replaceAll(/\\b[IiVvXx]+\\b/,{it.upper()}).replaceAll(/\\b[0-9](?i:th|nd|rd)\\b/,{it.lower()}).ascii()};norm(n)}\n/\n{episode.special?'Special':'Season_'+s.pad(2)}\n_\n({episodelist.findAll{it.season==s}.airdate.year[0,-1].unique().join('-')})\n/\n{norm(n)}\n-\n{episode.special?'S00E'+special.pad(2):s00e00.replaceAll(/[|:*\\s]+/,'')}\n-\n{norm(t).ascii().replaceAll(/[*\\s]+/,'').replaceAll('\\'','’')}\n[{allOf{vf}{vc}{source}{hd} join '-'}]\n{\n\tdef 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']\n\tdef filter={[it.lang,it.codec,it.ch]}\n\tdef audioStreams=[]\n\tdef audioClean={it.replaceAll(/[\\p{Pd}\\p{Space}]/,' ').replaceAll(/\\p{Space}{2,}/,' ').slash(' ')}\n\tdef 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')}\n\tdef oneStream={'['+it.collect{filter(it)}*.minus(null).unique().flatten().join('-')+']'}\n\tdef dString={it.toDouble().toString()}\n\tdef toInt={it.toInteger()}\n\taudio.collect{au ->\n\t\tdef codec=audioClean(any{au['CodecID/Hint']}{au['Format']})\n\t\tdef format_profile=any{audioClean(au['Format_AdditionalFeatures'])}{}\n\t\tdef String ch=any{channelClean(au.ChannelPositionsString2).tokenize('\\\\/')*.toDouble().toString().sum()}{channelClean(dString(au.ChannelsOriginal))} {channelClean(dString(au.Channels))}\n\t\tdef chFilter=((((ac=='AAC'||ac=='MP3')&&ch!='2.0')||((ac=='AC3'||ac=='EAC3'||ac=='DTS'||ac=='TrueHD'||ac=='MLPFBA')&&ch!='5.1'))?ch:null)\n\t\tdef combined=allOf{codec}{format_profile}.join(' ')\n\t\taudioStreams<<['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},'lang':any{au.'LanguageString3'.upper().replaceAll('SPA','ESP',)}{null}]\n\t\treturn audioStreams\n\t}\n\tdef allStreams=audioStreams.collect{filter(it)}*.minus(null).unique()*.join(' ')\n\tdef preferredStream=oneStream(audioStreams.findAll{it.index==audioStreams.index.max()})\n\tdef bestBitRate=oneStream(audioStreams.findAll{it.bitrate==audioStreams.bitrate.max()})\n\tdef defaultStream=oneStream(audioStreams.findAll{it.default==true})\n\tallStreams.join(' ').space(' ')\n\tpreferredStream.space(' ')\n\tdefaultStream.space(' ')\n\tbestBitRate.space(' ')\n\t[bestBitRate,preferredStream].unique().join(' ')\n\t[defaultStream,bestBitRate].unique().join('')\n}\n\n{'['+text.language.flatten().join('-')+']'}\""
The <{'_FOLDER/'}> thing is juste a part of my script, don't mind it.
(sorry for the hard reading, it's juste how its writen in my json conf file)


After several try I can't figure out what is causing the syntaxerror.
For me, escaping seems correct (or I miss an obvious thing ^^)

It's frustated, I moved from filebot 4.7.9 to 4.8.5 because of the theTVDB new api issue (301 Moved Permanently).
I reworked my old schemes to be compatible with 4.8.5, and it was working succesfully for a couple of files.
And it works fine from the GUI (but I want to use it from comandline)


I hope you'll see what I'm missing about the "SyntaxError: unexpected char: '\'"

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

Re: Help on custom scheme and syntaxerror "\"

Post by kim »

SyntaxError: unexpected char: '\'
=
replace all \ with \\
http://groovy-lang.org/syntax.html#_esc ... characters

why use "\t" and "\n" ?
then on to next problem ;)

btw: you need to edit... to only what you want...

Code: Select all

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('')
now this is same as

Code: Select all

def bestBitRate=oneStream(audioStreams.findAll{it.bitrate==audioStreams.bitrate.max()})
def defaultStream=oneStream(audioStreams.findAll{it.default==true})
[defaultStream,bestBitRate].unique().join('')
User avatar
rednoah
The Source
Posts: 22991
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Help on custom scheme and syntaxerror "\"

Post by rednoah »

:idea: Use the @file syntax for reading command-line arguments from external text files.

:!: Passing complex code on the command-line, or String-escaped from JS, is generally not humanly possible. If you're using JS, you can use JS to read the value from a file as well, instead of writing it as a String Literal:

Code: Select all

var fs = require('fs');
var format = fs.readFileSync('/path/to/format.txt', 'UTF-8');
:idea: Please read the FAQ and How to Request Help.
Post Reply