Automations with custom preset

Running FileBot from the console, Groovy scripting, shell scripts, etc
Post Reply
xeviff
Posts: 3
Joined: 03 Mar 2021, 19:55

Automations with custom preset

Post by xeviff »

Hello.
I have my own preset (very large) and I want to a process that automatically takes the files that I put in a specific folder and execute the preset, (moving and renaming those files in the folder preset says, because I set many diferent folders depending of some values...).

I don't know where to start. I've seen some tools like Node but it semms only work with amc.groovy as stardar...

Any help please?
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Automations with custom preset

Post by rednoah »

1.
You'll want to start by playing with the filebot command-line tool:
https://www.filebot.net/cli.html

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

:!: Depending on your needs, the amc script can be powerful and versatile solution, but can also be unnecessarily complicated if your use case is simple.


2.
Once you have learned how to use filebot on the command-line, then you move on to either calling filebot in regular intervals using some 3rd party scheduler (e.g. cron) or call filebot in response to file system changes via some 3rd party file monitoring tools (e.g. inotifywait). There are many ways to go about it, and the tools available to you will vary depending on the operating system platform (e.g. Automator for macOS).

:idea: Conceptually, (1) is completely separate and independent of (2) so it's best to tackle one problem at a time, and the put things together after you've figured out each aspect by itself.
:idea: Please read the FAQ and How to Request Help.
xeviff
Posts: 3
Joined: 03 Mar 2021, 19:55

Re: Automations with custom preset

Post by xeviff »

My preset was working on GUI, but in GUI is not working with this command:

Code: Select all

filebot -rename . --format z:\filebot\presets\4.9.4\HACK3-REPO_Pelis494.groovy
Where:
- Command was executed in a path that contains one film
- The groovy returns full path + movie file name (renamed, without file extension. This is how was working well on GUI - Windows Desktop Application)

The error says:

Code: Select all

 SyntaxError: expecting '}', found ''
After reading all documentation provided on the links, I can't figure out the proper command for this case.
Can you guide me with this ?
Cheers
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Automations with custom preset

Post by rednoah »

The format code (as opposed to Groovy code) you're passing in is syntactically incorrect.


:?: What have you tried so far? (if you have a problem, try something simple that can't not work first, and then take it from there)


:arrow: Use @/path/to/format.groovy in the GUI. Use --format /path/to/format.groovy on the CLI. Then things will work exactly the same.

Image


:!: Note that --format expects format code, e.g. --format "{plex}" where {plex} can be externalized to an UTF-8 encoded plain text file. In this case, {...} is the format code, and plex is the section that is interpreted as Groovy code, of which there may be many in a single format.
:idea: Please read the FAQ and How to Request Help.
xeviff
Posts: 3
Joined: 03 Mar 2021, 19:55

Re: Automations with custom preset

Post by xeviff »

My code is something like that: (I changed some code and put some ".......")

Code: Select all


//parámetros extra
def forceDocumental = false

/** RUTAS **/
[b]def rutaOK = "W:/MANGRANA - Pelis/Pelis/"
def ruta = rutaOK
def ruta_docu = "W:/MANGRANA - Pelis/Documentales/"
def ruta_anime = "W:/MANGRANA - Pelis/Pelis_anime/"
def ruta_animacion = "W:/MANGRANA - Pelis/Pelis_animacion/"
def ruta_infantil = "W:/MANGRANA - Pelis/Pelis_infantiles/"
def ruta_cat = "W:/MANGRANA - Pelis/Pelis_amb_cat/"
def ruta_cat_anime = "W:/MANGRANA - Pelis/Pelis_cat_anime/"
def ruta_esp = "W:/MANGRANA - Pelis/Pelis_esp/"
def ruta_semiesp = "W:/MANGRANA - Pelis/Pelis_semiesp/"
def ruta_esp_retro = "W:/MANGRANA - Pelis/Pelis_esp_retro/"
def ruta_esp_classic = "W:/MANGRANA - Pelis/Pelis_esp_classic/"
def ruta_retro = "W:/MANGRANA - Pelis/Pelis_retro/"
def ruta_estrenos = "W:/MANGRANA - Pelis/Pelis_estrenos/"
def ruta_classic = "W:/MANGRANA - Pelis/Pelis_classic/"

def rutaKO = "W:/MANGRANA - Subidas/error/Pelis/"[/b]
/**********/

def rutaKO = rutaTD+"₆₆₆ con errores (ignorar) ઈ(@̴̨̊̋̐̃̀̽̽ͅ❦@̴̨̊̋̐̃̀̽̽ͅ)ૐ/"
/**********/

/** Audio (definición) **/
def hayEAC3=false

[b]def getBestChannelFromList (audiosFormatFound) {[/b]
	def bestChanel
	def currentValue=0
	for (myAudio2 in audiosFormatFound) {
		if (myAudio2.Channels>currentValue) {
			currentValue = myAudio2.Channels
			bestChanel = myAudio2
		}
	}
	return bestChanel
}
.............

/***********/
/* otras funciones */[b]
def tieneGeneroAnimacion (generos) {
	for (genero in generos) {
        if (genero =~ /Anima..../) 
        return true
    }
    return false
}
def tieneGeneroFamilia (generos) {
	for (genero in generos) {
       if (genero =~ /Family/) 
       return true
    }
    return false
}
def tieneGeneroDocumental (generos) {
	for (genero in generos) {
       if (genero =~ /Docu/) 
       return true
    }
    return false
}
def tieneGeneroWestern (generos) {
	for (genero in generos) {
        if (genero =~ /Western/) 
        return true
    }
    return false
}[/b]

[b]try { [/b]//empieza el script

	/** Tipo de archivo incorrecto **/
	def esFicheroMetadatos = false
	def tipoMetadato
	def nombreWbloqueMediainfo
	if (ext=="jpg" || ext=="nfo" || ext=="png") {
		esFicheroMetadatos = true
			tipoMetadato = fn.find( //coge el contenido que encaja
				 /(?=\-[^-]+$)(.*)(?<!\}|\])$/ )
		if(tipoMetadato==null)tipoMetadato=''
	}
	else if (ext!="mkv" && ext!="avi" && ext!="mp4" && ext!="mpg" && ext!="m2ts") {
		throw new Exception("[formato_fichero_noestarndar]")
	}
	
	/** Codec Vídeo: en carpeta y en nombre fichero **/
	def codecVideo = (any{vc}{0} =~ /HEVC|265|ATEME/ ) ? 'HEVC' :
	    			 (any{vc}{0} =~ /264/) ? 'AVC' : vc
	/**************/
