Mediatomb Scripting - developer's tutorial. Process flow In the current implementation upon server start a single script is loaded and compiled into bytecodes by the SpiderMonkey engine. After this has happened the scripting environment is ready to efficiently handle virtual objects. Once a file is selected to be added it first gets included into PC Directory tree and then a JavaScript clone of the added object is created, assigned to the global variable 'orig' in the script's context and the script is invoked. Changes maid to the 'orig' variable during the script execution do not modify the added item. Scripting environment does not have any influence on items added to the PC Directory. This restriction may be reviewed in future releases. JavaScript object representation. Every Content Directory object is represented in JavaScript by a JavaScript object. Various object properties such as title or parentID are directly mapped to the regular JavaScript object properties with same symbolic names. ALL the properties are of integer or string type wigh one exception - .meta property is an object, more on this later. At the end of this tutorial there is a reference of all known properties. Example: The following script will print some info about an object after it has been inserted. print('Title: '+ orig.title); print('Parent ID: '+ orig.parentID); NOTE: This script doesn't create any objects. This particular chunk of code as a complete script is rather senseless, because it _never_ creates any virtual objects, but it's perfectly legal to have a script creating virtual objects not for every passed object and make decision based on the object properties. Every object has a special .meta property. the value of this property is a further JavaScript object and contains the metadata of the object. property names are the same as corresponding UPnP tag names. Several constants are defined for the UPnP classes and it is highly recommended to use them instead of UPnP names. Like this: print ( obj.meta[M_TITLE] ); instead of print ( obj.meta["dc:title"] ); NOTE: obj.meta[M_TITLE] may not be replaced with obj.meta.M_TITLE, don't get confused. A few words about titles, please read carefully. Every object has a required obj.title property and may have a obj.meta[M_TITLE] metadata set. This is important to know the difference. orig.meta[M_TITLE] is _never_ displayed to UPnP clients. It's sole purpose is to store the _original_ title of the object determined by media detection subsystem. When an object is passed to the script it's meta[M_TITLE] reflects the _detected_ title of the object (for example taken from an IDv3 tag inside mp3.) orig.title is initially set to the filename without path of the added object. (Since it is it's title in the PC Directory) NOTE: Almost _any_ kind of script would want to set the obj.title of the objects it creates to something different than the object's filename. It's rather likely for a script to have the following line of code. obj.title = obj.metadata[M_TITLE]; NOTE: this does not happen automatically, remember to explicitely set the obj.title property of every created object. Some coding suggestions: It is _highly recommended_ to always create a copy of the 'orig' object and work with the copy instead of modifying the orig object itself. Future releases will allow cascading scripts and building the logic out of any number of scripts combined. Adhering to this rule will - make the code easier to comprehend and be more modular and decoupled - minimize the risk of any interference between different scripts executed in one symbol space. Unless you have a REAL reason not to do so, always work with a copy. NOTE: if your concern is performance - you are optimizing at the wrong place, the bottleneck is definitely NOT JavaScript. BTW, some of you probably have thought, why the object passed to JavaScript has the variable name 'orig'. Wouldn't something like 'obj' be more natural? I've allowed myself to do it on purpose to signal that the object behind 'orig' has a special meaning of being the _original_ unchanged version with properties set to the values collected by media detectors. This object should be treated as a _prototype_ of the objects to create. Here is the 'right' way to add several objects in one script: var obj; // creating copy obj = copyObject(orig); obj.title = obj.meta[M_TITLE]; // REMEMBER to set obj.title explicitely :) // set further obj properties.... // add the parent container(s).... obj.parentID = ... addCdsObject(obj); // creating another copy obj = copyObject(orig); obj.title = obj.meta[M_TITLE]; // and again... // set further obj properties.... // add the parent container(s).... obj.parentID = ... addCdsObject(obj); /* copyObject is a javascript function, see import.js */ ----------------------------------------- Virtual object engine reference. Content directory service Object properties. If given an object instance 'obj', following properties can/must/will be defined. Properties marked as 'REQUIRED' are required to be defined before passing the object as an argument to the addCdsObject() function. --- Common object properties --- obj.objectType : INTEGER, REQUIRED This should be set to one of the predefined constants: OBJECT_TYPE_ITEM, OBJECT_TYPE_CONTAINER OBJECT_TYPE_ACTIVE_ITEM OBJECT_TYPE_ITEM_EXTERNAL_URL obj.id : STRING, the 'orig' object will have this property set, but it is ignored by the addCdsObject() function. Only automatic ID generation is supported. obj.title : STRING, REQUIRED This is the dispay title of the object, an arbitrary but not empty string obj.parentID : STRING, REQUIRED This must be set because the engine must know the parent container of the object to be added. obj.restricted : BOOLEAN See the UPnP specs obj.class : STRING See the UPnP specs. In addCdsObject this property is set to default value if omited. obj.location : STRING, REQUIRED Denotes the file path in the file system. obj.meta : OBJECT, object storing key => value pairs of metadata, see below for more details. --- Item specific properties --- obj.mimetype : STRING, REQUIRED mime type of the data --- Active Item specific properties --- obj.action : STRING (active items not documented yet) obj.state : STRING (active items not documented yet) --- Container specific properties --- obj.searchable : BOOLEAN See UPnP specs. Mediatomb currently does not use this flag in any way, but may be set and will be properly displayed to the devices. obj.updateID : INTEGER See UPnP specs, it is NOT recommended to set this property manually. Update id's should be handeled automatically. ............. NOTE: It is legal to set an object's property with any name. (because it s a regular JavaScript object), but only the fixed set of properties described above will be checked during addCdsObject, ANY other properties will be ignored. Metadata keys --------------- Constant Value M_ALBUM "upnp:album" M_ARTIST "upnp:artist" M_DESCRIPTION "dc:description" M_DATE: "dc:date" M_GENRE "upnp:genre" M_TITLE "dc:title" NOTE: Current implementation ignores any metadata keys except of the listed above when passing the containing object to the addCdsObject() function. This behaviour might be changed in future to allow scripts to set metadata keys not known to the server and have the server handle them correctly without knowing their semantics. Native functions ------------- JavaScript has a lot of predefined functions and the SpiderMonkey JavaScript implementation includes all the core classes of JavaScript like Date, RegExp, etc. Beside that the server implements a small number of custom native functions free to use from JavaScript. addCdsObject(obj) : adds the given object to the database, returns the objectID of the newly created object. This function is the key to the virtual object engine. print(msg) : prints the message to the stdout, should be used for debugging purposes only. As you see the list is small, and right now there are NO plans to extend it. Keeping the server's JavaScript to look as close to 'pure' JavaScript has it's benefits. Most time the scripts will manipulate strings and JavaScript is good enough at it without any enhancements. Our Idea is - anything that is possible to be written in pure JavaScript should be written in JavaScript, unless it would lead to significant performance degradation. If you think this list is missing something please don't hesitate to let us know, it is easy to extend. Further directions -------------------- I would suggest looking at the javascript files included into the package. (currently only one - $PREFIX/share/mediatomb/js/import.js) That's probably the shortest way to your first very own custom virtual container layout.