Page 1 of 1

[CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 03 Jun 2015, 11:20
by caphm
Hey guys,

I have created a script to be used with the Event Scripter extension of JDownloader 2. There are many requests around the web for how to automatically call Filebot when a download is finished in JD2. However I have never come across a satisfying solution, so I created one myself.

It relies on JD2 to extract archives (beaucse of the built in password "cracker") and then runs the AMC script on the extracted files. If it detects nested archives, it will skip processing until the actually relevant files are extracted. After successful renaming, the cleaner script will be called on the base directory of the package, to get rid of empty folders higher up in the hierarchy. It kind of relies on you downloading your stuff into separate folders for each package, but it should work either way.

There are a few options at the top of the script you need to customize and then you should be good to go. Just set up a script to be triggered on the "Archive Extraction Finished" event in JD2 and paste the code:

Code: Select all

var command = "filebot"; // Change this if filebot isn't on your path
var logfile = "C:/log/jdownloader-eventscripter.log"; // File this script logs to. Use forward slashes as path separators!
var filebotLogfile = "C:/log/filebot.log"; // File that filebot will log to. Use forward slashes as path separators!
var downloadBase = "D:\\Downloads"; // Base folder under which your download packages reside. Use escaped backslashes as path separators!
var archiveExtensions = /(\.(zip|rar|7z|par\d+|part\d+|r\d+|t\d+|\d{3}))$/; // Regex to test for nested archives in extracted files

// Parameters for the scripts to run
var params = {
    "rename" : {
        "options" : {
            "-script": "fn:amc",
            "--log-file": filebotLogfile,
            "--action": "move",
            "--conflict": "auto"
        },
        "defs" : {
            "plex": "ZEUS",
            "unsorted": "y",
            "skipExtract": "y",
            "clean": "y",
            "minFileSize": "104857600",
            "excludeList": "C:/Util/amc-input.txt",
            "seriesFormat": "D:/Serien/{n}/{'Season '+s}/{n} - {s00e00} - {t}",
            "movieFormat": "D:/Filme/{n} ({y}) [{vf}]/{n} ({y}) [{vf}]"
        },
        "switches" : [
            "-non-strict"
        ]
    },
    "cleaner" : {
        "options" : {
            "-script": "fn:cleaner",
            "--log-file": filebotLogfile
        },
        "defs" : {
            "root" : "y"
        },
        "switches" : []
    }
}

var logBuf = "";

function log(message) {
    logBuf += new Date().toISOString().slice(0, 19) + " - " + message + "\r\n";
}

function logArray(message, arr) {
    log("\t" + message);

    if (arr == null) {
        log("\t\tnone");
        return;
    }

    for (var i = 0; i < arr.length; i++) {
        log("\t\t" + arr[i]);
    }
}

function logSpacer() {
    log("++++++++++++++++++++++++++++++");
}

function flushLog() {
    // Comment out the next two lines to prevent log from being written to file
    writeFile(logfile, logBuf, true);
    logBuf = "";
}

function quoteIfNecessary(value) {
    return (value != null && value.indexOf("\"") < 0) ? '"' + value + '"' : value;
}

function quoteArrayElements(input) {
    var result = [];

    for (var i = 0; i < input.length; i++) {
        result[result.length] = quoteIfNecessary(input[i]);
    }

    return result;
}

function reduce(map, joinChar) {
    var keyValuePairs = [];

    for (var key in map) {
        keyValuePairs[keyValuePairs.length] = key + joinChar + map[key];
    }

    return keyValuePairs;
}

function mapToArray(map) {
    var array = [];

    for (var key in map) {
        array[array.length] = key;
        array[array.length] = map[key];
    }

    return array;
}

function createArgumentArray(parameters, inputs) {
    var options = mapToArray(parameters["options"]);
    var switches = parameters["switches"];
    var defs = reduce(parameters["defs"], "=");

    return [command].concat(options).concat(switches).concat(inputs).concat(["--def"]).concat(defs);
}

function isArchiveFile(filename) {
    return archiveExtensions.test(filename);
}

function containsNestedArchive(extractedFiles) {
    for (var i = 0; i < extractedFiles.length; i++) {
        if (isArchiveFile(extractedFiles[i])) {
            return true;
        }
    }

    return false;
}

function getPackageRoot(folder) {
    return folder.substring(0, folder.indexOf("\\", downloadBase.length + 1));
}

var archiveFolder = archive.getFolder();
var archiveName = archive.getName();
var archiveType = archive.getArchiveType();
var extractedFiles = archive.getExtractedFiles();
var archiveUID = archiveFolder + "\\" + archiveName;
var packageRoot = getPackageRoot(archiveFolder);

logSpacer();
log("FINISHED EXTRACTION - " + archiveUID);
log("\tType: " + archiveType);
log("\tPackage root: " + packageRoot);
logArray("Extracted files:", extractedFiles);

if (extractedFiles == null || extractedFiles.length == 0) {
    log("SKIPPING - No files extracted.");
} else if (containsNestedArchive(extractedFiles)) {
    log("SKIPPING - Nested archive detected.");
} else {
    var renameInputs = quoteArrayElements(extractedFiles);
    var renameArgs = createArgumentArray(params["rename"], renameInputs);
    log("RUNNING SCRIPT - " + archiveUID);

    callAsync(
        function(exitCode, stdOut, errOut) {
            if (exitCode == 0) {
                log("SUCCESS - " + archiveUID);

                var cleanerArgs = createArgumentArray(params["cleaner"], packageRoot);

                log("CLEANING - " + packageRoot);

                callAsync(
                    function(exitCode, stdOut, errOut) {
                        if(exitCode == 0) {
                            log("ALL CLEAN - " + packageRoot);
                        } else {
                            log("STILL DIRTY - " + packageRoot);
                        }

                        flushLog();
                    },
                    cleanerArgs
                );
            } else {
                log("ERROR - " + archiveUID + " - Code " + exitCode);
            }

            flushLog();
        },
        renameArgs
    );
}

logSpacer();
flushLog();
You can customize the way how Filebot is called by changing the values in params. The produced logfiles can become chunky rather quickly, so be sure to clean them out regularly to prevent wasting disk space. Or go ahead and comment out the part where the logfile is written (I have indicated the relevant lines in the code) to disable logging entirely. For debugging purposes I would not recommend that however.

I hope this script helps some of you people, it certainly worked like a charm for me :) Feel free to distribute and modify upon it and report any bugs you find in this thread.

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 13 Aug 2015, 01:39
by nytram
Hi

