1) launch a groovy script that
2) extracts rar files if necessary
3) ignore unfinished files (if more than one download is happening at the same time)
4) delete "sample" files so that they aren't processed
5) determine if the file is a movie or tv show
6) collect artwork and get subtitles from theMovieDB or theTVDB respectively
7) rename shows according to XBMC convention
8) create the appropriate directory if necessary
9) Send me a text message when finished to notify me of its completion and what was downloaded
Some of the things that I learned along the way:
- You should troubleshoot by looking at the log (tab at the bottom) from utorrent and cut and paste that into a cmd window. You can also troubleshoot groovy script with the "Groovy Console". I found the later less helpful because you often need the variables passed from utorrent to troubleshoot.
- Java for me (Windows 7 64bit) needed to be moved to the program files (x64) directory and permissions changed.
- sendemail would not work from the suggested directory (system32). I need to place it in the standard windows directory. It would work fine from the command line, but for some reason when called from the groovy script with the same command, it would fail until I moved the program.
I use a separate program "Belvedere" that keeps my downloads folder clean. After appropriate seeding time, it deletes the original downloaded torrent.
Huge thanks to Rednoah! I take no credit for any of the script. I felt like a child trying to build a rocket ship most of the time. He was very patient and helpful in constructing this hodgepodge of other people's work. I hope that some of this information can save others some frustration and time.
Code: Select all
// filebot -script "fn:utorrent-postprocess" --output "X:/media" --action copy --conflict override -non-strict -trust-script -Xxbmc=localhost "-Xut_dir=%D" "-Xut_file=%F" "-Xut_label=%L" "-Xut_state=%S" "-Xut_kind=%K"
def input = []
// print input parameters
_args.parameters.each{ k, v -> println "Parameter: $k = $v" }
if (ut_kind == "multi") {
input += new File(ut_dir).getFiles() // multi-file torrent
} else {
input += new File(ut_dir, ut_file) // single-file torrent
}
// extract archives if necessary
input += extract(file:input, output:".", conflict:"override")
// process only media files
input = input.findAll{ it.isVideo() || it.isSubtitle() }
// ignore chunk, part, par and hidden files
def incomplete(f) { f.name =~ /[.]incomplete|[.]chunk|[.]par$|[.]dat$/ || f.isHidden() }
[ut_dir].getFolders{ !it.hasFile{ incomplete(it) } && it.hasFile{ it.isVideo() } }.each{ dir ->
println "Deleting Sample Video Processing $dir"
def files = dir.listFiles{ it.isVideo() }
// if name contains "sample" and filesize is less than 50 MB
//def selection = args.getFiles{ it.name =~ "sample" && it.length() < 20 * 1024 * 1024}
def selection = dir.getFiles{ (it.name =~ "sample" || it.name =~ "Sample") && it.length() < 50 * 1024 * 1024}
selection.each{ println "delete $it" }
// delete all
selection*.delete()
}
// ignore clutter files
input = input.findAll{ !(it.name =~ /(?i:sample)/) }
// print input fileset
input.each{ println "Input: $it" }
// xbmc artwork/nfo utility
include("fn:lib/xbmc")
// group episodes/movies and rename according to XBMC standards
def groups = input.groupBy{
def tvs = detectSeriesName(it)
def mov = detectMovie(it, false)
println "$it.name [series: $tvs, movie: $mov]"
// DECIDE EPISODE VS MOVIE (IF NOT CLEAR)
if (tvs && mov) {
if (it.name =~ "(?i:$tvs - .+)" || parseEpisodeNumber(it.name) || parseDate(it.name)) {
println "Exclude Movie: $mov"
mov = null
} else if (detectMovie(it, true)) {
println "Exclude Series: $tvs"
tvs = null
}
}
return [tvs:tvs, mov:mov]
}
groups.each{ group, files ->
// fetch subtitles
def subs = getMissingSubtitles(file:files, output:"srt", encoding:"utf-8")
if (subs) files += subs
// EPISODE MODE
if (group.tvs && !group.mov) {
def dest = rename(file:files, format:'TV Shows/{n}/{episode.special ? "Special" : "Season "+s}/{n} - {episode.special ? "S00E"+special.pad(2) : s00e00} - {t}', db:'TheTVDB')
dest.mapByFolder().keySet().each{ dir ->
println "Fetching artwork for $dir from TheTVDB"
def query = group.tvs
def sxe = dest.findResult{ parseEpisodeNumber(it) }
def options = TheTVDB.search(query)
if (options.isEmpty()) {
println "TV Series not found: $query"
return
}
dest.findAll{ it.isVideo() }.each{
def msg = "${it.name} has been added to the library"
execute("c:/windows/sendEmail.exe", "-f", "[email protected]", "-t", "[email protected]", "-s", "smtp.gmail.com:587", "-o", "tls=yes", "-xu", "[email protected]", "-xp", "password", "-m", msg)
}
options = options.sortBySimilarity(query, { it.name })
fetchSeriesArtworkAndNfo(dir.dir, dir, options[0], sxe && sxe.season > 0 ? sxe.season : 1)
}
}
// MOVIE MODE
if (group.mov && !group.tvs) {
def dest = rename(file:files, format:'Movies/{n} ({y})/{n} ({y}){" CD$pi"}', db:'TheMovieDB')
dest.findAll{ it.isVideo() }.each{
def msg = "${it.name} has been added to the library"
execute("c:/windows/sendEmail.exe", "-f", "[email protected]", "-t", "[email protected]", "-s", "smtp.gmail.com:587", "-o", "tls=yes", "-xu", "[email protected]", "-xp", "password", "-m", msg)
}
dest.mapByFolder().keySet().each{ dir ->
println "Fetching artwork for $dir from TheMovieDB"
fetchMovieArtworkAndNfo(dir, group.mov)
}
}
}
// make XBMC scan for new content
xbmc.split(/[\s,|]+/).each{
println "Notify XBMC: $it"
invokeScanVideoLibrary(it)
}