Merge branch 'v0.17.x'
Conflicts: src/queue_save.c
This commit is contained in:
commit
def21cc87e
4
NEWS
4
NEWS
@ -12,10 +12,14 @@ ver 0.17.2 (2012/??/??)
|
|||||||
* output:
|
* output:
|
||||||
- httpd: use monotonic clock, avoid hiccups after system clock adjustment
|
- httpd: use monotonic clock, avoid hiccups after system clock adjustment
|
||||||
- httpd: fix throttling bug after resuming playback
|
- httpd: fix throttling bug after resuming playback
|
||||||
|
* playlist:
|
||||||
|
- cue: map "PERFORMER" to "artist" or "album artist"
|
||||||
* mapper: fix non-UTF8 music directory name
|
* mapper: fix non-UTF8 music directory name
|
||||||
* mapper: fix potential crash in file permission check
|
* mapper: fix potential crash in file permission check
|
||||||
* playlist: fix use-after-free bug
|
* playlist: fix use-after-free bug
|
||||||
* playlist: fix memory leak
|
* playlist: fix memory leak
|
||||||
|
* state_file: save song priorities
|
||||||
|
* player: disable cross-fading in "single" mode
|
||||||
|
|
||||||
|
|
||||||
ver 0.17.1 (2012/07/31)
|
ver 0.17.1 (2012/07/31)
|
||||||
|
@ -788,7 +788,7 @@ handle_next(G_GNUC_UNUSED struct client *client,
|
|||||||
{
|
{
|
||||||
/* single mode is not considered when this is user who
|
/* single mode is not considered when this is user who
|
||||||
* wants to change song. */
|
* wants to change song. */
|
||||||
int single = g_playlist.queue.single;
|
const bool single = g_playlist.queue.single;
|
||||||
g_playlist.queue.single = false;
|
g_playlist.queue.single = false;
|
||||||
|
|
||||||
playlist_next(&g_playlist, client->player_control);
|
playlist_next(&g_playlist, client->player_control);
|
||||||
|
@ -216,9 +216,19 @@ cue_parser_feed2(struct cue_parser *parser, char *p)
|
|||||||
if (tag != NULL)
|
if (tag != NULL)
|
||||||
cue_parse_rem(p, tag);
|
cue_parse_rem(p, tag);
|
||||||
} else if (strcmp(command, "PERFORMER") == 0) {
|
} else if (strcmp(command, "PERFORMER") == 0) {
|
||||||
|
/* MPD knows a "performer" tag, but it is not a good
|
||||||
|
match for this CUE tag; from the Hydrogenaudio
|
||||||
|
Knowledgebase: "At top-level this will specify the
|
||||||
|
CD artist, while at track-level it specifies the
|
||||||
|
track artist." */
|
||||||
|
|
||||||
|
enum tag_type type = parser->state == TRACK
|
||||||
|
? TAG_ARTIST
|
||||||
|
: TAG_ALBUM_ARTIST;
|
||||||
|
|
||||||
struct tag *tag = cue_current_tag(parser);
|
struct tag *tag = cue_current_tag(parser);
|
||||||
if (tag != NULL)
|
if (tag != NULL)
|
||||||
cue_add_tag(tag, TAG_PERFORMER, p);
|
cue_add_tag(tag, type, p);
|
||||||
} else if (strcmp(command, "TITLE") == 0) {
|
} else if (strcmp(command, "TITLE") == 0) {
|
||||||
if (parser->state == HEADER)
|
if (parser->state == HEADER)
|
||||||
cue_add_tag(parser->tag, TAG_ALBUM, p);
|
cue_add_tag(parser->tag, TAG_ALBUM, p);
|
||||||
|
@ -204,6 +204,14 @@ pc_set_pause(struct player_control *pc, bool pause_flag)
|
|||||||
player_unlock(pc);
|
player_unlock(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pc_set_border_pause(struct player_control *pc, bool border_pause)
|
||||||
|
{
|
||||||
|
player_lock(pc);
|
||||||
|
pc->border_pause = border_pause;
|
||||||
|
player_unlock(pc);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_get_status(struct player_control *pc, struct player_status *status)
|
pc_get_status(struct player_control *pc, struct player_status *status)
|
||||||
{
|
{
|
||||||
|
@ -137,6 +137,15 @@ struct player_control {
|
|||||||
float mixramp_db;
|
float mixramp_db;
|
||||||
float mixramp_delay_seconds;
|
float mixramp_delay_seconds;
|
||||||
double total_play_time;
|
double total_play_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this flag is set, then the player will be auto-paused at
|
||||||
|
* the end of the song, before the next song starts to play.
|
||||||
|
*
|
||||||
|
* This is a copy of the queue's "single" flag most of the
|
||||||
|
* time.
|
||||||
|
*/
|
||||||
|
bool border_pause;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct player_control *
|
struct player_control *
|
||||||
@ -225,6 +234,12 @@ pc_set_pause(struct player_control *pc, bool pause_flag);
|
|||||||
void
|
void
|
||||||
pc_pause(struct player_control *pc);
|
pc_pause(struct player_control *pc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the player's #border_pause flag.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pc_set_border_pause(struct player_control *pc, bool border_pause);
|
||||||
|
|
||||||
void
|
void
|
||||||
pc_kill(struct player_control *pc);
|
pc_kill(struct player_control *pc);
|
||||||
|
|
||||||
|
@ -862,6 +862,16 @@ player_song_border(struct player *player)
|
|||||||
if (!player_wait_for_decoder(player))
|
if (!player_wait_for_decoder(player))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
struct player_control *const pc = player->pc;
|
||||||
|
player_lock(pc);
|
||||||
|
|
||||||
|
if (pc->border_pause) {
|
||||||
|
player->paused = true;
|
||||||
|
pc->state = PLAYER_STATE_PAUSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
player_unlock(pc);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -979,7 +989,10 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
|||||||
player_dc_start(&player, music_pipe_new());
|
player_dc_start(&player, music_pipe_new());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player_dc_at_next_song(&player) &&
|
if (/* no cross-fading if MPD is going to pause at the
|
||||||
|
end of the current song */
|
||||||
|
!pc->border_pause &&
|
||||||
|
player_dc_at_next_song(&player) &&
|
||||||
player.xfade == XFADE_UNKNOWN &&
|
player.xfade == XFADE_UNKNOWN &&
|
||||||
!decoder_lock_is_starting(dc)) {
|
!decoder_lock_is_starting(dc)) {
|
||||||
/* enable cross fading in this song? if yes,
|
/* enable cross fading in this song? if yes,
|
||||||
|
@ -110,11 +110,6 @@ playlist_song_started(struct playlist *playlist, struct player_control *pc)
|
|||||||
playlist->current = playlist->queued;
|
playlist->current = playlist->queued;
|
||||||
playlist->queued = -1;
|
playlist->queued = -1;
|
||||||
|
|
||||||
/* Pause if we are in single mode. */
|
|
||||||
if(playlist->queue.single && !playlist->queue.repeat) {
|
|
||||||
pc_set_pause(pc, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(playlist->queue.consume)
|
if(playlist->queue.consume)
|
||||||
playlist_delete(playlist, pc,
|
playlist_delete(playlist, pc,
|
||||||
queue_order_to_position(&playlist->queue,
|
queue_order_to_position(&playlist->queue,
|
||||||
@ -311,7 +306,11 @@ playlist_set_repeat(struct playlist *playlist, struct player_control *pc,
|
|||||||
if (status == playlist->queue.repeat)
|
if (status == playlist->queue.repeat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
playlist->queue.repeat = status;
|
struct queue *queue = &playlist->queue;
|
||||||
|
|
||||||
|
queue->repeat = status;
|
||||||
|
|
||||||
|
pc_set_border_pause(pc, queue->single && !queue->repeat);
|
||||||
|
|
||||||
/* if the last song is currently being played, the "next song"
|
/* if the last song is currently being played, the "next song"
|
||||||
might change when repeat mode is toggled */
|
might change when repeat mode is toggled */
|
||||||
@ -339,7 +338,11 @@ playlist_set_single(struct playlist *playlist, struct player_control *pc,
|
|||||||
if (status == playlist->queue.single)
|
if (status == playlist->queue.single)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
playlist->queue.single = status;
|
struct queue *queue = &playlist->queue;
|
||||||
|
|
||||||
|
queue->single = status;
|
||||||
|
|
||||||
|
pc_set_border_pause(pc, queue->single && !queue->repeat);
|
||||||
|
|
||||||
/* if the last song is currently being played, the "next song"
|
/* if the last song is currently being played, the "next song"
|
||||||
might change when single mode is toggled */
|
might change when single mode is toggled */
|
||||||
|
@ -75,7 +75,7 @@ playlist_append_song(struct playlist *playlist, struct player_control *pc,
|
|||||||
|
|
||||||
queued = playlist_get_queued_song(playlist);
|
queued = playlist_get_queued_song(playlist);
|
||||||
|
|
||||||
id = queue_append(&playlist->queue, song);
|
id = queue_append(&playlist->queue, song, 0);
|
||||||
|
|
||||||
if (playlist->queue.random) {
|
if (playlist->queue.random) {
|
||||||
/* shuffle the new song into the list of remaining
|
/* shuffle the new song into the list of remaining
|
||||||
|
@ -96,7 +96,7 @@ queue_modify_all(struct queue *queue)
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
queue_append(struct queue *queue, struct song *song)
|
queue_append(struct queue *queue, struct song *song, uint8_t priority)
|
||||||
{
|
{
|
||||||
unsigned id = queue_generate_id(queue);
|
unsigned id = queue_generate_id(queue);
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ queue_append(struct queue *queue, struct song *song)
|
|||||||
.song = song_dup_detached(song),
|
.song = song_dup_detached(song),
|
||||||
.id = id,
|
.id = id,
|
||||||
.version = queue->version,
|
.version = queue->version,
|
||||||
.priority = 0,
|
.priority = priority,
|
||||||
};
|
};
|
||||||
|
|
||||||
queue->order[queue->length] = queue->length;
|
queue->order[queue->length] = queue->length;
|
||||||
|
@ -280,9 +280,11 @@ queue_modify_all(struct queue *queue);
|
|||||||
*
|
*
|
||||||
* If a song is not in the database (determined by
|
* If a song is not in the database (determined by
|
||||||
* song_in_database()), it is freed when removed from the queue.
|
* song_in_database()), it is freed when removed from the queue.
|
||||||
|
*
|
||||||
|
* @param priority the priority of this new queue item
|
||||||
*/
|
*/
|
||||||
unsigned
|
unsigned
|
||||||
queue_append(struct queue *queue, struct song *song);
|
queue_append(struct queue *queue, struct song *song, uint8_t priority);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Swaps two songs, addressed by their position.
|
* Swaps two songs, addressed by their position.
|
||||||
|
@ -24,9 +24,12 @@
|
|||||||
#include "uri.h"
|
#include "uri.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
#include "song_save.h"
|
#include "song_save.h"
|
||||||
|
#include "text_file.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define PRIO_LABEL "Prio: "
|
||||||
|
|
||||||
static void
|
static void
|
||||||
queue_save_database_song(FILE *fp, int idx, const struct song *song)
|
queue_save_database_song(FILE *fp, int idx, const struct song *song)
|
||||||
{
|
{
|
||||||
@ -54,8 +57,13 @@ queue_save_song(FILE *fp, int idx, const struct song *song)
|
|||||||
void
|
void
|
||||||
queue_save(FILE *fp, const struct queue *queue)
|
queue_save(FILE *fp, const struct queue *queue)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < queue_length(queue); i++)
|
for (unsigned i = 0; i < queue_length(queue); i++) {
|
||||||
|
uint8_t prio = queue_get_priority_at_position(queue, i);
|
||||||
|
if (prio != 0)
|
||||||
|
fprintf(fp, PRIO_LABEL "%u\n", prio);
|
||||||
|
|
||||||
queue_save_song(fp, i, queue_get(queue, i));
|
queue_save_song(fp, i, queue_get(queue, i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct song *
|
static struct song *
|
||||||
@ -75,6 +83,15 @@ queue_load_song(FILE *fp, GString *buffer, const char *line,
|
|||||||
if (queue_is_full(queue))
|
if (queue_is_full(queue))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
uint8_t priority = 0;
|
||||||
|
if (g_str_has_prefix(line, PRIO_LABEL)) {
|
||||||
|
priority = strtoul(line + sizeof(PRIO_LABEL) - 1, NULL, 10);
|
||||||
|
|
||||||
|
line = read_text_line(fp, buffer);
|
||||||
|
if (line == NULL)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (g_str_has_prefix(line, SONG_BEGIN)) {
|
if (g_str_has_prefix(line, SONG_BEGIN)) {
|
||||||
const char *uri = line + sizeof(SONG_BEGIN) - 1;
|
const char *uri = line + sizeof(SONG_BEGIN) - 1;
|
||||||
if (!uri_has_scheme(uri) && !g_path_is_absolute(uri))
|
if (!uri_has_scheme(uri) && !g_path_is_absolute(uri))
|
||||||
@ -102,7 +119,7 @@ queue_load_song(FILE *fp, GString *buffer, const char *line,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_append(queue, song);
|
queue_append(queue, song, priority);
|
||||||
|
|
||||||
if (song_in_database(song))
|
if (song_in_database(song))
|
||||||
db_return_song(song);
|
db_return_song(song);
|
||||||
|
@ -56,7 +56,7 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
|
|||||||
queue_init(&queue, 32);
|
queue_init(&queue, 32);
|
||||||
|
|
||||||
for (unsigned i = 0; i < G_N_ELEMENTS(songs); ++i)
|
for (unsigned i = 0; i < G_N_ELEMENTS(songs); ++i)
|
||||||
queue_append(&queue, &songs[i]);
|
queue_append(&queue, &songs[i], 0);
|
||||||
|
|
||||||
assert(queue_length(&queue) == G_N_ELEMENTS(songs));
|
assert(queue_length(&queue) == G_N_ELEMENTS(songs));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user