Merge branch 'tizen_3.0' into tizen_4.0
[platform/core/api/webapi-plugins.git] / src / content / content_manager.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "content/content_manager.h"
18
19 #include <metadata_extractor.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <algorithm>
23 #include <cstring>
24 #include <map>
25 #include <sstream>
26 #include <string>
27
28 #include "common/converter.h"
29 #include "common/filesystem/filesystem_provider.h"
30 #include "common/logger.h"
31 #include "common/scope_exit.h"
32 #include "common/tools.h"
33
34 #include "content/content_filter.h"
35
36 using namespace std;
37 using namespace common;
38
39 using common::tools::ReportSuccess;
40 using common::tools::ReportError;
41
42 namespace extension {
43 namespace content {
44
45 namespace {
46 static const std::string uri_prefix = "file://";
47 static const std::string uri_absolute_prefix = "file:///";
48 }
49
50 const std::map<std::string, media_content_orientation_e> orientationMap = {
51     {"NORMAL", MEDIA_CONTENT_ORIENTATION_NORMAL},
52     {"FLIP_HORIZONTAL", MEDIA_CONTENT_ORIENTATION_HFLIP},
53     {"ROTATE_180", MEDIA_CONTENT_ORIENTATION_ROT_180},
54     {"FLIP_VERTICAL", MEDIA_CONTENT_ORIENTATION_VFLIP},
55     {"TRANSPOSE", MEDIA_CONTENT_ORIENTATION_TRANSPOSE},
56     {"ROTATE_90", MEDIA_CONTENT_ORIENTATION_ROT_90},
57     {"TRANSVERSE", MEDIA_CONTENT_ORIENTATION_TRANSVERSE},
58     {"ROTATE_270", MEDIA_CONTENT_ORIENTATION_ROT_270},
59 };
60
61 std::string get_date(char* tmpStr) {
62   ScopeLogger();
63   if (tmpStr) {
64     struct tm* result = (struct tm*)calloc(1, sizeof(struct tm));
65     if (nullptr != result) {
66       if (strptime(tmpStr, "%Y:%m:%d %H:%M:%S", result) == NULL) {
67         free(result);
68         return std::string();
69       } else {
70         time_t t = mktime(result);  // + get_utc_offset() * 3600;
71         std::stringstream str_date;
72         str_date << t;
73         free(result);
74         return str_date.str();
75       }
76     }
77   }
78   return std::string();
79 }
80
81 void ContentToJson(media_info_h info, picojson::object& o) {
82   ScopeLogger();
83   int ret;
84   int tmpInt = 0;
85   bool tmpBool = false;
86   char* tmpStr = NULL;
87   time_t tmpDate;
88   double tmpDouble;
89   long long unsigned int tmpLong;
90   media_content_type_e type;
91
92   ret = media_info_get_media_type(info, &type);
93
94   if (ret != MEDIA_CONTENT_ERROR_NONE) {
95     LoggerE("Get media type failed: %d", ret);
96     type = MEDIA_CONTENT_TYPE_OTHERS;
97   }
98
99   if (type == MEDIA_CONTENT_TYPE_IMAGE) {
100     o["type"] = picojson::value(std::string("IMAGE"));
101     image_meta_h img;
102     if (MEDIA_CONTENT_ERROR_NONE == media_info_get_image(info, &img)) {
103       std::unique_ptr<std::remove_pointer<image_meta_h>::type, int (*)(image_meta_h)> img_ptr(
104           img, &image_meta_destroy);  // automatically release the memory
105       if (MEDIA_CONTENT_ERROR_NONE == image_meta_get_date_taken(img, &tmpStr)) {
106         if (tmpStr) {
107           o["releaseDate"] = picojson::value(get_date(tmpStr));
108           free(tmpStr);
109           tmpStr = NULL;
110         }
111       }
112       if (MEDIA_CONTENT_ERROR_NONE == image_meta_get_width(img, &tmpInt)) {
113         o["width"] = picojson::value(static_cast<double>(tmpInt));
114       }
115       if (MEDIA_CONTENT_ERROR_NONE == image_meta_get_height(img, &tmpInt)) {
116         o["height"] = picojson::value(static_cast<double>(tmpInt));
117       }
118       picojson::object geo;
119       if (MEDIA_CONTENT_ERROR_NONE == media_info_get_latitude(info, &tmpDouble)) {
120         geo["latitude"] = picojson::value(tmpDouble);
121       }
122       if (MEDIA_CONTENT_ERROR_NONE == media_info_get_longitude(info, &tmpDouble)) {
123         geo["longitude"] = picojson::value(tmpDouble);
124       }
125       o["geolocation"] = picojson::value(geo);
126       std::string ori;
127       media_content_orientation_e orientation;
128       if (MEDIA_CONTENT_ERROR_NONE == image_meta_get_orientation(img, &orientation)) {
129         switch (orientation) {
130           case MEDIA_CONTENT_ORIENTATION_NOT_AVAILABLE:
131           case MEDIA_CONTENT_ORIENTATION_NORMAL:
132             ori = "NORMAL";
133             break;
134           case MEDIA_CONTENT_ORIENTATION_HFLIP:
135             ori = "FLIP_HORIZONTAL";
136             break;
137           case MEDIA_CONTENT_ORIENTATION_ROT_180:
138             ori = "ROTATE_180";
139             break;
140           case MEDIA_CONTENT_ORIENTATION_VFLIP:
141             ori = "FLIP_VERTICAL";
142             break;
143           case MEDIA_CONTENT_ORIENTATION_TRANSPOSE:
144             ori = "TRANSPOSE";
145             break;
146           case MEDIA_CONTENT_ORIENTATION_ROT_90:
147             ori = "ROTATE_90";
148             break;
149           case MEDIA_CONTENT_ORIENTATION_TRANSVERSE:
150             ori = "TRANSVERSE";
151             break;
152           case MEDIA_CONTENT_ORIENTATION_ROT_270:
153             ori = "ROTATE_270";
154             break;
155         }
156         o["orientation"] = picojson::value(ori);
157       }
158     }
159   } else if (type == MEDIA_CONTENT_TYPE_VIDEO) {
160     o["type"] = picojson::value(std::string("VIDEO"));
161     video_meta_h video;
162     if (MEDIA_CONTENT_ERROR_NONE == media_info_get_video(info, &video)) {
163       std::unique_ptr<std::remove_pointer<video_meta_h>::type, int (*)(video_meta_h)> video_ptr(
164           video, &video_meta_destroy);  // automatically release the memory
165       if (MEDIA_CONTENT_ERROR_NONE == video_meta_get_width(video, &tmpInt)) {
166         o["width"] = picojson::value(static_cast<double>(tmpInt));
167       }
168
169       if (MEDIA_CONTENT_ERROR_NONE == video_meta_get_height(video, &tmpInt)) {
170         o["height"] = picojson::value(static_cast<double>(tmpInt));
171       }
172       if (MEDIA_CONTENT_ERROR_NONE == video_meta_get_artist(video, &tmpStr)) {
173         picojson::array artists;
174         if (tmpStr) {
175           artists.push_back(picojson::value(std::string(tmpStr)));
176           free(tmpStr);
177           tmpStr = NULL;
178         }
179         o["artists"] = picojson::value(artists);
180       }
181       if (MEDIA_CONTENT_ERROR_NONE == video_meta_get_album(video, &tmpStr)) {
182         if (tmpStr) {
183           o["album"] = picojson::value(tmpStr);
184           free(tmpStr);
185           tmpStr = NULL;
186         }
187       }
188       if (MEDIA_CONTENT_ERROR_NONE == video_meta_get_duration(video, &tmpInt)) {
189         o["duration"] = picojson::value(static_cast<double>(tmpInt));
190       }
191       if (MEDIA_CONTENT_ERROR_NONE == video_meta_get_recorded_date(video, &tmpStr)) {
192         if (tmpStr) {
193           o["releaseDate"] = picojson::value(get_date(tmpStr));
194           free(tmpStr);
195           tmpStr = NULL;
196         }
197       }
198     }
199     picojson::object geo;
200     if (MEDIA_CONTENT_ERROR_NONE == media_info_get_latitude(info, &tmpDouble)) {
201       geo["latitude"] = picojson::value(tmpDouble);
202     }
203     if (MEDIA_CONTENT_ERROR_NONE == media_info_get_longitude(info, &tmpDouble)) {
204       geo["longitude"] = picojson::value(tmpDouble);
205     }
206     o["geolocation"] = picojson::value(geo);
207   } else if (type == MEDIA_CONTENT_TYPE_SOUND || type == MEDIA_CONTENT_TYPE_MUSIC) {
208     o["type"] = picojson::value(std::string("AUDIO"));
209     audio_meta_h audio;
210     if (MEDIA_CONTENT_ERROR_NONE == media_info_get_audio(info, &audio)) {
211       std::unique_ptr<std::remove_pointer<audio_meta_h>::type, int (*)(audio_meta_h)> audio_ptr(
212           audio, &audio_meta_destroy);  // automatically release the memory
213       if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_recorded_date(audio, &tmpStr)) {
214         if (tmpStr) {
215           o["releaseDate"] = picojson::value(get_date(tmpStr));
216           free(tmpStr);
217           tmpStr = NULL;
218         }
219       }
220       if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_album(audio, &tmpStr)) {
221         if (tmpStr) {
222           o["album"] = picojson::value(std::string(tmpStr));
223           free(tmpStr);
224           tmpStr = NULL;
225         }
226       }
227       if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_artist(audio, &tmpStr)) {
228         if (tmpStr) {
229           picojson::array artists;
230           artists.push_back(picojson::value(std::string(tmpStr)));
231           o["artists"] = picojson::value(artists);
232           free(tmpStr);
233           tmpStr = NULL;
234         }
235       }
236       if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_genre(audio, &tmpStr)) {
237         if (tmpStr) {
238           picojson::array genres;
239           genres.push_back(picojson::value(std::string(tmpStr)));
240           o["genres"] = picojson::value(genres);
241           free(tmpStr);
242           tmpStr = NULL;
243         }
244       }
245       if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_composer(audio, &tmpStr)) {
246         if (tmpStr) {
247           picojson::array composers;
248           composers.push_back(picojson::value(std::string(tmpStr)));
249           o["composers"] = picojson::value(composers);
250           free(tmpStr);
251           tmpStr = NULL;
252         }
253       }
254       if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_copyright(audio, &tmpStr)) {
255         if (tmpStr) {
256           o["copyright"] = picojson::value(std::string(tmpStr));
257           free(tmpStr);
258           tmpStr = NULL;
259         }
260       }
261       if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_bit_rate(audio, &tmpInt)) {
262         o["bitrate"] = picojson::value(static_cast<double>(tmpInt));
263       }
264       if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_track_num(audio, &tmpStr)) {
265         if (tmpStr) {
266           o["trackNumber"] = picojson::value(static_cast<double>(std::atoi(tmpStr)));
267           free(tmpStr);
268           tmpStr = NULL;
269         } else {
270           o["trackNumber"] = picojson::value();
271         }
272       }
273       if (MEDIA_CONTENT_ERROR_NONE == audio_meta_get_duration(audio, &tmpInt)) {
274         o["duration"] = picojson::value(static_cast<double>(tmpInt));
275       }
276     }
277   } else {
278     o["type"] = picojson::value(std::string("OTHER"));
279   }
280
281   ret = media_info_get_media_id(info, &tmpStr);
282   if (ret == MEDIA_CONTENT_ERROR_NONE) {
283     if (tmpStr) {
284       o["id"] = picojson::value(std::string(tmpStr));
285       free(tmpStr);
286       tmpStr = NULL;
287     }
288   }
289   ret = media_info_get_display_name(info, &tmpStr);
290   if (ret == MEDIA_CONTENT_ERROR_NONE) {
291     if (tmpStr) {
292       o["name"] = picojson::value(std::string(tmpStr));
293       free(tmpStr);
294       tmpStr = NULL;
295     }
296   }
297
298   ret = media_info_get_mime_type(info, &tmpStr);
299   if (ret == MEDIA_CONTENT_ERROR_NONE) {
300     if (tmpStr) {
301       o["mimeType"] = picojson::value(std::string(tmpStr));
302       free(tmpStr);
303       tmpStr = NULL;
304     }
305   }
306   ret = media_info_get_title(info, &tmpStr);
307   if (ret == MEDIA_CONTENT_ERROR_NONE) {
308     if (tmpStr) {
309       o["title"] = picojson::value(std::string(tmpStr));
310       free(tmpStr);
311       tmpStr = NULL;
312     }
313   }
314   ret = media_info_get_file_path(info, &tmpStr);
315   if (ret == MEDIA_CONTENT_ERROR_NONE) {
316     if (tmpStr) {
317       o["contentURI"] = picojson::value(std::string(tmpStr));
318       free(tmpStr);
319       tmpStr = NULL;
320     }
321   }
322   ret = media_info_get_thumbnail_path(info, &tmpStr);
323   if (ret == MEDIA_CONTENT_ERROR_NONE) {
324     if (tmpStr) {
325       picojson::array thumbnails;
326       thumbnails.push_back(picojson::value(std::string(tmpStr)));
327       o["thumbnailURIs"] = picojson::value(thumbnails);
328       free(tmpStr);
329       tmpStr = NULL;
330     }
331   }
332   ret = media_info_get_description(info, &tmpStr);
333   if (ret == MEDIA_CONTENT_ERROR_NONE) {
334     if (tmpStr) {
335       o["description"] = picojson::value(std::string(tmpStr));
336       free(tmpStr);
337       tmpStr = NULL;
338     }
339   }
340   ret = media_info_get_rating(info, &tmpInt);
341   if (ret == MEDIA_CONTENT_ERROR_NONE) {
342     o["rating"] = picojson::value(static_cast<double>(tmpInt));
343   }
344   ret = media_info_get_size(info, &tmpLong);
345   if (ret == MEDIA_CONTENT_ERROR_NONE) {
346     o["size"] = picojson::value(static_cast<double>(tmpLong));
347   }
348   ret = media_info_get_favorite(info, &tmpBool);
349   if (ret == MEDIA_CONTENT_ERROR_NONE) {
350     o["isFavorite"] = picojson::value(tmpBool);
351   }
352   ret = media_info_get_modified_time(info, &tmpDate);
353   if (ret == MEDIA_CONTENT_ERROR_NONE) {
354     o["modifiedDate"] = picojson::value(static_cast<double>(tmpDate));
355   }
356 }
357
358 void ContentDirToJson(media_folder_h folder, picojson::object& o) {
359   ScopeLogger();
360   int ret;
361   char* tmpStr = NULL;
362   media_content_storage_e storage_type;
363   time_t tmpDate;
364
365   // id
366   ret = media_folder_get_folder_id(folder, &tmpStr);
367   if (ret == MEDIA_CONTENT_ERROR_NONE) {
368     if (tmpStr) {
369       o["id"] = picojson::value(std::string(tmpStr));
370       free(tmpStr);
371       tmpStr = NULL;
372     }
373   }
374
375   // directoryURI
376   ret = media_folder_get_path(folder, &tmpStr);
377   if (ret == MEDIA_CONTENT_ERROR_NONE) {
378     if (tmpStr) {
379       o["directoryURI"] = picojson::value(std::string(tmpStr));
380       free(tmpStr);
381       tmpStr = NULL;
382     }
383   }
384
385   // title
386   ret = media_folder_get_name(folder, &tmpStr);
387   if (ret == MEDIA_CONTENT_ERROR_NONE) {
388     if (tmpStr) {
389       o["title"] = picojson::value(std::string(tmpStr));
390       free(tmpStr);
391       tmpStr = NULL;
392     }
393   }
394
395   // storageType
396   ret = media_folder_get_storage_type(folder, &storage_type);
397   if (ret == MEDIA_CONTENT_ERROR_NONE) {
398     if (storage_type == MEDIA_CONTENT_STORAGE_INTERNAL) {
399       o["storageType"] = picojson::value(std::string("INTERNAL"));
400     } else if (storage_type == MEDIA_CONTENT_STORAGE_EXTERNAL) {
401       o["storageType"] = picojson::value(std::string("EXTERNAL"));
402     } else if (storage_type == MEDIA_CONTENT_STORAGE_CLOUD) {
403       o["storageType"] = picojson::value(std::string("CLOUD"));
404     }
405   }
406
407   // modifiedData
408   ret = media_folder_get_modified_time(folder, &tmpDate);
409   if (ret == MEDIA_CONTENT_ERROR_NONE) {
410     o["modifiedDate"] = picojson::value(static_cast<double>(tmpDate));
411   }
412 }
413
414 static int setContent(media_info_h media, const picojson::value& content) {
415   ScopeLogger();
416
417   int ret;
418   std::string name = content.get("name").to_str();
419   std::string description = content.get("description").to_str();
420   int rating = std::stoi(content.get("rating").to_str());
421   bool is_fav = content.get("isFavorite").get<bool>();
422
423   if (NULL == media) {
424     LoggerE("MEDIA_CONTENT_ERROR_DB_FAILED");
425     return MEDIA_CONTENT_ERROR_DB_FAILED;
426   }
427
428   media_content_type_e type;
429   ret = media_info_get_media_type(media, &type);
430   if (ret != MEDIA_CONTENT_ERROR_NONE) {
431     LoggerE("Failed: media_info_get_media_type()");
432     return ret;
433   }
434
435   ret = media_info_set_display_name(media, name.c_str());
436   if (ret != MEDIA_CONTENT_ERROR_NONE) {
437     LoggerE("Updating name failed.");
438   }
439
440   ret = media_info_set_description(media, description.c_str());
441   if (ret != MEDIA_CONTENT_ERROR_NONE) {
442     LoggerE("Updating description failed.");
443   }
444
445   ret = media_info_set_rating(media, rating);
446   if (ret != MEDIA_CONTENT_ERROR_NONE) {
447     LoggerE("Updating rating failed.");
448   }
449
450   ret = media_info_set_favorite(media, is_fav);
451   if (ret != MEDIA_CONTENT_ERROR_NONE) {
452     LoggerE("Updating isFavorite failed.");
453   }
454
455   if (ret != MEDIA_CONTENT_ERROR_NONE) {
456     LoggerE("Updating favorite failed.");
457   }
458
459   if (type == MEDIA_CONTENT_TYPE_IMAGE) {
460     std::string orientation = content.get("orientation").to_str();
461     auto orientationToSet = orientationMap.find(orientation);
462
463     if (orientationToSet != orientationMap.end()) {
464       image_meta_h img;
465       if (MEDIA_CONTENT_ERROR_NONE == media_info_get_image(media, &img) &&
466           MEDIA_CONTENT_ERROR_NONE == image_meta_set_orientation(img, orientationToSet->second) &&
467           MEDIA_CONTENT_ERROR_NONE == image_meta_update_to_db(img)) {
468         LoggerD("orientation update was successful");
469       } else {
470         LoggerE("orientation update failed");
471       }
472       image_meta_destroy(img);
473     }
474   }
475
476   if (type == MEDIA_CONTENT_TYPE_IMAGE || type == MEDIA_CONTENT_TYPE_VIDEO) {
477     picojson::value geo = content.get("geolocation");
478     if (geo.evaluate_as_boolean()) {
479       LoggerD("geolocation is not null");
480       double latitude = atof(geo.get("latitude").to_str().c_str());
481       double longitude = atof(geo.get("longitude").to_str().c_str());
482       ret = media_info_set_latitude(media, latitude);
483       if (ret != MEDIA_CONTENT_ERROR_NONE) {
484         LoggerE("Updating geolocation is failed.");
485       }
486       ret = media_info_set_longitude(media, longitude);
487       if (ret != MEDIA_CONTENT_ERROR_NONE) {
488         LoggerD("Updating geolocation is failed.");
489       }
490     } else {
491       LoggerD("geolocation is null");
492     }
493   }
494
495   return MEDIA_CONTENT_ERROR_NONE;
496 }
497
498 static void FolderToJson(media_folder_h folder, picojson::object* out) {
499   ScopeLogger();
500
501   char* name = NULL;
502   char* id = NULL;
503   char* path = NULL;
504   time_t date;
505   media_content_storage_e storageType;
506
507   int ret;
508
509   ret = media_folder_get_folder_id(folder, &id);
510   if (ret != MEDIA_CONTENT_ERROR_NONE) {
511     LogAndReportError(ContentManager::convertError(ret), out,
512                       ("Failed: media_folder_get_folder_id"));
513     return;
514   }
515
516   ret = media_folder_get_name(folder, &name);
517   if (ret != MEDIA_CONTENT_ERROR_NONE) {
518     LogAndReportError(ContentManager::convertError(ret), out, ("Failed: media_folder_get_name"));
519     free(id);
520     return;
521   }
522
523   ret = media_folder_get_path(folder, &path);
524   if (ret != MEDIA_CONTENT_ERROR_NONE) {
525     LogAndReportError(ContentManager::convertError(ret), out, ("Failed: media_folder_get_path"));
526     free(id);
527     free(name);
528     return;
529   }
530
531   ret = media_folder_get_modified_time(folder, &date);
532   if (ret != MEDIA_CONTENT_ERROR_NONE) {
533     LogAndReportError(ContentManager::convertError(ret), out, ("Failed: media_folder_get_path"));
534     free(id);
535     free(name);
536     free(path);
537     return;
538   }
539
540   ret = media_folder_get_storage_type(folder, &storageType);
541   if (ret != MEDIA_CONTENT_ERROR_NONE) {
542     free(id);
543     free(name);
544     free(path);
545     LogAndReportError(ContentManager::convertError(ret), out,
546                       ("Failed: media_folder_get_storage_type"));
547     return;
548   }
549
550   (*out)["id"] = picojson::value(std::string(id));
551   (*out)["directoryURI"] = picojson::value(std::string(path));
552   (*out)["title"] = picojson::value(std::string(name));
553
554   if (storageType == MEDIA_CONTENT_STORAGE_INTERNAL) {
555     (*out)["storageType"] = picojson::value(std::string("INTERNAL"));
556   } else if (storageType == MEDIA_CONTENT_STORAGE_EXTERNAL) {
557     (*out)["storageType"] = picojson::value(std::string("EXTERNAL"));
558   }
559
560   (*out)["modifiedDate"] = picojson::value(static_cast<double>(date));
561
562   free(name);
563   free(id);
564   free(path);
565 }
566
567 static bool media_foreach_directory_cb(media_folder_h folder, void* user_data) {
568   ScopeLogger();
569   picojson::array* array = static_cast<picojson::array*>(user_data);
570   picojson::object json;
571   FolderToJson(folder, &json);
572   array->push_back(picojson::value(json));
573   return true;
574 }
575
576 static bool media_foreach_content_cb(media_info_h media, void* user_data) {
577   ScopeLogger();
578   picojson::value::array* contents = static_cast<picojson::value::array*>(user_data);
579   picojson::value::object o;
580   ContentToJson(media, o);
581   contents->push_back(picojson::value(o));
582   return true;
583 }
584
585 static bool playlist_foreach_cb(media_playlist_h playlist, void* user_data) {
586   ScopeLogger();
587   picojson::value::array* playlists = static_cast<picojson::value::array*>(user_data);
588   picojson::value::object o;
589   if (playlist != NULL) {
590     int id, cnt;
591     char* thumb_path = NULL;
592     char* name = NULL;
593     filter_h filter = NULL;
594     if (media_playlist_get_playlist_id(playlist, &id) == MEDIA_CONTENT_ERROR_NONE) {
595       std::stringstream str_id;
596       str_id << id;
597       o["id"] = picojson::value(std::to_string(id));
598     } else {
599       LoggerD("Invalid ID for playlist.");
600     }
601     if (media_playlist_get_thumbnail_path(playlist, &thumb_path) == MEDIA_CONTENT_ERROR_NONE) {
602       if (thumb_path != NULL) {
603         std::string thumbnail_uri(thumb_path);
604         if (thumbnail_uri != " ") {
605           thumbnail_uri = uri_prefix + thumbnail_uri;
606         }
607         o["thumbnailURI"] = picojson::value(thumbnail_uri);
608         free(thumb_path);
609       } else {
610         o["thumbnailURI"] = picojson::value();  // picojson::value(std::string(""));
611       }
612     } else {
613       LoggerD("Invalid thumbnail path for playlist.");
614     }
615     if (media_playlist_get_name(playlist, &name) == MEDIA_CONTENT_ERROR_NONE) {
616       o["name"] = picojson::value(std::string(name));
617       free(name);
618     } else {
619       LoggerD("Invalid name for playlist.");
620     }
621
622     media_filter_create(&filter);
623     std::unique_ptr<std::remove_pointer<filter_h>::type, int (*)(filter_h)> filter_ptr(
624         filter, &media_filter_destroy);  // automatically release the memory
625     if (media_playlist_get_media_count_from_db(id, filter, &cnt) == MEDIA_CONTENT_ERROR_NONE) {
626       o["numberOfTracks"] = picojson::value(static_cast<double>(cnt));
627     } else {
628       LoggerE("Invalid count for playlist.");
629     }
630     playlists->push_back(picojson::value(o));
631   }
632   return true;
633 }
634
635 static bool playlist_content_member_cb(int playlist_member_id, media_info_h media,
636                                        void* user_data) {
637   ScopeLogger();
638   picojson::value::array* contents = static_cast<picojson::value::array*>(user_data);
639   picojson::value::object o;
640
641   o["playlist_member_id"] = picojson::value(static_cast<double>(playlist_member_id));
642   ContentToJson(media, o);
643   contents->push_back(picojson::value(o));
644   return true;
645 }
646
647 void CreateThumbnailCallback(media_content_error_e err, const char* path, void* user_data) {
648   ScopeLogger();
649
650   std::unique_ptr<CreateThumbnailCallbackData> callback_data_ptr(
651       (CreateThumbnailCallbackData*)user_data);
652   if (0 == callback_data_ptr->callback_id) {
653     LoggerD("Callback id is 0");
654     return;
655   }
656
657   if (!(ContentManager::getInstance()->getContentInstance())) {
658     // There is not instance already
659     LoggerD("There is not instance now");
660     return;
661   }
662
663   picojson::object out;
664
665   out["callbackId"] = picojson::value(callback_data_ptr->callback_id);
666
667   if (MEDIA_CONTENT_ERROR_NONE == err) {
668     out["result"] = picojson::value(std::string(path));
669     ReportSuccess(out);
670   } else {
671     PlatformResult result = ContentManager::getInstance()->convertError(err);
672     LogAndReportError(result, &out, ("Failed to create a thumbnail"));
673   }
674
675   common::Instance::PostMessage(ContentManager::getInstance()->getContentInstance(),
676                                 picojson::value(out).serialize().c_str());
677 }
678
679 ContentManager::ContentManager() {
680   ScopeLogger("ContentManager called");
681   if (media_content_connect() == MEDIA_CONTENT_ERROR_NONE) {
682     m_dbConnected = true;
683   } else {
684     m_dbConnected = false;
685   }
686   m_contentInstance = nullptr;
687 }
688
689 ContentManager::~ContentManager() {
690   ScopeLogger();
691   if (m_dbConnected) {
692     if (media_content_disconnect() == MEDIA_CONTENT_ERROR_NONE) {
693       m_dbConnected = false;
694     }
695   }
696 }
697
698 ContentManager* ContentManager::getInstance() {
699   ScopeLogger();
700   static ContentManager instance;
701   return &instance;
702 }
703
704 ContentInstance* ContentManager::getContentInstance() {
705   ScopeLogger();
706   return m_contentInstance;
707 }
708
709 void ContentManager::setContentInstance(ContentInstance* const content_instance) {
710   ScopeLogger();
711   m_contentInstance = content_instance;
712 }
713
714 bool ContentManager::isConnected() {
715   ScopeLogger();
716   return m_dbConnected;
717 }
718
719 void ContentManager::getDirectories(const std::shared_ptr<ReplyCallbackData>& user_data) {
720   ScopeLogger();
721   int ret;
722   filter_h filter = NULL;
723   ret = media_filter_create(&filter);
724   if (ret != MEDIA_CONTENT_ERROR_NONE) {
725     LoggerE("Failed: media_filter_create failed");
726     return;
727   }
728
729   SCOPE_EXIT {
730     media_filter_destroy(filter);
731   };
732
733   std::string condition = "(FOLDER_STORAGE_TYPE = 0 OR FOLDER_STORAGE_TYPE = 1)";
734   media_filter_set_condition(filter, condition.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT);
735
736   picojson::array pico_dirs;
737   ret = media_folder_foreach_folder_from_db(filter, media_foreach_directory_cb, &pico_dirs);
738   if (ret != MEDIA_CONTENT_ERROR_NONE) {
739     PlatformResult err = LogAndCreateResult(
740         ErrorCode::UNKNOWN_ERR, "Getting the directories failed.",
741         ("Failed: Getting the directories failed %d (%s)", ret, get_error_message(ret)));
742     user_data->isSuccess = err;
743     return;
744   }
745
746   user_data->result = picojson::value(pico_dirs);
747 }
748
749 void ContentManager::find(const std::shared_ptr<ReplyCallbackData>& user_data) {
750   ScopeLogger();
751
752   int ret;
753   int count, offset;
754   std::string dirId;
755
756   picojson::value::array arrayContent;
757   filter_h filter = nullptr;
758   media_filter_create(&filter);
759   SCOPE_EXIT {
760     if (filter) {
761       media_filter_destroy(filter);
762     }
763   };
764
765   if (!IsNull(user_data->args.get("filter"))) {
766     ContentFilter filterMechanism;
767     std::string query;
768     picojson::object argsObject = JsonCast<picojson::object>(user_data->args);
769     if (filterMechanism.BuildQuery(FromJson<picojson::object>(argsObject, "filter"), &query)) {
770       LoggerD("Filter query: %s", query.c_str());
771       ret = media_filter_set_condition(filter, query.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT);
772       if (MEDIA_CONTENT_ERROR_NONE != ret) {
773         LoggerE("Platform filter setting failed, error %d", ret);
774       }
775     }
776   }
777
778   if (user_data->args.contains("sortMode")) {
779     picojson::value vSortMode = user_data->args.get("sortMode");
780
781     if (vSortMode.is<picojson::object>()) {
782       std::string sortModeName, sortModeOrder;
783
784       ContentFilter::MapField(vSortMode.get("attributeName").to_str(), &sortModeName);
785
786       sortModeOrder = vSortMode.get("order").to_str();
787       if (!sortModeOrder.empty()) {
788         media_content_order_e order = MEDIA_CONTENT_ORDER_ASC;
789
790         if (sortModeOrder == "ASC") {
791           order = MEDIA_CONTENT_ORDER_ASC;
792         } else if (sortModeOrder == "DESC") {
793           order = MEDIA_CONTENT_ORDER_DESC;
794         }
795
796         ret = media_filter_set_order(filter, order, sortModeName.c_str(),
797                                      MEDIA_CONTENT_COLLATE_DEFAULT);
798         if (MEDIA_CONTENT_ERROR_NONE != ret) {
799           LoggerE("Platform SortMode setting failed, error: %d", ret);
800         }
801       }
802     }
803   }
804
805   if (!IsNull(user_data->args.get("count"))) {
806     count = static_cast<int>(user_data->args.get("count").get<double>());
807   } else {
808     count = -1;
809   }
810   if (!IsNull(user_data->args.get("offset"))) {
811     offset = static_cast<int>(user_data->args.get("offset").get<double>());
812   } else {
813     offset = -1;
814   }
815   ret = media_filter_set_offset(filter, offset, count);
816   if (MEDIA_CONTENT_ERROR_NONE != ret) {
817     LoggerE("A platform error occurs in media_filter_set_offset: %d", ret);
818   }
819   if (!IsNull(user_data->args.get("directoryId"))) {
820     dirId = user_data->args.get("directoryId").get<std::string>();
821     ret = media_folder_foreach_media_from_db(dirId.c_str(), filter, media_foreach_content_cb,
822                                              static_cast<void*>(&arrayContent));
823   } else {
824     ret = media_info_foreach_media_from_db(filter, media_foreach_content_cb,
825                                            static_cast<void*>(&arrayContent));
826   }
827
828   if (ret == MEDIA_CONTENT_ERROR_NONE) {
829     user_data->result = picojson::value(arrayContent);
830   } else {
831     PlatformResult err = LogAndCreateResult(
832         ErrorCode::UNKNOWN_ERR, "The iteration failed in platform",
833         ("The iteration failed in platform: %d (%s)", ret, get_error_message(ret)));
834     user_data->isSuccess = err;
835   }
836 }
837
838 int ContentManager::scanFile(std::string& uri) {
839   ScopeLogger();
840   return media_content_scan_file(uri.c_str());
841 }
842
843 PlatformResult ContentManager::scanDirectory(media_scan_completed_cb callback,
844                                              ReplyCallbackData* cbData) {
845   ScopeLogger();
846   const std::string& contentDirURI = cbData->args.get("contentDirURI").get<std::string>();
847   std::string real_path = common::FilesystemProvider::Create().GetRealPath(contentDirURI);
848   const bool recursive = cbData->args.get("recursive").get<bool>();
849
850   int ret = media_content_scan_folder(real_path.c_str(), recursive, callback, (void*)cbData);
851
852   if (ret != MEDIA_CONTENT_ERROR_NONE) {
853     if (MEDIA_CONTENT_ERROR_INVALID_PARAMETER == ret) {
854       return LogAndCreateResult(
855           ErrorCode::INVALID_VALUES_ERR, "Scanning content directory failed",
856           ("Scan folder failed in platform: %d (%s)", ret, get_error_message(ret)));
857
858     } else {
859       return LogAndCreateResult(
860           ErrorCode::UNKNOWN_ERR, "Scanning content directory failed",
861           ("Scan folder failed in platform: %d (%s)", ret, get_error_message(ret)));
862     }
863   }
864   return PlatformResult(ErrorCode::NO_ERROR);
865 }
866
867 PlatformResult ContentManager::cancelScanDirectory(const std::string& content_dir_uri) {
868   ScopeLogger();
869
870   int ret = media_content_cancel_scan_folder(content_dir_uri.c_str());
871   if (ret != MEDIA_CONTENT_ERROR_NONE) {
872     return LogAndCreateResult(
873         ErrorCode::UNKNOWN_ERR, "Cancel scan content directory failed",
874         ("Cancel scan folder failed in platform: %d (%s)", ret, get_error_message(ret)));
875   }
876   return PlatformResult(ErrorCode::NO_ERROR);
877 }
878
879 PlatformResult ContentManager::addChangeListener(media_content_noti_h* noti_handle,
880                                                  media_content_db_update_cb callback,
881                                                  void* user_data) {
882   ScopeLogger();
883
884   int ret = media_content_add_db_updated_cb(callback, user_data, noti_handle);
885
886   if (MEDIA_CONTENT_ERROR_NONE != ret) {
887     return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to add the listener.",
888                               ("Failed to add the listener: %d (%s)", ret, get_error_message(ret)));
889   }
890
891   return PlatformResult(ErrorCode::NO_ERROR);
892 }
893
894 PlatformResult ContentManager::removeChangeListener(media_content_noti_h noti_handle) {
895   ScopeLogger();
896
897   int ret = media_content_remove_db_updated_cb(noti_handle);
898
899   switch (ret) {
900     case MEDIA_CONTENT_ERROR_NONE:
901       return PlatformResult(ErrorCode::NO_ERROR);
902     case MEDIA_CONTENT_ERROR_INVALID_PARAMETER:
903       // Trying to remove non-existent listener, ignoring
904       LoggerI("Failed to remove the listener: %d (%s)", ret, get_error_message(ret));
905       return PlatformResult(ErrorCode::NO_ERROR);
906     default:
907       return LogAndCreateResult(
908           ErrorCode::ABORT_ERR, "Failed to remove the listener.",
909           ("Failed to remove the listener: %d (%s)", ret, get_error_message(ret)));
910   }
911 }
912
913 PlatformResult ContentManager::setChangeListener(media_content_db_update_cb callback,
914                                                  void* user_data) {
915   ScopeLogger();
916
917   int ret = media_content_set_db_updated_cb(callback, user_data);
918   if (ret != MEDIA_CONTENT_ERROR_NONE) {
919     return LogAndCreateResult(
920         ErrorCode::UNKNOWN_ERR, "registering the listener is failed.",
921         ("Failed: registering the listener is failed %d (%s)", ret, get_error_message(ret)));
922   }
923   return PlatformResult(ErrorCode::NO_ERROR);
924 }
925
926 PlatformResult ContentManager::unSetChangeListener() {
927   ScopeLogger();
928
929   int ret = media_content_unset_db_updated_cb();
930   if (ret != MEDIA_CONTENT_ERROR_NONE) {
931     return LogAndCreateResult(
932         ErrorCode::UNKNOWN_ERR, "unregistering the listener is failed.",
933         ("Failed: unregistering the listener is failed: %d (%s)", ret, get_error_message(ret)));
934   }
935   return PlatformResult(ErrorCode::NO_ERROR);
936 }
937
938 void ContentManager::createPlaylist(std::string name,
939                                     const std::shared_ptr<ReplyCallbackData>& user_data) {
940   ScopeLogger();
941   media_playlist_h playlist = NULL;
942
943   int ret = media_playlist_insert_to_db(name.c_str(), &playlist);
944   std::unique_ptr<std::remove_pointer<media_playlist_h>::type, int (*)(media_playlist_h)>
945       playlist_ptr(playlist, &media_playlist_destroy);  // automatically release the memory
946   if (ret != MEDIA_CONTENT_ERROR_NONE) {
947     // MEDIA_CONTENT_ERROR_DB_FAILED means that playlist probably already exists
948     PlatformResult err = LogAndCreateResult(
949         MEDIA_CONTENT_ERROR_DB_FAILED == ret ? ErrorCode::INVALID_VALUES_ERR
950                                              : ErrorCode::UNKNOWN_ERR,
951         "Creation of playlist has failed.",
952         ("Failed: creation of playlist is failed: %d (%s)", ret, get_error_message(ret)));
953     user_data->isSuccess = err;
954     return;
955   }
956   picojson::value::object o;
957
958   if (playlist != NULL) {
959     int id, cnt;
960     char* thumb_path = NULL;
961     char* name_playlist = NULL;
962     filter_h filter = NULL;
963     if (media_playlist_get_playlist_id(playlist, &id) == MEDIA_CONTENT_ERROR_NONE) {
964       o["id"] = picojson::value(std::to_string(id));
965     } else {
966       PlatformResult err =
967           LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "loading of playlist is failed.");
968       user_data->isSuccess = err;
969       return;
970     }
971     if (media_playlist_get_thumbnail_path(playlist, &thumb_path) == MEDIA_CONTENT_ERROR_NONE) {
972       if (thumb_path != NULL) {
973         o["thumbnailURI"] = picojson::value(std::string(thumb_path));
974         free(thumb_path);
975       } else {
976         o["thumbnailURI"] = picojson::value();
977       }
978     } else {
979       LoggerE("Invalid thumbnail path for playlist.");
980     }
981     if (media_playlist_get_name(playlist, &name_playlist) == MEDIA_CONTENT_ERROR_NONE) {
982       o["name"] = picojson::value(std::string(name_playlist));
983       free(name_playlist);
984     } else {
985       LoggerE("Invalid name for playlist.");
986     }
987     media_filter_create(&filter);
988     std::unique_ptr<std::remove_pointer<filter_h>::type, int (*)(filter_h)> filter_ptr(
989         filter, &media_filter_destroy);  // automatically release the memory
990
991     if (media_playlist_get_media_count_from_db(id, filter, &cnt) == MEDIA_CONTENT_ERROR_NONE) {
992       o["numberOfTracks"] = picojson::value(static_cast<double>(cnt));
993     } else {
994       LoggerE("Invalid count for playlist.");
995     }
996   }
997
998   user_data->result = picojson::value(o);
999 }
1000
1001 void ContentManager::getPlaylists(const std::shared_ptr<ReplyCallbackData>& user_data) {
1002   ScopeLogger();
1003   int ret;
1004   filter_h filter = nullptr;
1005   media_filter_create(&filter);
1006   std::unique_ptr<std::remove_pointer<filter_h>::type, int (*)(filter_h)> filter_ptr(
1007       filter, &media_filter_destroy);  // automatically release the memory
1008   picojson::value::array playlists;
1009
1010   ret = media_playlist_foreach_playlist_from_db(filter, playlist_foreach_cb,
1011                                                 static_cast<void*>(&playlists));
1012
1013   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1014     PlatformResult err = LogAndCreateResult(
1015         ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1016         ("Failed: Getting playlist is failed %d (%s)", ret, get_error_message(ret)));
1017     user_data->isSuccess = err;
1018   }
1019
1020   user_data->result = picojson::value(playlists);
1021 }
1022
1023 void ContentManager::removePlaylist(std::string playlistId,
1024                                     const std::shared_ptr<ReplyCallbackData>& user_data) {
1025   ScopeLogger();
1026   int id = std::atoi(playlistId.c_str());
1027   if (id == 0) {
1028     PlatformResult err = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "PlaylistId is wrong.");
1029     user_data->isSuccess = err;
1030     return;
1031   }
1032
1033   int ret = media_playlist_delete_from_db(id);
1034   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1035     PlatformResult err =
1036         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Removal of playlist is failed.");
1037     user_data->isSuccess = err;
1038   }
1039 }
1040
1041 int ContentManager::update(picojson::value args) {
1042   ScopeLogger();
1043
1044   int ret;
1045   picojson::value content = args.get("content");
1046   std::string id = content.get("id").to_str();
1047
1048   media_info_h media = NULL;
1049   ret = media_info_get_media_from_db(id.c_str(), &media);
1050   if (ret == MEDIA_CONTENT_ERROR_NONE) {
1051     setContent(media, content);
1052     ret = media_info_update_to_db(media);
1053     media_info_destroy(media);
1054   }
1055
1056   return ret;
1057 }
1058
1059 int ContentManager::updateBatch(picojson::value args) {
1060   ScopeLogger();
1061   int ret = 0;
1062   std::vector<picojson::value> contents = args.get("contents").get<picojson::array>();
1063
1064   for (picojson::value::array::iterator it = contents.begin(); it != contents.end(); ++it) {
1065     picojson::value content = *it;
1066     std::string id = content.get("id").to_str();
1067     media_info_h media = NULL;
1068     ret = media_info_get_media_from_db(id.c_str(), &media);
1069     if (media != NULL && ret == MEDIA_CONTENT_ERROR_NONE) {
1070       ret = setContent(media, content);
1071       if (ret != MEDIA_CONTENT_ERROR_NONE) {
1072         LoggerE("setContent failed");
1073         return ret;
1074       }
1075
1076       ret = media_info_update_to_db(media);
1077       if (ret != MEDIA_CONTENT_ERROR_NONE) {
1078         LoggerE("update to db failed");
1079       }
1080       media_info_destroy(media);
1081     } else {
1082       return ret;
1083     }
1084   }
1085   return ret;
1086 }
1087
1088 int ContentManager::playlistAdd(std::string playlist_id, std::string content_id) {
1089   ScopeLogger();
1090
1091   media_playlist_h playlist = NULL;
1092   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1093
1094   if (playlist != NULL && ret == MEDIA_CONTENT_ERROR_NONE) {
1095     ret = media_playlist_add_media(playlist, content_id.c_str());
1096     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1097       LoggerE("The content(id:%s) can't add to playlist", content_id.c_str());
1098     }
1099
1100     ret = media_playlist_update_to_db(playlist);
1101     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1102       LoggerE("The content(id:%s) can't add to playlist", content_id.c_str());
1103     }
1104   } else {
1105     LoggerE("Playlist(id:%s) is not exist", playlist_id.c_str());
1106   }
1107
1108   media_playlist_destroy(playlist);
1109   return ret;
1110 }
1111
1112 int ContentManager::playlistRemove(std::string playlist_id, int member_id) {
1113   ScopeLogger();
1114
1115   media_playlist_h playlist = NULL;
1116   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1117   if (playlist != NULL && ret == MEDIA_CONTENT_ERROR_NONE) {
1118     ret = media_playlist_remove_media(playlist, member_id);
1119     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1120       LoggerE("The content can't remove to playlist");
1121     }
1122
1123     ret = media_playlist_update_to_db(playlist);
1124     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1125       LoggerE("The content can't remove to playlist");
1126     }
1127   } else {
1128     LoggerE("Playlist(id:%s) is not exist", playlist_id.c_str());
1129   }
1130   media_playlist_destroy(playlist);
1131
1132   return ret;
1133 }
1134
1135 void ContentManager::playlistAddbatch(const std::shared_ptr<ReplyCallbackData>& user_data) {
1136   ScopeLogger();
1137   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1138
1139   media_playlist_h playlist = NULL;
1140   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1141
1142   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1143     PlatformResult err =
1144         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1145                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1146     user_data->isSuccess = err;
1147     return;
1148   }
1149
1150   std::vector<picojson::value> contents = user_data->args.get("contents").get<picojson::array>();
1151   for (picojson::value::array::iterator it = contents.begin(); it != contents.end(); ++it) {
1152     picojson::value content = *it;
1153     std::string id = content.get("id").to_str();
1154     ret = media_playlist_add_media(playlist, id.c_str());
1155     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1156       LoggerE("Adding Content(id:%s) is failed.", id.c_str());
1157     }
1158   }
1159
1160   ret = media_playlist_update_to_db(playlist);
1161   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1162     PlatformResult err =
1163         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Adding playlist is failed.",
1164                            ("Adding playlist is failed: %d (%s)", ret, get_error_message(ret)));
1165     user_data->isSuccess = err;
1166   }
1167   media_playlist_destroy(playlist);
1168 }
1169
1170 void ContentManager::playlistGet(const std::shared_ptr<ReplyCallbackData>& user_data) {
1171   ScopeLogger();
1172   media_playlist_h playlist = NULL;
1173   media_content_order_e order = MEDIA_CONTENT_ORDER_ASC;
1174   const std::string playOrder("play_order");
1175
1176   SCOPE_EXIT {
1177     if (playlist) {
1178       media_playlist_destroy(playlist);
1179     }
1180   };
1181
1182   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1183   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1184   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1185     PlatformResult err =
1186         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1187                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1188     user_data->isSuccess = err;
1189     return;
1190   }
1191
1192   filter_h filter = NULL;
1193   ret = media_filter_create(&filter);
1194   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1195     PlatformResult err =
1196         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Creating a filter is failed.",
1197                            ("Creating a filter is failed: %d (%s)", ret, get_error_message(ret)));
1198     user_data->isSuccess = err;
1199     return;
1200   }
1201
1202   int count = user_data->args.get("count").get<double>();
1203   int offset = user_data->args.get("offset").get<double>();
1204   ret = media_filter_set_offset(filter, offset, count);
1205   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1206     LoggerD("Setting a offset/count is failed.");
1207   }
1208   ret = media_filter_set_order(filter, order, playOrder.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT);
1209   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1210     LoggerD("Setting a offset/count is failed.");
1211   }
1212
1213   picojson::value::array arrayContent;
1214   ret = media_playlist_foreach_media_from_db(std::stoi(playlist_id), filter,
1215                                              playlist_content_member_cb,
1216                                              static_cast<void*>(&arrayContent));
1217
1218   media_filter_destroy(filter);
1219   if (ret == MEDIA_CONTENT_ERROR_NONE) {
1220     user_data->result = picojson::value(arrayContent);
1221   } else {
1222     PlatformResult err =
1223         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Creating a filter is failed.",
1224                            ("Creating a filter is failed: %d (%s)", ret, get_error_message(ret)));
1225     user_data->isSuccess = err;
1226   }
1227 }
1228
1229 void ContentManager::playlistRemovebatch(const std::shared_ptr<ReplyCallbackData>& user_data) {
1230   ScopeLogger();
1231   media_playlist_h playlist = NULL;
1232
1233   SCOPE_EXIT {
1234     if (playlist) {
1235       media_playlist_destroy(playlist);
1236     }
1237   };
1238
1239   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1240   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1241   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1242     PlatformResult err =
1243         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1244                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1245     user_data->isSuccess = err;
1246     return;
1247   }
1248
1249   std::vector<picojson::value> members = user_data->args.get("members").get<picojson::array>();
1250   std::size_t members_size = members.size();
1251   for (std::size_t i = 0; i < members_size; ++i) {
1252     int member_id = static_cast<int>(members.at(i).get<double>());
1253     ret = media_playlist_remove_media(playlist, member_id);
1254
1255     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1256       LoggerD("Removing a content is failed.");
1257     }
1258   }
1259
1260   ret = media_playlist_update_to_db(playlist);
1261   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1262     PlatformResult err = LogAndCreateResult(
1263         ErrorCode::UNKNOWN_ERR, "Removing the contents is failed.",
1264         ("Removing the contents is failed: %d (%s)", ret, get_error_message(ret)));
1265     user_data->isSuccess = err;
1266   }
1267 }
1268
1269 void ContentManager::playlistSetOrder(const std::shared_ptr<ReplyCallbackData>& user_data) {
1270   ScopeLogger();
1271   media_playlist_h playlist = NULL;
1272
1273   SCOPE_EXIT {
1274     if (playlist) {
1275       media_playlist_destroy(playlist);
1276     }
1277   };
1278
1279   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1280   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1281   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1282     PlatformResult err =
1283         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1284                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1285     user_data->isSuccess = err;
1286     return;
1287   }
1288
1289   int cnt;
1290   std::vector<picojson::value> members = user_data->args.get("members").get<picojson::array>();
1291
1292   ret = media_playlist_get_media_count_from_db(std::stoi(playlist_id), NULL, &cnt);
1293   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1294     LoggerE("Failed: media_playlist_get_media_count_from_db");
1295     PlatformResult err = convertError(ret);
1296     user_data->isSuccess = err;
1297     return;
1298   }
1299   std::size_t members_size = members.size();
1300   if (cnt < 0 || static_cast<size_t>(cnt) != members_size) {
1301     PlatformResult err = LogAndCreateResult(
1302         ErrorCode::INVALID_VALUES_ERR,
1303         "The items array does not contain all items from the playlist.",
1304         ("Failed: The items array does not contain all items from the playlist: %d (%s)", ret,
1305          get_error_message(ret)));
1306     user_data->isSuccess = err;
1307     return;
1308   }
1309
1310   for (std::size_t i = 0; i < members_size; ++i) {
1311     int member_id = static_cast<int>(members.at(i).get<double>());
1312     ret = media_playlist_set_play_order(playlist, member_id, i);
1313     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1314       LoggerD("Removing a content is failed.");
1315     }
1316   }
1317
1318   ret = media_playlist_update_to_db(playlist);
1319   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1320     PlatformResult err = LogAndCreateResult(
1321         ErrorCode::UNKNOWN_ERR, "Removing the contents is failed.",
1322         ("Removing the contents is failed: %d (%s)", ret, get_error_message(ret)));
1323     user_data->isSuccess = err;
1324   }
1325 }
1326
1327 void ContentManager::playlistMove(const std::shared_ptr<ReplyCallbackData>& user_data) {
1328   ScopeLogger();
1329   media_playlist_h playlist = NULL;
1330
1331   SCOPE_EXIT {
1332     if (playlist) {
1333       media_playlist_destroy(playlist);
1334     }
1335   };
1336
1337   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1338   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1339   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1340     PlatformResult err =
1341         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1342                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1343     user_data->isSuccess = err;
1344     return;
1345   }
1346   int old_order;
1347   double member_id = user_data->args.get("memberId").get<double>();
1348   double delta = user_data->args.get("delta").get<double>();
1349   ret = media_playlist_get_play_order(playlist, static_cast<int>(member_id), &old_order);
1350   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1351     PlatformResult err = LogAndCreateResult(
1352         ErrorCode::UNKNOWN_ERR, "The content can't find form playlist.",
1353         ("The content can't find form playlist: %d (%s)", ret, get_error_message(ret)));
1354     user_data->isSuccess = err;
1355     return;
1356   }
1357   int new_order = static_cast<int>(old_order) + static_cast<int>(delta);
1358   ret = media_playlist_set_play_order(playlist, static_cast<int>(member_id), new_order);
1359   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1360     PlatformResult err = LogAndCreateResult(
1361         ErrorCode::UNKNOWN_ERR, "The content can't update play_order.",
1362         ("The content can't update play_order: %d (%s)", ret, get_error_message(ret)));
1363     user_data->isSuccess = err;
1364     return;
1365   }
1366   ret = media_playlist_update_to_db(playlist);
1367   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1368     PlatformResult err = LogAndCreateResult(
1369         ErrorCode::UNKNOWN_ERR, "Updateing play_order is failed.",
1370         ("Updateing play_order is failed: %d (%s)", ret, get_error_message(ret)));
1371     user_data->isSuccess = err;
1372   }
1373 }
1374
1375 int ContentManager::getLyrics(const picojson::value& args, picojson::object& result) {
1376   ScopeLogger();
1377
1378   int ret = METADATA_EXTRACTOR_ERROR_NONE;
1379   const std::string& contentURI = args.get("contentURI").to_str();
1380   if (contentURI.empty()) {
1381     LoggerE("contentURI empty - skipping media extractor");
1382     return -1;
1383   }
1384
1385   metadata_extractor_h extractor;
1386   ret = metadata_extractor_create(&extractor);
1387   if (METADATA_EXTRACTOR_ERROR_NONE != ret) {
1388     LoggerE("metadata_extractor_create failed, error: %d", ret);
1389   }
1390   std::unique_ptr<std::remove_pointer<metadata_extractor_h>::type, int (*)(metadata_extractor_h)>
1391       extractor_ptr(extractor, &metadata_extractor_destroy);  // automatically release the memory
1392
1393   ret = metadata_extractor_set_path(extractor, contentURI.c_str());
1394   if (ret != METADATA_EXTRACTOR_ERROR_NONE) {
1395     LoggerE("metadata_extractor_set_path failed, error: %d", ret);
1396     return ret;
1397   }
1398   picojson::array timestamps;
1399   picojson::array texts = picojson::array();
1400   char* strSyncTextNum = NULL;
1401
1402   ret = metadata_extractor_get_metadata(extractor, METADATA_SYNCLYRICS_NUM, &strSyncTextNum);
1403   if (ret != METADATA_EXTRACTOR_ERROR_NONE) {
1404     LoggerE("Media extractor error %d", ret);
1405     return ret;
1406   }
1407
1408   int nSyncTextNum = 0;
1409   if (strSyncTextNum) {
1410     nSyncTextNum = atoi(strSyncTextNum);
1411     free(strSyncTextNum);
1412     strSyncTextNum = NULL;
1413   }
1414   if (nSyncTextNum > 0) {
1415     result["type"] = picojson::value(std::string("SYNCHRONIZED"));
1416     for (int i = 0; i < nSyncTextNum; i++) {
1417       unsigned long time_info = 0;
1418       char* lyrics = NULL;
1419       ret = metadata_extractor_get_synclyrics(extractor, i, &time_info, &lyrics);
1420       if (ret == METADATA_EXTRACTOR_ERROR_NONE) {
1421         timestamps.push_back(picojson::value(static_cast<double>(time_info)));
1422         texts.push_back(picojson::value(std::string(lyrics)));
1423         free(lyrics);
1424       }
1425     }
1426     result["texts"] = picojson::value(texts);
1427     result["timestamps"] = picojson::value(timestamps);
1428     ret = METADATA_EXTRACTOR_ERROR_NONE;
1429   } else {
1430     char* unSyncText = nullptr;
1431     ret = metadata_extractor_get_metadata(extractor, METADATA_UNSYNCLYRICS, &unSyncText);
1432     if (ret == METADATA_EXTRACTOR_ERROR_NONE) {
1433       result["type"] = picojson::value(std::string("UNSYNCHRONIZED"));
1434       if (nullptr == unSyncText) {
1435         LoggerE("Unsynchronized lyrics text is NULL");
1436       }
1437       texts.push_back(picojson::value(unSyncText ? unSyncText : ""));
1438       result["texts"] = picojson::value(texts);
1439       free(unSyncText);
1440     }
1441   }
1442
1443   return ret;
1444 }
1445
1446 media_playlist_h getPlaylistHandle(int id) {
1447   ScopeLogger();
1448   media_playlist_h playlist_handle = nullptr;
1449   int ret_code = media_playlist_get_playlist_from_db(id, &playlist_handle);
1450   if (MEDIA_CONTENT_ERROR_NONE != ret_code || playlist_handle == nullptr) {
1451     LoggerE("could not get playlist handle for id: %d", id);
1452     return nullptr;
1453   }
1454
1455   return playlist_handle;
1456 }
1457
1458 void destroyMediaPlaylistHandle(media_playlist_h& playlist_handle) {
1459   ScopeLogger();
1460   if (playlist_handle) {
1461     int ret_code = media_playlist_destroy(playlist_handle);
1462     playlist_handle = nullptr;
1463
1464     if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1465       LoggerE("media_playlist_destroy failed");
1466     }
1467   }
1468 }
1469
1470 int ContentManager::getPlaylistName(int id, std::string* result) {
1471   ScopeLogger();
1472   media_playlist_h playlist_handle = getPlaylistHandle(id);
1473   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1474
1475   char* tmp_playlist_name = nullptr;
1476   const int ret_code = media_playlist_get_name(playlist_handle, &tmp_playlist_name);
1477
1478   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1479     LoggerE("media_playlist_get_name failed");
1480     return TIZEN_ERROR_UNKNOWN;
1481   }
1482
1483   std::string playlist_name;
1484   if (tmp_playlist_name) {
1485     playlist_name = tmp_playlist_name;
1486     free(tmp_playlist_name);
1487     tmp_playlist_name = nullptr;
1488   }
1489
1490   *result = playlist_name;
1491   return MEDIA_CONTENT_ERROR_NONE;
1492 }
1493
1494 int updatePlaylistInDB(media_playlist_h playlist_handle) {
1495   ScopeLogger();
1496   int ret_code = media_playlist_update_to_db(playlist_handle);
1497   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1498     LoggerE("media_playlist_update_to_db failed");
1499     return ret_code;
1500   }
1501   return MEDIA_CONTENT_ERROR_NONE;
1502 }
1503
1504 int ContentManager::setPlaylistName(int id, const std::string& name) {
1505   ScopeLogger();
1506   if (name.empty()) {
1507     LoggerE("Cannot set empty playlist name!");
1508     return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
1509   }
1510
1511   media_playlist_h playlist_handle = getPlaylistHandle(id);
1512   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1513
1514   const int ret_code = media_playlist_set_name(playlist_handle, name.c_str());
1515   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1516     LoggerE("media_playlist_set_name failed");
1517     // Setting name that is used by other playlist does not return bad error code here.
1518     // MEDIA_CONTENT_ERROR_INVALID_OPERATION is being returned in updatePlaylistInDB
1519     return TIZEN_ERROR_UNKNOWN;
1520   }
1521
1522   int ret = updatePlaylistInDB(playlist_handle);
1523   if (MEDIA_CONTENT_ERROR_NONE != ret) {
1524     LoggerE("Error while updating playlist: %d", ret);
1525     if (MEDIA_CONTENT_ERROR_DB_FAILED == ret) {
1526       // We could fetch list of playlists and check if other playlist is using this
1527       // name, but that seems to be to much work in synchronous method
1528       LoggerE("Playlist name: %s is probably already used", name.c_str());
1529       return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
1530     }
1531     return ret;
1532   }
1533   return MEDIA_CONTENT_ERROR_NONE;
1534 }
1535
1536 int ContentManager::getThumbnailUri(int id, std::string* result) {
1537   ScopeLogger();
1538   media_playlist_h playlist_handle = getPlaylistHandle(id);
1539   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1540
1541   char* tmp_playlist_thb_path = nullptr;
1542   const int ret_code = media_playlist_get_thumbnail_path(playlist_handle, &tmp_playlist_thb_path);
1543
1544   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1545     LoggerE("media_playlist_get_name failed");
1546     return TIZEN_ERROR_UNKNOWN;
1547   }
1548
1549   std::string playlist_thb_path;
1550   if (tmp_playlist_thb_path) {
1551     playlist_thb_path = tmp_playlist_thb_path;
1552     free(tmp_playlist_thb_path);
1553     tmp_playlist_thb_path = nullptr;
1554   }
1555
1556   if (playlist_thb_path != " ") {
1557     playlist_thb_path = uri_prefix + playlist_thb_path;
1558   }
1559
1560   *result = playlist_thb_path;
1561   return MEDIA_CONTENT_ERROR_NONE;
1562 }
1563
1564 int ContentManager::setThumbnailUri(int id, const std::string& thb_uri) {
1565   ScopeLogger();
1566
1567   // Allow setting empty URI, unfortunately Core API does not allow to set empty
1568   // path so we need to set one empty space. This is probably issue of Core API.
1569   if (!thb_uri.empty() && " " != thb_uri) {
1570     if (thb_uri.find(uri_absolute_prefix) != 0) {
1571       LoggerE("thumbnail URI is not valid: [%s]", thb_uri.c_str());
1572       return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
1573     }
1574   }
1575
1576   media_playlist_h playlist_handle = getPlaylistHandle(id);
1577   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1578
1579   std::string real_path = common::FilesystemProvider::Create().GetRealPath(thb_uri);
1580   const int ret_code = media_playlist_set_thumbnail_path(playlist_handle, real_path.c_str());
1581   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1582     LoggerE("media_playlist_set_thumbnail_path failed");
1583     return TIZEN_ERROR_UNKNOWN;
1584   }
1585
1586   int ret = updatePlaylistInDB(playlist_handle);
1587   return ret;
1588 }
1589
1590 int ContentManager::getNumberOfTracks(int id, int* result) {
1591   ScopeLogger();
1592
1593   int count = 0;
1594   const int ret_code = media_playlist_get_media_count_from_db(id, nullptr, &count);
1595
1596   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1597     LoggerE("media_playlist_get_media_count_from_db failed");
1598     return TIZEN_ERROR_UNKNOWN;
1599   }
1600
1601   *result = count;
1602   return MEDIA_CONTENT_ERROR_NONE;
1603 }
1604
1605 common::PlatformResult ContentManager::createThumbnail(const picojson::value& args) {
1606   ScopeLogger();
1607
1608   std::unique_ptr<CreateThumbnailCallbackData> callback_data_ptr{new CreateThumbnailCallbackData};
1609   callback_data_ptr->callback_id = args.get("callbackId").get<double>();
1610   std::string id = args.get("id").get<std::string>();
1611
1612   int ret = media_info_get_media_from_db(id.c_str(), &callback_data_ptr->media);
1613   if (MEDIA_CONTENT_ERROR_NONE != ret && nullptr == callback_data_ptr->media) {
1614     return LogAndCreateResult(ErrorCode::ABORT_ERR, "Getting media is failed.",
1615                               ("Getting media is failed: %d (%s)", ret, get_error_message(ret)));
1616   }
1617
1618   ret = media_info_create_thumbnail(callback_data_ptr->media, CreateThumbnailCallback,
1619                                     static_cast<void*>(callback_data_ptr.get()));
1620
1621   if (MEDIA_CONTENT_ERROR_NONE != ret) {
1622     return LogAndCreateResult(ErrorCode::ABORT_ERR, "Creating thumbnail failed.",
1623                               ("Creating thumbnail failed: %d (%s)", ret, get_error_message(ret)));
1624   }
1625   callback_data_ptr.release();
1626   return PlatformResult(ErrorCode::NO_ERROR);
1627 }
1628
1629 PlatformResult ContentManager::convertError(int err) {
1630   char* error_msg = get_error_message(err);
1631   switch (err) {
1632     case MEDIA_CONTENT_ERROR_INVALID_PARAMETER:
1633       return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, error_msg);
1634     case MEDIA_CONTENT_ERROR_OUT_OF_MEMORY:
1635       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1636     case MEDIA_CONTENT_ERROR_INVALID_OPERATION:
1637       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1638     case MEDIA_CONTENT_FILE_NO_SPACE_ON_DEVICE:
1639       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1640     case MEDIA_CONTENT_ERROR_PERMISSION_DENIED:
1641       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1642     case MEDIA_CONTENT_ERROR_DB_FAILED:
1643       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1644     case MEDIA_CONTENT_ERROR_DB_BUSY:
1645       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1646     case MEDIA_CONTENT_ERROR_NETWORK:
1647       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1648     case MEDIA_CONTENT_ERROR_UNSUPPORTED_CONTENT:
1649       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1650     default:
1651       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error.");
1652   }
1653 }
1654
1655 }  // namespace content
1656 }  // namespace extension