Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
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 }