raster pushed a commit to branch master.

http://git.enlightenment.org/apps/rage.git/commit/?id=e3bb0420c16fcbed46a1decf7f0a8bb1bee2a527

commit e3bb0420c16fcbed46a1decf7f0a8bb1bee2a527
Author: Carsten Haitzler (Rasterman) <[email protected]>
Date:   Tue Aug 5 18:57:26 2014 +0900

    rage - add album art fetching for audio only stuff.
    
    if the track is audio only, it'll look in a cache of albumart, if not,
    request the big google in the sky for an image with some search terms
    guessed from id3/metadata/filename and then use that. tak'es the first
    thing found. not very smart, but pretty damned good most of the time.
---
 data/themes/default.edc |  81 +++++++++++++-
 src/bin/Makefile.am     |   3 +-
 src/bin/albumart.c      | 282 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/bin/albumart.h      |   6 ++
 src/bin/video.c         |  24 ++++-
 src/bin/video.h         |   3 +
 src/bin/videothumb.c    |  20 ++--
 src/bin/win.c           |  46 ++++++++
 src/bin/win.h           |   3 +-
 9 files changed, 455 insertions(+), 13 deletions(-)

diff --git a/data/themes/default.edc b/data/themes/default.edc
index cce94ef..070af3a 100644
--- a/data/themes/default.edc
+++ b/data/themes/default.edc
@@ -316,11 +316,86 @@ collections {
             target: "novid_clip2";
          }
 
+         part { name: "art_clip"; type: RECT; mouse_events: 0;
+            description { state: "default" 0.0;
+               max: 0 0;
+               visible: 0;
+               color: 255 255 255 0;
+               rel1.to: "base";
+               rel2.to: "base";
+               fixed: 1 1;
+               aspect: 1.0 1.0; aspect_preference: BOTH;
+            }
+            description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               max: 9999 9999;
+               visible: 1;
+               color: 255 255 255 255;
+            }
+         }
+         part { name: "art_clip2"; type: RECT; mouse_events: 0;
+            description { state: "default" 0.0;
+               visible: 0;
+               color: 255 255 255 0;
+               rel1.to: "base";
+               rel2.to: "base";
+               fixed: 1 1;
+               aspect: 1.0 1.0; aspect_preference: BOTH;
+            }
+            description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+               color: 255 255 255 255;
+            }
+         }
+         part { name: "artshadow"; mouse_events: 0;
+            clip_to: "art_clip2";
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               rel1.to: "art_clip";
+               rel2.to: "art_clip";
+               image.normal: "win_shadow.png";
+               image.border: 14 14 14 14;
+               image.middle: 0;
+               rel1.offset: -7  -3;
+               rel2.offset: 6 11;
+               fill.smooth: 0;
+            }
+         }
+         part { name: "rage.art"; type: SWALLOW;
+            clip_to: "art_clip";
+            description { state: "default" 0.0;
+               rel1.to: "art_clip";
+               rel2.to: "art_clip";
+            }
+         }
+         program {
+            signal: "action,newvid"; source: "rage";
+            action: STATE_SET "default" 0.0;
+            transition: ACCELERATE 0.2;
+            target: "art_clip";
+            target: "art_clip2";
+         }
+         program {
+            signal: "state,noart"; source: "rage";
+            action: STATE_SET "default" 0.0;
+            transition: ACCELERATE 1.0;
+            target: "art_clip";
+            target: "art_clip2";
+         }
+         program {
+            signal: "state,art"; source: "rage";
+            action: STATE_SET "visible" 0.0;
+            transition: DECELERATE 1.0;
+            target: "art_clip";
+            target: "art_clip2";
+         }
+
          part { name: "rage.content"; type: SWALLOW;
             description { state: "default" 0.0;
             }
          }