Nice work :-)

Thanks

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 13 Aug 2015, 10:49
by rednoah
Looks good. Thanks for the contribution! Might be a good idea to put in on GitHub? :)

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 29 Aug 2015, 18:00
by traxxus
Excellent!

But i Need some help: The subtitle files which are coming with the movie, get deleted instead of moved into the movie-folder...

My script:

Code: Select all

var command = "C://Program Files//FileBot//filebot.exe"; // Change this if filebot isn't on your path
var logfile = "C:/jdownloader2-eventscripter.log"; // File this script logs to. Use forward slashes as path separators!
var filebotLogfile = "C:/filebot.log"; // File that filebot will log to. Use forward slashes as path separators!
var downloadBase = "T:\\JDownloader\\entpackt"; // Base folder under which your download packages reside. Use escaped backslashes as path separators!
var archiveExtensions = /(\.(zip|rar|7z|par\d+|part\d+|r\d+|t\d+|\d{3}))$/; // Regex to test for nested archives in extracted files

// Parameters for the scripts to run
var params = {
    "rename": {
        "options": {
            "-script": "fn:amc",
            "--log-file": filebotLogfile,
            "--action": "move",
            "--conflict": "auto",
            "--lang": "de"

        },
        "defs": {
            "unsorted": "y",
            "skipExtract": "y",
            "clean": "y",
            "minFileSize": "104857600",
            "excludeList": "C:/amc-input.txt",
            "seriesFormat": "//NAS/Serien/{n}/{episode.special ? 'Special' : 'Season '+s.pad(2)}/{n}.{episode.special ? 'S00E'+special.pad(2) : s00e00}.{t.replaceAll(/[`´‘’ʻ]/, /'/).replaceAll(/[!?.]+$/).replacePart(', Part $1')}{'.'+lang}",
            "movieFormat": "//NAS/Filme/{n} ({y})/{n} ({y}){' CD'+pi}{'.'+lang}"
        },
        "switches": [
            "-non-strict"
        ]
    },
    "cleaner": {
        "options": {
            "-script": "fn:cleaner",
            "--log-file": filebotLogfile
        },
        "defs": {
            "root": "y"
        },
        "switches": []
    }
}

var logBuf = "";

function log(message) {
    logBuf += new Date().toISOString().slice(0, 19) + " - " + message + "\r\n";
}

function logArray(message, arr) {
    log("\t" + message);

    if (arr == null) {
        log("\t\tnone");
        return;
    }

    for (var i = 0; i < arr.length; i++) {
        log("\t\t" + arr[i]);
    }
}

function logSpacer() {
    log("++++++++++++++++++++++++++++++");
}

function flushLog() {
    // Comment out the next two lines to prevent log from being written to file
    writeFile(logfile, logBuf, true);
    logBuf = "";
}

function quoteIfNecessary(value) {
    return (value != null && value.indexOf("\"") < 0) ? '"' + value + '"' : value;
}

function quoteArrayElements(input) {
    var result = [];

    for (var i = 0; i < input.length; i++) {
        result[result.length] = quoteIfNecessary(input[i]);
    }

    return result;
}

function reduce(map, joinChar) {
    var keyValuePairs = [];

    for (var key in map) {
        keyValuePairs[keyValuePairs.length] = key + joinChar + map[key];
    }

    return keyValuePairs;
}

function mapToArray(map) {
    var array = [];

    for (var key in map) {
        array[array.length] = key;
        array[array.length] = map[key];
    }

    return array;
}

function createArgumentArray(parameters, inputs) {
    var options = mapToArray(parameters["options"]);
    var switches = parameters["switches"];
    var defs = reduce(parameters["defs"], "=");

    return [command].concat(options).concat(switches).concat(inputs).concat(["--def"]).concat(defs);
}

function isArchiveFile(filename) {
    return archiveExtensions.test(filename);
}

function containsNestedArchive(extractedFiles) {
    for (var i = 0; i < extractedFiles.length; i++) {
        if (isArchiveFile(extractedFiles[i])) {
            return true;
        }
    }

    return false;
}

function getPackageRoot(folder) {
    return folder.substring(0, folder.indexOf("\\", downloadBase.length + 1));
}

var archiveFolder = archive.getFolder();
var archiveName = archive.getName();
var archiveType = archive.getArchiveType();
var extractedFiles = archive.getExtractedFiles();
var archiveUID = archiveFolder + "\\" + archiveName;
var packageRoot = getPackageRoot(archiveFolder);

logSpacer();
log("FINISHED EXTRACTION - " + archiveUID);
log("\tType: " + archiveType);
log("\tPackage root: " + packageRoot);
logArray("Extracted files:", extractedFiles);

if (extractedFiles == null || extractedFiles.length == 0) {
    log("SKIPPING - No files extracted.");
} else if (containsNestedArchive(extractedFiles)) {
    log("SKIPPING - Nested archive detected.");
} else {
    var renameInputs = quoteArrayElements(extractedFiles);
    var renameArgs = createArgumentArray(params["rename"], renameInputs);
    log("RUNNING SCRIPT - " + archiveUID);

    callAsync(
        function(exitCode, stdOut, errOut) {
            if (exitCode == 0) {
                log("SUCCESS - " + archiveUID);

                var cleanerArgs = createArgumentArray(params["cleaner"], packageRoot);

                log("CLEANING - " + packageRoot);

                callAsync(
                    function(exitCode, stdOut, errOut) {
                        if (exitCode == 0) {
                            log("ALL CLEAN - " + packageRoot);
                        } else {
                            log("STILL DIRTY - " + packageRoot);
                        }

                        flushLog();
                    },
                    cleanerArgs
                );
            } else {
                log("ERROR - " + archiveUID + " - Code " + exitCode);
            }

            flushLog();
        },
        renameArgs
    );
}

logSpacer();
flushLog();

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 05 Sep 2015, 13:39
by neutron
Got another problem. Trying to use this on a synology nas (using linux style file paths) and the whole downloadBase folder stuff does not work. Doesn't get the packageroot correct, adding weird paths in front of download base path and so on...

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 19 Sep 2015, 16:07
by CENGOiSM
neutron wrote:Got another problem. Trying to use this on a synology nas (using linux style file paths) and the whole downloadBase folder stuff does not work. Doesn't get the packageroot correct, adding weird paths in front of download base path and so on...
I had the same problems with Jdownloader and Filebot, not on a synology but on the zyxel nas.
My solution is this:
EventScripter in JD:

Code: Select all

[{"eventTrigger":"ON_ARCHIVE_EXTRACTED",
"enabled":true,
"name":"FileBot",
"script":"var amcFile = \"/ffp/filebot/jdtofilebot.sh\"; \n var path = archive.getFolder(); callAsync(function() {}, amcFile, path);",
"eventTriggerSettings":{}}]
So on the "archive extracted" event, the sh file "jdtofilebot.sh" is called with the parameter "path", which represents the absolute path to the "packageRoot" folder you're referring to.

jdtofilebot.sh is custom written by me, and looks like this:

Code: Select all

#!/ffp/bin/sh
##FileBot needs these variables
LOG="/ffp/filebot/logs/amc.log"
EXC="/ffp/filebot/amc.txt"
SERIEN="/i-data/md0/TV-Serien/{n}/Staffel {s}/{n} S{s}E{e}"
FILME="/i-data/md0/Filme/{n} ({y})/{n} ({fn.contains('1080') ? '1080p ':''}{fn.contains('720') ? '720p ':''}{fn.contains('3D') || fn.contains('3-D') ? '3D ':''}HD)"
ANIME="/i-data/md0/Anime/{n}/{n} E{absolute}"

##Run FileBot
/ffp/filebot/filebot.sh -script fn:amc --lang de --log-file $LOG --action move "$1" --def "seriesFormat=$SERIEN" "movieFormat=$FILME" "animeFormat=$ANIME" -non-strict --def clean=y --def excludeList=$EXC --def xbmc=10.0.1.5

## Clean empty folders, samples etc after processing
/ffp/filebot/filebot.sh -script fn:cleaner "$1" --def root=y
'--action move "$1"' this $1 will be passed by the eventscripter in jd (the packageroot folder). So jdtofilebot.sh calls then filebot.sh which is shipped with the filebot installation with some custom parameters (eg. formatting, moving, update kodi library, ...). I really dont know if this helps you, but feel free to use it and set it to your personal needs. :D

