[Media Content] Initial version
authorDongyoung Kim <dydot1.kim@samsung.com>
Mon, 16 Feb 2015 23:52:48 +0000 (08:52 +0900)
committerDongyoung Kim <dydot1.kim@samsung.com>
Mon, 16 Feb 2015 23:52:48 +0000 (08:52 +0900)
Change-Id: Ic4eac077e811bf7fa0d5ac923b228e62003eeb31

12 files changed:
packaging/webapi-plugins.spec [changed mode: 0644->0755]
src/content/content.gyp [new file with mode: 0755]
src/content/content_api.js [new file with mode: 0755]
src/content/content_extension.cc [new file with mode: 0755]
src/content/content_extension.h [new file with mode: 0755]
src/content/content_filter.cc [new file with mode: 0755]
src/content/content_filter.h [new file with mode: 0755]
src/content/content_instance.cc [new file with mode: 0755]
src/content/content_instance.h [new file with mode: 0755]
src/content/content_manager.cc [new file with mode: 0755]
src/content/content_manager.h [new file with mode: 0755]
src/tizen-wrt.gyp [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index ea5203a..460ae76
@@ -186,6 +186,8 @@ BuildRequires: pkgconfig(capi-appfw-application)
 BuildRequires: pkgconfig(capi-appfw-app-manager)
 BuildRequires: pkgconfig(capi-appfw-package-manager)
 BuildRequires: pkgconfig(wrt-plugins-ipc-message)
+BuildRequires: pkgconfig(capi-content-media-content)
+BuildRequires: pkgconfig(capi-media-metadata-extractor)
 
 %if 0%{?tizen_feature_account_support}
 BuildRequires: pkgconfig(accounts-svc)
diff --git a/src/content/content.gyp b/src/content/content.gyp
new file mode 100755 (executable)
index 0000000..26ec742
--- /dev/null
@@ -0,0 +1,32 @@
+{
+  'includes':[
+    '../common/common.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'tizen_content',
+      'type': 'loadable_module',
+      'sources': [
+        'content_api.js',
+        'content_extension.cc',
+        'content_extension.h',
+        'content_instance.cc',
+        'content_instance.h',
+        'content_manager.h',
+        'content_manager.cc',
+      ],
+      'conditions': [
+        ['tizen == 1', {
+          'variables': {
+            'packages': [
+              'capi-content-media-content',
+              'capi-media-metadata-extractor',
+                                     'capi-base-common',
+              'dlog',
+            ]
+          },
+        }],
+      ],
+    },
+  ],
+}
diff --git a/src/content/content_api.js b/src/content/content_api.js
new file mode 100755 (executable)
index 0000000..c173839
--- /dev/null
@@ -0,0 +1,844 @@
+// Content
+
+var validator_ = xwalk.utils.validator;
+var types_ = validator_.Types;
+
+
+var callbackId = 0;
+var callbacks = {};
+
+extension.setMessageListener(function(json) {
+  var result = JSON.parse(json);
+  var callback = callbacks[result['callbackId']];
+  callback(result);
+});
+
+function nextCallbackId() {
+  return callbackId++;
+}
+
+
+var ExceptionMap = {
+  'UnknownError' : tizen.WebAPIException.UNKNOWN_ERR ,
+  'TypeMismatchError' : tizen.WebAPIException.TYPE_MISMATCH_ERR ,
+  'InvalidValuesError' : tizen.WebAPIException.INVALID_VALUES_ERR ,
+  'IOError' : tizen.WebAPIException.IO_ERR ,
+  'ServiceNotAvailableError' : tizen.WebAPIException.SERVICE_NOT_AVAILABLE_ERR ,
+  'SecurityError' : tizen.WebAPIException.SECURITY_ERR ,
+  'NetworkError' : tizen.WebAPIException.NETWORK_ERR ,
+  'NotSupportedError' : tizen.WebAPIException.NOT_SUPPORTED_ERR ,
+  'NotFoundError' : tizen.WebAPIException.NOT_FOUND_ERR ,
+  'InvalidAccessError' : tizen.WebAPIException.INVALID_ACCESS_ERR ,
+  'AbortError' : tizen.WebAPIException.ABORT_ERR ,
+  'QuotaExceededError' : tizen.WebAPIException.QUOTA_EXCEEDED_ERR ,
+}
+
+function callNative(cmd, args) {
+  var json = {'cmd':cmd, 'args':args};
+  var argjson = JSON.stringify(json);
+  var resultString = extension.internal.sendSyncMessage(argjson)
+  var result = JSON.parse(resultString);
+
+  if (typeof result !== 'object') {
+    throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR);
+  }
+
+  if (result['status'] == 'success') {
+    if(result['result']) {
+        return result['result'];
+    }
+    return true;
+  } else if (result['status'] == 'error') {
+    var err = result['error'];
+    if(err) {
+        if(ExceptionMap[err.name]) {
+            throw new tizen.WebAPIException(ExceptionMap[err.name], err.message);
+        } else {
+            throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR, err.message);
+        }
+    }
+    return false;
+  }
+}
+
+
+function callNativeWithCallback(cmd, args, callback) {
+  if(callback) {
+    var id = nextCallbackId();
+    args['callbackId'] = id;
+    callbacks[id] = callback;
+  }
+  return callNative(cmd, args);
+}
+
+function SetReadOnlyProperty(obj, n, v){
+  Object.defineProperty(obj, n, {value:v, writable: false});
+}
+
+function Playlist(id, name, numberOfTracks, thumbnailURI) {
+  var name_ = name;
+  Object.defineProperties(this, {
+    'id': { writable: false, value: id, enumerable: true },
+    'name': { writable: true, value: name, enumerable: true },
+    'numberOfTracks': { writable: false, value: numberOfTracks, enumerable: true },
+    'thumbnailURI': {writable: true, value: thumbnailURI, enumerable: true }
+  });
+}
+
+function PlaylistItem(content,playlist_member_id) {
+  var content_ = content;
+  var member_id = playlist_member_id;
+  Object.defineProperties(this, {
+    'content': { writable: false, value: content, enumerable: true },
+    'member_id': {
+      set: function(v) { if (v != null) member_id = v},
+      get: function() { return member_id; }
+    }
+  });
+}
+
+
+Playlist.prototype.add = function(item) {
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'item', 'type': types_.PLATFORM_OBJECT, 'values': Content, 'optional' : false, 'nullable' : false}
+  ]);
+  console.log("[dykim]Playlist add entered1");
+  var nativeParam = {
+    'playlist_id': this.id
+  };
+
+  if (args['item']) {
+    nativeParam['content_id'] = args.item.id;
+  }
+  try {
+    var syncResult = callNative('ContentPlaylist_add', nativeParam);
+  } catch(e) {
+    throw e;
+  }
+}
+
+Playlist.prototype.remove = function(item) {
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'item', 'type': types_.PLATFORM_OBJECT, 'values': PlaylistItem, 'optional' : false, 'nullable' : false}
+  ]);
+  var nativeParam = {
+    'playlist_id': this.id,
+    'member_id' : args.item.member_id
+  };
+
+  try {
+    var syncResult = callNative('ContentPlaylist_remove', nativeParam);
+  } catch(e) {
+    throw e;
+  }
+}
+
+
+Playlist.prototype.removeBatch = function(items) {
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'items', 'type': types_.ARRAY},
+    {'name' : 'successCallback', 'type': types_.FUNCTION, optional : true, nullable : true},  
+    {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true}
+  ]);
+
+  var nativeParam = {
+    'playlist_id': this.id,
+  };
+
+  nativeParam["members"] = [];
+  if (args['items']) {
+    for (var i = 0; i < args.items.length; i++) {
+      var c = args.items[i];
+      console.log("member_id:" + c.member_id);
+      nativeParam.members.push(c.member_id);
+    }
+    console.log("nativeParam['members']:" + nativeParam["members"]);
+  }
+
+  try {
+    var syncResult = callNativeWithCallback('ContentPlaylist_removeBatch', nativeParam, function(result) {
+      if (result.status == 'success') {
+        console.log("[dykim]ContentPlaylist_removeBatch successCallback entered");
+        args.successCallback();
+      }
+      else if(result.status == 'error') {
+        var err = result['value'];
+        args.errorCallback(err);
+      }
+    });
+  } catch(e) {
+    throw e;
+  }    
+}
+
+
+Playlist.prototype.get = function() {
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'successCallback', 'type': types_.FUNCTION},  
+    {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true},
+    {'name' : 'count', 'type': types_.LONG, optional : true, nullable : true},
+    {'name' : 'offset', 'type': types_.LONG, optional : true, nullable : true}
+  ]);
+
+  var nativeParam = {
+    'playlist_id': this.id
+  };
+
+  if (args['count']) {
+    nativeParam['count'] = args.count;
+  }
+  else {
+    nativeParam['count'] = -1;
+  }
+  if (args['offset']) {
+    nativeParam['offset'] = args.offset;
+  }
+  else {
+    nativeParam['offset'] = -1;
+  }
+  
+  try {
+    var syncResult = callNativeWithCallback('ContentPlaylist_get', nativeParam, function(result) {
+      if (result.status == 'success') {
+        var items = [];
+        console.log("successCallback Playlist get:%d",result.value.length);
+        for (var i = 0; i < result.value.length; i++) {
+          var c = result.value[i];
+          console.log("name:" + c.name);
+          console.log("playlist_member_id:" + c.playlist_member_id);
+          var content = new Content(c.id, c.name);
+          var item = new PlaylistItem(content,c.playlist_member_id);
+          console.log("item :" + item.member_id);
+          items.push(item);
+        }
+        args.successCallback(items);
+      }
+      else if(result.status == 'error') {
+        var err = result['value'];
+        args.errorCallback(err);
+      }
+    });
+  }
+  catch(e) {
+    throw e;
+  }
+}
+
+Playlist.prototype.addBatch = function() {
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'items', 'type': types_.ARRAY},
+    {'name' : 'successCallback', 'type': types_.FUNCTION, optional : true, nullable : true},  
+    {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true} 
+  ]);
+
+  var nativeParam = {
+    'playlist_id': this.id,
+    'contents' : args.items
+  };
+
+  try {
+    var syncResult = callNativeWithCallback('ContentPlaylist_addBatch', nativeParam, function(result) {
+      if (result.status == 'success') {
+        args.successCallback();
+      }
+      else if(result.status == 'error') {
+        var err = result['value'];
+        args.errorCallback(err);
+      }
+    });
+  } catch(e) {
+      throw e;
+  }
+}
+
+
+Playlist.prototype.setOrder  = function() {
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'items', 'type': types_.ARRAY},
+    {'name' : 'successCallback', 'type': types_.FUNCTION, optional : true, nullable : true},  
+    {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true} 
+  ]);
+
+  var nativeParam = {
+    'playlist_id': this.id,
+  };
+
+  nativeParam["members"] = [];
+  if (args['items']) {
+    for (var i = 0; i < args.items.length; i++) {
+      var c = args.items[i];
+      console.log("member_id:" + c.member_id);
+      nativeParam.members.push(c.member_id);
+    }
+  }
+
+  try {
+    var syncResult = callNativeWithCallback('ContentPlaylist_setOrder', nativeParam, function(result) {
+      if (result.status == 'success') {
+        args.successCallback();
+      }
+      else if(result.status == 'error') {
+        var err = result['value'];
+        args.errorCallback(err);
+      }
+    });
+  } catch(e) {
+    throw e;
+  }      
+}
+
+Playlist.prototype.move  = function(item, delta) {
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'item', 'type': types_.PLATFORM_OBJECT, 'values': PlaylistItem},
+    {'name' : 'delta', 'type': types_.LONG},
+    {'name' : 'successCallback', 'type': types_.FUNCTION, optional : true, nullable : true},  
+    {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true} 
+  ]);
+
+  var nativeParam = {
+    'playlist_id': this.id,
+    'member_id': args.item.member_id
+  };
+
+  if (args['delta']) {
+    nativeParam['delta'] = delta;
+  }
+
+  try {
+    var syncResult = callNativeWithCallback('ContentPlaylist_move', nativeParam, function(result) {
+      if (result.status == 'success') {
+          console.log("[dykim]ContentPlaylist_move successCallback entered");
+          args.successCallback();
+      }
+      else if(result.status == 'error') {
+          var err = result['value'];
+          args.errorCallback(err);
+      }
+    });
+  } catch(e) {
+    throw e;
+  }
+}
+
+
+function ContentDirectory(id, uri, type, title, date) {
+  Object.defineProperties(this, {
+    'id': { writable: false, value: id, enumerable: true },    
+    'directoryURI': { writable: false, value: uri, enumerable: true },
+    'title': { writable: false, value: title, enumerable: true },
+    'storageType': { writable: false, value: type, enumerable: true },
+    'date': { writable: false, value: date, enumerable: true },
+  });
+}
+
+
+function Content(id, name,type, mimeType, title, contentURI, thumbnailURIs, 
+  releaseDate, modifiedDate, size, description, rating, isFavorite) {
+  var name_ = name;
+  var rating_ = rating;
+  var editableAttributes_= ["name", "description", "rating", "isFavorite"];
+
+  if (type === "IMAGE") {
+    editableAttributes_.push("geolocation");
+    editableAttributes_.push("orientation");
+  }
+  else if(type === "VIDEO") {
+    editableAttributes_.push("geolocation");
+  }
+  Object.defineProperties(this, {
+    'editableAttributes': 
+      { enumerable: true,
+        get: function() { return editableAttributes_; }
+      },
+    'id': 
+      { writable: false, value: id, enumerable: true },
+    'name': 
+      { enumerable: true,
+        set: function(v) { if (v != null) name_ = v},
+        get: function() { return name_; }
+      },        
+    'type': 
+      { writable: false, value: type, enumerable: true },
+    'mimeType': 
+      { writable: false, value: mimeType, enumerable: true },
+    'title': 
+      { writable: false, value: title, enumerable: true },
+    'contentURI': 
+      { writable: false, value: contentURI, enumerable: true },
+    'thumbnailURIs': 
+      { writable: false, value: thumbnailURIs, enumerable: true },
+    'releaseDate': 
+      { writable: false, value: releaseDate, enumerable: true },
+    'modifiedDate': 
+      { writable: false, value: modifiedDate, enumerable: true },
+    'size': 
+      { writable: false, value: size, enumerable: true },
+    'description': 
+      { writable: true, value: description, enumerable: true },
+    'rating': 
+      { enumerable: true,
+        set: function(v) { if (v != null && v >= 0 && v <= 10) rating_ = v; },
+        get: function() { return rating_; }
+      },
+    'isFavorite': 
+      { writable: true, value: isFavorite, enumerable: true }
+  });
+}
+
+function ImageContent(obj, width, height, orientation, geolocation) {
+  Object.defineProperties(obj, {
+    'width': 
+      { writable: false, value: width, enumerable: true },
+    'height': 
+      { writable: false, value: height, enumerable: true },
+    'orientation': 
+      { writable: true, value: orientation, enumerable: true },
+    'geolocation': 
+      { writable: true, value: geolocation, enumerable: true }
+  });
+}
+
+function VideoContent(obj, geolocation, album, artists, duration, width, height) {
+  Object.defineProperties(obj, {
+    'geolocation': 
+      { writable: true, value: geolocation, enumerable: true },
+    'album': 
+      { writable: false, value: album, enumerable: true },
+    'artists': 
+      { writable: false, value: artists, enumerable: true },
+    'duration': 
+      { writable: false, value: duration, enumerable: true },
+    'width': 
+      { writable: false, value: width, enumerable: true },
+    'height': 
+      { writable: false, value: height, enumerable: true }
+  });
+}
+
+function AudioContentLyrics(type, timestamps, texts) {
+  Object.defineProperties(this, {
+    'type': 
+      { writable: false, value: type, enumerable: true },
+    'timestamps': 
+      { writable: false, value: timestamps, enumerable: true },
+    'texts': 
+      { writable: false, value: texts, enumerable: true }
+  });
+}
+
+function AudioContent(obj, album, genres, artists, composers, copyright,
+  bitrate, trackNumber, duration) {
+  var lyrics_ = undefined;
+  function getLyrics(contentURI) {
+    var nativeParam = {
+      'contentURI': contentURI
+    };
+
+    var syncResult = callNative('ContentManager_getLyrics', nativeParam);
+
+    if (syncResult.status == 'success') {
+      var l = syncResult['result'];
+      lyrics_ = new AudioContentLyrics(l.type, l.timestamps, l.texts);
+    }
+    else {
+      console.log("Getting the lyrics is failed.");
+    }
+  }
+  Object.defineProperties(obj, {
+    'album': 
+      { writable: false, value: album, enumerable: true },
+    'genres': 
+      { writable: false, value: genres, enumerable: true },
+    'artists': 
+      { writable: false, value: artists, enumerable: true },
+    'composers': 
+      { writable: false, value: composers, enumerable: true },
+    'copyright': 
+      { writable: false, value: copyright, enumerable: true },
+    'bitrate': 
+      { writable: false, value: bitrate, enumerable: true },
+    'trackNumber': 
+      { writable: false, value: trackNumber, enumerable: true },
+    'duration': 
+      { writable: false, value: duration, enumerable: true },
+    'lyrics': 
+      { enumerable: true,
+        get: function() { 
+               if(lyrics_ === undefined) {
+                       getLyrics(obj.contentURI);
+               }
+               return lyrics_;
+        }
+      }
+  });
+}
+
+function createContent(c) {
+  var content = new Content(c.id,
+    c.name,
+    c.type,
+    c.mimeType,
+    c.title,
+    c.contentURI,
+    c.thumbnailURIs,
+    c.releaseDate,
+    c.modifiedDate,
+    c.size,
+    c.description,
+    c.rating,
+    c.isFavorite
+  );
+  if (c.type === "IMAGE") {
+    var image = new ImageContent(content,
+      c.width,
+      c.height, 
+      c.orientation,
+      c.geolocation
+    );
+  }
+  else if (c.type === "VIDEO") {
+    var video = new VideoContent(content,
+      c.geo,
+      c.album,
+      c.artists,
+      c.duration,
+      c.width,
+      c.height
+    );
+  }
+  else if(c.type === "AUDIO") {
+    var audio = new AudioContent(content,
+      c.album,
+      c.genres,
+      c.artists,
+      c.composers,
+      c.copyright,
+      c.bitrate,
+      c.trackNumber,
+      c.duration
+    );
+  }
+  return content;
+}
+
+
+function ContentManager() {
+    // constructor of ContentManager
+}
+
+
+ContentManager.prototype.update = function(content) {
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'content', 'type': types_.PLATFORM_OBJECT}
+  ]);
+  console.log("[dykim]update entered1 id:" + content.id);
+  var nativeParam = {
+  };
+  if (args['content']) {
+      nativeParam['content'] = args.content;
+  }
+  try {
+    var syncResult = callNative('ContentManager_update', nativeParam);
+  } catch(e) {
+    throw e;
+  }
+}
+
+ContentManager.prototype.updateBatch = function(contents) {
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'contents', 'type': types_.ARRAY},  
+    {'name' : 'successCallback', 'type': types_.FUNCTION, optional : true, nullable : true},  
+    {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true} 
+  ]);
+
+  var nativeParam = {
+    'contents' : args.contents
+  };
+
+  try {
+    var syncResult = callNativeWithCallback('ContentManager_updateBatch', nativeParam, function(result) {
+      if (result.status == 'success') {
+        args.successCallback();
+      }
+      else if(result.status == 'error') {
+        var err = result['value'];
+        args.errorCallback(err);
+      }
+    });
+  } catch(e) {
+      throw e;
+  }
+}
+
+ContentManager.prototype.getDirectories = function(successCallback) {
+  console.log("[dykim]getDirectories entered");
+  var args = validator_.validateArgs(arguments, [
+      {'name' : 'successCallback', 'type': types_.FUNCTION, optional : false, nullable : false},  
+      {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true} 
+  ]);
+
+  var nativeParam = {
+  };
+
+  try {
+    var syncResult = callNativeWithCallback('ContentManager_getDirectories', nativeParam, function(result) {
+      if (result.status == 'success') {
+        console.log("[dykim]getDirectories successCallback entered");
+        var dirs = [];
+
+        for (var i = 0; i < result.value.length; i++) {
+          var res = result.value[i];
+          var dir = new ContentDirectory(
+            res.id,
+            res.directoryURI,
+            res.title,
+            res.storageType,
+            res.modifiedDate
+          );
+          
+          dirs.push(dir);
+        }
+        args.successCallback(dirs);
+      }
+      else if(result.status == 'error') {
+          var err = result['value'];
+          args.errorCallback(err);
+      }
+    });
+      // if you need synchronous result from native function using 'syncResult'.
+  }
+  catch(e) {
+    throw e;
+  }
+}
+
+ContentManager.prototype.find = function(successCallback) {
+  var args = validator_.validateArgs(arguments, [
+      {'name' : 'successCallback', 'type': types_.FUNCTION, 'values' : ['onsuccess']},  
+      {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true},  
+      {'name' : 'directoryId', 'type': types_.STRING, optional : true, nullable : true},  
+      {'name' : 'filter', 'type': types_.DICTIONARY, optional : true, nullable : true},  
+      {'name' : 'sortMode', 'type': types_.DICTIONARY, optional : true, nullable : true},  
+      {'name' : 'count', 'type': types_.LONG, optional : true},  
+      {'name' : 'offset', 'type': types_.LONG, optional : true} 
+  ]);
+
+  var nativeParam = {
+  };
+  
+  if (args['directoryId']) {
+      nativeParam['directoryId'] = args.directoryId;
+  }
+  if (args['filter']) {
+      nativeParam['filter'] = args.filter;
+  }
+  if (args['sortMode']) {
+      nativeParam['sortMode'] = args.sortMode;
+  }
+  if (args['count']) {
+      nativeParam['count'] = args.count;
+  }
+  if (args['offset']) {
+      nativeParam['offset'] = args.offset;
+  }
+  try {
+    var syncResult = callNativeWithCallback('ContentManager_find', nativeParam, function(result) {
+      if (result.status == 'success') {
+        var contents = [];
+        console.log("successCallback find:%d",result.value.length);
+        for ( var i = 0; i < result.value.length; i++) {
+          var c = result.value[i];
+
+          var content = createContent(c);
+          
+          contents.push(content);
+        }
+        args.successCallback(contents);
+      }
+      else if(result.status == 'error') {
+        var err = result['value'];
+        args.errorCallback(err);
+      }            
+    });
+      // if you need synchronous result from native function using 'syncResult'.
+  } catch(e) {
+    throw e;
+  }
+
+}
+
+ContentManager.prototype.scanFile = function(contentURI) {
+  console.log("[dykim]scanFile entered");
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'contentURI', 'type': types_.STRING},  
+    {'name' : 'successCallback', 'type': types_.FUNCTION, 'values' : ['onsuccess'], optional : true, nullable : true},  
+    {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true} 
+  ]);
+
+  var nativeParam = {
+    'contentURI': args.contentURI
+  };
+
+  try {
+    var syncResult = callNativeWithCallback('ContentManager_scanFile', nativeParam, function(result) {
+      if (result.status == 'success') {
+        if (args.successCallback) {
+            var uri = result['contentURI'];
+            args.successCallback(uri);
+        }
+      }
+      else if(result.status == 'error') {
+        var err = result['value'];
+        args.errorCallback(err);
+      }
+    });
+  } catch(e) {
+    throw e;
+  }
+
+}
+
+ContentManager.prototype.setChangeListener = function(changeCallback) {
+  console.log("[dykim]setChangeListener entered");
+  var args = validator_.validateArgs(arguments, [
+      {'name' : 'changeCallback', 'type': types_.LISTENER, 'values' : ['oncontentadded', 'oncontentupdated', 'oncontentremoved']} 
+  ]);
+
+  var nativeParam = {
+  };
+  try {
+    var syncResult = callNativeWithCallback('ContentManager_setChangeListener', nativeParam, function(result) {
+      if (result.status == 'oncontentadded') {
+        console.log("[dykim]setChangeListener oncontentadded");
+        var c = result['value'];
+        var content = createContent(c);
+        args.changeCallback.oncontentadded(content);
+      }
+      if (result.status == 'oncontentupdated') {
+        console.log("[dykim]setChangeListener oncontentupdated");
+        var c = result['value'];
+        var content = createContent(c);
+        args.changeCallback.oncontentupdated(content);
+      }
+      if (result.status == 'oncontentremoved') {
+        console.log("[dykim]setChangeListener oncontentremoved");
+        var contentId = result['value'];
+        args.changeCallback.oncontentremoved(contentId);
+      }
+    });
+      // if you need synchronous result from native function using 'syncResult'.
+  } catch(e) {
+      throw e;
+  }
+  console.log("[dykim]setChangeListener ended");
+}
+
+ContentManager.prototype.unsetChangeListener = function() {
+  var nativeParam = {};
+  try {
+      var syncResult = callNative('ContentManager_unsetChangeListener', nativeParam);
+  } catch(e) {
+      throw e;
+  }
+
+}
+
+ContentManager.prototype.getPlaylists = function(successCallback) {
+  console.log("[dykim]getPlaylists start");
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'successCallback', 'type': types_.FUNCTION},  
+    {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true} 
+  ]);
+
+  var nativeParam = {
+  };
+
+  try {
+    var syncResult = callNativeWithCallback('ContentManager_getPlaylists', nativeParam, function(result) {
+      if (result.status == 'success') {
+        var playlists = [];
+        for ( var i = 0; i < result.value.length; i++) {
+          var p = result.value[i];
+          var playlist = new Playlist(p.id, p.name, p.numberOfTracks, p.thumbnailURI);
+          playlists.push(playlist);
+        }
+        args.successCallback(playlists);
+      }
+      else if(result.status == 'error') {
+        var err = result['value'];
+        args.errorCallback(err);
+      }
+    });
+  } catch(e) {
+    throw e;
+  }
+  console.log("[dykim]getPlaylists end");
+}
+
+ContentManager.prototype.createPlaylist = function(name, successCallback) {
+  console.log("[dykim]createPlaylist start");
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'name', 'type': types_.STRING},  
+    {'name' : 'successCallback', 'type': types_.FUNCTION},  
+    {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true},  
+    {'name' : 'sourcePlaylist', 'type': types_.PLATFORM_OBJECT, optional : true, nullable : true}
+  ]);
+
+  var nativeParam = {
+    'name': args.name
+  };
+
+  if (args['sourcePlaylist']) {
+    nativeParam['sourcePlaylist'] = args.sourcePlaylist;
+  }
+
+  try {
+    var syncResult = callNativeWithCallback('ContentManager_createPlaylist', nativeParam, function(result) {
+      if (result.status == 'success') {
+        var p = result['value'];
+        var ret = new Playlist(p.id, p.name, p.numberOfTracks, p.thumbnailURI);
+        args.successCallback(ret);
+      }
+      else if(result.status == 'error') {
+        var err = result['value'];
+        args.errorCallback(err);
+      }
+    });
+  } catch(e) {
+      throw e;
+  }
+}
+
+ContentManager.prototype.removePlaylist = function(id) {
+  console.log("[dykim]removePlaylist start");
+  var args = validator_.validateArgs(arguments, [
+    {'name' : 'id', 'type': types_.STRING},  
+    {'name' : 'successCallback', 'type': types_.FUNCTION, optional : true, nullable : true},  
+    {'name' : 'errorCallback', 'type': types_.FUNCTION, optional : true, nullable : true} 
+  ]);
+
+  var nativeParam = {
+    'id': args.id
+  };
+
+  try {
+    var syncResult = callNativeWithCallback('ContentManager_removePlaylist', nativeParam, function(result) {
+      if (result.status == 'success') {
+        args.successCallback();
+      }
+      else if(result.status == 'error') {
+        var err = result['value'];
+        args.errorCallback(err);
+      }
+    });
+  } catch(e) {
+    throw e;
+  }
+
+  console.log("[dykim]removePlaylist end");
+}
+
+
+
+exports = new ContentManager();
+
diff --git a/src/content/content_extension.cc b/src/content/content_extension.cc
new file mode 100755 (executable)
index 0000000..8fd7513
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/content_extension.h"
+
+#include "content/content_instance.h"
+
+// This will be generated from content_api.js
+extern const char kSource_content_api[];
+
+common::Extension* CreateExtension() {
+  return new ContentExtension;
+}
+
+ContentExtension::ContentExtension() {
+  SetExtensionName("tizen.content");
+  SetJavaScriptAPI(kSource_content_api);
+}
+
+ContentExtension::~ContentExtension() {}
+
+common::Instance* ContentExtension::CreateInstance() {
+  return new extension::content::ContentInstance;
+}
\ No newline at end of file
diff --git a/src/content/content_extension.h b/src/content/content_extension.h
new file mode 100755 (executable)
index 0000000..66b0684
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CONTENT_EXTENSION_H_
+#define CONTENT_CONTENT_EXTENSION_H_
+
+#include "common/extension.h"
+
+class ContentExtension : public common::Extension {
+ public:
+  ContentExtension();
+  virtual ~ContentExtension();
+
+ private:
+  virtual common::Instance* CreateInstance();
+};
+
+#endif // CONTENT_CONTENT_EXTENSION_H_
diff --git a/src/content/content_filter.cc b/src/content/content_filter.cc
new file mode 100755 (executable)
index 0000000..d162fbf
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <amp>
+
+#include "content_filter.h"
+
+#define __DEBUG__ 1
+
+
+namespace extension {
+namespace content {
+
+const std::map<std::string, std::string>& attributeNameMap = {
+  {"id",                    "MEDIA_ID"},
+  {"type",                  "MEDIA_TYPE"},
+  {"mimeType",              "MEDIA_MIME_TYPE"},
+  {"name",                  "MEDIA_DISPLAY_NAME"},
+  {"title",                 "MEDIA_TITLE"},
+  {"contentURI",            "MEDIA_PATH"},
+  {"thumbnailURIs",         "MEDIA_THUMBNAIL_PATH"},
+  {"description",           "MEDIA_DESCRIPTION"},
+  {"rating",                "MEDIA_RATING"},
+  {"createdDate",           "MEDIA_ADDED_TIME"},
+  {"releaseDate",           "MEDIA_DATETAKEN"},
+  {"modifiedDate",          "MEDIA_MODIFIED_TIME"},
+  {"geolocation.latitude",  "MEDIA_LATITUDE"},
+  {"geolocation.longitude", "MEDIA_LONGITUDE"},
+  {"duration",              "MEDIA_DURATION"},
+  {"album",                 "MEDIA_ALBUM"},
+  {"artists",               "MEDIA_ARTIST"},
+  {"width",                 "MEDIA_WIDTH"},
+  {"height",                "MEDIA_HEIGHT"},
+  {"genres",                "MEDIA_GENRE"},
+  {"size",                  "MEDIA_SIZE"},
+};
+
+const std::map<std::string, std::string>& opMap = {
+  {"EXACTLY",    " = "},
+  {"FULLSTRING", " = "},
+  {"CONTAINS",   " LIKE "},
+  {"STARTSWITH", " LIKE "},
+  {"ENDSWITH",   " LIKE "},
+  {"EXISTS",     " IS NOT NULL "},
+};
+
+std::string ContentFilter::convert(const picojson::value& jsFilter) {
+  std::string attributeName = jsFilter.get("attributeName").to_str();
+  std::string matchFlag = jsFilter.get("matchFlag").to_str();
+  std::string matchValue = jsFilter.get("matchValue").to_str();
+
+#ifdef DEBUG
+  std::cout << "Filter IN: " << attributeName << " " << matchFlag << " " << matchValue << std::endl;
+#endif
+
+  std::string query;
+  if (attributeName.empty() || matchFlag.empty()) {
+    std::cerr <<
+        "Filter ERR: attribute or match flag missing" << std::endl;
+    return query;
+  }
+
+  std::map<std::string, std::string>::const_iterator it;
+  it = attributeNameMap.find(attributeName);
+  if (it == attributeNameMap.end()) {
+    std::cerr << "Filter ERR: unknown attributeName " <<
+        attributeName << std::endl;
+    return query;
+  }
+  std::string lValue = it->second;
+
+  it = opMap.find(matchFlag);
+  if (it == attributeNameMap.end()) {
+    std::cerr << "Filter ERR: unknown matchFlag " << matchFlag << std::endl;
+    return query;
+  }
+  std::string op = it->second;
+
+  // Tizen requires this weird mapping on type
+  if (attributeName == "type") {
+    if (matchValue == "IMAGE") {
+      matchValue = "0";
+    } else if (matchValue == "VIDEO") {
+      matchValue = "1";
+    } else if (matchValue == "AUDIO") {
+      matchValue = "3";
+    } else if (matchValue == "OTHER") {
+      matchValue = "4";
+    } else {
+      std::cerr << "Filter ERR: unknown media type " << matchValue << std::endl;
+      return query;
+    }
+  }
+
+  const std::string STR_QUOTE("'");
+  const std::string STR_PERCENT("%");
+  std::string rValue;
+  if (matchFlag == "CONTAINS")
+    rValue = STR_QUOTE + STR_PERCENT + matchValue + STR_PERCENT + STR_QUOTE;
+  else if (matchFlag == "STARTSWITH")
+    rValue = STR_QUOTE + matchValue + STR_PERCENT + STR_QUOTE;
+  else if (matchFlag == "ENDSWITH")
+    rValue = STR_QUOTE + STR_PERCENT + matchValue + STR_QUOTE;
+  else if (matchFlag == "FULLSTRING")
+    rValue = STR_QUOTE + matchValue + STR_QUOTE + " COLLATE NOCASE ";
+  else if (matchFlag == "EXISTS")
+    rValue = "";
+  else
+    rValue = STR_QUOTE + matchValue + STR_QUOTE;
+
+  query = lValue + op + rValue;
+#ifdef DEBUG
+  std::cout << "Filter OUT: " << query << std::endl;
+#endif
+  return query;
+}
+
+
+
+
+} // namespace content
+} // namespace extension
+
diff --git a/src/content/content_filter.h b/src/content/content_filter.h
new file mode 100755 (executable)
index 0000000..f0db019
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_FILTER_H_
+#define CONTENT_FILTER_H_
+
+#include "common/picojson.h"
+
+#include <string>
+#include <media_content.h>
+
+
+namespace extension {
+namespace content {
+
+class ContentFilter {
+ public:
+  std::string convert(const picojson::value &jsFilter);
+  
+ private:
+    
+
+};
+
+}
+}
+
+#endif 
+
diff --git a/src/content/content_instance.cc b/src/content/content_instance.cc
new file mode 100755 (executable)
index 0000000..3611119
--- /dev/null
@@ -0,0 +1,589 @@
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/content_instance.h"
+
+#include <functional>
+#include <string>
+#include <dlog.h>
+#include <glib.h>
+#include <memory>
+#include <media_content.h>
+
+#include "common/picojson.h"
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include "common/task-queue.h"
+
+#include "content_manager.h"
+
+namespace extension {
+namespace content {
+
+namespace {
+// The privileges that required in Content API
+const std::string kPrivilegeContent = "";
+
+} // namespace
+
+using namespace common;
+using namespace extension::content;
+
+ContentInstance::ContentInstance() {
+  using namespace std::placeholders;
+  #define REGISTER_SYNC(c,x) \
+    RegisterSyncHandler(c, std::bind(&ContentInstance::x, this, _1, _2));
+  REGISTER_SYNC("ContentManager_find", ContentManagerFind);
+  REGISTER_SYNC("ContentManager_update", ContentManagerUpdate);
+  REGISTER_SYNC("ContentManager_scanFile", ContentManagerScanfile);
+  REGISTER_SYNC("ContentManager_unsetChangeListener", ContentManagerUnsetchangelistener);
+  REGISTER_SYNC("ContentManager_setChangeListener", ContentManagerSetchangelistener);
+  REGISTER_SYNC("ContentManager_getDirectories", ContentManagerGetdirectories);
+  REGISTER_SYNC("ContentManager_updateBatch", ContentManagerUpdatebatch);
+  REGISTER_SYNC("ContentManager_removePlaylist", ContentManagerRemoveplaylist);
+  REGISTER_SYNC("ContentManager_createPlaylist", ContentManagerCreateplaylist);
+  REGISTER_SYNC("ContentManager_getPlaylists", ContentManagerGetplaylists);
+  REGISTER_SYNC("ContentPlaylist_add", ContentManagerPlaylistAdd);
+  REGISTER_SYNC("ContentPlaylist_addBatch", ContentManagerPlaylistAddbatch);
+  REGISTER_SYNC("ContentPlaylist_get", ContentManagerPlaylistGet);
+  REGISTER_SYNC("ContentPlaylist_remove", ContentManagerPlaylistRemove);
+  REGISTER_SYNC("ContentPlaylist_removeBatch", ContentManagerPlaylistRemovebatch);
+  REGISTER_SYNC("ContentPlaylist_setOrder", ContentManagerPlaylistSetorder);  
+  REGISTER_SYNC("ContentPlaylist_move", ContentManagerPlaylistMove);
+  REGISTER_SYNC("ContentManager_getLyrics", ContentManagerAudioGetLyrics);  
+
+  //  
+  #undef REGISTER_SYNC
+}
+
+ContentInstance::~ContentInstance() {
+  LoggerE("<<endterd>>");
+}
+
+static void ReplyAsync(ContentInstance* instance, ContentCallbacks cbfunc, 
+                       double callbackId, bool isSuccess, picojson::object& param) {
+  LoggerE("<<endterd>>");
+  param["callbackId"] = picojson::value(static_cast<double>(callbackId));
+  param["status"] = picojson::value(isSuccess ? "success" : "error");
+  
+  picojson::value result = picojson::value(param);
+  
+  instance->PostMessage(result.serialize().c_str());
+}
+
+static gboolean CompletedCallback(const std::shared_ptr<ReplyCallbackData>& user_data) {
+  LoggerE("<<endterd>>");
+
+  picojson::value::object reply;
+  reply["value"] = user_data->result;
+  LoggerE("CompletedCallback...(%d)" , user_data->isSuccess);
+  ReplyAsync(user_data->instance,user_data->cbType,user_data->callbackId,user_data->isSuccess,reply);
+
+  return false;  
+}
+
+static void* WorkThread(const std::shared_ptr<ReplyCallbackData>& user_data) {
+  LoggerE("<<endterd>>");
+  user_data->isSuccess = true;
+  ContentCallbacks cbType = user_data->cbType;
+  switch(cbType) {
+    case ContentManagerUpdatebatchCallback: {
+      LoggerE("ContentManagerUpdatebatchCallback...");
+      ContentManager::getInstance()->updateBatch(user_data->args);
+      break;
+    }
+    case ContentManagerGetdirectoriesCallback: {
+      LoggerE("ContentManagerGetdirectoriesCallback...");
+      ContentManager::getInstance()->getDirectories(user_data);
+      break;
+    }
+    case ContentManagerFindCallback: {
+      ContentManager::getInstance()->find(user_data);        
+      LoggerE("ContentManagerFindCallback...:%s", user_data->result.serialize().c_str());
+      break;
+    }
+    case ContentManagerScanfileCallback: {
+      std::string contentURI = user_data->args.get("contentURI").get<std::string>();
+      ContentManager::getInstance()->scanFile(contentURI);
+      break;
+    }
+    case ContentManagerGetplaylistsCallback: {
+      LoggerE("ContentManagerGetplaylistsCallback...");
+      ContentManager::getInstance()->getPlaylists(user_data);
+      break;
+    }
+    case ContentManagerCreateplaylistCallback: {
+      LoggerE("ContentManagerCreateplaylistCallback...");
+      if (user_data->args.contains("sourcePlaylist")) {
+        picojson::object playlist = user_data->args.get("sourcePlaylist").get<picojson::object>();
+        user_data->isSuccess = true;
+        user_data->result = picojson::value(playlist);
+      }
+      else{
+        std::string name = user_data->args.get("name").get<std::string>();
+        ContentManager::getInstance()->createPlaylist(name, user_data);
+      }
+      break;
+    }
+    case ContentManagerRemoveplaylistCallback: {
+      LoggerE("ContentManagerRemoveplaylistCallback...");
+      std::string id = user_data->args.get("id").get<std::string>();
+      ContentManager::getInstance()->removePlaylist(id, user_data);
+      // do something...
+      break;
+    }
+    case ContentManagerPlaylistAddbatchCallback: {
+      LoggerE("ContentManagerPlaylistAddBatchCallback...");
+      ContentManager::getInstance()->playlistAddbatch(user_data);
+      break;
+    }
+    case ContentManagerPlaylistGetCallback: {
+      LoggerE("ContentManagerPlaylistGetCallback...");
+      ContentManager::getInstance()->playlistGet(user_data);
+      break;
+    }
+    case ContentManagerPlaylistRemovebatchCallback: {
+      LoggerE("ContentManagerPlaylistGetCallback...");
+      ContentManager::getInstance()->playlistRemovebatch(user_data);
+      break;
+    }
+    case ContentManagerPlaylistSetOrderCallback: {
+      LoggerE("ContentManagerPlaylistSetOrderCallback...");
+      ContentManager::getInstance()->playlistSetOrder(user_data);
+      break;
+      //ContentManagerPlaylistSetOrderCallback
+    }
+    case ContentManagerPlaylistMoveCallback: {
+      LoggerE("ContentManagerPlaylistMove...");
+      ContentManager::getInstance()->playlistMove(user_data);
+      break;
+    }
+    case ContentManagerErrorCallback: {
+      UnknownException err("DB Connection is failed.");
+      user_data->isSuccess = false;
+      user_data->result = err.ToJSON();
+      break;
+    }
+    default: {
+      LoggerE("Invalid Callback Type");
+      return NULL;
+    }
+  }
+  return NULL;
+}
+
+static void changedContentCallback(media_content_error_e error, int pid, media_content_db_update_item_type_e update_item, 
+  media_content_db_update_type_e update_type, media_content_type_e media_type, 
+  char *uuid, char *path, char *mime_type, void* user_data) {
+
+  int ret;
+  std::shared_ptr<ReplyCallbackData> *cbData = (std::shared_ptr<ReplyCallbackData>*)(user_data);
+  LoggerE("ContentInstance::ContentManagerScanfile");
+  picojson::object reply;
+  
+  picojson::object o;
+  if( error == MEDIA_CONTENT_ERROR_NONE) {
+    if( update_item == MEDIA_ITEM_FILE) {
+      if(update_type == MEDIA_CONTENT_INSERT || update_type == MEDIA_CONTENT_UPDATE) {
+        media_info_h media = NULL;
+        std::string id(uuid);
+        ret = media_info_get_media_from_db(id.c_str(), &media);
+        if (ret == MEDIA_CONTENT_ERROR_NONE && media != NULL) {
+          ContentManager::getInstance()->contentToJson(media, o);
+          reply["value"] = picojson::value(o);
+          if (update_type == MEDIA_CONTENT_INSERT) {
+            reply["status"] = picojson::value("oncontentadded");
+          }
+          else if (update_type == MEDIA_CONTENT_UPDATE) {
+            reply["status"] = picojson::value("oncontentupdated");
+          }
+        }
+      }
+      else {
+        reply["value"] = picojson::value(std::string(uuid));
+        reply["status"] = picojson::value("oncontentremoved");
+      }
+    }
+  }
+  else {
+    return;
+  }
+  reply["callbackId"] = picojson::value(static_cast<double>((*cbData)->callbackId));
+  picojson::value result = picojson::value(reply);
+  (*cbData)->instance->PostMessage(result.serialize().c_str());
+}
+
+
+#define CHECK_EXIST(args, name, out) \
+  if (!args.contains(name)) {\
+    ReportError(TypeMismatchException(name" is required argument"), out);\
+    return;\
+  }
+
+
+void ContentInstance::ContentManagerUpdate(const picojson::value& args, picojson::object& out) {
+  LoggerE("ContentInstance::ContentManagerUpdate");
+  int ret;
+  if(ContentManager::getInstance()->isConnected()) {
+    ret = ContentManager::getInstance()->update(args);
+    if(ret != 0) {
+      ReportError(ContentManager::getInstance()->convertError(ret),out);
+    }
+  }
+  else {
+    ReportError(UnknownException("DB connection is failed."),out);
+  }
+}
+void ContentInstance::ContentManagerUpdatebatch(const picojson::value& args, picojson::object& out) {
+  LoggerE("entered");
+  double callbackId = args.get("callbackId").get<double>();
+  
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+  
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerUpdatebatchCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+}
+void ContentInstance::ContentManagerGetdirectories(const picojson::value& args, picojson::object& out) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentInstance::getDirectories started");
+  CHECK_EXIST(args, "callbackId", out)
+
+  double callbackId = args.get("callbackId").get<double>();
+  // implement it
+
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerGetdirectoriesCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+
+  // call ReplyAsync in later (Asynchronously)
+  
+  // if success
+  //ReportSuccess(out);
+  // if error
+  // ReportError(out);
+}
+void ContentInstance::ContentManagerFind(const picojson::value& args, picojson::object& out) {
+  CHECK_EXIST(args, "callbackId", out)
+
+  //double count = args.get("count").get<double>();
+  //double offset = args.get("offset").get<double>();
+
+  double callbackId = args.get("callbackId").get<double>();
+  
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerFindCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+  // implement it
+
+  // call ReplyAsync in later (Asynchronously)
+
+  // if success
+  // ReportSuccess(out);
+  // if error
+  // ReportError(out);
+}
+void ContentInstance::ContentManagerScanfile(const picojson::value& args, picojson::object& out) {
+  LoggerE("ContentInstance::ContentManagerScanfile");
+  CHECK_EXIST(args, "callbackId", out)
+  CHECK_EXIST(args, "contentURI", out)
+
+  double callbackId = args.get("callbackId").get<double>();
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerScanfileCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+  // implement it
+  // call ReplyAsync in later (Asynchronously)
+
+  // if success
+  // ReportSuccess(out);
+  // if error
+  // ReportError(out);
+}
+void ContentInstance::ContentManagerSetchangelistener(const picojson::value& args, picojson::object& out) {
+  CHECK_EXIST(args, "callbackId", out)
+
+  double callbackId = args.get("callbackId").get<double>();
+
+  std::shared_ptr<ReplyCallbackData>cbData(new ReplyCallbackData);
+  
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerSetchangelistenerCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+
+  ContentManager::getInstance()->setChangeListener(changedContentCallback,static_cast<void*>(&cbData));
+  
+  // implement it
+
+  // call ReplyAsync in later (Asynchronously)
+
+  // if success
+  // ReportSuccess(out);
+  // if error
+  // ReportError(out);
+}
+void ContentInstance::ContentManagerUnsetchangelistener(const picojson::value& args, picojson::object& out) {
+
+  ContentManager::getInstance()->unSetChangeListener();
+
+  // if success
+  // ReportSuccess(out);
+  // if error
+  // ReportError(out);
+}
+void ContentInstance::ContentManagerGetplaylists(const picojson::value& args, picojson::object& out) {
+  LoggerE("ContentInstance::ContentManagerGetplaylists");
+  CHECK_EXIST(args, "callbackId", out)
+
+  double callbackId = args.get("callbackId").get<double>();
+
+  // implement it
+  std::shared_ptr<ReplyCallbackData>cbData(new ReplyCallbackData);
+  
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerGetplaylistsCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+  
+}
+void ContentInstance::ContentManagerCreateplaylist(const picojson::value& args, picojson::object& out) {
+  LoggerE("ContentInstance::ContentManagerCreateplaylist");
+  CHECK_EXIST(args, "callbackId", out)
+  CHECK_EXIST(args, "name", out)
+
+  double callbackId = args.get("callbackId").get<double>();
+  const std::string& name = args.get("name").get<std::string>();
+
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerCreateplaylistCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+}
+void ContentInstance::ContentManagerRemoveplaylist(const picojson::value& args, picojson::object& out) {
+  LoggerE("ContentInstance::ContentManagerRemoveplaylist");
+
+  double callbackId = args.get("callbackId").get<double>();
+
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerRemoveplaylistCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+
+  // implement it
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+
+
+  // if success
+  // ReportSuccess(out);
+  // if error
+  // ReportError(out);
+}
+
+void ContentInstance::ContentManagerPlaylistAdd(const picojson::value& args, picojson::object& out) {
+  LoggerE("ContentInstance::ContentManagerPlaylistAdd");
+  int ret;
+  if(ContentManager::getInstance()->isConnected()) {
+    std::string playlist_id = args.get("playlist_id").get<std::string>();
+    std::string content_id = args.get("content_id").get<std::string>();
+    LoggerE("playlist:%s / content:%s", playlist_id.c_str() , content_id.c_str());
+    ret = ContentManager::getInstance()->playlistAdd(playlist_id, content_id);
+    if(ret != MEDIA_CONTENT_ERROR_NONE) {
+      ReportError(ContentManager::getInstance()->convertError(ret),out);
+    }
+  }
+  else {
+    ReportError(UnknownException("DB connection is failed."),out);
+  }  
+}
+
+void ContentInstance::ContentManagerPlaylistAddbatch(const picojson::value& args, picojson::object& out) {
+  LoggerE("entered");
+  double callbackId = args.get("callbackId").get<double>();
+  
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+  
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerPlaylistAddbatchCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+}
+
+
+void ContentInstance::ContentManagerPlaylistGet(const picojson::value& args, picojson::object& out) {
+  LoggerE("entered");
+  double callbackId = args.get("callbackId").get<double>();
+  
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+  
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerPlaylistGetCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+}
+
+void ContentInstance::ContentManagerPlaylistRemove(const picojson::value& args, picojson::object& out) {
+  LoggerE("ContentInstance::ContentManagerPlaylistRemove");
+  int ret;
+  if(ContentManager::getInstance()->isConnected()) {
+    std::string playlist_id = args.get("playlist_id").get<std::string>();
+    int member_id = args.get("member_id").get<double>();
+    LoggerE("playlist:%s / member_id:%d", playlist_id.c_str() , member_id);
+    ret = ContentManager::getInstance()->playlistRemove(playlist_id, member_id);
+    if(ret != MEDIA_CONTENT_ERROR_NONE) {
+      ReportError(ContentManager::getInstance()->convertError(ret),out);
+    }
+  }
+  else {
+    ReportError(UnknownException("DB connection is failed."),out);
+  }  
+}
+
+void ContentInstance::ContentManagerPlaylistRemovebatch(const picojson::value& args, picojson::object& out) {
+  LoggerE("entered");
+  double callbackId = args.get("callbackId").get<double>();
+  
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+  
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerPlaylistRemovebatchCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+}
+
+
+void ContentInstance::ContentManagerPlaylistSetorder(const picojson::value& args, picojson::object& out) {
+  LoggerE("entered");
+  double callbackId = args.get("callbackId").get<double>();
+  
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+  
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerPlaylistSetOrderCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
+}
+
+void ContentInstance::ContentManagerPlaylistMove(const picojson::value& args, picojson::object& out) {
+  LoggerE("entered");
+  double callbackId = args.get("callbackId").get<double>();
+  
+  auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
+  cbData->callbackId = callbackId;
+  cbData->instance = this;
+  cbData->args = args;
+  
+  if(ContentManager::getInstance()->isConnected()) {
+    cbData->cbType = ContentManagerPlaylistMoveCallback;
+  }
+  else {
+    cbData->cbType = ContentManagerErrorCallback;
+  }
+  common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);  
+}
+
+void ContentInstance::ContentManagerAudioGetLyrics(const picojson::value& args, picojson::object& out) {
+  LoggerE("ContentInstance::ContentManagerAudioGetLyrics");
+  int ret;
+  picojson::object lyrics;
+  if(ContentManager::getInstance()->isConnected()) {
+    ret = ContentManager::getInstance()->getLyrics(args,lyrics);
+    if(ret != MEDIA_CONTENT_ERROR_NONE) {
+      ReportError(ContentManager::getInstance()->convertError(ret),out);
+    }
+    else {
+      ReportSuccess(picojson::value(lyrics),out);
+    }
+  }
+  else {
+    ReportError(UnknownException("DB connection is failed."),out);
+  }
+}
+#undef CHECK_EXIST
+
+} // namespace content
+} // namespace extension
diff --git a/src/content/content_instance.h b/src/content/content_instance.h
new file mode 100755 (executable)
index 0000000..c930dfe
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CONTENT_INSTANCE_H_
+#define CONTENT_CONTENT_INSTANCE_H_
+
+#include "common/extension.h"
+
+namespace extension {
+namespace content {
+
+enum ContentCallbacks {
+  ContentManagerFindCallback, 
+  ContentManagerScanfileCallback, 
+  ContentManagerUnsetchangelistenerCallback, 
+  ContentManagerSetchangelistenerCallback, 
+  ContentManagerGetdirectoriesCallback, 
+  ContentManagerUpdatebatchCallback, 
+  ContentManagerRemoveplaylistCallback, 
+  ContentManagerCreateplaylistCallback, 
+  ContentManagerGetplaylistsCallback,
+  ContentManagerPlaylistAddbatchCallback,
+  ContentManagerPlaylistGetCallback,
+  ContentManagerPlaylistRemovebatchCallback,
+  ContentManagerPlaylistSetOrderCallback,
+  ContentManagerPlaylistMoveCallback,
+  ContentManagerErrorCallback
+};
+
+
+class ContentInstance : public common::ParsedInstance {
+ public:
+  ContentInstance();
+  virtual ~ContentInstance();
+
+ private:
+  void ContentManagerUpdate(const picojson::value& args, picojson::object& out);
+  void ContentManagerUpdatebatch(const picojson::value& args, picojson::object& out);
+  void ContentManagerGetdirectories(const picojson::value& args, picojson::object& out);
+  void ContentManagerFind(const picojson::value& args, picojson::object& out);
+  void ContentManagerScanfile(const picojson::value& args, picojson::object& out);
+  void ContentManagerSetchangelistener(const picojson::value& args, picojson::object& out);
+  void ContentManagerUnsetchangelistener(const picojson::value& args, picojson::object& out);
+  void ContentManagerGetplaylists(const picojson::value& args, picojson::object& out);
+  void ContentManagerCreateplaylist(const picojson::value& args, picojson::object& out);
+  void ContentManagerRemoveplaylist(const picojson::value& args, picojson::object& out);
+  void ContentManagerPlaylistAdd(const picojson::value& args, picojson::object& out);
+  void ContentManagerPlaylistAddbatch(const picojson::value& args, picojson::object& out);
+  void ContentManagerPlaylistGet(const picojson::value& args, picojson::object& out);
+  void ContentManagerPlaylistRemove(const picojson::value& args, picojson::object& out);
+  void ContentManagerPlaylistRemovebatch(const picojson::value& args, picojson::object& out);
+  void ContentManagerPlaylistSetorder(const picojson::value& args, picojson::object& out);
+  void ContentManagerPlaylistMove(const picojson::value& args, picojson::object& out);
+  void ContentManagerAudioGetLyrics(const picojson::value& args, picojson::object& out);
+
+//
+};
+
+typedef struct _ReplyCallbackData{
+  ContentInstance* instance;
+  ContentCallbacks cbType;
+  double callbackId;
+  bool isSuccess;
+  picojson::value args;
+  picojson::value result;
+}ReplyCallbackData;
+
+
+} // namespace content
+} // namespace extension
+
+#endif // CONTENT_CONTENT_INSTANCE_H_
diff --git a/src/content/content_manager.cc b/src/content/content_manager.cc
new file mode 100755 (executable)
index 0000000..2059f3f
--- /dev/null
@@ -0,0 +1,1230 @@
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <unistd.h>
+#include <cstring>
+#include <string>
+#include <algorithm>
+#include <dlog.h>
+#include <memory>
+#include <sstream>
+#include <metadata_extractor.h>
+
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include "content_manager.h"
+#include "content_filter.h"
+
+using namespace std;
+using namespace common;
+
+namespace extension {
+namespace content {
+
+#define TAG_DELIMETER '/'
+
+static int get_utc_offset()
+{
+  time_t zero = 24*60*60L;
+  struct tm * timeptr;
+  int gmtime_hours;
+
+  /* get the local time for Jan 2, 1900 00:00 UTC */
+  timeptr = localtime( &zero );
+  gmtime_hours = timeptr->tm_hour;
+
+  if( timeptr->tm_mday < 2 )
+    gmtime_hours -= 24;
+
+  return gmtime_hours;
+}
+
+static bool isContentUri(const std::string str) {
+  std::string schema("file://");
+  std::size_t found = str.find(schema);
+
+  if (found == std::string::npos || found != 0) {
+      return false;
+  }
+
+  return true;
+}
+
+static std::string ltrim(const std::string s) {
+  std::string str = s;
+  std::string::iterator i;
+  for (i = str.begin(); i != str.end(); i++) {
+      if (!isspace(*i)) {
+          break;
+      }
+  }
+  if (i == str.end()) {
+      str.clear();
+  } else {
+      str.erase(str.begin(), i);
+  }
+  return str;
+}
+
+
+static std::string convertUriToPath(const string str) {
+  string result;
+  std::string schema ("file://");
+  std::string _str = ltrim(str);
+
+  std::string _schema = _str.substr(0,schema.size());
+
+  if(_schema == schema)
+  {
+      result = _str.substr(schema.size());
+  }
+  else
+  {
+      result = _str;
+  }
+  return result;
+}
+
+static std::string convertPathToUri(const string str) {
+  string result;
+  std::string schema ("file://");
+  std::string _str = ltrim(str);
+
+  std::string _schema = _str.substr(0,schema.size());
+
+  if(_schema == schema)
+  {
+      result = _str;
+  }
+  else
+ {
+      result = schema + _str;
+  }
+  return result;
+}
+
+
+static void contentToJson(media_info_h info, picojson::object& o) {
+  int ret;
+  int tmpInt = 0;
+  bool tmpBool = false;
+  char* tmpStr = NULL;
+  time_t tmpDate;
+  double tmpDouble;
+  long long unsigned int tmpLong;
+  
+  media_content_type_e type;
+  ret == media_info_get_media_type(info, &type);
+  if(ret != MEDIA_CONTENT_ERROR_NONE) {
+    if ( type == MEDIA_CONTENT_TYPE_IMAGE ) {
+      o["type"] = picojson::value(std::string("IMAGE"));
+      image_meta_h img;
+      if(MEDIA_CONTENT_ERROR_NONE == media_info_get_image(info, &img)) {
+        if(MEDIA_CONTENT_ERROR_NONE == image_meta_get_date_taken (img, &tmpStr)) {
+          if ( tmpStr ) {
+            struct tm *result = (struct tm *)calloc(1, sizeof(struct tm));
+            if(strptime(tmpStr, "%Y:%m:%d %H:%M:%S", result) == NULL) {
+              LoggerE( "Couldn't convert supplied date.");
+            }
+            else {
+              time_t t = mktime( result );// + get_utc_offset() * 3600;
+              std::stringstream str_date;
+              str_date << t;
+              o["releaseDate"] = picojson::value(str_date.str());
+              free(tmpStr);
+              free(result);
+              tmpStr = NULL;
+            }
+          }
+        }
+        if(MEDIA_CONTENT_ERROR_NONE == image_meta_get_width(img, &tmpInt) ) {
+          o["width"] = picojson::value(static_cast<double>(tmpInt));
+        }
+
+        if(MEDIA_CONTENT_ERROR_NONE == image_meta_get_height(img, &tmpInt) ) {
+          o["height"] = picojson::value(static_cast<double>(tmpInt));          
+        }
+        picojson::object geo;
+        std::string str_latitude;
+        if (MEDIA_CONTENT_ERROR_NONE == media_info_get_latitude(info, &tmpDouble) ) {
+          geo["latitude"] = picojson::value(tmpDouble);
+        }
+        std::string str_longitude;
+        if(MEDIA_CONTENT_ERROR_NONE == media_info_get_longitude(info, &tmpDouble) ) {
+          geo["longitude"] = picojson::value(tmpDouble);
+        }
+        
+        o["geolocation"] = picojson::value(geo);
+
+        std::string ori;
+        media_content_orientation_e orientation;
+        if(MEDIA_CONTENT_ERROR_NONE == image_meta_get_orientation(img, &orientation) ) {
+          switch (orientation) {
+          case 0:
+          case 1:
+              ori = "NORMAL";
+              break;
+          case 2:
+              ori = "FLIP_HORIZONTAL";
+              break;
+          case 3:
+              ori = "ROTATE_180";
+              break;
+          case 4:
+              ori = "FLIP_VERTICAL";
+              break;
+          case 5:
+              ori = "TRANSPOSE";
+              break;
+          case 6:
+              ori = "ROTATE_90";
+              break;
+          case 7:
+              ori = "TRANSVERSE";
+              break;
+          case 8:
+              ori = "ROTATE_270";
+              break;
+          }
+          o["orientation"] = picojson::value(ori);
+        }
+        
+      }
+
+    }
+    else if( type == MEDIA_CONTENT_TYPE_VIDEO ) {
+      o.insert(std::make_pair(std::string("type"), std::string("VIDEO")));
+      video_meta_h video;
+      if(MEDIA_CONTENT_ERROR_NONE == media_info_get_video(info, &video)) {
+        if(MEDIA_CONTENT_ERROR_NONE == video_meta_get_width(video, &tmpInt)) {
+          std::stringstream str_width;
+          str_width << tmpInt;
+          o.insert(std::make_pair(std::string("width"), str_width.str()));
+        }
+
+        if(MEDIA_CONTENT_ERROR_NONE == video_meta_get_height(video, &tmpInt) ) {
+          std::stringstream str_height;
+          str_height << tmpInt;
+          o.insert(std::make_pair(std::string("height"), str_height.str()));
+        }
+        if (MEDIA_CONTENT_ERROR_NONE == video_meta_get_artist(video, &tmpStr) ) {
+          picojson::array artists;
+          if (tmpStr) {
+            artists.push_back(picojson::value(std::string(tmpStr)));
+          }
+          o["artists"] = picojson::value(artists);
+        }
+        if (MEDIA_CONTENT_ERROR_NONE == video_meta_get_album(video, &tmpStr)) {
+          if (tmpStr) {
+            o.insert(std::make_pair(std::string("album"), tmpStr));
+          }
+        }
+        if (MEDIA_CONTENT_ERROR_NONE == video_meta_get_duration(video, &tmpInt) ) {
+          o.insert(std::make_pair(std::string("duration"), std::to_string(tmpInt)));
+        }        
+      }
+      picojson::object geo;
+      if (MEDIA_CONTENT_ERROR_NONE == media_info_get_latitude(info, &tmpDouble) ) {
+        geo["latitude"] = picojson::value(tmpDouble);
+      }
+      if (MEDIA_CONTENT_ERROR_NONE == media_info_get_longitude(info, &tmpDouble) ) {
+        geo["longitude"] = picojson::value(tmpDouble);
+      }      
+      o["geolocation"] = picojson::value(geo);
+    }
+    else if( type == MEDIA_CONTENT_TYPE_SOUND || type == MEDIA_CONTENT_TYPE_MUSIC ) {
+      o["type"] = picojson::value(std::string("AUDIO"));
+      audio_meta_h audio;
+      if(MEDIA_CONTENT_ERROR_NONE == media_info_get_audio(info, &audio)) {
+        if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_recorded_date(audio, &tmpStr) ) {
+          if (tmpStr) {
+            struct tm *result = (struct tm *)calloc(1, sizeof(struct tm));
+            
+            if (strptime(tmpStr, "%Y:%m:%d %H:%M:%S", result) == NULL) {
+                LoggerD( "Couldn't convert supplied date.");
+            }
+            time_t t = mktime( result ) + get_utc_offset() * 3600;
+            std::stringstream str_date;
+            str_date << t;
+            o["releaseDate"] = picojson::value(str_date.str());
+            free(tmpStr);
+            free(result);
+            tmpStr = NULL;
+          }
+        }
+        if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_album(audio, &tmpStr)) {
+          if(tmpStr) {
+            o["album"] = picojson::value(std::string(tmpStr));
+            free(tmpStr);
+            tmpStr = NULL;
+          }
+        }
+        if(MEDIA_CONTENT_ERROR_NONE == audio_meta_get_artist(audio, &tmpStr)) {
+          if(tmpStr) {
+            picojson::array artists;
+            if (tmpStr) {
+              artists.push_back(picojson::value(std::string(tmpStr)));
+            }
+            o["artists"] = picojson::value(artists);
+            free(tmpStr);
+            tmpStr = NULL;
+          }
+        }
+        if(MEDIA_CONTENT_ERROR_NONE == audio_meta_get_genre(audio, &tmpStr)) {
+          if(tmpStr) {
+            picojson::array genres;
+            if (tmpStr) {
+              genres.push_back(picojson::value(std::string(tmpStr)));
+            }
+            o["genres"] = picojson::value(genres);
+            free(tmpStr);
+            tmpStr = NULL;
+          }
+        }
+        if(MEDIA_CONTENT_ERROR_NONE == audio_meta_get_composer(audio, &tmpStr)) {
+          if(tmpStr) {
+            picojson::array composers;
+            if (tmpStr) {
+              composers.push_back(picojson::value(std::string(tmpStr)));
+            }
+            o["composers"] = picojson::value(composers);
+            free(tmpStr);
+            tmpStr = NULL;
+          }
+        }
+        if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_copyright(audio, &tmpStr)) {
+          if(tmpStr) {
+            o["copyright"] = picojson::value(std::string(tmpStr));
+            free(tmpStr);
+            tmpStr = NULL;
+          }
+        }
+        if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_bit_rate(audio, &tmpInt)){
+          o["bitrate"] = picojson::value(static_cast<double>(tmpInt));
+        }
+        if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_track_num (audio, &tmpStr)){
+          if(tmpStr) {
+            o["trackNumber"] = picojson::value(static_cast<double>(std::stoi(tmpStr)));
+            free(tmpStr);
+            tmpStr = NULL;
+          }
+        }
+        if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_duration(audio, &tmpInt) ) {
+          o["duration"] = picojson::value(static_cast<double>(tmpInt));          
+        }
+        
+      }
+    }
+    else {
+      o["type"] = picojson::value(std::string("OTHER"));
+    }
+  }
+
+  ret = media_info_get_media_id(info, &tmpStr);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    if(tmpStr) {
+      o["id"] = picojson::value(std::string(tmpStr));
+      free(tmpStr);
+      tmpStr = NULL;
+    }
+  }
+  
+  ret = media_info_get_display_name(info, &tmpStr);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    if(tmpStr) {
+      o["name"] = picojson::value(std::string(tmpStr));      
+      free(tmpStr);
+      tmpStr = NULL;
+    }
+  }
+
+  ret = media_info_get_mime_type(info, &tmpStr);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    if(tmpStr) {
+      o["mimeType"] = picojson::value(std::string(tmpStr));
+      free(tmpStr);
+      tmpStr = NULL;
+    }
+  }    
+
+  ret = media_info_get_title(info, &tmpStr);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    if(tmpStr) {
+      o["title"] = picojson::value(std::string(tmpStr));
+      free(tmpStr);
+      tmpStr = NULL;
+    }
+  }
+  ret = media_info_get_file_path(info, &tmpStr);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    if(tmpStr) {
+      o["contentURI"] = picojson::value(std::string(tmpStr));
+      free(tmpStr);
+      tmpStr = NULL;
+    }
+  }
+  //dykim. thumbnailURIs
+  ret = media_info_get_thumbnail_path(info, &tmpStr);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    if(tmpStr) {
+      picojson::array thumbnails;
+      thumbnails.push_back(picojson::value(std::string(tmpStr)));
+      o["thumbnailURIs"] = picojson::value(thumbnails);
+      tmpStr = NULL;
+    }
+  }
+
+  ret = media_info_get_description(info, &tmpStr);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    if(tmpStr) {
+      o["description"] = picojson::value(std::string(tmpStr));
+      free(tmpStr);
+      tmpStr = NULL;
+    }
+  }
+
+  ret = media_info_get_rating(info, &tmpInt);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    o["rating"] = picojson::value(static_cast<double>(tmpInt));
+  }
+
+  ret = media_info_get_size(info, &tmpLong);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    o["size"] = picojson::value(static_cast<double>(tmpLong));
+  }
+
+  ret = media_info_get_favorite(info, &tmpBool);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    o["isFavorite"] = picojson::value(tmpBool);    
+  }
+
+  ret = media_info_get_modified_time(info, &tmpDate);
+  if(ret == MEDIA_CONTENT_ERROR_NONE) {
+    std::stringstream str_date;
+    str_date << tmpDate;
+    o.insert(std::make_pair(std::string("modifiedDate"), str_date.str()));
+  }  
+}
+
+static int setContent(media_info_h media, picojson::value content) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::setContent start");
+  
+  int ret;
+  std::string name = content.get("name").to_str();
+  std::string description = content.get("description").to_str();
+  std::string rating = content.get("rating").to_str();
+  std::string is_fav = content.get("isFavorite").to_str();
+
+  if (media != NULL) {
+    media_content_type_e type;
+    ret = media_info_get_media_type(media, &type);
+    if (ret != MEDIA_CONTENT_ERROR_NONE ) {
+      return ret;
+    }
+    ret = media_info_set_display_name(media, name.c_str());
+    if ( ret != MEDIA_CONTENT_ERROR_NONE) {
+      LoggerD("Updating name is failed.");
+    }
+    ret = media_info_set_description(media, description.c_str());
+    if ( ret != MEDIA_CONTENT_ERROR_NONE) {
+      LoggerD("Updating description is failed.");
+    }
+    ret = media_info_set_rating(media, std::stoi(rating));
+    if ( ret != MEDIA_CONTENT_ERROR_NONE) {
+      LoggerD("Updating rating is failed.");
+    }
+
+    if (is_fav == "true") {
+      ret = media_info_set_favorite(media, true);
+    }
+    else if (is_fav == "false") {
+      ret = media_info_set_favorite(media, false);
+    }
+
+    if ( ret != MEDIA_CONTENT_ERROR_NONE) {
+      LoggerD("Updating favorite is failed.");
+    }
+    if (type == MEDIA_CONTENT_TYPE_IMAGE || type == MEDIA_CONTENT_TYPE_VIDEO) {
+      picojson::value geo = content.get("geolocation");
+
+      double latitude = atof(geo.get("latitude").to_str().c_str());
+      double longitude = atof(geo.get("longitude ").to_str().c_str());
+      ret = media_info_set_latitude(media, latitude);
+      if ( ret != MEDIA_CONTENT_ERROR_NONE) {
+        LoggerD("Updating geolocation is failed.");
+      }
+      ret = media_info_set_longitude(media, longitude);
+      if ( ret != MEDIA_CONTENT_ERROR_NONE) {
+        LoggerD("Updating geolocation is failed.");
+      }
+    }
+    ret = MEDIA_CONTENT_ERROR_NONE;
+  }
+  else {
+    ret = MEDIA_CONTENT_ERROR_DB_FAILED;
+  }
+  return ret;
+}
+
+static bool media_foreach_directory_cb(media_folder_h folder, void *user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::media_foreach_directory_cb start");
+  std::vector<media_folder_h> *dir = static_cast<std::vector<media_folder_h>*>(user_data);
+  media_folder_h nfolder = NULL;
+  media_folder_clone (&nfolder, folder);
+  dir->push_back(nfolder);
+
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::media_foreach_directory_cb end");  
+}
+
+static bool media_foreach_content_cb(media_info_h media, void *user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::media_foreach_content_cb start.");
+  picojson::value::array *contents = static_cast<picojson::value::array*>(user_data);
+  picojson::value::object o;
+
+  contentToJson(media, o);
+  contents->push_back(picojson::value(o));  
+  return true;
+}
+
+static bool playlist_foreach_cb(media_playlist_h playlist, void *user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlist_foreach_cb start");
+
+  picojson::value::array *playlists = static_cast<picojson::value::array*>(user_data);
+  picojson::value::object o;
+  if (playlist != NULL) {
+    int id,cnt;
+    char* thumb_path = NULL;
+    char* name = NULL;
+    filter_h filter = NULL;
+    if( media_playlist_get_playlist_id(playlist, &id) == MEDIA_CONTENT_ERROR_NONE) {
+      std::stringstream str_id;
+      str_id << id;
+      o["id"] = picojson::value(std::to_string(id));
+    }
+    else {
+      dlog_print(DLOG_INFO, "DYKIM", "Invalid ID for playlist.");
+    }
+    if( media_playlist_get_thumbnail_path(playlist, &thumb_path) == MEDIA_CONTENT_ERROR_NONE) {
+      if (thumb_path != NULL) {
+        o["thumbnailURI"] = picojson::value(std::string(thumb_path));
+        free(thumb_path);
+      }
+      else {
+       o["thumbnailURI"] = picojson::value();//picojson::value(std::string(""));
+      }
+    }
+    else {
+      dlog_print(DLOG_INFO, "DYKIM", "Invalid thumbnail path for playlist.");
+    }
+    if( media_playlist_get_name(playlist, &name) == MEDIA_CONTENT_ERROR_NONE) {
+      o.insert(std::make_pair(std::string("name"), std::string(name)));
+      free(name);
+    }
+    else {
+      dlog_print(DLOG_INFO, "DYKIM", "Invalid name for playlist.");
+    }
+
+//    media_filter_create(&filter);
+//    if( media_playlist_get_media_count_from_db(id, filter, &cnt) == MEDIA_CONTENT_ERROR_NONE) {
+//      std::stringstream str_cnd;
+//      str_cnd << cnt;
+      o.insert(std::make_pair(std::string("numberOfTracks"), std::to_string(0)));
+//    }
+//    else {
+//      dlog_print(DLOG_INFO, "DYKIM", "Invalid count for playlist.");
+//    }
+    playlists->push_back(picojson::value(o));
+
+  }
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlist_foreach_cb end.");
+  return true;
+}
+
+static bool playlist_content_member_cb(int playlist_member_id, media_info_h media, void *user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlist_content_member_cb start.");
+  
+  picojson::value::array *contents = static_cast<picojson::value::array*>(user_data);
+  picojson::value::object o;
+  char *name = NULL;
+  
+  media_info_get_display_name(media, &name);
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlist_content_member_cb %s.",name);
+  o["playlist_member_id"] = picojson::value(static_cast<double>(playlist_member_id));  
+  contentToJson(media, o);
+  contents->push_back(picojson::value(o));
+  return true;
+}
+
+
+ContentManager::ContentManager() {
+  LoggerE("ContentManager called");
+  if(media_content_connect() == MEDIA_CONTENT_ERROR_NONE) {
+      m_dbConnected = true;
+  }
+  else
+      m_dbConnected = false;
+}
+
+ContentManager::~ContentManager() {
+  if(m_dbConnected) {
+    if(media_content_disconnect() == MEDIA_CONTENT_ERROR_NONE) {
+      m_dbConnected = false;
+    }
+  }
+}
+
+ContentManager* ContentManager::getInstance() {
+  static ContentManager instance;
+  return &instance;
+}
+
+bool ContentManager::isConnected() {
+  return m_dbConnected;
+}
+
+void ContentManager::getDirectories(const std::shared_ptr<ReplyCallbackData>& user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::getDirectories start");
+  
+  picojson::value::array pico_dirs;
+  
+  int ret = MEDIA_CONTENT_ERROR_NONE;
+  filter_h filter = NULL;
+  std::vector<media_folder_h> dirs;
+  
+  ret = media_folder_foreach_folder_from_db(filter, media_foreach_directory_cb, &dirs);
+
+  if (ret == MEDIA_CONTENT_ERROR_NONE) {
+    for(std::vector<media_folder_h>::iterator it = dirs.begin(); it != dirs.end(); ++it) {
+      char *name = NULL;
+      char *id = NULL;
+      char *path = NULL;
+      time_t date;
+      media_content_storage_e storageType;
+      picojson::value::object o;
+
+      media_folder_get_folder_id(*it, &id);
+      media_folder_get_name(*it, &name);
+      media_folder_get_path(*it, &path);
+      media_folder_get_modified_time(*it, &date);
+      media_folder_get_storage_type(*it, &storageType);
+
+      o["id"] = picojson::value(std::string(id));
+      o["directoryURI"] = picojson::value(std::string(path));
+      o["title"] = picojson::value(std::string(name));
+
+      if (storageType == MEDIA_CONTENT_STORAGE_INTERNAL) {
+        o["storageType"] = picojson::value(std::string("INTERNAL"));
+      } else if (storageType == MEDIA_CONTENT_STORAGE_EXTERNAL) {
+        o["storageType"] = picojson::value(std::string("EXTERNAL"));
+      }
+
+      char tmp[128];
+      ctime_r(&date, tmp);    
+      o["modifiedDate"] = picojson::value(std::string(tmp));
+      pico_dirs.push_back(picojson::value(o));
+
+      free(name);
+      free(id);
+      free(path);
+    }
+    user_data->isSuccess = true;
+    user_data->result = picojson::value(pico_dirs);
+  }
+  else {
+    UnknownException err("Getting the directories is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+  }
+
+}
+
+void ContentManager::find(const std::shared_ptr<ReplyCallbackData>& user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::find start");
+  int ret;
+  double count, offset;
+  std::string dirId, attributeName, matchFlag, matchValue;
+  std::string sortModeName, sortModeOrder;
+  media_content_order_e order;
+
+  picojson::value::array arrayContent;
+  filter_h filter = NULL;
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::find start1");
+  ret = media_filter_create(&filter);
+
+  if(ret != MEDIA_CONTENT_ERROR_NONE) {
+    UnknownException err("Memory allcation for filter is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+    return;    
+  }
+  if(user_data->args.contains("filter")) {
+    //dykim. filter
+    picojson::value vfilter = user_data->args.get("filter");
+    if (!vfilter.is<picojson::null>() && vfilter.is<picojson::object>()) {
+      attributeName = vfilter.get("attributeName").to_str();
+      matchFlag = vfilter.get("matchFlag").to_str();
+      matchValue = vfilter.get("matchValue").to_str();
+    }
+  }
+  if(user_data->args.contains("sortMode")) {
+    picojson::value vSortMode = user_data->args.get("sortMode");
+    if (!vSortMode.is<picojson::null>() && vSortMode.is<picojson::object>()) {
+      sortModeName = vSortMode.get("attributeName").to_str();
+      sortModeOrder = vSortMode.get("order").to_str();
+      if ( !sortModeOrder.empty() ) {
+        if( sortModeOrder == "ASC" ) {
+          order = MEDIA_CONTENT_ORDER_ASC;
+        }
+        else if( sortModeOrder == "DESC" ) {
+          order = MEDIA_CONTENT_ORDER_DESC;
+        }
+        ret = media_filter_set_order(filter, order, sortModeName.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT );
+        if (MEDIA_CONTENT_ERROR_NONE != ret )
+        {
+          LoggerD("Platform SortMode setting is failed.");
+        }
+      }
+    }
+  }
+  if(user_data->args.contains("count")) {
+    count = user_data->args.get("count").get<double>();
+  }
+  else {
+    count = -1;
+  }
+  if(user_data->args.contains("offset")) {
+    offset = user_data->args.get("offset").get<double>();
+  }
+  else {
+    offset = -1;
+  }
+  ret = media_filter_set_offset(filter, offset, count);
+  if ( MEDIA_CONTENT_ERROR_NONE != ret) {
+    LoggerD("A platform error occurs in media_filter_set_offset.");
+  }
+  if(user_data->args.contains("directoryId")) {
+    dirId = user_data->args.get("directoryId").get<std::string>();
+    ret = media_folder_foreach_media_from_db(dirId.c_str(), filter, media_foreach_content_cb, static_cast<void*>(&arrayContent));
+  }
+  else {
+    ret = media_info_foreach_media_from_db(filter, media_foreach_content_cb, static_cast<void*>(&arrayContent));
+  }
+  media_filter_destroy(filter);
+
+  if (ret == MEDIA_CONTENT_ERROR_NONE) {
+    user_data->isSuccess = true;
+    user_data->result = picojson::value(arrayContent);
+  }
+  else {
+    UnknownException err("The iteration is failed in platform.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+  }
+}
+
+int ContentManager::scanFile(std::string& uri) {
+  return media_content_scan_file(uri.c_str());
+}
+
+int ContentManager::setChangeListener(media_content_db_update_cb callback, void *user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::setChangeListener start");
+
+  int ret = media_content_set_db_updated_cb(callback, user_data);
+  if(ret != MEDIA_CONTENT_ERROR_NONE) {
+    throw UnknownException("registering the listener is failed.");
+  }
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::media_content_db_update_cb end");
+}
+
+void ContentManager::unSetChangeListener() {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::unSetChangeListener start");
+  int ret = media_content_unset_db_updated_cb();
+  if(ret != MEDIA_CONTENT_ERROR_NONE) {
+    throw UnknownException("unSetChangeListener is failed.");
+  }
+}
+
+void ContentManager::createPlaylist(std::string name, 
+  const std::shared_ptr<ReplyCallbackData>& user_data) {
+  
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::createPlaylist start");
+  media_playlist_h     playlist = NULL;
+
+  int ret = media_playlist_insert_to_db(name.c_str(),&playlist);
+  if(ret != MEDIA_CONTENT_ERROR_NONE) { 
+    UnknownException err("creation of playlist is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();    
+  }
+  picojson::value::object o;
+  
+  if( playlist != NULL) {
+    int id,cnt;
+    char* thumb_path = NULL;
+    char* name = NULL;
+    filter_h filter = NULL;
+    if( media_playlist_get_playlist_id(playlist, &id) == MEDIA_CONTENT_ERROR_NONE) {
+      o.insert(std::make_pair(std::string("id"), std::to_string(id)));
+    }
+    else {
+      UnknownException err("loading of playlist is failed.");
+      user_data->isSuccess = false;
+      user_data->result = err.ToJSON();
+      return;
+    }
+    if( media_playlist_get_thumbnail_path(playlist, &thumb_path) == MEDIA_CONTENT_ERROR_NONE) {
+      if (thumb_path != NULL) {
+        o["thumbnailURI"] = picojson::value(std::string(thumb_path));
+        free(thumb_path);
+      }
+      else {
+        o["thumbnailURI"] = picojson::value();
+      }
+    }
+    else {
+      dlog_print(DLOG_INFO, "DYKIM", "Invalid thumbnail path for playlist.");
+    }
+    if( media_playlist_get_name(playlist, &name) == MEDIA_CONTENT_ERROR_NONE) {
+      o["name"] = picojson::value(std::string(name));      
+      free(name);
+    }
+    else {
+      dlog_print(DLOG_INFO, "DYKIM", "Invalid name for playlist.");
+    }
+    media_filter_create(&filter);
+    if( media_playlist_get_media_count_from_db(id, filter, &cnt) == MEDIA_CONTENT_ERROR_NONE) {
+      o["numberOfTracks"] = picojson::value(static_cast<double>(cnt));
+    }
+    else {
+      dlog_print(DLOG_INFO, "DYKIM", "Invalid count for playlist.");
+    }
+  }
+  user_data->isSuccess = true;
+  user_data->result = picojson::value(o);
+
+}
+
+void ContentManager::getPlaylists(const std::shared_ptr<ReplyCallbackData>& user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::getPlaylist start");
+  int ret;
+  filter_h     filter;
+  media_filter_create(&filter);
+  picojson::value::array playlists;
+  
+  ret = media_playlist_foreach_playlist_from_db(filter, playlist_foreach_cb, static_cast<void*>(&playlists));
+
+  if(ret != MEDIA_CONTENT_ERROR_NONE) {
+    UnknownException err("Getting playlist is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();      
+  }
+  user_data->isSuccess = true;
+  user_data->result = picojson::value(playlists);
+}
+
+void ContentManager::removePlaylist(std::string playlistId, 
+  const std::shared_ptr<ReplyCallbackData>& user_data) {
+  
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::removePlaylist start");
+  int id = std::stoi(playlistId);
+  int ret = media_playlist_delete_from_db(id);
+
+  if(ret != MEDIA_CONTENT_ERROR_NONE) {
+    UnknownException err("Removal of playlist is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();      
+  }
+}
+
+int ContentManager::update(picojson::value args) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::update start");
+
+  int ret;
+  picojson::value content = args.get("content");
+  std::string id = content.get("id").to_str();
+
+  media_info_h media = NULL;
+  ret = media_info_get_media_from_db (id.c_str(), &media);
+  if (media != NULL) {
+    setContent(media, content);
+    ret = media_info_update_to_db(media);
+  }
+  else {
+    LoggerD("There is no content(%s)",id.c_str());
+    ret = MEDIA_CONTENT_ERROR_NONE;
+  }
+  return ret;
+}
+
+
+int ContentManager::updateBatch(picojson::value args) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::updateBatch start");
+
+  int ret;
+  std::vector<picojson::value> contents = args.get("contents").get<picojson::array>();
+  for (picojson::value::array::iterator it = contents.begin(); it != contents.end(); it++) {
+    picojson::value content = *it;
+    std::string id = content.get("id").to_str();
+    media_info_h media = NULL;
+    ret = media_info_get_media_from_db (id.c_str(), &media);
+    if (media != NULL && ret == MEDIA_CONTENT_ERROR_NONE) {
+      setContent(media, content);
+      ret = media_info_update_to_db(media);
+    }
+    else {
+      return ret;
+    }
+  }
+  return ret;
+}
+
+
+
+int ContentManager::playlistAdd(std::string playlist_id, std::string content_id) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlistAdd start");
+  int ret = MEDIA_CONTENT_ERROR_NONE;
+
+  media_playlist_h playlist = NULL;
+  ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
+
+  if (playlist != NULL && ret == MEDIA_CONTENT_ERROR_NONE) {
+    ret = media_playlist_add_media(playlist, content_id.c_str());
+    if (ret != MEDIA_CONTENT_ERROR_NONE) {
+      LoggerD("The content(id:%s) can't add to playlist",content_id.c_str());      
+    }
+
+    ret = media_playlist_update_to_db(playlist);
+    if (ret != MEDIA_CONTENT_ERROR_NONE) {
+      LoggerD("The content(id:%s) can't add to playlist",content_id.c_str());
+    }
+  }
+  else {
+    LoggerD("Playlist(id:%s) is not exist",playlist_id.c_str());
+  }
+  
+  media_playlist_destroy(playlist);
+  return ret;
+}
+
+int ContentManager::playlistRemove(std::string playlist_id, int member_id) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlistRemove start");
+  int ret = MEDIA_CONTENT_ERROR_NONE;
+
+  media_playlist_h playlist = NULL;
+  ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlistRemove member_id(%d)", member_id);
+  if (playlist != NULL && ret == MEDIA_CONTENT_ERROR_NONE) {
+    ret = media_playlist_remove_media(playlist, member_id);
+    if (ret != MEDIA_CONTENT_ERROR_NONE) {
+      LoggerD("The content can't remove to playlist");      
+    }
+
+    ret = media_playlist_update_to_db(playlist);
+    if (ret != MEDIA_CONTENT_ERROR_NONE) {
+      LoggerD("The content can't remove to playlist");
+    }
+  }
+  else {
+    LoggerD("Playlist(id:%s) is not exist",playlist_id.c_str());
+  }
+  media_playlist_destroy(playlist);
+  
+  return ret;
+}
+
+
+void ContentManager::playlistAddbatch(const std::shared_ptr<ReplyCallbackData>& user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlistAddbatch start");
+  
+  int ret = MEDIA_CONTENT_ERROR_NONE;
+  std::string playlist_id = user_data->args.get("playlist_id").get<std::string>();
+
+  media_playlist_h playlist = NULL;  
+  ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
+
+  if(ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) { 
+    UnknownException err("Getting playlist is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+    return;
+  }
+  
+  std::vector<picojson::value> contents = user_data->args.get("contents").get<picojson::array>();
+  for (picojson::value::array::iterator it = contents.begin(); it != contents.end(); it++) {
+    picojson::value content = *it;
+    std::string id = content.get("id").to_str();
+    dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlistAddbatch id(%s)",id.c_str());
+    ret = media_playlist_add_media(playlist, id.c_str());
+    if (ret != MEDIA_CONTENT_ERROR_NONE) {
+      dlog_print(DLOG_INFO, "DYKIM", "Adding Content(id:%s) is failed.", id.c_str());
+    }
+  }
+
+  ret = media_playlist_update_to_db(playlist);
+  if(ret != MEDIA_CONTENT_ERROR_NONE ) {
+    UnknownException err("Adding playlist is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+  }
+  media_playlist_destroy(playlist);
+}
+
+void ContentManager::playlistGet(const std::shared_ptr<ReplyCallbackData>& user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlistGet start");
+  
+  int ret = MEDIA_CONTENT_ERROR_NONE;
+  media_playlist_h playlist = NULL;  
+
+  std::string playlist_id = user_data->args.get("playlist_id").get<std::string>();
+  ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
+  if(ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) { 
+    UnknownException err("Getting playlist is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+    return;
+  }
+
+  filter_h filter = NULL;
+  ret = media_filter_create(&filter);
+  if (ret != MEDIA_CONTENT_ERROR_NONE) {
+    UnknownException err("Creating a filter is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+    return;    
+  }
+
+  int count = user_data->args.get("count").get<double>();
+  int offset = user_data->args.get("offset").get<double>();
+  ret = media_filter_set_offset(filter, offset, count);
+  if (ret != MEDIA_CONTENT_ERROR_NONE) {
+    LoggerD("Setting a offset/count is failed.");
+  }
+  picojson::value::array arrayContent;
+  ret = media_playlist_foreach_media_from_db(std::stoi(playlist_id),
+    filter, playlist_content_member_cb, static_cast<void*>(&arrayContent));
+
+  media_filter_destroy(filter);
+  if (ret == MEDIA_CONTENT_ERROR_NONE) {
+    user_data->isSuccess = true;
+    user_data->result = picojson::value(arrayContent);
+  }
+  else {
+    UnknownException err("Creating a filter is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+  }
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlistGet start7");  
+}
+
+void ContentManager::playlistRemovebatch(const std::shared_ptr<ReplyCallbackData>& user_data) {
+
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlistRemovebatch start");
+  
+  int ret = MEDIA_CONTENT_ERROR_NONE;
+  media_playlist_h playlist = NULL;  
+
+  std::string playlist_id = user_data->args.get("playlist_id").get<std::string>();
+  ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
+  if(ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) { 
+    UnknownException err("Getting playlist is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+    return;
+  }
+
+  std::vector<picojson::value> members = user_data->args.get("members").get<picojson::array>();
+  for( int i = 0; i < members.size(); i++ ) {
+    int member_id = static_cast<int>(members.at(i).get<double>());
+    ret = media_playlist_remove_media(playlist, member_id);
+
+    if (ret != MEDIA_CONTENT_ERROR_NONE) {
+      LoggerD("Removing a content is failed.");
+    }
+  }
+
+  ret = media_playlist_update_to_db(playlist);
+  if (ret != MEDIA_CONTENT_ERROR_NONE) {
+    UnknownException err("Removing the contents is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();    
+  }
+  else {
+    user_data->isSuccess = true;
+  }
+}
+
+void ContentManager::playlistSetOrder(const std::shared_ptr<ReplyCallbackData>& user_data) {
+
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlistSetOrder start");
+  
+  int ret = MEDIA_CONTENT_ERROR_NONE;
+  media_playlist_h playlist = NULL;
+
+  std::string playlist_id = user_data->args.get("playlist_id").get<std::string>();
+  ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
+  if(ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
+    UnknownException err("Getting playlist is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+    return;
+  }
+
+  int cnt;
+  std::vector<picojson::value> members = user_data->args.get("members").get<picojson::array>();  
+  
+  ret = media_playlist_get_media_count_from_db(std::stoi(playlist_id), NULL, &cnt);
+
+  if ( cnt != members.size() ) {
+    InvalidValuesException err("The items array does not contain all items from the playlist.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+    return;    
+  }
+  
+  for( int i = 0; i < members.size(); i++ ) {
+    int member_id = static_cast<int>(members.at(i).get<double>());
+    ret = media_playlist_set_play_order(playlist, member_id, i);
+    if (ret != MEDIA_CONTENT_ERROR_NONE) {
+      LoggerD("Removing a content is failed.");
+    }
+  }
+  
+  ret = media_playlist_update_to_db(playlist);
+  if (ret != MEDIA_CONTENT_ERROR_NONE) {
+    UnknownException err("Removing the contents is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();    
+  }
+  else {
+    user_data->isSuccess = true;
+  }
+}
+
+void ContentManager::playlistMove(const std::shared_ptr<ReplyCallbackData>& user_data) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::playlistMove start");
+  
+  int ret = MEDIA_CONTENT_ERROR_NONE;
+  media_playlist_h playlist = NULL;
+
+  std::string playlist_id = user_data->args.get("playlist_id").get<std::string>();
+  ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
+  if(ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
+    UnknownException err("Getting playlist is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+    return;
+  }
+  int old_order;
+  double member_id = user_data->args.get("member_id").get<double>();
+  long delta = user_data->args.get("delta").get<long>();  
+  ret = media_playlist_get_play_order(playlist, static_cast<int>(member_id), &old_order);
+  if (ret != MEDIA_CONTENT_ERROR_NONE) {
+    UnknownException err("The content can't find form playlist.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+    return;
+  }
+
+  int new_order = static_cast<int>(old_order) + static_cast<int>(delta);
+  ret = media_playlist_set_play_order(playlist, static_cast<int>(member_id), new_order);
+  if (ret != MEDIA_CONTENT_ERROR_NONE) {
+    UnknownException err("The content can't update play_order.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();
+    return;
+  }
+
+  ret = media_playlist_update_to_db(playlist);
+  if (ret != MEDIA_CONTENT_ERROR_NONE) {
+    UnknownException err("Updateing play_order is failed.");
+    user_data->isSuccess = false;
+    user_data->result = err.ToJSON();    
+  }
+  else {
+    user_data->isSuccess = true;
+  }  
+}
+
+int ContentManager::getLyrics(const picojson::value& args, picojson::object& result) {
+
+  int ret = METADATA_EXTRACTOR_ERROR_NONE;
+  std::string contentURI = convertUriToPath(args.get("contentURI").get<std::string>());
+  metadata_extractor_h extractor;
+  
+  if (!(contentURI.empty())) {
+    ret = metadata_extractor_set_path(extractor, contentURI.c_str());
+    if (ret != METADATA_EXTRACTOR_ERROR_NONE) {
+      return -1;
+    }
+    picojson::array timestamps;
+    picojson::array texts;
+    char* strSyncTextNum=NULL;
+    metadata_extractor_attr_e attr = METADATA_SYNCLYRICS_NUM;
+    ret = metadata_extractor_get_metadata(extractor, attr, &strSyncTextNum);
+    if (ret = METADATA_EXTRACTOR_ERROR_NONE && strSyncTextNum ) {
+      int nSyncTextNum = atoi(strSyncTextNum);
+      free(strSyncTextNum);
+      strSyncTextNum = NULL;
+      if (nSyncTextNum > 0) {
+        result["type"] = picojson::value(std::string("SYNCHRONIZED"));
+        for(int i=0; i < nSyncTextNum; i++) {
+          unsigned long time_info = 0;
+          char * lyrics = NULL;
+          ret = metadata_extractor_get_synclyrics(extractor, i, &time_info, &lyrics);
+          if (ret == METADATA_EXTRACTOR_ERROR_NONE) {
+            timestamps.push_back(picojson::value(static_cast<double>(time_info)));
+            texts.push_back(picojson::value(std::string(lyrics)));
+            free(lyrics);
+          }
+        }
+        result["texts"] = picojson::value(texts);
+        result["timestamps"] = picojson::value(timestamps);
+        ret = METADATA_EXTRACTOR_ERROR_NONE;
+      }
+      else {
+        char* unSyncText = NULL;
+        attr = METADATA_UNSYNCLYRICS;
+        ret = metadata_extractor_get_metadata(extractor, attr, &unSyncText);
+        if (ret == METADATA_EXTRACTOR_ERROR_NONE) {
+          result["type"] = picojson::value(std::string("UNSYNCHRONIZED"));
+          texts.push_back(picojson::value(std::string(unSyncText)));
+          result["texts"] = picojson::value(texts);
+          free(unSyncText);
+        }
+      }
+    }
+  }
+  return ret;
+}
+
+
+common::PlatformException ContentManager::convertError(int err) {
+  dlog_print(DLOG_INFO, "DYKIM", "ContentManager::convertError start");
+  switch (err) {
+    case MEDIA_CONTENT_ERROR_INVALID_PARAMETER :
+      return common::InvalidValuesException("Invalid parameter.");
+    case MEDIA_CONTENT_ERROR_OUT_OF_MEMORY :
+      return common::UnknownException("Out of memory.");
+    case MEDIA_CONTENT_ERROR_INVALID_OPERATION :
+      return common::UnknownException("Invalid Operation.");
+    case MEDIA_CONTENT_FILE_NO_SPACE_ON_DEVICE :
+      return common::UnknownException("No space left on device.");
+    case MEDIA_CONTENT_ERROR_PERMISSION_DENIED :
+      return common::UnknownException("Permission denied.");
+    case MEDIA_CONTENT_ERROR_DB_FAILED :
+      return common::UnknownException("DB operation failed.");
+    case MEDIA_CONTENT_ERROR_DB_BUSY :
+      return common::UnknownException("DB operation BUSY.");
+    case MEDIA_CONTENT_ERROR_NETWORK :
+      return common::UnknownException("Network Fail.");
+    case MEDIA_CONTENT_ERROR_UNSUPPORTED_CONTENT :
+      return common::UnknownException("Unsupported Content.");
+    default:
+      return common::UnknownException("Unknown error.");
+  }
+}
+
+} // namespace content
+} // namespace extension
+
diff --git a/src/content/content_manager.h b/src/content/content_manager.h
new file mode 100755 (executable)
index 0000000..ce27ee4
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_MANAGER_H_
+#define CONTENT_MANAGER_H_
+
+#include "common/extension.h"
+#include "common/picojson.h"
+#include "common/platform_exception.h"
+
+#include <string>
+#include <list>
+#include <media_content.h>
+#include <glib.h>
+
+#include "content_instance.h"
+
+namespace extension {
+namespace content {
+
+class ContentManager {
+ public:
+  virtual ~ContentManager();
+  bool isConnected();
+  static ContentManager* getInstance();
+
+  void getDirectories(const std::shared_ptr<ReplyCallbackData>& user_data);
+  void find(const std::shared_ptr<ReplyCallbackData>& user_data);
+  int update(picojson::value args);
+  int updateBatch(picojson::value args);
+  void contentToJson(media_info_h media, picojson::object& o);
+  //directorytoJson
+  
+  int scanFile(std::string& uri);
+  int setChangeListener(media_content_db_update_cb callback, void *user_data);
+  void unSetChangeListener();
+
+//Lyrics
+  int getLyrics(const picojson::value& args,picojson::object& result);
+
+//playlist
+  void createPlaylist(std::string name, const std::shared_ptr<ReplyCallbackData>& user_data);
+  void getPlaylists(const std::shared_ptr<ReplyCallbackData>& user_data);
+  void removePlaylist(std::string playlistId, const std::shared_ptr<ReplyCallbackData>& user_data);  
+  int playlistAdd(std::string playlist_id, std::string content_id);
+  int playlistRemove(std::string playlist_id, int member_id);
+  void playlistAddbatch(const std::shared_ptr<ReplyCallbackData>& user_data);
+  void playlistGet(const std::shared_ptr<ReplyCallbackData>& user_data);
+  void playlistRemovebatch(const std::shared_ptr<ReplyCallbackData>& user_data);
+  void playlistSetOrder(const std::shared_ptr<ReplyCallbackData>& user_data);
+  void playlistMove(const std::shared_ptr<ReplyCallbackData>& user_data);  
+  
+//playlistSetOrder
+  common::PlatformException convertError(int err);
+ private:
+  //int setContent(media_info_h media, picojson::value content);
+  ContentManager();
+
+ private:
+  bool m_dbConnected;
+
+};
+
+} // namespace power
+} // namespace extension
+
+#endif
+
old mode 100644 (file)
new mode 100755 (executable)
index 3a79c8c..88db812
@@ -18,6 +18,7 @@
         'exif/exif.gyp:*',
         'websetting/websetting.gyp:*',
         'systemsetting/systemsetting.gyp:*',
+       'content/content.gyp:*',
       ],
       'conditions': [
         [