.............
	
	def carpetaCalidad = ((codecVideo=='HEVC' && calidad!='SD' && calidad!='720p')?'H.265 · ':'')+ calidad +'/'
	
	def calidadF = 	calidad=="4K-UHDRemux" ? "4K"
					: calidad=="4K-UHDRip" ? "4K"
					: calidad=="4K-MicroUHD" ? "micro4K"
					: calidad=="1080-BDRemux" ? "1080p"
					: calidad=="1080-HD" ? "1080p"
					: calidad=="1080-MicroHD" ? "micro1080p"
					: calidad=="SD" ? vf // Los SD vamos a poner su resolución
					: calidad //tal cual
	/***************************/

		/** Formato distribución **/
		formato_distribucion =
			fn=~/(?i)\bblu.?ray\b/ ? 'BDRemux' :
			fn=~/(?i)\bDVD.?RIP\b/ ? 'DVDRip' :
			fn=~/(?i)\bHDiTunes\b/ ? 'HDiTunes' :
			fn=~/(?i)\bTV.?RIP\b/ ? 'TVRip' :
			fn=~/(?i)\bWEB.?Screener\b/ ? 'WEB-SRC' :
			'no_encontrado'
......
		/** Formato distribución 2ª ronda**/
		//formato_distribucion = formato_distribucion=='no_encontrado'? '' : ' '+formato_distribucion
		if (formato_distribucion=='no_encontrado') {
			formato_distribucion = 
				calidad=="4K-UHDRemux" ? "UHDRemux" :
				calidad=="4K-UHDRip" ? "UHDRip" :
				calidad=="4K-MicroUHD" ? "UHDRip" :
				calidad=="1080-BDRemux" ? "BDRemux" :
				calidad=="1080-HD" ? "DBRip" :
				calidad=="1080-MicroHD" ? "BDRip" :
				'' //no_encontrado -> ''
		} 
		if (formato_distribucion!='') formato_distribucion=' '+formato_distribucion
		/**********************************/	

