1 /*
2 This file is part of Deadbeef Player source code
3 http://deadbeef.sourceforge.net
4
5 playlist metadata management
6
7 Copyright (C) 2009-2013 Alexey Yakovenko
8
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any damages
11 arising from the use of this software.
12
13 Permission is granted to anyone to use this software for any purpose,
14 including commercial applications, and to alter it and redistribute it
15 freely, subject to the following restrictions:
16
17 1. The origin of this software must not be misrepresented; you must not
18 claim that you wrote the original software. If you use this software
19 in a product, an acknowledgment in the product documentation would be
20 appreciated but is not required.
21 2. Altered source versions must be plainly marked as such, and must not be
22 misrepresented as being the original software.
23 3. This notice may not be removed or altered from any source distribution.
24
25 Alexey Yakovenko waker@users.sourceforge.net
26 */
27
28 #include <string.h>
29 #include <stdlib.h>
30 #include "playlist.h"
31 #include "deadbeef.h"
32 #include "metacache.h"
33 #include "pltmeta.h"
34
35 #define LOCK {pl_lock();}
36 #define UNLOCK {pl_unlock();}
37
38 void
plt_add_meta(playlist_t * it,const char * key,const char * value)39 plt_add_meta (playlist_t *it, const char *key, const char *value) {
40 LOCK;
41 // check if it's already set
42 DB_metaInfo_t *tail = NULL;
43 DB_metaInfo_t *m = it->meta;
44 while (m) {
45 if (!strcasecmp (key, m->key)) {
46 // duplicate key
47 UNLOCK;
48 return;
49 }
50 tail = m;
51 m = m->next;
52 }
53 // add
54 char str[256];
55 if (!value || !*value) {
56 UNLOCK;
57 return;
58 }
59 m = malloc (sizeof (DB_metaInfo_t));
60 memset (m, 0, sizeof (DB_metaInfo_t));
61 m->key = metacache_add_string (key); //key;
62 m->value = metacache_add_string (value); //strdup (value);
63
64 if (tail) {
65 tail->next = m;
66 }
67 else {
68 it->meta = m;
69 }
70 UNLOCK;
71 }
72
73 void
plt_append_meta(playlist_t * it,const char * key,const char * value)74 plt_append_meta (playlist_t *it, const char *key, const char *value) {
75 pl_lock ();
76 const char *old = plt_find_meta (it, key);
77 size_t newlen = strlen (value);
78 if (!old) {
79 plt_add_meta (it, key, value);
80 }
81 else {
82 // check for duplicate data
83 const char *str = old;
84 int len;
85 while (str) {
86 char *next = strchr (str, '\n');
87
88 if (next) {
89 len = next - str;
90 next++;
91 }
92 else {
93 len = strlen (str);
94 }
95
96 if (len == newlen && !memcmp (str, value, len)) {
97 pl_unlock ();
98 return;
99 }
100
101 str = next;
102 }
103 int sz = strlen (old) + newlen + 2;
104 char out[sz];
105 snprintf (out, sz, "%s\n%s", old, value);
106 plt_replace_meta (it, key, out);
107 }
108 pl_unlock ();
109 }
110
111 void
plt_replace_meta(playlist_t * it,const char * key,const char * value)112 plt_replace_meta (playlist_t *it, const char *key, const char *value) {
113 LOCK;
114 // check if it's already set
115 DB_metaInfo_t *m = it->meta;
116 while (m) {
117 if (!strcasecmp (key, m->key)) {
118 break;
119 }
120 m = m->next;
121 }
122 if (m) {
123 metacache_remove_string (m->value);
124 m->value = metacache_add_string (value);
125 UNLOCK;
126 return;
127 }
128 else {
129 plt_add_meta (it, key, value);
130 }
131 UNLOCK;
132 }
133
134 void
plt_set_meta_int(playlist_t * it,const char * key,int value)135 plt_set_meta_int (playlist_t *it, const char *key, int value) {
136 char s[20];
137 snprintf (s, sizeof (s), "%d", value);
138 plt_replace_meta (it, key, s);
139 }
140
141 void
plt_set_meta_float(playlist_t * it,const char * key,float value)142 plt_set_meta_float (playlist_t *it, const char *key, float value) {
143 char s[20];
144 snprintf (s, sizeof (s), "%f", value);
145 plt_replace_meta (it, key, s);
146 }
147
148 void
plt_delete_meta(playlist_t * it,const char * key)149 plt_delete_meta (playlist_t *it, const char *key) {
150 DB_metaInfo_t *prev = NULL;
151 DB_metaInfo_t *m = it->meta;
152 while (m) {
153 if (!strcasecmp (key, m->key)) {
154 if (prev) {
155 prev->next = m->next;
156 }
157 else {
158 it->meta = m->next;
159 }
160 metacache_remove_string (m->key);
161 metacache_remove_string (m->value);
162 free (m);
163 break;
164 }
165 prev = m;
166 m = m->next;
167 }
168 }
169
170 const char *
plt_find_meta(playlist_t * it,const char * key)171 plt_find_meta (playlist_t *it, const char *key) {
172 DB_metaInfo_t *m = it->meta;
173 while (m) {
174 if (!strcasecmp (key, m->key)) {
175 return m->value;
176 }
177 m = m->next;
178 }
179 return NULL;
180 }
181
182 int
plt_find_meta_int(playlist_t * it,const char * key,int def)183 plt_find_meta_int (playlist_t *it, const char *key, int def) {
184 pl_lock ();
185 const char *val = plt_find_meta (it, key);
186 int res = val ? atoi (val) : def;
187 pl_unlock ();
188 return res;
189 }
190
191 float
plt_find_meta_float(playlist_t * it,const char * key,float def)192 plt_find_meta_float (playlist_t *it, const char *key, float def) {
193 pl_lock ();
194 const char *val = plt_find_meta (it, key);
195 float res = val ? atof (val) : def;
196 pl_unlock ();
197 return res;
198 }
199
200 DB_metaInfo_t *
plt_get_metadata_head(playlist_t * it)201 plt_get_metadata_head (playlist_t *it) {
202 return it->meta;
203 }
204
205 void
plt_delete_metadata(playlist_t * it,DB_metaInfo_t * meta)206 plt_delete_metadata (playlist_t *it, DB_metaInfo_t *meta) {
207 DB_metaInfo_t *prev = NULL;
208 DB_metaInfo_t *m = it->meta;
209 while (m) {
210 if (m == meta) {
211 if (prev) {
212 prev->next = m->next;
213 }
214 else {
215 it->meta = m->next;
216 }
217 metacache_remove_string (m->key);
218 metacache_remove_string (m->value);
219 free (m);
220 break;
221 }
222 prev = m;
223 m = m->next;
224 }
225 }
226
227
228 void
plt_delete_all_meta(playlist_t * it)229 plt_delete_all_meta (playlist_t *it) {
230 LOCK;
231 DB_metaInfo_t *m = it->meta;
232 DB_metaInfo_t *prev = NULL;
233 while (m) {
234 DB_metaInfo_t *next = m->next;
235 if (m->key[0] == ':') {
236 prev = m;
237 }
238 else {
239 if (prev) {
240 prev->next = next;
241 }
242 else {
243 it->meta = next;
244 }
245 metacache_remove_string (m->key);
246 metacache_remove_string (m->value);
247 free (m);
248 }
249 m = next;
250 }
251 UNLOCK;
252 }
253
254 int
plt_get_meta(playlist_t * handle,const char * key,char * val,int size)255 plt_get_meta (playlist_t *handle, const char *key, char *val, int size) {
256 *val = 0;
257 LOCK;
258 const char *v = plt_find_meta (handle, key);
259 if (!v) {
260 UNLOCK;
261 return 0;
262 }
263 strncpy (val, v, size);
264 UNLOCK;
265 return 1;
266 }
267