-         
+
          part { name: "rage.list"; type: SWALLOW;
             description { state: "default" 0.0;
                align: 0.0 0.5;
@@ -1557,13 +1632,13 @@ collections {
          }
          program { name: "posshow";
             action: STATE_SET "visible" 0.0;
-            transition: SINUSOIDAL 0.3 CURRENT;
+            transition: SINUSOIDAL 0.3;
             target: "poscover";
             target: "posclip";
          }
          program { name: "poshide";
             action: STATE_SET "default" 0.0;
-            transition: SINUSOIDAL 1.0 CURRENT;
+            transition: SINUSOIDAL 1.0;
             target: "poscover";
             target: "posclip";
          }
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index bc92fe4..358121a 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -21,7 +21,8 @@ win.c win.h \
 winlist.c winlist.h \
 config.c config.h \
 sha1.c sha1.h \
-videothumb.c videothumb.h
+videothumb.c videothumb.h \
+albumart.c albumart.h
 
 internal_bindir = $(libdir)/rage/utils
 internal_bin_PROGRAMS = rage_thumb
diff --git a/src/bin/albumart.c b/src/bin/albumart.c
new file mode 100644
index 0000000..346bfa6
--- /dev/null
+++ b/src/bin/albumart.c
@@ -0,0 +1,282 @@
+#include <Elementary.h>
+#include "video.h"
+#include "win.h"
+#include "rage_config.h"
+#include "config.h"
+#include "albumart.h"
+#include "sha1.h"
+
+#define Q_START "http://www.google.com/search?as_st=y&tbm=isch&hl=en&as_q=";
+#define Q_END 
"&as_epq=&as_oq=&as_eq=&cr=&as_sitesearch=&safe=images&tbs=iar:s,ift:jpg"
+
+static Ecore_Con_Url *fetch = NULL;
+static Ecore_Event_Handler *handle_data = NULL;
+static Ecore_Event_Handler *handle_complete = NULL;
+static Eina_Strbuf *sb_result = NULL;
+static Eina_Bool fetch_image = EINA_FALSE;
+static char *fetchfile = NULL;
+static FILE *fout = NULL;
+static Evas_Object *fetchwin = NULL;
+
+static char *
+_thumbpath(const char *file)
+{
+   char buf_base[PATH_MAX];
+   char buf_file[PATH_MAX];
+   unsigned char sum[20];
+
+   if (!sha1((unsigned char *)file, strlen(file), sum)) return NULL;
+   snprintf(buf_base, sizeof(buf_base), "%s/rage/albumart/%02x",
+            efreet_cache_home_get(), sum[0]);
+   if (!ecore_file_mkpath(buf_base)) return NULL;
+   snprintf(buf_file, sizeof(buf_base),
+            "%s/%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+            "%02x%02x%02x%02x%02x%02x%02x%02x.jpg",
+            buf_base,
+            sum[1], sum[2], sum[3],
+            sum[4], sum[5], sum[6], sum[7],
+            sum[8], sum[9], sum[10], sum[11],
+            sum[12], sum[13], sum[14], sum[15],
+            sum[16], sum[17], sum[18], sum[19]);
+   return strdup(buf_file);
+}
+
+static Ecore_Con_Url *
+_fetch(Eina_Strbuf *sb)
+{
+   Ecore_Con_Url *f;
+   const char *qs;
+
+   qs = eina_strbuf_string_get(sb);
+   if (!qs) return NULL;
+   f = ecore_con_url_new(qs);
+   if (!f) return NULL;
+   ecore_con_url_additional_header_add
+   (f, "user-agent",
+    "Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0");
+   ecore_con_url_get(f);
+   return f;
+}
+
+static Eina_Bool
+_cb_http_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Url_Data *ev = event;
+
+   if (ev->url_con != fetch) return EINA_TRUE;
+   if (fetch_image) fwrite(ev->data, ev->size, 1, fout);
+   else if (sb_result)
+     eina_strbuf_append_length(sb_result, (char *)ev->data, (size_t)ev->size);
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_cb_http_complete(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Url_Complete *ev = event;
+   Eina_Bool ok = EINA_FALSE;
+
+   if (ev->url_con != fetch) return EINA_TRUE;
+   if (fetch_image)
+     {
+        char *path;
+
+        fetch_image = EINA_FALSE;
+        fclose(fout);
+        fout = NULL;
+        path = _thumbpath(fetchfile);
+        if (path)
+          {
+             win_art(fetchwin, path);
+             free(path);
+          }
+     }
+   else
+     {
+        if (sb_result)
+          {
+             const char *res = eina_strbuf_string_get(sb_result);
+             if (res)
+               {
+                  const char *p, *pe;
+                  Eina_Strbuf *sb;
+
+                  sb = eina_strbuf_new();
+                  p = strstr(res, "<img data-sz=\"f\" name=\"");
+                  if (p)
+                    {
+                       p = strstr(p, "src=\"http");
+                       p += 5;
+                       pe = strchr(p, '"');
+                       if (pe)
+                         {
+                            eina_strbuf_append_length(sb, p, pe - p);
+                            ok = EINA_TRUE;
+                         }
+                    }
+                  if (!ok)
+                    {
+                       p = strstr(res, "imgurl=");
+                       if (p)
+                         {
+                            p += 7;
+                            pe = strstr(p, "&amp;");
+                            if (pe)
+                              {
+                                 eina_strbuf_append_length(sb, p, pe - p);
+                                 ok = EINA_TRUE;
+                              }
+                         }
+                    }
+                  if (ok)
+                    {
+                       char *path;
+
+                       ecore_con_url_free(fetch);
+                       fetch = NULL;
+
+                       path = _thumbpath(fetchfile);
+                       if (path)
+                         {
+                            fout = fopen(path, "wb");
+                            if (fout)
+                              {
+                                 fetch_image = EINA_TRUE;
+                                 fetch = _fetch(sb);
+                              }
+                            free(path);
+                         }
+                    }
+                  eina_strbuf_free(sb);
+               }
+             eina_strbuf_free(sb_result);
+             sb_result = NULL;
+          }
+     }
+   if (!ok)
+     {
+        ecore_con_url_free(fetch);
+        fetch = NULL;
+        if (fetchfile)
+          {
+             free(fetchfile);
+             fetchfile = NULL;
+          }
+     }
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_search_append(Eina_Strbuf *sb, const char *str, Eina_Bool hadword)
+{
+   const char *s;
+   Eina_Bool word = EINA_FALSE;
+
+   for (s = str; *s; s++)
+     {
+        if (((*s >= 'a') && (*s <= 'z')) ||
+            ((*s >= 'A') && (*s <= 'Z')) ||
+            ((*s >= '0') && (*s <= '9')))
+          {
+             if (!word)
+               {
+                  if (hadword)
+                    {
+                       eina_strbuf_append_char(sb, '+');
+                       word = EINA_FALSE;
+                    }
+               }
+             eina_strbuf_append_char(sb, *s);
+             word = EINA_TRUE;
+             hadword = EINA_TRUE;
+          }
+        else word = EINA_FALSE;
+        if (*s == '.') break;
+     }
+   return hadword;
+}
+
+void
+albumart_find(Evas_Object *win, Evas_Object *vid)
+{
+   const char *file, *album, *artist, *title;
+   Eina_Strbuf *sb;
+   char *realfile, *path;
+
+   if (fetchfile)
+     {
+        free(fetchfile);
+        fetchfile = NULL;
+     }
+   if (fetch)
+     {
+        ecore_con_url_free(fetch);
+        fetch = NULL;
+     }
+   if (fout)
+     {
+        fclose(fout);
+        fout = NULL;
+     }
+   if (sb_result)
+     {
+        eina_strbuf_free(sb_result);
+        sb_result = NULL;
+     }
+   fetch_image = EINA_FALSE;
+   if (!vid) return;
+
+   if (!handle_data)
+     handle_data = ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA,
+                                           _cb_http_data, NULL);
+   if (!handle_complete)
+     handle_complete = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE,
+                                               _cb_http_complete, NULL);
+
+   file = video_file_get(vid);
+   if (!file) return;
+   realfile = ecore_file_realpath(file);
+   if (!realfile) fetchfile = strdup(file);
+   else fetchfile = realfile;
+
+   path = _thumbpath(fetchfile);
+   if (path)
+     {
+        if (ecore_file_exists(path))
+          {
+             win_art(win, path);
+             free(path);
+             free(fetchfile);
+             fetchfile = NULL;
+             return;
+          }
+        else free(path);
+     }
+   fetchwin = win;
+
+   sb = eina_strbuf_new();
+   eina_strbuf_append(sb, Q_START);
+
+   title = video_meta_title_get(vid);
+   artist = video_meta_artist_get(vid);
+   album = video_meta_album_get(vid);
+   if ((title) || (album) || (artist))
+     {
+        Eina_Bool had = EINA_FALSE;
+
+        if (artist) had = _search_append(sb, artist, had);
+        if (album) had = _search_append(sb, album, had);
+        if (title) had = _search_append(sb, title, had);
+     }
+   else
+     _search_append(sb, ecore_file_file_get(fetchfile), EINA_FALSE);
+
+   eina_strbuf_append(sb, Q_END);
+
+   if (sb_result) eina_strbuf_free(sb_result);
+   sb_result = eina_strbuf_new();
+
+   fetch = _fetch(sb);
+
+   eina_strbuf_free(sb);
+}
diff --git a/src/bin/albumart.h b/src/bin/albumart.h
new file mode 100644
index 0000000..0130c69
--- /dev/null
+++ b/src/bin/albumart.h
@@ -0,0 +1,6 @@
+#ifndef _ALBUMART_H__
+#define _ALBUMART_H__ 1
+
+void albumart_find(Evas_Object *win, Evas_Object *vid);
+
+#endif
diff --git a/src/bin/video.c b/src/bin/video.c
index 3ac4f0f..6282b92 100644
--- a/src/bin/video.c
+++ b/src/bin/video.c
@@ -1,5 +1,4 @@
 #include <Elementary.h>
-#include <Emotion.h>
 #include "video.h"
 #include "rage_config.h"
 #include "config.h"
@@ -825,6 +824,29 @@ video_lowquality_get(Evas_Object *obj)
    return sd->lowqual;
 }
 