.....
		/* RESULTADO MEDIAINFO */
		def bloqueCalidadVideo = calidadF+formato_distribucion+hdr_info
		def bloqueProfundidad = myBitrate+myFps
		if (bloqueProfundidad!='' && profundidadColor!='') bloqueProfundidad=' '+bloqueProfundidad

		nombreWbloqueMediainfo = nombrePelicula_formatoPlex +' ['+codecVideo+' '+bloqueCalidadVideo+']['+profundidadColor+bloqueProfundidad+']'+' ['+bloqueAudio+']'
							//+' {imdb-'+imdbid+'}'
	//}

	/**************************************/
	/****  Carpeta / tipo contenido *******/
	def generes
	def errorNoGenero=false
	try {generes=genres} catch (err) {errorNoGenero=true}
	//return errorNoGenero
	def esDocu = forceDocumental || tieneGeneroDocumental(generes)
	def esAnimacion = tieneGeneroAnimacion(generes)
	def esAnime = anime || (tieneGeneroAnimacion(generes) && info.ProductionCountries.contains("JP"))	

	def esWestern = tieneGeneroWestern(generes)

	//util anys
	def strAny
	def contemporanea = false
	if (y>=1920 && y<1930) strAny = '/20s/'
	else if (y>=1930 && y<1940) strAny = '/30s/'
	else if (y>=1940 && y<1950) strAny = '/40s/'
	else if (y>=1950 && y<1960) strAny = '/50s/'
	else if (y>=1960 && y<1970) strAny = '/60s/'
	else if (y>=1970 && y<1980) strAny = '/70s/'
	else if (y>=1980 && y<1990) strAny = '/80s/'

		//tria
	def clasificada = true
	if (tenimCat) ruta = ruta_cat
	else if (esDocu) ruta = ruta_docu
	else if (esWestern) {
		ruta = ruta_western + strAny
		carpetaCalidad=''
	}
	else if (infantil) ruta = ruta_infantil
	else if (espanyola) ruta = ruta_esp + strAny
	else if (esAnime) ruta = ruta_anime
	else if (esAnimacion) ruta = ruta_animacion
	/********************************************/
	/**************************************/
	
	if (errorNoGenero && !clasificada)
		throw new Exception("[genero_no_especificado]")


	def nomPrincipal = esFicheroMetadatos ? nombreWbloqueMediainfo+tipoMetadato : nombreWbloqueMediainfo
	def resultado = ruta + carpetaCalidad + //directorios
						//nombre fichero
							//inicial + 
						'/' + nomPrincipal 
						//+ tmdb

	/********************************************/
	[b]return resultado[/b]

[b]} catch (err) {[/b]
	/*
	String str= err.getStackTrace().toString()
	def pattern = ( str =~ /groovy.(\d+)./   )
	return " Error at line number = " + pattern[0][1]
	*/

	def rutaMotivoErr
	def msgErr = err.getMessage()
	if (msgErr=="[formato_fichero_noestarndar]" || msgErr=="[video_roto]")
		rutaMotivoErr="/fichero/"
	else if (msgErr=="[genero_no_especificado]" || msgErr=="[certificado_edad_no_especificado]") {
		rutaMotivoErr="/themoviedb/"
	} else if (msgErr.startsWith("[idioma_audio")) {
		rutaMotivoErr="/audio/"
	} else {
		def errSplitted = msgErr.split("\\-")
		return msgErr
		if (errSplitted==null) {
			rutaMotivoErr="/error_desconocido/"
		} else  {
			def errType = errSplitted[0]
			if (errType=="[formato_audio_no_encontrado")
				rutaMotivoErr="/audio/"
			else if (errType.startsWith("[idioma_audio"))
				rutaMotivoErr="/idioma/"
		}
	}
	
	def resultado = rutaKO + rutaMotivoErr + msgErr + '/' + fn
	
	[b]return resultado[/b]
[b]}[/b]
As you see I have functions, error managment and a return of the new path + new name. None of this is applicable to a {....}.
Right now I can't see any way to use my format in the CLI...
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: Automations with custom preset

Post by rednoah »

:!: This is definitely not the FileBot Format code that you have typed into the Format Expression text field. You posted Groovy code, which is not to be confused with FileBot Format code which happens to use Groovy as a sub-language for {...} delimited sections.


This is FileBot Format code:

Code: Select all

/path/to/Movies/
{
	def x = "Hello"
	return x
}
/
{
	plex
}
:arrow: This is the thing that you type into the Format Expression text field in the GUI, or pass as --format option value.


This is Groovy code:

Code: Select all

def x = "Hello"
return x

Code: Select all

plex
:arrow: The sections delimited by {...} in your format code are Groovy code. Groovy code is not FileBot Format code. FileBot Format code is a template language that uses Groovy code for dynamically evaluated sections.



:idea: If you want to use the same format file (as opposed to files that you dynamically evaluate from within your own custom Groovy code) in both GUI and CLI, then this is the easiest way. Since you're using Presets, that means you'll want to create one format file and use that, instead of typing format code into the text field.
rednoah wrote: 27 Aug 2021, 13:55 Use @/path/to/format.groovy in the GUI. Use --format /path/to/format.groovy on the CLI. Then things will work exactly the same.

Image
:idea: Please read the FAQ and How to Request Help.
Post Reply