Accessing newly added tracks in iTunes with COM interface - javascript

I am trying to add track information to newly added tracks in iTunes using the COM interface and JavaScript. I am able to successfully add files, but am unable to grab them using OperationStatus.Tracks(). I know that OperationStatus.Tracks() is unavailable until after OperationStatus.InProgress() returns false. However, when I try to call InProgress() on what I expect to be an OperationStatus object, I receive the error: "Object doesn't support this property or method."
var iTunesApp = WScript.CreateObject("iTunes.Application");
var status = iTunesApp.LibraryPlaylist.AddFile('newfile.mp4');
WScript.Echo(status.InProgress());
Can anyone shed some light on to what is going wrong here?

I have since been able to answer my own question. I was simply adding empty parens when no parameters were necessary. As such, the methods and properties were not being recognized. The last line mentioned above will work in the following form:WScript.Echo(status.InProgress);To access the tracks that have been recently added can be done using var newtracks = status.Tracks; Then to access properties about an individual track can be done as follows: var newtrack = newtracks.ItemByName('filename');WScript.Echo(newtrack.Name);

Don't forget the result from the AddFile is asynchronous, so you will need to loop and wait before you can access the data.
var results = iTunesApp.AddFile( filepath );
// wait for the result to be available
while( results.InProgress )
Thread.Yield();
foreach( var it in results.Tracks )
{
tune = it as IITFileOrCDTrack;
Console.WriteLine( "Track '{0} - {1}' was added to itunes library", tune.Artist, tune.Name );
}
To get the latest added tracks, i guess you could create a smart playlist, sorted by the added date and access cycle through, this will probably be faster than accessing the whole itunes DB.

Related

Getting "All SuiteScript API Modules are unavailable while executing your define callback" When Creating NetSuite Script With Custom Module

When trying to create a new script record within NetSuite, I get the error "Fail to evaluate script: All SuiteScript API Modules are unavailable while executing your define callback". I can't find any real information on what may cause this, and I can't see anything in my custom module that looks suspicious. I can't post the code here as the module is nearly 2,000 lines in length and has some proprietary code in it. As it was with another custom module I built that had issues at the "Upload Script File" stage, if I remove reference to the module in the script the process continues, and then I can go back to the script and return the module reference, wherein everything seems to work correctly afterward.
The only information I found that seemed useful was that the error could be caused by referencing a module outside of the define callback, but that isn't the case. The module has two large objects constructed within, and they're returned from the callback. The only other thing I can think of is that this module calls the other custom module, but I haven't seen anything that says I can't do that.
So, overall, what should I look for to resolve this error? I really cn't seem to find anything useful or that applies to this situation.
EDIT
Ok, so I believe that I discovered the cause is due to the calling of a search function outside of an object/function being returned for the callback. Here's a simplified version of what's happening, since a lot of fields and values are managed:
/**
* custom.module.js
* #NApiVersion 2.x
* #NModuleScope Public
*/
define(['N/search'],
/**
* #param {search} search
*/
function(search) {
var fields = new Array("a","b","c","d","e");
var lValues = search.lookupFields({
type : "customrecord_ng_cs_settings"
, id : "1"
, columns : fields
});
var _values = {
a : lValues.a
, b : lValues.b
, c : lValues.c
, d : lValues.d
, e : lValues.e
};
var _funcs = {
func_a : function() {
// do stuff
}
, func_b : function() {
// do stuff
}
, func_c : function() {
// do stuff
}
};
return {
value : _values
, func : _funcs
};
});
I need to maintain this kind of structure as not everything that gets returned in _values is actually a search/lookup result. Am I going to be forced to encapsulate the construction of this object within a function? And would that cause the lookup to occur every time a value is needed? This is a conversion from a 1.0 script, and this gets loaded and set only once at the beginning so the data is all there the entire time without having to be repeatedly fetched.
So, I see the following options:
Convert the callback output to a function and doing something like
the following at the start of every script:
var _values = customModule.values();
Find some way to rework the code so that any script using the module
can still access values in the following way:
var _a = customModule.values.a;
I'd very much prefer option #2. Is it possible?
You cannot run any SuiteScript module code outside of an entry point. You will need to encapsulate your data retrieval in a function, then invoke that function at the beginning of your entry point.
If you want to avoid multiple fetches, you can leverage memoization in your function, or perhaps N/cache or N/session to store the data.

(JavaScript API 1.3 for Office) Set Value of Custom Properties