+const char *
+video_meta_title_get(Evas_Object *obj)
+{
+   Video *sd = evas_object_smart_data_get(obj);
+   if (!sd) return NULL;
+   return emotion_object_meta_info_get(sd->o_vid, 
EMOTION_META_INFO_TRACK_TITLE);
+}
+
+const char *
+video_meta_artist_get(Evas_Object *obj)
+{
+   Video *sd = evas_object_smart_data_get(obj);
+   if (!sd) return NULL;
+   return emotion_object_meta_info_get(sd->o_vid, 
EMOTION_META_INFO_TRACK_ARTIST);
+}
+
+const char *
+video_meta_album_get(Evas_Object *obj)
+{
+   Video *sd = evas_object_smart_data_get(obj);
+   if (!sd) return NULL;
+   return emotion_object_meta_info_get(sd->o_vid, 
EMOTION_META_INFO_TRACK_ALBUM);
+}
 
 // emotion_object_seekable_get
 // emotion_object_play_speed_set
diff --git a/src/bin/video.h b/src/bin/video.h
index 8257520..bd5b294 100644
--- a/src/bin/video.h
+++ b/src/bin/video.h
@@ -46,5 +46,8 @@ int video_spu_button_get(Evas_Object *obj);
 void video_event_send(Evas_Object *obj, Emotion_Event ev);
 void video_lowquality_set(Evas_Object *obj, Eina_Bool lowq);
 Eina_Bool video_lowquality_get(Evas_Object *obj);
