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