My client has decided to migrate to Office 2016 and porting portions of a business process to that client requires us to offer a replacement to the Document Information Panel, which is no longer available. The Backstage file information area isn't considered a sufficient user experience for the users in question, so we're endeavoring to replace the DIP with a Task Pane app.
This example: https://www.youtube.com/watch?v=LVGqpns0oT8&feature=share shows that the idea is, at least in theory, possible. We considered buying this app but can't find sufficient information to do so.
So we set about attempting to replicate the functionality we need in the DIP. It appears that we can successfully set Document Properties of standard types, such as strings, which looks something like this:
Word.context.run(function(context){
var properties = context.document.properties;
context.load(properties):
return context.sync().then(function(){
properties.title = properties.title + " Additional Title Text"; // once the sync goes off, this works.
return context.sync();
});
});
However, when we try to update an Document Property that's, for example, a Managed Metadata property defined by a SharePoint content type, the value in the proxy object loads and remains changed, but it seems to break its relationship to the actual document property. The code below demonstrates:
Word.context.run(function(context){
var properties = context.document.properties;
var customProperties = properties.customProperties;
context.load(properties):
context.load(customProperties);
return context.sync().then(function(){
var managedMetadataProperty = customProperties.getItem('MngdMetadata');
properties.title = properties.title + " Additional Title Text"; // once the sync goes off, this works.
context.load(managedMetadataProperty);
return context.sync().then(function(){
console.log(managedMetadataProperty.value) // let's say this looks like "10;#Label 1|64d2cd3d-57d4-4c23-9603-866d54ee74f1"
managedMetadataProperty.value = "11;#Label 2|cc3d57d4-4c23-72d4-3031-238b9100f52g"
return context.sync(); // now the value in the javascript object for managedMetadataProperty is updated, but the value in the document does not change.
});
});
});
The document property Managed Metadata Property never changes in the Word UI, nor does a change push back to the SharePoint. Say we save and close the document after making the update, then re-open it. The Property value has not visibly changed, however when we load the proxy object with 'context.load()', the value that's available reflects the changes we made on last run.
I'm unclear about why this would be. It seems like to circumvent this, I would need to make a call back to SharePoint to update the relevant field, but I don't know how I would instruct Word to refresh with the new information from SharePoint.
That's a great question.
The custom properties API gives you access to some built-in properties as well as custom properties. SP-related properties do NOT follow in this category from the API perspective. (and the same is true in VBA/VSTO/COM) To access those you need to use the CustomXmlParts functionalities. Here is a good example on how to use it in the Javascript API.
Also, FYI, the team is working right now in a feature to enable the DIP again, i don't have concrete dates or commitment, but you might get this functionality again out of the box soon.
Have you tried customPropertyCollectionObject.add(key, value) ?
It will replace existing kvp's in the customPropertiesCollectionObject.
Here is the documentation customPropertiesCollection

Setting a new property to PFObject

