[CODE] Snippets & Examples

Running FileBot from the console, Groovy scripting, shell scripts, etc
Post Reply
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

[CODE] Snippets & Examples

Post by rednoah »

Reading torrent files might be useful for some people. Since FileBot already includes the code for that I'll quickly paste a Groovy snippet here on how to do it.

Code: Select all

args.getFiles{ it.extension == 'torrent' }.each{
	def torrent = new net.filebot.torrent.Torrent(it)
	
	println "Torrent: $torrent.name"
	torrent.files.eachWithIndex{ entry, index ->
		println "$index: $entry.path [$entry.length]"
	}
}
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: [CODE] Reading Torrent Files

Post by rednoah »

Here's example code for mapping files to torrents:

Code: Select all

def torrents = args.getFiles{ it.extension == 'torrent' }.findResults{ new net.sourceforge.filebot.torrent.Torrent(it) }
def videos = args.getFiles{ it.isVideo() }

videos.each{ f ->
	def m = torrents.find{ t ->
		t.files.find{ e ->
			e.name == f.name && e.length == f.length() 
		}
	}
	if (m) {
		println "file [$f.name] belongs to torrent [$m.name]"
	}
}
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

[CODE] Force series for specific files

Post by rednoah »

Sometimes it might be useful to override series auto-detection by forcing a series title for a specific set of files. This is how you do it. Only process a certain set of files via file parameter and force the series title via the query parameter.

Code: Select all

rename(file: args.getFiles{ it =~ /(?i:colbert.report)/}, query: "The Colbert Report", db: "TheTVDB")
rename(file: args.getFiles{ it =~ /(?i:daily.show)/}, query: "The Daily Show with Jon Stewart", db: "TheTVDB")
...
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: [CODE] Read Internal Rename History

Post by rednoah »

Print rename log of this session:

Code: Select all

getRenameLog().each{ from, to -> println "$from => $to"}
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

[CODE] Custom Rename Action

Post by rednoah »

In scripting you can just pass in a closure to replace the standard action with your own arbitrary logic. Anything is possible.

e.g.

Code: Select all

rename(
	file: args.getFiles(),
	action: { from, to ->
		execute('echo', 'FROM', from, 'TO', to)
	}
)
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

[CODE] Scrape Webpages with JSoup

Post by rednoah »

Sometimes you might wanna grab data from websites, aka page scraping. Groovy with JSoup will greatly simplify any kind of scraping you wanna do. Here's an example of how to write a script that'll extract all links from a given page.

Code: Select all

@Grab('org.jsoup:jsoup')

def page = org.jsoup.Jsoup
   .connect('http://filebot.sf.net')
   .userAgent('Mozilla/5.0')
   .get()

page.select("A").each { println it }
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

[CODE] Control rtorrent via XML-RPC

Post by rednoah »

Here's a an example of how to use Groovy XML-RPC to hook into rtorrent and retrieve the list of completed downloads. If you got rutorrent running fine you can just use it's rpc proxy. Otherwise you might wanna look into the RTorrentXMLRPCGuide.

Code: Select all

@Grab('org.codehaus.groovy:groovy-xmlrpc')
import groovy.net.xmlrpc.*

def rpc = new XMLRPCServerProxy("http://localhost/rutorrent/plugins/rpc/rpc.php", true)
rpc.setBasicAuth("username", "password")

rpc.invokeMethod("d.multicall", ['complete', 'd.get_directory_base=', 'd.get_name=']).each{
    println it
}
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

[CODE] Process Audio Files

Post by rednoah »

With the format engine and mediainfo bindings at your command it's pretty straight-forward to index your music collection.

e.g. print artist, album and title for each audio file:

Code: Select all

args.getFiles{ it.isAudio() }.each{
	println getMediaInfo(file:it, format:'''{media.Performer} / {media.Album} / {media.TrackPosition.pad(2)} - {media.Title}''')
}
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: [CODE] Movie Parsing / Lookup

Post by rednoah »

You easily can make use of filebots parsing functions to make sense of files in your own scripts.

e.g.

Code: Select all

def f = 'X:/Cloud Atlas.mp4' as File

// fast file-name lookup
println matchMovie(f.name, false)

// full file-structure search/lookup
println detectMovie(f, false)

// fetch complete movie data
println TheMovieDB.getMovieInfo(detectMovie(f, false), Locale.ENGLISH)
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: [CODE] Examples and Snippets

Post by rednoah »

Here's a little script to make sure the <id/> tag in .nfo files is well formatted according to IMDb/XBMC standards. This script will replace occurrences of something like <id>123456</id> and change it to <id>tt0123456</id> so FileBot and similar tools can easily recognize the IMDbID pattern.

Code: Select all

args.getFiles{ f -> f.extension == 'nfo' }.each{ f ->
	f.text.replaceAll('<id>(\\d+)</id>', { m, id -> "<id>tt${id.pad(7)}</id>"}).saveAs(f)
}
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Re: [CODE] Examples and Snippets

Post by rednoah »

Here's an example of how to plug in your rename function and copy files to a remote server via SSH/SFTP without creating any temporary files. Because scp won't create folders for us we have to call mkdir on the server first.

Code: Select all

include('fn:lib/ant')

def copy_scp = { from, to ->
	def remoteHost = 'www.example.org'
	def remoteUser = 'username'
	def remotePassword = 'password' // instead of using a password you probably wanna use a keyfile though
	
	def localRoot = new File(_args.output).canonicalFile
	def remoteRoot = '/home/user/media'
	
	def remoteDir = "${remoteRoot}/${localRoot.relativize(to.dir)}".replace('\\', '/')
	def remoteFile = "${remoteRoot}/${localRoot.relativize(to)}".replace('\\', '/')
	
	sshexec(command: "mkdir -p '${remoteDir}'", host: remoteHost, username: remoteUser, password: remotePassword)
	scp(file: from, remoteFile: remoteFile, host: remoteHost, username: remoteUser, password: remotePassword)
}

rename(file:args.getFiles(), action: copy_scp)
:idea: Please read the FAQ and How to Request Help.
User avatar
rednoah
The Source
Posts: 22923
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Modify SxE numbers

Post by rednoah »

Rename Alias 1x01 to Alias 2x01:

Code: Select all

def offset = [season: +1, episode: 0]

def p = /(\d{1,2})(\D)(\d{2})/
def r = { m, s, x, e -> ((s as int) + offset.season) + x + ((e as int) + offset.episode).pad(2) }

rename(
	map: args.getFiles().findAll{ parseEpisodeNumber(it) != null }.collectEntries{ [it, it.name.replaceFirst(p, r)] }
)
:idea: Please read the FAQ and How to Request Help.
Post Reply