Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
art.c
Go to the documentation of this file.
1 /*
2  * art.c
3  * Copyright 2011 John Lindgren
4  *
5  * This file is part of Audacious.
6  *
7  * Audacious is free software: you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free Software
9  * Foundation, version 2 or version 3 of the License.
10  *
11  * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Audacious. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * The Audacious team does not consider modular code linking to Audacious or
19  * using our public API to be a derived work.
20  */
21 
22 #include <errno.h>
23 #include <glib.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include <libaudcore/audstrings.h>
30 #include <libaudcore/hook.h>
31 
32 #include "main.h"
33 #include "misc.h"
34 #include "playlist.h"
35 #include "util.h"
36 
37 typedef struct {
38  char * song_file; /* pooled */
39  int refcount;
40 
41  /* album art as JPEG or PNG data */
42  void * data;
43  int64_t len;
44 
45  /* album art as (possibly a temporary) file */
46  char * art_file;
48 } ArtItem;
49 
50 static GHashTable * art_items;
51 static char * current_file; /* pooled */
52 
53 static void art_item_free (ArtItem * item)
54 {
55  /* delete temporary file */
56  if (item->art_file && item->is_temp)
57  {
58  char * unixname = uri_to_filename (item->art_file);
59  if (unixname)
60  {
61  unlink (unixname);
62  g_free (unixname);
63  }
64  }
65 
66  str_unref (item->song_file);
67  g_free (item->data);
68  g_free (item->art_file);
69  g_slice_free (ArtItem, item);
70 }
71 
72 static ArtItem * art_item_new (const char * file)
73 {
74  /* local files only */
75  if (strncmp (file, "file://", 7))
76  return NULL;
77 
78  ArtItem * item = g_slice_new0 (ArtItem);
79  item->song_file = str_get (file);
80 
81  /* try to load embedded album art */
83  if (decoder)
84  file_read_image (file, decoder, & item->data, & item->len);
85 
86  if (item->data)
87  return item;
88 
89  /* try to find external image file */
90  char * unixname = get_associated_image_file (file);
91  if (unixname)
92  {
93  item->art_file = filename_to_uri (unixname);
94  g_free (unixname);
95  }
96 
97  if (item->art_file)
98  return item;
99 
100  /* failed */
101  art_item_free (item);
102  return NULL;
103 }
104 
105 static ArtItem * art_item_get (const char * file)
106 {
107  if (! art_items)
108  art_items = g_hash_table_new_full (g_str_hash, g_str_equal,
109  NULL, (GDestroyNotify) art_item_free);
110 
111  ArtItem * item = g_hash_table_lookup (art_items, file);
112  if (item)
113  {
114  item->refcount ++;
115  return item;
116  }
117 
118  item = art_item_new (file);
119  if (! item)
120  return NULL;
121 
122  g_hash_table_insert (art_items, item->song_file, item);
123  item->refcount = 1;
124  return item;
125 }
126 
127 static void art_item_unref (ArtItem * item)
128 {
129  if (! -- item->refcount)
130  {
131  /* keep album art for current entry */
132  if (current_file && ! strcmp (current_file, item->song_file))
133  return;
134 
135  g_hash_table_remove (art_items, item->song_file);
136  }
137 }
138 
139 static void release_current (void)
140 {
141  if (! art_items || ! current_file)
142  return;
143 
144  /* free album art for previous entry */
145  ArtItem * item = g_hash_table_lookup (art_items, current_file);
146  if (item && ! item->refcount)
147  g_hash_table_remove (art_items, current_file);
148 }
149 
150 static void position_hook (void * data, void * user)
151 {
152  release_current ();
154 
155  int list = playlist_get_playing ();
156  int entry = (list >= 0) ? playlist_get_position (list) : -1;
157  current_file = (entry >= 0) ? playlist_entry_get_filename (list, entry) : NULL;
158 }
159 
160 void art_init (void)
161 {
162  hook_associate ("playlist position", position_hook, NULL);
163  hook_associate ("playlist set playing", position_hook, NULL);
164 }
165 
166 void art_cleanup (void)
167 {
168  hook_dissociate ("playlist position", position_hook);
169  hook_dissociate ("playlist set playing", position_hook);
170 
171  release_current ();
173  current_file = NULL;
174 
175  if (art_items && g_hash_table_size (art_items))
176  {
177  fprintf (stderr, "Album art not freed\n");
178  abort ();
179  }
180 
181  if (art_items)
182  {
183  g_hash_table_destroy (art_items);
184  art_items = NULL;
185  }
186 }
187 
188 void art_get_data (const char * file, const void * * data, int64_t * len)
189 {
190  * data = NULL;
191  * len = 0;
192 
193  ArtItem * item = art_item_get (file);
194  if (! item)
195  return;
196 
197  /* load data from external image file */
198  if (! item->data && item->art_file)
199  vfs_file_get_contents (item->art_file, & item->data, & item->len);
200 
201  if (! item->data)
202  {
203  art_item_unref (item);
204  return;
205  }
206 
207  * data = item->data;
208  * len = item->len;
209 }
210 
211 const char * art_get_file (const char * file)
212 {
213  ArtItem * item = art_item_get (file);
214  if (! item)
215  return NULL;
216 
217  /* save data to temporary file */
218  if (item->data && ! item->art_file)
219  {
220  char * unixname = write_temp_file (item->data, item->len);
221  if (unixname)
222  {
223  item->art_file = filename_to_uri (unixname);
224  item->is_temp = TRUE;
225  g_free (unixname);
226  }
227  }
228 
229  if (! item->art_file)
230  {
231  art_item_unref (item);
232  return NULL;
233  }
234 
235  return item->art_file;
236 }
237 
238 void art_unref (const char * file)
239 {
240  ArtItem * item = art_items ? g_hash_table_lookup (art_items, file) : NULL;
241  if (item)
242  art_item_unref (item);
243 }