mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-27 06:33:21 -05:00
[library] Some refactoring of the library module
Misc refactoring, e.g. alignment of how modules save tracks and playlists, incl use of mfi and pli. Also try to avoid direct calls between library and player.
This commit is contained in:
parent
08e89ffd4f
commit
abdc0d6d27
@ -2182,6 +2182,7 @@ queue_tracks_add_playlist(const char *id, int pos)
|
||||
static int
|
||||
queue_tracks_add_byuris(const char *param, int pos, int *total_count)
|
||||
{
|
||||
struct player_status status;
|
||||
char *uris;
|
||||
char *uri;
|
||||
char *ptr;
|
||||
@ -2227,7 +2228,9 @@ queue_tracks_add_byuris(const char *param, int pos, int *total_count)
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = library_queue_add(uri, pos, &count, NULL);
|
||||
player_get_status(&status);
|
||||
|
||||
ret = library_queue_item_add(uri, pos, status.shuffle, status.item_id, &count, NULL);
|
||||
if (ret != LIBRARY_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_WEB, "Invalid uri '%s'\n", uri);
|
||||
|
428
src/library.c
428
src/library.c
@ -48,12 +48,22 @@
|
||||
#include "listener.h"
|
||||
#include "player.h"
|
||||
|
||||
struct playlist_add_param
|
||||
struct playlist_item_add_param
|
||||
{
|
||||
const char *vp_playlist;
|
||||
const char *vp_item;
|
||||
};
|
||||
|
||||
struct queue_item_add_param
|
||||
{
|
||||
const char *path;
|
||||
int position;
|
||||
char reshuffle;
|
||||
uint32_t item_id;
|
||||
int *count;
|
||||
int *new_item_id;
|
||||
};
|
||||
|
||||
static struct commands_base *cmdbase;
|
||||
static pthread_t tid_library;
|
||||
|
||||
@ -95,27 +105,11 @@ static struct event *updateev;
|
||||
static unsigned int deferred_update_notifications;
|
||||
static short deferred_update_events;
|
||||
|
||||
static bool
|
||||
handle_deferred_update_notifications(void)
|
||||
{
|
||||
time_t update_time;
|
||||
bool ret = (deferred_update_notifications > 0);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Database changed (%d changes)\n", deferred_update_notifications);
|
||||
|
||||
deferred_update_notifications = 0;
|
||||
update_time = time(NULL);
|
||||
db_admin_setint64(DB_ADMIN_DB_UPDATE, (int64_t) update_time);
|
||||
db_admin_setint64(DB_ADMIN_DB_MODIFIED, (int64_t) update_time);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/* ------------------- CALLED BY LIBRARY SOURCE MODULES -------------------- */
|
||||
|
||||
void
|
||||
library_add_media(struct media_file_info *mfi)
|
||||
library_media_save(struct media_file_info *mfi)
|
||||
{
|
||||
if (!mfi->path || !mfi->fname)
|
||||
{
|
||||
@ -138,106 +132,48 @@ library_add_media(struct media_file_info *mfi)
|
||||
}
|
||||
|
||||
int
|
||||
library_queue_add(const char *path, int position, int *count, int *new_item_id)
|
||||
library_playlist_save(struct playlist_info *pli)
|
||||
{
|
||||
struct player_status status;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_LIB, "Add items for path '%s' to the queue\n", path);
|
||||
|
||||
player_get_status(&status);
|
||||
|
||||
ret = LIBRARY_PATH_INVALID;
|
||||
for (i = 0; sources[i] && ret == LIBRARY_PATH_INVALID; i++)
|
||||
if (!pli->path)
|
||||
{
|
||||
if (sources[i]->disabled || !sources[i]->queue_add)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support queue_add\n", sources[i]->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = sources[i]->queue_add(path, position, status.shuffle, status.item_id, count, new_item_id);
|
||||
|
||||
if (ret == LIBRARY_OK)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Items for path '%s' from library source '%s' added to the queue\n", path, sources[i]->name);
|
||||
break;
|
||||
}
|
||||
DPRINTF(E_LOG, L_LIB, "Ignoring playlist file with missing path\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret != LIBRARY_OK)
|
||||
DPRINTF(E_LOG, L_LIB, "Failed to add items for path '%s' to the queue (%d)\n", path, ret);
|
||||
if (!pli->directory_id || !pli->virtual_path)
|
||||
{
|
||||
// Missing informations for virtual_path and directory_id (may) lead to misplaced appearance in mpd clients
|
||||
DPRINTF(E_WARN, L_LIB, "Playlist with missing values (path='%s', directory='%d', virtual_path='%s')\n",
|
||||
pli->path, pli->directory_id, pli->virtual_path);
|
||||
}
|
||||
|
||||
return ret;
|
||||
if (pli->id == 0)
|
||||
return db_pl_add(pli, NULL);
|
||||
else
|
||||
return db_pl_update(pli);
|
||||
}
|
||||
|
||||
int
|
||||
library_add_playlist_info(const char *path, const char *title, const char *virtual_path, enum pl_type type, int parent_pl_id, int dir_id)
|
||||
|
||||
/* ---------------------- LIBRARY ABSTRACTION --------------------- */
|
||||
/* thread: library */
|
||||
|
||||
static bool
|
||||
handle_deferred_update_notifications(void)
|
||||
{
|
||||
struct playlist_info *pli;
|
||||
int plid;
|
||||
int ret;
|
||||
time_t update_time;
|
||||
bool ret = (deferred_update_notifications > 0);
|
||||
|
||||
pli = db_pl_fetch_bypath(path);
|
||||
if (pli)
|
||||
if (ret)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Playlist found ('%s', link %s), updating\n", title, path);
|
||||
DPRINTF(E_DBG, L_LIB, "Database changed (%d changes)\n", deferred_update_notifications);
|
||||
|
||||
plid = pli->id;
|
||||
|
||||
pli->type = type;
|
||||
free(pli->title);
|
||||
pli->title = strdup(title);
|
||||
if (pli->virtual_path)
|
||||
free(pli->virtual_path);
|
||||
pli->virtual_path = safe_strdup(virtual_path);
|
||||
pli->directory_id = dir_id;
|
||||
|
||||
ret = db_pl_update(pli);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LIB, "Error updating playlist ('%s', link %s)\n", title, path);
|
||||
|
||||
free_pli(pli, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
db_pl_clear_items(plid);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Adding playlist ('%s', link %s)\n", title, path);
|
||||
|
||||
pli = (struct playlist_info *)malloc(sizeof(struct playlist_info));
|
||||
if (!pli)
|
||||
{
|
||||
DPRINTF(E_LOG, L_LIB, "Out of memory\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(pli, 0, sizeof(struct playlist_info));
|
||||
|
||||
pli->type = type;
|
||||
pli->title = strdup(title);
|
||||
pli->path = strdup(path);
|
||||
pli->virtual_path = safe_strdup(virtual_path);
|
||||
pli->parent_id = parent_pl_id;
|
||||
pli->directory_id = dir_id;
|
||||
|
||||
ret = db_pl_add(pli, &plid);
|
||||
if ((ret < 0) || (plid < 1))
|
||||
{
|
||||
DPRINTF(E_LOG, L_LIB, "Error adding playlist ('%s', link %s, ret %d, plid %d)\n", title, path, ret, plid);
|
||||
|
||||
free_pli(pli, 0);
|
||||
return -1;
|
||||
}
|
||||
deferred_update_notifications = 0;
|
||||
update_time = time(NULL);
|
||||
db_admin_setint64(DB_ADMIN_DB_UPDATE, (int64_t) update_time);
|
||||
db_admin_setint64(DB_ADMIN_DB_MODIFIED, (int64_t) update_time);
|
||||
}
|
||||
|
||||
free_pli(pli, 0);
|
||||
return plid;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -378,9 +314,135 @@ fullrescan(void *arg, int *ret)
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback to notify listeners of database changes
|
||||
*/
|
||||
static enum command_state
|
||||
playlist_item_add(void *arg, int *retval)
|
||||
{
|
||||
struct playlist_item_add_param *param = arg;
|
||||
int i;
|
||||
int ret = LIBRARY_ERROR;
|
||||
|
||||
DPRINTF(E_DBG, L_LIB, "Adding item '%s' to playlist '%s'\n", param->vp_item, param->vp_playlist);
|
||||
|
||||
for (i = 0; sources[i]; i++)
|
||||
{
|
||||
if (sources[i]->disabled || !sources[i]->playlist_item_add)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support playlist_item_add\n", sources[i]->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = sources[i]->playlist_item_add(param->vp_playlist, param->vp_item);
|
||||
|
||||
if (ret == LIBRARY_OK)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Adding item '%s' to playlist '%s' with library source '%s'\n", param->vp_item, param->vp_playlist, sources[i]->name);
|
||||
listener_notify(LISTENER_STORED_PLAYLIST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*retval = ret;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static enum command_state
|
||||
playlist_remove(void *arg, int *retval)
|
||||
{
|
||||
const char *virtual_path = arg;
|
||||
int i;
|
||||
int ret = LIBRARY_ERROR;
|
||||
|
||||
DPRINTF(E_DBG, L_LIB, "Removing playlist at path '%s'\n", virtual_path);
|
||||
|
||||
for (i = 0; sources[i]; i++)
|
||||
{
|
||||
if (sources[i]->disabled || !sources[i]->playlist_remove)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support playlist_remove\n", sources[i]->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = sources[i]->playlist_remove(virtual_path);
|
||||
|
||||
if (ret == LIBRARY_OK)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Removing playlist '%s' with library source '%s'\n", virtual_path, sources[i]->name);
|
||||
listener_notify(LISTENER_STORED_PLAYLIST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*retval = ret;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static enum command_state
|
||||
queue_item_add(void *arg, int *retval)
|
||||
{
|
||||
struct queue_item_add_param *param = arg;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_LIB, "Add items for path '%s' to the queue\n", param->path);
|
||||
|
||||
ret = LIBRARY_PATH_INVALID;
|
||||
for (i = 0; sources[i] && ret == LIBRARY_PATH_INVALID; i++)
|
||||
{
|
||||
if (sources[i]->disabled || !sources[i]->queue_item_add)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support queue_add\n", sources[i]->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = sources[i]->queue_item_add(param->path, param->position, param->reshuffle, param->item_id, param->count, param->new_item_id);
|
||||
|
||||
if (ret == LIBRARY_OK)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Items for path '%s' from library source '%s' added to the queue\n", param->path, sources[i]->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != LIBRARY_OK)
|
||||
DPRINTF(E_LOG, L_LIB, "Failed to add items for path '%s' to the queue (%d)\n", param->path, ret);
|
||||
|
||||
*retval = ret;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static enum command_state
|
||||
queue_save(void *arg, int *retval)
|
||||
{
|
||||
const char *virtual_path = arg;
|
||||
int i;
|
||||
int ret = LIBRARY_ERROR;
|
||||
|
||||
DPRINTF(E_DBG, L_LIB, "Saving queue to path '%s'\n", virtual_path);
|
||||
|
||||
for (i = 0; sources[i]; i++)
|
||||
{
|
||||
if (sources[i]->disabled || !sources[i]->queue_save)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support queue_save\n", sources[i]->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = sources[i]->queue_save(virtual_path);
|
||||
|
||||
if (ret == LIBRARY_OK)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Saving queue to path '%s' with library source '%s'\n", virtual_path, sources[i]->name);
|
||||
listener_notify(LISTENER_STORED_PLAYLIST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*retval = ret;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
|
||||
// Callback to notify listeners of database changes
|
||||
static void
|
||||
update_trigger_cb(int fd, short what, void *arg)
|
||||
{
|
||||
@ -410,7 +472,7 @@ update_trigger(void *arg, int *retval)
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------- LIBRARY INTERFACE -------------------------- */
|
||||
/* ----------------------- LIBRARY EXTERNAL INTERFACE ---------------------- */
|
||||
|
||||
void
|
||||
library_rescan()
|
||||
@ -437,6 +499,7 @@ library_metarescan()
|
||||
scanning = true; // TODO Guard "scanning" with a mutex
|
||||
commands_exec_async(cmdbase, metarescan, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
library_fullrescan()
|
||||
{
|
||||
@ -494,39 +557,24 @@ initscan()
|
||||
listener_notify(LISTENER_UPDATE);
|
||||
}
|
||||
|
||||
/*
|
||||
* @return true if scan is running, otherwise false
|
||||
*/
|
||||
bool
|
||||
library_is_scanning()
|
||||
{
|
||||
return scanning;
|
||||
}
|
||||
|
||||
/*
|
||||
* @param is_scanning true if scan is running, otherwise false
|
||||
*/
|
||||
void
|
||||
library_set_scanning(bool is_scanning)
|
||||
{
|
||||
scanning = is_scanning;
|
||||
}
|
||||
|
||||
/*
|
||||
* @return true if a running scan should be aborted due to imminent shutdown, otherwise false
|
||||
*/
|
||||
bool
|
||||
library_is_exiting()
|
||||
{
|
||||
return scan_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger for sending the DATABASE event
|
||||
*
|
||||
* Needs to be called, if an update to the database (library tables) occurred. The DATABASE event
|
||||
* is emitted with the delay 'library_update_wait'. It is safe to call this function from any thread.
|
||||
*/
|
||||
void
|
||||
library_update_trigger(short update_events)
|
||||
{
|
||||
@ -547,81 +595,17 @@ library_update_trigger(short update_events)
|
||||
}
|
||||
}
|
||||
|
||||
static enum command_state
|
||||
playlist_add(void *arg, int *retval)
|
||||
{
|
||||
struct playlist_add_param *param = arg;
|
||||
int i;
|
||||
int ret = LIBRARY_ERROR;
|
||||
|
||||
DPRINTF(E_DBG, L_LIB, "Adding item '%s' to playlist '%s'\n", param->vp_item, param->vp_playlist);
|
||||
|
||||
for (i = 0; sources[i]; i++)
|
||||
{
|
||||
if (sources[i]->disabled || !sources[i]->playlist_add)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support playlist_add\n", sources[i]->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = sources[i]->playlist_add(param->vp_playlist, param->vp_item);
|
||||
|
||||
if (ret == LIBRARY_OK)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Adding item '%s' to playlist '%s' with library source '%s'\n", param->vp_item, param->vp_playlist, sources[i]->name);
|
||||
listener_notify(LISTENER_STORED_PLAYLIST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*retval = ret;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
int
|
||||
library_playlist_add(const char *vp_playlist, const char *vp_item)
|
||||
library_playlist_item_add(const char *vp_playlist, const char *vp_item)
|
||||
{
|
||||
struct playlist_add_param param;
|
||||
struct playlist_item_add_param param;
|
||||
|
||||
if (library_is_scanning())
|
||||
return -1;
|
||||
|
||||
param.vp_playlist = vp_playlist;
|
||||
param.vp_item = vp_item;
|
||||
return commands_exec_sync(cmdbase, playlist_add, NULL, ¶m);
|
||||
}
|
||||
|
||||
static enum command_state
|
||||
playlist_remove(void *arg, int *retval)
|
||||
{
|
||||
const char *virtual_path;
|
||||
int i;
|
||||
int ret = LIBRARY_ERROR;
|
||||
|
||||
virtual_path = arg;
|
||||
|
||||
DPRINTF(E_DBG, L_LIB, "Removing playlist at path '%s'\n", virtual_path);
|
||||
|
||||
for (i = 0; sources[i]; i++)
|
||||
{
|
||||
if (sources[i]->disabled || !sources[i]->playlist_remove)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support playlist_remove\n", sources[i]->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = sources[i]->playlist_remove(virtual_path);
|
||||
|
||||
if (ret == LIBRARY_OK)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Removing playlist '%s' with library source '%s'\n", virtual_path, sources[i]->name);
|
||||
listener_notify(LISTENER_STORED_PLAYLIST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*retval = ret;
|
||||
return COMMAND_END;
|
||||
return commands_exec_sync(cmdbase, playlist_item_add, NULL, ¶m);
|
||||
}
|
||||
|
||||
int
|
||||
@ -633,39 +617,6 @@ library_playlist_remove(char *virtual_path)
|
||||
return commands_exec_sync(cmdbase, playlist_remove, NULL, virtual_path);
|
||||
}
|
||||
|
||||
static enum command_state
|
||||
queue_save(void *arg, int *retval)
|
||||
{
|
||||
const char *virtual_path;
|
||||
int i;
|
||||
int ret = LIBRARY_ERROR;
|
||||
|
||||
virtual_path = arg;
|
||||
|
||||
DPRINTF(E_DBG, L_LIB, "Saving queue to path '%s'\n", virtual_path);
|
||||
|
||||
for (i = 0; sources[i]; i++)
|
||||
{
|
||||
if (sources[i]->disabled || !sources[i]->queue_save)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Library source '%s' is disabled or does not support queue_save\n", sources[i]->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = sources[i]->queue_save(virtual_path);
|
||||
|
||||
if (ret == LIBRARY_OK)
|
||||
{
|
||||
DPRINTF(E_DBG, L_LIB, "Saving queue to path '%s' with library source '%s'\n", virtual_path, sources[i]->name);
|
||||
listener_notify(LISTENER_STORED_PLAYLIST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*retval = ret;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
int
|
||||
library_queue_save(char *path)
|
||||
{
|
||||
@ -675,15 +626,24 @@ library_queue_save(char *path)
|
||||
return commands_exec_sync(cmdbase, queue_save, NULL, path);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute the function 'func' with the given argument 'arg' in the library thread.
|
||||
*
|
||||
* The pointer passed as argument is freed in the library thread after func returned.
|
||||
*
|
||||
* @param func The function to be executed
|
||||
* @param arg Argument passed to func
|
||||
* @return 0 if triggering the function execution succeeded, -1 on failure.
|
||||
*/
|
||||
int
|
||||
library_queue_item_add(const char *path, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id)
|
||||
{
|
||||
struct queue_item_add_param param;
|
||||
|
||||
if (library_is_scanning())
|
||||
return -1;
|
||||
|
||||
param.path = path;
|
||||
param.position = position;
|
||||
param.reshuffle = reshuffle;
|
||||
param.item_id = item_id;
|
||||
param.count = count;
|
||||
param.new_item_id = new_item_id;
|
||||
|
||||
return commands_exec_sync(cmdbase, queue_item_add, NULL, ¶m);
|
||||
}
|
||||
|
||||
int
|
||||
library_exec_async(command_function func, void *arg)
|
||||
{
|
||||
|
@ -72,9 +72,9 @@ struct library_source
|
||||
int (*fullrescan)(void);
|
||||
|
||||
/*
|
||||
* Save queue as a new playlist under the given virtual path
|
||||
* Add item to playlist
|
||||
*/
|
||||
int (*playlist_add)(const char *vp_playlist, const char *vp_item);
|
||||
int (*playlist_item_add)(const char *vp_playlist, const char *vp_item);
|
||||
|
||||
/*
|
||||
* Removes the playlist under the given virtual path
|
||||
@ -89,17 +89,18 @@ struct library_source
|
||||
/*
|
||||
* Add item for the given path to the current queue
|
||||
*/
|
||||
int (*queue_add)(const char *path, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id);
|
||||
int (*queue_item_add)(const char *path, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id);
|
||||
};
|
||||
|
||||
/* --------------------- Interface towards source backends ----------------- */
|
||||
|
||||
void
|
||||
library_add_media(struct media_file_info *mfi);
|
||||
library_media_save(struct media_file_info *mfi);
|
||||
|
||||
int
|
||||
library_add_playlist_info(const char *path, const char *title, const char *virtual_path, enum pl_type type, int parent_pl_id, int dir_id);
|
||||
library_playlist_save(struct playlist_info *pli);
|
||||
|
||||
int
|
||||
library_queue_add(const char *path, int position, int *count, int *new_item_id);
|
||||
/* ------------------------ Library external interface --------------------- */
|
||||
|
||||
void
|
||||
library_rescan();
|
||||
@ -110,20 +111,35 @@ library_metarescan();
|
||||
void
|
||||
library_fullrescan();
|
||||
|
||||
/*
|
||||
* @return true if scan is running, otherwise false
|
||||
*/
|
||||
bool
|
||||
library_is_scanning();
|
||||
|
||||
/*
|
||||
* @param is_scanning true if scan is running, otherwise false
|
||||
*/
|
||||
void
|
||||
library_set_scanning(bool is_scanning);
|
||||
|
||||
/*
|
||||
* @return true if a running scan should be aborted due to imminent shutdown, otherwise false
|
||||
*/
|
||||
bool
|
||||
library_is_exiting();
|
||||
|
||||
/*
|
||||
* Trigger for sending the DATABASE event
|
||||
*
|
||||
* Needs to be called, if an update to the database (library tables) occurred. The DATABASE event
|
||||
* is emitted with the delay 'library_update_wait'. It is safe to call this function from any thread.
|
||||
*/
|
||||
void
|
||||
library_update_trigger(short update_events);
|
||||
|
||||
int
|
||||
library_playlist_add(const char *vp_playlist, const char *vp_item);
|
||||
library_playlist_item_add(const char *vp_playlist, const char *vp_item);
|
||||
|
||||
int
|
||||
library_playlist_remove(char *virtual_path);
|
||||
@ -131,6 +147,18 @@ library_playlist_remove(char *virtual_path);
|
||||
int
|
||||
library_queue_save(char *path);
|
||||
|
||||
int
|
||||
library_queue_item_add(const char *path, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id);
|
||||
|
||||
/*
|
||||
* Execute the function 'func' with the given argument 'arg' in the library thread.
|
||||
*
|
||||
* The pointer passed as argument is freed in the library thread after func returned.
|
||||
*
|
||||
* @param func The function to be executed
|
||||
* @param arg Argument passed to func
|
||||
* @return 0 if triggering the function execution succeeded, -1 on failure.
|
||||
*/
|
||||
int
|
||||
library_exec_async(command_function func, void *arg);
|
||||
|
||||
|
@ -538,7 +538,7 @@ process_regular_file(const char *file, struct stat *sb, int type, int flags, int
|
||||
}
|
||||
}
|
||||
|
||||
library_add_media(&mfi);
|
||||
library_media_save(&mfi);
|
||||
|
||||
cache_artwork_ping(file, sb->st_mtime, !is_bulkscan);
|
||||
// TODO [artworkcache] If entry in artwork cache exists for no artwork available, delete the entry if media file has embedded artwork
|
||||
@ -676,13 +676,14 @@ check_speciallib(char *path, const char *libtype)
|
||||
|
||||
/* Thread: scan */
|
||||
static int
|
||||
create_virtual_path(char *path, char *virtual_path, int virtual_path_len)
|
||||
virtual_path_make(char *virtual_path, int virtual_path_len, const char *path)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = snprintf(virtual_path, virtual_path_len, "/file:%s", path);
|
||||
if ((ret < 0) || (ret >= virtual_path_len))
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Virtual path /file:%s, PATH_MAX exceeded\n", path);
|
||||
DPRINTF(E_LOG, L_SCAN, "Virtual path '/file:%s', virtual_path_len exceeded (%d/%d)\n", path, ret, virtual_path_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -766,7 +767,7 @@ process_directory(char *path, int parent_id, int flags)
|
||||
|
||||
/* Add/update directories table */
|
||||
|
||||
ret = create_virtual_path(path, virtual_path, sizeof(virtual_path));
|
||||
ret = virtual_path_make(virtual_path, sizeof(virtual_path), path);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
@ -893,7 +894,7 @@ process_parent_directories(char *path)
|
||||
strncpy(buf, path, (ptr - path));
|
||||
buf[(ptr - path)] = '\0';
|
||||
|
||||
ret = create_virtual_path(buf, virtual_path, sizeof(virtual_path));
|
||||
ret = virtual_path_make(virtual_path, sizeof(virtual_path), buf);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
@ -1028,7 +1029,7 @@ get_parent_dir_id(const char *path)
|
||||
|
||||
pathcopy = strdup(path);
|
||||
parent_dir = dirname(pathcopy);
|
||||
ret = create_virtual_path(parent_dir, virtual_path, sizeof(virtual_path));
|
||||
ret = virtual_path_make(virtual_path, sizeof(virtual_path), parent_dir);
|
||||
if (ret == 0)
|
||||
parent_id = db_directory_id_byvirtualpath(virtual_path);
|
||||
else
|
||||
@ -1222,7 +1223,6 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
|
||||
uint32_t path_hash;
|
||||
char *file = path;
|
||||
char resolved_path[PATH_MAX];
|
||||
char *dir;
|
||||
char dir_vpath[PATH_MAX];
|
||||
int type;
|
||||
int i;
|
||||
@ -1291,14 +1291,12 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
// If file was successfully enabled, update the directory id
|
||||
dir = strdup(path);
|
||||
ptr = strrchr(dir, '/');
|
||||
dir[(ptr - dir)] = '\0';
|
||||
|
||||
ret = create_virtual_path(dir, dir_vpath, sizeof(dir_vpath));
|
||||
ret = virtual_path_make(dir_vpath, sizeof(dir_vpath), path);
|
||||
if (ret >= 0)
|
||||
{
|
||||
ptr = strrchr(dir_vpath, '/');
|
||||
*ptr = '\0';
|
||||
|
||||
dir_id = db_directory_id_byvirtualpath(dir_vpath);
|
||||
if (dir_id > 0)
|
||||
{
|
||||
@ -1307,8 +1305,6 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
|
||||
DPRINTF(E_LOG, L_SCAN, "Error updating directory id for file: %s\n", path);
|
||||
}
|
||||
}
|
||||
|
||||
free(dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1719,7 +1715,7 @@ map_media_file_to_queue_item(struct db_queue_item *queue_item, struct media_file
|
||||
}
|
||||
|
||||
static int
|
||||
queue_add_stream(const char *path, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id)
|
||||
queue_item_stream_add(const char *path, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id)
|
||||
{
|
||||
struct media_file_info mfi;
|
||||
struct db_queue_item item;
|
||||
@ -1753,11 +1749,11 @@ queue_add_stream(const char *path, int position, char reshuffle, uint32_t item_i
|
||||
}
|
||||
|
||||
static int
|
||||
queue_add(const char *uri, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id)
|
||||
queue_item_add(const char *uri, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id)
|
||||
{
|
||||
if (strncasecmp(uri, "http://", strlen("http://")) == 0 || strncasecmp(uri, "https://", strlen("https://")) == 0)
|
||||
{
|
||||
queue_add_stream(uri, position, reshuffle, item_id, count, new_item_id);
|
||||
queue_item_stream_add(uri, position, reshuffle, item_id, count, new_item_id);
|
||||
return LIBRARY_OK;
|
||||
}
|
||||
|
||||
@ -1828,7 +1824,7 @@ has_suffix(const char *file, const char *suffix)
|
||||
* Returns NULL on error and a new allocated path on success.
|
||||
*/
|
||||
static char *
|
||||
get_playlist_path(const char *vp_playlist)
|
||||
playlist_path_create(const char *vp_playlist)
|
||||
{
|
||||
const char *path;
|
||||
char *pl_path;
|
||||
@ -1863,27 +1859,6 @@ get_playlist_path(const char *vp_playlist)
|
||||
return pl_path;
|
||||
}
|
||||
|
||||
static int
|
||||
get_playlist_id(const char *pl_path, const char *vp_playlist)
|
||||
{
|
||||
const char *filename;
|
||||
char *title;
|
||||
int dir_id;
|
||||
int pl_id;
|
||||
|
||||
pl_id = db_pl_id_bypath(pl_path);
|
||||
if (pl_id < 0)
|
||||
{
|
||||
dir_id = get_parent_dir_id(pl_path);
|
||||
filename = filename_from_path(pl_path);
|
||||
title = strip_extension(filename);
|
||||
pl_id = library_add_playlist_info(pl_path, title, vp_playlist, PL_PLAIN, 0, dir_id);
|
||||
free(title);
|
||||
}
|
||||
|
||||
return pl_id;
|
||||
}
|
||||
|
||||
static int
|
||||
playlist_add_path(FILE *fp, int pl_id, const char *path)
|
||||
{
|
||||
@ -1950,7 +1925,7 @@ playlist_add_files(FILE *fp, int pl_id, const char *virtual_path)
|
||||
|
||||
memset(&mfi, 0, sizeof(struct media_file_info));
|
||||
scan_metadata_stream(path, &mfi);
|
||||
library_add_media(&mfi);
|
||||
library_media_save(&mfi);
|
||||
free_mfi(&mfi, 1);
|
||||
|
||||
ret = playlist_add_path(fp, pl_id, path);
|
||||
@ -1967,15 +1942,60 @@ playlist_add_files(FILE *fp, int pl_id, const char *virtual_path)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Fills a basic pli template based on a path. Caller can then modify content
|
||||
// before saving the playlist.
|
||||
int
|
||||
playlist_template_fill(struct playlist_info *pli, const char *path)
|
||||
{
|
||||
const char *filename;
|
||||
char virtual_path[PATH_MAX];
|
||||
int ret;
|
||||
|
||||
filename = filename_from_path(path);
|
||||
|
||||
memset(pli, 0, sizeof(struct playlist_info));
|
||||
|
||||
pli->type = PL_PLAIN;
|
||||
pli->path = strdup(path);
|
||||
pli->title = strip_extension(filename); // Will alloc
|
||||
|
||||
ret = virtual_path_make(virtual_path, sizeof(virtual_path), path);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
pli->virtual_path = strip_extension(virtual_path); // Will alloc
|
||||
|
||||
pli->directory_id = get_parent_dir_id(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
playlist_add(const char *vp_playlist, const char *vp_item)
|
||||
playlist_create(const char *path)
|
||||
{
|
||||
struct playlist_info pli;
|
||||
int ret;
|
||||
|
||||
ret = playlist_template_fill(&pli, path);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
ret = library_playlist_save(&pli);
|
||||
free_pli(&pli, 1);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
return db_pl_id_bypath(path);
|
||||
}
|
||||
|
||||
static int
|
||||
playlist_item_add(const char *vp_playlist, const char *vp_item)
|
||||
{
|
||||
char *pl_path;
|
||||
FILE *fp;
|
||||
int pl_id;
|
||||
int ret;
|
||||
|
||||
pl_path = get_playlist_path(vp_playlist);
|
||||
pl_path = playlist_path_create(vp_playlist);
|
||||
if (!pl_path)
|
||||
return LIBRARY_PATH_INVALID;
|
||||
|
||||
@ -1983,31 +2003,36 @@ playlist_add(const char *vp_playlist, const char *vp_item)
|
||||
if (!fp)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Error opening file '%s' for writing: %d\n", pl_path, errno);
|
||||
free(pl_path);
|
||||
return LIBRARY_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pl_id = get_playlist_id(pl_path, vp_playlist);
|
||||
free(pl_path);
|
||||
pl_id = db_pl_id_bypath(pl_path);
|
||||
if (pl_id < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Could not get playlist id for %s\n", vp_playlist);
|
||||
fclose(fp);
|
||||
return LIBRARY_ERROR;
|
||||
pl_id = playlist_create(pl_path);
|
||||
if (pl_id < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = playlist_add_files(fp, pl_id, vp_item);
|
||||
fclose(fp);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Could not add %s to playlist\n", vp_item);
|
||||
return LIBRARY_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
free(pl_path);
|
||||
|
||||
db_pl_ping(pl_id);
|
||||
|
||||
return LIBRARY_OK;
|
||||
|
||||
error:
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
free(pl_path);
|
||||
return LIBRARY_ERROR;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2018,7 +2043,7 @@ playlist_remove(const char *vp_playlist)
|
||||
int pl_id;
|
||||
int ret;
|
||||
|
||||
pl_path = get_playlist_path(vp_playlist);
|
||||
pl_path = playlist_path_create(vp_playlist);
|
||||
if (!pl_path)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Unsupported virtual path '%s'\n", vp_playlist);
|
||||
@ -2059,7 +2084,7 @@ queue_save(const char *virtual_path)
|
||||
int pl_id;
|
||||
int ret;
|
||||
|
||||
pl_path = get_playlist_path(virtual_path);
|
||||
pl_path = playlist_path_create(virtual_path);
|
||||
if (!pl_path)
|
||||
return LIBRARY_PATH_INVALID;
|
||||
|
||||
@ -2067,17 +2092,15 @@ queue_save(const char *virtual_path)
|
||||
if (!fp)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Error opening file '%s' for writing: %d\n", pl_path, errno);
|
||||
free(pl_path);
|
||||
return LIBRARY_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pl_id = get_playlist_id(pl_path, virtual_path);
|
||||
free(pl_path);
|
||||
pl_id = db_pl_id_bypath(pl_path);
|
||||
if (pl_id < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Could not get playlist id for %s\n", virtual_path);
|
||||
fclose(fp);
|
||||
return LIBRARY_ERROR;
|
||||
pl_id = playlist_create(pl_path);
|
||||
if (pl_id < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(&query_params, 0, sizeof(struct query_params));
|
||||
@ -2085,8 +2108,7 @@ queue_save(const char *virtual_path)
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SCAN, "Failed to start queue enum\n");
|
||||
fclose(fp);
|
||||
return LIBRARY_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
while ((ret = db_queue_enum_fetch(&query_params, &queue_item)) == 0 && queue_item.id > 0)
|
||||
@ -2106,7 +2128,7 @@ queue_save(const char *virtual_path)
|
||||
|
||||
memset(&mfi, 0, sizeof(struct media_file_info));
|
||||
scan_metadata_stream(queue_item.path, &mfi);
|
||||
library_add_media(&mfi);
|
||||
library_media_save(&mfi);
|
||||
free_mfi(&mfi, 1);
|
||||
}
|
||||
else
|
||||
@ -2131,7 +2153,9 @@ queue_save(const char *virtual_path)
|
||||
}
|
||||
|
||||
db_queue_enum_end(&query_params);
|
||||
|
||||
fclose(fp);
|
||||
free(pl_path);
|
||||
|
||||
db_pl_ping(pl_id);
|
||||
|
||||
@ -2139,6 +2163,12 @@ queue_save(const char *virtual_path)
|
||||
return LIBRARY_ERROR;
|
||||
|
||||
return LIBRARY_OK;
|
||||
|
||||
error:
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
free(pl_path);
|
||||
return LIBRARY_ERROR;
|
||||
}
|
||||
|
||||
/* Thread: main */
|
||||
@ -2174,8 +2204,8 @@ struct library_source filescanner =
|
||||
.rescan = filescanner_rescan,
|
||||
.metarescan = filescanner_metarescan,
|
||||
.fullrescan = filescanner_fullrescan,
|
||||
.playlist_add = playlist_add,
|
||||
.playlist_item_add = playlist_item_add,
|
||||
.playlist_remove = playlist_remove,
|
||||
.queue_save = queue_save,
|
||||
.queue_add = queue_add,
|
||||
.queue_item_add = queue_item_add,
|
||||
};
|
||||
|
@ -109,7 +109,7 @@ process_url(int pl_id, const char *path, struct media_file_info *mfi)
|
||||
{
|
||||
mfi->id = db_file_id_bypath(path);
|
||||
scan_metadata_stream(path, mfi);
|
||||
library_add_media(mfi);
|
||||
library_media_save(mfi);
|
||||
return db_pl_add_item_bypath(pl_id, path);
|
||||
}
|
||||
|
||||
|
12
src/mpd.c
12
src/mpd.c
@ -1695,6 +1695,7 @@ mpd_queue_add(char *path, bool exact_match, int position)
|
||||
static int
|
||||
mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
|
||||
{
|
||||
struct player_status status;
|
||||
int ret;
|
||||
|
||||
ret = mpd_queue_add(argv[1], false, -1);
|
||||
@ -1707,8 +1708,10 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, st
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
player_get_status(&status);
|
||||
|
||||
// Given path is not in the library, check if it is possible to add as a non-library queue item
|
||||
ret = library_queue_add(argv[1], -1, NULL, NULL);
|
||||
ret = library_queue_item_add(argv[1], -1, status.shuffle, status.item_id, NULL, NULL);
|
||||
if (ret != LIBRARY_OK)
|
||||
{
|
||||
*errmsg = safe_asprintf("Failed to add song '%s' to playlist (unkown path)", argv[1]);
|
||||
@ -1728,6 +1731,7 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, st
|
||||
static int
|
||||
mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
|
||||
{
|
||||
struct player_status status;
|
||||
int to_pos = -1;
|
||||
int ret;
|
||||
|
||||
@ -1745,8 +1749,10 @@ mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg,
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
player_get_status(&status);
|
||||
|
||||
// Given path is not in the library, directly add it as a new queue item
|
||||
ret = library_queue_add(argv[1], to_pos, NULL, NULL);
|
||||
ret = library_queue_item_add(argv[1], to_pos, status.shuffle, status.item_id, NULL, NULL);
|
||||
if (ret != LIBRARY_OK)
|
||||
{
|
||||
*errmsg = safe_asprintf("Failed to add song '%s' to playlist (unkown path)", argv[1]);
|
||||
@ -2510,7 +2516,7 @@ mpd_command_playlistadd(struct evbuffer *evbuf, int argc, char **argv, char **er
|
||||
|
||||
vp_item = prepend_slash(argv[2]);
|
||||
|
||||
ret = library_playlist_add(vp_playlist, vp_item);
|
||||
ret = library_playlist_item_add(vp_playlist, vp_item);
|
||||
free(vp_playlist);
|
||||
free(vp_item);
|
||||
if (ret < 0)
|
||||
|
@ -1239,7 +1239,7 @@ queue_add_playlist(const char *uri, int position, char reshuffle, uint32_t item_
|
||||
}
|
||||
|
||||
static int
|
||||
queue_add(const char *uri, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id)
|
||||
queue_item_add(const char *uri, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id)
|
||||
{
|
||||
if (strncasecmp(uri, "spotify:track:", strlen("spotify:track:")) == 0)
|
||||
{
|
||||
@ -1423,7 +1423,7 @@ track_add(struct spotify_track *track, struct spotify_album *album, const char *
|
||||
|
||||
map_track_to_mfi(&mfi, track, album, pl_name);
|
||||
|
||||
library_add_media(&mfi);
|
||||
library_media_save(&mfi);
|
||||
|
||||
free_mfi(&mfi, 1);
|
||||
}
|
||||
@ -1571,6 +1571,23 @@ scan_playlist_tracks(const char *playlist_tracks_endpoint_uri, int plid)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
map_playlist_to_pli(struct playlist_info *pli, struct spotify_playlist *playlist)
|
||||
{
|
||||
|
||||
pli->type = PL_PLAIN;
|
||||
pli->path = strdup(playlist->uri);
|
||||
pli->title = safe_strdup(playlist->name);
|
||||
|
||||
pli->parent_id = spotify_base_plid;
|
||||
pli->directory_id = DIR_SPOTIFY;
|
||||
|
||||
if (playlist->owner)
|
||||
pli->virtual_path = safe_asprintf("/spotify:/%s (%s)", playlist->name, playlist->owner);
|
||||
else
|
||||
pli->virtual_path = safe_asprintf("/spotify:/%s", playlist->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a saved playlist to the library
|
||||
*/
|
||||
@ -1578,8 +1595,8 @@ static int
|
||||
saved_playlist_add(json_object *item, int index, int total, void *arg)
|
||||
{
|
||||
struct spotify_playlist playlist;
|
||||
char virtual_path[PATH_MAX];
|
||||
int plid;
|
||||
struct playlist_info pli;
|
||||
int pl_id;
|
||||
|
||||
// Map playlist information
|
||||
parse_metadata_playlist(item, &playlist);
|
||||
@ -1592,21 +1609,17 @@ saved_playlist_add(json_object *item, int index, int total, void *arg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (playlist.owner)
|
||||
{
|
||||
snprintf(virtual_path, PATH_MAX, "/spotify:/%s (%s)", playlist.name, playlist.owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(virtual_path, PATH_MAX, "/spotify:/%s", playlist.name);
|
||||
}
|
||||
memset(&pli, 0, sizeof(struct playlist_info));
|
||||
|
||||
db_transaction_begin();
|
||||
plid = library_add_playlist_info(playlist.uri, playlist.name, virtual_path, PL_PLAIN, spotify_base_plid, DIR_SPOTIFY);
|
||||
db_transaction_end();
|
||||
map_playlist_to_pli(&pli, &playlist);
|
||||
|
||||
if (plid > 0)
|
||||
scan_playlist_tracks(playlist.tracks_href, plid);
|
||||
library_playlist_save(&pli);
|
||||
pl_id = db_pl_id_bypath(pli.path);
|
||||
|
||||
free_pli(&pli, 1);
|
||||
|
||||
if (pl_id > 0)
|
||||
scan_playlist_tracks(playlist.tracks_href, pl_id);
|
||||
else
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Error adding playlist: '%s' (%s) \n", playlist.name, playlist.uri);
|
||||
|
||||
@ -1633,8 +1646,19 @@ scan_playlists()
|
||||
static void
|
||||
create_saved_tracks_playlist()
|
||||
{
|
||||
spotify_saved_plid = library_add_playlist_info("spotify:savedtracks", "Spotify Saved", "/spotify:/Spotify Saved", PL_PLAIN, spotify_base_plid, DIR_SPOTIFY);
|
||||
struct playlist_info pli =
|
||||
{
|
||||
.path = "spotify:savedtracks",
|
||||
.title = "Spotify Saved",
|
||||
.virtual_path = "/spotify:/Spotify Saved",
|
||||
.type = PL_PLAIN,
|
||||
.parent_id = spotify_base_plid,
|
||||
.directory_id = DIR_SPOTIFY,
|
||||
};
|
||||
|
||||
library_playlist_save(&pli);
|
||||
|
||||
spotify_saved_plid = db_pl_id_bypath(pli.path);
|
||||
if (spotify_saved_plid <= 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Error adding playlist for saved tracks\n");
|
||||
@ -1649,17 +1673,25 @@ static void
|
||||
create_base_playlist()
|
||||
{
|
||||
cfg_t *spotify_cfg;
|
||||
int ret;
|
||||
struct playlist_info pli =
|
||||
{
|
||||
.path = "spotify:playlistfolder",
|
||||
.title = "Spotify",
|
||||
.type = PL_FOLDER,
|
||||
};
|
||||
|
||||
spotify_base_plid = 0;
|
||||
spotify_cfg = cfg_getsec(cfg, "spotify");
|
||||
if (!cfg_getbool(spotify_cfg, "base_playlist_disable"))
|
||||
if (cfg_getbool(spotify_cfg, "base_playlist_disable"))
|
||||
return;
|
||||
|
||||
library_playlist_save(&pli);
|
||||
|
||||
spotify_base_plid = db_pl_id_bypath(pli.path);
|
||||
if (spotify_base_plid < 0)
|
||||
{
|
||||
ret = library_add_playlist_info("spotify:playlistfolder", "Spotify", NULL, PL_FOLDER, 0, 0);
|
||||
if (ret < 0)
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Error adding base playlist\n");
|
||||
else
|
||||
spotify_base_plid = ret;
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Error adding base playlist\n");
|
||||
spotify_base_plid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1968,6 +2000,6 @@ struct library_source spotifyscanner =
|
||||
.metarescan = rescan,
|
||||
.initscan = initscan,
|
||||
.fullrescan = fullrescan,
|
||||
.queue_add = queue_add,
|
||||
.queue_item_add = queue_item_add,
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user