Mercurial > audlegacy
annotate Plugins/General/scrobbler/xmms_scrobbler.c @ 813:c8cf439179b8 trunk
[svn] - Fix a ton and a half of memory leaks, via the wonderful Leonardo Boshell <leonardop -at- gentoo.org>.
author | nenolod |
---|---|
date | Fri, 10 Mar 2006 08:20:15 -0800 |
parents | f2b43ca69f3c |
children | 6549a4c58e15 |
rev | line source |
---|---|
688 | 1 #include <audacious/plugin.h> |
2 #include <libaudacious/configdb.h> | |
3 #include <libaudacious/beepctrl.h> | |
4 | |
5 #include <glib.h> | |
6 #include <glib/gi18n.h> | |
7 | |
8 #include <unistd.h> | |
9 #include <stdio.h> | |
10 #include <stdlib.h> | |
11 #include <string.h> | |
12 #include <ctype.h> | |
13 #include <wchar.h> | |
14 #include <sys/time.h> | |
15 | |
16 #include "tags/include/tags.h" | |
17 #include "scrobbler.h" | |
18 #include "gtkstuff.h" | |
19 #include "config.h" | |
20 #include "fmt.h" | |
21 #include "tags/include/unicode.h" | |
22 | |
23 #define XS_CS xmms_scrobbler.xmms_session | |
24 | |
25 typedef struct submit_t | |
26 { | |
27 int dosubmit, pos_c, len; | |
28 } submit_t; | |
29 | |
30 static void init(void); | |
31 static void cleanup(void); | |
32 static void *xs_thread(void *); | |
33 static void *hs_thread(void *); | |
34 static int going; | |
35 | |
36 static GThread *pt_scrobbler; | |
37 static GMutex *m_scrobbler; | |
38 static GThread *pt_handshake; | |
39 | |
40 static GeneralPlugin xmms_scrobbler = | |
41 { | |
42 NULL, | |
43 NULL, | |
44 -1, | |
45 NULL, | |
46 init, | |
47 about_show, | |
48 configure_dialog, | |
49 cleanup | |
50 }; | |
51 | |
52 static void init(void) | |
53 { | |
54 char *username = NULL, *password = NULL; | |
55 ConfigDb *cfgfile; | |
56 going = 1; | |
57 GError **moo = NULL; | |
58 | |
59 if ((cfgfile = bmp_cfg_db_open()) != NULL) { | |
60 bmp_cfg_db_get_string(cfgfile, "audioscrobbler", "username", | |
61 &username); | |
62 bmp_cfg_db_get_string(cfgfile, "audioscrobbler", "password", | |
63 &password); | |
64 bmp_cfg_db_close(cfgfile); | |
65 } | |
66 if ((!username || !password) || (!*username || !*password)) { | |
67 pdebug("username/password not found - not starting", | |
68 DEBUG); | |
69 going = 0; | |
70 return; | |
71 } | |
72 sc_init(username, password); | |
73 g_free(username); | |
74 g_free(password); | |
75 m_scrobbler = g_mutex_new(); | |
76 if ((pt_scrobbler = g_thread_create(xs_thread, m_scrobbler, TRUE, moo)) == NULL) { | |
77 pdebug(fmt_vastr("Error creating scrobbler thread: %s", moo), DEBUG); | |
78 going = 0; | |
79 return; | |
80 } | |
81 if ((pt_handshake = g_thread_create(hs_thread, m_scrobbler, TRUE, NULL)) == NULL) { | |
82 pdebug("Error creating handshake thread", DEBUG); | |
83 going = 0; | |
84 return; | |
85 } | |
86 pdebug("plugin started", DEBUG); | |
87 } | |
88 | |
89 static void cleanup(void) | |
90 { | |
813
c8cf439179b8
[svn] - Fix a ton and a half of memory leaks, via the wonderful Leonardo Boshell <leonardop -at- gentoo.org>.
nenolod
parents:
786
diff
changeset
|
91 g_free (xmms_scrobbler.description); |
c8cf439179b8
[svn] - Fix a ton and a half of memory leaks, via the wonderful Leonardo Boshell <leonardop -at- gentoo.org>.
nenolod
parents:
786
diff
changeset
|
92 xmms_scrobbler.description = NULL; |
c8cf439179b8
[svn] - Fix a ton and a half of memory leaks, via the wonderful Leonardo Boshell <leonardop -at- gentoo.org>.
nenolod
parents:
786
diff
changeset
|
93 |
688 | 94 if (!going) |
95 return; | |
96 pdebug("about to lock mutex", DEBUG); | |
97 g_mutex_lock(m_scrobbler); | |
98 pdebug("locked mutex", DEBUG); | |
99 going = 0; | |
100 g_mutex_unlock(m_scrobbler); | |
101 pdebug("joining threads", DEBUG); | |
102 g_thread_join(pt_scrobbler); | |
103 | |
104 g_thread_join(pt_handshake); | |
105 | |
106 sc_cleaner(); | |
107 } | |
108 | |
109 static char ishttp(const char *a) | |
110 { | |
111 char *tmp, *bp; | |
112 int status = 0; | |
113 | |
114 if (!a || !*a) | |
115 return 0; | |
116 | |
117 tmp = strdup(a); | |
118 for (bp = tmp; *bp; bp++) | |
119 *bp = toupper(*bp); | |
120 if (strstr(tmp, "HTTP://")) | |
121 status = -1; | |
122 free(tmp); | |
123 return status; | |
124 } | |
125 | |
126 /* Following code thanks to nosuke | |
127 * | |
128 * It should probably be cleaned up | |
129 */ | |
130 static submit_t get_song_status(void) | |
131 { | |
132 static int pos_c, playlistlen_c, playtime_c, time_c, | |
133 pos_p = 0, playlistlen_p = 0, playtime_p = 0, | |
134 playtime_i = 0, time_i = 0, | |
135 playtime_ofs = 0; | |
136 static char *file_c = NULL, *file_p = NULL; | |
137 | |
138 static enum playstatus { | |
139 ps_stop, ps_play, ps_pause | |
140 } ps_c, ps_p = ps_stop; | |
141 | |
142 static int submitted = 0, changed, seeked, repeat, | |
143 filechanged, rewind, len = 0; | |
144 | |
145 static enum state { | |
146 start, stop, pause, restart, playing, pausing, stopping | |
147 } playstate; | |
148 | |
149 submit_t dosubmit; | |
150 | |
151 struct timeval timetmp; | |
152 | |
153 /* clear dosubmit */ | |
154 dosubmit.dosubmit = dosubmit.pos_c = dosubmit.len = 0; | |
155 | |
156 /* current music number */ | |
157 pos_c = xmms_remote_get_playlist_pos(XS_CS); | |
158 /* current file name */ | |
159 file_c = xmms_remote_get_playlist_file(XS_CS, pos_c); | |
160 /* total number */ | |
161 playlistlen_c = xmms_remote_get_playlist_length(XS_CS); | |
162 /* current playtime */ | |
163 playtime_c = xmms_remote_get_output_time(XS_CS); | |
164 /* total length */ | |
165 len = xmms_remote_get_playlist_time(XS_CS, pos_c); | |
166 | |
167 /* current time (ms) */ | |
168 gettimeofday(&timetmp, NULL); | |
169 time_c = timetmp.tv_sec * 1000 + timetmp.tv_usec / 1000; | |
170 | |
171 /* current status */ | |
172 if( xmms_remote_is_paused(XS_CS) ) { | |
173 ps_c = ps_pause; | |
174 }else if( xmms_remote_is_playing(XS_CS) ) { | |
175 ps_c = ps_play; | |
176 }else{ | |
177 ps_c = ps_stop; | |
178 } | |
179 | |
180 /* repeat setting */ | |
181 repeat = xmms_remote_is_repeat(XS_CS); | |
182 | |
183 /* | |
184 #ifdef MAKE_XMMS | |
185 // advance setting (required xmms-1.2.11 or over) | |
186 advance = xmms_remote_is_advance(XS_CS); | |
187 #else | |
188 advance = 1; | |
189 #endif | |
190 */ | |
191 | |
192 if( ps_p == ps_stop && ps_c == ps_stop ) playstate = stopping; | |
193 else if( ps_p == ps_stop && ps_c == ps_play ) playstate = start; | |
194 /* else if( ps_p == ps_stop && ps_c == ps_pause ) ; */ | |
195 else if( ps_p == ps_play && ps_c == ps_play ) playstate = playing; | |
196 else if( ps_p == ps_play && ps_c == ps_stop ) playstate = stop; | |
197 else if( ps_p == ps_play && ps_c == ps_pause ) playstate = pause; | |
198 else if( ps_p == ps_pause && ps_c == ps_pause ) playstate = pausing; | |
199 else if( ps_p == ps_pause && ps_c == ps_play ) playstate = restart; | |
200 else if( ps_p == ps_pause && ps_c == ps_stop ) playstate = stop; | |
201 else playstate = stopping; | |
202 | |
203 /* filename has changed */ | |
204 if( !(file_p == NULL && file_c == NULL) && | |
205 ((file_p == NULL && file_c != NULL) || | |
206 (file_p != NULL && file_c == NULL) || | |
207 (file_p != NULL && file_c != NULL && strcmp(file_c, file_p))) ){ | |
208 filechanged = 1; | |
209 pdebug("*** filechange ***", SUB_DEBUG); | |
210 }else{ | |
211 filechanged = 0; | |
212 } | |
213 if( file_c == NULL ){ len = 0; } | |
214 | |
215 /* whole rewind has occurred (maybe) */ | |
216 if( len != 0 && len - (playtime_p - playtime_c) < 3000 ){ | |
217 rewind = 1; | |
218 pdebug("*** rewind ***", SUB_DEBUG); | |
219 }else{ | |
220 rewind = 0; | |
221 } | |
222 | |
223 | |
224 changed = 0; | |
225 seeked = 0; | |
226 | |
227 switch( playstate ){ | |
228 case start: | |
229 pdebug("*** START ***", SUB_DEBUG); | |
230 break; | |
231 case stop: | |
232 pdebug("*** STOP ***", SUB_DEBUG); | |
233 len = 0; | |
234 break; | |
235 case pause: | |
236 pdebug("*** PAUSE ***", SUB_DEBUG); | |
237 playtime_ofs += playtime_c - playtime_i; /* save playtime */ | |
238 break; | |
239 case restart: | |
240 pdebug("*** RESTART ***", SUB_DEBUG); | |
241 playtime_i = playtime_c; /* restore playtime */ | |
242 break; | |
243 case playing: | |
244 if( (playtime_c < playtime_p) || /* back */ | |
245 ( (playtime_c - playtime_i) - (time_c - time_i) > 3000 ) | |
246 /* forward */ | |
247 ) { | |
248 seeked = 1; | |
249 } | |
250 | |
251 if( filechanged || /* filename has changed */ | |
252 ( !filechanged && /* filename has not changed... */ | |
253 /* (( rewind && (repeat && (!advance || | |
254 (pos_c == 0 && playlistlen_c == 1 )))) || */ | |
255 /* looping with only one file */ | |
256 (( pos_c == 0 && playlistlen_c == 1 && repeat | |
257 && rewind ) || | |
258 /* looping? */ | |
259 ( pos_p == pos_c && rewind ) || | |
260 | |
261 ( pos_p != pos_c && seeked ) || | |
262 /* skip from current music to next music, | |
263 which has the same filename as previous one */ | |
264 ( pos_p < pos_c && playtime_c < playtime_p ) || | |
265 /* current song has removed from playlist | |
266 but the next (following) song has the same | |
267 filename */ | |
268 ( playlistlen_p > playlistlen_c | |
269 && playtime_c < playtime_p )))){ | |
270 pdebug("*** CHANGE ***",SUB_DEBUG); | |
271 pdebug(fmt_vastr(" filechanged = %d",filechanged),SUB_DEBUG); | |
272 pdebug(fmt_vastr(" pos_c = %d",pos_c),SUB_DEBUG); | |
273 pdebug(fmt_vastr(" pos_p = %d",pos_p),SUB_DEBUG); | |
274 pdebug(fmt_vastr(" rewind = %d", rewind),SUB_DEBUG); | |
275 pdebug(fmt_vastr(" seeked = %d", seeked),SUB_DEBUG); | |
276 pdebug(fmt_vastr(" playtime_c = %d", playtime_c),SUB_DEBUG); | |
277 pdebug(fmt_vastr(" playtime_p = %d", playtime_p),SUB_DEBUG); | |
278 pdebug(fmt_vastr(" playlistlen_c = %d", playlistlen_p), | |
279 SUB_DEBUG); | |
280 pdebug(fmt_vastr(" playlistlen_p = %d", playlistlen_p), | |
281 SUB_DEBUG); | |
282 changed = 1; | |
283 seeked = 0; | |
786 | 284 |
285 if (file_p != NULL) | |
286 { | |
287 g_free(file_p); | |
288 file_p = NULL; | |
289 } | |
688 | 290 }else if( seeked ) { |
291 seeked = 1; | |
292 pdebug("*** SEEK ***", SUB_DEBUG); | |
293 } | |
294 | |
295 break; | |
296 case pausing: | |
297 if(playtime_c != playtime_p){ | |
298 pdebug("*** SEEK ***", SUB_DEBUG); | |
299 seeked = 1; | |
300 } | |
301 break; | |
302 case stopping: | |
303 len = 0; | |
304 break; | |
305 default: | |
306 pdebug("*** unknown state tranfer!!! ***", SUB_DEBUG); | |
307 break; | |
308 } | |
309 | |
310 | |
311 if( playstate == start || changed || (seeked && !submitted) ){ | |
312 /* reset counter */ | |
313 pdebug(" <<< reset counter >>>", SUB_DEBUG); | |
314 | |
315 submitted = 0; | |
316 playtime_ofs = 0; | |
317 playtime_i = playtime_c; | |
318 time_i = time_c; | |
319 | |
320 }else{ | |
321 /* check playtime for submitting */ | |
322 if( !submitted ){ | |
323 if( len > 30 * 1000 && | |
324 /* len < 30 *60 * 1000 && // crazy rule!!! */ | |
325 ( | |
326 (playtime_ofs + playtime_c - playtime_i > len / 2) || | |
327 (playtime_ofs + playtime_c - playtime_i > 240 * 1000) | |
328 /* (playtime_c - playtime_i > 10 * 1000)// for debug */ | |
329 )){ | |
330 pdebug("*** submitting requirements are satisfied.", | |
331 SUB_DEBUG); | |
332 pdebug(fmt_vastr(" len = %d, playtime = %d", | |
333 len / 1000, (playtime_c - playtime_i)/1000 ), | |
334 SUB_DEBUG); | |
335 submitted = 1; | |
336 dosubmit.dosubmit = 1; | |
337 dosubmit.pos_c = pos_c; | |
338 dosubmit.len = len; | |
339 } | |
340 } | |
341 } | |
342 | |
786 | 343 g_free(file_p); |
344 | |
688 | 345 /* keep current value for next iteration */ |
346 ps_p = ps_c; | |
347 file_p = file_c; | |
348 playtime_p = playtime_c; | |
349 pos_p = pos_c; | |
350 playlistlen_p = playlistlen_c; | |
351 | |
352 return dosubmit; | |
353 } | |
354 | |
700
99382cddf771
[svn] Fixes for all warnings (except 3 spurious GCC 4.0 ones, upgrade to 4.1 if you see them) and a performance increase. By external contributor Diego "FlameEyes" Petteno (Gentoo).
chainsaw
parents:
697
diff
changeset
|
355 static void *xs_thread(void *data __attribute__((unused))) |
688 | 356 { |
357 int run = 1, i; | |
358 char *charpos, *dirname; | |
359 gboolean direxists; | |
360 submit_t dosubmit; | |
361 | |
362 while (run) { | |
363 /* Error catching */ | |
364 if(sc_catch_error()) | |
365 { | |
366 errorbox_show(sc_fetch_error()); | |
697 | 367 sc_clear_error(); |
688 | 368 } |
369 | |
370 /* Check for ability to submit */ | |
371 dosubmit = get_song_status(); | |
372 | |
373 if(dosubmit.dosubmit) { | |
374 char *fname, /**title, *artist,*/ *tmp = NULL; /**sep*/ | |
375 int track = 0; | |
376 metatag_t *meta; | |
377 | |
378 pdebug("Submitting song.", DEBUG); | |
379 | |
380 meta = metatag_new(); | |
381 | |
382 fname = xmms_remote_get_playlist_file(0,dosubmit.pos_c); | |
383 if (ishttp(fname)) { | |
384 g_free(fname); | |
385 continue; | |
386 } | |
387 charpos = strrchr(fname, '.'); | |
388 if(charpos != NULL && | |
389 !fmt_strncasecmp(charpos + 1, "cda", 3)) | |
390 { | |
391 ConfigDb *cfgfile; | |
392 | |
393 if ((cfgfile = bmp_cfg_db_open()) | |
394 != NULL) | |
395 { | |
396 char *direntry = calloc(32, 1); | |
397 | |
398 dirname = fname; | |
399 tmp = strrchr(fname, '.'); | |
400 *tmp = '\0'; | |
401 track = (char)atoi(tmp - 2); | |
402 pdebug(fmt_vastr("Track: %d", track), | |
403 DEBUG); | |
404 tmp = strrchr(dirname, '/'); | |
405 *(tmp + 1) = '\0'; | |
406 direxists = bmp_cfg_db_get_string( | |
407 cfgfile, "CDDA", | |
408 "directory", &fname); | |
409 for(i = 0; direxists == TRUE | |
410 && strcmp(dirname, fname) == 0;) | |
411 { | |
412 i++; | |
413 snprintf(direntry, 31, | |
414 "directory%d", i); | |
415 g_free(fname); | |
416 direxists = | |
417 bmp_cfg_db_get_string( | |
418 cfgfile, "CDDA", | |
419 direntry, &fname); | |
420 } | |
421 if(i > 0) | |
422 { | |
423 snprintf(direntry, 31, | |
424 "device%d", i); | |
425 } | |
426 else | |
427 { | |
428 snprintf(direntry, 31, | |
429 "device"); | |
430 } | |
431 g_free(fname); | |
432 bmp_cfg_db_get_string(cfgfile, "CDDA", | |
433 direntry, &fname); | |
434 bmp_cfg_db_close(cfgfile); | |
435 free(direntry); | |
436 pdebug(fmt_vastr("CD Device: %s", | |
437 fname), DEBUG); | |
438 } | |
439 } | |
440 | |
441 pdebug(fmt_vastr("get_tag_data, %s", fname), DEBUG); | |
442 get_tag_data(meta, fname, track); | |
443 | |
444 if(meta->artist != NULL && meta->title != NULL) | |
445 { | |
446 pdebug(fmt_vastr( | |
447 "submitting artist: %s, title: %s", | |
448 meta->artist, meta->title), DEBUG); | |
449 sc_addentry(m_scrobbler, meta, | |
450 dosubmit.len/1000); | |
451 } | |
452 else | |
453 pdebug("couldn't determine artist - " | |
454 "title, not submitting", | |
455 DEBUG); | |
456 /* g_free(tmp); */ | |
457 g_free(fname); | |
458 metatag_delete(meta); | |
459 } | |
460 g_mutex_lock(m_scrobbler); | |
461 run = going; | |
462 g_mutex_unlock(m_scrobbler); | |
463 usleep(100000); | |
464 } | |
465 pdebug("scrobbler thread: exiting", DEBUG); | |
466 g_thread_exit(NULL); | |
467 | |
468 return NULL; | |
469 } | |
470 | |
700
99382cddf771
[svn] Fixes for all warnings (except 3 spurious GCC 4.0 ones, upgrade to 4.1 if you see them) and a performance increase. By external contributor Diego "FlameEyes" Petteno (Gentoo).
chainsaw
parents:
697
diff
changeset
|
471 static void *hs_thread(void *data __attribute__((unused))) |
688 | 472 { |
473 int run = 1; | |
474 | |
475 while(run) | |
476 { | |
477 if(sc_idle(m_scrobbler)) | |
478 { | |
479 pdebug("Giving up due to fatal error", DEBUG); | |
480 g_mutex_lock(m_scrobbler); | |
481 going = 0; | |
482 g_mutex_lock(m_scrobbler); | |
483 } | |
484 g_mutex_lock(m_scrobbler); | |
485 run = going; | |
486 g_mutex_unlock(m_scrobbler); | |
487 sleep(1); | |
488 } | |
489 pdebug("handshake thread: exiting", DEBUG); | |
490 g_thread_exit(NULL); | |
491 | |
492 return NULL; | |
493 } | |
494 | |
495 GeneralPlugin *get_gplugin_info(void) | |
496 { | |
497 xmms_scrobbler.description = g_strdup_printf(_("Scrobbler Plugin")); | |
498 return &xmms_scrobbler; | |
499 } |