empc/src/bin/empc_metadata.c

436 lines
13 KiB
C

#include "empc_private.h"
typedef struct Metadata_Image
{
EINA_INLIST;
Ecore_Con_Url *url;
Eina_Binbuf *buf;
Empc_Fetch_Request_Internal *ireq;
} Metadata_Image;
static Eina_List *handlers = NULL;
static Eina_List *image_reqs = NULL;
static Eina_List *lyric_entries = NULL;
static void
metadata_lyric_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
lyric_entries = eina_list_remove(lyric_entries, obj);
}
static void
metadata_image_done(Metadata_Image *m, Eina_Bool deleted)
{
Eina_File *f;
Eina_List *l, *ll, *lll;
Evas_Object *o;
m->ireq->urls = eina_inlist_remove(m->ireq->urls, EINA_INLIST_GET(m));
if (!deleted)
{
size_t len;
len = eina_binbuf_length_get(m->buf);
//INF("REMOTE COVER DONE(%s:%s)", m->ireq->req.artist, m->ireq->req.album);
f = eina_file_virtualize(ecore_con_url_url_get(m->url),
eina_binbuf_string_steal(m->buf), len,
EINA_FALSE);
l = empc_metadata_images_add((void*)m->ireq);
EINA_LIST_FOREACH_SAFE(l, ll, lll, o)
{
if (!elm_image_mmap_set(o, f, NULL))
{
evas_object_del(o);
l = eina_list_remove_list(l, ll);
}
}
if (l)
empc_metadata_fetch_done((void*)m->ireq, l);
eina_file_close(f);
E_FREE_LIST(m->ireq->urls_pending, eina_stringshare_del);
}
eina_binbuf_free(m->buf);
if ((!m->ireq->urls) && (!m->ireq->req.running))
empc_metadata_fetch_done((void*)m->ireq, NULL);
free(m);
}
static Metadata_Image *
metadata_image_new(Empc_Fetch_Request_Internal *ireq, const char *url)
{
Metadata_Image *m;
m = calloc(1, sizeof(Metadata_Image));
m->ireq = ireq;
//INF("REMOTE COVER START(%s:%s)", m->ireq->req.artist, m->ireq->req.album);
ireq->urls = eina_inlist_append(ireq->urls, EINA_INLIST_GET(m));
m->url = ecore_con_url_new(url);
m->buf = eina_binbuf_new();
image_reqs = eina_list_append(image_reqs, m->url);
ecore_con_url_data_set(m->url, m);
ecore_con_url_get(m->url);
return m;
}
static Eina_Bool
metadata_data_cb(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Con_Event_Url_Data *ev)
{
Metadata_Image *m;
if ((!image_reqs) || (!eina_list_data_find(image_reqs, ev->url_con))) return ECORE_CALLBACK_RENEW;
m = ecore_con_url_data_get(ev->url_con);
if (!eina_binbuf_length_get(m->buf))
{
if (ecore_con_url_status_code_get(ev->url_con) != 200)
{
if (m->ireq->urls_pending)
{
metadata_image_new(m->ireq, eina_list_data_get(m->ireq->urls_pending));
m->ireq->urls_pending = eina_list_remove_list(m->ireq->urls_pending, m->ireq->urls_pending);
}
metadata_image_done(m, 1);
image_reqs = eina_list_remove(image_reqs, ev->url_con);
ecore_con_url_free(ev->url_con);
return ECORE_CALLBACK_DONE;
}
}
eina_binbuf_append_length(m->buf, ev->data, ev->size);
return ECORE_CALLBACK_DONE;
}
static Eina_Bool
metadata_done_cb(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Con_Event_Url_Complete *ev)
{
Metadata_Image *m;
if ((!image_reqs) || (!eina_list_data_find(image_reqs, ev->url_con))) return ECORE_CALLBACK_RENEW;
m = ecore_con_url_data_get(ev->url_con);
image_reqs = eina_list_remove(image_reqs, ev->url_con);
metadata_image_done(m, !ev->status);
ecore_con_url_free(ev->url_con);
return ECORE_CALLBACK_DONE;
}
static Empc_Fetch_Request_Internal *
metadata_fetch_req_new(const char *artist, const char *album, const char *song)
{
Empc_Fetch_Request_Internal *ireq;
ireq = calloc(1, sizeof(Empc_Fetch_Request_Internal));
ireq->req.artist = eina_stringshare_add(artist);
ireq->req.album = eina_stringshare_add(album);
ireq->req.song = eina_stringshare_add(song);
return ireq;
}
static Empc_Fetch_Request *
metadata_fetch_continue(Empc_Fetch_Request_Internal *ireq)
{
Empc_Module *mod;
Eina_Inlist *mods;
if (ireq->module)
{
mods = EINA_INLIST_GET(ireq->module)->next;
ireq->module = NULL;
}
else
mods = empc_modules[EMPC_MODULE_TYPE_METADATA_FETCH];
EINA_INLIST_FOREACH(mods, mod)
{
Empc_Module_Metadata_Fetch *em = (Empc_Module_Metadata_Fetch*)mod;
if (mod->remote && (((!master) && (!ireq->req.force)) || (ireq->req.local))) continue;
if (!em->fetch((Empc_Fetch_Request*)ireq)) continue;
//INF("METADATA FETCH(%s)", strrchr(eina_module_file_get(mod->module), '/') + 1);
ireq->module = mod;
ireq->in_progress = 1;
break;
}
return (ireq->module) ? (void*)ireq : NULL;
}
static void
metadata_fail_cb(Empc_Fetch_Request_Internal *ireq)
{
ireq->fail_job = NULL;
empc_metadata_fetch_done((void*)ireq, NULL);
}
Empc_Fetch_Request *
metadata_fetch_begin(Empc_Metadata_Type type, Evas_Object *obj, const char *attr1, const char *attr2, const char *uri, Eina_Bool force, Eina_Bool local, Empc_Module_Metadata_Fetch_Result_Cb cb, const void *data)
{
Empc_Fetch_Request_Internal *ireq;
Empc_Fetch_Request *req;
Empc_Metadata_Result_Cb *res;
char buf[2048];
if (attr1 && (!attr1[0]) && attr2 && (!attr2[0])) return NULL; //fuck you
force = !!force;
snprintf(buf, sizeof(buf), "%s::%s", attr1 ?: "", attr2 ?: "");
ireq = eina_hash_find(empc_metadata_fetch_reqs[type], buf);
if (ireq)
{
Eina_List *l;
if (ireq->req.type != type) return NULL; //wtf
EINA_LIST_FOREACH(ireq->results, l, res)
{
if ((res->cb == cb) && (res->data == data) && (res->obj == obj)) return NULL;
}
res = malloc(sizeof(Empc_Metadata_Result_Cb));
res->cb = cb;
res->data = (void*)data;
res->force = force;
res->obj = obj;
ireq->results = eina_list_append(ireq->results, res);
ireq->req.force |= force;
ireq->deleted = 0;
return (Empc_Fetch_Request*)ireq;
}
switch (type)
{
case EMPC_METADATA_TYPE_IMAGE:
ireq = metadata_fetch_req_new(attr1, attr2, NULL);
break;
case EMPC_METADATA_TYPE_TEXT:
ireq = metadata_fetch_req_new(attr1, NULL, attr2);
break;
default:
return NULL;
}
ireq->req.local = !!local;
ireq->req.type = type;
ireq->req.uri = eina_stringshare_add(uri);
res = malloc(sizeof(Empc_Metadata_Result_Cb));
res->cb = cb;
res->data = (void*)data;
res->force = force;
res->obj = obj;
ireq->results = eina_list_append(ireq->results, res);
ireq->req.force = !!force;
eina_hash_add(empc_metadata_fetch_reqs[type], buf, ireq);
req = metadata_fetch_continue(ireq);
if (!req)
{
eina_hash_del_by_key(empc_metadata_fetch_reqs[type], buf);
if (!ireq->fail_job)
ireq->fail_job = ecore_job_add((Ecore_Cb)metadata_fail_cb, ireq);
}
return req;
}
void
metadata_fetch_cancel(Empc_Fetch_Request *req, Evas_Object *obj, Empc_Module_Metadata_Fetch_Result_Cb cb, const void *data)
{
Empc_Module_Metadata_Fetch *em;
Empc_Fetch_Request_Internal *ireq = (Empc_Fetch_Request_Internal*)req;
Empc_Metadata_Result_Cb *res;
Eina_List *l, *ll;
if (!req) return;
if (!ireq->module) return;
em = (Empc_Module_Metadata_Fetch*)ireq->module;
EINA_LIST_FOREACH_SAFE(ireq->results, l, ll, res)
{
if ((res->cb == cb) && (res->data == data) && ((!obj) || (res->obj == obj)))
{
ireq->results = eina_list_remove_list(ireq->results, l);
free(res);
}
}
if (ireq->results) return;
if (em->cancel)
{
em->cancel(req);
req->running = 0;
E_FREE_LIST(ireq->urls_pending, eina_stringshare_del);
while (ireq->urls)
{
Metadata_Image *m;
m = EINA_INLIST_CONTAINER_GET(ireq->urls, Metadata_Image);
ireq->urls = eina_inlist_remove(ireq->urls, ireq->urls);
image_reqs = eina_list_remove(image_reqs, m->url);
ecore_con_url_free(m->url);
eina_binbuf_free(m->buf);
free(m);
}
eina_hash_del_by_data(empc_metadata_fetch_reqs[ireq->module->type], req);
}
else
ireq->deleted = 1;
}
void
metadata_shutdown(void)
{
Eina_List *l;
Ecore_Con_Url *url;
E_FREE_LIST(handlers, ecore_event_handler_del);
EINA_LIST_FOREACH(image_reqs, l, url)
{
Metadata_Image *m = ecore_con_url_data_get(url);
eina_binbuf_free(m->buf);
free(m);
}
}
void
metadata_fetch_cb_add(Empc_Fetch_Request *req, Ecore_End_Cb cb, const void *data)
{
Empc_Fetch_Request_Internal *ireq = (Empc_Fetch_Request_Internal*)req;
Empc_Fetch_Request_End_Cb *ecb;
EINA_SAFETY_ON_NULL_RETURN(req);
ecb = malloc(sizeof(Empc_Fetch_Request_End_Cb));
ecb->cb = cb;
ecb->data = (void*)data;
ireq->end_cbs = eina_inlist_append(ireq->end_cbs, EINA_INLIST_GET(ecb));
}
void
empc_metadata_fetch_done(Empc_Fetch_Request *req, Eina_List *l)
{
Empc_Fetch_Request_Internal *ireq = (Empc_Fetch_Request_Internal*)req;
Empc_Metadata_Result_Cb *res;
Eina_List *ll, *lll;
ireq->in_progress = (!!l) || (!!ireq->urls);
//switch (ireq->req.type)
//{
//case EMPC_METADATA_TYPE_IMAGE:
//INF("COVER RETURN(%s) %d", strrchr(eina_module_file_get(ireq->module->module), '/') + 1, eina_list_count(l));
//break;
//case EMPC_METADATA_TYPE_TEXT:
//INF("LYRIC RETURN(%s) %d", strrchr(eina_module_file_get(ireq->module->module), '/') + 1, eina_list_count(l));
//break;
//default: break;
//}
if (l && ireq->deleted)
{
E_FREE_LIST(l, evas_object_del);
return;
}
if (!l)
{
Eina_Bool del = EINA_TRUE;
if (ireq->urls) return;
if ((!ireq->deleted) && (req->force || (!ireq->count)))
del = !metadata_fetch_continue(ireq);
if (del)
{
if ((!ireq->count) && (!ireq->deleted))
{
EINA_LIST_FREE(ireq->results, res)
{
res->cb(res->data, req, NULL);
free(res);
}
}
eina_hash_del_by_data(empc_metadata_fetch_reqs[ireq->req.type], req);
}
return;
}
ireq->count++;
EINA_LIST_FOREACH_SAFE(ireq->results, ll, lll, res)
{
Evas_Object *o;
o = eina_list_data_get(l);
if (elm_object_parent_widget_get(o) != res->obj) continue;
evas_object_ref(o);
res->cb(res->data, req, o);
if (master && (ireq->req.type = EMPC_METADATA_TYPE_IMAGE) && evas_object_data_get(o, "__empc_resave"))
{
Empc_Module *mod;
EINA_INLIST_FOREACH(empc_modules[EMPC_MODULE_TYPE_METADATA_SAVER], mod)
{
Empc_Module_Metadata_Save *es = (Empc_Module_Metadata_Save *)mod;
INF("IMAGE SAVE(%s)", strrchr(eina_module_file_get(mod->module), '/') + 1);
if (es->save_image) es->save_image(o, NULL, ireq->req.artist, ireq->req.album, NULL);
}
}
evas_object_unref(o);
l = eina_list_remove_list(l, l);
if (res->force) continue;
ireq->results = eina_list_remove_list(ireq->results, ll);
free(res);
}
E_FREE_LIST(l, evas_object_del);
}
Eina_List *
empc_metadata_entries_add(Empc_Fetch_Request *req)
{
Empc_Fetch_Request_Internal *ireq = (Empc_Fetch_Request_Internal*)req;
Empc_Metadata_Result_Cb *res;
Eina_List *l, *ret = NULL;
if (ireq->deleted) return NULL;
EINA_LIST_FOREACH(ireq->results, l, res)
{
Evas_Object *o;
o = elm_entry_add(res->obj);
elm_object_style_set(o, "lyrics");
elm_scroller_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
elm_entry_editable_set(o, 0);
elm_entry_single_line_set(o, 0);
elm_entry_scrollable_set(o, 1);
elm_object_focus_allow_set(o, 0);
elm_entry_line_wrap_set(o, ELM_WRAP_MIXED);
ret = eina_list_append(ret, o);
evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, metadata_lyric_del, NULL);
lyric_entries = eina_list_append(lyric_entries, o);
}
return ret;
}
Eina_List *
empc_metadata_images_add(Empc_Fetch_Request *req)
{
Empc_Fetch_Request_Internal *ireq = (Empc_Fetch_Request_Internal*)req;
Empc_Metadata_Result_Cb *res;
Eina_List *l, *ret = NULL;
if (ireq->deleted) return NULL;
EINA_LIST_FOREACH(ireq->results, l, res)
{
Evas_Object *o;
o = elm_image_add(res->obj);
elm_image_preload_disabled_set(o, EINA_TRUE);
elm_image_smooth_set(o, EINA_FALSE);
elm_image_fill_outside_set(o, EINA_FALSE);
ret = eina_list_append(ret, o);
}
return ret;
}
void
empc_metadata_image_download(Empc_Fetch_Request *req, const char *url)
{
if (!handlers)
{
E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_DATA, metadata_data_cb, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_COMPLETE, metadata_done_cb, NULL);
}
metadata_image_new((void*)req, url);
}
void
empc_metadata_image_download_queue(Empc_Fetch_Request *req, const char *url)
{
Empc_Fetch_Request_Internal *ireq = (Empc_Fetch_Request_Internal*)req;
if (ireq->urls)
ireq->urls_pending = eina_list_append(ireq->urls_pending, eina_stringshare_add(url));
else
empc_metadata_image_download(req, url);
}