#LyX 1.4.3 created this file. For more info see http://www.lyx.org/
\lyxformat 245
\begin_document
\begin_header
\textclass docbook
\language english
\inputencoding auto
\fontscheme default
\graphics default
\paperfontsize default
\papersize default
\use_geometry false
\use_amsmath 0
\cite_engine basic
\use_bibtopic false
\paperorientation portrait
\secnumdepth 3
\tocdepth 3
\paragraph_separation indent
\defskip medskip
\quotes_language english
\papercolumns 1
\papersides 1
\paperpagestyle default
\tracking_changes false
\output_changes true
\end_header
\begin_body
\begin_layout Title
MediaTomb Scripting
\end_layout
\begin_layout Section
Introduction
\end_layout
\begin_layout Standard
MediaTomb allows you to customize the structure of how your media is being
presented to your renderer.
One of the most important features introduced since the version 0.8 are
the virtual containers and virtual items.
Let's think of possible scenarios:
\end_layout
\begin_layout Itemize
you may want to separate your content by music, photo, video, maybe create
a special container with all non playable stuff
\end_layout
\begin_layout Itemize
you may want your music to be sorted by genre, year, artist, album, or maybe
by starting letters, so you can more easily find your favorite song when
browsing the server
\end_layout
\begin_layout Itemize
you want to have your photos that you took with your favorite digital camera
to appear in a special folder, or maybe you even want to separate the photos
that you took with flash-on from the ones that you made without flash
\end_layout
\begin_layout Itemize
your media player does not support video, so you do not even want to see
the Video container
\end_layout
\begin_layout Itemize
it's up to your imagination :)
\end_layout
\begin_layout Standard
The scenarios described above and much more can be achieved with the help
of an import script.
\end_layout
\begin_layout Section
How It Works
\end_layout
\begin_layout Standard
This section will give you some overview on how virtual objects work and
on how they are related to scripting.
\end_layout
\begin_layout Subsection
Understanding Virtual Objects.
\end_layout
\begin_layout Standard
When you add a file or directory to the database via the web interface several
things happen.
\end_layout
\begin_layout Enumerate
The object is inserted into the PC Directory.
PC Directory is simply a special non-removable container.
Any media file added will have an entry inside the PC Directory tree.
PC Directory's hierarchy reflects the filesystem hierarchy, all objects
inside the PC Directory including itself are NON-VIRTUAL objects.
All virtual objects may have a different title, descripting, etc., but they
are still references to objects in the PC-Directory.
That's why it is not possible to change a location of a virtual object
- the only exceptions are URL items and Active items.
\end_layout
\begin_layout Enumerate
Once an item is added to the PC Directory it is forwarded to the virtual
object engine.
The virtual object engine's mission is to organize and present the media
database in a logical hierarchy based on the available metadata of the
items.
\end_layout
\begin_layout Standard
Each UPnP server implements this so called virtual object hierarchy in a
different way.
Audio files are usually sorted by artist, album, some servers may just
present a view similar to the filesystem and so on.
Most servers have strong limitations on the structure of the virtual containers
, they usually offer a predefined layout of data and the user has to live
with it.
In MediaTomb we try to address this shortcoming by introducing the scriptable
virtual object engine.
It is designed to be:
\end_layout
\begin_layout Itemize
maximally flexible
\end_layout
\begin_layout Itemize
easily customizable and extendable
\end_layout
\begin_layout Itemize
robust and efficient
\end_layout
\begin_layout Standard
We try to achieve these goals by embedding a scripting runtime environment
that allows the execution of ECMAScript-262 conform scripts better known
as JavaScript.
We are using Mozilla's JavaScript implementation called SpiderMonkey, it
is a stand-alone easily embeddable javascript engine, supporting JavaScript
versions 1.0 through 1.4.
\end_layout
\begin_layout Subsection
Theory Of Operation
\end_layout
\begin_layout Standard
After an item is added to the PC Directory it is automatically fed as input
to the import script.
The script then creates one or more virtual items for the given original
item.
Items created from scripts are always marked virtual.
\end_layout
\begin_layout Standard
When the virtual object engine gets notified of an added item, following
happens: a javascript object is created mirroring the properties of the
item.
The object is introduced to the script environment and bound to the predefined
variable 'orig'.
This way a variable orig is always defined for every script invocation
and represents the original data of the added item.
Then the script is invoked.
\end_layout
\begin_layout Standard
In the current implementation, if you modify the script then you will have
to restart the server for the new logic to take effect.
Note, that the script is only triggered when new objects are added to the
database, also note that the script does not modify any objects that already
exist in the database - it only processes new objects that are being added.
\end_layout
\begin_layout Section
The Import Script
\end_layout
\begin_layout Standard
In this section we will introduce the properties of the object that will
be processed by the script, as well as functions that are offered by the
server.
\end_layout
\begin_layout Subsection
Global Variables And Constants
\end_layout
\begin_layout Subsubsection
The 'orig' Object
\end_layout
\begin_layout Standard
As described in Section 2.2, each time an item is added to the database the
import script is invoked.
So, one script invocation processes exactly one non virtual item, and creates
a number of virtual items and containers.
The original item is made available in the form of the global variable
'orig'.
It is usually a good idea to only read from this variable and to create
and only modify local copies.
\end_layout
\begin_layout Standard
Here is a list of properties of an object, you can set them you create a
new object or when you modify a copy of the 'orig' object.
\end_layout
\begin_layout Standard
\emph on
RW
\emph default
means read/write, i.e.
- changes made to that property will be transferred into the database.
\end_layout
\begin_layout Standard
\emph on
RO
\emph default
means, that this is a readonly property, any changes made to it will get
lost.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.objectType
\end_layout
\begin_layout Standard
\emph on
RW
\end_layout
\begin_layout Standard
This defines the object type, following types are available:
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
OBJECT_TYPE_CONTAINER
\end_layout
\begin_layout Standard
Object is a container.
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
OBJECT_TYPE_ITEM
\end_layout
\begin_layout Standard
Object is an item.
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
OBJECT_TYPE_ACTIVE_ITEM
\end_layout
\begin_layout Standard
Object is an active item.
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
OBJECT_TYPE_ITEM_EXTERNAL_URL
\end_layout
\begin_layout Standard
Object is a link to a resouce on the internet.
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
OBJECT_TYPE_ITEM_INTERNAL_URL
\end_layout
\begin_layout Standard
Object is an internal link.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.title
\end_layout
\begin_layout Standard
\family typewriter
\emph on
RW
\end_layout
\begin_layout Standard
This is the title of the original object, since the object represents an
entry in the PC-Directory, the title will be set to it's filename.
This field corresponds to dc:title in the DIDL-Lite XML.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.id
\end_layout
\begin_layout Standard
\family typewriter
\emph on
RO
\end_layout
\begin_layout Standard
The object ID, make sure to set all refID's (reference IDs) of your virtual
objects to that ID.
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.parentID
\end_layout
\begin_layout Standard
\family typewriter
\emph on
RO
\end_layout
\begin_layout Standard
The object ID of the parent container.
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.class
\end_layout
\begin_layout Standard
\family typewriter
\emph on
RW
\end_layout
\begin_layout Standard
The upnp class of the item, this corresponds to upnp:class in the DIDL-Lite
XML.
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.location
\end_layout
\begin_layout Standard
\family typewriter
\emph on
RO
\end_layout
\begin_layout Standard
Location on disk, given by the absolute path and filename.
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.mimetype
\end_layout
\begin_layout Standard
\family typewriter
\emph on
RW
\end_layout
\begin_layout Standard
Mimetype of the object.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.meta
\end_layout
\begin_layout Standard
\family typewriter
\emph on
RW
\end_layout
\begin_layout Standard
Array holding the metadata that was extracted from the object (i.e.
id3/exif/etc.
information)
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.meta[M_TITLE]
\end_layout
\begin_layout Standard
\family typewriter
\emph on
RW
\end_layout
\begin_layout Standard
Extracted title (for example the id3 title if the object is an mp3 file),
if you want that your new virtual object is displayed under this title
you will have to set obj.title = orig.meta[M_TITLE]
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.meta[M_ARTIST]
\end_layout
\begin_layout Standard
\emph on
RW
\end_layout
\begin_layout Standard
Artist information, this correponds to upnp:artist in the DIDL-Lite XML.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.meta[M_ALBUM]
\end_layout
\begin_layout Standard
\family typewriter
\emph on
RW
\end_layout
\begin_layout Standard
Album information, this corresponds to upnp:album in the DIDL-Lite XML.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.meta[M_DATE]
\end_layout
\begin_layout Standard
\emph on
RW
\end_layout
\begin_layout Standard
Date, must be in the format of YYYY-MM-DD (required by the UPnP spec), this
corresponds to dc:date in the DIDL-Lite XML.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.meta[M_GENRE]
\end_layout
\begin_layout Standard
\family typewriter
\emph on
RW
\end_layout
\begin_layout Standard
Genre of the item, this corresponds to upnp:genre in the DIDL-Lite XML.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.meta[M_DESCRIPTION]
\end_layout
\begin_layout Standard
\emph on
RW
\end_layout
\begin_layout Standard
Description of the item, this corresponds to dc:description in the DIDL-Lite
XML.
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.meta[M_TRACKNUMBER]
\end_layout
\begin_layout Standard
\emph on
RW
\end_layout
\begin_layout Standard
Track number of the item, this corresponds to upnp:originalTrackNumber in
the DIDL-Lite XML.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
orig.aux
\end_layout
\begin_layout Standard
\emph on
RO
\end_layout
\begin_layout Standard
Array holding the so called auxilary data.
Aux data is metadata that is not part of UPnP, for example - this can be
a camera model that was used to make a photo, or the information if the
photo was taken with or without flash.
Currently aux data can be gathered from libexif and libextractor (see the
Import section in the main documentation for more details).
So, this array will hold the tags that you specified in your config.xml,
allowing you to create your virtual structure according to your liking.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Subsubsection
Constants
\end_layout
\begin_layout Standard
Actually there are no such things as constants in JS, so those are actually
predefined global variables that are set during JS engine initialization.
Do not assign any values to them, otherwise following script invocation
will be using wrong values.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
UPNP_CLASS_CONTAINER
\end_layout
\begin_layout Standard
\emph on
Type: string
\end_layout
\begin_layout Standard
\emph on
Value: object.container
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
UPNP_CLASS_CONTAINER_MUSIC
\end_layout
\begin_layout Standard
\emph on
Type: string
\end_layout
\begin_layout Standard
\emph on
Value: object.container.musicContainer
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
UPNP_CLASS_CONTAINER_MUSIC_ARTIST
\end_layout
\begin_layout Standard
\emph on
Type: string
\end_layout
\begin_layout Standard
\emph on
Value: object.container.person.musicArtist
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
UPNP_CLASS_CONTINAER_MUSIC_GENRE
\end_layout
\begin_layout Standard
\emph on
Type: string
\end_layout
\begin_layout Standard
\emph on
Value: object.container.genre.musicGenre
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
UPNP_CLASS_CONTAINER_MUSIC_ALBUM
\end_layout
\begin_layout Standard
\emph on
Type: string
\end_layout
\begin_layout Standard
\emph on
Value: object.container.album.musicAlbum
\end_layout
\begin_layout Description
Note: this container class will be treaded by the server in a special way,
all music items in this container will be sorted by ID3 track number.
\end_layout
\begin_layout Standard
\begin_inset ERT
status collapsed
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
UPNP_CLASS_ITEM
\end_layout
\begin_layout Standard
\emph on
Type: string
\end_layout
\begin_layout Standard
\emph on
Value: object.item
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
UPNP_CLASS_ITEM_MUSIC_TRACK
\end_layout
\begin_layout Standard
\emph on
Type: string
\end_layout
\begin_layout Standard
\emph on
Value: object.item.audioItem.musicTrack
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
OBJECT_TYPE_CONTAINER
\end_layout
\begin_layout Standard
\emph on
Type: integer
\end_layout
\begin_layout Standard
\emph on
Value: 1
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
OBJECT_TYPE_ITEM
\end_layout
\begin_layout Standard
\emph on
Type: integer
\end_layout
\begin_layout Standard
\emph on
Value: 2
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
OBJECT_TYPE_ACTIVE_ITEM
\end_layout
\begin_layout Standard
\emph on
Type: integer
\end_layout
\begin_layout Standard
\emph on
Value: 4
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
OBJECT_TYPE_ITEM_EXTERNAL_URL
\end_layout
\begin_layout Standard
\emph on
Type: integer
\end_layout
\begin_layout Standard
\emph on
Value: 8
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
OBJECT_TYPE_ITEM_INTERNAL_URL
\end_layout
\begin_layout Standard
\emph on
Type: integer
\end_layout
\begin_layout Standard
\emph on
Value: 16
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Subsection
Available Functions
\end_layout
\begin_layout Standard
This section will introduce the functions that you can use in order to add
your objects to the database.
Some functions are offered by the server, and some helper functions are
defined in your import script.
\end_layout
\begin_layout Subsubsection
Server Functions
\end_layout
\begin_layout Standard
The server offers three functions which can be called from within the import
script:
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
addCdsObject(object, containerChain, lastContainerClass);
\end_layout
\begin_layout Standard
This function adds a virtual object to the server database, the path in
the database is defined by the containerChain parameter.
The third argument is optional, it allows to set the upnp:class of the
last container in the chain.
\end_layout
\begin_layout Standard
Parameters:
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
object
\end_layout
\begin_layout Standard
A virtual object that is either a copy of or a reference to 'orig', see
Section 3.2 for a list of properties.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
containerChain
\end_layout
\begin_layout Standard
A string, defining where the object will be added in the database hierarchy.
The containers in the chain are separated by a slash '/', for example,
a value of '/Audio/All Music' will add the object to the Audio, All Music
container in the server hierarchy.
Make sure to properly escape the slash characters in container names.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
lastContainerClass
\end_layout
\begin_layout Standard
A string, defining the upnp:class of the container that appears last in
the chain.
This parameter can be ommited, in this case the default value 'object.container'
will be taken.
Setting specific upnp container classes is useful to define the special
meaning of a particular container; for example, the server will always
sort songs by track number if upnp class of a container is set to 'object.contai
ner.album.musicAlbum'.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
copyObject(originalObject);
\end_layout
\begin_layout Standard
This function returns a copy of the virtual object.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Code
print(...);
\end_layout
\begin_layout Standard
This function is useful for debugging scripts, it simply prints to the standard
output.
\end_layout
\begin_layout Standard
\begin_inset ERT
status open
\begin_layout Standard
\end_layout
\end_inset
\end_layout
\begin_layout Section
Walkthrough
\end_layout
\begin_layout Standard
Now it is time to take a closer look at the default import script that is
supplied with MediaTomb.
Usually it is installed in the /usr/share/mediatomb/js/import.js directory,
but you will also find it in scripts/js/import.js in the MediaTomb source
tree.
\end_layout
\begin_layout Description
Note: this is not a JavaScript tutorial, if you are new to JS you should
probably make yourself familiar with the language.
\end_layout
\begin_layout Subsection
Helper Functions
\end_layout
\begin_layout Standard
At the beginning of the script we define a couple of helper functions that
we will use later on.
\end_layout
\begin_layout Standard
The first function escapes slash '/' characters in a string.
This is necessary, because the container chain is defined by a slash separated
string, where slash has a special meaning - it defines the container hierarchy.
That means, that slashes that appear in the object's title need to be properly
escaped.
\end_layout
\begin_layout Code
function escapeSlash(name)
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
name = name.replace(/
\backslash
\backslash
/g, "
\backslash
\backslash
\backslash
\backslash
");
\end_layout
\begin_layout Code
name = name.replace(/
\backslash
//g, "
\backslash
\backslash
/");
\end_layout
\begin_layout Code
return name;
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Code
\end_layout
\begin_layout Standard
The following function makes it easier to work with container chains; it
takes an array of container names as argument, makes sure that the names
are properly escaped and adds the slash separators as necessary.
It returns a string that is formatted to be used as a parameter for the
addCdsObject function.
\end_layout
\begin_layout Code
function createContainerChain(arr)
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
var path = ''; for (var i = 0; i < arr.length; i++)
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
path = path + '/' + escapeSlash(arr[i]);
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Code
return path;
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Standard
I just realized, that this may not be what we want...
TODO Jin!!!
\end_layout
\begin_layout Code
function normalizeDate(date)
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
var matches = date.match(/([0-9]+)-01-01/);
\end_layout
\begin_layout Code
if (matches)
\end_layout
\begin_layout Code
return matches[1];
\end_layout
\begin_layout Code
else
\end_layout
\begin_layout Code
return date;
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Standard
Next, let's look at the functions that organize our content in the database
by creating the virtual structure.
Each media type - audio, image and video is handled by a separate function.
\end_layout
\begin_layout Standard
The biggest one is the function that handles audio - the reason is simple:
mp3 files offer a lot of metadata like album, artist, genre, etc.
information, this allows us to create a nice container layout.
\end_layout
\begin_layout Code
function addAudio(obj)
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
var desc = '';
\end_layout
\begin_layout Code
var artist_full;
\end_layout
\begin_layout Code
var album_full;
\end_layout
\begin_layout Standard
First we will gather all the metadata that is provided by our object, of
course it is possible that some fields are empty - we will have to check
that to make sure that we handle this case correctly.
\end_layout
\begin_layout Code
var title = obj.meta[M_TITLE];
\end_layout
\begin_layout Standard
Note the difference between obj.title and obj.meta[M_TITLE] - while object.title
will originally be set to the filename, obj.meta[M_TITLE] will contain the
parsed title - in this particular example the ID3 title of an MP3.
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
if (!title) title = obj.title;
\end_layout
\begin_layout Code
var artist = obj.meta[M_ARTIST];
\end_layout
\begin_layout Code
if (!artist)
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
artist = 'Unknown';
\end_layout
\begin_layout Code
artist_full = null;
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Code
else
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
artist_full = artist;
\end_layout
\begin_layout Code
desc = artist;
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
var album = obj.meta[M_ALBUM];
\end_layout
\begin_layout Code
if (!album)
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
album = 'Unknown';
\end_layout
\begin_layout Code
album_full = null;
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Code
else
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
desc = desc + ', ' + album;
\end_layout
\begin_layout Code
album_full = album;
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
if (desc)
\end_layout
\begin_layout Code
desc = desc + ', ';
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
desc = desc + title;
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
var date = obj.meta[M_DATE];
\end_layout
\begin_layout Code
if (!date)
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
date = 'Unknown';
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Code
else
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
date = normalizeDate(date);
\end_layout
\begin_layout Code
desc = desc + ', ' + date;
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
var genre = obj.meta[M_GENRE];
\end_layout
\begin_layout Code
if (!genre)
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
genre = 'Unknown';
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Code
else
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Code
desc = desc + ', ' + genre;
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
var description = obj.meta[M_DESCRIPTION];
\end_layout
\begin_layout Code
if (!description)
\end_layout
\begin_layout Code
{
\end_layout
\begin_layout Standard
Note how we are setting properties of an object - in this case we put together
a description and we are setting for objects that did not already have
one.
\end_layout
\begin_layout Code
obj.meta[M_DESCRIPTION] = desc;
\end_layout
\begin_layout Code
}
\end_layout
\begin_layout Standard
We finally gathered all data that we need, so let's create a nice layout
for our audio files.
Note how we are constructing the chain, in the line below the array 'chain'
will be converted to 'Audio/All audio' by the createContainerChain() function.
\end_layout
\begin_layout Code
var chain = new Array('Audio', 'All audio');
\end_layout
\begin_layout Code
obj.title = title;
\end_layout
\begin_layout Standard
The UPnP class argument to addCdsObject() is optional, if it is not supplied
the default UPnP class will be used.
However, it is suggested to correctly set UPnP classes of containers and
object - this information may be used by some renderers to identify the
type of the container and present the content in a different manner .
\end_layout
\begin_layout Code
addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC);
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
chain = new Array('Audio', 'Artists', artist, 'All songs');
\end_layout
\begin_layout Code
addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC);
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
chain = new Array('Audio', 'All - full name');
\end_layout
\begin_layout Code
var temp = '';
\end_layout
\begin_layout Code
if (artist_full)
\end_layout
\begin_layout Code
temp = artist_full;
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
if (album_full)
\end_layout
\begin_layout Code
temp = temp + ' - ' + album_full + ' - ';
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
obj.title = temp + title;
\end_layout
\begin_layout Code
\end_layout
\begin_layout Code
addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC);
\end_layout
\begin_layout Code
chain = new Array('Audio', 'Artists', artist, 'All - full name');
addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC);
\end_layout
\begin_layout Code
chain = new Array('Audio', 'Artists', artist, album); obj.title =
track + title; addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CO
NTAINER_MUSIC_ALBUM);
\end_layout
\begin_layout Code
chain = new Array('Audio', 'Albums', album); obj.title = track +
title; addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_
MUSIC_ALBUM);
\end_layout
\begin_layout Code
chain = new Array('Audio', 'Genres', genre); addCdsObject(obj, createCon
tainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_GENRE);
\end_layout
\begin_layout Code
chain = new Array('Audio', 'Year', date); addCdsObject(obj, createContai
nerChain(chain), UPNP_CLASS_CONTAINER_MUSIC); }
\end_layout
\end_body
\end_document