Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
art.c
Go to the documentation of this file.
00001 /*
00002  * art.c
00003  * Copyright 2011 John Lindgren
00004  *
00005  * This file is part of Audacious.
00006  *
00007  * Audacious is free software: you can redistribute it and/or modify it under
00008  * the terms of the GNU General Public License as published by the Free Software
00009  * Foundation, version 2 or version 3 of the License.
00010  *
00011  * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
00012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00013  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License along with
00016  * Audacious. If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * The Audacious team does not consider modular code linking to Audacious or
00019  * using our public API to be a derived work.
00020  */
00021 
00022 #include <errno.h>
00023 #include <glib.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <unistd.h>
00028 
00029 #include <libaudcore/audstrings.h>
00030 #include <libaudcore/hook.h>
00031 
00032 #include "main.h"
00033 #include "misc.h"
00034 #include "playlist.h"
00035 #include "util.h"
00036 
00037 typedef struct {
00038     char * song_file; /* pooled */
00039     int refcount;
00040 
00041     /* album art as JPEG or PNG data */
00042     void * data;
00043     int64_t len;
00044 
00045     /* album art as (possibly a temporary) file */
00046     char * art_file;
00047     bool_t is_temp;
00048 } ArtItem;
00049 
00050 static GHashTable * art_items;
00051 static char * current_file; /* pooled */
00052 
00053 static void art_item_free (ArtItem * item)
00054 {
00055     /* delete temporary file */
00056     if (item->art_file && item->is_temp)
00057     {
00058         char * unixname = uri_to_filename (item->art_file);
00059         if (unixname)
00060         {
00061             unlink (unixname);
00062             g_free (unixname);
00063         }
00064     }
00065 
00066     str_unref (item->song_file);
00067     g_free (item->data);
00068     g_free (item->art_file);
00069     g_slice_free (ArtItem, item);
00070 }
00071 
00072 static ArtItem * art_item_new (const char * file)
00073 {
00074     /* local files only */
00075     if (strncmp (file, "file://", 7))
00076         return NULL;
00077 
00078     ArtItem * item = g_slice_new0 (ArtItem);
00079     item->song_file = str_get (file);
00080 
00081     /* try to load embedded album art */
00082     PluginHandle * decoder = file_find_decoder (file, FALSE);
00083     if (decoder)
00084         file_read_image (file, decoder, & item->data, & item->len);
00085 
00086     if (item->data)
00087         return item;
00088 
00089     /* try to find external image file */
00090     char * unixname = get_associated_image_file (file);
00091     if (unixname)
00092     {
00093         item->art_file = filename_to_uri (unixname);
00094         g_free (unixname);
00095     }
00096 
00097     if (item->art_file)
00098         return item;
00099 
00100     /* failed */
00101     art_item_free (item);
00102     return NULL;
00103 }
00104 
00105 static ArtItem * art_item_get (const char * file)
00106 {
00107     if (! art_items)
00108         art_items = g_hash_table_new_full (g_str_hash, g_str_equal,
00109          NULL, (GDestroyNotify) art_item_free);
00110 
00111     ArtItem * item = g_hash_table_lookup (art_items, file);
00112     if (item)
00113     {
00114         item->refcount ++;
00115         return item;
00116     }
00117 
00118     item = art_item_new (file);
00119     if (! item)
00120         return NULL;
00121 
00122     g_hash_table_insert (art_items, item->song_file, item);
00123     item->refcount = 1;
00124     return item;
00125 }
00126 
00127 static void art_item_unref (ArtItem * item)
00128 {
00129     if (! -- item->refcount)
00130     {
00131         /* keep album art for current entry */
00132         if (current_file && ! strcmp (current_file, item->song_file))
00133             return;
00134 
00135         g_hash_table_remove (art_items, item->song_file);
00136     }
00137 }
00138 
00139 static void release_current (void)
00140 {
00141     if (! art_items || ! current_file)
00142         return;
00143 
00144     /* free album art for previous entry */
00145     ArtItem * item = g_hash_table_lookup (art_items, current_file);
00146     if (item && ! item->refcount)
00147         g_hash_table_remove (art_items, current_file);
00148 }
00149 
00150 static void position_hook (void * data, void * user)
00151 {
00152     release_current ();
00153     str_unref (current_file);
00154 
00155     int list = playlist_get_playing ();
00156     int entry = (list >= 0) ? playlist_get_position (list) : -1;
00157     current_file = (entry >= 0) ? playlist_entry_get_filename (list, entry) : NULL;
00158 }
00159 
00160 void art_init (void)
00161 {
00162     hook_associate ("playlist position", position_hook, NULL);
00163     hook_associate ("playlist set playing", position_hook, NULL);
00164 }
00165 
00166 void art_cleanup (void)
00167 {
00168     hook_dissociate ("playlist position", position_hook);
00169     hook_dissociate ("playlist set playing", position_hook);
00170 
00171     release_current ();
00172     str_unref (current_file);
00173     current_file = NULL;
00174 
00175     if (art_items && g_hash_table_size (art_items))
00176     {
00177         fprintf (stderr, "Album art not freed\n");
00178         abort ();
00179     }
00180 
00181     if (art_items)
00182     {
00183         g_hash_table_destroy (art_items);
00184         art_items = NULL;
00185     }
00186 }
00187 
00188 void art_get_data (const char * file, const void * * data, int64_t * len)
00189 {
00190     * data = NULL;
00191     * len = 0;
00192 
00193     ArtItem * item = art_item_get (file);
00194     if (! item)
00195         return;
00196 
00197     /* load data from external image file */
00198     if (! item->data && item->art_file)
00199         vfs_file_get_contents (item->art_file, & item->data, & item->len);
00200 
00201     if (! item->data)
00202     {
00203         art_item_unref (item);
00204         return;
00205     }
00206 
00207     * data = item->data;
00208     * len = item->len;
00209 }
00210 
00211 const char * art_get_file (const char * file)
00212 {
00213     ArtItem * item = art_item_get (file);
00214     if (! item)
00215         return NULL;
00216 
00217     /* save data to temporary file */
00218     if (item->data && ! item->art_file)
00219     {
00220         char * unixname = write_temp_file (item->data, item->len);
00221         if (unixname)
00222         {
00223             item->art_file = filename_to_uri (unixname);
00224             item->is_temp = TRUE;
00225             g_free (unixname);
00226         }
00227     }
00228 
00229     if (! item->art_file)
00230     {
00231         art_item_unref (item);
00232         return NULL;
00233     }
00234 
00235     return item->art_file;
00236 }
00237 
00238 void art_unref (const char * file)
00239 {
00240     ArtItem * item = art_items ? g_hash_table_lookup (art_items, file) : NULL;
00241     if (item)
00242         art_item_unref (item);
00243 }