/* * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "data/datamgr.h" #define STR_IMAGE_NAME "Photo" #define STR_VIDEO_NAME "Video" #define STR_PLACE_UNKNOWN "Unknown" typedef int (*media_compare)(struct group_info *gi, app_media_info *info); typedef void *(*media_compare_data_get)(app_media_info *info); typedef char *(*group_name_get)(app_media_info *info); static int _compare_cb_date(const void *, const void *); static int _compare_cb_name(const void *, const void *); static int _compare_cb_genre(const void *, const void *); static int _compare_cb_place(const void *, const void *); static int _compare_cb_type(const void *, const void *); static int _compare_title(struct group_info *, app_media_info *); static char *_get_title(app_media_info *); static void *_get_data_title(app_media_info *info); static int _compare_time(struct group_info *, app_media_info *); static char *_get_time(app_media_info *); static void *_get_data_time(app_media_info *info); static int _compare_genre(struct group_info *, app_media_info *); static char *_get_genre(app_media_info *); static void *_get_data_genre(app_media_info *); static int _compare_place(struct group_info *, app_media_info *); static char *_get_place(app_media_info *); static void *_get_data_place(app_media_info *); static int _compare_type(struct group_info *, app_media_info *); static char *_get_type(app_media_info *); static void *_get_data_type(app_media_info *); struct mediadata { Eina_List *media_list; int media_count[E_FILE_MAX]; const char *media_type; int source_type; }; struct _list_info { Eina_Compare_Cb sort_cmp_cb; media_compare media_cmp; media_compare_data_get data_get; group_name_get name_get; }; static struct _list_info g_group_info[E_GROUP_MEDIA_MAX] = { [E_GROUP_MEDIA_DATE] = { .sort_cmp_cb = _compare_cb_date, .media_cmp = _compare_time, .name_get = _get_time, .data_get = _get_data_time, }, [E_GROUP_MEDIA_NAME] = { .sort_cmp_cb = _compare_cb_name, .media_cmp = _compare_title, .name_get = _get_title, .data_get = _get_data_title, }, [E_GROUP_MEDIA_GENRE] = { .sort_cmp_cb = _compare_cb_genre, .media_cmp = _compare_genre, .name_get = _get_genre, .data_get = _get_data_genre, }, [E_GROUP_MEDIA_PLACE] = { .sort_cmp_cb = _compare_cb_place, .media_cmp = _compare_place, .name_get = _get_place, .data_get = _get_data_place, }, [E_GROUP_MEDIA_TYPE] = { .sort_cmp_cb = _compare_cb_type, .media_cmp = _compare_type, .name_get = _get_type, .data_get = _get_data_type, }, }; static bool _create_filter(struct mediadata *md, filter_h *filter) { filter_h tmp_filter; int ret; char buf[1024]; ret = media_filter_create(&tmp_filter); if (ret != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to create media filter"); return false; } snprintf(buf, sizeof(buf), "%s", md->media_type); if (md->source_type != E_SOURCE_ALL) { char s[64]; snprintf(s, sizeof(s), " AND MEDIA_STORAGE_TYPE=%d", md->source_type); strncat(buf, s, strlen(s)); } media_filter_set_condition(tmp_filter, buf, MEDIA_CONTENT_COLLATE_DEFAULT); *filter = tmp_filter; return true; } static char *_get_date_string(struct tm *tm) { char buf[32]; strftime(buf, sizeof(buf), "%Y.%m.%d", tm); return strdup(buf); } static int _compare_title(struct group_info *gi, app_media_info *info) { if (!gi->data || !info->title) return -1; return strncasecmp(gi->data, info->title, 1); } static void *_get_data_title(app_media_info *info) { if (!info->title) return NULL; return strdup(info->title); } static char *_get_title(app_media_info *info) { if (!info->title) return NULL; return strndup(info->title, 1); } static int _compare_time(struct group_info *gi, app_media_info *info) { struct tm *tm; if (!gi->data) return -1; tm = gi->data; if (tm->tm_year == info->content_time->tm_year && tm->tm_yday == info->content_time->tm_yday) return 0; return 1; } static void *_get_data_time(app_media_info *info) { struct tm *tm; tm = calloc(1, sizeof(*tm)); if (!tm) return NULL; memcpy(tm, info->content_time, sizeof(*tm)); return tm; } static char *_get_time(app_media_info *info) { return _get_date_string(info->content_time); } static const char *_get_genre_string(app_media_info *info) { const char *genre; if (info->media_type == MEDIA_CONTENT_TYPE_VIDEO) genre = info->video->genre; else if (info->media_type == MEDIA_CONTENT_TYPE_MUSIC) genre = info->audio->genre; else genre = NULL; return genre; } static int _compare_genre(struct group_info *gi, app_media_info *info) { const char *genre; genre = _get_genre_string(info); if (!gi->data || !genre) return -1; return strcmp(gi->data, genre); } static void *_get_data_genre(app_media_info *info) { const char *genre; genre = _get_genre_string(info); if (!genre) return NULL; return strdup(genre); } static char *_get_genre(app_media_info *info) { const char *genre; genre = _get_genre_string(info); if (!genre) return NULL; return strdup(genre); } static void _get_place_string(const char *src, char **city, char **country) { char str[64]; char *p, *tmp; if (!src) { *city = strdup(STR_PLACE_UNKNOWN); *country = strdup(STR_PLACE_UNKNOWN); return; } snprintf(str, sizeof(str), "%s", src); p = strtok_r(str, "/", &tmp); if (!p) p = STR_PLACE_UNKNOWN; *city = strdup(p); p = strtok_r(tmp, "", &tmp); if (!p) p = STR_PLACE_UNKNOWN; *country = strdup(p); } static int _compare_place(struct group_info *gi, app_media_info *info) { if (!gi->data) return -1; if (!info->location_tag) return strcmp(gi->data, STR_PLACE_UNKNOWN); return strcmp(gi->data, info->location_tag); } static void *_get_data_place(app_media_info *info) { if (!info->location_tag) return strdup(STR_PLACE_UNKNOWN); return strdup(info->location_tag); } static char *_get_place(app_media_info *info) { if (!info->location_tag) return strdup(STR_PLACE_UNKNOWN); return strdup(info->location_tag); } static int _compare_type(struct group_info *gi, app_media_info *info) { int *type; if (!gi->data) return -1; type = gi->data; if (*type == info->media_type) return 0; return 1; } static void *_get_data_type(app_media_info *info) { int *type; type = calloc(1, sizeof(*type)); if (!type) return NULL; *type = info->media_type; return type; } static char *_get_type(app_media_info *info) { const char *type; if (info->media_type == MEDIA_CONTENT_TYPE_IMAGE) type = STR_IMAGE_NAME; else if (info->media_type == MEDIA_CONTENT_TYPE_VIDEO) type = STR_VIDEO_NAME; else type = NULL; if (!type) return NULL; return strdup(type); } static int _compare_cb_date(const void *data1, const void *data2) { app_media *am1, *am2; app_media_info *info1, *info2; time_t tm1, tm2; am1 = (app_media *)data1; am2 = (app_media *)data2; info1 = app_media_get_info(am1); info2 = app_media_get_info(am2); if (!info1 || !info2) return -1; tm1 = mktime(info1->content_time); tm2 = mktime(info2->content_time); if (tm1 < tm2) return 1; return -1; } static int _compare_cb_name(const void *data1, const void *data2) { app_media *am1, *am2; app_media_info *info1, *info2; am1 = (app_media *)data1; am2 = (app_media *)data2; info1 = app_media_get_info(am1); info2 = app_media_get_info(am2); if (!info1 || !info2 || !info1->display_name || !info2->display_name) return -1; return strcasecmp(info1->display_name, info2->display_name); } static int _compare_cb_genre(const void *data1, const void *data2) { app_media *am1, *am2; app_media_info *info1, *info2; const char *genre1, *genre2; am1 = (app_media *)data1; am2 = (app_media *)data2; info1 = app_media_get_info(am1); info2 = app_media_get_info(am2); if (!info1 || !info2) return -1; genre1 = _get_genre_string(info1); genre2 = _get_genre_string(info2); if (!genre1 || !genre2) return -1; return strcmp(genre1, genre2); } static int _compare_cb_place(const void *data1, const void *data2) { app_media *am1, *am2; app_media_info *info1, *info2; char *city1, *city2; char *country1, *country2; int r; am1 = (app_media *)data1; am2 = (app_media *)data2; info1 = app_media_get_info(am1); info2 = app_media_get_info(am2); if (!info1 || !info2) return -1; _get_place_string(info1->location_tag, &city1, &country1); _get_place_string(info2->location_tag, &city2, &country2); if (!city1 || !city2 || !country1 || !country2) { r = -1; goto ret; } r = strcmp(country1, country2); if (!r) r = strcmp(city1, city2); else { /* NOTE: to set "Unknown" as the last item */ if (r < 0 && !strcmp(country1, STR_PLACE_UNKNOWN)) r = 1; else if (r > 0 && !strcmp(country2, STR_PLACE_UNKNOWN)) r = -1; } ret: free(city1); free(city2); free(country1); free(country2); return r; } static int _compare_cb_type(const void *data1, const void *data2) { app_media *am1, *am2; app_media_info *info1, *info2; am1 = (app_media *)data1; am2 = (app_media *)data2; info1 = app_media_get_info(am1); info2 = app_media_get_info(am2); if (!info1 || !info2) return -1; if (info1->media_type < info2->media_type) return 1; return -1; } static Eina_List *_sort_list(Eina_List *list, int sort) { Eina_List *sorted_list; sorted_list = eina_list_sort(list, 0, g_group_info[sort].sort_cmp_cb); return sorted_list; } static void _destroy_media_list(Eina_List *list) { app_media *am; EINA_LIST_FREE(list, am) app_media_destroy(am); } static bool _get_each_media_info(media_info_h media_h, void *data) { Eina_List **list; app_media *am; if (!data) return false; list = data; am = app_media_create(media_h); if (!am) { _ERR("failed to create app media"); return false; } *list = eina_list_append(*list, am); return true; } static bool _get_medialist(struct mediadata *md) { Eina_List *list; filter_h filter; int ret; ret = media_content_connect(); if (ret != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to connect to media content"); return false; } if (md->media_list) { _destroy_media_list(md->media_list); md->media_list = NULL; } if (!_create_filter(md, &filter)) { _ERR("failed to create filter"); return false; } list = NULL; ret = media_info_foreach_media_from_db(filter, _get_each_media_info, &list); if (ret != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to get media info"); media_filter_destroy(filter); return false; } md->media_list = list; media_filter_destroy(filter); media_content_disconnect(); return true; } static void *_create(const char *media_type, int source_type) { struct mediadata *md; if (!media_type) { _ERR("invalid argument"); return NULL; } md = calloc(1, sizeof(*md)); if (!md) { _ERR("failed to allocate md"); return NULL; } md->media_type = media_type; md->source_type = source_type; if (!_get_medialist(md)) { _ERR("failed to get medialist"); free(md); return NULL; } return (void *)md; } static void _destroy(void *handle) { struct mediadata *md; if (!handle) { _ERR("failed to get mediadata handle"); return; } md = handle; _destroy_media_list(md->media_list); free(md); } static Eina_List *_get_list(void *handle, int type, void *data) { struct mediadata *md; if (!handle) { _ERR("failed to get mediadata handle"); return NULL; } md = handle; return md->media_list; } static int _get_count(void *handle, int type) { struct mediadata *md; if (!handle) { _ERR("failed to get mediadata handle"); return -1; } if (type < 0 || type >= E_FILE_MAX) { _ERR("invalid argument"); return -1; } md = handle; return md->media_count[type]; } static void _free_group_list(Eina_List *list) { struct group_info *gi; EINA_LIST_FREE(list, gi) { free(gi->name); free(gi->data); eina_list_free(gi->list); free(gi); } } static void _free_group(Eina_List *list) { _free_group_list(list); } static Eina_List *_get_group(void *handle, int type, void *data) { Eina_List *list, *l; struct mediadata *md; struct group_info *gi; app_media *am; app_media_info *info; int i; if (!handle) { _ERR("failed to get mediadata handle"); return NULL; } if (type < 0 || type >= E_GROUP_MEDIA_MAX) { _ERR("invalid argument"); return NULL; } md = handle; if (!_get_medialist(md)) { _ERR("failed to get media list"); return NULL; } md->media_list = _sort_list(md->media_list, type); for (i = 0; i < E_FILE_MAX; i++) md->media_count[i] = 0; gi = NULL; list = NULL; EINA_LIST_FOREACH(md->media_list, l, am) { info = app_media_get_info(am); if (!info) { _ERR("failed to get media info"); _free_group_list(list); return NULL; } if (!gi || g_group_info[type].media_cmp(gi, info)) { gi = calloc(1, sizeof(*gi)); if (!gi) { _ERR("failed to create group info"); _free_group_list(list); return NULL; } gi->name = g_group_info[type].name_get(info); gi->data = g_group_info[type].data_get(info); list = eina_list_append(list, gi); } gi->list = eina_list_append(gi->list, am); md->media_count[info->media_type]++; } return list; } static void _set_source(void *handle, int source_type) { struct mediadata *md; if (!handle) { _ERR("failed to get mediadata handle"); return; } md = handle; md->source_type = source_type; _get_medialist(md); } static struct data_ops _ops = { .create = _create, .destroy = _destroy, .get_list = _get_list, .get_count = _get_count, .get_group = _get_group, .free_group = _free_group, .set_source = _set_source, }; struct data_ops *mediadata_get_ops(void) { return &_ops; };