summaryrefslogtreecommitdiff
path: root/playlist.c
diff options
context:
space:
mode:
authorGravatar waker <wakeroid@gmail.com>2012-04-09 16:29:23 +0200
committerGravatar waker <wakeroid@gmail.com>2012-04-09 16:29:23 +0200
commit516f25073a726709abb83c3b73bd1e53404514c9 (patch)
tree68113731910c0df756717191a9cfaf55be514130 /playlist.c
parent6502057510696ea575a1cf0143dec02acb7cf01c (diff)
parent1ed51a80ec0979bc0be453f75548c59965fbd6f5 (diff)
Merge branch 'master' into devel
Conflicts: plugins/gtkui/callbacks.c plugins/gtkui/callbacks.h plugins/gtkui/gtkui.h
Diffstat (limited to 'playlist.c')
-rw-r--r--playlist.c474
1 files changed, 161 insertions, 313 deletions
diff --git a/playlist.c b/playlist.c
index b73d4ad3..ebc68ce5 100644
--- a/playlist.c
+++ b/playlist.c
@@ -1,6 +1,6 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
+ Copyright (C) 2009-2012 Alexey Yakovenko <waker@users.sourceforge.net>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1117,20 +1117,18 @@ plt_insert_cue_from_buffer (playlist_t *playlist, playItem_t *after, playItem_t
// fprintf (stderr, "got unknown line:\n%s\n", p);
}
}
- if (!title[0]) {
- UNLOCK;
- return NULL;
- }
- // 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);
- if (it) {
- trace ("last track endsample: %d\n", numsamples-1);
- it->endsample = numsamples-1;
- if (it->endsample >= numsamples || it->startsample >= numsamples) {
- goto error;
+ 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);
+ if (it) {
+ trace ("last track endsample: %d\n", numsamples-1);
+ it->endsample = numsamples-1;
+ if (it->endsample >= numsamples || it->startsample >= numsamples) {
+ goto error;
+ }
+ plt_set_item_duration (playlist, it, (float)(it->endsample - it->startsample + 1) / samplerate);
+ cuetracks[ncuetracks++] = it;
}
- plt_set_item_duration (playlist, it, (float)(it->endsample - it->startsample + 1) / samplerate);
- cuetracks[ncuetracks++] = it;
}
if (!ncuetracks) {
@@ -1161,6 +1159,7 @@ plt_insert_cue_from_buffer (playlist_t *playlist, playItem_t *after, playItem_t
UNLOCK;
return after;
error:
+ trace ("cue parsing error occured\n");
for (int i = 0; i < ncuetracks; i++) {
pl_item_unref (cuetracks[i]);
}
@@ -1206,265 +1205,6 @@ plt_insert_cue (playlist_t *plt, playItem_t *after, playItem_t *origin, int nums
return plt_insert_cue_from_buffer (plt, after, origin, buf, sz, numsamples, samplerate);
}
-#if 0
-playItem_t *
-plt_insert_m3u (playlist_t *plt, playItem_t *after, const char *fname, int *pabort, int (*cb)(playItem_t *it, void *data), void *user_data) {
- trace ("enter pl_insert_m3u\n");
- // skip all empty lines and comments
- DB_FILE *fp = vfs_fopen (fname);
- if (!fp) {
- trace ("failed to open file %s\n", fname);
- return NULL;
- }
- int sz = vfs_fgetlength (fp);
- if (sz > 1024*1024) {
- vfs_fclose (fp);
- trace ("file %s is too large to be a playlist\n", fname);
- return NULL;
- }
- trace ("loading m3u...\n");
- uint8_t buffer[sz];
- vfs_fread (buffer, 1, sz, fp);
- vfs_fclose (fp);
- const uint8_t *p = buffer;
- const uint8_t *end = buffer+sz;
- while (p < end) {
- p = pl_str_skipspaces (p, end);
- if (p >= end) {
- break;
- }
- if (*p == '#') {
- while (p < end && *p >= 0x20) {
- p++;
- }
- if (p >= end) {
- break;
- }
- continue;
- }
- const uint8_t *e = p;
- while (e < end && *e >= 0x20) {
- e++;
- }
- int n = e-p;
- uint8_t nm[n+1];
- memcpy (nm, p, n);
- nm[n] = 0;
- trace ("pl_insert_m3u: adding file %s\n", nm);
- playItem_t *it = plt_insert_file (plt, after, nm, pabort, cb, user_data);
- if (it) {
- after = it;
- }
- if (pabort && *pabort) {
- return after;
- }
- p = e;
- if (p >= end) {
- break;
- }
- }
- trace ("leave pl_insert_m3u\n");
- return after;
-}
-
-// that has to be opened with vfs functions to allow loading from http, as
-// referenced from M3U.
-static playItem_t *
-plt_insert_pls (playlist_t *playlist, playItem_t *after, const char *fname, int *pabort, int (*cb)(playItem_t *it, void *data), void *user_data) {
- DB_FILE *fp = vfs_fopen (fname);
- if (!fp) {
- trace ("failed to open file %s\n", fname);
- return NULL;
- }
- int sz = vfs_fgetlength (fp);
- if (sz > 1024*1024) {
- vfs_fclose (fp);
- trace ("file %s is too large to be a playlist\n", fname);
- return NULL;
- }
- if (sz < 10) {
- vfs_fclose (fp);
- trace ("file %s is too small to be a playlist (%d)\n", fname, sz);
- return NULL;
- }
- vfs_rewind (fp);
- uint8_t buffer[sz];
- vfs_fread (buffer, 1, sz, fp);
- vfs_fclose (fp);
- // 1st line must be "[playlist]"
- const uint8_t *p = buffer;
- const uint8_t *end = buffer+sz;
- if (strncasecmp (p, "[playlist]", 10)) {
- trace ("file %s doesn't begin with [playlist]\n", fname);
- return NULL;
- }
- p += 10;
- p = pl_str_skipspaces (p, end);
- if (p >= end) {
- trace ("file %s finished before numberofentries had been read\n", fname);
- return NULL;
- }
- // fetch all tracks
- char url[1024] = "";
- char title[1024] = "";
- char length[20] = "";
- int lastidx = -1;
- while (p < end) {
- p = pl_str_skipspaces (p, end);
- if (p >= end) {
- break;
- }
- if (end-p < 6) {
- break;
- }
- const uint8_t *e;
- int n;
- if (!strncasecmp (p, "numberofentries=", 16) || !strncasecmp (p, "version=", 8)) {
- while (p < end && *p >= 0x20) {
- p++;
- }
- continue;
- }
- else if (!strncasecmp (p, "file", 4)) {
- int idx = atoi (p + 4);
- if (url[0] && idx != lastidx && lastidx != -1) {
- // add track
- playItem_t *it = plt_insert_file (playlist, after, url, pabort, cb, user_data);
- if (it) {
- after = it;
- plt_set_item_duration (playlist, it, atoi (length));
- if (title[0]) {
- pl_delete_all_meta (it);
- pl_add_meta (it, "title", title);
- }
- }
- if (pabort && *pabort) {
- return after;
- }
- url[0] = 0;
- title[0] = 0;
- length[0] = 0;
- }
- lastidx = idx;
- p += 4;
- while (p < end && *p != '=') {
- p++;
- }
- p++;
- if (p >= end) {
- break;
- }
- e = p;
- while (e < end && *e >= 0x20) {
- e++;
- }
- n = e-p;
- n = min (n, sizeof (url)-1);
- memcpy (url, p, n);
- url[n] = 0;
- trace ("url: %s\n", url);
- p = ++e;
- }
- else if (!strncasecmp (p, "title", 5)) {
- int idx = atoi (p + 5);
- if (url[0] && idx != lastidx && lastidx != -1) {
- // add track
- playItem_t *it = plt_insert_file (playlist, after, url, pabort, cb, user_data);
- if (it) {
- after = it;
- plt_set_item_duration (playlist, it, atoi (length));
- if (title[0]) {
- pl_delete_all_meta (it);
- pl_add_meta (it, "title", title);
- }
- }
- if (pabort && *pabort) {
- return after;
- }
- url[0] = 0;
- title[0] = 0;
- length[0] = 0;
- }
- lastidx = idx;
- p += 5;
- while (p < end && *p != '=') {
- p++;
- }
- p++;
- if (p >= end) {
- break;
- }
- e = p;
- while (e < end && *e >= 0x20) {
- e++;
- }
- n = e-p;
- n = min (n, sizeof (title)-1);
- memcpy (title, p, n);
- title[n] = 0;
- trace ("title: %s\n", title);
- p = ++e;
- }
- else if (!strncasecmp (p, "length", 6)) {
- int idx = atoi (p + 6);
- if (url[0] && idx != lastidx && lastidx != -1) {
- // add track
- playItem_t *it = plt_insert_file (playlist, after, url, pabort, cb, user_data);
- if (it) {
- after = it;
- if (title[0]) {
- pl_delete_all_meta (it);
- pl_add_meta (it, "title", title);
- }
- }
- if (pabort && *pabort) {
- return after;
- }
- url[0] = 0;
- title[0] = 0;
- length[0] = 0;
- }
- lastidx = idx;
- p += 6;
- // skip =
- while (p < end && *p != '=') {
- p++;
- }
- p++;
- if (p >= end) {
- break;
- }
- e = p;
- while (e < end && *e >= 0x20) {
- e++;
- }
- n = e-p;
- n = min (n, sizeof (length)-1);
- memcpy (length, p, n);
- }
- else {
- trace ("invalid entry in pls file: %s\n", p);
- break;
- }
- while (e < end && *e < 0x20) {
- e++;
- }
- p = e;
- }
- if (url[0]) {
- playItem_t *it = plt_insert_file (playlist, after, url, pabort, cb, user_data);
- if (it) {
- after = it;
- if (title[0]) {
- pl_delete_all_meta (it);
- pl_add_meta (it, "title", title);
- }
- }
- }
- return after;
-}
-#endif
-
static int follow_symlinks = 0;
static int ignore_archives = 0;
@@ -1496,13 +1236,6 @@ plt_insert_file (playlist_t *playlist, playItem_t *after, const char *fname, int
}
}
- // detect decoder
- const char *eol = strrchr (fname, '.');
- if (!eol) {
- return NULL;
- }
- eol++;
-
const char *fn = strrchr (fname, '/');
if (!fn) {
fn = fname;
@@ -1510,19 +1243,6 @@ plt_insert_file (playlist_t *playlist, playItem_t *after, const char *fname, int
else {
fn++;
}
-#if 0
- // detect pls/m3u files
- // they must be handled before checking for http://,
- // so that remote playlist files referenced from other playlist files could
- // be loaded correctly
- if (!strncmp (eol, "m3u", 3) || !strncmp (eol, "m3u8", 4)) {
- return plt_insert_m3u (playlist, after, fname, pabort, cb, user_data);
- }
- else if (!strncmp (eol, "pls", 3)) {
-
- return plt_insert_pls (playlist, after, fname, pabort, cb, user_data);
- }
-#endif
// add all posible streams as special-case:
// set decoder to NULL, and filetype to "content"
@@ -1587,6 +1307,13 @@ plt_insert_file (playlist_t *playlist, playItem_t *after, const char *fname, int
fname += 7;
}
+ // detect decoder
+ const char *eol = strrchr (fname, '.');
+ if (!eol) {
+ return NULL;
+ }
+ eol++;
+
DB_decoder_t **decoders = plug_get_decoder_list ();
// match by decoder
for (int i = 0; decoders[i]; i++) {
@@ -1674,6 +1401,10 @@ plt_insert_dir_int (playlist_t *playlist, DB_vfs_t *vfs, playItem_t *after, cons
}
else {
inserted = plt_insert_file (playlist, after, namelist[i]->d_name, pabort, cb, user_data);
+ if (!inserted) {
+ // special case for loading playlists in zip files
+ inserted = plt_load (playlist, after, namelist[i]->d_name, pabort, cb, user_data);
+ }
}
if (inserted) {
after = inserted;
@@ -1925,7 +1656,24 @@ plt_insert_item (playlist_t *playlist, playItem_t *after, playItem_t *it) {
// shuffle
playItem_t *prev = it->prev[PL_MAIN];
- if (pl_order == PLAYBACK_ORDER_SHUFFLE_ALBUMS && prev && pl_find_meta_raw (prev, "album") == pl_find_meta_raw (it, "album") && pl_find_meta_raw (prev, "artist") == pl_find_meta_raw (it, "artist")) {
+ const char *aa = NULL, *prev_aa = NULL;
+ if (prev) {
+ aa = pl_find_meta_raw (it, "band");
+ if (!aa) {
+ aa = pl_find_meta_raw (it, "album artist");
+ }
+ if (!aa) {
+ aa = pl_find_meta_raw (it, "albumartist");
+ }
+ prev_aa = pl_find_meta_raw (prev, "band");
+ if (!prev_aa) {
+ prev_aa = pl_find_meta_raw (prev, "album artist");
+ }
+ if (!prev_aa) {
+ prev_aa = pl_find_meta_raw (prev, "albumartist");
+ }
+ }
+ if (pl_order == PLAYBACK_ORDER_SHUFFLE_ALBUMS && prev && pl_find_meta_raw (prev, "album") == pl_find_meta_raw (it, "album") && ((aa && prev_aa && aa == prev_aa) || pl_find_meta_raw (prev, "artist") == pl_find_meta_raw (it, "artist"))) {
it->shufflerating = prev->shufflerating;
}
else {
@@ -2067,8 +1815,9 @@ plt_delete_selected (playlist_t *playlist) {
int
pl_delete_selected (void) {
LOCK;
- plt_delete_selected (playlist);
+ int ret = plt_delete_selected (playlist);
UNLOCK;
+ return ret;
}
void
@@ -2362,15 +2111,10 @@ pl_save_all (void) {
playItem_t *
plt_load (playlist_t *plt, playItem_t *after, const char *fname, int *pabort, int (*cb)(playItem_t *it, void *data), void *user_data) {
- FILE *fp = fopen (fname, "rb");
- if (!fp) {
- trace ("plt_load: failed to open %s\n", fname);
- return NULL;
- }
-
// try plugins 1st
const char *ext = strrchr (fname, '.');
if (ext) {
+ trace ("finding playlist plugin for %s\n", ext);
ext++;
DB_playlist_t **plug = plug_get_playlist_list ();
int p, e;
@@ -2384,6 +2128,12 @@ plt_load (playlist_t *plt, playItem_t *after, const char *fname, int *pabort, in
}
}
trace ("plt_load: loading dbpl\n");
+ FILE *fp = fopen (fname, "rb");
+ if (!fp) {
+ trace ("plt_load: failed to open %s\n", fname);
+ return NULL;
+ }
+
uint8_t majorver;
uint8_t minorver;
@@ -2643,7 +2393,6 @@ pl_load_all (void) {
char path[1024];
DB_conf_item_t *it = conf_find ("playlist.tab.", NULL);
if (!it) {
-// fprintf (stderr, "INFO: loading legacy default playlist\n");
// legacy (0.3.3 and earlier)
char defpl[1024]; // $HOME/.config/deadbeef/default.dbpl
if (snprintf (defpl, sizeof (defpl), "%s/default.dbpl", dbconfdir) > sizeof (defpl)) {
@@ -2730,8 +2479,17 @@ plt_reshuffle (playlist_t *playlist, playItem_t **ppmin, playItem_t **ppmax) {
playItem_t *prev = NULL;
const char *alb = NULL;
const char *art = NULL;
+ const char *aa = NULL;
for (playItem_t *it = playlist->head[PL_MAIN]; it; it = it->next[PL_MAIN]) {
- if (pl_order == PLAYBACK_ORDER_SHUFFLE_ALBUMS && prev && alb == pl_find_meta_raw (it, "album") && art == pl_find_meta_raw (it, "artist")) {
+ const char *new_aa = NULL;
+ new_aa = pl_find_meta_raw (it, "band");
+ if (!new_aa) {
+ new_aa = pl_find_meta_raw (it, "album artist");
+ }
+ if (!new_aa) {
+ new_aa = pl_find_meta_raw (it, "albumartist");
+ }
+ if (pl_order == PLAYBACK_ORDER_SHUFFLE_ALBUMS && prev && alb == pl_find_meta_raw (it, "album") && ((aa && new_aa && aa == new_aa) || art == pl_find_meta_raw (it, "artist"))) {
it->shufflerating = prev->shufflerating;
}
else {
@@ -2739,6 +2497,7 @@ plt_reshuffle (playlist_t *playlist, playItem_t **ppmin, playItem_t **ppmax) {
it->shufflerating = rand ();
alb = pl_find_meta_raw (it, "album");
art = pl_find_meta_raw (it, "artist");
+ aa = new_aa;
}
if (!pmin || it->shufflerating < pmin->shufflerating) {
pmin = it;
@@ -2822,6 +2581,7 @@ pl_get_item_replaygain (playItem_t *it, int idx) {
case DDB_REPLAYGAIN_TRACKPEAK:
return pl_find_meta_float (it, rg_keys[idx], 1);
}
+ return 0;
}
int
@@ -2951,9 +2711,7 @@ pl_format_elapsed (const char *ret, char *elapsed, int size) {
// @escape_chars: list of escapable characters terminated with 0, or NULL if none
static int
pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s, int size, int id, const char *fmt) {
- char dur[50];
- char elp[50];
- char fno[50];
+ char tmp[50];
char tags[200];
char dirname[PATH_MAX];
const char *duration = NULL;
@@ -2969,8 +2727,8 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s,
if (idx == -1) {
idx = pl_get_idx_of (it);
}
- snprintf (fno, sizeof (fno), "%d", idx+1);
- text = fno;
+ snprintf (tmp, sizeof (tmp), "%d", idx+1);
+ text = tmp;
break;
case DB_COLUMN_PLAYING:
UNLOCK;
@@ -3094,8 +2852,8 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s,
p++;
}
if (!(*p)) {
- snprintf (fno, sizeof (fno), "%02d", atoi (meta));
- meta = fno;
+ snprintf (tmp, sizeof (tmp), "%02d", atoi (meta));
+ meta = tmp;
}
}
}
@@ -3115,7 +2873,7 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s,
meta = pl_find_meta_raw (it, "copyright");
}
else if (*fmt == 'l') {
- const char *value = (duration = pl_format_duration (it, duration, dur, sizeof (dur)));
+ const char *value = (duration = pl_format_duration (it, duration, tmp, sizeof (tmp)));
while (n > 0 && *value) {
*s++ = *value++;
n--;
@@ -3123,7 +2881,7 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s,
}
else if (*fmt == 'e') {
// what a hack..
- const char *value = (elapsed = pl_format_elapsed (elapsed, elp, sizeof (elp)));
+ const char *value = (elapsed = pl_format_elapsed (elapsed, tmp, sizeof (tmp)));
while (n > 0 && *value) {
*s++ = *value++;
n--;
@@ -3227,6 +2985,36 @@ pl_format_title_int (const char *escape_chars, playItem_t *it, int idx, char *s,
meta = dirname;
}
}
+ else if (*fmt == 'L') {
+ float l = 0;
+ for (playItem_t *it = playlist->head[PL_MAIN]; it; it = it->next[PL_MAIN]) {
+ if (it->selected) {
+ l += it->_duration;
+ }
+ }
+ pl_format_time (l, tmp, sizeof(tmp));
+ meta = tmp;
+ }
+ else if (*fmt == 'X') {
+ int n = 0;
+ for (playItem_t *it = playlist->head[PL_MAIN]; it; it = it->next[PL_MAIN]) {
+ if (it->selected) {
+ n++;
+ }
+ }
+ snprintf (tmp, sizeof (tmp), "%d", n);
+ meta = tmp;
+ }
+ else if (*fmt == 'Z') {
+ DB_fileinfo_t *c = deadbeef->streamer_get_current_fileinfo (); // FIXME: might crash streamer
+ if (c->fmt.channels <= 2) {
+ meta = c->fmt.channels == 1 ? _("Mono") : _("Stereo");
+ }
+ else {
+ snprintf (tmp, sizeof (tmp), "%dch Multichannel", c->fmt.channels);
+ meta = tmp;
+ }
+ }
else if (*fmt == 'V') {
meta = VERSION;
}
@@ -3386,7 +3174,13 @@ qsort_cmp_func (const void *a, const void *b) {
}
void
-plt_sort (playlist_t *playlist, int iter, int id, const char *format, int ascending) {
+plt_sort (playlist_t *playlist, int iter, int id, const char *format, int order) {
+ if (order == DDB_SORT_RANDOM) {
+ plt_sort_random (playlist, iter);
+ return;
+ }
+ int ascending = order == DDB_SORT_DESCENDING ? 0 : 1;
+
if (id == DB_COLUMN_FILENUMBER || !playlist->head[iter] || !playlist->head[iter]->next[iter]) {
return;
}
@@ -3446,6 +3240,56 @@ plt_sort (playlist_t *playlist, int iter, int id, const char *format, int ascend
}
void
+plt_sort_random (playlist_t *playlist, int iter) {
+ if (!playlist->head[iter] || !playlist->head[iter]->next[iter]) {
+ return;
+ }
+
+ LOCK;
+
+ const int playlist_count = playlist->count[iter];
+ playItem_t **array = malloc (playlist_count * sizeof (playItem_t *));
+ int idx = 0;
+ for (playItem_t *it = playlist->head[iter]; it; it = it->next[iter], idx++) {
+ array[idx] = it;
+ }
+
+ //randomize array
+ for (int swap_a = 0; swap_a < playlist_count - 1; swap_a++) {
+ //select random item above swap_a-1
+ const int swap_b = swap_a + (rand() / (float)RAND_MAX * (playlist_count - swap_a));
+
+ //swap a with b
+ playItem_t* const swap_temp = array[swap_a];
+ array[swap_a] = array[swap_b];
+ array[swap_b] = swap_temp;
+
+ }
+
+ playItem_t *prev = NULL;
+ playlist->head[iter] = 0;
+ for (idx = 0; idx < playlist->count[iter]; idx++) {
+ playItem_t *it = array[idx];
+ it->prev[iter] = prev;
+ it->next[iter] = NULL;
+ if (!prev) {
+ playlist->head[iter] = it;
+ }
+ else {
+ prev->next[iter] = it;
+ }
+ prev = it;
+ }
+ playlist->tail[iter] = array[playlist->count[iter]-1];
+
+ free (array);
+
+ plt_modified (playlist);
+
+ UNLOCK;
+}
+
+void
plt_reset_cursor (playlist_t *playlist) {
int i;
LOCK;
@@ -3457,6 +3301,9 @@ plt_reset_cursor (playlist_t *playlist) {
float
plt_get_totaltime (playlist_t *playlist) {
+ if (!playlist) {
+ return 0;
+ }
return playlist->totaltime;
}
@@ -3784,6 +3631,7 @@ pl_playqueue_clear (void) {
}
for (i = 0; i < cnt; i++) {
pl_item_unref (playqueue[i]);
+ playqueue[i] = NULL;
}
UNLOCK;
}