I have a Parse.com cloud function that sends back a PFObject. In some cases I need to send back values for keys that don't exist in the PFObject. Is that possible?
This is what I tried:
var test = prodAndTitles["products"][0];
test["XOXO"] = "kisses";
prodAndTitles["products"][0] = test;
console.log("XOXO = " + prodAndTitles["products"][0]["XOXO"]);
This prints out kisses as expected.
But back in the app when I try to get the XOXO key it's not there:
NSLog(#"The product's XOXO %#", [self.product objectForKey:#"XOXO"]);
This prints out null.
I also tried changing the product type from PFObject to id, but it doesn't help.
Is there a solution, without going into the datastore class and creating dummy columns?
Here's a complete answer to the problem I faced:
The issue is that none of the notations above works for the Parse.com backbone javascript objects that come from the datastore. This is the notation that does work:
testObject.set('TestProp', 'TestValue');
But this is still only part of the solution. When trying to send the testObject with the newly set property to the client ios app, it causes an error:
Uncaught Tried to save an object with a pointer to a new, unsaved object.
The solution for this is to save the testObject after setting the property:
testObject.save();
This doesn't really make sense because I would have liked to add properties to the testObject and NOT save them to the datastore -- and it's a waste of a database call -- but it seems like Parse won't allow it. Weird.
This is done with setting the correct ACL. The ACL has to be set for the user to be able to read and write. Then you can add new columns. In Cocoa it looks something like this:
PFACL *acl = [PFACL ACL];
[acl setReadAccess:YES forUser:[PFUser currentUser]];
[acl setWriteAccess:YES forUser:[PFUser currentUser]];
[test setACL:acl];

Writing JS code to mimic api design

We're planning on rebuilding our service at my workplace, creating a RESTful API and such and I happened to stumble on an interesting question: can I make my JS code in a way that it mimics my API design?
Here's an example to illustrate what I mean:
We have dogs, and you can access those dogs doing a GET /dogs, and get info on a specific one by GET /dogs/{id}.
My Javascript code would then be something like
var api = {
dogs : function(dogId) {
if ( dogId === undefined ) {
//request /dogs from server
} else {
//request /dogs/dogId from server
}
}
}
All if fine and dandy with that code, I just have to call api.dogs() or api.dogs(123) and I'll get the info I want.
Now, let's say those dogs have a list of diseases (or whatever, really) which you can fetch via GET /dogs/{id}/disases. Is there a way to modify my Javascript so that the previous calls will remain the same - api.dogs() returns all dogs and api.dogs(123) returns dog 123's info - while allowing me to do something like api.dogs(123).diseases() to list dog 123's diseases?
The simplest way I thought of doing it is by having my methods actually build queries instead of retrieving the data and a get or run method to actually run those queries and fetch the data.
The only way I can think of building something like this is if I could somehow, when executing a function, if some other function is chained to the object, but I don't know if that's possible.
What are your thoughts on this?
I cannot give you a concrete implementation, but a few hints how you could accomplish what you want. It would be interesting to know, what kind of Server and framework you are using.
Generate (Write yourself or autogenerate from code) a WADL describing your Service and then try do generate the Code for example with XSLT
In my REST projects I use swagger, that analyzes some common Java REST Implementation and generates JSON descriptions, that you could use as a base for Your JavaScript API
It can be easy for simple REST Apis but gets complicated as the API divides into complex hierarchies or has a tree structure. Then everything will depend on an exact documentation of your service.
Assuming that your JS application knows of the services provided by your REST API i.e send a JSON or XML file describing the services, you could do the following:
var API = (function(){
// private members, here you hide the API's functionality from the outside.
var sendRequest = function (url){ return {} }; // send GET request
return {
// public members, here you place methods that will be exposed to the public.
var getDog = function (id, criteria) {
// check that criteria isn't an invalid request. Remember the JSON file?
// Generate url
response = sendRequest(url);
return response;
};
};
}());
var diseases = API.getDog("123", "diseases");
var breed = API.getDog("123", "breed");
The code above isn't 100% correct since you still have to deal with AJAX call but it is more or less what you what.
I hope this helps!

Trying to save open MS Access documents from JScript

I was hoping to save all open MS Access documents via a JScript run from the Windows Script Host.
So far I was able to obtain the MS Access object by calling:
var objAccess = GetObject('', "Access.Application");
But now I'm stumped. If it was MS Word, I'd enumerate all open documents in the .Documents property and call Documents.Item(n).SaveAs() method on each of them.
But how do you save-as all open documents in MS Access?
After you have your object variable set to an Access application instance with GetObject, use its Quit method with the acQuitSaveAll option (value = 1). Not sure about JScript; in VBScript, I can do it like this.
Dim objAccess
Set objAccess = GetObject(,"Access.Application")
WScript.Echo objAccess.CurrentDb.Name
objAccess.Quit(1) ' acQuitSaveAll
Set objAccess = Nothing
Note, when I used GetObject as in your example, objAccess was a new Access application instance rather than a reference to the instance which was running previously. So, with the GetObject line like this ...
Set objAccess = GetObject('', "Access.Application")
... the WScript.Echo line threw an error with CurrentDb.Name (because there was not a database open in that Access application instance.
This approach will save any changes to database objects (tables, forms, reports, etc.) which were in design mode but not saved. However if a user has any unsaved changes to data in a form, those changes will be discarded despite the acQuitSaveAll option. It seems that option only applies to objects, not data.
Edit: If that approach is not satisfactory, you can do something more sophisticated with VBA in your Access applications, as #Remou mentioned in his comment. An example is KickEmOff from Arvin Meyer. He also offers a sample database which demonstrates that code in action.
Edit2: Remou's comment got me thinking acQuitSaveNone (value = 2) should be safer than acQuitSaveAll ... the unsaved object changes would be discarded, but at least you would be less likely to save an object in a non-functional state.

Categories