Need to invoke a python script

I'm looking at the simple script function example that leo mentioned a couple of posts up:

gpsoft.com.au/help/opus11/in ... nction.htm

My intention is to be able to use vbscript or jscript (I have no idea which may be the best one to use or why) to do the equivalent of the dos batch file method of calling the python code with the modified folder to be processed. I have zero experience with vbscript or jscript, so this is a very steep learning curve. Looking at something that's working and having a play with it has always worked for me in the past as a way to start to understand how it works.

Your select size=largest might be a step at some point...

Here's what I want to do in jscript (why jscript you ask - no idea, just choosing one):

  1. Select folder to be processed
  2. press button marked SCAN to invoke script
  3. script then creates a variable with full path including folder e.g. \NAS\share\a\b\c\final folder
  4. script then updates variable to change \ to \, space to \space, etc
  5. script then issues COMMAND to run dos command with inserted variable: python pythonscript -d
@script jscript
function OnClick(clickData) {
	target = new Enumerator(clickData.func.sourcetab.selected_dirs);
	[at the moment only one folder selected is allowed]
	[have not seen any sign of how to manipulate target variable]
	[several dos batch commands to be issued as a unit including getting to the right folder, followed by this one]
	clickData.func.command.RunCommand("python pythonscript -d " + target + " bit more at the end")
}

Not choosing vbs to start with scripting is a good decision, even if it was out of luck. o) JS is more versatile than vbs.
This hopefully gives you a start, notice that I removed the output redirection, I'm currently not aware of how DOs RunCommand() handles that. If you need redirected output and/or pyhton.exe return code, let us know and avoid trying hard, it can be an itchy topic. o)

[code]@script jscript

