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:

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

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:

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:

  1. 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>
    
  2. 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!  
});