mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-28 16:15:57 -05:00
Remove LastFM thread now that it can run from the worker thread
This commit is contained in:
parent
0b87c04f57
commit
d870b97142
443
src/lastfm.c
443
src/lastfm.c
@ -28,11 +28,9 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
#include <mxml.h>
|
#include <mxml.h>
|
||||||
#include <event2/event.h>
|
|
||||||
#include <event2/buffer.h>
|
#include <event2/buffer.h>
|
||||||
#include <event2/http.h>
|
#include <event2/http.h>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
@ -43,28 +41,6 @@
|
|||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
|
|
||||||
struct lastfm_command;
|
|
||||||
|
|
||||||
typedef int (*cmd_func)(struct lastfm_command *cmd);
|
|
||||||
|
|
||||||
struct lastfm_command
|
|
||||||
{
|
|
||||||
pthread_mutex_t lck;
|
|
||||||
pthread_cond_t cond;
|
|
||||||
|
|
||||||
cmd_func func;
|
|
||||||
|
|
||||||
int nonblock;
|
|
||||||
|
|
||||||
union {
|
|
||||||
void *noarg;
|
|
||||||
int id;
|
|
||||||
struct keyval *kv;
|
|
||||||
} arg;
|
|
||||||
|
|
||||||
int ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct https_client_ctx
|
struct https_client_ctx
|
||||||
{
|
{
|
||||||
const char *url;
|
const char *url;
|
||||||
@ -72,37 +48,22 @@ struct https_client_ctx
|
|||||||
struct evbuffer *data;
|
struct evbuffer *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* --- Globals --- */
|
|
||||||
// lastfm thread
|
|
||||||
static pthread_t tid_lastfm;
|
|
||||||
|
|
||||||
// Event base, pipes and events
|
|
||||||
struct event_base *evbase_lastfm;
|
|
||||||
static int g_exit_pipe[2];
|
|
||||||
static int g_cmd_pipe[2];
|
|
||||||
static struct event *g_exitev;
|
|
||||||
static struct event *g_cmdev;
|
|
||||||
|
|
||||||
// Tells us if the LastFM thread has been set up
|
|
||||||
static int g_initialized = 0;
|
|
||||||
|
|
||||||
// LastFM becomes disabled if we get a scrobble, try initialising session,
|
// LastFM becomes disabled if we get a scrobble, try initialising session,
|
||||||
// but can't (probably no session key in db because user does not use LastFM)
|
// but can't (probably no session key in db because user does not use LastFM)
|
||||||
static int g_disabled = 0;
|
static int lastfm_disabled = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The API key and secret (not so secret being open source) is specific to
|
* The API key and secret (not so secret being open source) is specific to
|
||||||
* forked-daapd, and is used to identify forked-daapd and to sign requests
|
* forked-daapd, and is used to identify forked-daapd and to sign requests
|
||||||
*/
|
*/
|
||||||
const char *g_api_key = "579593f2ed3f49673c7364fd1c9c829b";
|
const char *lastfm_api_key = "579593f2ed3f49673c7364fd1c9c829b";
|
||||||
const char *g_secret = "ce45a1d275c10b3edf0ecfa27791cb2b";
|
const char *lastfm_secret = "ce45a1d275c10b3edf0ecfa27791cb2b";
|
||||||
|
|
||||||
const char *api_url = "http://ws.audioscrobbler.com/2.0/";
|
const char *api_url = "http://ws.audioscrobbler.com/2.0/";
|
||||||
const char *auth_url = "https://ws.audioscrobbler.com/2.0/";
|
const char *auth_url = "https://ws.audioscrobbler.com/2.0/";
|
||||||
|
|
||||||
// Session key
|
// Session key
|
||||||
char *g_session_key = NULL;
|
char *lastfm_session_key = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -285,7 +246,7 @@ param_sign(struct keyval *kv)
|
|||||||
gcry_md_write(md_hdl, okv->value, strlen(okv->value));
|
gcry_md_write(md_hdl, okv->value, strlen(okv->value));
|
||||||
}
|
}
|
||||||
|
|
||||||
gcry_md_write(md_hdl, g_secret, strlen(g_secret));
|
gcry_md_write(md_hdl, lastfm_secret, strlen(lastfm_secret));
|
||||||
|
|
||||||
hash_bytes = gcry_md_read(md_hdl, GCRY_MD_MD5);
|
hash_bytes = gcry_md_read(md_hdl, GCRY_MD_MD5);
|
||||||
if (!hash_bytes)
|
if (!hash_bytes)
|
||||||
@ -325,57 +286,7 @@ mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ---------------------------- COMMAND EXECUTION -------------------------- */
|
|
||||||
|
|
||||||
static int
|
|
||||||
send_command(struct lastfm_command *cmd)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!cmd->func)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "BUG: cmd->func is NULL!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = write(g_cmd_pipe[1], &cmd, sizeof(cmd));
|
|
||||||
if (ret != sizeof(cmd))
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not send command: %s\n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nonblock_command(struct lastfm_command *cmd)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = send_command(cmd);
|
|
||||||
if (ret < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Thread: main */
|
|
||||||
static void
|
|
||||||
thread_exit(void)
|
|
||||||
{
|
|
||||||
int dummy = 42;
|
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_LASTFM, "Killing lastfm thread\n");
|
|
||||||
|
|
||||||
if (write(g_exit_pipe[1], &dummy, sizeof(dummy)) != sizeof(dummy))
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not write to exit fd: %s\n", strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------------- MAIN --------------------------------- */
|
/* --------------------------------- MAIN --------------------------------- */
|
||||||
/* Thread: lastfm */
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
request_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
|
request_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
|
||||||
@ -460,10 +371,10 @@ response_proces(struct https_client_ctx *ctx)
|
|||||||
DPRINTF(E_LOG, L_LASTFM, "Got session key from LastFM: %s\n", sk);
|
DPRINTF(E_LOG, L_LASTFM, "Got session key from LastFM: %s\n", sk);
|
||||||
db_admin_add("lastfm_sk", sk);
|
db_admin_add("lastfm_sk", sk);
|
||||||
|
|
||||||
if (g_session_key)
|
if (lastfm_session_key)
|
||||||
free(g_session_key);
|
free(lastfm_session_key);
|
||||||
|
|
||||||
g_session_key = sk;
|
lastfm_session_key = sk;
|
||||||
}
|
}
|
||||||
|
|
||||||
mxmlDelete(tree);
|
mxmlDelete(tree);
|
||||||
@ -529,7 +440,7 @@ request_post(char *method, struct keyval *kv, int auth)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!auth)
|
if (!auth)
|
||||||
ret = keyval_add(kv, "sk", g_session_key);
|
ret = keyval_add(kv, "sk", lastfm_session_key);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -559,17 +470,7 @@ request_post(char *method, struct keyval *kv, int auth)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
login(struct lastfm_command *cmd)
|
scrobble(int id)
|
||||||
{
|
|
||||||
request_post("auth.getMobileSession", cmd->arg.kv, 1);
|
|
||||||
|
|
||||||
keyval_clear(cmd->arg.kv);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
scrobble(struct lastfm_command *cmd)
|
|
||||||
{
|
{
|
||||||
struct media_file_info *mfi;
|
struct media_file_info *mfi;
|
||||||
struct keyval *kv;
|
struct keyval *kv;
|
||||||
@ -578,10 +479,10 @@ scrobble(struct lastfm_command *cmd)
|
|||||||
char timestamp[16];
|
char timestamp[16];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mfi = db_file_fetch_byid(cmd->arg.id);
|
mfi = db_file_fetch_byid(id);
|
||||||
if (!mfi)
|
if (!mfi)
|
||||||
{
|
{
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Scrobble failed, track id %d is unknown\n", cmd->arg.id);
|
DPRINTF(E_LOG, L_LASTFM, "Scrobble failed, track id %d is unknown\n", id);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,8 +506,8 @@ scrobble(struct lastfm_command *cmd)
|
|||||||
snprintf(trackNumber, sizeof(trackNumber), "%" PRIu32, mfi->track);
|
snprintf(trackNumber, sizeof(trackNumber), "%" PRIu32, mfi->track);
|
||||||
snprintf(timestamp, sizeof(timestamp), "%" PRIi64, (int64_t)time(NULL));
|
snprintf(timestamp, sizeof(timestamp), "%" PRIi64, (int64_t)time(NULL));
|
||||||
|
|
||||||
ret = ( (keyval_add(kv, "api_key", g_api_key) == 0) &&
|
ret = ( (keyval_add(kv, "api_key", lastfm_api_key) == 0) &&
|
||||||
(keyval_add(kv, "sk", g_session_key) == 0) &&
|
(keyval_add(kv, "sk", lastfm_session_key) == 0) &&
|
||||||
(keyval_add(kv, "artist", mfi->artist) == 0) &&
|
(keyval_add(kv, "artist", mfi->artist) == 0) &&
|
||||||
(keyval_add(kv, "track", mfi->title) == 0) &&
|
(keyval_add(kv, "track", mfi->title) == 0) &&
|
||||||
(keyval_add(kv, "album", mfi->album) == 0) &&
|
(keyval_add(kv, "album", mfi->album) == 0) &&
|
||||||
@ -621,16 +522,18 @@ scrobble(struct lastfm_command *cmd)
|
|||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
{
|
||||||
keyval_clear(kv);
|
keyval_clear(kv);
|
||||||
|
free(kv);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(E_INFO, L_LASTFM, "Scrobbling '%s' by '%s'\n", keyval_get(kv, "track"), keyval_get(kv, "artist"));
|
DPRINTF(E_INFO, L_LASTFM, "Scrobbling '%s' by '%s'\n", keyval_get(kv, "track"), keyval_get(kv, "artist"));
|
||||||
|
|
||||||
request_post("track.scrobble", kv, 0);
|
ret = request_post("track.scrobble", kv, 0);
|
||||||
|
|
||||||
keyval_clear(kv);
|
keyval_clear(kv);
|
||||||
|
free(kv);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
|
|
||||||
noscrobble:
|
noscrobble:
|
||||||
free_mfi(mfi, 0);
|
free_mfi(mfi, 0);
|
||||||
@ -640,96 +543,12 @@ scrobble(struct lastfm_command *cmd)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void *
|
|
||||||
lastfm(void *arg)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_LASTFM, "Main loop initiating\n");
|
|
||||||
|
|
||||||
ret = db_perthread_init();
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Error: DB init failed\n");
|
|
||||||
pthread_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
event_base_dispatch(evbase_lastfm);
|
|
||||||
|
|
||||||
if (g_initialized)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "LastFM event loop terminated ahead of time!\n");
|
|
||||||
g_initialized = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
db_perthread_deinit();
|
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_LASTFM, "Main loop terminating\n");
|
|
||||||
|
|
||||||
pthread_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
exit_cb(int fd, short what, void *arg)
|
|
||||||
{
|
|
||||||
int dummy;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = read(g_exit_pipe[0], &dummy, sizeof(dummy));
|
|
||||||
if (ret != sizeof(dummy))
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Error reading from exit pipe\n");
|
|
||||||
|
|
||||||
event_base_loopbreak(evbase_lastfm);
|
|
||||||
|
|
||||||
g_initialized = 0;
|
|
||||||
|
|
||||||
event_add(g_exitev, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
command_cb(int fd, short what, void *arg)
|
|
||||||
{
|
|
||||||
struct lastfm_command *cmd;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = read(g_cmd_pipe[0], &cmd, sizeof(cmd));
|
|
||||||
if (ret != sizeof(cmd))
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not read command! (read %d): %s\n", ret, (ret < 0) ? strerror(errno) : "-no error-");
|
|
||||||
goto readd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd->nonblock)
|
|
||||||
{
|
|
||||||
cmd->func(cmd);
|
|
||||||
|
|
||||||
free(cmd);
|
|
||||||
goto readd;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&cmd->lck);
|
|
||||||
|
|
||||||
ret = cmd->func(cmd);
|
|
||||||
cmd->ret = ret;
|
|
||||||
|
|
||||||
pthread_cond_signal(&cmd->cond);
|
|
||||||
pthread_mutex_unlock(&cmd->lck);
|
|
||||||
|
|
||||||
readd:
|
|
||||||
event_add(g_cmdev, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------- Our lastfm API --------------------------- */
|
/* ---------------------------- Our lastfm API --------------------------- */
|
||||||
|
|
||||||
static int
|
|
||||||
lastfm_init(void);
|
|
||||||
|
|
||||||
/* Thread: filescanner */
|
/* Thread: filescanner */
|
||||||
void
|
int
|
||||||
lastfm_login(char *path)
|
lastfm_login(char *path)
|
||||||
{
|
{
|
||||||
struct lastfm_command *cmd;
|
|
||||||
struct keyval *kv;
|
struct keyval *kv;
|
||||||
char *username;
|
char *username;
|
||||||
char *password;
|
char *password;
|
||||||
@ -738,252 +557,66 @@ lastfm_login(char *path)
|
|||||||
DPRINTF(E_DBG, L_LASTFM, "Got LastFM login request\n");
|
DPRINTF(E_DBG, L_LASTFM, "Got LastFM login request\n");
|
||||||
|
|
||||||
// Delete any existing session key
|
// Delete any existing session key
|
||||||
if (g_session_key)
|
if (lastfm_session_key)
|
||||||
free(g_session_key);
|
free(lastfm_session_key);
|
||||||
|
|
||||||
g_session_key = NULL;
|
lastfm_session_key = NULL;
|
||||||
|
|
||||||
db_admin_delete("lastfm_sk");
|
db_admin_delete("lastfm_sk");
|
||||||
|
|
||||||
// Read the credentials file
|
// Read the credentials file
|
||||||
ret = credentials_read(path, &username, &password);
|
ret = credentials_read(path, &username, &password);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return;
|
return -1;
|
||||||
|
|
||||||
// Enable LastFM now that we got a login attempt
|
// Enable LastFM now that we got a login attempt
|
||||||
g_disabled = 0;
|
lastfm_disabled = 0;
|
||||||
|
|
||||||
kv = keyval_alloc();
|
kv = keyval_alloc();
|
||||||
if (!kv)
|
if (!kv)
|
||||||
{
|
{
|
||||||
free(username);
|
free(username);
|
||||||
free(password);
|
free(password);
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ( (keyval_add(kv, "api_key", g_api_key) == 0) &&
|
ret = ( (keyval_add(kv, "api_key", lastfm_api_key) == 0) &&
|
||||||
(keyval_add(kv, "username", username) == 0) &&
|
(keyval_add(kv, "username", username) == 0) &&
|
||||||
(keyval_add(kv, "password", password) == 0) );
|
(keyval_add(kv, "password", password) == 0) );
|
||||||
|
|
||||||
free(username);
|
free(username);
|
||||||
free(password);
|
free(password);
|
||||||
|
|
||||||
if (!ret)
|
// Send the login request
|
||||||
{
|
ret = request_post("auth.getMobileSession", kv, 1);
|
||||||
keyval_clear(kv);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spawn thread
|
keyval_clear(kv);
|
||||||
ret = lastfm_init();
|
free(kv);
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
g_disabled = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
g_initialized = 1;
|
|
||||||
|
|
||||||
// Send login command to the thread
|
return ret;
|
||||||
cmd = (struct lastfm_command *)malloc(sizeof(struct lastfm_command));
|
|
||||||
if (!cmd)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not allocate lastfm_command\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(cmd, 0, sizeof(struct lastfm_command));
|
|
||||||
|
|
||||||
cmd->nonblock = 1;
|
|
||||||
cmd->func = login;
|
|
||||||
cmd->arg.kv = kv;
|
|
||||||
|
|
||||||
nonblock_command(cmd);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Thread: http and player */
|
/* Thread: worker */
|
||||||
int
|
int
|
||||||
lastfm_scrobble(int id)
|
lastfm_scrobble(int id)
|
||||||
{
|
{
|
||||||
struct lastfm_command *cmd;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
DPRINTF(E_DBG, L_LASTFM, "Got LastFM scrobble request\n");
|
DPRINTF(E_DBG, L_LASTFM, "Got LastFM scrobble request\n");
|
||||||
|
|
||||||
// LastFM is disabled because we already tried looking for a session key, but failed
|
// LastFM is disabled because we already tried looking for a session key, but failed
|
||||||
if (g_disabled)
|
if (lastfm_disabled)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// No session key in mem or in db
|
// No session key in mem or in db
|
||||||
if (!g_session_key)
|
if (!lastfm_session_key)
|
||||||
g_session_key = db_admin_get("lastfm_sk");
|
lastfm_session_key = db_admin_get("lastfm_sk");
|
||||||
|
|
||||||
if (!g_session_key)
|
if (!lastfm_session_key)
|
||||||
{
|
{
|
||||||
DPRINTF(E_INFO, L_LASTFM, "No valid LastFM session key\n");
|
DPRINTF(E_INFO, L_LASTFM, "No valid LastFM session key\n");
|
||||||
g_disabled = 1;
|
lastfm_disabled = 1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn LastFM thread
|
return scrobble(id);
|
||||||
ret = lastfm_init();
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
g_disabled = 1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
g_initialized = 1;
|
|
||||||
|
|
||||||
// Send scrobble command to the thread
|
|
||||||
cmd = (struct lastfm_command *)malloc(sizeof(struct lastfm_command));
|
|
||||||
if (!cmd)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not allocate lastfm_command\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(cmd, 0, sizeof(struct lastfm_command));
|
|
||||||
|
|
||||||
cmd->nonblock = 1;
|
|
||||||
cmd->func = scrobble;
|
|
||||||
cmd->arg.id = id;
|
|
||||||
|
|
||||||
nonblock_command(cmd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
lastfm_init(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (g_initialized)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
|
||||||
|
|
||||||
# if defined(__linux__)
|
|
||||||
ret = pipe2(g_exit_pipe, O_CLOEXEC);
|
|
||||||
# else
|
|
||||||
ret = pipe(g_exit_pipe);
|
|
||||||
# endif
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not create pipe: %s\n", strerror(errno));
|
|
||||||
goto exit_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
# if defined(__linux__)
|
|
||||||
ret = pipe2(g_cmd_pipe, O_CLOEXEC);
|
|
||||||
# else
|
|
||||||
ret = pipe(g_cmd_pipe);
|
|
||||||
# endif
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not create command pipe: %s\n", strerror(errno));
|
|
||||||
goto cmd_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
evbase_lastfm = event_base_new();
|
|
||||||
if (!evbase_lastfm)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not create an event base\n");
|
|
||||||
goto evbase_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBEVENT2
|
|
||||||
g_exitev = event_new(evbase_lastfm, g_exit_pipe[0], EV_READ, exit_cb, NULL);
|
|
||||||
if (!g_exitev)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not create exit event\n");
|
|
||||||
goto evnew_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_cmdev = event_new(evbase_lastfm, g_cmd_pipe[0], EV_READ, command_cb, NULL);
|
|
||||||
if (!g_cmdev)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not create cmd event\n");
|
|
||||||
goto evnew_fail;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
g_exitev = (struct event *)malloc(sizeof(struct event));
|
|
||||||
if (!g_exitev)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not create exit event\n");
|
|
||||||
goto evnew_fail;
|
|
||||||
}
|
|
||||||
event_set(g_exitev, g_exit_pipe[0], EV_READ, exit_cb, NULL);
|
|
||||||
event_base_set(evbase_lastfm, g_exitev);
|
|
||||||
|
|
||||||
g_cmdev = (struct event *)malloc(sizeof(struct event));
|
|
||||||
if (!g_cmdev)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not create cmd event\n");
|
|
||||||
goto evnew_fail;
|
|
||||||
}
|
|
||||||
event_set(g_cmdev, g_cmd_pipe[0], EV_READ, command_cb, NULL);
|
|
||||||
event_base_set(evbase_lastfm, g_cmdev);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
event_add(g_exitev, NULL);
|
|
||||||
event_add(g_cmdev, NULL);
|
|
||||||
|
|
||||||
DPRINTF(E_INFO, L_LASTFM, "LastFM thread init\n");
|
|
||||||
|
|
||||||
ret = pthread_create(&tid_lastfm, NULL, lastfm, NULL);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_LASTFM, "Could not spawn LastFM thread: %s\n", strerror(errno));
|
|
||||||
|
|
||||||
goto thread_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
thread_fail:
|
|
||||||
evnew_fail:
|
|
||||||
event_base_free(evbase_lastfm);
|
|
||||||
evbase_lastfm = NULL;
|
|
||||||
|
|
||||||
evbase_fail:
|
|
||||||
close(g_cmd_pipe[0]);
|
|
||||||
close(g_cmd_pipe[1]);
|
|
||||||
|
|
||||||
cmd_fail:
|
|
||||||
close(g_exit_pipe[0]);
|
|
||||||
close(g_exit_pipe[1]);
|
|
||||||
|
|
||||||
exit_fail:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lastfm_deinit(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!g_initialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
curl_global_cleanup();
|
|
||||||
|
|
||||||
thread_exit();
|
|
||||||
|
|
||||||
ret = pthread_join(tid_lastfm, NULL);
|
|
||||||
if (ret != 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_FATAL, L_LASTFM, "Could not join lastfm thread: %s\n", strerror(errno));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free event base (should free events too)
|
|
||||||
event_base_free(evbase_lastfm);
|
|
||||||
|
|
||||||
// Close pipes
|
|
||||||
close(g_cmd_pipe[0]);
|
|
||||||
close(g_cmd_pipe[1]);
|
|
||||||
close(g_exit_pipe[0]);
|
|
||||||
close(g_exit_pipe[1]);
|
|
||||||
}
|
|
||||||
|
@ -2,13 +2,10 @@
|
|||||||
#ifndef __LASTFM_H__
|
#ifndef __LASTFM_H__
|
||||||
#define __LASTFM_H__
|
#define __LASTFM_H__
|
||||||
|
|
||||||
void
|
int
|
||||||
lastfm_login(char *path);
|
lastfm_login(char *path);
|
||||||
|
|
||||||
int
|
int
|
||||||
lastfm_scrobble(int id);
|
lastfm_scrobble(int id);
|
||||||
|
|
||||||
void
|
|
||||||
lastfm_deinit(void);
|
|
||||||
|
|
||||||
#endif /* !__LASTFM_H__ */
|
#endif /* !__LASTFM_H__ */
|
||||||
|
14
src/main.c
14
src/main.c
@ -68,7 +68,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
|||||||
#include "worker.h"
|
#include "worker.h"
|
||||||
|
|
||||||
#ifdef LASTFM
|
#ifdef LASTFM
|
||||||
# include "lastfm.h"
|
# include <curl/curl.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SPOTIFY_H
|
#ifdef HAVE_SPOTIFY_H
|
||||||
# include "spotify.h"
|
# include "spotify.h"
|
||||||
@ -590,6 +590,11 @@ main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
av_log_set_callback(logger_ffmpeg);
|
av_log_set_callback(logger_ffmpeg);
|
||||||
|
|
||||||
|
#ifdef LASTFM
|
||||||
|
/* Initialize libcurl */
|
||||||
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Initialize libgcrypt */
|
/* Initialize libgcrypt */
|
||||||
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
|
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
|
||||||
|
|
||||||
@ -837,10 +842,6 @@ main(int argc, char **argv)
|
|||||||
player_deinit();
|
player_deinit();
|
||||||
|
|
||||||
player_fail:
|
player_fail:
|
||||||
#ifdef LASTFM
|
|
||||||
DPRINTF(E_LOG, L_MAIN, "LastFM deinit\n");
|
|
||||||
lastfm_deinit();
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_SPOTIFY_H
|
#ifdef HAVE_SPOTIFY_H
|
||||||
DPRINTF(E_LOG, L_MAIN, "Spotify deinit\n");
|
DPRINTF(E_LOG, L_MAIN, "Spotify deinit\n");
|
||||||
spotify_deinit();
|
spotify_deinit();
|
||||||
@ -885,6 +886,9 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
signal_block_fail:
|
signal_block_fail:
|
||||||
gcrypt_init_fail:
|
gcrypt_init_fail:
|
||||||
|
#ifdef LASTFM
|
||||||
|
curl_global_cleanup();
|
||||||
|
#endif
|
||||||
#if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 13)
|
#if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 13)
|
||||||
avformat_network_deinit();
|
avformat_network_deinit();
|
||||||
#endif
|
#endif
|
||||||
|
13
src/player.c
13
src/player.c
@ -642,6 +642,17 @@ playcount_inc_cb(void *arg)
|
|||||||
db_file_inc_playcount(*id);
|
db_file_inc_playcount(*id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LASTFM
|
||||||
|
/* Callback from the worker thread (async operation as it may block) */
|
||||||
|
static void
|
||||||
|
scrobble_cb(void *arg)
|
||||||
|
{
|
||||||
|
int *id = arg;
|
||||||
|
|
||||||
|
lastfm_scrobble(*id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Callback from the worker thread
|
/* Callback from the worker thread
|
||||||
* This prepares metadata in the worker thread, since especially the artwork
|
* This prepares metadata in the worker thread, since especially the artwork
|
||||||
* retrieval may take some time. raop_metadata_prepare() is thread safe. The
|
* retrieval may take some time. raop_metadata_prepare() is thread safe. The
|
||||||
@ -1762,7 +1773,7 @@ source_check(void)
|
|||||||
id = (int)cur_playing->id;
|
id = (int)cur_playing->id;
|
||||||
worker_execute(playcount_inc_cb, &id, sizeof(int), 5);
|
worker_execute(playcount_inc_cb, &id, sizeof(int), 5);
|
||||||
#ifdef LASTFM
|
#ifdef LASTFM
|
||||||
lastfm_scrobble(id);
|
worker_execute(scrobble_cb, &id, sizeof(int), 8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Stop playback if:
|
/* Stop playback if:
|
||||||
|
Loading…
Reference in New Issue
Block a user