function OnClick(data) {
var tab = data.func.sourcetab; //create a more handy sourcetab reference
var cmd = data.func.command; //create a more handy command reference
cmd.deselect = false; //do not deselect affected folder
if (!(tab.selected.count==1 && tab.selected_dirs.count==1))
return; //get out of here if selection is different from one folder
var folderPath = new String(tab.selected_dirs(0).realpath); //get folderpath as jscript string
folderPath = folderPath.replace(/(\|\ |%|-|+|')/g,'\$1'); //' replace/escape chars
var cmdLine = '"C:\Python27\python.exe" scan.py -d sonospy.db "'+folderPath+'"'; //build cmdline
DOpus.Output("Running: " + cmdLine); //output cmdline to DO console for looking at it
cmd.RunCommand(cmdLine); //run
}
[/code]

Thanks tbone that looks good. I've tried it out with the final runcommand commented out. I can see the output to the script log. The only bit missing now is to put in the command to change directory so that when the python script runs it is in the right place.

Here's the latest version:

@script jscript

function OnClick(data) {
   var tab = data.func.sourcetab; //create a more handy sourcetab reference
   var cmd = data.func.command; //create a more handy command reference
   cmd.deselect = false; //do not deselect affected folder
   if (!(tab.selected.count==1 && tab.selected_dirs.count==1))
      return; //get out of here if selection is different from one folder
   var folderPath = new String(tab.selected_dirs(0).realpath); //get folderpath as jscript string
   folderPath = folderPath.replace(/(\\|\ |\%|\-|\+|\')/g,'\\$1'); //' replace/escape chars
   var cmdLine = '"C:\\Python27\\python.exe" scan.py -d sonospy.db '+folderPath+''; //build cmdline
   DOpus.Output("Running: " + cmdLine); //output cmdline to DO console for looking at it
	var cmdLine2 = 'CD /D "C:\Users\xxx\Downloads\SonospyReleases\sonospy-current\sonospy"';
	cmd.RunCommand(cmdLine2);
	var cmdLine3 = 'dir';
	cmd.RunCommand(cmdLine3);
   //cmd.RunCommand(cmdLine); //run
}

The python line now looks perfect according to the dopus.output. The puzzle at the moment is that when cmdLine2 is executed (assuming it is) there is no visible sign. I was expecting a dos window or something to pop up. And the next puzzle is the error message when cmdLine3 is executed:

Windows cannot find 'dir'
Make sure you typed the name correctly and then try again.

So the main puzzle is the place where the dos commands are executed and where the output and results can be seen. As you mentioned before there is some uncertainty about how to capture the output. Before we get there though it would be nice to just see the output.

For "cd" and "dir" dos-commands to work, you need to set the type of the command object to "msdos".
Running multiple commands that build up on each other need to be added in a way that creates a set of commands, which then is not run by RunCommand() but Run(). See this, it opens a dos-prompt and "dirs" the directory content. The prior calls to "cd" and python.exe fail for me of course.

Whenever you fiddle with paths in jscript, you need to escape the backslashes, I doubled all "" in your cd command, the one calling python was already set correctly. I also removed +'' at the end of the python commandline as adding an empty string to a string seldomly makes sense. You again wanted to get rid of the doubleqoutes, which worked the way you did it, but that loose +'' at the end is not necessary if it does not contain character(s) like it did before.

[code]@script jscript

function OnClick(data) {
var tab = data.func.sourcetab; //create a more handy sourcetab reference
var cmd = data.func.command; //create a more handy command reference
cmd.deselect = false; //do not deselect affected folder
cmd.SetType("msdos"); //set "button" type to msdos
if (!(tab.selected.count==1 && tab.selected_dirs.count==1))
return; //get out of here if selection is different from one folder
var folderPath = new String(tab.selected_dirs(0).realpath); //get folderpath as jscript string
folderPath = folderPath.replace(/(\|\ |%|-|+|')/g,'\$1'); //' replace/escape chars
cmd.AddLine('cd /D "C:\Users\xxx\Downloads\SonospyReleases\sonospy-current\sonospy"');
cmd.AddLine('"C:\Python27\python.exe" scan.py -d sonospy.db '+folderPath); //build cmdline
cmd.AddLine('dir');
cmd.AddLine('pause');
cmd.Run(); //run
}[/code]

There is an internal CD command (where the /D argument isn't needed), but if you want to use "dir" and "pause" after the python script is run then you'll still want to use DOS mode for the cmd object, since those are both DOS commands.

If you don't use filename quoting, you'll have to quote it yourself, even for the dos SET command.
This command will also fail:

SET test=hello&world

However, this works:

SET "test=hello&world"

lol, I didn't notice this was a multipage post :slight_smile:
sorry..

ok back in the saddle ready to try the latest version out - thanks tbone, leo "&" myarmor

I will be interested to see if I get a proper dos window opening up where I can have a pause at the end to be able to inspect it and then hopefully I will also be able to capture the output. Just to clarify, I don't need a dir command as such, I was just trying to illustrate that there will be a series of dos commands.

I was diverted because I foolishly managed to update my music files on the backup nas rather than the main one and then also updated the sonospy database. I'd made a few changes and had to work out what I'd done so that I could back it all out and start again. Any way in the course of that I thought wouldn't it be wonderful if I could highlight the backup tab in some way (via colour, font, background, lock updates, etc), but try as I might via search forum and manual and clicking about, I can't work it out.

My compromise was to update the script with a Set foldertoscan=%foldertoscan:NAS_TO_BE_AVOIDED=IGNORE_THIS_NAS% and that seems to do the trick as the python scan will now be pointed at a non-existent folder. Must work out how to do the same thing with the jscript version.

ok that's looking very good!

I do get a proper dos window and with a pause that's perfect. I just have to try out the redirection stuff:

adding

>>nrscan3.log 2>&1

to the end of the python line, plus another couple of bits.

Not sure if it's because I've edited it a few times but it is starting to look readable...

This all seems to be working fine now, with redirection to a log. I've tried it out a few times now and it is looking good.

@script jscript

function OnClick(data) {
   var tab = data.func.sourcetab; //create a more handy sourcetab reference
   var cmd = data.func.command; //create a more handy command reference
   cmd.deselect = false; //do not deselect affected folder
   cmd.SetType("msdos"); //set "button" type to msdos
   if (!(tab.selected.count==1 && tab.selected_dirs.count==1))
      return; //get out of here if selection is different from one folder
   var folderPath = new String(tab.selected_dirs(0).realpath); //get folderpath as jscript string
   var re = /SYN-DS215J-A/i;
   if (folderPath.search(re) > 0)
   	return;
   folderPath = folderPath.replace(/(\\|\ |\%|\-|\+|\')/g,'\\$1'); //' replace/escape chars
   cmd.AddLine('echo on');
   cmd.AddLine('prompt $D_$T_$G');
   cmd.AddLine('echo ----------  start scan  ---------- >>nrscan3.log');
   cmd.AddLine('cd /D "C:\\Users\\Nigel\\Downloads\\SonospyReleases\\sonospy-current\\sonospy"');
   cmd.AddLine('dir sonospy.db >>nrscan3.log');
   cmd.AddLine('C:\\Python27\\python.exe scan.py -d sonospy.db '+folderPath+' >>nrscan3.log 2>&1'); //build cmdline
   cmd.AddLine('echo ----------  end scan  ---------- >>nrscan3.log');
   cmd.AddLine('type logs\\scanlog.txt');
   cmd.AddLine('pause');
   cmd.Run(); //run
}

The only line I'm having trouble understanding is this one:

folderPath = folderPath.replace(/(\\|\ |\%|\-|\+|\')/g,'\\$1'); //' replace/escape chars

I googled for jscript replace method but everything seemed to point to microsoft and I became none the wiser. It's all probably second nature and you don't need to look stuff up, but do you have any recommendations for good sources of info about jscript, with examples, etc that isn't designed for rocket science use only?

The only bit I'd like to add is to detect where I'm trying to use the backup NAS, so something like:
if (folderPath.includes('SYN-DS215J-A'))
return; // get out of here

Well, you can see my novice attempt in the code above, which seems to work - I just used an example I found at microsoft, and I'm sure it can be combined into a single line of code... It would be nice to have some suitable messages go to the script log if the script makes a sharp exit, but not sure how you do that in jscript...

this would be between the var folderPath and the replace...

Your attempt with .search() uses a regular expression to search in the path, if it works - ok! If not try this:
if (folderPath.toUpperCase().indexOf("SYN-DS215J-A") != -1) return;

The line you're having trouble with "folderPath = folderPath.replace(..);" is a regular expression search and replace.
It searches for the given characters (%'-+ etc.) and replaces any occurence with the same character and a leading .
It's the equivalent to your block of "Set folderpath=%folderpath:?=?%" commands used in the former batch version.

Printing text and log-information to the DO console can be done with DOpus.Output("my text"); - we already used it at some point. Here is the validation of the current selection with a little text printed whenever it's different from 1 folder and so leads to exiting the script. Watch the added {} brackets, they surround multiple statements now (2 in this case), they are required if you like to execute more than one statement for an if-condition that evaluates to true.

if (!(tab.selected.count==1 && tab.selected_dirs.count==1)){ DOpus.Output("Not a single folder selected, exiting.."); return; //get out of here if selection is different from one folder }
We already had some good links regarding js-tutorials and how to avoid drowning in google-hits relevant to javascript only. Please check the search and notice that most javascript code will do fine in the jscript world. So a basic javascript tutorial would be fine too I guess, you "just" need to ignore all browser related objects, facts and figures. o)

thanks that's all in and tested ok

I think I understand now about how it isn't going to be possible to completely separate javascript from web stuff. I had a look on amazon and looking through some sample pages, Head First Javascript programming by Eric Freeman looks promising for the aspiring novice as it seems to have good stuff about javascript principles.

To get started, all you need is a texteditor and some kind of command prompt to run your first scripts from. Some editors also allow to run scripts directly and will display the console output as well. Editplus is one of my favourites. You don't need to use DO to get into scripting. Instead, stick to the regular windows/dos-prompt, read-in and write-out some files, get in touch with arrays and objects and check how to work with strings and such. Once you feel like making progress, maybe lookup some existing DO scripts and try to read them (not without looking into the DO scripting reference of course! o).

Some windows scripting related information using jscript here:

tergestesoft.com/~manuals/jslang/JStutor.htm
winscripter.com/WSH/default.aspx
wsh2.uw.hu/index.html
technet.microsoft.com/de-de/lib ... 56607.aspx

To add to tbone's list, here's some more (this is documentation, not guides):

Offline JScript and VBScript (5.6) documentation: this (CHM helpfile).
Online JScript and VBScript documentation: msdn.

My editor of choice is EditPad Pro.

One advantage to using jscript is that loops are now possible, so I'd like to modify the script to handle 1 or more folders selected. Obviously the test to return if the number of folders selected is not 1 is now not required, and the while loop and folderpath manipulation get moved to generate multiple cmdline python calls.

Having looked at a few of your suggested readings, I can now make progress with jscript, but working out how to interface with the dopus objects is not too clear, yet!


// assume all the setup stuff is in place
var folderPath; // define outside the while loop
something.moveFirst(); //position at first selected folder - something???
while something.atEnd() == false // something??
{
folderPath=string(tab.selected_dirs.realpath); // not sure how to get the current one - item???
//folderPath replace escape chars here
cmd.addLine('python scan for folderPath here')
something.moveNext(); //position to next selected folder something???
}
// and the closedown stuff here

Thanks

I linked an example earlier in the thread:

[quote="leo"]Starting points for scripting in Opus:

Opus manual: Scripting chapter
Opus manual: Scripting reference
Opus forum: Scripting questions & answers
Opus forum: Lots of example scripts

In a script function, clickData.Func.SourceTab.selected (or selected_files or selected_dirs) will get you a list of the selected files.

The simple script function example in the manual shows how to enumerate through a list of files. (It goes through the SourceTab.files list of all files, which isn't the list you want, but the way you enumerate the lists is the same for the selected file/dir lists.

You can use Opus's own Command object to run the python script, but you can also use WScript's shell.run as well; it doesn't make much difference in this case. (Sometimes one is preferable, sometimes the other, and often it doesn't matter which.)[/quote]

I did have a look at that, honest!

The referencing name in your example seems to be different from tbone's referencing which is what is throwing me at the moment. Anyway, I'm going back to basics, I'm going through the objects and listing all the properties. For example:

@script jscript
// somehow when the script button is clicked, data contains something useful
function OnClick(data) 
{
   var tab = data.func.sourcetab; //create a more handy sourcetab reference
   var cmd = data.func.command; //create a more handy command reference
   DOpus.Output('access ' + tab.selected_dirs(0).access);
   DOpus.Output('access_utc ' + tab.selected_dirs(0).access_utc);
   DOpus.Output('attr ' + tab.selected_dirs(0).attr);
   DOpus.Output('attr_text ' + tab.selected_dirs(0).attr_text);
   DOpus.Output('checked ' + tab.selected_dirs(0).checked);
   DOpus.Output('create ' + tab.selected_dirs(0).create);
   DOpus.Output('create_utc ' + tab.selected_dirs(0).create_utc);   
   DOpus.Output('display_name ' + tab.selected_dirs(0).display_name);
   DOpus.Output('ext ' + tab.selected_dirs(0).ext);
   DOpus.Output('failed ' + tab.selected_dirs(0).failed);
   DOpus.Output('got_size ' + tab.selected_dirs(0).got_size);
   DOpus.Output('groups ' + tab.selected_dirs(0).groups);
   DOpus.Output('id ' + tab.selected_dirs(0).id);
   DOpus.Output('is_dir ' + tab.selected_dirs(0).is_dir);
   DOpus.Output('metadata ' + tab.selected_dirs(0).metadata);
   DOpus.Output('modify ' + tab.selected_dirs(0).modify);
   DOpus.Output('modify_utc ' + tab.selected_dirs(0).modify_utc);
   DOpus.Output('name ' + tab.selected_dirs(0).name);
   DOpus.Output('name_stem ' + tab.selected_dirs(0).name_stem);
   DOpus.Output('path ' + tab.selected_dirs(0).path);
   DOpus.Output('realpath ' + tab.selected_dirs(0).realpath);
   DOpus.Output('selected ' + tab.selected_dirs(0).selected);
   DOpus.Output('size ' + tab.selected_dirs(0).size);

   

   return;

yields:

Successfully initialized 'jscript' engine
Script started successfully
access Sat Jun 6 19:55:44 UTC+0100 2015
access_utc Sat Jun 6 18:55:44 UTC+0100 2015
attr 16
attr_text ------
checked false
create Sat Jun 6 16:31:27 UTC+0100 2015
create_utc Sat Jun 6 15:31:27 UTC+0100 2015
display_name 
ext 
failed false
got_size true
groups 
id 4
is_dir true
metadata doc
modify Sat Jun 6 19:57:03 UTC+0100 2015
modify_utc Sat Jun 6 18:57:03 UTC+0100 2015
name Lets_Get_Lost
name_stem Lets_Get_Lost
path D:\downloads\qb
realpath D:\downloads\qb\Chet_Baker_Lets_Get_Lost
selected true
size 0
Script completed

So that's starting to make more sense, and hopefully I can repeat this for other objects and their properties and sneak up on it that way.

Questions arising from this:

  1. what does attr 16 mean - it's not in the Item doc:

gpsoft.com.au/help/opus11/in ... g/Item.htm

  1. is there a built in way to dump stuff out like this? A sort of object dump?

  2. So, I've successfully used a refence like this:

tab.selected_dirs(0).access to get hold of the access time. presumably the (0) gets hold of the first selection, array position zero, so I'm not far away from working out how get that reference inside a while loop for multiple folders.

Leo, ok I stopped trying to modify my existing script which works for one folder, and started with your example.

my apologies.

anyway here is a while loop that dumps out stuff and is very close to being able to be the new script that works for multiple folders. This might be the basis of a bit of an intro tutorial for anyone who is new to objects, jscript, etc. I know it helped me and I'll continue to develop this dumping mechanism.

Thanks for your patience

@script jscript
// somehow when the script button is clicked, data contains something useful
function OnClick(data) 
{
   var tab = data.func.sourcetab; //create a more handy sourcetab reference
   var cmd = data.func.command; //create a more handy command reference
   enumFiles = new Enumerator(tab.selected_dirs);
   enumFiles.moveFirst();
   while (enumFiles.atEnd() == false)
   {
   DOpus.Output('access ' + enumFiles.item().access);
   DOpus.Output('access_utc ' + enumFiles.item().access_utc);
   DOpus.Output('attr ' + enumFiles.item().attr);
   DOpus.Output('attr_text ' + enumFiles.item().attr_text);
   DOpus.Output('checked ' + enumFiles.item().checked);
   DOpus.Output('create ' + enumFiles.item().create);
   DOpus.Output('create_utc ' + enumFiles.item().create_utc);   
   DOpus.Output('display_name ' + enumFiles.item().display_name);
   DOpus.Output('ext ' + enumFiles.item().ext);
   DOpus.Output('failed ' + enumFiles.item().failed);
   DOpus.Output('got_size ' + enumFiles.item().got_size);
   DOpus.Output('groups ' + enumFiles.item().groups);
   DOpus.Output('id ' + enumFiles.item().id);
   DOpus.Output('is_dir ' + enumFiles.item().is_dir);
   DOpus.Output('metadata ' + enumFiles.item().metadata);
   DOpus.Output('modify ' + enumFiles.item().modify);
   DOpus.Output('modify_utc ' + enumFiles.item().modify_utc);
   DOpus.Output('name ' + enumFiles.item().name);
   DOpus.Output('name_stem ' + enumFiles.item().name_stem);
   DOpus.Output('path ' + enumFiles.item().path);
   DOpus.Output('realpath ' + enumFiles.item().realpath);
   DOpus.Output('selected ' + enumFiles.item().selected);
   DOpus.Output('size ' + enumFiles.item().size);
   DOpus.Output('size.cy ' + enumFiles.item().size.cy);
   DOpus.Output('size.fmt ' + enumFiles.item().size.fmt);
   DOpus.Output('size.high ' + enumFiles.item().size.high);
   DOpus.Output('size.low ' + enumFiles.item().size.low);
// not sure how to define it outside the while loop and use it inside
   var folderPath = new String(enumFiles.item().realpath); //get folderpath as jscript string
   DOpus.Output('folderPath ' + folderPath);
   enumFiles.moveNext();
   }
   

   return;