How to determine the actual folder

Started by nordkapp, November 01, 2018, 06:39:43 PM

Previous topic - Next topic

nordkapp

Is it possible to get the name of the active folder? I only found the method getActiveView() which returns, if the folder&media view is selected.

If the folder has images in it, I could get the focused file and then take the foldername from there. But if the folder is empty or has more than 1000 files (Imatch paused) it doesn't work

Mario

There can be more than one folder selected, mind.

You can query the idlist @imatch.selectedFolders if you want the ids of the selected folders, or just use this idlist in whatever folder-related endpoint you call.

The names of all idlists are comfortable enumerated by the IMatch helper class. See https://www.photools.com/dev-center/doc/imatch/IMatch.html for the documentation and list.
You can just use IMatch.selectedFolders in your code to work with all selected folders.
Similar idlists exist for selected categories, collections etc.
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

nordkapp

Thanks Mario for the quick reply.

I don't get it. I have read the documentation twice and tried all different things. And it did not work.

Started from a working get request:
    IMatch.get('v1/folders',{
        id: 'all',
        fields: 'path'
    }).then(function(response) {


I tried to change the value for the parameter 'id' to
'selectedFolders'
'IMatch.selectedFolders'
IMatch.selectedFolders (without quotes)
'@selectedFolders'
'@imatch.selectedFolders'

and I changed the name of the parameter from id to idlist
but I get every time an error with 'Bad request' or an empty repsonse

And I tried IMatch.selectedFolders() as a function but it is not defined.

My understanding is still to little so I have to use trial and error. Could you give me a little hint or a working snippet, please.

Thanks,
Ralph

thrinn

#3
This should do the trick:

IMatch.get('v1/folders', { idlist: '@imatch.selectedFolders', fields: 'id,path' }).
    then(response => {
        console.log(JSON.stringify(response));
});


You can also use:

IMatch.get('v1/folders', { idlist: IMatch.idlist.selectedFolders, fields: 'id,path' }).
    then(response => {
        console.log(JSON.stringify(response));
    });


Be careful regarding upper and lower case. And I think Mario missed the .idlist. part in his answer which may have added to the confusion  ;).

To explain: imatchlib.js defines a global object IMatch. A property of this object is the enum idlist. One member of idlist is selectedFolders, which is defined as the string '@imatch.selectedFolders'.
So, IMatch.idlist.selectedFolders resolves to '@imatch.selectedFolders' which is why you can use one or the other.
Thorsten
Win 10 / 64, IMatch 2018, IMA

Mario

-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

nordkapp

Thanks Thorsten for the good clarification. Now it works and I have learned a little bit more  :D

For me as a beginner to javascript it add a little bit more complexity that you can use so much different writings and ommit some parts of the code at some point. I like the notation you used to call the IMatch.get My code now looks a little bit easier to read.

I have to determine the actual folder in another script. Is it possible to capsule the code in a function like this:

function getActualFolder() {
    IMatch.get('v1/folders', { idlist: '@imatch.selectedFolders', fields: 'id,path' }).
        then(response => {
            if (response.folders.length == 1) {
                return response.folders[0].path;
            } else {
                return '';
            }
         });   
}


My experience is that it is not possible because of the asynchron execution of the code. I tried it with other promisses calls and it did not work. Maybe there is another trick ;)

thrinn

Quote from: nordkapp on November 02, 2018, 09:52:28 AM
My experience is that it is not possible because of the asynchron execution of the code. I tried it with other promisses calls and it did not work. Maybe there is another trick ;)
There is  ;D
Basically, you have two options:

  • Returning a Promise (as opposed to a result value) from your helper function, using then to build a chain of function calls that rely on the result of the previous call.
  • Use the async and await language components.
We all (that is: the old-time Basic scripters) were struggling with this asynchronous concept at first. Have a look at this old post:
https://www.photools.com/community/index.php?topic=6721.0
The async/await keywords make it much easier to use some kind of synchronous programming paradigm with Promises. But still, you first have to get acquainted with them. In my opinion, the linked resources in the post mentioned above were very helpful.
Thorsten
Win 10 / 64, IMatch 2018, IMA

nordkapp

The trick is great !!!

I havn't seen the thread you linked to but I came across the hackernoon link https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9 month ago at the beginning of my javascript learning from another thread here in the forum. And I didn't understand anything. But now after some own experience I think I understand not all but a lot more.

