Media Indexer

The Media Indexer automatically stores and maintains information about all device audio and video media. This information is kept in the device's resident db8 JSON database. Using API calls provided with Palm's JavaScript Foundation libraries for accessing the db8 service (com.palm.db), 3rd party applications can read (but not write) media information organized into the following categories:
- Albums
- Album images
- Artists
- Audio files
- Genres - For example: country, blues, reggae, etc. Each media file has a genre field and the Media Indexer keeps track of genre totals.
- Images
- Playlists - Organized lists of audio files.
- Video files
Accessing media data is granted only after the user has indicated your app has permission to do so.
In this section:
- Accessing Media Indexer Data
- Media Indexer Data Types and Kinds
- Using the Code Samples
- Getting Permission to Access Media Data
Accessing Media Indexer Data
The Media Indexer keeps device media information in db8 database storage as JSON data objects. db8 is an addition to the webOS JavaScript Framework's current storage methods designed to meet the needs of robust, high-performance applications. Though not a database itself, it is a service (com.palm.db) available on the device bus that interfaces to an embedded database. Javascript applications can use API calls provided with the JavaScript Foundation libraries to interface with the db8 service.
JSON is a lightweight data-interchange text format based on a subset of the JavaScript programming language that is easy for humans to read and write and for machines to parse and generate. Like XML, JSON contains name/value pair collections and ordered list of values (i.e., arrays).
For more information on JSON, see the following websites:
- JSON objects, values and format—http://www.json.org/
- JSON schemas—http://tools.ietf.org/html/draft-zyp-json-schema-02
A primer on how JSON data objects are formatted is beyond the scope of this document - consult the two links above for more information. However, in brief:
- Curly brackets ('{', '}') are used to enclose objects.
- Angle brackets ('[', ']') are used to enclose arrays.
- Colons (':') are used as delimiters in name/value pairs.
- Quotes (") are used for string values. Numeric values are not quoted.
Media Indexer Data Types and Kinds
The schemas below detail the layout of media JSON data objects; 3rd party applications can access this data using the db8 JavaScript wrapper provided with Palm's JavaScript Foundation libraries or with the serviceRequest
call that directly accesses the db8 service—com.palm.db8
. See the db8 documentation for detailed information on including and using these calls in your JavaScript code. Examples of db8 JavaScript calls are provided with each of the data type schemas detailed below.
For each data object, you need to know the name of its kind. Kind objects in db8 define the indexes and access control for stored JSON data objects. You must specify the kind when accessing data objects of that kind (see the example db8 queries for the schemas).
The Media Indexer has the following data objects and kinds. Note that the kind names are appended with a version number (i.e., ":1").
Data Type | Kind |
albumimage | com.palm.media.image.album:1 |
album | com.palm.media.audio.album:1 |
artist | com.palm.media.audio.artist:1 |
audio file | com.palm.media.audio.audio.file:1 |
genre | com.palm.media.audio.genre:1 |
image | com.palm.media.image.file:1 |
playlist | com.palm.media.audio.playlist.object:1 |
thumbnail | |
video file | com.palm.media.audio.videofile:1 |
NOTES
-
When used, kind fields must be enclosed in quotes ("), i.e., "audiofile:1".
-
The example db8 JavaScript calls shown in the documentation below use a Foundation Library construct known as a "future", which is a kind of asynchronous callback.
-
The schemas below do not include the "_id", "_rev" and "_kind" fields that are automatically assigned to each data object once it is stored. If you retrieve data objects in their entirety, you will see these fields. See the db8 documentation for information about these special fields and how they are used.
Using the Code Samples
As mentioned earlier, media data is kept in the device's resident db8 JSON database. The code samples use API calls provided with Palm's JavaScript Foundation libraries for accessing the db8 service (com.palm.db
). Foundations is a loadable framework that both Mojo and JavaScript service applications can use.
To use Foundations in your code:
-
Include the following two script tags in your app's "Index.html" file:
<script src="/usr/palm/frameworks/mojo/mojo.js" type="text/javascript" x-mojo-version="1"></script> <script src="/usr/palm/frameworks/mojoloader.js" type="text/javascript"></script>
- Load and reference foundations in your JavaScript:
var libraries = MojoLoader.require({ name: "foundations", version: "1.0" }); var DB = libraries["foundations"].Data.DB; // db8 JS wrapper API calls var Future = libraries["foundations"].Control.Future; // Future - async callbacks for db8 wrapper calls
Alternatively, you can use the "serviceRequest" function to access the db8 service. See the db8 Service API for more information.
albumimage
Schema
{
"path" : string,
"name" : string,
"sortKey" : string,
"thumbnails" : thumbnail array
"total" : {
"images" : int
}
"modifiedTime": long
}
Elements
Element | Required | Type | Description |
---|---|---|---|
path | Yes | string | Path to directory on disk. |
name | Yes | string | Display name for albums (local albums start off as folder name on disk). |
sortKey | Yes | string | Used for correct sorting with priority. |
thumbnails | Yes | thumbnail array | A pre-populated array of up to three thumbnails to use as previews pulled from the first images of the album. |
total | Yes | inline object, see element below | Totals |
total.images | Yes | int | The total number of images contained in this album. |
modifiedTime | Yes | long | The last time the album was updated in milliseconds since the epoch (Jan 1, Midnight, 1970). |
Example JavaScript db8 find
var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls
//** Construct query, specifying fields to retrieve and kind
var fquery = { "from":"com.palm.media.image.album:1" };
DB.find(fquery, false, false).then(function(future) { // Get data, no watch, no count
var result = future.result;
if (result.returnValue == true) // Success
{
Mojo.Log.info("Success: Album images= "+JSON.stringify(result.results));
}
else // Failure
{
result = future.exception;
Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message);
}
});
Example Output
Success: Album images= [
{
"_id":"2+5a",
"_kind":"com.palm.media.image.album:1",
"_rev":1402,
"modifiedTime":1236702265000,
"name":"Wallpapers",
"path":"/media/internal/wallpapers",
"searchKey":"Wallpapers",
"sortKey":"900_Wallpapers",
"thumbnails":[
{
"_id":"2+Jb",
"data":{
"length":3717,
"offset":330,
"path":"/media/internal/wallpapers/04.jpg"
},
"type":"embedded"
},
{
"_id":"2+Jd",
"data":{
"length":0,
"offset":0,
"path":"/media/internal/wallpapers/05.jpg"
},
"type":"embedded"
},
{
"_id":"2+J_",
"data":{
"length":0,
"offset":0,
"path":"/media/internal/wallpapers/11.jpg"
},
"type":"embedded"
}
],
"total":{
"images":12
}
}
album
Schema
{
"name" : string,
"total" : {
"tracks" : int
},
"artist" : string,
"thumbnails" : thumbnail array
}
Elements
Element | Required | Type | Description |
---|---|---|---|
name | Yes | string | Album name. |
total | Yes | inline object | See element below. |
total.tracks | Yes | int | Total number of tracks on album. |
artist | Yes | string | Album artist. |
thumbnails | Yes | thumbnail array | Thumbnails for album. |
Example JavaScript db8 find
var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls
//** Construct query, specifying fields to retrieve and kind
var fquery = {"select" : ["name", "artist", "total.tracks"], "from":"com.palm.media.audio.album:1" };
DB.find(fquery, false, false).then(function(future) { // Get data, no watch, no count
var result = future.result;
if (result.returnValue == true) // Success
{
var albums = result.results;
var i = 0;
while (albums[i] != null)
Mojo.Log.info("Album name: "+albums[i].name+ ", Artist: "+ albums[i].artist + ", #tracks="+albums[i++].total.tracks);
}
else // Failure
{
result = future.exception;
Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message);
}
});
Example Output
Album name: Beethoven: Symphonies Nos. 5 & 9 "Choral"; Piano Concerto No. 5 "Emperor" Disc 1, Artist: Ludwig van Beethoven, composer. Seattle Symphony. Gerard Schwarz, director, #tracks=1
Album name: Speakin' Out, Artist: Marc Seales, composer. New Stories. Ernie Watts, saxophone., #tracks=1
artist
Schema
{
"name" : string,
"total" : {
"tracks" : int,
"albums" : int
},
"thumbnails" : thumbnail array
}
Elements
Element | Required | Type | Description |
---|---|---|---|
name | Yes | string | Artist name. |
total | Yes | inline object | See two elements below. |
total.tracks | Yes | int | Total number of the artist's audio tracks on the device. |
total.albums | Yes | int | Total number of the artist's audio albums on the device. |
thumbnail | Yes | thumbnail array | Thumbnails for artist. |
Example JavaScript db8 find
var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls
//** Construct query, specifying fields to retrieve and kind
var fquery = { "select" : ["name", "total.tracks", "total.albums"], "from":"com.palm.media.audio.artist:1" };
DB.find(fquery, false, false).then(function(future) { // Get data, no watch, no count
var result = future.result;
if (result.returnValue == true) // Success
{
var artists = result.results;
var i = 0;
while (artists[i] != null)
Mojo.Log.info("Artist name: "+artists[i].name+ ", #tracks = "+artists[i].total.tracks+", #albums="+ artists[i++].total.albums);
}
else // Failure
{
result = future.exception;
Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message);
}
});
Example Output
Artist name: Ludwig van Beethoven, composer. Seattle Symphony. Gerard Schwarz, director, #tracks = 1, #albums=1
Artist name: Marc Seales, composer. New Stories. Ernie Watts, saxophone., #tracks = 1, #albums=1
Artist name: Elvis Presley, #tracks = 2, #albums=10
audio file
Schema
{
"title" : string,
"path" : string,
"createdTime" : float,
"size" : int,
"duration" : int,
"track" : {
"position" : int,
"total" : int
}
"disc" : {
"position" : int,
"total" : int
}
"artist" : string,
"album" : string,
"genre" : string,
"isRingtone" : boolean,
"thumbnails" : thumbnail array,
}
Elements
Element | Required | Type | Description |
---|---|---|---|
title | Yes | string | Song title. |
path | Yes | string | Song path. |
createdTime | Yes | float | The time this song was created, expressed in seconds elapsed since midnight on January 1, 1970 (epoch). |
size | Yes | int | File size in bytes. |
duration | Yes | int | File duration in seconds. |
track | Yes | inline object | See two elements below. |
track.position | Yes | int | File's track number. |
track.total | Yes | int | Number of tracks on file's album. |
disc | Yes | inline object | See two elements below. |
disc.position | Yes | int | File's position on disc. |
disc.total | Yes | int | How many discs this file is on. |
artist | Yes | string | Song artist. |
album | Yes | string | Song album. |
genre | Yes | string | Song genre, i.e., country, blues, etc. |
isRingtone | Yes | boolean | Is song a ringtone flag. |
thumbnails | Yes | thumbnail array | Song thumbnails. |
Example JavaScript db8 find
var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls
//** Construct query, specifying fields to retrieve and kind
var fquery = { "select" : ["title", "path", "created", "size", "duration", "artist", "album", "genre", "isRingtone" ], "from":"com.palm.media.audio.file:1"};
DB.find(fquery, false, false).then(function(future) { // Get data, no watch, no count
var result = future.result;
if (result.returnValue == true) // Success
{
var audiofiles = result.results;
var i = 0;
while (audiofiles[i] != null)
{
Mojo.Log.info("title: "+audiofiles[i].title+ ", path: "+ audiofiles[i].path + ", created: "+audiofiles[i].createdTime+", size: "+ audiofiles[i].size);
Mojo.Log.info("duration: "+audiofiles[i].duration+ ", artist: "+ audiofiles[i].artist + ", album: "+audiofiles[i].album+", genre: "+ audiofiles[i].genre+", isRingtone: "+ audiofiles[i++].isRingtone);
}
}
else
{
result = future.exception;
Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message);
}
});
Example Output
title: Anticipation (short), path: /media/internal/ringtones/Anticipation (short).mp3, created: undefined, size: 37990,
duration: 0, artist: Palm, Inc., album: webOS Alert Sounds, genre: Alert Sounds, isRingtone: true
title: Dulcimer (short), path: /media/internal/ringtones/Dulcimer (short).mp3, created: undefined, size: 45101,
duration: 0, artist: Palm, Inc., album: webOS Alert Sounds, genre: Alert Sounds, isRingtone: true
title: Dulcimer, path: /media/internal/ringtones/Dulcimer.mp3, created: undefined, size: 1308978
duration: 0, artist: Palm, Inc., album: Pre Ringtones, genre: Ringtones, isRingtone: true
title: Rain Dance (short), path: /media/internal/ringtones/Rain Dance (short).mp3, created: undefined, size: 49047, duration: 0, artist: Palm, Inc., album: webOS Alert Sounds, genre: Alert Sounds, isRingtone: true
title: Symphony No. 9 (Scherzo), path: /media/internal/DCIM/100PALM/01 Symphony No. 9 (Scherzo).m4a, created: undefined, size: 2201304
duration: 75.72, artist: Ludwig van Beethoven, composer. Seattle Symphony. Gerard Schwarz, director, album: Beethoven: Symphonies Nos. 5 & 9 "Choral"; Piano Concerto No. 5 "Emperor" Disc 1, genre: Classical, isRingtone: false
title: "Highway Blues", path: /media/internal/DCIM/100PALM/01 _Highway Blues_.m4a, created: undefined, size: 2976455,
duration: 93.65, artist: Marc Seales, composer. New Stories. Ernie Watts, saxophone., album: Speakin' Out, genre: Jazz, isRingtone: false
genre
Schema
{
"name" : string,
"total" : {
"tracks" : int,
"albums" : int
}
"thumbnails" : thumbnail array
}
Elements
Element | Required | Type | Description |
---|---|---|---|
name | Yes | string | Genre name. |
total | Yes | inline object | See two elements below. |
total.tracks | Yes | int | The number of tracks on the device by this artist. |
total.albums | Yes | int | The number of albums on the device by this artist. |
thumbnails | No | thumbnail array | Genre's thumbnails. |
Example JavaScript db8 find
var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls
//** Construct query, specifying fields to retrieve and kind
var fquery = { "select" : ["name", "total.tracks", "total.albums"], "from":"com.palm.media.audio.genre:1"};
DB.find(fquery, false, false).then(function(future) { // Get data, no watch, no count
var result = future.result;
if (result.returnValue == true) // Success
{
var genreobjects = result.results;
var i = 0;
while (genreobjects[i] != null)
Mojo.Log.info("Name: "+genreobjects[i].name+ ", #tracks: "+ genreobjects[i].total.tracks + ", #albums="+genreobjects[i++].total.albums);
}
else
{
result = future.exception;
Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message);
}
});
Example Output
Name: Classical, #tracks: 1, #albums=1
Name: Jazz, #tracks: 1, #albums=1
image
Schema
{
"path" : string,
"created" : int,
"albumId" : string,
"thumbnails" : thumbnail array
}
Elements
Element | Required | Type | Description |
---|---|---|---|
path | Yes | string | Path to file on disk. |
created | Yes | int | The metadata information for the created time in seconds. |
albumId | Yes | string | The ID of the image's album. |
thumbnails | No | thumbnail array | Thumbnails for this image. |
Example JavaScript db8 find
var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls
var fquery = { "from":"com.palm.media.image.file:1" };
DB.find(fquery, false, false).then(function(future) { // Get data, no watch, no count
var result = future.result;
if (result.returnValue == true) // Success
{
Mojo.Log.info("Success: Images= "+JSON.stringify(result.results));
}
else // Failure
{
result = future.exception;
Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message);
}
});
Example Output
Success: Images= [
{
"_id":"2+4Q",
"_kind":"com.palm.media.image.file:1",
"_rev":433,
"albumId":"2+5a",
"albumPath":"/media/internal/wallpapers",
"createdTime":0,
"path":"/media/internal/wallpapers/06.jpg",
"thumbnails":[
{
"_id":"2+4R",
"data":{
"length":0,
"offset":0,
"path":"/media/internal/wallpapers/06.jpg"
},
"type":"embedded"
}
]
},
{
"_id":"2+4_",
"_kind":"com.palm.media.image.file:1",
"_rev":438,
"albumId":"2+5a",
"albumPath":"/media/internal/wallpapers",
"createdTime":0,
"path":"/media/internal/wallpapers/07.jpg",
"thumbnails":[
{
"_id":"2+4a",
"data":{
"length":0,
"offset":0,
"path":"/media/internal/wallpapers/07.jpg"
},
"type":"embedded"
}
]
},
{
"_id":"2+4d",
"_kind":"com.palm.media.image.file:1",
"_rev":440,
"albumId":"2+5a",
"albumPath":"/media/internal/wallpapers",
"createdTime":0,
"path":"/media/internal/wallpapers/12.jpg",
"thumbnails":[
{
"_id":"2+4e",
"data":{
"length":0,
"offset":0,
"path":"/media/internal/wallpapers/12.jpg"
},
"type":"embedded"
}
]
}
]
playlist
Schema
{
"name" : string,
"songIds" : string array,
"thumbnails" : thumbnail array
}
Elements
Element | Required | Type | Description |
---|---|---|---|
name | Yes | string | Playlist name. Not necessarily unique. |
songIds | Yes | string array | In order array of db8 IDs of audiofile ("com.palm.media.audio.file:1") objects. |
thumbnails | No | thumbnail array | Playlist thumbnails. |
Example JavaScript db8 find
var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls
//** Construct query, specifying fields to retrieve and kind
var fquery = { "select" : ["name", "path", "songIds"], "from":"com.palm.media.playlist.object:1"};
DB.find(fquery, false, true).then(function(future) {
var result = future.result;
if (result.returnValue == true) // Success
{
var playlistobjects = result.results;
var i = 0;
while (playlistobjects[i] != null)
{
Mojo.Log.info("Name: "+playlistobjects[i].name+ ", IDs: "+playlistobjects[i++].songIds);
}
}
else
{
result = future.exception;
Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message);
}
});
Example Output
Name: Beatles, IDs: 2+SN,2+ST,2+SW,2+SV
thumbnail
Schema
{
"type" : string,
"data" : {
"path" : string,
"offset" : int,
"length" : int
}
"cacheEntry" : {
"pathName" : string,
"aspect" : string,
"width" : int,
"height" : int
}
}
Elements
Element | Required | Type | Description |
---|---|---|---|
type | Yes | string | Thumbnail format - "external" or "embedded" (on device). |
data | Yes | inline object | See three fields below. |
data.path | Yes | string | Location on device. |
data.offset | Yes | int | Offset into path where data is contained. |
data.length | Yes | int | Length of data in path (requires offset). |
cacheEntry | Yes | inline object | See four fields below |
cacheEntry.pathName | Yes | string | Path determined from filecache/InsertCacheObject |
cacheEntry.aspect | Yes | string | Aspect used to crop at width/height specified. |
cacheEntry.width | Yes | int | Cache entry width (less than or equal to this value). |
cacheEntry.height | Yes | int | Cache entry height (less than or equal to this value). |
video file
Schema
{
"path" : string,
"capturedOnDevice" : boolean,
"modifiedTime" : float,
"createdTime" : float,
"title" : string,
"size" : int,
"playbackPosition" : int,
"duration" : int,
"description" : string,
"thumbnails" : thumbnail array
}
Elements
Element | Required | Type | Description |
---|---|---|---|
path | Yes | string | Video path. |
capturedOnDevice | Yes | boolean | Was file captured on device flag. |
createdTime | Yes | float | The time this video was created, expressed in seconds since midnight on January 1, 1970 (epoch). |
modifiedTime | Yes | float | The time this video was last modified, expressed in seconds since midnight on January 1, 1970 (epoch). |
title | Yes | string | Video name. |
size | Yes | int | File size in bytes. |
playbackPosition | Yes | int | The last playback position in milliseconds. |
duration | Yes | int | Video duration in milliseconds. |
description | Yes | string | Video description. |
thumbnails | Yes | thumbnail array | Video thumbnails. |
Example JavaScript db8 find
var DB = libraries["foundations"].Data.DB; // Get JS wrapper for DB calls
//** Construct query, specifying fields to retrieve and kind
var fquery = { "select" : ["path", "modifiedTime", "createdTime", "title", "size", "playbackPosition", "duration", "description"], "from":"com.palm.media.video.file:1"};
DB.find(fquery, false, false).then(function(future) { // Get data, no watch, no count
var result = future.result;
if (result.returnValue == true) // Success
{
var videofiles = result.results;
var i = 0;
while (videofiles[i] != null)
{
Mojo.Log.info("Path: "+videofiles[i].path+ ", Modified: "+ videofiles[i].modifiedTime+", Created: "+videofiles[i].createdTime + ", Title: "+videofiles[i].title);
Mojo.Log.info("Size: "+videofiles[i].size+ ", Playback Position: "+ videofiles[i].playbackPosition+", Duration: "+videofiles[i].duration + ", Description: "+videofiles[i++].description);
}
}
else
{
result = future.exception;
Mojo.Log.info("find failure: Err code=" + result.errorCode + "Err message=" + result.message);
}
});
Example Output
Path: /media/internal/demo.mpg, Modified: 1276805542, Created: 1267477942, Title: Palm Pre Demo
Size: 2000000, Playback Position: 30000, Duration: 3000000, Description: Demo of Palm Pre features and how to use them
Path: /media/internal/HowToEmail.avi, Modified: 1275855932, Created: 1262381132, Title: How to send email
Size: 1000000, Playback Position: 7890399, Duration: 180000000, Description: Demo of how to send email from a Palm Pre
Getting Permission to Access Media Data
Unless you are the owner, the db8 service, by default, denies application and service access to all stored data objects. Read-only access to db8 data is granted through the "com.palm.mediapermissions" service. Currently, this service provides the following API.
request
Your app can use this API to request access to one or more db8 kinds and their stored data objects. If the caller is new to the media permissions service, a dialog box is displayed to the user asking if access is ok for this app. Once the user responds, the caller is notified with the verdict - either the app has complete access or none at all. At the moment, it is not possible for the user to grant limited or partial access or deny. The response is then stored in the database for future reference. This cached response is used in case repeated requests for access are made so the user is not disturbed.
Note that granted permissions can become invalid after inactivity or application removal. There is no guaranteed permissions duration, though it is unlikely permissions would be revoked immediately after being granted. A typical solution is to attempt access during application start and, if denied, make a request call to prompt the user before continuing.
Schema
{
"rights": {
"read": string array
}
}
Elements
Element | Required | Type | Description |
---|---|---|---|
rights | Yes | inline object | See element below |
rights.read | Yes | string array | db8 kinds you want read-only access for |
Returns
{
"returnValue" : boolean,
"isAllowed" : boolean,
"reason" : string
}
Elements
Element | Required | Type | Description |
---|---|---|---|
returnValue | Yes | boolean | Service call success (true) or failure (false) |
isAllowed | Yes | boolean | If true, rights are granted. |
reason | No | string | If "isAllowed" is false, reason for denial. |
Example
var self = this;
var imageKind = "com.palm.media.image.file:1";
var albumKind = "com.palm.media.image.album:1";
function requestPermission(done) {
self.controller.serviceRequest('palm://com.palm.mediapermissions', {
method: 'request',
parameters: {
rights: {
read: [imageKind, albumKind]
}
},
onComplete: function(response) {
if (response.returnValue && response.isAllowed) {
Mojo.Log.info('Got permissions okay!');
done();
} else {
Mojo.Log.error('Failed to get permissions!');
}
}
});
}
function checkPermissions(done) {
self.controller.serviceRequest('palm://com.palm.db', {
method: 'find',
parameters: {
query: {
from: imageKind,
limit: 1
}
},
onSuccess: function() {
Mojo.Log.info('We have permissions.');
done();
},
onFailure: function() {
Mojo.Log.info('We do not have permission, asking.');
requestPermission(done);
}
});
}
checkPermissions(function continueToRunApp() {
// we're running good now!
});