Merge "[Common] Fixing Coverity issues: AUTO_CAUSES_COPY" into tizen
[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   filter_h filter = NULL;
627   ret = media_filter_create(&filter);
628   if (ret != MEDIA_CONTENT_ERROR_NONE) {
629     LoggerE("Failed: media_filter_create failed");
630     return;
631   }
632
633   SCOPE_EXIT {
634     media_filter_destroy(filter);
635   };
636
637   std::string condition = "(FOLDER_STORAGE_TYPE = 0 OR FOLDER_STORAGE_TYPE = 1)";
638   media_filter_set_condition(filter, condition.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT);
639
640   picojson::array pico_dirs;
641   ret = media_folder_foreach_folder_from_db(filter, media_foreach_directory_cb, &pico_dirs);
642   if (ret != MEDIA_CONTENT_ERROR_NONE) {
643     PlatformResult err = LogAndCreateResult(
644         ErrorCode::UNKNOWN_ERR, "Getting the directories failed.",
645         ("Failed: Getting the directories failed %d (%s)", ret, get_error_message(ret)));
646     user_data->isSuccess = err;
647     return;
648   }
649
650   user_data->result = picojson::value(pico_dirs);
651 }
652
653 void ContentManager::find(const std::shared_ptr<ReplyCallbackData>& user_data) {
654   ScopeLogger();
655
656   int ret;
657   int count, offset;
658   std::string dirId;
659
660   picojson::value::array arrayContent;
661   filter_h filter = nullptr;
662   media_filter_create(&filter);
663   SCOPE_EXIT {
664     if (filter) {
665       media_filter_destroy(filter);
666     }
667   };
668
669   if (!IsNull(user_data->args.get("filter"))) {
670     ContentFilter filterMechanism;
671     std::string query;
672     picojson::object argsObject = JsonCast<picojson::object>(user_data->args);
673     if (filterMechanism.BuildQuery(FromJson<picojson::object>(argsObject, "filter"), &query)) {
674       LoggerD("Filter query: %s", query.c_str());
675       ret = media_filter_set_condition(filter, query.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT);
676       if (MEDIA_CONTENT_ERROR_NONE != ret) {
677         LoggerE("Platform filter setting failed, error %d", ret);
678       }
679     }
680   }
681
682   if (user_data->args.contains("sortMode")) {
683     picojson::value vSortMode = user_data->args.get("sortMode");
684
685     if (vSortMode.is<picojson::object>()) {
686       std::string sortModeName, sortModeOrder;
687
688       ContentFilter::MapField(vSortMode.get("attributeName").to_str(), &sortModeName);
689
690       sortModeOrder = vSortMode.get("order").to_str();
691       if (!sortModeOrder.empty()) {
692         media_content_order_e order = MEDIA_CONTENT_ORDER_ASC;
693
694         if (sortModeOrder == "ASC") {
695           order = MEDIA_CONTENT_ORDER_ASC;
696         } else if (sortModeOrder == "DESC") {
697           order = MEDIA_CONTENT_ORDER_DESC;
698         }
699
700         ret = media_filter_set_order(filter, order, sortModeName.c_str(),
701                                      MEDIA_CONTENT_COLLATE_DEFAULT);
702         if (MEDIA_CONTENT_ERROR_NONE != ret) {
703           LoggerE("Platform SortMode setting failed, error: %d", ret);
704         }
705       }
706     }
707   }
708
709   if (!IsNull(user_data->args.get("count"))) {
710     count = static_cast<int>(user_data->args.get("count").get<double>());
711   } else {
712     count = -1;
713   }
714   if (!IsNull(user_data->args.get("offset"))) {
715     offset = static_cast<int>(user_data->args.get("offset").get<double>());
716   } else {
717     offset = -1;
718   }
719   ret = media_filter_set_offset(filter, offset, count);
720   if (MEDIA_CONTENT_ERROR_NONE != ret) {
721     LoggerE("A platform error occurs in media_filter_set_offset: %d", ret);
722   }
723   if (!IsNull(user_data->args.get("directoryId"))) {
724     dirId = user_data->args.get("directoryId").get<std::string>();
725     ret = media_folder_foreach_media_from_db(dirId.c_str(), filter, media_foreach_content_cb,
726                                              static_cast<void*>(&arrayContent));
727   } else {
728     ret = media_info_foreach_media_from_db(filter, media_foreach_content_cb,
729                                            static_cast<void*>(&arrayContent));
730   }
731
732   if (ret == MEDIA_CONTENT_ERROR_NONE) {
733     user_data->result = picojson::value(arrayContent);
734   } else {
735     PlatformResult err = LogAndCreateResult(
736         ErrorCode::UNKNOWN_ERR, "The iteration failed in platform",
737         ("The iteration failed in platform: %d (%s)", ret, get_error_message(ret)));
738     user_data->isSuccess = err;
739   }
740 }
741
742 int ContentManager::scanFile(std::string& uri) {
743   ScopeLogger();
744   return media_content_scan_file(uri.c_str());
745 }
746
747 PlatformResult ContentManager::scanDirectory(media_scan_completed_cb callback,
748                                              ReplyCallbackData* cbData) {
749   ScopeLogger();
750   const std::string& contentDirURI = cbData->args.get("contentDirURI").get<std::string>();
751   std::string real_path = common::FilesystemProvider::Create().GetRealPath(contentDirURI);
752   const bool recursive = cbData->args.get("recursive").get<bool>();
753
754   int ret = media_content_scan_folder(real_path.c_str(), recursive, callback, (void*)cbData);
755
756   if (ret != MEDIA_CONTENT_ERROR_NONE) {
757     if (MEDIA_CONTENT_ERROR_INVALID_PARAMETER == ret) {
758       return LogAndCreateResult(
759           ErrorCode::INVALID_VALUES_ERR, "Scanning content directory failed",
760           ("Scan folder failed in platform: %d (%s)", ret, get_error_message(ret)));
761
762     } else {
763       return LogAndCreateResult(
764           ErrorCode::UNKNOWN_ERR, "Scanning content directory failed",
765           ("Scan folder failed in platform: %d (%s)", ret, get_error_message(ret)));
766     }
767   }
768   return PlatformResult(ErrorCode::NO_ERROR);
769 }
770
771 PlatformResult ContentManager::cancelScanDirectory(const std::string& content_dir_uri) {
772   ScopeLogger();
773
774   int ret = media_content_cancel_scan_folder(content_dir_uri.c_str());
775   if (ret != MEDIA_CONTENT_ERROR_NONE) {
776     return LogAndCreateResult(
777         ErrorCode::UNKNOWN_ERR, "Cancel scan content directory failed",
778         ("Cancel scan folder failed in platform: %d (%s)", ret, get_error_message(ret)));
779   }
780   return PlatformResult(ErrorCode::NO_ERROR);
781 }
782
783 PlatformResult ContentManager::addChangeListener(media_content_noti_h* noti_handle,
784                                                  media_content_db_update_cb callback,
785                                                  void* user_data) {
786   ScopeLogger();
787
788   int ret = media_content_add_db_updated_cb(callback, user_data, noti_handle);
789
790   if (MEDIA_CONTENT_ERROR_NONE != ret) {
791     return LogAndCreateResult(ErrorCode::ABORT_ERR, "Failed to add the listener.",
792                               ("Failed to add the listener: %d (%s)", ret, get_error_message(ret)));
793   }
794
795   return PlatformResult(ErrorCode::NO_ERROR);
796 }
797
798 PlatformResult ContentManager::removeChangeListener(media_content_noti_h noti_handle) {
799   ScopeLogger();
800
801   int ret = media_content_remove_db_updated_cb(noti_handle);
802
803   switch (ret) {
804     case MEDIA_CONTENT_ERROR_NONE:
805       return PlatformResult(ErrorCode::NO_ERROR);
806     case MEDIA_CONTENT_ERROR_INVALID_PARAMETER:
807       // Trying to remove non-existent listener, ignoring
808       LoggerI("Failed to remove the listener: %d (%s)", ret, get_error_message(ret));
809       return PlatformResult(ErrorCode::NO_ERROR);
810     default:
811       return LogAndCreateResult(
812           ErrorCode::ABORT_ERR, "Failed to remove the listener.",
813           ("Failed to remove the listener: %d (%s)", ret, get_error_message(ret)));
814   }
815 }
816
817 void ContentManager::createPlaylist(std::string name,
818                                     const std::shared_ptr<ReplyCallbackData>& user_data) {
819   ScopeLogger();
820   media_playlist_h playlist = NULL;
821
822   int ret = media_playlist_insert_to_db(name.c_str(), &playlist);
823   std::unique_ptr<std::remove_pointer<media_playlist_h>::type, int (*)(media_playlist_h)>
824       playlist_ptr(playlist, &media_playlist_destroy);  // automatically release the memory
825   if (ret != MEDIA_CONTENT_ERROR_NONE) {
826     // MEDIA_CONTENT_ERROR_DB_FAILED means that playlist probably already exists
827     PlatformResult err = LogAndCreateResult(
828         MEDIA_CONTENT_ERROR_DB_FAILED == ret ? ErrorCode::INVALID_VALUES_ERR
829                                              : ErrorCode::UNKNOWN_ERR,
830         "Creation of playlist has failed.",
831         ("Failed: creation of playlist is failed: %d (%s)", ret, get_error_message(ret)));
832     user_data->isSuccess = err;
833     return;
834   }
835   picojson::value::object o;
836
837   if (playlist != NULL) {
838     int id, cnt;
839     char* thumb_path = NULL;
840     char* name_playlist = NULL;
841     filter_h filter = NULL;
842     if (media_playlist_get_playlist_id(playlist, &id) == MEDIA_CONTENT_ERROR_NONE) {
843       o["id"] = picojson::value(std::to_string(id));
844     } else {
845       PlatformResult err =
846           LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "loading of playlist is failed.");
847       user_data->isSuccess = err;
848       return;
849     }
850     if (media_playlist_get_thumbnail_path(playlist, &thumb_path) == MEDIA_CONTENT_ERROR_NONE) {
851       if (thumb_path != NULL) {
852         o["thumbnailURI"] = picojson::value(std::string(thumb_path));
853         free(thumb_path);
854       } else {
855         o["thumbnailURI"] = picojson::value();
856       }
857     } else {
858       LoggerE("Invalid thumbnail path for playlist.");
859     }
860     if (media_playlist_get_name(playlist, &name_playlist) == MEDIA_CONTENT_ERROR_NONE) {
861       o["name"] = picojson::value(std::string(name_playlist));
862       free(name_playlist);
863     } else {
864       LoggerE("Invalid name for playlist.");
865     }
866     media_filter_create(&filter);
867     std::unique_ptr<std::remove_pointer<filter_h>::type, int (*)(filter_h)> filter_ptr(
868         filter, &media_filter_destroy);  // automatically release the memory
869
870     if (media_playlist_get_media_count_from_db(id, filter, &cnt) == MEDIA_CONTENT_ERROR_NONE) {
871       o["numberOfTracks"] = picojson::value(static_cast<double>(cnt));
872     } else {
873       LoggerE("Invalid count for playlist.");
874     }
875   }
876
877   user_data->result = picojson::value(o);
878 }
879
880 void ContentManager::getPlaylists(const std::shared_ptr<ReplyCallbackData>& user_data) {
881   ScopeLogger();
882   int ret;
883   filter_h filter = nullptr;
884   media_filter_create(&filter);
885   std::unique_ptr<std::remove_pointer<filter_h>::type, int (*)(filter_h)> filter_ptr(
886       filter, &media_filter_destroy);  // automatically release the memory
887   picojson::value::array playlists;
888
889   ret = media_playlist_foreach_playlist_from_db(filter, playlist_foreach_cb,
890                                                 static_cast<void*>(&playlists));
891
892   if (ret != MEDIA_CONTENT_ERROR_NONE) {
893     PlatformResult err = LogAndCreateResult(
894         ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
895         ("Failed: Getting playlist is failed %d (%s)", ret, get_error_message(ret)));
896     user_data->isSuccess = err;
897   }
898
899   user_data->result = picojson::value(playlists);
900 }
901
902 void ContentManager::removePlaylist(std::string playlistId,
903                                     const std::shared_ptr<ReplyCallbackData>& user_data) {
904   ScopeLogger();
905   int id = std::atoi(playlistId.c_str());
906   if (id == 0) {
907     PlatformResult err = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "PlaylistId is wrong.");
908     user_data->isSuccess = err;
909     return;
910   }
911
912   int ret = media_playlist_delete_from_db(id);
913   if (ret != MEDIA_CONTENT_ERROR_NONE) {
914     PlatformResult err =
915         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Removal of playlist is failed.");
916     user_data->isSuccess = err;
917   }
918 }
919
920 int ContentManager::update(const picojson::value& args) {
921   ScopeLogger();
922   const picojson::value content = args.get("content");
923   int ret = updateContent(content);
924   if (ret != MEDIA_CONTENT_ERROR_NONE) {
925     LoggerE("updateContent failed: %d", ret);
926   }
927   return ret;
928 }
929
930 int ContentManager::updateBatch(const picojson::value& args) {
931   ScopeLogger();
932   int ret = MEDIA_CONTENT_ERROR_NONE;
933   std::vector<picojson::value> contents = args.get("contents").get<picojson::array>();
934
935   for (picojson::value::array::iterator it = contents.begin(); it != contents.end(); ++it) {
936     const picojson::value content = *it;
937     ret = updateContent(content);
938     if (ret != MEDIA_CONTENT_ERROR_NONE) {
939       LoggerE("updateContent failed: %d", ret);
940       break;
941     }
942   }
943   return ret;
944 }
945
946 int ContentManager::playlistAdd(std::string playlist_id, std::string content_id) {
947   ScopeLogger();
948
949   media_playlist_h playlist = NULL;
950   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
951
952   if (playlist != NULL && ret == MEDIA_CONTENT_ERROR_NONE) {
953     ret = media_playlist_add_media(playlist, content_id.c_str());
954     if (ret != MEDIA_CONTENT_ERROR_NONE) {
955       LoggerE("The content(id:%s) can't add to playlist", content_id.c_str());
956     }
957
958     ret = media_playlist_update_to_db(playlist);
959     if (ret != MEDIA_CONTENT_ERROR_NONE) {
960       LoggerE("The content(id:%s) can't add to playlist", content_id.c_str());
961     }
962   } else {
963     LoggerE("Playlist(id:%s) is not exist", playlist_id.c_str());
964   }
965
966   media_playlist_destroy(playlist);
967   return ret;
968 }
969
970 int ContentManager::playlistRemove(std::string playlist_id, int member_id) {
971   ScopeLogger();
972
973   media_playlist_h playlist = NULL;
974   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
975   if (playlist != NULL && ret == MEDIA_CONTENT_ERROR_NONE) {
976     ret = media_playlist_remove_media(playlist, member_id);
977     if (ret != MEDIA_CONTENT_ERROR_NONE) {
978       LoggerE("The content can't remove to playlist");
979     }
980
981     ret = media_playlist_update_to_db(playlist);
982     if (ret != MEDIA_CONTENT_ERROR_NONE) {
983       LoggerE("The content can't remove to playlist");
984     }
985   } else {
986     LoggerE("Playlist(id:%s) is not exist", playlist_id.c_str());
987   }
988   media_playlist_destroy(playlist);
989
990   return ret;
991 }
992
993 void ContentManager::playlistAddbatch(const std::shared_ptr<ReplyCallbackData>& user_data) {
994   ScopeLogger();
995   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
996
997   media_playlist_h playlist = NULL;
998   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
999
1000   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1001     PlatformResult err =
1002         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1003                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1004     user_data->isSuccess = err;
1005     return;
1006   }
1007
1008   std::vector<picojson::value> contents = user_data->args.get("contents").get<picojson::array>();
1009   for (picojson::value::array::iterator it = contents.begin(); it != contents.end(); ++it) {
1010     picojson::value content = *it;
1011     std::string id = content.get("id").to_str();
1012     ret = media_playlist_add_media(playlist, id.c_str());
1013     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1014       LoggerE("Adding Content(id:%s) is failed.", id.c_str());
1015     }
1016   }
1017
1018   ret = media_playlist_update_to_db(playlist);
1019   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1020     PlatformResult err =
1021         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Adding playlist is failed.",
1022                            ("Adding playlist is failed: %d (%s)", ret, get_error_message(ret)));
1023     user_data->isSuccess = err;
1024   }
1025   media_playlist_destroy(playlist);
1026 }
1027
1028 void ContentManager::playlistGet(const std::shared_ptr<ReplyCallbackData>& user_data) {
1029   ScopeLogger();
1030   media_playlist_h playlist = NULL;
1031   media_content_order_e order = MEDIA_CONTENT_ORDER_ASC;
1032   const std::string playOrder("playlist_member_order");
1033
1034   SCOPE_EXIT {
1035     if (playlist) {
1036       media_playlist_destroy(playlist);
1037     }
1038   };
1039
1040   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1041   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1042   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1043     PlatformResult err =
1044         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1045                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1046     user_data->isSuccess = err;
1047     return;
1048   }
1049
1050   filter_h filter = NULL;
1051   ret = media_filter_create(&filter);
1052   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1053     PlatformResult err =
1054         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Creating a filter is failed.",
1055                            ("Creating a filter is failed: %d (%s)", ret, get_error_message(ret)));
1056     user_data->isSuccess = err;
1057     return;
1058   }
1059
1060   int count = user_data->args.get("count").get<double>();
1061   int offset = user_data->args.get("offset").get<double>();
1062   ret = media_filter_set_offset(filter, offset, count);
1063   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1064     LoggerD("Setting a offset/count is failed.");
1065   }
1066   ret = media_filter_set_order(filter, order, playOrder.c_str(), MEDIA_CONTENT_COLLATE_DEFAULT);
1067   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1068     LoggerD("Setting a offset/count is failed.");
1069   }
1070
1071   picojson::value::array arrayContent;
1072   ret = media_playlist_foreach_media_from_db(std::stoi(playlist_id), filter,
1073                                              playlist_content_member_cb,
1074                                              static_cast<void*>(&arrayContent));
1075
1076   media_filter_destroy(filter);
1077   if (ret == MEDIA_CONTENT_ERROR_NONE) {
1078     user_data->result = picojson::value(arrayContent);
1079   } else {
1080     PlatformResult err =
1081         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Creating a filter is failed.",
1082                            ("Creating a filter is failed: %d (%s)", ret, get_error_message(ret)));
1083     user_data->isSuccess = err;
1084   }
1085 }
1086
1087 void ContentManager::playlistRemovebatch(const std::shared_ptr<ReplyCallbackData>& user_data) {
1088   ScopeLogger();
1089   media_playlist_h playlist = NULL;
1090
1091   SCOPE_EXIT {
1092     if (playlist) {
1093       media_playlist_destroy(playlist);
1094     }
1095   };
1096
1097   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1098   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1099   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1100     PlatformResult err =
1101         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1102                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1103     user_data->isSuccess = err;
1104     return;
1105   }
1106
1107   std::vector<picojson::value> members = user_data->args.get("members").get<picojson::array>();
1108   std::size_t members_size = members.size();
1109   for (std::size_t i = 0; i < members_size; ++i) {
1110     int member_id = static_cast<int>(members.at(i).get<double>());
1111     ret = media_playlist_remove_media(playlist, member_id);
1112
1113     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1114       LoggerD("Removing a content is failed.");
1115     }
1116   }
1117
1118   ret = media_playlist_update_to_db(playlist);
1119   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1120     PlatformResult err = LogAndCreateResult(
1121         ErrorCode::UNKNOWN_ERR, "Removing the contents is failed.",
1122         ("Removing the contents is failed: %d (%s)", ret, get_error_message(ret)));
1123     user_data->isSuccess = err;
1124   }
1125 }
1126
1127 void ContentManager::playlistSetOrder(const std::shared_ptr<ReplyCallbackData>& user_data) {
1128   ScopeLogger();
1129   media_playlist_h playlist = NULL;
1130
1131   SCOPE_EXIT {
1132     if (playlist) {
1133       media_playlist_destroy(playlist);
1134     }
1135   };
1136
1137   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1138   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1139   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1140     PlatformResult err =
1141         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1142                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1143     user_data->isSuccess = err;
1144     return;
1145   }
1146
1147   int cnt;
1148   std::vector<picojson::value> members = user_data->args.get("members").get<picojson::array>();
1149
1150   ret = media_playlist_get_media_count_from_db(std::stoi(playlist_id), NULL, &cnt);
1151   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1152     LoggerE("Failed: media_playlist_get_media_count_from_db");
1153     PlatformResult err = convertError(ret);
1154     user_data->isSuccess = err;
1155     return;
1156   }
1157   std::size_t members_size = members.size();
1158   if (cnt < 0 || static_cast<size_t>(cnt) != members_size) {
1159     PlatformResult err = LogAndCreateResult(
1160         ErrorCode::INVALID_VALUES_ERR,
1161         "The items array does not contain all items from the playlist.",
1162         ("Failed: The items array does not contain all items from the playlist: %d (%s)", ret,
1163          get_error_message(ret)));
1164     user_data->isSuccess = err;
1165     return;
1166   }
1167
1168   for (std::size_t i = 0; i < members_size; ++i) {
1169     int member_id = static_cast<int>(members.at(i).get<double>());
1170     ret = media_playlist_set_play_order(playlist, member_id, i);
1171     if (ret != MEDIA_CONTENT_ERROR_NONE) {
1172       LoggerD("Removing a content is failed.");
1173     }
1174   }
1175
1176   ret = media_playlist_update_to_db(playlist);
1177   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1178     PlatformResult err = LogAndCreateResult(
1179         ErrorCode::UNKNOWN_ERR, "Removing the contents is failed.",
1180         ("Removing the contents is failed: %d (%s)", ret, get_error_message(ret)));
1181     user_data->isSuccess = err;
1182   }
1183 }
1184
1185 void ContentManager::playlistMove(const std::shared_ptr<ReplyCallbackData>& user_data) {
1186   ScopeLogger();
1187   media_playlist_h playlist = NULL;
1188
1189   SCOPE_EXIT {
1190     if (playlist) {
1191       media_playlist_destroy(playlist);
1192     }
1193   };
1194
1195   std::string playlist_id = user_data->args.get("playlistId").get<std::string>();
1196   int ret = media_playlist_get_playlist_from_db(std::stoi(playlist_id), &playlist);
1197   if (ret != MEDIA_CONTENT_ERROR_NONE && playlist == NULL) {
1198     PlatformResult err =
1199         LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Getting playlist is failed.",
1200                            ("Getting playlist is failed: %d (%s)", ret, get_error_message(ret)));
1201     user_data->isSuccess = err;
1202     return;
1203   }
1204   int old_order;
1205   double member_id = user_data->args.get("memberId").get<double>();
1206   double delta = user_data->args.get("delta").get<double>();
1207   ret = media_playlist_get_play_order(playlist, static_cast<int>(member_id), &old_order);
1208   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1209     PlatformResult err = LogAndCreateResult(
1210         ErrorCode::UNKNOWN_ERR, "The content can't find form playlist.",
1211         ("The content can't find form playlist: %d (%s)", ret, get_error_message(ret)));
1212     user_data->isSuccess = err;
1213     return;
1214   }
1215   int new_order = static_cast<int>(old_order) + static_cast<int>(delta);
1216   ret = media_playlist_set_play_order(playlist, static_cast<int>(member_id), new_order);
1217   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1218     PlatformResult err = LogAndCreateResult(
1219         ErrorCode::UNKNOWN_ERR, "The content can't update play_order.",
1220         ("The content can't update play_order: %d (%s)", ret, get_error_message(ret)));
1221     user_data->isSuccess = err;
1222     return;
1223   }
1224   ret = media_playlist_update_to_db(playlist);
1225   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1226     PlatformResult err = LogAndCreateResult(
1227         ErrorCode::UNKNOWN_ERR, "Updateing play_order is failed.",
1228         ("Updateing play_order is failed: %d (%s)", ret, get_error_message(ret)));
1229     user_data->isSuccess = err;
1230   }
1231 }
1232
1233 int ContentManager::getLyrics(const picojson::value& args, picojson::object& result) {
1234   ScopeLogger();
1235
1236   int ret = METADATA_EXTRACTOR_ERROR_NONE;
1237   const std::string& contentURI = args.get("contentURI").to_str();
1238   if (contentURI.empty()) {
1239     LoggerE("contentURI empty - skipping media extractor");
1240     return -1;
1241   }
1242
1243   metadata_extractor_h extractor;
1244   ret = metadata_extractor_create(&extractor);
1245   if (METADATA_EXTRACTOR_ERROR_NONE != ret) {
1246     LoggerE("metadata_extractor_create failed, error: %d", ret);
1247   }
1248   std::unique_ptr<std::remove_pointer<metadata_extractor_h>::type, int (*)(metadata_extractor_h)>
1249       extractor_ptr(extractor, &metadata_extractor_destroy);  // automatically release the memory
1250
1251   ret = metadata_extractor_set_path(extractor, contentURI.c_str());
1252   if (ret != METADATA_EXTRACTOR_ERROR_NONE) {
1253     LoggerE("metadata_extractor_set_path failed, error: %d", ret);
1254     return ret;
1255   }
1256   picojson::array timestamps;
1257   picojson::array texts = picojson::array();
1258   char* strSyncTextNum = NULL;
1259
1260   ret = metadata_extractor_get_metadata(extractor, METADATA_SYNCLYRICS_NUM, &strSyncTextNum);
1261   if (ret != METADATA_EXTRACTOR_ERROR_NONE) {
1262     LoggerE("Media extractor error %d", ret);
1263     return ret;
1264   }
1265
1266   int nSyncTextNum = 0;
1267   if (strSyncTextNum) {
1268     nSyncTextNum = atoi(strSyncTextNum);
1269     free(strSyncTextNum);
1270     strSyncTextNum = NULL;
1271   }
1272   if (nSyncTextNum > 0) {
1273     result["type"] = picojson::value(std::string("SYNCHRONIZED"));
1274     for (int i = 0; i < nSyncTextNum; i++) {
1275       unsigned long time_info = 0;
1276       char* lyrics = NULL;
1277       ret = metadata_extractor_get_synclyrics(extractor, i, &time_info, &lyrics);
1278       if (ret == METADATA_EXTRACTOR_ERROR_NONE) {
1279         timestamps.push_back(picojson::value(static_cast<double>(time_info)));
1280         texts.push_back(picojson::value(std::string(lyrics)));
1281         free(lyrics);
1282       }
1283     }
1284     result["texts"] = picojson::value(texts);
1285     result["timestamps"] = picojson::value(timestamps);
1286     ret = METADATA_EXTRACTOR_ERROR_NONE;
1287   } else {
1288     char* unSyncText = nullptr;
1289     ret = metadata_extractor_get_metadata(extractor, METADATA_UNSYNCLYRICS, &unSyncText);
1290     if (ret == METADATA_EXTRACTOR_ERROR_NONE) {
1291       result["type"] = picojson::value(std::string("UNSYNCHRONIZED"));
1292       if (nullptr == unSyncText) {
1293         LoggerE("Unsynchronized lyrics text is NULL");
1294       }
1295       texts.push_back(picojson::value(unSyncText ? unSyncText : ""));
1296       result["texts"] = picojson::value(texts);
1297       free(unSyncText);
1298     }
1299   }
1300
1301   return ret;
1302 }
1303
1304 media_playlist_h getPlaylistHandle(int id) {
1305   ScopeLogger();
1306   media_playlist_h playlist_handle = nullptr;
1307   int ret_code = media_playlist_get_playlist_from_db(id, &playlist_handle);
1308   if (MEDIA_CONTENT_ERROR_NONE != ret_code || playlist_handle == nullptr) {
1309     LoggerE("could not get playlist handle for id: %d", id);
1310     return nullptr;
1311   }
1312
1313   return playlist_handle;
1314 }
1315
1316 void destroyMediaPlaylistHandle(media_playlist_h playlist_handle) {
1317   ScopeLogger();
1318   if (playlist_handle) {
1319     int ret_code = media_playlist_destroy(playlist_handle);
1320     playlist_handle = nullptr;
1321
1322     if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1323       LoggerE("media_playlist_destroy failed");
1324     }
1325   }
1326 }
1327
1328 int ContentManager::getPlaylistName(int id, std::string* result) {
1329   ScopeLogger();
1330   media_playlist_h playlist_handle = getPlaylistHandle(id);
1331   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1332
1333   char* tmp_playlist_name = nullptr;
1334   const int ret_code = media_playlist_get_name(playlist_handle, &tmp_playlist_name);
1335
1336   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1337     LoggerE("media_playlist_get_name failed");
1338     return TIZEN_ERROR_UNKNOWN;
1339   }
1340
1341   std::string playlist_name;
1342   if (tmp_playlist_name) {
1343     playlist_name = tmp_playlist_name;
1344     free(tmp_playlist_name);
1345     tmp_playlist_name = nullptr;
1346   }
1347
1348   *result = playlist_name;
1349   return MEDIA_CONTENT_ERROR_NONE;
1350 }
1351
1352 int updatePlaylistInDB(media_playlist_h playlist_handle) {
1353   ScopeLogger();
1354   int ret_code = media_playlist_update_to_db(playlist_handle);
1355   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1356     LoggerE("media_playlist_update_to_db failed");
1357     return ret_code;
1358   }
1359   return MEDIA_CONTENT_ERROR_NONE;
1360 }
1361
1362 int ContentManager::setPlaylistName(int id, const std::string& name) {
1363   ScopeLogger();
1364   if (name.empty()) {
1365     LoggerE("Cannot set empty playlist name!");
1366     return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
1367   }
1368
1369   media_playlist_h playlist_handle = getPlaylistHandle(id);
1370   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1371
1372   const int ret_code = media_playlist_set_name(playlist_handle, name.c_str());
1373   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1374     LoggerE("media_playlist_set_name failed");
1375     // Setting name that is used by other playlist does not return bad error code here.
1376     // MEDIA_CONTENT_ERROR_INVALID_OPERATION is being returned in updatePlaylistInDB
1377     return TIZEN_ERROR_UNKNOWN;
1378   }
1379
1380   int ret = updatePlaylistInDB(playlist_handle);
1381   if (MEDIA_CONTENT_ERROR_NONE != ret) {
1382     LoggerE("Error while updating playlist: %d", ret);
1383     if (MEDIA_CONTENT_ERROR_DB_FAILED == ret) {
1384       // We could fetch list of playlists and check if other playlist is using this
1385       // name, but that seems to be to much work in synchronous method
1386       LoggerE("Playlist name: %s is probably already used", name.c_str());
1387       return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
1388     }
1389     return ret;
1390   }
1391   return MEDIA_CONTENT_ERROR_NONE;
1392 }
1393
1394 int ContentManager::getThumbnailUri(int id, std::string* result) {
1395   ScopeLogger();
1396   media_playlist_h playlist_handle = getPlaylistHandle(id);
1397   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1398
1399   char* tmp_playlist_thb_path = nullptr;
1400   const int ret_code = media_playlist_get_thumbnail_path(playlist_handle, &tmp_playlist_thb_path);
1401
1402   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1403     LoggerE("media_playlist_get_name failed");
1404     return TIZEN_ERROR_UNKNOWN;
1405   }
1406
1407   std::string playlist_thb_path;
1408   if (tmp_playlist_thb_path) {
1409     playlist_thb_path = tmp_playlist_thb_path;
1410     free(tmp_playlist_thb_path);
1411     tmp_playlist_thb_path = nullptr;
1412   }
1413
1414   if (playlist_thb_path != " ") {
1415     playlist_thb_path = uri_prefix + playlist_thb_path;
1416   }
1417
1418   *result = playlist_thb_path;
1419   return MEDIA_CONTENT_ERROR_NONE;
1420 }
1421
1422 int ContentManager::setThumbnailUri(int id, const std::string& thb_uri) {
1423   ScopeLogger();
1424
1425   // Allow setting empty URI, unfortunately Core API does not allow to set empty
1426   // path so we need to set one empty space. This is probably issue of Core API.
1427   if (!thb_uri.empty() && " " != thb_uri) {
1428     if (thb_uri.find(uri_absolute_prefix) != 0) {
1429       LoggerE("thumbnail URI is not valid: [%s]", thb_uri.c_str());
1430       return MEDIA_CONTENT_ERROR_INVALID_PARAMETER;
1431     }
1432   }
1433
1434   media_playlist_h playlist_handle = getPlaylistHandle(id);
1435   PlaylistUniquePtr playlist_ptr(playlist_handle, destroyMediaPlaylistHandle);
1436
1437   std::string real_path = common::FilesystemProvider::Create().GetRealPath(thb_uri);
1438   const int ret_code = media_playlist_set_thumbnail_path(playlist_handle, real_path.c_str());
1439   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1440     LoggerE("media_playlist_set_thumbnail_path failed");
1441     return TIZEN_ERROR_UNKNOWN;
1442   }
1443
1444   int ret = updatePlaylistInDB(playlist_handle);
1445   return ret;
1446 }
1447
1448 int ContentManager::getNumberOfTracks(int id, int* result) {
1449   ScopeLogger();
1450
1451   int count = 0;
1452   const int ret_code = media_playlist_get_media_count_from_db(id, nullptr, &count);
1453
1454   if (MEDIA_CONTENT_ERROR_NONE != ret_code) {
1455     LoggerE("media_playlist_get_media_count_from_db failed");
1456     return TIZEN_ERROR_UNKNOWN;
1457   }
1458
1459   *result = count;
1460   return MEDIA_CONTENT_ERROR_NONE;
1461 }
1462
1463 common::PlatformResult ContentManager::createThumbnail(const std::string& id,
1464                                                        picojson::object* obj) {
1465   ScopeLogger();
1466
1467   media_info_h media_h = nullptr;
1468   int ret = media_info_get_media_from_db(id.c_str(), &media_h);
1469   if (MEDIA_CONTENT_ERROR_NONE != ret || nullptr == media_h) {
1470     return LogAndCreateResult(ErrorCode::ABORT_ERR, "Getting media failed.",
1471                               ("Getting media failed: %d (%s)", ret, get_error_message(ret)));
1472   }
1473   SCOPE_EXIT {
1474     media_info_destroy(media_h);
1475   };
1476
1477   ret = media_info_generate_thumbnail(media_h);
1478   if (MEDIA_CONTENT_ERROR_NONE != ret) {
1479     return LogAndCreateResult(ErrorCode::ABORT_ERR, "Creating thumbnail failed.",
1480                               ("Creating thumbnail failed: %d (%s)", ret, get_error_message(ret)));
1481   }
1482
1483   char* path = nullptr;
1484   ret = media_info_get_thumbnail_path(media_h, &path);
1485   if (MEDIA_CONTENT_ERROR_NONE != ret) {
1486     return LogAndCreateResult(
1487         ErrorCode::ABORT_ERR, "Creating thumbnail succeeded, but failed to get thumbnail path.",
1488         ("Getting thumbnail path failed: %d (%s)", ret, get_error_message(ret)));
1489   }
1490   obj->emplace("result", picojson::value(path));
1491   std::unique_ptr<char[], decltype(&free)>(path, free);
1492   return PlatformResult(ErrorCode::NO_ERROR);
1493 }
1494
1495 PlatformResult ContentManager::convertError(int err) {
1496   char* error_msg = get_error_message(err);
1497   switch (err) {
1498     case MEDIA_CONTENT_ERROR_INVALID_PARAMETER:
1499       return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, error_msg);
1500     case MEDIA_CONTENT_ERROR_OUT_OF_MEMORY:
1501       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1502     case MEDIA_CONTENT_ERROR_INVALID_OPERATION:
1503       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1504     case MEDIA_CONTENT_FILE_NO_SPACE_ON_DEVICE:
1505       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1506     case MEDIA_CONTENT_ERROR_PERMISSION_DENIED:
1507       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1508     case MEDIA_CONTENT_ERROR_DB_FAILED:
1509       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1510     case MEDIA_CONTENT_ERROR_DB_BUSY:
1511       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1512     case MEDIA_CONTENT_ERROR_NETWORK:
1513       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1514     case MEDIA_CONTENT_ERROR_UNSUPPORTED_CONTENT:
1515       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, error_msg);
1516     default:
1517       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error.");
1518   }
1519 }
1520
1521 }  // namespace content
1522 }  // namespace extension