First I convert my syntax to the syntax mentioned there
const getActualFolder = async () => {
    var response = await IMatch.get('v1/folders', { idlist: '@imatch.selectedFolders', fields: 'id,path' })
    if (response.folders.length == 1) {
        return response.folders[0].path;
    } else {
        return '';
    }
}

I had to replace the word function with const
But to call the function with     var actFolder = getActualFolder();
    if (actFolder != '') {
        console.log(actFolder);
    }
did not work. console.log reported something like promis pending.
Then I changed the call to     getActualFolder().
        then(actFolder => {
            console.log(actFolder);
    });

So it works. But what is the advantage of it? It is still the nesting of a asynchronus call.

But then I rewrote my script and put the whole logic in an async function and I am very happy with the result.

Here is a snippet of the function. The goal of my script is to go to another folder in my database depending on the folder i am actually in
const getDestinationFolder = async (wahl) => {
    // Als erstes den aktuellen Odner ermitteln.
    var actFolder = await getActualFolder();
    // Daraus dann den Namen des Zielordners bilden
    var gotoFolder = getGotoFolder(wahl, actFolder);
    // Prüfen, ob der Zielordner in der DB ist
    var folderID = await checkFolderExists(gotoFolder);
    if (folderID >= 0) {
        return folderID;       
    } else {
        // Der Ordner existiert nicht in der DB, daher den Serienordner verwenden (der aber auch nicht unbedingt existieren muss)
        var folderNameSerie = getSerienOrdner(gotoFolder);
        // Prüfen, ob der Serienordner in der DB ist
        folderID = await checkFolderExists(folderNameSerie);
        if (folderID >= 0) {
            return folderID;       
        } else {
            // Der Serienordner existiert auch nicht, daher -1 zurückgeben
            return -1;
        }
    }
}

this code is now much more looking like the synchronus programming paradigm.
At this time I have not much of an error handling but for this little script ist is ok. And I will try this technique more often in the future

Mario

There are some examples shipped with IMatch which use async to actually (shudder) block the code and wait for a request.

The general idea of promises is that you call a function (endpoint) which can take a long time. Or run in an error.
Whatever the outcome is, your promise will be fulfilled when the called function succeeds and it will be rejected otherwise.  However long that takes. May be 0.1 or 10 seconds.

This is a different programming paradigm, but one that becomes a key feature of all programming languages. Modern computers have , 4, 8 or even 32 separate processor cores and making a program wait for a calculation or a response from a web service is not really smart.

You want information about which folder is selected. To answer that, IMWS may need 0.1 seconds or 3 seconds.
So you use a promise (like for all IMWS calls) and tell JavaScript "Get me the selected folder, and when you know it, call this function". And in that function you do whatever needs doing.

Promises can also be easily chained, if you need to do A then B then C, for example.
But you can also do A and B and C at the same time and then let JS call a function in your code when everything is finished.

async / await is a modern construct to make this easier, apparently blocking the execution of your JavaScript code. It only works in modern browsers, but if your code is only for IMatch apps, you're good.

IMWS is not restricted to JavaScript. It can be accessed from all programming languages. I run Python scripts and even Windows Powershell scripts to process IMatch database contents
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

Carlo Didier

Quote from: Mario on November 02, 2018, 02:51:02 PM
IMWS is not restricted to JavaScript. It can be accessed from all programming languages. I run Python scripts and even Windows Powershell scripts to process IMatch database contents

I'd love to see an example of how you do that... Do you make http requests from Powershell?

Mario

A Python example is shipped with IMatch. And making REST requests from PowerShell is easy.  For example (from the top of my head, not tested):

Invoke-RestMethod -Uri "http://127.0.0.1:50519/v1/files?auth_token=&idlist=%40imatch.filewindow.active.selection&fields=id%2Cname"

Gives you the names of all currently selected files. This returns a JSON object which you can parse using the standard PowerShell JSON processing functions.
Or you can do a simple

$temp = Invoke-WebRequest -Uri "http://127.0.0.1:50519/v1/files?auth_token=&idlist=%40imatch.filewindow.active.selection&fields=id%2Cname" | ConvertFrom-Json

to make an object you can easily manipulate in PowerShell.

Numerous examples on calling REST services from PowerShell available on the internet.
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

Carlo Didier

Thanks Mario! I'll give that a try. Never had to call web services from Powershell before.


Mario

As I said, from the top of my head. But it works, right? Not hard to do.
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook