436 lines
13 KiB
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);
|
|
}
|