[Content] Storage type usage removed
[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
354   // id
355   ret = media_folder_get_folder_id(folder, &tmpStr);
356   if (ret == MEDIA_CONTENT_ERROR_NONE) {
357     if (tmpStr) {
358       o["id"] = picojson::value(std::string(tmpStr));
359       free(tmpStr);
360       tmpStr = NULL;
361     }
362   }
363
364   // directoryURI
365   std::string folder_path;
366   ret = media_folder_get_path(folder, &tmpStr);
367   if (ret == MEDIA_CONTENT_ERROR_NONE) {
368     if (tmpStr) {
369       o["directoryURI"] = picojson::value(std::string(tmpStr));
370       // folder_path value kept for modifiedDate property gathering
371       folder_path = tmpStr;
372       free(tmpStr);
373       tmpStr = NULL;
374     }
375   }
376
377   // title
378   ret = media_folder_get_name(folder, &tmpStr);
379   if (ret == MEDIA_CONTENT_ERROR_NONE) {
380     if (tmpStr) {
381       o["title"] = picojson::value(std::string(tmpStr));
382       free(tmpStr);
383       tmpStr = NULL;
384     }
385   }
386
387   // modifiedDate
388   struct stat stat_res;
389   if (stat(folder_path.c_str(), &stat_res) == 0) {
390     auto mod_time = stat_res.st_mtime;
391     o["modifiedDate"] = picojson::value(static_cast<double>(mod_time));
392   }
393 }
394
395 static int setContent(media_info_h media, const picojson::value& content) {
396   ScopeLogger();
397
398   int ret = MEDIA_CONTENT_ERROR_NONE;
399   bool is_fav = content.get("isFavorite").get<bool>();
400
401   if (NULL == media) {
402     LoggerE("MEDIA_CONTENT_ERROR_DB_FAILED");
403     return MEDIA_CONTENT_ERROR_DB_FAILED;
404   }
405
406   media_content_type_e type;
407   ret = media_info_get_media_type(media, &type);
408   if (ret != MEDIA_CONTENT_ERROR_NONE) {
409     LoggerE("Failed: media_info_get_media_type()");
410     return ret;
411   }
412
413   ret = media_info_set_favorite(media, is_fav);
414   if (ret != MEDIA_CONTENT_ERROR_NONE) {
415     LoggerE("Updating isFavorite failed.");
416   }
417
418   if (ret != MEDIA_CONTENT_ERROR_NONE) {
419     LoggerE("Updating favorite failed.");
420   }
421
422   return MEDIA_CONTENT_ERROR_NONE;
423 }
424
425 static int updateContent(const picojson::value& content) {
426   ScopeLogger();
427
428   int ret = MEDIA_CONTENT_ERROR_NONE;
429   std::string id = content.get("id").to_str();
430   media_info_h media = nullptr;
431   SCOPE_EXIT {
432     if (media) {
433       media_info_destroy(media);
434     }
435   };
436
437   ret = media_info_get_media_from_db(id.c_str(), &media);
438   if (ret != MEDIA_CONTENT_ERROR_NONE) {
439     LoggerE("media_info_get_media_from_db failed: %d", ret);
440     return ret;
441   }
442   ret = setContent(media, content);
443   if (ret != MEDIA_CONTENT_ERROR_NONE) {
444     LoggerE("setContent failed: %d", ret);
445     return ret;
446   }
447   ret = media_info_update_to_db(media);
448   if (ret != MEDIA_CONTENT_ERROR_NONE) {
449     LoggerE("media_info_update_to_db failed: %d", ret);
450     return ret;
451   }
452
453   return ret;
454 }
455
456 static void FolderToJson(media_folder_h folder, picojson::object* out) {
457   ScopeLogger();
458
459   char* name = NULL;
460   char* id = NULL;
461   char* path = NULL;
462   time_t date;
463
464   int ret;
465
466   ret = media_folder_get_folder_id(folder, &id);
467   if (ret != MEDIA_CONTENT_ERROR_NONE) {
468     LogAndReportError(ContentManager::convertError(ret), out,
469                       ("Failed: media_folder_get_folder_id"));
470     return;
471   }
472   std::unique_ptr<char, decltype(&free)> id_ptr(id, &free);
473
474   ret = media_folder_get_name(folder, &name);
475   if (ret != MEDIA_CONTENT_ERROR_NONE) {
476     LogAndReportError(ContentManager::convertError(ret), out, ("Failed: media_folder_get_name"));
477     return;
478   }
479   std::unique_ptr<char, decltype(&free)> name_ptr(name, &free);
480
481   ret = media_folder_get_path(folder, &path);
482   if (ret != MEDIA_CONTENT_ERROR_NONE) {
483     LogAndReportError(ContentManager::convertError(ret), out, ("Failed: media_folder_get_path"));
484     return;
485   }
486   std::unique_ptr<char, decltype(&free)> path_ptr(path, &free);
487
488   struct stat stat_res;
489   ret = stat(path, &stat_res);
490   if (0 != ret) {
491     LogAndReportError(ContentManager::convertError(errno), out, ("Failed: stat"));
492     return;
493   }
494   date = stat_res.st_mtime;
495
496   (*out)["id"] = picojson::value(std::string(id));
497   (*out)["directoryURI"] = picojson::value(std::string(path));
498   (*out)["title"] = picojson::value(std::string(name));
499
500   (*out)["modifiedDate"] = picojson::value(static_cast<double>(date));
501 }
502
503 static bool media_foreach_directory_cb(media_folder_h folder, void* user_data) {
504   ScopeLogger();
505   picojson::array* array = static_cast<picojson::array*>(user_data);
506   picojson::object json;
507   FolderToJson(folder, &json);
508   array->push_back(picojson::value(json));
509   return true;
510 }
511
512 static bool media_foreach_content_cb(media_info_h media, void* user_data) {
513   ScopeLogger();
514   picojson::value::array* contents = static_cast<picojson::value::array*>(user_data);
515   picojson::value::object o;
516   ContentToJson(media, o);
517   contents->push_back(picojson::value(o));
518   return true;
519 }
520
521 static bool playlist_foreach_cb(media_playlist_h playlist, void* user_data) {
522   ScopeLogger();
523   picojson::value::array* playlists = static_cast<picojson::value::array*>(user_data);
524   picojson::value::object o;
525   if (playlist != NULL) {
526     int id, cnt;
527     char* thumb_path = NULL;
528     char* name = NULL;
529     filter_h filter = NULL;
530     if (media_playlist_get_playlist_id(playlist, &id) == MEDIA_CONTENT_ERROR_NONE) {
531       std::stringstream str_id;
532       str_id << id;
533       o["id"] = picojson::value(std::to_string(id));
534     } else {
535       LoggerD("Invalid ID for playlist.");
536     }
537     if (media_playlist_get_thumbnail_path(playlist, &thumb_path) == MEDIA_CONTENT_ERROR_NONE) {
538       if (thumb_path != NULL) {
539         std::string thumbnail_uri(thumb_path);
540         if (thumbnail_uri != " ") {
541           thumbnail_uri = uri_prefix + thumbnail_uri;
542         }
543         o["thumbnailURI"] = picojson::value(thumbnail_uri);
544         free(thumb_path);
545       } else {
546         o["thumbnailURI"] = picojson::value();  // picojson::value(std::string(""));
547       }
548     } else {
549       LoggerD("Invalid thumbnail path for playlist.");
550     }
551     if (media_playlist_get_name(playlist, &name) == MEDIA_CONTENT_ERROR_NONE) {
552       o["name"] = picojson::value(std::string(name));
553       free(name);
554     } else {
555       LoggerD("Invalid name for playlist.");
556     }
557
558     media_filter_create(&filter);
559     std::unique_ptr<std::remove_pointer<filter_h>::type, int (*)(filter_h)> filter_ptr(
560         filter, &media_filter_destroy);  // automatically release the memory
561     if (media_playlist_get_media_count_from_db(id, filter, &cnt) == MEDIA_CONTENT_ERROR_NONE) {
562       o["numberOfTracks"] = picojson::value(static_cast<double>(cnt));
563     } else {
564       LoggerE("Invalid count for playlist.");
565     }
566     playlists->push_back(picojson::value(o));
567   }
568   return true;
569 }
570
571 static bool playlist_content_member_cb(int playlist_member_id, media_info_h media,
572                                        void* user_data) {
573   ScopeLogger();
574   picojson::value::array* contents = static_cast<picojson::value::array*>(user_data);
575   picojson::value::object o;
576
577   o["playlist_member_id"] = picojson::value(static_cast<double>(playlist_member_id));
578   ContentToJson(media, o);
579   contents->push_back(picojson::value(o));
580   return true;
581 }
582
583 ContentManager::ContentManager() {
584   ScopeLogger("ContentManager called");
585   if (media_content_connect() == MEDIA_CONTENT_ERROR_NONE) {
586     m_dbConnected = true;
587   } else {
588     m_dbConnected = false;
589   }
590   m_contentInstance = nullptr;
591 }
592
593 ContentManager::~ContentManager() {
594   ScopeLogger();
595   if (m_dbConnected) {
596     if (media_content_disconnect() == MEDIA_CONTENT_ERROR_NONE) {
597       m_dbConnected = false;
598     }
599   }
600 }
601
602 ContentManager* ContentManager::getInstance() {
603   ScopeLogger();
604   static ContentManager instance;
605   return &instance;
606 }
607
608 ContentInstance* ContentManager::getContentInstance() {
609   ScopeLogger();
610   return m_contentInstance;
611 }
612
613 void ContentManager::setContentInstance(ContentInstance* const content_instance) {
614   ScopeLogger();
615   m_contentInstance = content_instance;
616 }
617
618 bool ContentManager::isConnected() {
619   ScopeLogger();
620   return m_dbConnected;
621 }
622
623 void ContentManager::getDirectories(const std::shared_ptr<ReplyCallbackData>& user_data) {
624   ScopeLogger();
625   int ret;
626
627   picojson::array pico_dirs;
628   ret = media_folder_foreach_folder_from_db(nullptr, media_foreach_directory_cb,
629                                             &pico_dirs);
630   if (ret != MEDIA_CONTENT_ERROR_NONE) {
631     PlatformResult err = LogAndCreateResult(
632         ErrorCode::UNKNOWN_ERR, "Getting the directories failed.",
633         ("Failed: Getting the directories failed %d (%s)", ret, get_error_message(ret)));
634     user_data->isSuccess = err;
635     return;
636   }
637
638   user_data->result = picojson::value(pico_dirs);
639 }
640
641 void ContentManager::find(const std::shared_ptr<ReplyCallbackData>& user_data) {
642   ScopeLogger();
643
644   int ret;
645   int count, offset;
646   std::string dirId;
647
648   picojson::value::array arrayContent;
649   filter_h filter = nullptr;
650   media_filter_create(&filter);
651   SCOPE_EXIT {
652     if (filter) {
653       media_filter_destroy(filter);
654     }
655   };
656
657   if (!IsNull(user_data->args.get("filter"))) {
658     ContentFilter filterMechanism;
659     std::string query;
660     picojson::object argsObject = JsonCast<picojson::object>(user_data->args);
661     if (filterMechanism.BuildQuery(FromJson<picojson::object>(argsObject, "filter"), &query)) {
662       LoggerD("Filter query: %s", query.c_str());
663       ret = media_filter_set_condition(filter, query.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT);
664       if (MEDIA_CONTENT_ERROR_NONE != ret) {
665         LoggerE("Platform filter setting failed, error %d", ret);
666       }
667     }
668   }
669
670   if (user_data->args.contains("sortMode")) {
671     picojson::value vSortMode = user_data->args.get("sortMode");
672
673     if (vSortMode.is<picojson::object>()) {
674       std::string sortModeName, sortModeOrder;
675
676       ContentFilter::MapField(vSortMode.get("attributeName").to_str(), &sortModeName);
677
678       sortModeOrder = vSortMode.get("order").to_str();
679       if (!sortModeOrder.empty()) {
680         media_content_order_e order = MEDIA_CONTENT_ORDER_ASC;
681
682         if (sortModeOrder == "ASC") {
683           order = MEDIA_CONTENT_ORDER_ASC;
684         } else if (sortModeOrder == "DESC") {
685           order = MEDIA_CONTENT_ORDER_DESC;
686         }
687
688         ret = media_filter_set_order(filter, order, sortModeName.c_str(),
689                                      MEDIA_CONTENT_COLLATE_DEFAULT);
690         if (MEDIA_CONTENT_ERROR_NONE != ret) {
691           LoggerE("Platform SortMode setting failed, error: %d", ret);
692         }
693       }
694     }
695   }
696
697   if (!IsNull(user_data->args.get("count"))) {
698     count = static_cast<int>(user_data->args.get("count").get<double>());
699   } else {
700     count = -1;
701   }
702   if (!IsNull(user_data->args.get("offset"))) {
703     offset = static_cast<int>(user_data->args.get("offset").get<double>());
704   } else {
705     offset = -1;
706   }
707   ret = media_filter_set_offset(filter, offset, count);
708   if (MEDIA_CONTENT_ERROR_NONE != ret) {
709     LoggerE("A platform error occurs in media_filter_set_offset: %d", ret);
710   }
711   if (!IsNull(user_data->args.get("directoryId"))) {
712     dirId = user_data->args.get("directoryId").get<std::string>();
713     ret = media_folder_foreach_media_from_db(dirId.c_str(), filter, media_foreach_content_cb,
714                                              static_cast<void*>(&arrayContent));
715   } else {
716     ret = media_info_foreach_media_from_db(filter, media_foreach_content_cb,
717                                            static_cast<void*>(&arrayContent));
718   }
719
720   if (ret == MEDIA_CONTENT_ERROR_NONE) {
721     user_data->result = picojson::value(arrayContent);
722   } else {
723     PlatformResult err = LogAndCreateResult(
724         ErrorCode::UNKNOWN_ERR, "The iteration failed in platform",
725         ("The iteration failed in platform: %d (%s)", ret, get_error_message(ret)));
726     user_data->isSuccess = err;
727   }
728 }
729
730 int ContentManager::scanFile(std::string& uri) {
731   ScopeLogger();
732   return media_content_scan_file(uri.c_str());
733 }
734
735 PlatformResult ContentManager::scanDirectory(media_scan_completed_cb callback,
736                                              ReplyCallbackData* cbData) {
737   ScopeLogger();
738   const std::string& contentDirURI = cbData->args.get("contentDirURI").get<std::string>();
739   std::string real_path = common::FilesystemProvider::Create().GetRealPath(contentDirURI);
740   const bool recursive = cbData->args.get("recursive").get<bool>();
741
742   int ret = media_content_scan_folder(real_path.c_str(), recursive, callback, (void*)cbData);
743
744   if (ret != MEDIA_CONTENT_ERROR_NONE) {
745     if (MEDIA_CONTENT_ERROR_INVALID_PARAMETER == ret) {
746       return LogAndCreateResult(
747           ErrorCode::INVALID_VALUES_ERR, "Scanning content directory failed",
748           ("Scan folder failed in platform: %d (%s)", ret, get_error_message(ret)));
749
750     } else {
751       return LogAndCreateResult(
752           ErrorCode::UNKNOWN_ERR, "Scanning content directory failed",
753           ("Scan folder failed in platform: %d (%s)", ret, get_error_message(ret)));
754     }
755   }
756   return PlatformResult(ErrorCode::NO_ERROR);
757 }
758
759 PlatformResult ContentManager::cancelScanDirectory(const std::string& content_dir_uri) {
760   ScopeLogger();
761
762   int ret = media_content_cancel_scan_folder(content_dir_uri.c_str());
763   if (ret != MEDIA_CONTENT_ERROR_NONE) {
764     return LogAndCreateResult(
765         ErrorCode::UNKNOWN_ERR, "Cancel scan content directory failed",
766         ("Cancel scan folder failed in platform: %d (%s)", ret, get_error_message(ret)));
767   }
768   return PlatformResult(ErrorCode::NO_ERROR);
769 }
770
771 PlatformResult ContentManager::addChangeListener(media_content_noti_h* noti_handle,
772                                                  media_content_db_update_cb callback,
773                                                  void* user_data) {
774   ScopeLogger();
775
776   int ret = media_content_add_db_updated_cb(callback, user_data, noti_handle);
777
778   if (MEDIA_CONTENT_ERROR_NONE != ret) {
779     return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to add the listener.",
780                               ("Failed to add the listener: %d (%s)", ret, get_error_message(ret)));
781   }
782
783   return PlatformResult(ErrorCode::NO_ERROR);
784 }
785
786 PlatformResult ContentManager::removeChangeListener(media_content_noti_h noti_handle) {
787   ScopeLogger();
788
789   int ret = media_content_remove_db_updated_cb(noti_handle);
790
791   switch (ret) {
792     case MEDIA_CONTENT_ERROR_NONE:
793       return PlatformResult(ErrorCode::NO_ERROR);
794     case MEDIA_CONTENT_ERROR_INVALID_PARAMETER:
795       // Trying to remove non-existent listener, ignoring
796       LoggerI("Failed to remove the listener: %d (%s)", ret, get_error_message(ret));
797       return PlatformResult(ErrorCode::NO_ERROR);
798     default:
799       return LogAndCreateResult(
800           ErrorCode::ABORT_ERR, "Failed to remove the listener.",
801           ("Failed to remove the listener: %d (%s)", ret, get_error_message(ret)));
802   }
803 }
804
805 void ContentManager::createPlaylist(std::string name,
806                                     const std::shared_ptr<ReplyCallbackData>& user_data) {
807   ScopeLogger();
808   media_playlist_h playlist = NULL;
809
810   int ret = media_playlist_insert_to_db(name.c_str(), &playlist);
811   std::unique_ptr<std::remove_pointer<media_playlist_h>::type, int (*)(media_playlist_h)>
812       playlist_ptr(playlist, &media_playlist_destroy);  // automatically release the memory
813   if (ret != MEDIA_CONTENT_ERROR_NONE) {
814     // MEDIA_CONTENT_ERROR_DB_FAILED means that playlist probably already exists
815     PlatformResult err = LogAndCreateResult(
816         MEDIA_CONTENT_ERROR_DB_FAILED == ret ? ErrorCode::INVALID_VALUES_ERR
817                                              : ErrorCode::UNKNOWN_ERR,
818         "Creation of playlist has failed.",
819         ("Failed: creation of playlist is failed: %d (%s)", ret, get_error_message(ret)));
820     user_data->isSuccess = err;
821     return;
822   }
823   picojson::value::object o;
824
825   if (playlist != NULL) {
826     int id, cnt;
827     char* thumb_path = NULL;
828     char* name_playlist = NULL;
829     filter_h filter = NULL;
830     if (media_playlist_get_playlist_id(playlist, &id) == MEDIA_CONTENT_ERROR_NONE) {
831       o["id"] = picojson::value(std::to_string(id));
832     } else {
833       PlatformResult err =
834           LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "loading of playlist is failed.");
835       user_data->isSuccess = err;
836       return;
837     }
838     if (media_playlist_get_thumbnail_path(playlist, &thumb_path) == MEDIA_CONTENT_ERROR_NONE) {
839       if (thumb_path != NULL) {
840         o["thumbnailURI"] = picojson::value(std::string(thumb_path));
841         free(thumb_path);
842       } else {
843         o["thumbnailURI"] = picojson::value();
844       }
845     } else {
846       LoggerE("Invalid thumbnail path for playlist.");
847     }
848     if (media_playlist_get_name(playlist, &name_playlist) == MEDIA_CONTENT_ERROR_NONE) {
849       o["name"] = picojson::value(std::string(name_playlist));
850       free(name_playlist);
851     } else {
852       LoggerE("Invalid name for playlist.");
853     }
854     media_filter_create(&filter);
855     std::unique_ptr<std::remove_pointer<filter_h>::type, int (*)(filter_h)> filter_ptr(
856         filter, &media_filter_destroy);  // automatically release the memory
857
858     if (media_playlist_get_media_count_from_db(id, filter, &cnt) == MEDIA_CONTENT_ERROR_NONE) {
859       o["numberOfTracks"] = picojson::value(static_cast<double>(cnt));
860     } else {
861       LoggerE("Invalid count for playlist.");
862     }
863   }
864
865   user_data->result = picojson::value(o);
866 }
867
868 void ContentManager::getPlaylists(const std::shared_ptr<ReplyCallbackData>& user_data) {
869   ScopeLogger();
870   int ret;
871   filter_h filter = nullptr;
872   media_filter_create(&filter);
873   std::unique_ptr<std::remove_pointer<filter_h>::type, int (*)(filter_h)> filter_ptr(
874       filter, &media_filter_destroy);  // automatically release the memory
875   picojson::value::array playlists;
876
877   ret = media_playlist_foreach_playlist_from_db(filter, playlist_foreach_cb,
878                                                 static_cast<void*>(&playlists));
879
880   if (ret != MEDIA_CONTENT_ERROR_NONE) {
881     PlatformResult err = LogAndCreateResult(
882         ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
883         ("Failed: Getting playlist is failed %d (%s)", ret, get_error_message(ret)));
884     user_data->isSuccess = err;
885   }
886
887   user_data->result = picojson::value(playlists);
888 }
889
890 void ContentManager::removePlaylist(std::string playlistId,
891                                     const std::shared_ptr<ReplyCallbackData>& user_data) {
892   ScopeLogger();
893   int id = std::atoi(playlistId.c_str());
894   if (id == 0) {
895     PlatformResult err = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "PlaylistId is wrong.");
896     user_data->isSuccess = err;
897     return;
898   }
899
900   int ret = media_playlist_delete_from_db(id);
901   if (ret != MEDIA_CONTENT_ERROR_NONE) {
902     PlatformResult err =
903         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Removal of playlist is failed.");
904     user_data->isSuccess = err;
905   }
906 }
907
908 int ContentManager::update(const picojson::value& args) {
909   ScopeLogger();
910   const picojson::value content = args.get("content");
911   int ret = updateContent(content);
912   if (ret != MEDIA_CONTENT_ERROR_NONE) {
913     LoggerE("updateContent failed: %d", ret);
914   }
915   return ret;
916 }
917
918 int ContentManager::updateBatch(const picojson::value& args) {
919   ScopeLogger();
920   int ret = MEDIA_CONTENT_ERROR_NONE;
921   std::vector<picojson::value> contents = args.get("contents").get<picojson::array>();
922
923   for (picojson::value::array::iterator it = contents.begin(); it != contents.end(); ++it) {
924     const picojson::value content = *it;
925     ret = updateContent(content);
926     if (ret != MEDIA_CONTENT_ERROR_NONE) {
927       LoggerE("updateContent failed: %d", ret);
928       break;
929     }
930   }
931   return ret;
932 }
933
934 int ContentManager::playlistAdd(std::string playlist_id, std::string content_id) {
935   ScopeLogger();
936
937   media_playlist_h playlist = NULL;
938   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
939
940   if (playlist != NULL && ret == MEDIA_CONTENT_ERROR_NONE) {
941     ret = media_playlist_add_media(playlist, content_id.c_str());
942     if (ret != MEDIA_CONTENT_ERROR_NONE) {
943       LoggerE("The content(id:%s) can't add to playlist", content_id.c_str());
944     }
945
946     ret = media_playlist_update_to_db(playlist);
947     if (ret != MEDIA_CONTENT_ERROR_NONE) {
948       LoggerE("The content(id:%s) can't add to playlist", content_id.c_str());
949     }
950   } else {
951     LoggerE("Playlist(id:%s) is not exist", playlist_id.c_str());
952   }
953
954   media_playlist_destroy(playlist);
955   return ret;
956 }
957
958 int ContentManager::playlistRemove(std::string playlist_id, int member_id) {
959   ScopeLogger();
960
961   media_playlist_h playlist = NULL;
962   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
963   if (playlist != NULL && ret == MEDIA_CONTENT_ERROR_NONE) {
964     ret = media_playlist_remove_media(playlist, member_id);
965     if (ret != MEDIA_CONTENT_ERROR_NONE) {
966       LoggerE("The content can't remove to playlist");
967     }
968
969     ret = media_playlist_update_to_db(playlist);
970     if (ret != MEDIA_CONTENT_ERROR_NONE) {
971       LoggerE("The content can't remove to playlist");
972     }
973   } else {
974     LoggerE("Playlist(id:%s) is not exist", playlist_id.c_str());
975   }
976   media_playlist_destroy(playlist);
977
978   return ret;
979 }
980
981 void ContentManager::playlistAddbatch(const std::shared_ptr<ReplyCallbackData>& user_data) {
982   ScopeLogger();
983   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
984
985   media_playlist_h playlist = NULL;
986   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
987
988   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
989     PlatformResult err =
990         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
991                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
992     user_data->isSuccess = err;
993     return;
994   }
995
996   std::vector<picojson::value> contents = user_data->args.get("contents").get<picojson::array>();
997   for (picojson::value::array::iterator it = contents.begin(); it != contents.end(); ++it) {
998     picojson::value content = *it;
999     std::string id = content.get("id").to_str();
1000     ret = media_playlist_add_media(playlist, id.c_str());
1001     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1002       LoggerE("Adding Content(id:%s) is failed.", id.c_str());
1003     }
1004   }
1005
1006   ret = media_playlist_update_to_db(playlist);
1007   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1008     PlatformResult err =
1009         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Adding playlist is failed.",
1010                            ("Adding playlist is failed: %d (%s)", ret, get_error_message(ret)));
1011     user_data->isSuccess = err;
1012   }
1013   media_playlist_destroy(playlist);
1014 }
1015
1016 void ContentManager::playlistGet(const std::shared_ptr<ReplyCallbackData>& user_data) {
1017   ScopeLogger();
1018   media_playlist_h playlist = NULL;
1019   media_content_order_e order = MEDIA_CONTENT_ORDER_ASC;
1020   const std::string playOrder("playlist_member_order");
1021
1022   SCOPE_EXIT {
1023     if (playlist) {
1024       media_playlist_destroy(playlist);
1025     }
1026   };
1027
1028   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1029   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1030   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1031     PlatformResult err =
1032         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1033                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1034     user_data->isSuccess = err;
1035     return;
1036   }
1037
1038   filter_h filter = NULL;
1039   ret = media_filter_create(&filter);
1040   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1041     PlatformResult err =
1042         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Creating a filter is failed.",
1043                            ("Creating a filter is failed: %d (%s)", ret, get_error_message(ret)));
1044     user_data->isSuccess = err;
1045     return;
1046   }
1047
1048   int count = user_data->args.get("count").get<double>();
1049   int offset = user_data->args.get("offset").get<double>();
1050   ret = media_filter_set_offset(filter, offset, count);
1051   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1052     LoggerD("Setting a offset/count is failed.");
1053   }
1054   ret = media_filter_set_order(filter, order, playOrder.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT);
1055   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1056     LoggerD("Setting a offset/count is failed.");
1057   }
1058
1059   picojson::value::array arrayContent;
1060   ret = media_playlist_foreach_media_from_db(std::stoi(playlist_id), filter,
1061                                              playlist_content_member_cb,
1062                                              static_cast<void*>(&arrayContent));
1063
1064   media_filter_destroy(filter);
1065   if (ret == MEDIA_CONTENT_ERROR_NONE) {
1066     user_data->result = picojson::value(arrayContent);
1067   } else {
1068     PlatformResult err =
1069         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Creating a filter is failed.",
1070                            ("Creating a filter is failed: %d (%s)", ret, get_error_message(ret)));
1071     user_data->isSuccess = err;
1072   }
1073 }
1074
1075 void ContentManager::playlistRemovebatch(const std::shared_ptr<ReplyCallbackData>& user_data) {
1076   ScopeLogger();
1077   media_playlist_h playlist = NULL;
1078
1079   SCOPE_EXIT {
1080     if (playlist) {
1081       media_playlist_destroy(playlist);
1082     }
1083   };
1084
1085   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1086   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1087   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1088     PlatformResult err =
1089         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1090                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1091     user_data->isSuccess = err;
1092     return;
1093   }
1094
1095   std::vector<picojson::value> members = user_data->args.get("members").get<picojson::array>();
1096   std::size_t members_size = members.size();
1097   for (std::size_t i = 0; i < members_size; ++i) {
1098     int member_id = static_cast<int>(members.at(i).get<double>());
1099     ret = media_playlist_remove_media(playlist, member_id);
1100
1101     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1102       LoggerD("Removing a content is failed.");
1103     }
1104   }
1105
1106   ret = media_playlist_update_to_db(playlist);
1107   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1108     PlatformResult err = LogAndCreateResult(
1109         ErrorCode::UNKNOWN_ERR, "Removing the contents is failed.",
1110         ("Removing the contents is failed: %d (%s)", ret, get_error_message(ret)));
1111     user_data->isSuccess = err;
1112   }
1113 }
1114
1115 void ContentManager::playlistSetOrder(const std::shared_ptr<ReplyCallbackData>& user_data) {
1116   ScopeLogger();
1117   media_playlist_h playlist = NULL;
1118
1119   SCOPE_EXIT {
1120     if (playlist) {
1121       media_playlist_destroy(playlist);
1122     }
1123   };
1124
1125   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1126   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1127   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1128     PlatformResult err =
1129         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1130                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1131     user_data->isSuccess = err;
1132     return;
1133   }
1134
1135   int cnt;
1136   std::vector<picojson::value> members = user_data->args.get("members").get<picojson::array>();
1137
1138   ret = media_playlist_get_media_count_from_db(std::stoi(playlist_id), NULL, &cnt);
1139   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1140     LoggerE("Failed: media_playlist_get_media_count_from_db");
1141     PlatformResult err = convertError(ret);
1142     user_data->isSuccess = err;
1143     return;
1144   }
1145   std::size_t members_size = members.size();
1146   if (cnt < 0 || static_cast<size_t>(cnt) != members_size) {
1147     PlatformResult err = LogAndCreateResult(
1148         ErrorCode::INVALID_VALUES_ERR,
1149         "The items array does not contain all items from the playlist.",
1150         ("Failed: The items array does not contain all items from the playlist: %d (%s)", ret,
1151          get_error_message(ret)));
1152     user_data->isSuccess = err;
1153     return;
1154   }
1155
1156   for (std::size_t i = 0; i < members_size; ++i) {
1157     int member_id = static_cast<int>(members.at(i).get<double>());
1158     ret = media_playlist_set_play_order(playlist, member_id, i);
1159     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1160       LoggerD("Removing a content is failed.");
1161     }
1162   }
1163
1164   ret = media_playlist_update_to_db(playlist);
1165   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1166     PlatformResult err = LogAndCreateResult(
1167         ErrorCode::UNKNOWN_ERR, "Removing the contents is failed.",
1168         ("Removing the contents is failed: %d (%s)", ret, get_error_message(ret)));
1169     user_data->isSuccess = err;
1170   }
1171 }
1172
1173 void ContentManager::playlistMove(const std::shared_ptr<ReplyCallbackData>& user_data) {
1174   ScopeLogger();
1175   media_playlist_h playlist = NULL;
1176
1177   SCOPE_EXIT {
1178     if (playlist) {
1179       media_playlist_destroy(playlist);
1180     }
1181   };
1182
1183   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1184   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1185   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1186     PlatformResult err =
1187         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1188                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1189     user_data->isSuccess = err;
1190     return;
1191   }
1192   int old_order;
1193   double member_id = user_data->args.get("memberId").get<double>();
1194   double delta = user_data->args.get("delta").get<double>();
1195   ret = media_playlist_get_play_order(playlist, static_cast<int>(member_id), &old_order);
1196   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1197     PlatformResult err = LogAndCreateResult(
1198         ErrorCode::UNKNOWN_ERR, "The content can't find form playlist.",
1199         ("The content can't find form playlist: %d (%s)", ret, get_error_message(ret)));
1200     user_data->isSuccess = err;
1201     return;
1202   }
1203   int new_order = static_cast<int>(old_order) + static_cast<int>(delta);
1204   ret = media_playlist_set_play_order(playlist, static_cast<int>(member_id), new_order);
1205   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1206     PlatformResult err = LogAndCreateResult(
1207         ErrorCode::UNKNOWN_ERR, "The content can't update play_order.",
1208         ("The content can't update play_order: %d (%s)", ret, get_error_message(ret)));
1209     user_data->isSuccess = err;
1210     return;
1211   }
1212   ret = media_playlist_update_to_db(playlist);
1213   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1214     PlatformResult err = LogAndCreateResult(
1215         ErrorCode::UNKNOWN_ERR, "Updateing play_order is failed.",
1216         ("Updateing play_order is failed: %d (%s)", ret, get_error_message(ret)));
1217     user_data->isSuccess = err;
1218   }
1219 }
1220
1221 int ContentManager::getLyrics(const picojson::value& args, picojson::object& result) {
1222   ScopeLogger();
1223
1224   int ret = METADATA_EXTRACTOR_ERROR_NONE;
1225   const std::string& contentURI = args.get("contentURI").to_str();
1226   if (contentURI.empty()) {
1227     LoggerE("contentURI empty - skipping media extractor");
1228     return -1;
1229   }
1230
1231   metadata_extractor_h extractor;
1232   ret = metadata_extractor_create(&extractor);
1233   if (METADATA_EXTRACTOR_ERROR_NONE != ret) {
1234     LoggerE("metadata_extractor_create failed, error: %d", ret);
1235   }
1236   std::unique_ptr<std::remove_pointer<metadata_extractor_h>::type, int (*)(metadata_extractor_h)>
1237       extractor_ptr(extractor, &metadata_extractor_destroy);  // automatically release the memory
1238
1239   ret = metadata_extractor_set_path(extractor, contentURI.c_str());
1240   if (ret != METADATA_EXTRACTOR_ERROR_NONE) {
1241     LoggerE("metadata_extractor_set_path failed, error: %d", ret);
1242     return ret;
1243   }
1244   picojson::array timestamps;
1245   picojson::array texts = picojson::array();
1246   char* strSyncTextNum = NULL;
1247
1248   ret = metadata_extractor_get_metadata(extractor, METADATA_SYNCLYRICS_NUM, &strSyncTextNum);
1249   if (ret != METADATA_EXTRACTOR_ERROR_NONE) {
1250     LoggerE("Media extractor error %d", ret);
1251     return ret;
1252   }
1253
1254   int nSyncTextNum = 0;
1255   if (strSyncTextNum) {
1256     nSyncTextNum = atoi(strSyncTextNum);
1257     free(strSyncTextNum);
1258     strSyncTextNum = NULL;
1259   }
1260   if (nSyncTextNum > 0) {
1261     result["type"] = picojson::value(std::string("SYNCHRONIZED"));
1262     for (int i = 0; i < nSyncTextNum; i++) {
1263       unsigned long time_info = 0;
1264       char* lyrics = NULL;
1265       ret = metadata_extractor_get_synclyrics(extractor, i, &time_info, &lyrics);
1266       if (ret == METADATA_EXTRACTOR_ERROR_NONE) {
1267         timestamps.push_back(picojson::value(static_cast<double>(time_info)));
1268         texts.push_back(picojson::value(std::string(lyrics)));
1269         free(lyrics);
1270       }
1271     }
1272     result["texts"] = picojson::value(texts);
1273     result["timestamps"] = picojson::value(timestamps);
1274     ret = METADATA_EXTRACTOR_ERROR_NONE;
1275   } else {
1276     char* unSyncText = nullptr;
1277     ret = metadata_extractor_get_metadata(extractor, METADATA_UNSYNCLYRICS, &unSyncText);
1278     if (ret == METADATA_EXTRACTOR_ERROR_NONE) {
1279       result["type"] = picojson::value(std::string("UNSYNCHRONIZED"));
1280       if (nullptr == unSyncText) {
1281         LoggerE("Unsynchronized lyrics text is NULL");
1282       }
1283       texts.push_back(picojson::value(unSyncText ? unSyncText : ""));
1284       result["texts"] = picojson::value(texts);
1285       free(unSyncText);
1286     }
1287   }
1288
1289   return ret;
1290 }
1291
1292 media_playlist_h getPlaylistHandle(int id) {
1293   ScopeLogger();
1294   media_playlist_h playlist_handle = nullptr;
1295   int ret_code = media_playlist_get_playlist_from_db(id, &playlist_handle);
1296   if (MEDIA_CONTENT_ERROR_NONE != ret_code || playlist_handle == nullptr) {
1297     LoggerE("could not get playlist handle for id: %d", id);
1298     return nullptr;
1299   }
1300
1301   return playlist_handle;
1302 }
1303
1304 void destroyMediaPlaylistHandle(media_playlist_h playlist_handle) {
1305   ScopeLogger();
1306   if (playlist_handle) {
1307     int ret_code = media_playlist_destroy(playlist_handle);
1308     playlist_handle = nullptr;
1309
1310     if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1311       LoggerE("media_playlist_destroy failed");
1312     }
1313   }
1314 }
1315
1316 int ContentManager::getPlaylistName(int id, std::string* result) {
1317   ScopeLogger();
1318   media_playlist_h playlist_handle = getPlaylistHandle(id);
1319   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1320
1321   char* tmp_playlist_name = nullptr;
1322   const int ret_code = media_playlist_get_name(playlist_handle, &tmp_playlist_name);
1323
1324   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1325     LoggerE("media_playlist_get_name failed");
1326     return TIZEN_ERROR_UNKNOWN;
1327   }
1328
1329   std::string playlist_name;
1330   if (tmp_playlist_name) {
1331     playlist_name = tmp_playlist_name;
1332     free(tmp_playlist_name);
1333     tmp_playlist_name = nullptr;
1334   }
1335
1336   *result = playlist_name;
1337   return MEDIA_CONTENT_ERROR_NONE;
1338 }
1339
1340 int updatePlaylistInDB(media_playlist_h playlist_handle) {
1341   ScopeLogger();
1342   int ret_code = media_playlist_update_to_db(playlist_handle);
1343   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1344     LoggerE("media_playlist_update_to_db failed");
1345     return ret_code;
1346   }
1347   return MEDIA_CONTENT_ERROR_NONE;
1348 }
1349
1350 int ContentManager::setPlaylistName(int id, const std::string& name) {
1351   ScopeLogger();
1352   if (name.empty()) {
1353     LoggerE("Cannot set empty playlist name!");
1354     return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
1355   }
1356
1357   media_playlist_h playlist_handle = getPlaylistHandle(id);
1358   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1359
1360   const int ret_code = media_playlist_set_name(playlist_handle, name.c_str());
1361   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1362     LoggerE("media_playlist_set_name failed");
1363     // Setting name that is used by other playlist does not return bad error code here.
1364     // MEDIA_CONTENT_ERROR_INVALID_OPERATION is being returned in updatePlaylistInDB
1365     return TIZEN_ERROR_UNKNOWN;
1366   }
1367
1368   int ret = updatePlaylistInDB(playlist_handle);
1369   if (MEDIA_CONTENT_ERROR_NONE != ret) {
1370     LoggerE("Error while updating playlist: %d", ret);
1371     if (MEDIA_CONTENT_ERROR_DB_FAILED == ret) {
1372       // We could fetch list of playlists and check if other playlist is using this
1373       // name, but that seems to be to much work in synchronous method
1374       LoggerE("Playlist name: %s is probably already used", name.c_str());
1375       return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
1376     }
1377     return ret;
1378   }
1379   return MEDIA_CONTENT_ERROR_NONE;
1380 }
1381
1382 int ContentManager::getThumbnailUri(int id, std::string* result) {
1383   ScopeLogger();
1384   media_playlist_h playlist_handle = getPlaylistHandle(id);
1385   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1386
1387   char* tmp_playlist_thb_path = nullptr;
1388   const int ret_code = media_playlist_get_thumbnail_path(playlist_handle, &tmp_playlist_thb_path);
1389
1390   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1391     LoggerE("media_playlist_get_name failed");
1392     return TIZEN_ERROR_UNKNOWN;
1393   }
1394
1395   std::string playlist_thb_path;
1396   if (tmp_playlist_thb_path) {
1397     playlist_thb_path = tmp_playlist_thb_path;
1398     free(tmp_playlist_thb_path);
1399     tmp_playlist_thb_path = nullptr;
1400   }
1401
1402   if (playlist_thb_path != " ") {
1403     playlist_thb_path = uri_prefix + playlist_thb_path;
1404   }
1405
1406   *result = playlist_thb_path;
1407   return MEDIA_CONTENT_ERROR_NONE;
1408 }
1409
1410 int ContentManager::setThumbnailUri(int id, const std::string& thb_uri) {
1411   ScopeLogger();
1412
1413   // Allow setting empty URI, unfortunately Core API does not allow to set empty
1414   // path so we need to set one empty space. This is probably issue of Core API.
1415   if (!thb_uri.empty() && " " != thb_uri) {
1416     if (thb_uri.find(uri_absolute_prefix) != 0) {
1417       LoggerE("thumbnail URI is not valid: [%s]", thb_uri.c_str());
1418       return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
1419     }
1420   }
1421
1422   media_playlist_h playlist_handle = getPlaylistHandle(id);
1423   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1424
1425   std::string real_path = common::FilesystemProvider::Create().GetRealPath(thb_uri);
1426   const int ret_code = media_playlist_set_thumbnail_path(playlist_handle, real_path.c_str());
1427   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1428     LoggerE("media_playlist_set_thumbnail_path failed");
1429     return TIZEN_ERROR_UNKNOWN;
1430   }
1431
1432   int ret = updatePlaylistInDB(playlist_handle);
1433   return ret;
1434 }
1435
1436 int ContentManager::getNumberOfTracks(int id, int* result) {
1437   ScopeLogger();
1438
1439   int count = 0;
1440   const int ret_code = media_playlist_get_media_count_from_db(id, nullptr, &count);
1441
1442   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1443     LoggerE("media_playlist_get_media_count_from_db failed");
1444     return TIZEN_ERROR_UNKNOWN;
1445   }
1446
1447   *result = count;
1448   return MEDIA_CONTENT_ERROR_NONE;
1449 }
1450
1451 common::PlatformResult ContentManager::createThumbnail(const std::string& id,
1452                                                        picojson::object* obj) {
1453   ScopeLogger();
1454
1455   media_info_h media_h = nullptr;
1456   int ret = media_info_get_media_from_db(id.c_str(), &media_h);
1457   if (MEDIA_CONTENT_ERROR_NONE != ret || nullptr == media_h) {
1458     return LogAndCreateResult(ErrorCode::ABORT_ERR, "Getting media failed.",
1459                               ("Getting media failed: %d (%s)", ret, get_error_message(ret)));
1460   }
1461   SCOPE_EXIT {
1462     media_info_destroy(media_h);
1463   };
1464
1465   ret = media_info_generate_thumbnail(media_h);
1466   if (MEDIA_CONTENT_ERROR_NONE != ret) {
1467     return LogAndCreateResult(ErrorCode::ABORT_ERR, "Creating thumbnail failed.",
1468                               ("Creating thumbnail failed: %d (%s)", ret, get_error_message(ret)));
1469   }
1470
1471   char* path = nullptr;
1472   ret = media_info_get_thumbnail_path(media_h, &path);
1473   if (MEDIA_CONTENT_ERROR_NONE != ret) {
1474     return LogAndCreateResult(
1475         ErrorCode::ABORT_ERR, "Creating thumbnail succeeded, but failed to get thumbnail path.",
1476         ("Getting thumbnail path failed: %d (%s)", ret, get_error_message(ret)));
1477   }
1478   obj->emplace("result", picojson::value(path));
1479   std::unique_ptr<char[], decltype(&free)>(path, free);
1480   return PlatformResult(ErrorCode::NO_ERROR);
1481 }
1482
1483 PlatformResult ContentManager::convertError(int err) {
1484   char* error_msg = get_error_message(err);
1485   switch (err) {
1486     case MEDIA_CONTENT_ERROR_INVALID_PARAMETER:
1487       return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, error_msg);
1488     case MEDIA_CONTENT_ERROR_OUT_OF_MEMORY:
1489       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1490     case MEDIA_CONTENT_ERROR_INVALID_OPERATION:
1491       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1492     case MEDIA_CONTENT_FILE_NO_SPACE_ON_DEVICE:
1493       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1494     case MEDIA_CONTENT_ERROR_PERMISSION_DENIED:
1495       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1496     case MEDIA_CONTENT_ERROR_DB_FAILED:
1497       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1498     case MEDIA_CONTENT_ERROR_DB_BUSY:
1499       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1500     case MEDIA_CONTENT_ERROR_NETWORK:
1501       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1502     case MEDIA_CONTENT_ERROR_UNSUPPORTED_CONTENT:
1503       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1504     default:
1505       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error.");
1506   }
1507 }
1508
1509 }  // namespace content
1510 }  // namespace extension