+const char *video_meta_title_get(Evas_Object *obj);
+const char *video_meta_artist_get(Evas_Object *obj);
+const char *video_meta_album_get(Evas_Object *obj);
 
 #endif
diff --git a/src/bin/videothumb.c b/src/bin/videothumb.c
index 8d41f5b..2d33a75 100644
--- a/src/bin/videothumb.c
+++ b/src/bin/videothumb.c
@@ -12,6 +12,7 @@ struct _Videothumb
    Ecore_Event_Handler *exe_handler;
    const char *file;
    const char *realfile;
+   char *realpath;
    double pos;
    unsigned int realpos;
    int iw, ih;
@@ -87,7 +88,7 @@ _thumb_match_update(Evas_Object *obj, const char *file)
    Videothumb *sd = evas_object_smart_data_get(obj);
 
    if (!sd) return;
-   if (!strcmp(sd->file, file)) _thumb_update(obj);
+   if (!strcmp(sd->realpath, file)) _thumb_update(obj);
 }
 
 static Eina_Bool
@@ -103,8 +104,11 @@ _cb_thumb_exe(void *data, int type EINA_UNUSED, void 
*event)
         Eina_List *l;
         Evas_Object *o;
 
-        _busy_del(sd->file);
-        EINA_LIST_FOREACH(vidthumbs, l, o) _thumb_match_update(o, sd->file);
+        _busy_del(sd->realpath);
+        EINA_LIST_FOREACH(vidthumbs, l, o)
+          {
+             _thumb_match_update(o, sd->realpath);
+          }
         if ((sd->iw <= 0) || (sd->ih <= 0))
           {
              if (sd->exe_handler)
@@ -144,7 +148,7 @@ _videothumb_image_load(Evas_Object *obj)
    if (!sd->file) return;
    sd->o_img = evas_object_image_filled_add(evas_object_evas_get(obj));
    evas_object_smart_member_add(sd->o_img, obj);
-   if (!sha1((unsigned char *)sd->file, strlen(sd->file), sum)) return;
+   if (!sha1((unsigned char *)sd->realpath, strlen(sd->realpath), sum)) return;
    snprintf(buf_base, sizeof(buf_base), "%s/rage/thumb/%02x",
             efreet_cache_home_get(), sum[0]);
    snprintf(buf_file, sizeof(buf_base),
@@ -170,7 +174,7 @@ _videothumb_image_load(Evas_Object *obj)
         Eina_Bool ok = EINA_FALSE;
         struct stat st1, st2;
 
-        if (stat(sd->file, &st1) == 0)
+        if (stat(sd->realpath, &st1) == 0)
           {
              if (stat(sd->realfile, &st2) == 0)
                {
@@ -183,14 +187,14 @@ _videothumb_image_load(Evas_Object *obj)
              return;
           }
      }
-   if (!_busy_add(sd->file)) return;
+   if (!_busy_add(sd->realpath)) return;
    ecore_exe_run_priority_set(10);
    if (sd->thumb_exe)
      {
         ecore_exe_free(sd->thumb_exe);
         sd->thumb_exe = NULL;
      }
-   s = ecore_file_escape_name(sd->file);
+   s = ecore_file_escape_name(sd->realpath);
    if (s)
      {
         libdir = elm_app_lib_dir_get();
@@ -283,6 +287,7 @@ _smart_del(Evas_Object *obj)
    vidthumbs = eina_list_remove(vidthumbs, obj);
    if (sd->file) eina_stringshare_del(sd->file);
    if (sd->realfile) eina_stringshare_del(sd->realfile);
+   if (sd->realpath) free(sd->realpath);
    if (sd->o_img) evas_object_del(sd->o_img);
    if (sd->thumb_exe) ecore_exe_free(sd->thumb_exe);
    if (sd->exe_handler) ecore_event_handler_del(sd->exe_handler);
@@ -366,6 +371,7 @@ videothumb_file_set(Evas_Object *obj, const char *file, 
double pos)
    if ((sd->file == file) && (sd->pos == pos)) return;
    if (sd->file) eina_stringshare_del(sd->file);
    sd->file = eina_stringshare_add(file);
+   sd->realpath = ecore_file_realpath(sd->file);
    sd->pos = pos;
    _videothumb_eval(obj, EINA_TRUE);
 }
diff --git a/src/bin/win.c b/src/bin/win.c
index d356099..69eab61 100644
--- a/src/bin/win.c
+++ b/src/bin/win.c
@@ -8,6 +8,7 @@
 #include "key.h"
 #include "controls.h"
 #include "gesture.h"
+#include "albumart.h"
 
 static void
 _cb_fullscreen(void *data EINA_UNUSED, Evas_Object *obj, void *event 
EINA_UNUSED)
@@ -364,6 +365,48 @@ win_title_update(Evas_Object *win)
 }
 
 void
+win_art(Evas_Object *win, const char *path)
+{
+   Inf *inf = evas_object_data_get(win, "inf");
+
+   if (!path)
+     {
+        elm_layout_signal_emit(inf->lay, "state,noart", "rage");
+        if (inf->artimg)
+          {
+             evas_object_del(inf->artimg);
+             inf->artimg = NULL;
+          }
+     }
+   else
+     {
+        int iw, ih;
+
+        if (inf->artimg)
+          {
+             evas_object_del(inf->artimg);
+             inf->artimg = NULL;
+          }
+        inf->artimg = evas_object_image_filled_add(evas_object_evas_get(win));
+        evas_object_image_file_set(inf->artimg, path, NULL);
+        evas_object_image_size_get(inf->artimg, &iw, &ih);
+        if ((iw > 0) && (ih > 0))
+          {
+             evas_object_size_hint_aspect_set(inf->artimg,
+                                              EVAS_ASPECT_CONTROL_NEITHER,
+                                              iw, ih);
+             elm_object_part_content_set(inf->lay, "rage.art", inf->artimg);
+             elm_layout_signal_emit(inf->lay, "state,art", "rage");
+          }
+        else
+          {
+             evas_object_del(inf->artimg);
+             inf->artimg = NULL;
+          }
+     }
+}
+
+void
 win_show(Evas_Object *win, int w, int h)
 {
    Inf *inf = evas_object_data_get(win, "inf");
@@ -378,6 +421,9 @@ win_show(Evas_Object *win, int w, int h)
           }
         evas_object_show(win);
      }