Be sure to set the right (absolute) paths to the scripts, movies/shows folder, logs, exclude list - and the needed rights (755) and also to run it with the same users, so there is no problems with the privileges, rights etc.

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 31 Oct 2015, 19:30
by zocidj
Hy can you help me to make script work for me, step by step. Thanks

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 26 Nov 2015, 11:05
by Crack00r
May anyone can help me?
I have right now this in Jdownloader 2
but I just get a error . . .
net.sourceforge.htmlunit.corejs.javascript.EcmaError: TypeError: Cannot call method "substring" of null (#129)

Code: Select all

var command = "C://Program Files//FileBot//filebot.exe"; // Change this if filebot isn't on your path
var logfile = "C:/jdownloader-eventscripter.log"; // File this script logs to. Use forward slashes as path separators!
var filebotLogfile = "C:/filebot.log"; // File that filebot will log to. Use forward slashes as path separators!
var downloadBase = "D:\Downloads"; // Base folder under which your download packages reside. Use escaped backslashes as path separators!
var archiveExtensions = /(\.(zip|rar|7z|par\d+|part\d+|r\d+|t\d+|\d{3}))$/; // Regex to test for nested archives in extracted files

// Parameters for the scripts to run
var params = {
    "rename": {
        "options": {
            "-script": "fn:amc",
            "--log-file": filebotLogfile,
            "--action": "move",
            "--conflict": "auto"
        },
        "defs": {
            "plex": "crack00r",
            "unsorted": "y",
            "skipExtract": "y",
            "clean": "y",
            "minFileSize": "104857600",
            "excludeList": "C:\amc-input.txt",
            "seriesFormat": "D:\Filme\Filme\Serien\{n}/{'Season '+s}/{n} - {s00e00} - {t}",
            "movieFormat": "D:\Filme\Filme\Filme\{n} ({y}) [{vf}]/{n} ({y}) [{vf}]"
        },
        "switches": [
            "-non-strict"
        ]
    },
    "cleaner": {
        "options": {
            "-script": "fn:cleaner",
            "--log-file": filebotLogfile
        },
        "defs": {
            "root": "y"
        },
        "switches": []
    }
}

var logBuf = "";

function log(message) {
    logBuf += new Date().toISOString().slice(0, 19) + " - " + message + "\r\n";
}

function logArray(message, arr) {
    log("\t" + message);

    if (arr == null) {
        log("\t\tnone");
        return;
    }

    for (var i = 0; i < arr.length; i++) {
        log("\t\t" + arr[i]);
    }
}

function logSpacer() {
    log("++++++++++++++++++++++++++++++");
}

function flushLog() {
    // Comment out the next two lines to prevent log from being written to file
    writeFile(logfile, logBuf, true);
    logBuf = "";
}

function quoteIfNecessary(value) {
    return (value != null && value.indexOf("\"") < 0) ? '"' + value + '"' : value;
}

function quoteArrayElements(input) {
    var result = [];

    for (var i = 0; i < input.length; i++) {
        result[result.length] = quoteIfNecessary(input[i]);
    }

    return result;
}

function reduce(map, joinChar) {
    var keyValuePairs = [];

    for (var key in map) {
        keyValuePairs[keyValuePairs.length] = key + joinChar + map[key];
    }

    return keyValuePairs;
}

function mapToArray(map) {
    var array = [];

    for (var key in map) {
        array[array.length] = key;
        array[array.length] = map[key];
    }

    return array;
}

function createArgumentArray(parameters, inputs) {
    var options = mapToArray(parameters["options"]);
    var switches = parameters["switches"];
    var defs = reduce(parameters["defs"], "=");

    return [command].concat(options).concat(switches).concat(inputs).concat(["--def"]).concat(defs);
}

function isArchiveFile(filename) {
    return archiveExtensions.test(filename);
}

function containsNestedArchive(extractedFiles) {
    for (var i = 0; i < extractedFiles.length; i++) {
        if (isArchiveFile(extractedFiles[i])) {
            return true;
        }
    }

    return false;
}

function getPackageRoot(folder) {
    return folder.substring(0, folder.indexOf("\\", downloadBase.length + 1));
}

var archiveFolder = archive.getFolder();
var archiveName = archive.getName();
var archiveType = archive.getArchiveType();
var extractedFiles = archive.getExtractedFiles();
var archiveUID = archiveFolder + "\\" + archiveName;
var packageRoot = getPackageRoot(archiveFolder);

logSpacer();
log("FINISHED EXTRACTION - " + archiveUID);
log("\tType: " + archiveType);
log("\tPackage root: " + packageRoot);
logArray("Extracted files:", extractedFiles);

if (extractedFiles == null || extractedFiles.length == 0) {
    log("SKIPPING - No files extracted.");
} else if (containsNestedArchive(extractedFiles)) {
    log("SKIPPING - Nested archive detected.");
} else {
    var renameInputs = quoteArrayElements(extractedFiles);
    var renameArgs = createArgumentArray(params["rename"], renameInputs);
    log("RUNNING SCRIPT - " + archiveUID);

    callAsync(
        function(exitCode, stdOut, errOut) {
            if (exitCode == 0) {
                log("SUCCESS - " + archiveUID);

                var cleanerArgs = createArgumentArray(params["cleaner"], packageRoot);

                log("CLEANING - " + packageRoot);

                callAsync(
                    function(exitCode, stdOut, errOut) {
                        if (exitCode == 0) {
                            log("ALL CLEAN - " + packageRoot);
                        } else {
                            log("STILL DIRTY - " + packageRoot);
                        }

                        flushLog();
                    },
                    cleanerArgs
                );
            } else {
                log("ERROR - " + archiveUID + " - Code " + exitCode);
            }

            flushLog();
        },
        renameArgs
    );
}

logSpacer();
flushLog();

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 16 Dec 2015, 20:06
by mrtec
I am having the same issue as the previous member.
can anybody help?
( also what to do to change the code to work only when package has finished? )

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 26 Jan 2016, 10:55
by m4hu
has anyone tried to set this up on os x ?

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 30 Jan 2016, 23:16
by ronniehd
Crack00r wrote:May anyone can help me?
I have right now this in Jdownloader 2
but I just get a error . . .
net.sourceforge.htmlunit.corejs.javascript.EcmaError: TypeError: Cannot call method "substring" of null (#129)

Code: Select all

var command = "C://Program Files//FileBot//filebot.exe"; // Change this if filebot isn't on your path
var logfile = "C:/jdownloader-eventscripter.log"; // File this script logs to. Use forward slashes as path separators!
var filebotLogfile = "C:/filebot.log"; // File that filebot will log to. Use forward slashes as path separators!
var downloadBase = "D:\Downloads"; // Base folder under which your download packages reside. Use escaped backslashes as path separators!
var archiveExtensions = /(\.(zip|rar|7z|par\d+|part\d+|r\d+|t\d+|\d{3}))$/; // Regex to test for nested archives in extracted files

// Parameters for the scripts to run
var params = {
    "rename": {
        "options": {
            "-script": "fn:amc",
            "--log-file": filebotLogfile,
            "--action": "move",
            "--conflict": "auto"
        },
        "defs": {
            "plex": "crack00r",
            "unsorted": "y",
            "skipExtract": "y",
            "clean": "y",
            "minFileSize": "104857600",
            "excludeList": "C:\amc-input.txt",
            "seriesFormat": "D:\Filme\Filme\Serien\{n}/{'Season '+s}/{n} - {s00e00} - {t}",
            "movieFormat": "D:\Filme\Filme\Filme\{n} ({y}) [{vf}]/{n} ({y}) [{vf}]"
        },
        "switches": [
            "-non-strict"
        ]
    },
    "cleaner": {
        "options": {
            "-script": "fn:cleaner",
            "--log-file": filebotLogfile
        },
        "defs": {
            "root": "y"
        },
        "switches": []
    }
}

var logBuf = "";

function log(message) {
    logBuf += new Date().toISOString().slice(0, 19) + " - " + message + "\r\n";
}

function logArray(message, arr) {
    log("\t" + message);

    if (arr == null) {
        log("\t\tnone");
        return;
    }

    for (var i = 0; i < arr.length; i++) {
        log("\t\t" + arr[i]);
    }
}

function logSpacer() {
    log("++++++++++++++++++++++++++++++");
}

function flushLog() {
    // Comment out the next two lines to prevent log from being written to file
    writeFile(logfile, logBuf, true);
    logBuf = "";
}

function quoteIfNecessary(value) {
    return (value != null && value.indexOf("\"") < 0) ? '"' + value + '"' : value;
}

function quoteArrayElements(input) {
    var result = [];

    for (var i = 0; i < input.length; i++) {
        result[result.length] = quoteIfNecessary(input[i]);
    }

    return result;
}

function reduce(map, joinChar) {
    var keyValuePairs = [];

    for (var key in map) {
        keyValuePairs[keyValuePairs.length] = key + joinChar + map[key];
    }

    return keyValuePairs;
}

function mapToArray(map) {
    var array = [];

    for (var key in map) {
        array[array.length] = key;
        array[array.length] = map[key];
    }

    return array;
}

function createArgumentArray(parameters, inputs) {
    var options = mapToArray(parameters["options"]);
    var switches = parameters["switches"];
    var defs = reduce(parameters["defs"], "=");

    return [command].concat(options).concat(switches).concat(inputs).concat(["--def"]).concat(defs);
}

function isArchiveFile(filename) {
    return archiveExtensions.test(filename);
}

function containsNestedArchive(extractedFiles) {
    for (var i = 0; i < extractedFiles.length; i++) {
        if (isArchiveFile(extractedFiles[i])) {
            return true;
        }
    }

    return false;
}

function getPackageRoot(folder) {
    return folder.substring(0, folder.indexOf("\\", downloadBase.length + 1));
}

var archiveFolder = archive.getFolder();
var archiveName = archive.getName();
var archiveType = archive.getArchiveType();
var extractedFiles = archive.getExtractedFiles();
var archiveUID = archiveFolder + "\\" + archiveName;
var packageRoot = getPackageRoot(archiveFolder);

logSpacer();
log("FINISHED EXTRACTION - " + archiveUID);
log("\tType: " + archiveType);
log("\tPackage root: " + packageRoot);
logArray("Extracted files:", extractedFiles);

if (extractedFiles == null || extractedFiles.length == 0) {
    log("SKIPPING - No files extracted.");
} else if (containsNestedArchive(extractedFiles)) {
    log("SKIPPING - Nested archive detected.");
} else {
    var renameInputs = quoteArrayElements(extractedFiles);
    var renameArgs = createArgumentArray(params["rename"], renameInputs);
    log("RUNNING SCRIPT - " + archiveUID);

    callAsync(
        function(exitCode, stdOut, errOut) {
            if (exitCode == 0) {
                log("SUCCESS - " + archiveUID);

                var cleanerArgs = createArgumentArray(params["cleaner"], packageRoot);

                log("CLEANING - " + packageRoot);

                callAsync(
                    function(exitCode, stdOut, errOut) {
                        if (exitCode == 0) {
                            log("ALL CLEAN - " + packageRoot);
                        } else {
                            log("STILL DIRTY - " + packageRoot);
                        }

                        flushLog();
                    },
                    cleanerArgs
                );
            } else {
                log("ERROR - " + archiveUID + " - Code " + exitCode);
            }

            flushLog();
        },
        renameArgs
    );
}

logSpacer();
flushLog();
SAME HERE, did anyone find a solution?
This thread appears to be dead noone reply, hopefully OP or someone that knows can help with this.

T.I.A

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 03 Feb 2016, 02:43
by ronniehd
Ok i think i figured out and got rid of the error mentioned above and a second error related to permission denied.
I keep testing, once it works properly I'll post the code and setup with an explanation.

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 04 Mar 2016, 11:22
by FadeAway12
Any updates on this? :)

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 05 Mar 2016, 00:01
by rednoah

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 08 May 2016, 05:01
by Crack00r
I got this running on Windows, without any errors


the only problem is, it didnt delete the folder after move

Code: Select all

var command = "filebot.exe"; // Change this if filebot isn't on your path
var logfile = "D:/jdownloader-eventscripter.log"; // File this script logs to. Use forward slashes as path separators!
var filebotLogfile = "D:/filebot.log"; // File that filebot will log to. Use forward slashes as path separators!
var downloadBase = "D:/\Downloads/\extracted"; // Base folder under which your download packages reside. Use escaped backslashes as path separators!
var archiveExtensions = /(\.(zip|rar|7z|par\d+|part\d+|r\d+|t\d+|\d{3}))$/; // Regex to test for nested archives in extracted files

// Parameters for the scripts to run
var params = {
    "rename": {
        "options": {
            "-script": "fn:amc",
            "--log-file": filebotLogfile,
            "--action": "move",
            "--conflict": "override",
            "--lang": "de"
        },
        "defs": {
            "plex": "crack00r",
            "unsorted": "y",
            "skipExtract": "y",
            "clean": "y",
            "minFileSize": "104857600",
            "excludeList": "D:/amc-input.txt",
            "seriesFormat": "D:/Filme/Filme/Serien/{n}/{'Staffel '+s}/{n} - {s00e00} - {t}",
            "movieFormat": "D:/Filme/Filme/Filme/{n} ({y})"
        },
        "switches": [
            "-non-strict"
        ]
    },
    "cleaner": {
        "options": {
            "-script": "fn:cleaner",
            "--log-file": filebotLogfile
        },
        "defs": {
            "root": "y"
        },
        "switches": []
    }
}

var logBuf = "";

function log(message) {
    logBuf += new Date().toISOString().slice(0, 19) + " - " + message + "\r\n";
}

function logArray(message, arr) {
    log("\t" + message);

    if (arr == null) {
        log("\t\tnone");
        return;
    }

    for (var i = 0; i < arr.length; i++) {
        log("\t\t" + arr[i]);
    }
}

function logSpacer() {
    log("++++++++++++++++++++++++++++++");
}

function flushLog() {
    // Comment out the next two lines to prevent log from being written to file
    writeFile(logfile, logBuf, true);
    logBuf = "";
}

function quoteIfNecessary(value) {
    return (value != null && value.indexOf("\"") < 0) ? '"' + value + '"' : value;
}

function quoteArrayElements(input) {
    var result = [];

    for (var i = 0; i < input.length; i++) {
        result[result.length] = quoteIfNecessary(input[i]);
    }

    return result;
}

function reduce(map, joinChar) {
    var keyValuePairs = [];

    for (var key in map) {
        keyValuePairs[keyValuePairs.length] = key + joinChar + map[key];
    }

    return keyValuePairs;
}

function mapToArray(map) {
    var array = [];

    for (var key in map) {
        array[array.length] = key;
        array[array.length] = map[key];
    }

    return array;
}

function createArgumentArray(parameters, inputs) {
    var options = mapToArray(parameters["options"]);
    var switches = parameters["switches"];
    var defs = reduce(parameters["defs"], "=");

    return [command].concat(options).concat(switches).concat(inputs).concat(["--def"]).concat(defs);
}

function isArchiveFile(filename) {
    return archiveExtensions.test(filename);
}

function containsNestedArchive(extractedFiles) {
    for (var i = 0; i < extractedFiles.length; i++) {
        if (isArchiveFile(extractedFiles[i])) {
            return true;
        }
    }

    return false;
}

function getPackageRoot(folder) {
    return folder.substring(0, folder.indexOf("\\", downloadBase.length + 1));
}

var archiveFolder = archive.getFolder();
var archiveName = archive.getName();
var archiveType = archive.getArchiveType();
var extractedFiles = archive.getExtractedFiles();
var archiveUID = archiveFolder + "\\" + archiveName;
var packageRoot = getPackageRoot(archiveFolder);

logSpacer();
log("FINISHED EXTRACTION - " + archiveUID);
log("\tType: " + archiveType);
log("\tPackage root: " + packageRoot);
logArray("Extracted files:", extractedFiles);

if (extractedFiles == null || extractedFiles.length == 0) {
    log("SKIPPING - No files extracted.");
} else if (containsNestedArchive(extractedFiles)) {
    log("SKIPPING - Nested archive detected.");
} else {
    var renameInputs = quoteArrayElements(extractedFiles);
    var renameArgs = createArgumentArray(params["rename"], renameInputs);
    log("RUNNING SCRIPT - " + archiveUID);

    callAsync(
        function(exitCode, stdOut, errOut) {
            if (exitCode == 0) {
                log("SUCCESS - " + archiveUID);

                var cleanerArgs = createArgumentArray(params["cleaner"], packageRoot);

                log("CLEANING - " + packageRoot);

                callAsync(
                    function(exitCode, stdOut, errOut) {
                        if (exitCode == 0) {
                            log("ALL CLEAN - " + packageRoot);
                        } else {
                            log("STILL DIRTY - " + packageRoot);
                        }

                        flushLog();
                    },
                    cleanerArgs
                );
            } else {
                log("ERROR - " + archiveUID + " - Code " + exitCode);
            }

            flushLog();
        },
        renameArgs
    );
}

logSpacer();
flushLog();

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 01 Nov 2016, 14:39
by caphm
It's been a while, I'm sorry for leaving you guys with this still buggy script all alone :(

Anyway, I've been updating the script, fixing a lot of the bugs you mentioned and adding additional features.

Here's what's new:
  • Fixed detection of package root folder. I've tried using package.getDownloadFolder(), but if you have JDwonloader set to create a subfolder for each package, it only returns C:\PathToYourFolder\<jd:packagename>. That's why I reverted to the path matching method. This should work reasonably well on Windows, I've not encountered any problems. For other platforms, especially when using forward slashes as path separators, you will have to change line 143 to reflect this.
  • Added checking for relevant files: Many downloads include additional folders/files for sample, proof, etc. These shall not be considered and will thus not be excluded from processing.
  • Improved checking for nested archives: This is the major pitfall with JDownloaders EventScripter extension. The event is triggered for every successfully extracted archive. If there are nested archives, we don't want to run filebot prematurely. We only want it to run once the innermost archive has been extracted. When there are nested archives, the script recognizes this and skips further processing. The script will be called by JDowloader again once the nested archive has been extracted. This way you can use JDownloader for password cracking. Filebot won't do any decryption on its own. Just be sure to enable deep extract in JDownloader settings.
  • Added checking for relevant archives: Some downloads may contain separate archives for sample, proof and subs. We don't want filebot to run, if the main file has not been extracted yet. This works in conjunction with checking for relevant files. Together, these functions ensure, that filebot is only run once we definitely have the file we're interested in decrypted.
    Depending on the download, this will interfere with subtitles contained in separate archives. These will simply be ignored. Unfortunately, I haven't been able to find a solution yet, that doesn't break proper nested archive recognition.
  • Added tagging of packages for postprocessing: The package path will now be checked if it contains a tag to mark it for postprocessing. I've included it, because I didn't want everything processed by this script. It currently looks for [fb] (case insensitive, including the angle brackets) anywhere in the package path. You can customize this by modifying the regex in line 9.
  • Added tagging for 3D movies: Similarly to the postprocessing tag, you can also tag your packages if they are 3D. Just include [h-sbs] or [h-ou] (both case insensitive, must include angle brackets) anywhere in your package path, depending on the 3D format at hand. The movieFolderFormat and movieFileFormat in lines 16 and 17 use these tags to properly name your 3D movies and move them to a different location. If either h-sbs or h-ou tag is present, the folder where movies are stored will be prefixed with 3D. Also, the proper tag will be added to the new filename, such that your media center (Plex in my case) can properly recognize that it's a 3D movie.
    The naming scheme is specific to Plex's naming best practices. Be sure to customize it to your needs. I prefer having my 3D movies in a separate folder, because Plex doesn't indicate wether a movie has a 3D version while viewing your library.
    The tags can all be combined in one pair of angle brackets by separating them with any character, for example:

    Code: Select all

    [fb,h-sbs]
I've been running this script for quite a while now and it has proven fairly stable. It realiably detects nested archives and other junk files and only calls filebot when there really is a file we actually want to rename. Unfortunately, it doesn't work with subtitles contained in separate nested archives. Subtitles contained directly within the same archive as the main file(s) will be picked up and passed to filebot. You might have to tweak the arguments passed to filebot, to make sure that these will also be moved and not ignored.

I've tried adding Pushbullet support, to send notifications to your smartphone if a download is renamed successfully or if there was an error using alexschneider's amazing pushbullet-js (check it out at https://github.com/alexschneider/pushbullet-js ). Unfortunately, the EMACS interpreter used by JDownloader doesn't support the required Javascript functions, so we'll have to do without.

Hopefully this update will alleviate most of the troubles you guys have been dealing with. Go ahead and try it out:

Code: Select all

var command = "filebot"; // Change this if filebot isn't on your path
var logfile = "C:/log/jdownloader-eventscripter.log"; // File this script logs to. Use forward slashes as path separators!
var filebotLogfile = "C:/log/filebot.log"; // File that filebot will log to. Use forward slashes as path separators!
var downloadBase = "D:\\Downloads"; // Base folder under which your download packages reside. Use escaped backslashes as path separators!
var archiveExtensions = /(\.(zip|rar|7z|par\d+|part\d+|r\d+|t\d+|\d{3}))$/; // Regex to test for nested archives in extracted files
var irrelevantFiles = /(\\subs\\|\\proof\\|\-subs|\-proof)/i; // Regex for matching files which are irrelevant to renaming (subs, proof, etc)

var tags = {
    "filebot" : /\[.*FB.*\]/i,
    "3d" : "(?i)\\[.*(H\\-SBS|H\\-OU).*\\]",
    "hsbs" : "(?i)\\[.*H\\-SBS.*\\]",
    "hou" : "(?i)\\[.*H\\-OU.*\\]"
}

var movieDrive = "D:/Media/"
var movieFolderFormat = "{file =~ /"+tags["3d"]+"/ ? '3D ' : ''}Filme/{n} ({y}) [{vf}]{file =~ /"+tags["3d"]+"/ ? ' [3D]' : ''}{file =~ /"+tags["hsbs"]+"/ ? ' [H-SBS]' : ''}{file =~ /"+tags["hou"]+"/ ? ' [H-OU]' : ''}"
var movieFileFormat = "{n} ({y}) [{vf}]{file =~ /"+tags["3d"]+"/ ? ' [3D]' : ''}{file =~ /"+tags["hsbs"]+"/ ? ' [H-SBS]' : ''}{file =~ /"+tags["hou"]+"/ ? ' [H-OU]' : ''}{' CD'+pi}"

// Parameters for the scripts to run
var params = {
    "rename" : {
        "options" : {
            "-script": "fn:amc",
            "--log-file": filebotLogfile,
            "--action": "move",
            "--conflict": "auto"
        },
        "defs" : {
            "unsorted": "y",
            "skipExtract": "y",
            "clean": "y",
            "minFileSize": "104857600",
            "excludeList": "C:/Util/amc-input.txt",
            "seriesFormat": "D:/Media/Serien/{n}/{'Season '+s}/{n} - {s00e00} - {t}",
            "movieFormat": movieDrive + movieFolderFormat + "/" + movieFileFormat
        },
        "switches" : [
            "-non-strict"
        ]
    },
    "cleaner" : {
        "options" : {
            "-script": "fn:cleaner",
            "--log-file": filebotLogfile
        },
        "defs" : {
            "root" : "y"
        },
        "switches" : []
    }
}

var logBuf = "";

function log(message) {
    logBuf += new Date().toISOString().slice(0, 19) + " - " + message + "\r\n";
}

function logArray(message, arr) {
    log("\t" + message);

    if (arr == null || arr.length == 0) {
        log("\t\tnone");
        return;
    }

    for (var i = 0; i < arr.length; i++) {
        log("\t\t" + arr[i]);
    }
}

function logSpacer() {
    log("++++++++++++++++++++++++++++++");
}

function flushLog() {
    writeFile(logfile, logBuf, true);
    logBuf = "";
}

function quoteIfNecessary(value) {
    return (value != null && value.indexOf("\"") < 0) ? '"' + value + '"' : value;
}

function quoteArrayElements(input) {
    var result = [];

    for (var i = 0; i < input.length; i++) {
        result[result.length] = quoteIfNecessary(input[i]);
    }

    return result;
}

function reduce(map, joinChar) {
    var keyValuePairs = [];

    for (var key in map) {
        keyValuePairs[keyValuePairs.length] = key + joinChar + map[key];
    }

    return keyValuePairs;
}

function mapToArray(map) {
    var array = [];

    for (var key in map) {
        array[array.length] = key;
        array[array.length] = map[key];
    }

    return array;
}

function createArgumentArray(parameters, inputs) {
    var options = mapToArray(parameters["options"]);
    var switches = parameters["switches"];
    var defs = reduce(parameters["defs"], "=");

    return [command].concat(options).concat(switches).concat(inputs).concat(["--def"]).concat(defs);
}

function isArchiveFile(filename) {
    return archiveExtensions.test(filename);
}

function isRelevant(filename) {
    return !irrelevantFiles.test(filename);
}

function containsNestedArchive(extractedFiles) {
    for (var i = 0; i < extractedFiles.length; i++) {
        if (isArchiveFile(extractedFiles[i]) && isRelevant(extractedFiles[i])) {
            return true;
        }
    }

    return false;
}

function getPackageRoot(folder) {
    return folder.substring(0, folder.indexOf("\\", downloadBase.length + 1));
}

function commissionRelevantFiles(files) {
    if(files == null) return [];

    var relevantFiles = [];

    for (var i = 0; i < files.length; i++) {
        if(isRelevant(files[i])) {
            relevantFiles[relevantFiles.length] = files[i];
        }
    }

    return relevantFiles;
}

var links = archive.getDownloadLinks() ? archive.getDownloadLinks() : []
var package = links.length > 0 ? links[0].getPackage() : null
var archiveFolder = archive.getFolder();
var archiveName = archive.getName();
var archiveType = archive.getArchiveType();
var extractedFiles = archive.getExtractedFiles();
var archiveUID = archiveFolder + "\\" + archiveName;
var packageRoot = getPackageRoot(archiveFolder + "\\");
var relevantFiles = commissionRelevantFiles(extractedFiles);

logSpacer();
log("FINISHED EXTRACTION - " + archiveUID);
log("\tType: " + archiveType);
log("\tPackage root: " + packageRoot);
logArray("Extracted files:", extractedFiles);
logArray("Relevant files:", relevantFiles);

if (!tags["filebot"].test(packageRoot)) {
    log("SKIPPING - Package is not tagged for processing.");
} else if (extractedFiles == null || extractedFiles.length == 0) {
    log("SKIPPING - No files extracted.");
} else if (relevantFiles == null || relevantFiles.length == 0) {
    log("SKIPPING - No relevant files encountered.");
} else if (containsNestedArchive(extractedFiles)) {
    log("SKIPPING - Nested archive detected.");
} else if (!isRelevant(archiveUID)) {
    log("SKIPPING - Archive is irrelevant.");
} else {
    var renameInputs = quoteArrayElements(relevantFiles);
    var renameArgs = createArgumentArray(params["rename"], renameInputs);
    log("RUNNING SCRIPT - " + archiveUID);

    callAsync(
        function(exitCode, stdOut, errOut) {
            if (exitCode == 0) {
                log("SUCCESS - " + archiveUID);

                var cleanerArgs = createArgumentArray(params["cleaner"], packageRoot);

                log("CLEANING - " + packageRoot);

                callAsync(
                    function(exitCode, stdOut, errOut) {
                        if(exitCode == 0) {
                            log("ALL CLEAN - " + packageRoot);
                        } else {
                            log("STILL DIRTY - " + packageRoot);
                        }

                        flushLog();
                    },
                    cleanerArgs
                );
            } else {
                log("ERROR - " + archiveUID + " - Code " + exitCode);
            }

            flushLog();
        },
        renameArgs
    );
}

logSpacer();
flushLog();
As a last sidenote, I recommend ommitting the plex option from filebot and enabling Plex's internal folder watcher. By design of Plex's API, filebot is unfortunately limited to issuing a refresh command to all of your libraries. If you have a large photo or music library (like I do), this update takes ages to complete. Depending on the internal numbering of your libraries, your movies or series will only be picked up last, which can take up to over an hour. Plex's folder watcher has become really good recently. I've consistently seen it pick up new files after a couple of seconds, at least on Windows.

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 07 Nov 2016, 03:26
by Crack00r
i just get
SKIPPING - Package is not tagged for processing
on all files

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 07 Nov 2016, 06:16
by rednoah
Context? Logs?

SKIPPING - Package is not tagged for processing doesn't sound like something FileBot would say, so it's probably a JDownloader problem that's best discussed in the JDownloader forums:
https://board.jdownloader.org/

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 07 Nov 2016, 06:19
by caphm
It's an output of the script. You have to include [fb] somewhere in the filename (including brackets). See second to last bullet of my last post for info.

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 07 Nov 2016, 06:22
by rednoah
My bad. I'll leave this thread in the capable hands of caphm then. :lol:

Re: [CODE] Calling Filebot from JDownloader 2 Event Scripter

Posted: 07 Nov 2021, 12:56
by blackpit
Moin zusammen,
ich bekomme es nicht hin das Musik mit gemacht wird. Movies und Serien läuft super aber Mucke??? Synology Jdownloader Event Scripter
Hier mal mein sh Datei

Code: Select all

#!/bin/sh
##FileBot benötigt diese Variablen
##/bin/mkdir /volume1/video/download/testordner
QUELLE="/volume1/video/download/"
export JAVA_OPTS=`free | awk -vm=1024 -vp=0.7 '/Mem:/ {printf "-Xmx%dm", ($2*p)/m; exit}'`    # set -Xmx to 0.7 of physical memory
LOG="/volume1/video/Filebot/amc/amc.log"
EXC="/volume1/video/Filebot/amc/amc.txt"
SERIEN="/volume1/video/Serien/{n}/{'Staffel 0'+s}/{n} - {s00e00} - {t} ({y}) {vf}"
FILME="/volume1/video/Filme/{n.colon(' - ')} - {y}{' CD'+pi}{subt}"
MUSIC="/volume1/video/Music/{n}/{album+'/'}{pi.pad(2)+'. '}{artist} - {t}"
##filebot -script 'fn:amc' /volume1/video/download --output /volume1/video/Music/ --lang en --def 'music=y' 'unsorted=y' 'clean=y' 'deleteAfterExtract=y' 'plex=0.0.0.0' 'pushbullet=vLOrqXdy0whTtBTrPyDxmBHPSfkhbf6n' 'excludeList=.excludes' --log all
##UNSORTIERT="/volume1/video/unsortiert/{file.parentFile.name}/{file.structurePathTail}" ### Wenn Filebot mal etwas nicht zuordnen kann, dann kannst du es in einen seperaten Ordner verschieben lassen, dann bleibt es im Downloadordner übersichtlich.
##FileBot ausführen
/volume1/@appstore/filebot/bin/filebot -script fn:amc --lang de --log-file $LOG --action move "$1" --output "/volume1/video/" --def "seriesFormat=$SERIEN" "movieFormat=$FILME" "musicFormat=$MUSIC" "unsortedFormat=$UNSORTIERT" -non-strict --def unsorted=y "artwork=n" --def clean=y
## Aufräumen, --def root löscht den Unterordner mit
/volume1/@appstore/filebot/bin/filebot -script fn:cleaner "$1" --def root=y