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