mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-26 14:13:18 -05:00
Use queue db table instead of in memory queue struct
This commit is contained in:
parent
8ebf2f9307
commit
c504abe451
25
src/db.c
25
src/db.c
@ -2022,6 +2022,31 @@ db_files_get_count_bymatch(char *path)
|
||||
#undef Q_TMPL
|
||||
}
|
||||
|
||||
int
|
||||
db_file_get_seekpos(uint32_t id)
|
||||
{
|
||||
#define Q_TMPL "SELECT seek FROM files f WHERE f.id = %d;"
|
||||
char *query;
|
||||
int seek_ms;
|
||||
|
||||
query = sqlite3_mprintf(Q_TMPL, id);
|
||||
if (!query)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory making seekpos query string.\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
seek_ms = db_get_count(query);
|
||||
sqlite3_free(query);
|
||||
|
||||
if (seek_ms < 0)
|
||||
seek_ms = 0;
|
||||
|
||||
return seek_ms;
|
||||
#undef Q_TMPL
|
||||
}
|
||||
|
||||
void
|
||||
db_files_update_songartistid(void)
|
||||
{
|
||||
|
3
src/db.h
3
src/db.h
@ -507,6 +507,9 @@ db_files_get_album_count(void);
|
||||
int
|
||||
db_files_get_count_bymatch(char *path);
|
||||
|
||||
int
|
||||
db_file_get_seekpos(uint32_t id);
|
||||
|
||||
void
|
||||
db_files_update_songartistid(void);
|
||||
|
||||
|
@ -1227,6 +1227,7 @@ bulk_scan(int flags)
|
||||
|
||||
DPRINTF(E_DBG, L_SCAN, "Purging old database content\n");
|
||||
db_purge_cruft(start);
|
||||
db_queue_cleanup();
|
||||
cache_artwork_purge_cruft(start);
|
||||
|
||||
DPRINTF(E_LOG, L_SCAN, "Bulk library scan completed in %.f sec\n", difftime(end, start));
|
||||
@ -1244,6 +1245,7 @@ bulk_scan(int flags)
|
||||
static void *
|
||||
filescanner(void *arg)
|
||||
{
|
||||
int clear_queue_on_stop_disabled;
|
||||
int ret;
|
||||
#if defined(__linux__)
|
||||
struct sched_param param;
|
||||
@ -1284,6 +1286,19 @@ filescanner(void *arg)
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
// Only clear the queue if enabled (default) in config
|
||||
clear_queue_on_stop_disabled = cfg_getbool(cfg_getsec(cfg, "mpd"), "clear_queue_on_stop_disable");
|
||||
if (!clear_queue_on_stop_disabled)
|
||||
{
|
||||
ret = db_queue_clear();
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Error: could not clear queue from DB\n");
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Recompute all songartistids and songalbumids, in case the SQLite DB got transferred
|
||||
* to a different host; the hash is not portable.
|
||||
* It will also rebuild the groups we just cleared.
|
||||
@ -1937,7 +1952,7 @@ filescanner_fullrescan(void *arg, int *retval)
|
||||
DPRINTF(E_LOG, L_SCAN, "Full rescan triggered\n");
|
||||
|
||||
player_playback_stop();
|
||||
player_queue_clear();
|
||||
db_queue_clear();
|
||||
inofd_event_unset(); // Clears all inotify watches
|
||||
db_purge_all(); // Clears files, playlists, playlistitems, inotify and groups
|
||||
|
||||
|
472
src/httpd_dacp.c
472
src/httpd_dacp.c
@ -51,7 +51,6 @@
|
||||
#include "db.h"
|
||||
#include "daap_query.h"
|
||||
#include "player.h"
|
||||
#include "queue.h"
|
||||
#include "listener.h"
|
||||
|
||||
/* httpd event base, from httpd.c */
|
||||
@ -76,7 +75,7 @@ struct dacp_update_request {
|
||||
struct dacp_update_request *next;
|
||||
};
|
||||
|
||||
typedef void (*dacp_propget)(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
typedef void (*dacp_propget)(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
typedef void (*dacp_propset)(const char *value, struct evkeyvalq *query);
|
||||
|
||||
struct dacp_prop_map {
|
||||
@ -88,40 +87,40 @@ struct dacp_prop_map {
|
||||
|
||||
/* Forward - properties getters */
|
||||
static void
|
||||
dacp_propget_volume(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_volume(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_volumecontrollable(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_volumecontrollable(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_playerstate(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_playerstate(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_shufflestate(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_shufflestate(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_availableshufflestates(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_availableshufflestates(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_repeatstate(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_repeatstate(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_availablerepeatstates(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_availablerepeatstates(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_nowplaying(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_nowplaying(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_playingtime(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_playingtime(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
|
||||
static void
|
||||
dacp_propget_fullscreenenabled(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_fullscreenenabled(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_fullscreen(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_fullscreen(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_visualizerenabled(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_visualizerenabled(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_visualizer(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_visualizer(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_itms_songid(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_itms_songid(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_haschapterdata(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_haschapterdata(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_mediakind(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_mediakind(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
static void
|
||||
dacp_propget_extendedmediakind(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi);
|
||||
dacp_propget_extendedmediakind(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item);
|
||||
|
||||
/* Forward - properties setters */
|
||||
static void
|
||||
@ -165,16 +164,25 @@ static struct media_file_info dummy_mfi =
|
||||
.album = "(unknown album)",
|
||||
.genre = "(unknown genre)",
|
||||
};
|
||||
static struct db_queue_item dummy_queue_item =
|
||||
{
|
||||
.file_id = 9999999,
|
||||
.title = "(unknown title)",
|
||||
.artist = "(unknown artist)",
|
||||
.album = "(unknown album)",
|
||||
.genre = "(unknown genre)",
|
||||
};
|
||||
|
||||
|
||||
/* DACP helpers */
|
||||
static void
|
||||
dacp_nowplaying(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_nowplaying(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
uint32_t id;
|
||||
int64_t songalbumid;
|
||||
int pos_pl;
|
||||
|
||||
if ((status->status == PLAY_STOPPED) || !mfi)
|
||||
if ((status->status == PLAY_STOPPED) || !queue_item)
|
||||
return;
|
||||
|
||||
/* Send bogus id's if playing internet radio, because clients like
|
||||
@ -183,44 +191,46 @@ dacp_nowplaying(struct evbuffer *evbuf, struct player_status *status, struct med
|
||||
* FIXME: Giving the client invalid ids on purpose is hardly ideal, but the
|
||||
* clients don't seem to use these ids for anything other than rating.
|
||||
*/
|
||||
if (mfi->data_kind == DATA_KIND_HTTP)
|
||||
if (queue_item->data_kind == DATA_KIND_HTTP)
|
||||
{
|
||||
id = djb_hash(mfi->album, strlen(mfi->album));
|
||||
id = djb_hash(queue_item->album, strlen(queue_item->album));
|
||||
songalbumid = (int64_t)id;
|
||||
}
|
||||
else
|
||||
{
|
||||
id = status->id;
|
||||
songalbumid = mfi->songalbumid;
|
||||
songalbumid = queue_item->songalbumid;
|
||||
}
|
||||
|
||||
pos_pl = db_queue_get_pos(status->item_id, 0);
|
||||
|
||||
dmap_add_container(evbuf, "canp", 16);
|
||||
dmap_add_raw_uint32(evbuf, 1); /* Database */
|
||||
dmap_add_raw_uint32(evbuf, status->plid);
|
||||
dmap_add_raw_uint32(evbuf, status->pos_pl);
|
||||
dmap_add_raw_uint32(evbuf, pos_pl);
|
||||
dmap_add_raw_uint32(evbuf, id);
|
||||
|
||||
dmap_add_string(evbuf, "cann", mfi->title);
|
||||
dmap_add_string(evbuf, "cana", mfi->artist);
|
||||
dmap_add_string(evbuf, "canl", mfi->album);
|
||||
dmap_add_string(evbuf, "cang", mfi->genre);
|
||||
dmap_add_string(evbuf, "cann", queue_item->title);
|
||||
dmap_add_string(evbuf, "cana", queue_item->artist);
|
||||
dmap_add_string(evbuf, "canl", queue_item->album);
|
||||
dmap_add_string(evbuf, "cang", queue_item->genre);
|
||||
dmap_add_long(evbuf, "asai", songalbumid);
|
||||
|
||||
dmap_add_int(evbuf, "cmmk", 1);
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_playingtime(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_playingtime(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
if ((status->status == PLAY_STOPPED) || !mfi)
|
||||
if ((status->status == PLAY_STOPPED) || !queue_item)
|
||||
return;
|
||||
|
||||
if (mfi->song_length)
|
||||
dmap_add_int(evbuf, "cant", mfi->song_length - status->pos_ms); /* Remaining time in ms */
|
||||
if (queue_item->song_length)
|
||||
dmap_add_int(evbuf, "cant", queue_item->song_length - status->pos_ms); /* Remaining time in ms */
|
||||
else
|
||||
dmap_add_int(evbuf, "cant", 0); /* Unknown remaining time */
|
||||
|
||||
dmap_add_int(evbuf, "cast", mfi->song_length); /* Song length in ms */
|
||||
dmap_add_int(evbuf, "cast", queue_item->song_length); /* Song length in ms */
|
||||
}
|
||||
|
||||
|
||||
@ -229,7 +239,7 @@ static int
|
||||
make_playstatusupdate(struct evbuffer *evbuf)
|
||||
{
|
||||
struct player_status status;
|
||||
struct media_file_info *mfi;
|
||||
struct db_queue_item *queue_item = NULL;
|
||||
struct evbuffer *psu;
|
||||
int ret;
|
||||
|
||||
@ -245,16 +255,14 @@ make_playstatusupdate(struct evbuffer *evbuf)
|
||||
|
||||
if (status.status != PLAY_STOPPED)
|
||||
{
|
||||
mfi = db_file_fetch_byid(status.id);
|
||||
if (!mfi)
|
||||
queue_item = db_queue_fetch_byitemid(status.item_id);
|
||||
if (!queue_item)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not fetch file id %d\n", status.id);
|
||||
DPRINTF(E_LOG, L_DACP, "Could not fetch item id %d (file id %d)\n", status.item_id, status.id);
|
||||
|
||||
mfi = &dummy_mfi;
|
||||
queue_item = &dummy_queue_item;
|
||||
}
|
||||
}
|
||||
else
|
||||
mfi = NULL;
|
||||
|
||||
dmap_add_int(psu, "mstt", 200); /* 12 */
|
||||
|
||||
@ -271,19 +279,19 @@ make_playstatusupdate(struct evbuffer *evbuf)
|
||||
dmap_add_char(psu, "cafe", 0); /* 9 */ /* dacp.fullscreenenabled */
|
||||
dmap_add_char(psu, "cave", 0); /* 9 */ /* dacp.visualizerenabled */
|
||||
|
||||
if (mfi)
|
||||
if (queue_item)
|
||||
{
|
||||
dacp_nowplaying(psu, &status, mfi);
|
||||
dacp_nowplaying(psu, &status, queue_item);
|
||||
|
||||
dmap_add_int(psu, "casa", 1); /* 12 */ /* unknown */
|
||||
dmap_add_int(psu, "astm", mfi->song_length);
|
||||
dmap_add_int(psu, "astm", queue_item->song_length);
|
||||
dmap_add_char(psu, "casc", 1); /* Maybe an indication of extra data? */
|
||||
dmap_add_char(psu, "caks", 6); /* Unknown */
|
||||
|
||||
dacp_playingtime(psu, &status, mfi);
|
||||
dacp_playingtime(psu, &status, queue_item);
|
||||
|
||||
if (mfi != &dummy_mfi)
|
||||
free_mfi(mfi, 0);
|
||||
if (queue_item != &dummy_queue_item)
|
||||
free_queue_item(queue_item, 0);
|
||||
}
|
||||
|
||||
dmap_add_char(psu, "casu", 1); /* 9 */ /* unknown */
|
||||
@ -448,103 +456,103 @@ update_fail_cb(struct evhttp_connection *evcon, void *arg)
|
||||
|
||||
/* Properties getters */
|
||||
static void
|
||||
dacp_propget_volume(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_volume(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
dmap_add_int(evbuf, "cmvo", status->volume);
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_volumecontrollable(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_volumecontrollable(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
dmap_add_char(evbuf, "cavc", 1);
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_playerstate(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_playerstate(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
dmap_add_char(evbuf, "caps", status->status);
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_shufflestate(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_shufflestate(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
dmap_add_char(evbuf, "cash", status->shuffle);
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_availableshufflestates(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_availableshufflestates(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
dmap_add_int(evbuf, "caas", 2);
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_repeatstate(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_repeatstate(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
dmap_add_char(evbuf, "carp", status->repeat);
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_availablerepeatstates(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_availablerepeatstates(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
dmap_add_int(evbuf, "caar", 6);
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_nowplaying(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_nowplaying(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
dacp_nowplaying(evbuf, status, mfi);
|
||||
dacp_nowplaying(evbuf, status, queue_item);
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_playingtime(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_playingtime(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
dacp_playingtime(evbuf, status, mfi);
|
||||
dacp_playingtime(evbuf, status, queue_item);
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_fullscreenenabled(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_fullscreenenabled(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_fullscreen(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_fullscreen(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_visualizerenabled(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_visualizerenabled(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_visualizer(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_visualizer(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_itms_songid(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_itms_songid(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_haschapterdata(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_haschapterdata(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_mediakind(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_mediakind(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_propget_extendedmediakind(struct evbuffer *evbuf, struct player_status *status, struct media_file_info *mfi)
|
||||
dacp_propget_extendedmediakind(struct evbuffer *evbuf, struct player_status *status, struct db_queue_item *queue_item)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
@ -845,20 +853,19 @@ find_first_song_id(const char *query)
|
||||
|
||||
|
||||
static int
|
||||
dacp_queueitem_make(struct queue_item **head, const char *query, const char *queuefilter, const char *sort, int quirk)
|
||||
dacp_queueitem_add(const char *query, const char *queuefilter, const char *sort, int quirk, int mode)
|
||||
{
|
||||
struct media_file_info *mfi;
|
||||
struct query_params qp;
|
||||
struct queue_item *items;
|
||||
int64_t albumid;
|
||||
int64_t artistid;
|
||||
int plid;
|
||||
int id;
|
||||
int idx;
|
||||
int ret;
|
||||
int len;
|
||||
char *s;
|
||||
char buf[1024];
|
||||
struct player_status status;
|
||||
|
||||
if (query)
|
||||
{
|
||||
@ -965,36 +972,34 @@ dacp_queueitem_make(struct queue_item **head, const char *query, const char *que
|
||||
qp.sort = S_ARTIST;
|
||||
}
|
||||
|
||||
items = queueitem_make_byquery(&qp);
|
||||
player_get_status(&status);
|
||||
|
||||
if (mode == 3)
|
||||
ret = db_queue_add_by_queryafteritemid(&qp, status.item_id);
|
||||
else
|
||||
ret = db_queue_add_by_query(&qp, status.shuffle, status.item_id);
|
||||
|
||||
if (qp.filter)
|
||||
free(qp.filter);
|
||||
|
||||
if (items)
|
||||
*head = items;
|
||||
else
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
// Get the position (0-based) of the first item
|
||||
idx = queueitem_pos(items, id);
|
||||
|
||||
return idx;
|
||||
return id;
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
|
||||
{
|
||||
struct player_status status;
|
||||
struct queue_item *items;
|
||||
const char *sort;
|
||||
const char *cuequery;
|
||||
const char *param;
|
||||
uint32_t id;
|
||||
uint32_t item_id;
|
||||
uint32_t pos;
|
||||
int clear;
|
||||
struct db_queue_item *queue_item = NULL;
|
||||
struct player_history *history;
|
||||
int hist;
|
||||
int ret;
|
||||
|
||||
/* /cue?command=play&query=...&sort=...&index=N */
|
||||
@ -1009,18 +1014,16 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
|
||||
{
|
||||
player_playback_stop();
|
||||
|
||||
player_queue_clear();
|
||||
db_queue_clear();
|
||||
}
|
||||
}
|
||||
|
||||
player_get_status(&status);
|
||||
|
||||
cuequery = evhttp_find_header(query, "query");
|
||||
if (cuequery)
|
||||
{
|
||||
sort = evhttp_find_header(query, "sort");
|
||||
|
||||
ret = dacp_queueitem_make(&items, cuequery, NULL, sort, 0);
|
||||
ret = dacp_queueitem_add(cuequery, NULL, sort, 0, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not build song queue\n");
|
||||
@ -1028,11 +1031,11 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
|
||||
dmap_send_error(req, "cacr", "Could not build song queue");
|
||||
return;
|
||||
}
|
||||
|
||||
player_queue_add(items, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
player_get_status(&status);
|
||||
|
||||
if (status.status != PLAY_STOPPED)
|
||||
player_playback_stop();
|
||||
}
|
||||
@ -1041,7 +1044,6 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
|
||||
if (param)
|
||||
dacp_propset_shufflestate(param, NULL);
|
||||
|
||||
id = 0;
|
||||
item_id = 0;
|
||||
pos = 0;
|
||||
param = evhttp_find_header(query, "index");
|
||||
@ -1053,7 +1055,6 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
|
||||
}
|
||||
|
||||
/* If selection was from Up Next queue or history queue (command will be playnow), then index is relative */
|
||||
hist = 0;
|
||||
if ((param = evhttp_find_header(query, "command")) && (strcmp(param, "playnow") == 0))
|
||||
{
|
||||
/* If mode parameter is -1 or 1, the index is relative to the history queue, otherwise to the Up Next queue */
|
||||
@ -1061,12 +1062,20 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
|
||||
if (param && ((strcmp(param, "-1") == 0) || (strcmp(param, "1") == 0)))
|
||||
{
|
||||
/* Play from history queue */
|
||||
hist = 1;
|
||||
history = player_history_get();
|
||||
if (history->count > pos)
|
||||
{
|
||||
pos = (history->start_index + history->count - pos - 1) % MAX_HISTORY_COUNT;
|
||||
item_id = history->item_id[pos];
|
||||
|
||||
queue_item = db_queue_fetch_byitemid(item_id);
|
||||
if (!queue_item)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not start playback from history\n");
|
||||
|
||||
dmap_send_error(req, "cacr", "Playback failed to start");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1079,19 +1088,22 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
|
||||
else
|
||||
{
|
||||
/* Play from Up Next queue */
|
||||
pos += status.pos_pl;
|
||||
|
||||
if (status.status == PLAY_STOPPED && pos > 0)
|
||||
pos--;
|
||||
|
||||
queue_item = db_queue_fetch_byposrelativetoitem(pos, status.item_id, status.shuffle);
|
||||
if (!queue_item)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not fetch item from queue: pos=%d, now playing=%d\n", pos, status.item_id);
|
||||
|
||||
dmap_send_error(req, "cacr", "Playback failed to start");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If playing from history queue, the pos holds the id of the item to play */
|
||||
if (hist)
|
||||
ret = player_playback_start_byitemid(item_id, &id);
|
||||
else
|
||||
ret = player_playback_start_bypos(pos, &id);
|
||||
|
||||
ret = player_playback_start_byitem(queue_item);
|
||||
free_queue_item(queue_item, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not start playback\n");
|
||||
@ -1100,9 +1112,11 @@ dacp_reply_cue_play(struct evhttp_request *req, struct evbuffer *evbuf, char **u
|
||||
return;
|
||||
}
|
||||
|
||||
player_get_status(&status);
|
||||
|
||||
dmap_add_container(evbuf, "cacr", 24); /* 8 + len */
|
||||
dmap_add_int(evbuf, "mstt", 200); /* 12 */
|
||||
dmap_add_int(evbuf, "miid", id); /* 12 */
|
||||
dmap_add_int(evbuf, "miid", status.id);/* 12 */
|
||||
|
||||
httpd_send_reply(req, HTTP_OK, "OK", evbuf, 0);
|
||||
}
|
||||
@ -1114,7 +1128,7 @@ dacp_reply_cue_clear(struct evhttp_request *req, struct evbuffer *evbuf, char **
|
||||
|
||||
player_playback_stop();
|
||||
|
||||
player_queue_clear();
|
||||
db_queue_clear();
|
||||
|
||||
dmap_add_container(evbuf, "cacr", 24); /* 8 + len */
|
||||
dmap_add_int(evbuf, "mstt", 200); /* 12 */
|
||||
@ -1159,13 +1173,12 @@ static void
|
||||
dacp_reply_playspec(struct evhttp_request *req, struct evbuffer *evbuf, char **uri, struct evkeyvalq *query)
|
||||
{
|
||||
struct player_status status;
|
||||
struct queue_item *items;
|
||||
struct daap_session *s;
|
||||
const char *param;
|
||||
const char *shuffle;
|
||||
uint32_t plid;
|
||||
uint32_t id;
|
||||
int pos;
|
||||
struct db_queue_item *queue_item = NULL;
|
||||
int ret;
|
||||
|
||||
/* /ctrl-int/1/playspec?database-spec='dmap.persistentid:0x1'&container-spec='dmap.persistentid:0x5'&container-item-spec='dmap.containeritemid:0x9'
|
||||
@ -1241,40 +1254,41 @@ dacp_reply_playspec(struct evhttp_request *req, struct evbuffer *evbuf, char **u
|
||||
|
||||
DPRINTF(E_DBG, L_DACP, "Playspec request for playlist %d, start song id %d%s\n", plid, id, (shuffle) ? ", shuffle" : "");
|
||||
|
||||
items = NULL;
|
||||
if (plid > 0)
|
||||
items = queueitem_make_byplid(plid);
|
||||
else if (id > 0)
|
||||
items = queueitem_make_byid(id);
|
||||
player_get_status(&status);
|
||||
|
||||
if (!items)
|
||||
if (status.status != PLAY_STOPPED)
|
||||
player_playback_stop();
|
||||
|
||||
db_queue_clear();
|
||||
|
||||
if (plid > 0)
|
||||
ret = db_queue_add_by_playlistid(plid, status.shuffle, status.item_id);
|
||||
else if (id > 0)
|
||||
ret = db_queue_add_by_fileid(id, status.shuffle, status.item_id);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not build song queue from playlist %d\n", plid);
|
||||
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
pos = queueitem_pos(items, id);
|
||||
if (pos < 0)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DACP, "No item with %d found in queue\n", id);
|
||||
pos = 0;
|
||||
}
|
||||
DPRINTF(E_DBG, L_DACP, "Playspec start song index is %d\n", pos);
|
||||
|
||||
player_get_status(&status);
|
||||
|
||||
if (status.status != PLAY_STOPPED)
|
||||
player_playback_stop();
|
||||
|
||||
player_queue_clear();
|
||||
player_queue_add(items, NULL);
|
||||
player_queue_plid(plid);
|
||||
|
||||
if (shuffle)
|
||||
dacp_propset_shufflestate(shuffle, NULL);
|
||||
|
||||
ret = player_playback_start_bypos(pos, NULL);
|
||||
if (id > 0)
|
||||
queue_item = db_queue_fetch_byfileid(id);
|
||||
|
||||
if (queue_item)
|
||||
{
|
||||
ret = player_playback_start_byitem(queue_item);
|
||||
free_queue_item(queue_item, 0);
|
||||
}
|
||||
else
|
||||
ret = player_playback_start(NULL);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not start playback\n");
|
||||
@ -1500,6 +1514,44 @@ playqueuecontents_add_source(struct evbuffer *songlist, uint32_t source_id, int
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
playqueuecontents_add_queue_item(struct evbuffer *songlist, struct db_queue_item *queue_item, int pos_in_queue, uint32_t plid)
|
||||
{
|
||||
struct evbuffer *song;
|
||||
int ret;
|
||||
|
||||
song = evbuffer_new();
|
||||
if (!song)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not allocate song evbuffer for playqueue-contents\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dmap_add_container(song, "ceQs", 16);
|
||||
dmap_add_raw_uint32(song, 1); /* Database */
|
||||
dmap_add_raw_uint32(song, plid);
|
||||
dmap_add_raw_uint32(song, 0); /* Should perhaps be playlist index? */
|
||||
dmap_add_raw_uint32(song, queue_item->file_id);
|
||||
dmap_add_string(song, "ceQn", queue_item->title);
|
||||
dmap_add_string(song, "ceQr", queue_item->artist);
|
||||
dmap_add_string(song, "ceQa", queue_item->album);
|
||||
dmap_add_string(song, "ceQg", queue_item->genre);
|
||||
dmap_add_long(song, "asai", queue_item->songalbumid);
|
||||
dmap_add_int(song, "cmmk", queue_item->media_kind);
|
||||
dmap_add_int(song, "casa", 1); /* Unknown */
|
||||
dmap_add_int(song, "astm", queue_item->song_length);
|
||||
dmap_add_char(song, "casc", 1); /* Maybe an indication of extra data? */
|
||||
dmap_add_char(song, "caks", 6); /* Unknown */
|
||||
dmap_add_int(song, "ceQI", pos_in_queue);
|
||||
|
||||
dmap_add_container(songlist, "mlit", evbuffer_get_length(song));
|
||||
|
||||
ret = evbuffer_add_buffer(songlist, song);
|
||||
evbuffer_free(song);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf, char **uri,
|
||||
struct evkeyvalq *query)
|
||||
@ -1509,17 +1561,15 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
struct evbuffer *playlists;
|
||||
struct player_status status;
|
||||
struct player_history *history;
|
||||
struct queue *queue;
|
||||
struct queue_item *item;
|
||||
const char *param;
|
||||
size_t songlist_length;
|
||||
size_t playlist_length;
|
||||
int span;
|
||||
int count;
|
||||
int i;
|
||||
int n;
|
||||
int ret;
|
||||
int start_index;
|
||||
struct db_queue_enum queue_enum;
|
||||
struct db_queue_item queue_item;
|
||||
|
||||
/* /ctrl-int/1/playqueue-contents?span=50&session-id=... */
|
||||
|
||||
@ -1538,7 +1588,7 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
DPRINTF(E_LOG, L_DACP, "Invalid span value in playqueue-contents request\n");
|
||||
}
|
||||
|
||||
n = 0; // count of songs in songlist
|
||||
count = 0; // count of songs in songlist
|
||||
songlist = evbuffer_new();
|
||||
if (!songlist)
|
||||
{
|
||||
@ -1548,8 +1598,6 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
return;
|
||||
}
|
||||
|
||||
player_get_status(&status);
|
||||
|
||||
/*
|
||||
* If the span parameter is negativ make song list for Previously Played,
|
||||
* otherwise make song list for Up Next and begin with first song after playlist position.
|
||||
@ -1565,9 +1613,9 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
{
|
||||
start_index = (history->start_index + history->count - abs(span)) % MAX_HISTORY_COUNT;
|
||||
}
|
||||
for (n = 0; n < history->count && n < abs(span); n++)
|
||||
for (count = 0; count < history->count && count < abs(span); count++)
|
||||
{
|
||||
ret = playqueuecontents_add_source(songlist, history->id[(start_index + n) % MAX_HISTORY_COUNT], (n + 1), status.plid);
|
||||
ret = playqueuecontents_add_source(songlist, history->id[(start_index + count) % MAX_HISTORY_COUNT], (count + 1), status.plid);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not add song to songlist for playqueue-contents\n");
|
||||
@ -1579,15 +1627,21 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
}
|
||||
else
|
||||
{
|
||||
queue = player_queue_get_bypos(abs(span));
|
||||
if (queue)
|
||||
player_get_status(&status);
|
||||
|
||||
memset(&queue_enum, 0, sizeof(struct db_queue_enum));
|
||||
if (status.shuffle)
|
||||
queue_enum.orderby_shufflepos = 1;
|
||||
ret = db_queue_enum_start(&queue_enum);
|
||||
|
||||
count = 0; //FIXME [queue] Check count value
|
||||
while ((ret = db_queue_enum_fetch(&queue_enum, &queue_item)) == 0 && queue_item.item_id > 0)
|
||||
{
|
||||
i = 0;
|
||||
count = queue_count(queue);
|
||||
for (n = 0; (n < count) && (n < abs(span)); n++)
|
||||
if (status.item_id == 0 || status.item_id == queue_item.item_id)
|
||||
count = 1;
|
||||
else if (count > 0)
|
||||
{
|
||||
item = queue_get_byindex(queue, n, 0);
|
||||
ret = playqueuecontents_add_source(songlist, queueitem_id(item), (n + i + 1), status.plid);
|
||||
ret = playqueuecontents_add_queue_item(songlist, &queue_item, count, status.plid);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not add song to songlist for playqueue-contents\n");
|
||||
@ -1595,9 +1649,13 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
dmap_send_error(req, "ceQR", "Out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
queue_free(queue);
|
||||
}
|
||||
|
||||
db_queue_enum_end(&queue_enum);
|
||||
sqlite3_free(queue_enum.filter);
|
||||
}
|
||||
|
||||
/* Playlists are hist, curr and main. */
|
||||
@ -1628,7 +1686,7 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
dmap_add_container(playlists, "mlit", 69);
|
||||
dmap_add_string(playlists, "ceQk", "main"); /* 12 */
|
||||
dmap_add_int(playlists, "ceQi", 1); /* 12 */
|
||||
dmap_add_int(playlists, "ceQm", n); /* 12 */
|
||||
dmap_add_int(playlists, "ceQm", count); /* 12 */
|
||||
dmap_add_string(playlists, "ceQl", "Up Next"); /* 15 = 8 + 7 */
|
||||
dmap_add_string(playlists, "ceQh", "from Music"); /* 18 = 8 + 10 */
|
||||
|
||||
@ -1640,10 +1698,10 @@ dacp_reply_playqueuecontents(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
/* Final construction of reply */
|
||||
playlist_length = evbuffer_get_length(playlists);
|
||||
dmap_add_container(evbuf, "ceQR", 79 + playlist_length + songlist_length); /* size of entire container */
|
||||
dmap_add_int(evbuf, "mstt", 200); /* 12, dmap.status */
|
||||
dmap_add_int(evbuf, "mtco", abs(span)); /* 12 */
|
||||
dmap_add_int(evbuf, "mrco", n); /* 12 */
|
||||
dmap_add_char(evbuf, "ceQu", 0); /* 9 */
|
||||
dmap_add_int(evbuf, "mstt", 200); /* 12, dmap.status */
|
||||
dmap_add_int(evbuf, "mtco", abs(span)); /* 12 */
|
||||
dmap_add_int(evbuf, "mrco", count); /* 12 */
|
||||
dmap_add_char(evbuf, "ceQu", 0); /* 9 */
|
||||
dmap_add_container(evbuf, "mlcl", 8 + playlist_length + songlist_length); /* 8 */
|
||||
dmap_add_container(evbuf, "ceQS", playlist_length); /* 8 */
|
||||
ret = evbuffer_add_buffer(evbuf, playlists);
|
||||
@ -1691,7 +1749,7 @@ dacp_reply_playqueueedit_clear(struct evhttp_request *req, struct evbuffer *evbu
|
||||
if (strcmp(param,"0x68697374") == 0)
|
||||
player_queue_clear_history();
|
||||
else
|
||||
player_queue_clear();
|
||||
db_queue_clear();
|
||||
|
||||
dmap_add_container(evbuf, "cacr", 24); /* 8 + len */
|
||||
dmap_add_int(evbuf, "mstt", 200); /* 12 */
|
||||
@ -1712,7 +1770,6 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
//?command=add&query='dmap.itemid:2'&query-modifier=containers&sort=name&mode=2&session-id=100
|
||||
// -> mode 2: stop playblack, clear playqueue, add shuffled songs from playlist=itemid to playqueue
|
||||
|
||||
struct queue_item *items;
|
||||
const char *editquery;
|
||||
const char *queuefilter;
|
||||
const char *querymodifier;
|
||||
@ -1724,6 +1781,7 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
int plid;
|
||||
int ret;
|
||||
int quirkyquery;
|
||||
struct db_queue_item *queue_item;
|
||||
|
||||
mode = 1;
|
||||
|
||||
@ -1743,67 +1801,54 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
if ((mode == 1) || (mode == 2))
|
||||
{
|
||||
player_playback_stop();
|
||||
player_queue_clear();
|
||||
db_queue_clear();
|
||||
}
|
||||
|
||||
editquery = evhttp_find_header(query, "query");
|
||||
if (editquery)
|
||||
if (!editquery)
|
||||
{
|
||||
sort = evhttp_find_header(query, "sort");
|
||||
DPRINTF(E_LOG, L_DACP, "Could not add song queue, DACP query missing\n");
|
||||
|
||||
// if sort param is missing and an album or artist is added to the queue, set sort to "album"
|
||||
if (!sort && (strstr(editquery, "daap.songalbumid:") || strstr(editquery, "daap.songartistid:")))
|
||||
{
|
||||
sort = "album";
|
||||
}
|
||||
dmap_send_error(req, "cacr", "Invalid request");
|
||||
return;
|
||||
}
|
||||
|
||||
// only use queryfilter if mode is not equal 0 (add to up next), 3 (play next) or 5 (add to up next)
|
||||
queuefilter = (mode == 0 || mode == 3 || mode == 5) ? NULL : evhttp_find_header(query, "queuefilter");
|
||||
sort = evhttp_find_header(query, "sort");
|
||||
|
||||
querymodifier = evhttp_find_header(query, "query-modifier");
|
||||
if (!querymodifier || (strcmp(querymodifier, "containers") != 0))
|
||||
{
|
||||
quirkyquery = (mode == 1) && strstr(editquery, "dmap.itemid:") && ((!queuefilter) || strstr(queuefilter, "(null)"));
|
||||
ret = dacp_queueitem_make(&items, editquery, queuefilter, sort, quirkyquery);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Modify the query: Take the id from the editquery and use it as a queuefilter playlist id
|
||||
ret = safe_atoi32(strchr(editquery, ':') + 1, &plid);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Invalid playlist id in request: %s\n", editquery);
|
||||
// if sort param is missing and an album or artist is added to the queue, set sort to "album"
|
||||
if (!sort && (strstr(editquery, "daap.songalbumid:") || strstr(editquery, "daap.songartistid:")))
|
||||
{
|
||||
sort = "album";
|
||||
}
|
||||
|
||||
dmap_send_error(req, "cacr", "Invalid request");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(modifiedquery, sizeof(modifiedquery), "playlist:%d", plid);
|
||||
ret = dacp_queueitem_make(&items, NULL, modifiedquery, sort, 0);
|
||||
}
|
||||
// only use queryfilter if mode is not equal 0 (add to up next), 3 (play next) or 5 (add to up next)
|
||||
queuefilter = (mode == 0 || mode == 3 || mode == 5) ? NULL : evhttp_find_header(query, "queuefilter");
|
||||
|
||||
querymodifier = evhttp_find_header(query, "query-modifier");
|
||||
if (!querymodifier || (strcmp(querymodifier, "containers") != 0))
|
||||
{
|
||||
quirkyquery = (mode == 1) && strstr(editquery, "dmap.itemid:") && ((!queuefilter) || strstr(queuefilter, "(null)"));
|
||||
ret = dacp_queueitem_add(editquery, queuefilter, sort, quirkyquery, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Modify the query: Take the id from the editquery and use it as a queuefilter playlist id
|
||||
ret = safe_atoi32(strchr(editquery, ':') + 1, &plid);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not build song queue\n");
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Invalid playlist id in request: %s\n", editquery);
|
||||
|
||||
dmap_send_error(req, "cacr", "Invalid request");
|
||||
return;
|
||||
}
|
||||
|
||||
idx = ret;
|
||||
|
||||
if (mode == 3)
|
||||
{
|
||||
player_queue_add_next(items);
|
||||
}
|
||||
else
|
||||
{
|
||||
player_queue_add(items, NULL);
|
||||
}
|
||||
snprintf(modifiedquery, sizeof(modifiedquery), "playlist:%d", plid);
|
||||
ret = dacp_queueitem_add(NULL, modifiedquery, sort, 0, mode);
|
||||
}
|
||||
else
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not add song queue, DACP query missing\n");
|
||||
DPRINTF(E_LOG, L_DACP, "Could not build song queue\n");
|
||||
|
||||
dmap_send_error(req, "cacr", "Invalid request");
|
||||
return;
|
||||
@ -1812,11 +1857,27 @@ dacp_reply_playqueueedit_add(struct evhttp_request *req, struct evbuffer *evbuf,
|
||||
if (mode == 2)
|
||||
{
|
||||
player_shuffle_set(1);
|
||||
idx = 0;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
queue_item = NULL;
|
||||
if (ret > 0)
|
||||
{
|
||||
queue_item = db_queue_fetch_byfileid(ret);
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG, L_DACP, "Song queue built, playback starting at index %" PRIu32 "\n", idx);
|
||||
ret = player_playback_start_bypos(idx, NULL);
|
||||
if (queue_item)
|
||||
{
|
||||
ret = player_playback_start_byitem(queue_item);
|
||||
free_queue_item(queue_item, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = player_playback_start(NULL);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not start playback\n");
|
||||
@ -1840,6 +1901,7 @@ dacp_reply_playqueueedit_move(struct evhttp_request *req, struct evbuffer *evbuf
|
||||
* The 'edit-param.move-pair' param contains the index of the song in the playqueue to be moved (index 3 in the example)
|
||||
* and the index of the song after which it should be inserted (index 0 in the exampe, the now playing song).
|
||||
*/
|
||||
struct player_status status;
|
||||
int ret;
|
||||
|
||||
const char *param;
|
||||
@ -1867,7 +1929,8 @@ dacp_reply_playqueueedit_move(struct evhttp_request *req, struct evbuffer *evbuf
|
||||
return;
|
||||
}
|
||||
|
||||
player_queue_move_bypos(src, dst);
|
||||
player_get_status(&status);
|
||||
db_queue_move_byposrelativetoitem(src, dst, status.item_id, status.shuffle);
|
||||
}
|
||||
|
||||
/* 204 No Content is the canonical reply */
|
||||
@ -1882,6 +1945,7 @@ dacp_reply_playqueueedit_remove(struct evhttp_request *req, struct evbuffer *evb
|
||||
* Exampe request (removes song at position 1 in the playqueue):
|
||||
* ?command=remove&items=1&session-id=100
|
||||
*/
|
||||
struct player_status status;
|
||||
int ret;
|
||||
|
||||
const char *param;
|
||||
@ -1899,7 +1963,9 @@ dacp_reply_playqueueedit_remove(struct evhttp_request *req, struct evbuffer *evb
|
||||
return;
|
||||
}
|
||||
|
||||
player_queue_remove_bypos(item_index);
|
||||
player_get_status(&status);
|
||||
|
||||
db_queue_delete_byposrelativetoitem(item_index, status.item_id, status.shuffle);
|
||||
}
|
||||
|
||||
/* 204 No Content is the canonical reply */
|
||||
@ -2150,7 +2216,7 @@ dacp_reply_getproperty(struct evhttp_request *req, struct evbuffer *evbuf, char
|
||||
struct player_status status;
|
||||
struct daap_session *s;
|
||||
const struct dacp_prop_map *dpm;
|
||||
struct media_file_info *mfi;
|
||||
struct db_queue_item *queue_item = NULL;
|
||||
struct evbuffer *proplist;
|
||||
const char *param;
|
||||
char *ptr;
|
||||
@ -2194,17 +2260,15 @@ dacp_reply_getproperty(struct evhttp_request *req, struct evbuffer *evbuf, char
|
||||
|
||||
if (status.status != PLAY_STOPPED)
|
||||
{
|
||||
mfi = db_file_fetch_byid(status.id);
|
||||
if (!mfi)
|
||||
queue_item = db_queue_fetch_byitemid(status.item_id);
|
||||
if (!queue_item)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DACP, "Could not fetch file id %d\n", status.id);
|
||||
DPRINTF(E_LOG, L_DACP, "Could not fetch queue_item for item-id %d\n", status.item_id);
|
||||
|
||||
dmap_send_error(req, "cmgt", "Server error");
|
||||
goto out_free_proplist;
|
||||
}
|
||||
}
|
||||
else
|
||||
mfi = NULL;
|
||||
|
||||
prop = strtok_r(propstr, ",", &ptr);
|
||||
while (prop)
|
||||
@ -2213,7 +2277,7 @@ dacp_reply_getproperty(struct evhttp_request *req, struct evbuffer *evbuf, char
|
||||
if (dpm)
|
||||
{
|
||||
if (dpm->propget)
|
||||
dpm->propget(proplist, &status, mfi);
|
||||
dpm->propget(proplist, &status, queue_item);
|
||||
else
|
||||
DPRINTF(E_WARN, L_DACP, "No getter method for DACP property %s\n", prop);
|
||||
}
|
||||
@ -2225,8 +2289,8 @@ dacp_reply_getproperty(struct evhttp_request *req, struct evbuffer *evbuf, char
|
||||
|
||||
free(propstr);
|
||||
|
||||
if (mfi)
|
||||
free_mfi(mfi, 0);
|
||||
if (queue_item)
|
||||
free_queue_item(queue_item, 0);
|
||||
|
||||
len = evbuffer_get_length(proplist);
|
||||
dmap_add_container(evbuf, "cmgt", 12 + len);
|
||||
|
411
src/mpd.c
411
src/mpd.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2010 Julien BLACHE <jb@jblache.org>
|
||||
* Copyright (C) 2016 Christian Meffert <christian.meffert@googlemail.com>
|
||||
*
|
||||
* 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
|
||||
@ -61,7 +61,6 @@
|
||||
#include "artwork.h"
|
||||
|
||||
#include "player.h"
|
||||
#include "queue.h"
|
||||
#include "filescanner.h"
|
||||
#include "commands.h"
|
||||
|
||||
@ -396,18 +395,16 @@ mpd_parse_args(char *args, int *argc, char **argv)
|
||||
* Id: 1
|
||||
*
|
||||
* @param evbuf the response event buffer
|
||||
* @param mfi media information
|
||||
* @param item_id queue-item id
|
||||
* @param pos_pl position in the playqueue, if -1 the position is ignored
|
||||
* @param queue_item queue item information
|
||||
* @return the number of bytes added if successful, or -1 if an error occurred.
|
||||
*/
|
||||
static int
|
||||
mpd_add_mediainfo(struct evbuffer *evbuf, struct media_file_info *mfi, unsigned int item_id, int pos_pl)
|
||||
mpd_add_db_queue_item(struct evbuffer *evbuf, struct db_queue_item *queue_item)
|
||||
{
|
||||
char modified[32];
|
||||
int ret;
|
||||
|
||||
mpd_time(modified, sizeof(modified), mfi->time_modified);
|
||||
mpd_time(modified, sizeof(modified), queue_item->time_modified);
|
||||
|
||||
ret = evbuffer_add_printf(evbuf,
|
||||
"file: %s\n"
|
||||
@ -422,65 +419,28 @@ mpd_add_mediainfo(struct evbuffer *evbuf, struct media_file_info *mfi, unsigned
|
||||
"Track: %d\n"
|
||||
"Date: %d\n"
|
||||
"Genre: %s\n"
|
||||
"Disc: %d\n",
|
||||
(mfi->virtual_path + 1),
|
||||
"Disc: %d\n"
|
||||
"Pos: %d\n"
|
||||
"Id: %d\n",
|
||||
(queue_item->virtual_path + 1),
|
||||
modified,
|
||||
(mfi->song_length / 1000),
|
||||
mfi->artist,
|
||||
mfi->album_artist,
|
||||
mfi->artist_sort,
|
||||
mfi->album_artist_sort,
|
||||
mfi->album,
|
||||
mfi->title,
|
||||
mfi->track,
|
||||
mfi->year,
|
||||
mfi->genre,
|
||||
mfi->disc);
|
||||
|
||||
if (ret >= 0 && pos_pl >= 0)
|
||||
{
|
||||
ret = evbuffer_add_printf(evbuf,
|
||||
"Pos: %d\n",
|
||||
pos_pl);
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
ret = evbuffer_add_printf(evbuf,
|
||||
"Id: %d\n",
|
||||
item_id);
|
||||
}
|
||||
}
|
||||
(queue_item->song_length / 1000),
|
||||
queue_item->artist,
|
||||
queue_item->album_artist,
|
||||
queue_item->artist_sort,
|
||||
queue_item->album_artist_sort,
|
||||
queue_item->album,
|
||||
queue_item->title,
|
||||
queue_item->track,
|
||||
queue_item->year,
|
||||
queue_item->genre,
|
||||
queue_item->disc,
|
||||
queue_item->pos,
|
||||
queue_item->item_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mpd_add_mediainfo_byid(struct evbuffer *evbuf, int id, unsigned int item_id, int pos_pl)
|
||||
{
|
||||
struct media_file_info *mfi;
|
||||
int ret;
|
||||
|
||||
mfi = db_file_fetch_byid(id);
|
||||
if (!mfi)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MPD, "Error fetching file by id: %d\n", id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mpd_add_mediainfo(evbuf, mfi, item_id, pos_pl);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MPD, "Error adding media info for file with id: %d\n", id);
|
||||
|
||||
free_mfi(mfi, 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
free_mfi(mfi, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds the informations (path, id, tags, etc.) for the given song to the given buffer.
|
||||
*
|
||||
@ -568,6 +528,7 @@ mpd_command_currentsong(struct evbuffer *evbuf, int argc, char **argv, char **er
|
||||
{
|
||||
|
||||
struct player_status status;
|
||||
struct db_queue_item *queue_item;
|
||||
int ret;
|
||||
|
||||
player_get_status(&status);
|
||||
@ -578,7 +539,20 @@ mpd_command_currentsong(struct evbuffer *evbuf, int argc, char **argv, char **er
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = mpd_add_mediainfo_byid(evbuf, status.id, status.item_id, status.pos_pl);
|
||||
queue_item = db_queue_fetch_byitemid(status.item_id);
|
||||
if (!queue_item)
|
||||
{
|
||||
ret = asprintf(errmsg, "Error adding queue item info for file with id: %d", status.item_id);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
ret = mpd_add_db_queue_item(evbuf, queue_item);
|
||||
|
||||
free_queue_item(queue_item, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Error adding media info for file with id: %d", status.id);
|
||||
@ -717,7 +691,11 @@ static int
|
||||
mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
struct player_status status;
|
||||
int queue_length;
|
||||
int queue_version;
|
||||
char *state;
|
||||
int pos_pl;
|
||||
struct db_queue_item *next_item;
|
||||
|
||||
player_get_status(&status);
|
||||
|
||||
@ -736,6 +714,9 @@ mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
break;
|
||||
}
|
||||
|
||||
queue_version = db_queue_get_version();
|
||||
queue_length = db_queue_get_count();
|
||||
|
||||
evbuffer_add_printf(evbuf,
|
||||
"volume: %d\n"
|
||||
"repeat: %d\n"
|
||||
@ -751,12 +732,14 @@ mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
status.shuffle,
|
||||
(status.repeat == REPEAT_SONG ? 1 : 0),
|
||||
0 /* consume: not supported by forked-daapd, always return 'off' */,
|
||||
status.plversion,
|
||||
status.playlistlength,
|
||||
queue_version,
|
||||
queue_length,
|
||||
state);
|
||||
|
||||
if (status.status != PLAY_STOPPED)
|
||||
{
|
||||
pos_pl = db_queue_get_pos(status.item_id, 0);
|
||||
|
||||
evbuffer_add_printf(evbuf,
|
||||
"song: %d\n"
|
||||
"songid: %d\n"
|
||||
@ -764,7 +747,7 @@ mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
"elapsed: %#.3f\n"
|
||||
"bitrate: 128\n"
|
||||
"audio: 44100:16:2\n",
|
||||
status.pos_pl,
|
||||
pos_pl,
|
||||
status.item_id,
|
||||
(status.pos_ms / 1000), (status.len_ms / 1000),
|
||||
(status.pos_ms / 1000.0));
|
||||
@ -777,11 +760,17 @@ mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
|
||||
if (status.status != PLAY_STOPPED)
|
||||
{
|
||||
next_item = db_queue_fetch_next(status.item_id, status.shuffle);
|
||||
if (next_item)
|
||||
{
|
||||
evbuffer_add_printf(evbuf,
|
||||
"nextsong: %d\n"
|
||||
"nextsongid: %d\n",
|
||||
status.next_pos_pl,
|
||||
status.next_item_id);
|
||||
next_item->item_id,
|
||||
next_item->pos);
|
||||
|
||||
free_queue_item(next_item, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1145,10 +1134,9 @@ mpd_command_play(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
int songpos;
|
||||
struct player_status status;
|
||||
struct db_queue_item *queue_item;
|
||||
int ret;
|
||||
|
||||
player_get_status(&status);
|
||||
|
||||
songpos = 0;
|
||||
if (argc > 1)
|
||||
{
|
||||
@ -1162,6 +1150,8 @@ mpd_command_play(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
}
|
||||
}
|
||||
|
||||
player_get_status(&status);
|
||||
|
||||
if (status.status == PLAY_PLAYING && songpos < 0)
|
||||
{
|
||||
DPRINTF(E_DBG, L_MPD, "Ignoring play command with parameter '%s', player is already playing.\n", argv[1]);
|
||||
@ -1175,7 +1165,19 @@ mpd_command_play(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
}
|
||||
|
||||
if (songpos > 0)
|
||||
ret = player_playback_start_byindex(songpos, NULL);
|
||||
{
|
||||
queue_item = db_queue_fetch_bypos(songpos, 0);
|
||||
if (!queue_item)
|
||||
{
|
||||
ret = asprintf(errmsg, "Failed to start playback");
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
ret = player_playback_start_byitem(queue_item);
|
||||
free_queue_item(queue_item, 0);
|
||||
}
|
||||
else
|
||||
ret = player_playback_start(NULL);
|
||||
|
||||
@ -1200,6 +1202,7 @@ mpd_command_playid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
uint32_t id;
|
||||
struct player_status status;
|
||||
struct db_queue_item *queue_item;
|
||||
int ret;
|
||||
|
||||
player_get_status(&status);
|
||||
@ -1225,7 +1228,19 @@ mpd_command_playid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
}
|
||||
|
||||
if (id > 0)
|
||||
ret = player_playback_start_byitemid(id, NULL);
|
||||
{
|
||||
queue_item = db_queue_fetch_byitemid(id);
|
||||
if (!queue_item)
|
||||
{
|
||||
ret = asprintf(errmsg, "Failed to start playback");
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
ret = player_playback_start_byitem(queue_item);
|
||||
free_queue_item(queue_item, 0);
|
||||
}
|
||||
else
|
||||
ret = player_playback_start(NULL);
|
||||
|
||||
@ -1279,7 +1294,6 @@ mpd_command_previous(struct evbuffer *evbuf, int argc, char **argv, char **errms
|
||||
static int
|
||||
mpd_command_seek(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
struct player_status status;
|
||||
uint32_t songpos;
|
||||
float seek_target_sec;
|
||||
int seek_target_msec;
|
||||
@ -1303,14 +1317,6 @@ mpd_command_seek(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
}
|
||||
|
||||
//TODO Allow seeking in songs not currently playing
|
||||
player_get_status(&status);
|
||||
if (status.pos_pl != songpos)
|
||||
{
|
||||
ret = asprintf(errmsg, "Given song is not the current playing one, seeking is not supported");
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
seek_target_sec = strtof(argv[2], NULL);
|
||||
seek_target_msec = seek_target_sec * 1000;
|
||||
@ -1470,11 +1476,12 @@ mpd_command_stop(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct queue_item *
|
||||
mpd_queueitem_make(char *path, int recursive)
|
||||
static int
|
||||
mpd_queue_add(char *path, int recursive)
|
||||
{
|
||||
struct query_params qp;
|
||||
struct queue_item *items;
|
||||
struct player_status status;
|
||||
int ret;
|
||||
|
||||
memset(&qp, 0, sizeof(struct query_params));
|
||||
|
||||
@ -1495,10 +1502,12 @@ mpd_queueitem_make(char *path, int recursive)
|
||||
DPRINTF(E_DBG, L_PLAYER, "Out of memory\n");
|
||||
}
|
||||
|
||||
items = queueitem_make_byquery(&qp);
|
||||
player_get_status(&status);
|
||||
|
||||
ret = db_queue_add_by_query(&qp, status.shuffle, status.item_id);
|
||||
|
||||
sqlite3_free(qp.filter);
|
||||
return items;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1509,7 +1518,6 @@ mpd_queueitem_make(char *path, int recursive)
|
||||
static int
|
||||
mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
struct queue_item *items;
|
||||
int ret;
|
||||
|
||||
if (argc < 2)
|
||||
@ -1520,9 +1528,9 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
items = mpd_queueitem_make(argv[1], 1);
|
||||
ret = mpd_queue_add(argv[1], 1);
|
||||
|
||||
if (!items)
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Failed to add song '%s' to playlist", argv[1]);
|
||||
if (ret < 0)
|
||||
@ -1530,8 +1538,6 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
player_queue_add(items, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1544,8 +1550,6 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
static int
|
||||
mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
struct queue_item *items;
|
||||
uint32_t item_id;
|
||||
int ret;
|
||||
|
||||
if (argc < 2)
|
||||
@ -1562,9 +1566,9 @@ mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
DPRINTF(E_LOG, L_MPD, "Adding at a specified position not supported for 'addid', adding songs at end of queue.\n");
|
||||
}
|
||||
|
||||
items = mpd_queueitem_make(argv[1], 0);
|
||||
ret = mpd_queue_add(argv[1], 0);
|
||||
|
||||
if (!items)
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Failed to add song '%s' to playlist", argv[1]);
|
||||
if (ret < 0)
|
||||
@ -1572,12 +1576,9 @@ mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
player_queue_add(items, &item_id);
|
||||
|
||||
evbuffer_add_printf(evbuf,
|
||||
"Id: %d\n",
|
||||
item_id);
|
||||
ret); // mpd_queue_add returns the item_id of the last inserted queue item
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1597,7 +1598,7 @@ mpd_command_clear(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
DPRINTF(E_DBG, L_MPD, "Failed to stop playback\n");
|
||||
}
|
||||
|
||||
player_queue_clear();
|
||||
db_queue_clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1616,10 +1617,10 @@ mpd_command_delete(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
int count;
|
||||
int ret;
|
||||
|
||||
// If argv[1] is ommited clear the whole queue except the current playing one
|
||||
// If argv[1] is ommited clear the whole queue
|
||||
if (argc < 2)
|
||||
{
|
||||
player_queue_clear();
|
||||
db_queue_clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1635,7 +1636,7 @@ mpd_command_delete(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
|
||||
count = end_pos - start_pos;
|
||||
|
||||
ret = player_queue_remove_byindex(start_pos, count);
|
||||
ret = db_queue_delete_bypos(start_pos, count);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Failed to remove %d songs starting at position %d", count, start_pos);
|
||||
@ -1674,7 +1675,7 @@ mpd_command_deleteid(struct evbuffer *evbuf, int argc, char **argv, char **errms
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
ret = player_queue_remove_byitemid(songid);
|
||||
ret = db_queue_delete_byitemid(songid);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Failed to remove song with id '%s'", argv[1]);
|
||||
@ -1726,7 +1727,7 @@ mpd_command_move(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
ret = player_queue_move_byindex(start_pos, to_pos);
|
||||
ret = db_queue_move_bypos(start_pos, to_pos);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Failed to move song at position %d to %d", start_pos, to_pos);
|
||||
@ -1771,7 +1772,7 @@ mpd_command_moveid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
ret = player_queue_move_byitemid(songid, to_pos);
|
||||
ret = db_queue_move_byitemid(songid, to_pos);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Failed to move song with id '%s' to index '%s'", argv[1], argv[2]);
|
||||
@ -1793,12 +1794,9 @@ mpd_command_moveid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
static int
|
||||
mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
struct queue *queue;
|
||||
struct queue_item *item;
|
||||
struct db_queue_enum queue_enum;
|
||||
struct db_queue_item queue_item;
|
||||
uint32_t songid;
|
||||
int pos_pl;
|
||||
int count;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
songid = 0;
|
||||
@ -1815,39 +1813,38 @@ mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **err
|
||||
}
|
||||
}
|
||||
|
||||
// Get the whole queue (start_pos = 0, end_pos = -1)
|
||||
queue = player_queue_get_byindex(0, 0);
|
||||
memset(&queue_enum, 0, sizeof(struct db_queue_enum));
|
||||
|
||||
if (!queue)
|
||||
if (songid > 0)
|
||||
queue_enum.filter = sqlite3_mprintf("id = %d", songid);
|
||||
|
||||
ret = db_queue_enum_start(&queue_enum);
|
||||
if (ret < 0)
|
||||
{
|
||||
// Queue is emtpy
|
||||
return 0;
|
||||
sqlite3_free(queue_enum.filter);
|
||||
ret = asprintf(errmsg, "Failed to start queue enum for command playlistid: '%s'", argv[1]);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
pos_pl = 0;
|
||||
count = queue_count(queue);
|
||||
for (i = 0; i < count; i++)
|
||||
while ((ret = db_queue_enum_fetch(&queue_enum, &queue_item)) == 0 && queue_item.item_id > 0)
|
||||
{
|
||||
item = queue_get_byindex(queue, i, 0);
|
||||
if (songid == 0 || songid == queueitem_item_id(item))
|
||||
{
|
||||
ret = mpd_add_mediainfo_byid(evbuf, queueitem_id(item), queueitem_item_id(item), pos_pl);
|
||||
ret = mpd_add_db_queue_item(evbuf, &queue_item);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Error adding media info for file with id: %d", queueitem_id(item));
|
||||
|
||||
queue_free(queue);
|
||||
|
||||
ret = asprintf(errmsg, "Error adding media info for file with id: %d", queue_item.file_id);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
|
||||
db_queue_enum_end(&queue_enum);
|
||||
sqlite3_free(queue_enum.filter);
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
pos_pl++;
|
||||
}
|
||||
|
||||
queue_free(queue);
|
||||
db_queue_enum_end(&queue_enum);
|
||||
sqlite3_free(queue_enum.filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1863,17 +1860,15 @@ mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **err
|
||||
static int
|
||||
mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
struct queue *queue;
|
||||
struct queue_item *item;
|
||||
struct db_queue_enum queue_enum;
|
||||
struct db_queue_item queue_item;
|
||||
int start_pos;
|
||||
int end_pos;
|
||||
int count;
|
||||
int pos_pl;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
start_pos = 0;
|
||||
end_pos = 0;
|
||||
memset(&queue_enum, 0, sizeof(struct db_queue_enum));
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
@ -1885,46 +1880,41 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
count = end_pos - start_pos;
|
||||
|
||||
if (start_pos < 0)
|
||||
{
|
||||
DPRINTF(E_DBG, L_MPD, "Command 'playlistinfo' called with pos < 0 (arg = '%s'), ignore arguments and return whole queue\n", argv[1]);
|
||||
start_pos = 0;
|
||||
count = 0;
|
||||
else
|
||||
queue_enum.filter = sqlite3_mprintf("pos >= %d AND pos < %d", start_pos, end_pos);
|
||||
}
|
||||
|
||||
queue = player_queue_get_byindex(start_pos, count);
|
||||
|
||||
if (!queue)
|
||||
ret = db_queue_enum_start(&queue_enum);
|
||||
if (ret < 0)
|
||||
{
|
||||
// Queue is emtpy
|
||||
return 0;
|
||||
sqlite3_free(queue_enum.filter);
|
||||
ret = asprintf(errmsg, "Failed to start queue enum for command playlistinfo: '%s'", argv[1]);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
pos_pl = start_pos;
|
||||
count = queue_count(queue);
|
||||
for (i = 0; i < count; i++)
|
||||
while ((ret = db_queue_enum_fetch(&queue_enum, &queue_item)) == 0 && queue_item.item_id > 0)
|
||||
{
|
||||
item = queue_get_byindex(queue, i, 0);
|
||||
ret = mpd_add_mediainfo_byid(evbuf, queueitem_id(item), queueitem_item_id(item), pos_pl);
|
||||
ret = mpd_add_db_queue_item(evbuf, &queue_item);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Error adding media info for file with id: %d", queueitem_id(item));
|
||||
|
||||
queue_free(queue);
|
||||
ret = asprintf(errmsg, "Error adding media info for file with id: %d", queue_item.file_id);
|
||||
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
|
||||
db_queue_enum_end(&queue_enum);
|
||||
sqlite3_free(queue_enum.filter);
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
pos_pl++;
|
||||
}
|
||||
|
||||
queue_free(queue);
|
||||
db_queue_enum_end(&queue_enum);
|
||||
sqlite3_free(queue_enum.filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1936,46 +1926,42 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e
|
||||
static int
|
||||
mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
struct queue *queue;
|
||||
struct queue_item *item;
|
||||
int pos_pl;
|
||||
int count;
|
||||
int i;
|
||||
struct db_queue_enum queue_enum;
|
||||
struct db_queue_item queue_item;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* forked-daapd does not keep track of changes in the queue based on the playlist version,
|
||||
* therefor plchanges returns all songs in the queue as changed ignoring the given version.
|
||||
*/
|
||||
queue = player_queue_get_byindex(0, 0);
|
||||
memset(&queue_enum, 0, sizeof(struct db_queue_enum));
|
||||
|
||||
if (!queue)
|
||||
ret = db_queue_enum_start(&queue_enum);
|
||||
if (ret < 0)
|
||||
{
|
||||
// Queue is emtpy
|
||||
return 0;
|
||||
ret = asprintf(errmsg, "Failed to start queue enum for command plchanges");
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
pos_pl = 0;
|
||||
count = queue_count(queue);
|
||||
for (i = 0; i < count; i++)
|
||||
while ((ret = db_queue_enum_fetch(&queue_enum, &queue_item)) == 0 && queue_item.item_id > 0)
|
||||
{
|
||||
item = queue_get_byindex(queue, i, 0);
|
||||
ret = mpd_add_mediainfo_byid(evbuf, queueitem_id(item), queueitem_item_id(item), pos_pl);
|
||||
ret = mpd_add_db_queue_item(evbuf, &queue_item);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Error adding media info for file with id: %d", queueitem_id(item));
|
||||
|
||||
queue_free(queue);
|
||||
ret = asprintf(errmsg, "Error adding media info for file with id: %d", queue_item.file_id);
|
||||
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
|
||||
db_queue_enum_end(&queue_enum);
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
pos_pl++;
|
||||
}
|
||||
|
||||
queue_free(queue);
|
||||
db_queue_enum_end(&queue_enum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1986,36 +1972,36 @@ mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errm
|
||||
static int
|
||||
mpd_command_plchangesposid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
struct queue *queue;
|
||||
struct queue_item *item;
|
||||
int count;
|
||||
int i;
|
||||
struct db_queue_enum queue_enum;
|
||||
struct db_queue_item queue_item;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* forked-daapd does not keep track of changes in the queue based on the playlist version,
|
||||
* therefor plchangesposid returns all songs in the queue as changed ignoring the given version.
|
||||
*/
|
||||
queue = player_queue_get_byindex(0, 0);
|
||||
memset(&queue_enum, 0, sizeof(struct db_queue_enum));
|
||||
|
||||
if (!queue)
|
||||
ret = db_queue_enum_start(&queue_enum);
|
||||
if (ret < 0)
|
||||
{
|
||||
// Queue is emtpy
|
||||
return 0;
|
||||
ret = asprintf(errmsg, "Failed to start queue enum for command plchangesposid");
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
return ACK_ERROR_ARG;
|
||||
}
|
||||
|
||||
count = queue_count(queue);
|
||||
for (i = 0; i < count; i++)
|
||||
while ((ret = db_queue_enum_fetch(&queue_enum, &queue_item)) == 0 && queue_item.item_id > 0)
|
||||
{
|
||||
item = queue_get_byindex(queue, i, 0);
|
||||
|
||||
evbuffer_add_printf(evbuf,
|
||||
"cpos: %d\n"
|
||||
"Id: %d\n",
|
||||
i,
|
||||
queueitem_item_id(item));
|
||||
queue_item.pos,
|
||||
queue_item.item_id);
|
||||
}
|
||||
|
||||
queue_free(queue);
|
||||
db_queue_enum_end(&queue_enum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2239,7 +2225,7 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
struct playlist_info *pli;
|
||||
struct queue_item *items;
|
||||
struct player_status status;
|
||||
int ret;
|
||||
|
||||
if (argc < 2)
|
||||
@ -2274,20 +2260,18 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
|
||||
//TODO If a second parameter is given only add the specified range of songs to the playqueue
|
||||
|
||||
items = queueitem_make_byplid(pli->id);
|
||||
player_get_status(&status);
|
||||
|
||||
if (!items)
|
||||
ret = db_queue_add_by_playlistid(pli->id, status.shuffle, status.item_id);
|
||||
free_pli(pli, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
free_pli(pli, 0);
|
||||
|
||||
ret = asprintf(errmsg, "Failed to add song '%s' to playlist", argv[1]);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_MPD, "Out of memory\n");
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
player_queue_add(items, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2436,6 +2420,7 @@ mpd_command_count(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
if (ret < 0)
|
||||
{
|
||||
db_query_end(&qp);
|
||||
sqlite3_free(qp.filter);
|
||||
|
||||
ret = asprintf(errmsg, "Could not start query");
|
||||
if (ret < 0)
|
||||
@ -2447,6 +2432,7 @@ mpd_command_count(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
if (ret < 0)
|
||||
{
|
||||
db_query_end(&qp);
|
||||
sqlite3_free(qp.filter);
|
||||
|
||||
ret = asprintf(errmsg, "Could not fetch query count");
|
||||
if (ret < 0)
|
||||
@ -2461,6 +2447,7 @@ mpd_command_count(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
(fci.length / 1000));
|
||||
|
||||
db_query_end(&qp);
|
||||
sqlite3_free(qp.filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2492,6 +2479,7 @@ mpd_command_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
if (ret < 0)
|
||||
{
|
||||
db_query_end(&qp);
|
||||
sqlite3_free(qp.filter);
|
||||
|
||||
ret = asprintf(errmsg, "Could not start query");
|
||||
if (ret < 0)
|
||||
@ -2509,6 +2497,7 @@ mpd_command_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
}
|
||||
|
||||
db_query_end(&qp);
|
||||
sqlite3_free(qp.filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2517,7 +2506,7 @@ static int
|
||||
mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
struct query_params qp;
|
||||
struct queue_item *items;
|
||||
struct player_status status;
|
||||
int ret;
|
||||
|
||||
if (argc < 3 || ((argc - 1) % 2) != 0)
|
||||
@ -2536,9 +2525,11 @@ mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
|
||||
|
||||
mpd_get_query_params_find(argc - 1, argv + 1, &qp);
|
||||
|
||||
items = queueitem_make_byquery(&qp);
|
||||
player_get_status(&status);
|
||||
|
||||
if (!items)
|
||||
ret = db_queue_add_by_query(&qp, status.shuffle, status.item_id);
|
||||
sqlite3_free(qp.filter);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Failed to add songs to playlist");
|
||||
if (ret < 0)
|
||||
@ -2546,8 +2537,6 @@ mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
player_queue_add(items, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2639,6 +2628,7 @@ mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
if (ret < 0)
|
||||
{
|
||||
db_query_end(&qp);
|
||||
sqlite3_free(qp.filter);
|
||||
|
||||
ret = asprintf(errmsg, "Could not start query");
|
||||
if (ret < 0)
|
||||
@ -2682,6 +2672,7 @@ mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
}
|
||||
|
||||
db_query_end(&qp);
|
||||
sqlite3_free(qp.filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3121,6 +3112,7 @@ mpd_command_search(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
if (ret < 0)
|
||||
{
|
||||
db_query_end(&qp);
|
||||
sqlite3_free(qp.filter);
|
||||
|
||||
ret = asprintf(errmsg, "Could not start query");
|
||||
if (ret < 0)
|
||||
@ -3138,6 +3130,7 @@ mpd_command_search(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
}
|
||||
|
||||
db_query_end(&qp);
|
||||
sqlite3_free(qp.filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3146,7 +3139,7 @@ static int
|
||||
mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
{
|
||||
struct query_params qp;
|
||||
struct queue_item *items;
|
||||
struct player_status status;
|
||||
int ret;
|
||||
|
||||
if (argc < 3 || ((argc - 1) % 2) != 0)
|
||||
@ -3165,9 +3158,11 @@ mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errm
|
||||
|
||||
mpd_get_query_params_search(argc - 1, argv + 1, &qp);
|
||||
|
||||
items = queueitem_make_byquery(&qp);
|
||||
player_get_status(&status);
|
||||
|
||||
if (!items)
|
||||
ret = db_queue_add_by_query(&qp, status.shuffle, status.item_id);
|
||||
sqlite3_free(qp.filter);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = asprintf(errmsg, "Failed to add songs to playlist");
|
||||
if (ret < 0)
|
||||
@ -3175,8 +3170,6 @@ mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errm
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
player_queue_add(items, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
908
src/player.c
908
src/player.c
File diff suppressed because it is too large
Load Diff
63
src/player.h
63
src/player.h
@ -5,7 +5,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* AirTunes v2 packet interval in ns */
|
||||
/* (352 samples/packet * 1e9 ns/s) / 44100 samples/s = 7981859 ns/packet */
|
||||
@ -28,6 +27,12 @@ enum play_status {
|
||||
PLAY_PLAYING = 4,
|
||||
};
|
||||
|
||||
enum repeat_mode {
|
||||
REPEAT_OFF = 0,
|
||||
REPEAT_SONG = 1,
|
||||
REPEAT_ALL = 2,
|
||||
};
|
||||
|
||||
struct spk_flags {
|
||||
unsigned selected:1;
|
||||
unsigned has_password:1;
|
||||
@ -44,13 +49,6 @@ struct player_status {
|
||||
|
||||
/* Playlist id */
|
||||
uint32_t plid;
|
||||
/* Playlist version
|
||||
After startup plversion is 0 and gets incremented after each change of the playlist
|
||||
(e. g. after adding/moving/removing items). It is used by mpd clients to recognize if
|
||||
they need to update the current playlist. */
|
||||
uint32_t plversion;
|
||||
/* Playlist length */
|
||||
uint32_t playlistlength;
|
||||
/* Id of the playing file/item in the files database */
|
||||
uint32_t id;
|
||||
/* Item-Id of the playing file/item in the queue */
|
||||
@ -59,14 +57,6 @@ struct player_status {
|
||||
uint32_t pos_ms;
|
||||
/* Length in ms of playing item */
|
||||
uint32_t len_ms;
|
||||
/* Playlist position of playing item*/
|
||||
int pos_pl;
|
||||
/* Item id of next item in playlist */
|
||||
uint32_t next_id;
|
||||
/* Item-Id of the next file/item in the queue */
|
||||
uint32_t next_item_id;
|
||||
/* Playlist position of next item */
|
||||
int next_pos_pl;
|
||||
};
|
||||
|
||||
typedef void (*spk_enum_cb)(uint64_t id, const char *name, int relvol, int absvol, struct spk_flags flags, void *arg);
|
||||
@ -107,13 +97,7 @@ int
|
||||
player_playback_start(uint32_t *id);
|
||||
|
||||
int
|
||||
player_playback_start_byindex(int pos, uint32_t *id);
|
||||
|
||||
int
|
||||
player_playback_start_bypos(int pos, uint32_t *id);
|
||||
|
||||
int
|
||||
player_playback_start_byitemid(uint32_t item_id, uint32_t *id);
|
||||
player_playback_start_byitem(struct db_queue_item *queue_item);
|
||||
|
||||
int
|
||||
player_playback_stop(void);
|
||||
@ -147,39 +131,6 @@ int
|
||||
player_shuffle_set(int enable);
|
||||
|
||||
|
||||
struct queue *
|
||||
player_queue_get_bypos(int count);
|
||||
|
||||
struct queue *
|
||||
player_queue_get_byindex(int pos, int count);
|
||||
|
||||
int
|
||||
player_queue_add(struct queue_item *items, uint32_t *item_id);
|
||||
|
||||
int
|
||||
player_queue_add_next(struct queue_item *items);
|
||||
|
||||
int
|
||||
player_queue_move_bypos(int ps_pos_from, int ps_pos_to);
|
||||
|
||||
int
|
||||
player_queue_move_byindex(int pos_from, int pos_to);
|
||||
|
||||
int
|
||||
player_queue_move_byitemid(uint32_t item_id, int pos_to);
|
||||
|
||||
int
|
||||
player_queue_remove_bypos(int pos);
|
||||
|
||||
int
|
||||
player_queue_remove_byindex(int pos, int count);
|
||||
|
||||
int
|
||||
player_queue_remove_byitemid(uint32_t id);
|
||||
|
||||
void
|
||||
player_queue_clear(void);
|
||||
|
||||
void
|
||||
player_queue_clear_history(void);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user