00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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;
00039 int refcount;
00040
00041
00042 void * data;
00043 int64_t len;
00044
00045
00046 char * art_file;
00047 bool_t is_temp;
00048 } ArtItem;
00049
00050 static GHashTable * art_items;
00051 static char * current_file;
00052
00053 static void art_item_free (ArtItem * item)
00054 {
00055
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
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
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
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
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
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
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
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
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 }