+   if (!video_has_video_get(inf->vid)) albumart_find(win, inf->vid);
+   else albumart_find(win, NULL);
+
    if (!video_has_video_get(inf->vid))
      elm_layout_signal_emit(inf->lay, "state,novideo", "rage");
    else
diff --git a/src/bin/win.h b/src/bin/win.h
index 6967f78..8c96245 100644
--- a/src/bin/win.h
+++ b/src/bin/win.h
@@ -5,7 +5,7 @@ typedef struct _Inf Inf;
 
 struct _Inf
 {
-   Evas_Object *vid, *lay, *event, *event2, *glayer, *vidthumb;
+   Evas_Object *vid, *lay, *event, *event2, *glayer, *vidthumb, *artimg;
    Eina_List *file_list, *file_cur;
    Ecore_Job *next_job;
    Ecore_Timer *show_timeout;
@@ -42,6 +42,7 @@ Eina_Bool win_video_have_prev(Evas_Object *win);
 Evas_Object *win_add(void);
 void win_title_update(Evas_Object *win);
 void win_show(Evas_Object *win, int w, int h);
+void win_art(Evas_Object *win, const char *path);
 void win_aspect_adjust(Evas_Object *win);
 void win_frame_decode(Evas_Object *win);
 

-- 


Reply via email to