From 3269cd672a9a5493f368be1a7a3f3b29e3f92199 Mon Sep 17 00:00:00 2001 From: waker Date: Mon, 23 Apr 2012 22:34:50 +0200 Subject: fixed ignoring cuesheet and log in search --- playlist.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index 4975faf0..2c07fccf 100644 --- a/playlist.c +++ b/playlist.c @@ -3531,9 +3531,6 @@ plt_search_process (playlist_t *playlist, const char *text) { } *out = 0; - const char *cuesheet = metacache_add_string ("cuesheet"); - const char *log = metacache_add_string("log"); - static int cmpidx = 0; cmpidx++; if (cmpidx > 127) { @@ -3548,7 +3545,7 @@ plt_search_process (playlist_t *playlist, const char *text) { if (m->key[0] == ':' || m->key[0] == '_' || m->key[0] == '!') { break; } - if (m->key!=cuesheet && m->key!=log) { + if (strcasecmp(m->key, "cuesheet") && strcasecmp (m->key, "log")) { char cmp = *(m->value-1); if (abs (cmp) == cmpidx) { @@ -3589,8 +3586,6 @@ plt_search_process (playlist_t *playlist, const char *text) { } } } - metacache_remove_string (cuesheet); - metacache_remove_string(log); UNLOCK; } -- cgit v1.2.3 From ce7f7611615bbe32c859a94a13f343097a120f19 Mon Sep 17 00:00:00 2001 From: waker Date: Wed, 25 Apr 2012 17:23:03 +0200 Subject: fixed plt_search_process bug which was creating single-linked list instead of double-linked; fixed plt_load bug which was leading to crash if playlist file fails to load early, e.g. if a file has size of 0 --- playlist.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index 2c07fccf..cc8eca64 100644 --- a/playlist.c +++ b/playlist.c @@ -2134,12 +2134,14 @@ plt_load (playlist_t *plt, playItem_t *after, const char *fname, int *pabort, in return NULL; } + playItem_t *last_added = NULL; uint8_t majorver; uint8_t minorver; playItem_t *it = NULL; char magic[4]; if (fread (magic, 1, 4, fp) != 4) { + trace ("failed to read magic\n"); goto load_fail; } if (strncmp (magic, "DBPL", 4)) { @@ -2166,8 +2168,6 @@ plt_load (playlist_t *plt, playItem_t *after, const char *fname, int *pabort, in goto load_fail; } - playItem_t *last_added = NULL; - for (uint32_t i = 0; i < cnt; i++) { it = pl_item_alloc (); if (!it) { @@ -2379,6 +2379,7 @@ plt_load (playlist_t *plt, playItem_t *after, const char *fname, int *pabort, in trace ("plt_load: success\n"); return last_added; load_fail: + plt_clear (plt); fprintf (stderr, "playlist load fail (%s)!\n", fname); if (fp) { fclose (fp); @@ -3551,6 +3552,7 @@ plt_search_process (playlist_t *playlist, const char *text) { if (abs (cmp) == cmpidx) { if (cmp > 0) { it->next[PL_SEARCH] = NULL; + it->prev[PL_SEARCH] = playlist->tail[PL_SEARCH]; if (playlist->tail[PL_SEARCH]) { playlist->tail[PL_SEARCH]->next[PL_SEARCH] = it; playlist->tail[PL_SEARCH] = it; @@ -3567,6 +3569,7 @@ plt_search_process (playlist_t *playlist, const char *text) { //fprintf (stderr, "%s -> %s match (%s.%s)\n", text, m->value, pl_find_meta_raw (it, ":URI"), m->key); // add to list it->next[PL_SEARCH] = NULL; + it->prev[PL_SEARCH] = playlist->tail[PL_SEARCH]; if (playlist->tail[PL_SEARCH]) { playlist->tail[PL_SEARCH]->next[PL_SEARCH] = it; playlist->tail[PL_SEARCH] = it; -- cgit v1.2.3 From 44ce52f45732fa0c293da88afb384c6cbc9c8b9f Mon Sep 17 00:00:00 2001 From: waker Date: Wed, 16 May 2012 19:46:20 +0200 Subject: added filename handling to search_process --- playlist.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index cc8eca64..11a280c1 100644 --- a/playlist.c +++ b/playlist.c @@ -3543,9 +3543,20 @@ plt_search_process (playlist_t *playlist, const char *text) { if (*text) { DB_metaInfo_t *m = NULL; for (m = it->meta; m; m = m->next) { - if (m->key[0] == ':' || m->key[0] == '_' || m->key[0] == '!') { + int is_uri = !strcmp (m->key, ":URI"); + if ((m->key[0] == ':' && !is_uri) || m->key[0] == '_' || m->key[0] == '!') { break; } + const char *value = m->value; + if (is_uri) { + value = strrchr (value, '/'); + if (value) { + value++; + } + else { + value = m->value; + } + } if (strcasecmp(m->key, "cuesheet") && strcasecmp (m->key, "log")) { char cmp = *(m->value-1); @@ -3565,8 +3576,8 @@ plt_search_process (playlist_t *playlist, const char *text) { break; } } - else if (utfcasestr_fast (m->value, lc)) { - //fprintf (stderr, "%s -> %s match (%s.%s)\n", text, m->value, pl_find_meta_raw (it, ":URI"), m->key); + else if (utfcasestr_fast (value, lc)) { + //fprintf (stderr, "%s -> %s match (%s.%s)\n", text, value, pl_find_meta_raw (it, ":URI"), m->key); // add to list it->next[PL_SEARCH] = NULL; it->prev[PL_SEARCH] = playlist->tail[PL_SEARCH]; -- cgit v1.2.3 From 816d87e1d38dc0fecbe1fa47794b2d7a18d2e321 Mon Sep 17 00:00:00 2001 From: waker Date: Thu, 17 May 2012 20:50:47 +0200 Subject: fixed many calls to pl_find_meta[_raw] being called without pl_lock; added debug pl_ensure_lock function which asserts when pl_lock is not set when it is required; added new API functions for thread-safe metadata access --- deadbeef.h | 11 +++++ playlist.c | 20 +++++++++- playlist.h | 15 +++++++ plmeta.c | 45 +++++++++++++++++---- pltmeta.c | 13 ++++++ plugins.c | 5 +++ plugins/gtkui/gtkui.c | 6 +-- plugins/gtkui/plcommon.c | 12 +++++- plugins/gtkui/trkproperties.c | 18 +++++++-- plugins/lastfm/lastfm.c | 93 +++++++++++++++++++++---------------------- plugins/mpgmad/mpgmad.c | 23 +++++++---- plugins/shellexec/shellexec.c | 2 + streamer.c | 4 ++ 13 files changed, 194 insertions(+), 73 deletions(-) (limited to 'playlist.c') diff --git a/deadbeef.h b/deadbeef.h index 73452c4e..6de9e9d0 100644 --- a/deadbeef.h +++ b/deadbeef.h @@ -61,6 +61,7 @@ extern "C" { // api version history: // 9.9 -- devel +// 1.4 -- deadbeef-0.5.5 // 1.3 -- deadbeef-0.5.3 // 1.2 -- deadbeef-0.5.2 // 1.1 -- deadbeef-0.5.1 @@ -750,10 +751,20 @@ typedef struct { void (*metacache_unref) (const char *str); // this function must return original un-overriden value (ignoring the keys prefixed with '!') + // it's not thread-safe, and must be used under the same conditions as the + // pl_find_meta const char *(*pl_find_meta_raw) (DB_playItem_t *it, const char *key); // ******* new 1.3 APIs ******** int (*streamer_dsp_chain_save) (void); + + // ******* new 1.4 APIs ******** + int (*pl_get_meta) (DB_playItem_t *it, const char *key, char *val, int size); + int (*pl_get_meta_raw) (DB_playItem_t *it, const char *key, char *val, int size); + int (*plt_get_meta) (ddb_playlist_t *handle, const char *key, char *val, int size); + + // fast way to test if a field exists in playitem + int (*pl_meta_exists) (DB_playItem_t *it, const char *key); } DB_functions_t; // NOTE: an item placement must be selected like this diff --git a/playlist.c b/playlist.c index 11a280c1..d50bff77 100644 --- a/playlist.c +++ b/playlist.c @@ -55,7 +55,7 @@ #define DISABLE_LOCKING 0 #define DEBUG_LOCKING 0 -//#define DETECT_PL_LOCK_RC 1 +#define DETECT_PL_LOCK_RC 1 // file format revision history // 1.1->1.2 changelog: @@ -186,7 +186,7 @@ pl_lock (void) { #if !DISABLE_LOCKING mutex_lock (mutex); #if DETECT_PL_LOCK_RC - pl_lock_tid = pthread_self(); + pl_lock_tid = pthread_self (); tids[ntids++] = pl_lock_tid; #endif @@ -1170,10 +1170,12 @@ error: playItem_t * plt_insert_cue (playlist_t *plt, playItem_t *after, playItem_t *origin, int numsamples, int samplerate) { trace ("pl_insert_cue numsamples=%d, samplerate=%d\n", numsamples, samplerate); + pl_lock (); const char *fname = pl_find_meta_raw (origin, ":URI"); int len = strlen (fname); char cuename[len+5]; strcpy (cuename, fname); + pl_unlock (); strcpy (cuename+len, ".cue"); DB_FILE *fp = vfs_fopen (cuename); if (!fp) { @@ -3812,3 +3814,17 @@ int plt_is_fast_mode (playlist_t *plt) { return plt->fast_mode; } + +void +pl_ensure_lock (void) { +#if DETECT_PL_LOCK_RC + pthread_t tid = pthread_self (); + for (int i = 0; i < ntids; i++) { + if (tids[i] == tid) { + return; + } + } + fprintf (stderr, "\033[0;31mnon-thread-safe playlist access function was called outside of pl_lock. please make a backtrace and post a bug. thank you.\033[37;0m\n"); + assert(0); +#endif +} diff --git a/playlist.h b/playlist.h index fefb3943..06966bde 100644 --- a/playlist.h +++ b/playlist.h @@ -454,4 +454,19 @@ plt_set_fast_mode (playlist_t *plt, int fast); int plt_is_fast_mode (playlist_t *plt); +void +pl_ensure_lock (void); + +int +pl_get_meta (playItem_t *it, const char *key, char *val, int size); + +int +pl_get_meta_raw (playItem_t *it, const char *key, char *val, int size); + +int +pl_meta_exists (playItem_t *it, const char *key); + +int +plt_get_meta (playlist_t *handle, const char *key, char *val, int size); + #endif // __PLAYLIST_H diff --git a/plmeta.c b/plmeta.c index cf17f341..4b8e9a8a 100644 --- a/plmeta.c +++ b/plmeta.c @@ -190,14 +190,13 @@ pl_delete_meta (playItem_t *it, const char *key) { const char * pl_find_meta (playItem_t *it, const char *key) { - pl_lock (); + pl_ensure_lock (); DB_metaInfo_t *m = it->meta; if (key && key[0] == ':') { // try to find an override while (m) { if (m->key[0] == '!' && !strcasecmp (key+1, m->key+1)) { - pl_unlock (); return m->value; } m = m->next; @@ -207,27 +206,23 @@ pl_find_meta (playItem_t *it, const char *key) { m = it->meta; while (m) { if (!strcasecmp (key, m->key)) { - pl_unlock (); return m->value; } m = m->next; } - pl_unlock (); return NULL; } const char * pl_find_meta_raw (playItem_t *it, const char *key) { - pl_lock (); + pl_ensure_lock (); DB_metaInfo_t *m = it->meta; while (m) { if (!strcasecmp (key, m->key)) { - pl_unlock (); return m->value; } m = m->next; } - pl_unlock (); return NULL; } @@ -303,3 +298,39 @@ pl_delete_all_meta (playItem_t *it) { } UNLOCK; } + +int +pl_get_meta (playItem_t *it, const char *key, char *val, int size) { + *val = 0; + pl_lock (); + const char *v = pl_find_meta (it, key); + if (!val) { + pl_unlock (); + return 0; + } + strncpy (val, v, size); + pl_unlock (); + return 1; +} + +int +pl_get_meta_raw (playItem_t *it, const char *key, char *val, int size) { + *val = 0; + pl_lock (); + const char *v = pl_find_meta_raw (it, key); + if (!val) { + pl_unlock (); + return 0; + } + strncpy (val, v, size); + pl_unlock (); + return 1; +} + +int +pl_meta_exists (playItem_t *it, const char *key) { + pl_lock (); + const char *v = pl_find_meta (it, key); + pl_unlock (); + return v ? 1 : 0; +} diff --git a/pltmeta.c b/pltmeta.c index e2e6cd04..63c7279c 100644 --- a/pltmeta.c +++ b/pltmeta.c @@ -234,3 +234,16 @@ plt_delete_all_meta (playlist_t *it) { UNLOCK; } +int +plt_get_meta (playlist_t *handle, const char *key, char *val, int size) { + *val = 0; + LOCK; + const char *v = plt_find_meta (handle, key); + if (!v) { + UNLOCK; + return 0; + } + strncpy (val, v, size); + UNLOCK; + return 1; +} diff --git a/plugins.c b/plugins.c index 522930de..c5f56c4f 100644 --- a/plugins.c +++ b/plugins.c @@ -331,6 +331,11 @@ static DB_functions_t deadbeef_api = { .pl_find_meta_raw = (const char *(*) (DB_playItem_t *it, const char *key))pl_find_meta_raw, // ******* new 1.3 APIs ******** .streamer_dsp_chain_save = streamer_dsp_chain_save, + // ******* new 1.4 APIs ******** + .pl_get_meta = (int (*) (DB_playItem_t *it, const char *key, char *val, int size))pl_get_meta, + .pl_get_meta_raw = (int (*) (DB_playItem_t *it, const char *key, char *val, int size))pl_get_meta_raw, + .plt_get_meta = (int (*) (ddb_playlist_t *handle, const char *key, char *val, int size))plt_get_meta, + .pl_meta_exists = (int (*) (DB_playItem_t *it, const char *key))pl_meta_exists, }; DB_functions_t *deadbeef = &deadbeef_api; diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c index 7ded4f6d..b96eb301 100644 --- a/plugins/gtkui/gtkui.c +++ b/plugins/gtkui/gtkui.c @@ -192,9 +192,9 @@ update_songinfo (gpointer ctx) { } } const char *spaused = deadbeef->get_output ()->state () == OUTPUT_STATE_PAUSED ? _("Paused | ") : ""; - const char *filetype = deadbeef->pl_find_meta (track, ":FILETYPE"); - if (!filetype) { - filetype = "-"; + char filetype[20]; + if (!deadbeef->pl_get_meta (track, ":FILETYPE", filetype, sizeof (filetype))) { + strcpy (filetype, "-"); } snprintf (sbtext_new, sizeof (sbtext_new), _("%s%s %s| %dHz | %d bit | %s | %d:%02d / %s | %d tracks | %s total playtime"), spaused, filetype, sbitrate, samplerate, bitspersample, mode, minpos, secpos, t, deadbeef->pl_getcount (PL_MAIN), totaltime_str); } diff --git a/plugins/gtkui/plcommon.c b/plugins/gtkui/plcommon.c index 406b2f16..f0c36a24 100644 --- a/plugins/gtkui/plcommon.c +++ b/plugins/gtkui/plcommon.c @@ -256,8 +256,16 @@ main_reload_metadata_activate DdbListview *ps = DDB_LISTVIEW (g_object_get_data (G_OBJECT (menuitem), "ps")); DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN); while (it) { - const char *decoder_id = deadbeef->pl_find_meta (it, ":DECODER"); - if (deadbeef->pl_is_selected (it) && deadbeef->is_local_file (deadbeef->pl_find_meta (it, ":URI")) && decoder_id) { + deadbeef->pl_lock (); + char decoder_id[100]; + const char *dec = deadbeef->pl_find_meta (it, ":DECODER"); + if (dec) { + strncpy (decoder_id, dec, sizeof (decoder_id)); + } + int match = deadbeef->pl_is_selected (it) && deadbeef->is_local_file (deadbeef->pl_find_meta (it, ":URI")) && dec; + deadbeef->pl_unlock (); + + if (match) { uint32_t f = deadbeef->pl_get_item_flags (it); if (!(f & DDB_IS_SUBTRACK)) { f &= ~DDB_TAG_MASK; diff --git a/plugins/gtkui/trkproperties.c b/plugins/gtkui/trkproperties.c index 590bf1fa..75b1f256 100644 --- a/plugins/gtkui/trkproperties.c +++ b/plugins/gtkui/trkproperties.c @@ -107,6 +107,7 @@ get_field_value (char *out, int size, const char *key, const char *(*getter)(DB_ return 0; } char *p = out; + deadbeef->pl_lock (); const char **prev = malloc (sizeof (const char *) * numtracks); memset (prev, 0, sizeof (const char *) * numtracks); for (int i = 0; i < numtracks; i++) { @@ -142,6 +143,7 @@ get_field_value (char *out, int size, const char *key, const char *(*getter)(DB_ break; } } + deadbeef->pl_unlock (); if (size <= 1) { gchar *prev = g_utf8_prev_char (out-4); strcpy (prev, "..."); @@ -491,8 +493,9 @@ static gboolean set_progress_cb (void *ctx) { DB_playItem_t *track = ctx; GtkWidget *progressitem = lookup_widget (progressdlg, "progresstitle"); - const char *fname = deadbeef->pl_find_meta_raw (track, ":URI"); - gtk_entry_set_text (GTK_ENTRY (progressitem), fname); + deadbeef->pl_lock (); + gtk_entry_set_text (GTK_ENTRY (progressitem), deadbeef->pl_find_meta_raw (track, ":URI")); + deadbeef->pl_unlock (); deadbeef->pl_item_unref (track); return FALSE; } @@ -504,8 +507,15 @@ write_meta_worker (void *ctx) { break; } DB_playItem_t *track = tracks[t]; - const char *decoder_id = deadbeef->pl_find_meta_raw (track, ":DECODER"); - if (track && decoder_id) { + deadbeef->pl_lock (); + const char *dec = deadbeef->pl_find_meta_raw (track, ":DECODER"); + char decoder_id[100]; + if (dec) { + strncpy (decoder_id, dec, sizeof (decoder_id)); + } + int match = track && dec; + deadbeef->pl_unlock (); + if (match) { int is_subtrack = deadbeef->pl_get_item_flags (track) & DDB_IS_SUBTRACK; if (is_subtrack) { continue; diff --git a/plugins/lastfm/lastfm.c b/plugins/lastfm/lastfm.c index 8ab6c5f8..1e4fec70 100644 --- a/plugins/lastfm/lastfm.c +++ b/plugins/lastfm/lastfm.c @@ -49,6 +49,8 @@ static uintptr_t lfm_cond; static int lfm_stopthread; static intptr_t lfm_tid; +#define META_FIELD_SIZE 200 + DB_plugin_t * lastfm_load (DB_functions_t *api) { deadbeef = api; @@ -317,50 +319,41 @@ fail: } static int -lfm_fetch_song_info (DB_playItem_t *song, const char **a, const char **t, const char **b, float *l, const char **n, const char **m) { +lfm_fetch_song_info (DB_playItem_t *song, char *a, char *t, char *b, float *l, char *n, char *m) { if (deadbeef->conf_get_int ("lastfm.prefer_album_artist", 0)) { - *a = deadbeef->pl_find_meta (song, "band"); - if (!(*a)) { - *a = deadbeef->pl_find_meta (song, "album artist"); - } - if (!(*a)) { - *a = deadbeef->pl_find_meta (song, "albumartist"); - } - if (!(*a)) { - *a = deadbeef->pl_find_meta (song, "artist"); + if (!deadbeef->pl_get_meta (song, "band", a, META_FIELD_SIZE)) { + if (!deadbeef->pl_get_meta (song, "album artist", a, META_FIELD_SIZE)) { + if (!deadbeef->pl_get_meta (song, "albumartist", a, META_FIELD_SIZE)) { + if (!deadbeef->pl_get_meta (song, "artist", a, META_FIELD_SIZE)) { + return -1; + } + } + } } } else { - *a = deadbeef->pl_find_meta (song, "artist"); - if (!(*a)) { - *a = deadbeef->pl_find_meta (song, "band"); - } - if (!(*a)) { - *a = deadbeef->pl_find_meta (song, "album artist"); - } - if (!(*a)) { - *a = deadbeef->pl_find_meta (song, "albumartist"); + if (!deadbeef->pl_get_meta (song, "artist", a, META_FIELD_SIZE)) { + if (!deadbeef->pl_get_meta (song, "band", a, META_FIELD_SIZE)) { + if (!deadbeef->pl_get_meta (song, "album artist", a, META_FIELD_SIZE)) { + if (!deadbeef->pl_get_meta (song, "albumartist", a, META_FIELD_SIZE)) { + return -1; + } + } + } } } - if (!*a) { - return -1; - } - *t = deadbeef->pl_find_meta (song, "title"); - if (!*t) { + if (!deadbeef->pl_get_meta (song, "title", t, META_FIELD_SIZE)) { return -1; } - *b = deadbeef->pl_find_meta (song, "album"); - if (!*b) { - *b = ""; + if (!deadbeef->pl_get_meta (song, "album", b, META_FIELD_SIZE)) { + *b = 0; } *l = deadbeef->pl_get_item_duration (song); - *n = deadbeef->pl_find_meta (song, "track"); - if (!*n) { - *n = ""; + if (!deadbeef->pl_get_meta (song, "track", n, META_FIELD_SIZE)) { + *n = 0; } - *m = deadbeef->pl_find_meta (song, "mbid"); - if (!*m) { - *m = ""; + if (!deadbeef->pl_get_meta (song, "mbid", m, META_FIELD_SIZE)) { + *m = 0; } return 0; } @@ -443,12 +436,12 @@ lfm_format_uri (int subm, DB_playItem_t *song, char *out, int outl, time_t start return -1; } int sz = outl; - const char *a; // artist - const char *t; // title - const char *b; // album + char a[META_FIELD_SIZE]; // artist + char t[META_FIELD_SIZE]; // title + char b[META_FIELD_SIZE]; // album float l; // duration - const char *n; // tracknum - const char *m; // muzicbrainz id + char n[META_FIELD_SIZE]; // tracknum + char m[META_FIELD_SIZE]; // muzicbrainz id char ka[6] = "a"; char kt[6] = "t"; @@ -466,7 +459,7 @@ lfm_format_uri (int subm, DB_playItem_t *song, char *out, int outl, time_t start strcpy (km+1, ka+1); } - if (lfm_fetch_song_info (song, &a, &t, &b, &l, &n, &m) == 0) { + if (lfm_fetch_song_info (song, a, t, b, &l, n, m) == 0) { // trace ("playtime: %f\nartist: %s\ntitle: %s\nalbum: %s\nduration: %f\ntracknum: %s\n---\n", song->playtime, a, t, b, l, n); } else { @@ -559,9 +552,8 @@ lastfm_songchanged (ddb_event_trackchange_t *ev, uintptr_t data) { #endif - if (!deadbeef->pl_find_meta (ev->from, "artist") - || !deadbeef->pl_find_meta (ev->from, "title") -// || !deadbeef->pl_find_meta (ev->from, "album") + if (!deadbeef->pl_meta_exists (ev->from, "artist") + || !deadbeef->pl_meta_exists (ev->from, "title") ) { trace ("lfm: not enough metadata for submission, artist=%s, title=%s, album=%s\n", deadbeef->pl_find_meta (ev->from, "artist"), deadbeef->pl_find_meta (ev->from, "title"), deadbeef->pl_find_meta (ev->from, "album")); return 0; @@ -876,11 +868,14 @@ lastfm_stop (void) { static int lfm_action_lookup (DB_plugin_action_t *action, DB_playItem_t *it) { - const char *artist = deadbeef->pl_find_meta (it, "artist"); - const char *title = deadbeef->pl_find_meta (it, "title"); - - if (!title || !artist) + char artist[META_FIELD_SIZE]; + if (!deadbeef->pl_get_meta (it, "artist", artist, sizeof (artist))) { + return 0; + } + char title[META_FIELD_SIZE]; + if (!deadbeef->pl_get_meta (it, "title", title, sizeof (title))) { return 0; + } char eartist [strlen (artist) * 3 + 1]; char etitle [strlen (title) * 3 + 1]; @@ -925,9 +920,10 @@ static DB_plugin_action_t lookup_action = { static DB_plugin_action_t * lfm_get_actions (DB_playItem_t *it) { + deadbeef->pl_lock (); if (!it || - !deadbeef->pl_find_meta (it, "artist") || - !deadbeef->pl_find_meta (it, "title")) + !deadbeef->pl_meta_exists (it, "artist") || + !deadbeef->pl_meta_exists (it, "title")) { love_action.flags |= DB_ACTION_DISABLED; lookup_action.flags |= DB_ACTION_DISABLED; @@ -937,6 +933,7 @@ lfm_get_actions (DB_playItem_t *it) love_action.flags &= ~DB_ACTION_DISABLED; lookup_action.flags &= ~DB_ACTION_DISABLED; } + deadbeef->pl_unlock (); return &lookup_action; } diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 32f4022f..0e06bbeb 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -793,7 +793,9 @@ cmp3_init (DB_fileinfo_t *_info, DB_playItem_t *it) { mpgmad_info_t *info = (mpgmad_info_t *)_info; _info->plugin = &plugin; memset (&info->buffer, 0, sizeof (info->buffer)); + deadbeef->pl_lock (); info->buffer.file = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI")); + deadbeef->pl_unlock (); if (!info->buffer.file) { return -1; } @@ -1357,15 +1359,20 @@ cmp3_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { deadbeef->plt_set_item_duration (plt, it, buffer.duration); deadbeef->fclose (fp); - const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet"); - if (cuesheet) { - DB_playItem_t *last = deadbeef->plt_insert_cue_from_buffer (plt, after, it, cuesheet, strlen (cuesheet), buffer.totalsamples-buffer.delay-buffer.padding, buffer.samplerate); - if (last) { - deadbeef->pl_item_unref (it); - deadbeef->pl_item_unref (last); - return last; + deadbeef->pl_lock (); + { + const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet"); + if (cuesheet) { + DB_playItem_t *last = deadbeef->plt_insert_cue_from_buffer (plt, after, it, cuesheet, strlen (cuesheet), buffer.totalsamples-buffer.delay-buffer.padding, buffer.samplerate); + deadbeef->pl_unlock (); + if (last) { + deadbeef->pl_item_unref (it); + deadbeef->pl_item_unref (last); + return last; + } } } + deadbeef->pl_unlock (); // FIXME! bad numsamples passed to cue @@ -1383,7 +1390,9 @@ cmp3_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { int cmp3_read_metadata (DB_playItem_t *it) { + deadbeef->pl_lock (); DB_FILE *fp = deadbeef->fopen (deadbeef->pl_find_meta (it, ":URI")); + deadbeef->pl_unlock (); if (!fp) { return -1; } diff --git a/plugins/shellexec/shellexec.c b/plugins/shellexec/shellexec.c index b419a4c9..7d49c2d6 100644 --- a/plugins/shellexec/shellexec.c +++ b/plugins/shellexec/shellexec.c @@ -103,7 +103,9 @@ shx_callback (Shx_action_t *action, DB_playItem_t *it) static DB_plugin_action_t * shx_get_plugin_actions (DB_playItem_t *it) { + deadbeef->pl_lock (); int is_local = it ? deadbeef->is_local_file (deadbeef->pl_find_meta (it, ":URI")) : 1; + deadbeef->pl_unlock (); Shx_action_t *action; for (action = actions; action; action = (Shx_action_t *)action->parent.next) diff --git a/streamer.c b/streamer.c index 2a5d22bc..53993d9c 100644 --- a/streamer.c +++ b/streamer.c @@ -813,7 +813,9 @@ streamer_set_current (playItem_t *it) { pl_item_ref (i); int res = -1; while (i) { + pl_lock (); pl_replace_meta (it, "!URI", pl_find_meta_raw (i, ":URI")); + pl_unlock (); res = streamer_set_current (it); if (!res) { pl_item_unref (i); @@ -2244,6 +2246,7 @@ streamer_notify_order_changed (int prev_order, int new_order) { playItem_t *curr = playing_track; if (curr) { + pl_lock (); const char *alb = pl_find_meta_raw (curr, "album"); const char *art = pl_find_meta_raw (curr, "artist"); playItem_t *next = curr->prev[PL_MAIN]; @@ -2256,6 +2259,7 @@ streamer_notify_order_changed (int prev_order, int new_order) { break; } } + pl_unlock (); } streamer_unlock (); } -- cgit v1.2.3 From b2aa79597d437294233f60835dad3cf9396cf710 Mon Sep 17 00:00:00 2001 From: waker Date: Sun, 20 May 2012 12:58:43 +0200 Subject: disabled pl_lock debugging --- playlist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index d50bff77..855486c6 100644 --- a/playlist.c +++ b/playlist.c @@ -55,7 +55,7 @@ #define DISABLE_LOCKING 0 #define DEBUG_LOCKING 0 -#define DETECT_PL_LOCK_RC 1 +#define DETECT_PL_LOCK_RC 0 // file format revision history // 1.1->1.2 changelog: -- cgit v1.2.3 From df0232d67ee161abc1c1341856a2c5e60b9e568a Mon Sep 17 00:00:00 2001 From: waker Date: Tue, 22 May 2012 22:21:55 +0200 Subject: implemented playlist saving as atomic operation; fixed few PATH_MAX definitions --- common.h | 7 +++++-- playlist.c | 9 +++++++-- plugins.c | 4 ---- plugins/converter/converter.c | 10 ++++++---- plugins/converter/convgui.c | 10 ++++++---- 5 files changed, 24 insertions(+), 16 deletions(-) (limited to 'playlist.c') diff --git a/common.h b/common.h index 39355685..0b8fe998 100644 --- a/common.h +++ b/common.h @@ -19,8 +19,11 @@ #define __COMMON_H #include -#ifndef PATH_MAX -#define PATH_MAX 1024 /* max # of characters in a path name */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#if HAVE_SYS_SYSLIMITS_H +#include #endif #define min(x,y) ((x)<(y)?(x):(y)) diff --git a/playlist.c b/playlist.c index 855486c6..3b957487 100644 --- a/playlist.c +++ b/playlist.c @@ -1864,10 +1864,12 @@ plt_save (playlist_t *plt, playItem_t *first, playItem_t *last, const char *fnam } } + char tempfile[PATH_MAX]; + snprintf (tempfile, sizeof (tempfile), "%s.tmp", fname); const char magic[] = "DBPL"; uint8_t majorver = PLAYLIST_MAJOR_VER; uint8_t minorver = PLAYLIST_MINOR_VER; - FILE *fp = fopen (fname, "w+b"); + FILE *fp = fopen (tempfile, "w+b"); if (!fp) { UNLOCK; return -1; @@ -2034,11 +2036,14 @@ plt_save (playlist_t *plt, playItem_t *first, playItem_t *last, const char *fnam UNLOCK; fclose (fp); + if (rename (tempfile, fname) != 0) { + fprintf (stderr, "playlist rename %s -> %s failed: %s\n", tempfile, fname, strerror (errno)); + } return 0; save_fail: UNLOCK; fclose (fp); - unlink (fname); + unlink (tempfile); return -1; } diff --git a/plugins.c b/plugins.c index c5f56c4f..1cdb5111 100644 --- a/plugins.c +++ b/plugins.c @@ -50,10 +50,6 @@ #define trace(...) { fprintf(stderr, __VA_ARGS__); } //#define trace(fmt,...) -#ifndef PATH_MAX -#define PATH_MAX 1024 /* max # of characters in a path name */ -#endif - //#define DISABLE_VERSIONCHECK 1 // deadbeef api diff --git a/plugins/converter/converter.c b/plugins/converter/converter.c index ad68bab9..ed276f20 100644 --- a/plugins/converter/converter.c +++ b/plugins/converter/converter.c @@ -16,6 +16,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#ifdef HAVE_CONFIG_H +# include "../../config.h" +#endif +#if HAVE_SYS_SYSLIMITS_H +#include +#endif #include #include #include @@ -36,10 +42,6 @@ }) #endif -#ifndef PATH_MAX -#define PATH_MAX 1024 /* max # of characters in a path name */ -#endif - #ifndef __linux__ #define O_LARGEFILE 0 #endif diff --git a/plugins/converter/convgui.c b/plugins/converter/convgui.c index 27517022..8054768b 100644 --- a/plugins/converter/convgui.c +++ b/plugins/converter/convgui.c @@ -16,6 +16,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#ifdef HAVE_CONFIG_H +# include "../../config.h" +#endif +#if HAVE_SYS_SYSLIMITS_H +#include +#endif #include #include #include @@ -27,10 +33,6 @@ #include "interface.h" #include "../gtkui/gtkui_api.h" -#ifndef PATH_MAX -#define PATH_MAX 1024 /* max # of characters in a path name */ -#endif - DB_functions_t *deadbeef; ddb_converter_t *converter_plugin; -- cgit v1.2.3 From 51f37c71ba906c9887934836c51122ffe927976b Mon Sep 17 00:00:00 2001 From: waker Date: Tue, 22 May 2012 22:40:45 +0200 Subject: return err if playlist save fails on rename --- playlist.c | 1 + 1 file changed, 1 insertion(+) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index 3b957487..0cc0533f 100644 --- a/playlist.c +++ b/playlist.c @@ -2038,6 +2038,7 @@ plt_save (playlist_t *plt, playItem_t *first, playItem_t *last, const char *fnam fclose (fp); if (rename (tempfile, fname) != 0) { fprintf (stderr, "playlist rename %s -> %s failed: %s\n", tempfile, fname, strerror (errno)); + return -1; } return 0; save_fail: -- cgit v1.2.3 From eb320c8cd20380ae78bcd7be582dcf4dbdcc97b9 Mon Sep 17 00:00:00 2001 From: waker Date: Fri, 3 Aug 2012 21:22:52 +0200 Subject: added itunes tags support to title formatting --- playlist.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index 0cc0533f..9244b205 100644 --- a/playlist.c +++ b/playlist.c @@ -2947,6 +2947,10 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s, c = snprintf (t, e-t, "Icy | "); t += c; } + if (it->_flags & DDB_TAG_ITUNES) { + c = snprintf (t, e-t, "iTunes | "); + t += c; + } if (t != tags) { *(t - 3) = 0; } -- cgit v1.2.3 From 99730a4ce8e554147c01fc976e5c862ce01ee1e0 Mon Sep 17 00:00:00 2001 From: waker Date: Sun, 5 Aug 2012 12:04:48 +0200 Subject: skip utf8 bom in cuesheets --- playlist.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index 9244b205..5b240e80 100644 --- a/playlist.c +++ b/playlist.c @@ -998,6 +998,10 @@ plt_process_cue_track (playlist_t *playlist, const char *fname, playItem_t **pre playItem_t * plt_insert_cue_from_buffer (playlist_t *playlist, playItem_t *after, playItem_t *origin, const uint8_t *buffer, int buffersize, int numsamples, int samplerate) { LOCK; + if (buffersize >= 3 && buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf) { + buffer += 3; + buffersize -= 3; + } playItem_t *ins = after; trace ("plt_insert_cue_from_buffer numsamples=%d, samplerate=%d\n", numsamples, samplerate); char albumperformer[256] = ""; -- cgit v1.2.3 From b75b72bdb1d273c522263310211d477b4676f16c Mon Sep 17 00:00:00 2001 From: waker Date: Fri, 24 Aug 2012 22:12:54 +0200 Subject: minor cuesheet code optimization --- playlist.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index 5b240e80..197a204e 100644 --- a/playlist.c +++ b/playlist.c @@ -1123,7 +1123,9 @@ plt_insert_cue_from_buffer (playlist_t *playlist, playItem_t *after, playItem_t } if (title[0]) { // handle last track - playItem_t *it = plt_process_cue_track (playlist, pl_find_meta_raw (origin, ":URI"), &prev, track, index00, index01, pregap, title, albumperformer, performer, albumtitle, genre, date, replaygain_album_gain, replaygain_album_peak, replaygain_track_gain, replaygain_track_peak, pl_find_meta_raw (origin, ":DECODER"), filetype, samplerate); + const char *uri = pl_find_meta_raw (origin, ":URI"); + const char *dec = pl_find_meta_raw (origin, ":DECODER"); + playItem_t *it = plt_process_cue_track (playlist, uri, &prev, track, index00, index01, pregap, title, albumperformer, performer, albumtitle, genre, date, replaygain_album_gain, replaygain_album_peak, replaygain_track_gain, replaygain_track_peak, dec, filetype, samplerate); if (it) { trace ("last track endsample: %d\n", numsamples-1); it->endsample = numsamples-1; -- cgit v1.2.3 From b1a86937e1de44242d556967a755d05de3c0a505 Mon Sep 17 00:00:00 2001 From: waker Date: Fri, 24 Aug 2012 23:46:45 +0200 Subject: minor cuesheet optimization --- playlist.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index 197a204e..c61aa271 100644 --- a/playlist.c +++ b/playlist.c @@ -1018,6 +1018,8 @@ plt_insert_cue_from_buffer (playlist_t *playlist, playItem_t *after, playItem_t char replaygain_album_peak[256] = ""; char replaygain_track_gain[256] = ""; char replaygain_track_peak[256] = ""; + const char *uri = pl_find_meta_raw (origin, ":URI"); + const char *dec = pl_find_meta_raw (origin, ":DECODER"); const char *filetype = pl_find_meta_raw (origin, ":FILETYPE"); playItem_t *cuetracks[MAX_CUE_TRACKS]; @@ -1072,10 +1074,10 @@ plt_insert_cue_from_buffer (playlist_t *playlist, playItem_t *after, playItem_t pl_get_value_from_cue (p + 9, sizeof (date), date); } else if (!strncmp (p, "TRACK ", 6)) { - trace ("cue: adding track: %s %s %s\n", pl_find_meta_raw (origin, ":URI"), title, track); + trace ("cue: adding track: %s %s %s\n", uri, title, track); if (title[0]) { // add previous track - playItem_t *it = plt_process_cue_track (playlist, pl_find_meta_raw (origin, ":URI"), &prev, track, index00, index01, pregap, title, albumperformer, performer, albumtitle, genre, date, replaygain_album_gain, replaygain_album_peak, replaygain_track_gain, replaygain_track_peak, pl_find_meta_raw (origin, ":DECODER"), filetype, samplerate); + playItem_t *it = plt_process_cue_track (playlist, uri, &prev, track, index00, index01, pregap, title, albumperformer, performer, albumtitle, genre, date, replaygain_album_gain, replaygain_album_peak, replaygain_track_gain, replaygain_track_peak, dec, filetype, samplerate); trace ("cue: added %p\n", it); if (it) { if (it->startsample >= numsamples || it->endsample >= numsamples) { @@ -1123,8 +1125,6 @@ plt_insert_cue_from_buffer (playlist_t *playlist, playItem_t *after, playItem_t } if (title[0]) { // handle last track - const char *uri = pl_find_meta_raw (origin, ":URI"); - const char *dec = pl_find_meta_raw (origin, ":DECODER"); playItem_t *it = plt_process_cue_track (playlist, uri, &prev, track, index00, index01, pregap, title, albumperformer, performer, albumtitle, genre, date, replaygain_album_gain, replaygain_album_peak, replaygain_track_gain, replaygain_track_peak, dec, filetype, samplerate); if (it) { trace ("last track endsample: %d\n", numsamples-1); -- cgit v1.2.3 From 7c0af6a8dae61cd5f394b7490bdc3b1dec47eed4 Mon Sep 17 00:00:00 2001 From: waker Date: Tue, 4 Sep 2012 20:39:43 +0200 Subject: a bit more tracing --- playlist.c | 1 + plugins/alac/alac_plugin.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index c61aa271..4ada1132 100644 --- a/playlist.c +++ b/playlist.c @@ -1335,6 +1335,7 @@ plt_insert_file (playlist_t *playlist, playItem_t *after, const char *fname, int if (cb && cb (inserted, user_data) < 0) { *pabort = 1; } + trace ("file has been added by decoder: %s\n", decoders[i]->plugin.id); return inserted; } } diff --git a/plugins/alac/alac_plugin.c b/plugins/alac/alac_plugin.c index 69da1007..25f45d1e 100644 --- a/plugins/alac/alac_plugin.c +++ b/plugins/alac/alac_plugin.c @@ -553,6 +553,7 @@ alacplug_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { qtmovie_free_demux (&demux_res); + trace ("duration %f\n", duration); if (duration > 0) { char s[100]; snprintf (s, sizeof (s), "%lld", fsize); @@ -590,6 +591,7 @@ alacplug_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { } } + trace ("success\n"); success: after = deadbeef->plt_insert_item (plt, after, it); deadbeef->pl_item_unref (it); -- cgit v1.2.3 From c02d39b2e57c06ead8453e9b2452936699d1e34c Mon Sep 17 00:00:00 2001 From: waker Date: Thu, 6 Sep 2012 20:11:41 +0200 Subject: show "" instead of "?" when the field is not found in metadata --- playlist.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index 4ada1132..27e50421 100644 --- a/playlist.c +++ b/playlist.c @@ -2795,7 +2795,7 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s, nm[l] = 0; meta = pl_find_meta_raw (it, nm); if (!meta) { - meta = "?"; + meta = ""; } fmt = e; } @@ -2827,11 +2827,11 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s, meta = dirname; } else { - meta = "?"; + meta = ""; } } else { - meta = "?"; + meta = ""; } } } -- cgit v1.2.3 From 716afd8d2d3a48a3bef3a22a89f7b911b55aea4c Mon Sep 17 00:00:00 2001 From: waker Date: Fri, 7 Sep 2012 21:13:56 +0200 Subject: added fwd-slash escaping support to title formatter using "%/" --- playlist.c | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index 27e50421..b2f536a2 100644 --- a/playlist.c +++ b/playlist.c @@ -2732,6 +2732,7 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s, char dirname[PATH_MAX]; const char *duration = NULL; const char *elapsed = NULL; + int escape_slash = 0; char *ss = s; @@ -2800,6 +2801,10 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s, fmt = e; } } + else if (*fmt == '/') { + // this means all '/' in the ongoing fields must be replaced with '\' + escape_slash = 1; + } else if (*fmt == 'a') { meta = pl_find_meta_raw (it, "artist"); if (!meta) { @@ -3054,22 +3059,21 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s, n--; while (n > 2 && *value) { const char *e = escape_chars; - for (; *e; e++) { - if (*value == *e) { - if (n < 2) { - // doesn't fit into output buffer, return - // empty string and error code - *ss = 0; - return -1; - } - *s++ = '\\'; - n--; - *s++ = *value++; - n--; - } - else { - *s++ = *value++; - } + if (strchr (escape_chars, *value)) { + *s++ = '\\'; + n--; + *s++ = *value++; + n--; + } + else if (escape_slash && *value == '/') { + *s++ = '\\'; + n--; + *s++ = '\\'; + n--; + break; + } + else { + *s++ = *value++; } } if (n < 1) { @@ -3082,8 +3086,15 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s, } else { while (n > 0 && *value) { - *s++ = *value++; - n--; + if (escape_slash && *value == '/') { + *s++ = '\\'; + n--; + value++; + } + else { + *s++ = *value++; + n--; + } } } } -- cgit v1.2.3 From 05ec171a0e812fa90dcee6aaa0dbcd0d9d409086 Mon Sep 17 00:00:00 2001 From: waker Date: Mon, 10 Sep 2012 20:53:44 +0200 Subject: cue: better trace message --- playlist.c | 1 + 1 file changed, 1 insertion(+) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index b2f536a2..6078e60f 100644 --- a/playlist.c +++ b/playlist.c @@ -1081,6 +1081,7 @@ plt_insert_cue_from_buffer (playlist_t *playlist, playItem_t *after, playItem_t trace ("cue: added %p\n", it); if (it) { if (it->startsample >= numsamples || it->endsample >= numsamples) { + trace ("cue: the track is shorter than cue timeline\n"); goto error; } cuetracks[ncuetracks++] = it; -- cgit v1.2.3 From 4329eb94c148cb7c0dca339172b3ed46c1641291 Mon Sep 17 00:00:00 2001 From: waker Date: Thu, 13 Sep 2012 18:39:40 +0200 Subject: fixed resuming in shuffle-albums mode --- main.c | 7 +++++++ playlist.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'playlist.c') diff --git a/main.c b/main.c index 228e3ecb..466126df 100644 --- a/main.c +++ b/main.c @@ -676,6 +676,13 @@ restore_resume_state (void) { streamer_lock (); // need to hold streamer thread to make the resume operation atomic streamer_set_current_playlist (plt); streamer_set_nextsong (track, paused ? 2 : 3); + if (pl_get_order () == PLAYBACK_ORDER_SHUFFLE_ALBUMS) { + playlist_t *p = plt_get_for_idx (plt); + if (p) { + plt_init_shuffle_albums (p, track); + plt_unref (p); + } + } streamer_set_seek (pos); streamer_unlock (); } diff --git a/playlist.c b/playlist.c index 6078e60f..cbcc1e03 100644 --- a/playlist.c +++ b/playlist.c @@ -3812,7 +3812,7 @@ pl_get_playlist (playItem_t *it) { return NULL; } -// this function must be called user starts track manually in shuffle albums mode +// this function must be called when the user starts track manually in shuffle albums mode // r is an index of current track // mark previous songs in the album as played void -- cgit v1.2.3 From 3aaf888bfd21412425d9dbf900a72f0e6ca26b89 Mon Sep 17 00:00:00 2001 From: waker Date: Mon, 1 Oct 2012 22:45:14 +0200 Subject: fixed bug in the shuffle albums mode, which would crash the player if a current track was paused, then deleted --- playlist.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'playlist.c') diff --git a/playlist.c b/playlist.c index cbcc1e03..d998ca8a 100644 --- a/playlist.c +++ b/playlist.c @@ -3819,6 +3819,10 @@ void plt_init_shuffle_albums (playlist_t *plt, int r) { pl_lock (); playItem_t *first = plt_get_item_for_idx (plt, r, PL_MAIN); + if (!first) { + pl_unlock (); + return; + } if (first->played) { plt_reshuffle (plt, NULL, NULL); } -- cgit v1.2.3