[vlc-devel] [PATCH] Add module to submit listens to ListenBrainz.
Kartik Ohri
kartikohri13 at gmail.com
Tue Apr 21 06:19:34 CEST 2020
On Mon, Apr 20, 2020 at 9:51 PM Rémi Denis-Courmont <remi at remlab.net> wrote:
> Le maanantaina 20. huhtikuuta 2020, 19.05.15 EEST Kartik Ohri a écrit :
> > VLC already has the audioscrobbler module to submit scrobbles to
> > last.fm and other services with a similar API. This module extends
> > that functionality to allow submission of listens to ListenBrainz.
> > The existing audioscrobbler module is incompatible with ListenBrainz
> > due to difference in authentication procedures and REST API for
> > submissions.
> >
> > The term scrobble is a trademarked term by Last.fm, therefore the
> > term listen used instead. More information about ListenBrainz is
> > available at listenbrainz [dot] org.
> > ---
> > modules/misc/Makefile.am | 4 +
> > modules/misc/listenbrainz.c | 607 ++++++++++++++++++++++++++++++++++++
> > 2 files changed, 611 insertions(+)
> > create mode 100755 modules/misc/listenbrainz.c
> >
> > diff --git a/modules/misc/Makefile.am b/modules/misc/Makefile.am
> > index 78f9b09710..ed3ef24ee6 100644
> > --- a/modules/misc/Makefile.am
> > +++ b/modules/misc/Makefile.am
> > @@ -8,6 +8,10 @@ libaudioscrobbler_plugin_la_SOURCES =
> misc/audioscrobbler.c
> > libaudioscrobbler_plugin_la_LIBADD = $(SOCKET_LIBS)
> > misc_LTLIBRARIES += libaudioscrobbler_plugin.la
> >
> > +liblistenbrainz_plugin_la_SOURCES = misc/listenbrainz.c
> > +liblistenbrainz_plugin_la_LIBADD = $(SOCKET_LIBS)
> > +misc_LTLIBRARIES += liblistenbrainz_plugin.la
> > +
> > libexport_plugin_la_SOURCES = \
> > misc/playlist/html.c \
> > misc/playlist/m3u.c \
> > diff --git a/modules/misc/listenbrainz.c b/modules/misc/listenbrainz.c
> > new file mode 100755
> > index 0000000000..ae251b53e6
> > --- /dev/null
> > +++ b/modules/misc/listenbrainz.c
> > @@ -0,0 +1,607 @@
> >
> +/**************************************************************************
> > *** + * listenbrainz.c : ListenBrainz submission plugin
> > + * ListenBrainz Submit Listens API 1
> > + * https://api.listenbrainz.org/1/submit-listens
> > +
> >
> ***************************************************************************
> > ** + * Copyright (C) 2020 VLC authors and VideoLAN
> > + *
> > + * Author: Kartik Ohri <kartikohri13 at gmail dot com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> it
> > + * under the terms of the GNU Lesser General Public License as
> published by
> > + * the Free Software Foundation; either version 2.1 of the License, or
> + *
> > (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> License
> > + * along with this program; if not, write to the Free Software
> Foundation,
> > + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. +
> >
> ***************************************************************************
> > **/ +
> > +#ifdef HAVE_CONFIG_H
> > +#include "config.h"
> > +#endif
> > +
> > +#include <assert.h>
> > +#include <time.h>
> > +
> > +#include <vlc_common.h>
> > +#include <vlc_plugin.h>
> > +#include <vlc_interface.h>
> > +#include <vlc_input_item.h>
> > +#include <vlc_dialog.h>
> > +#include <vlc_meta.h>
> > +#include <vlc_memstream.h>
> > +#include <vlc_stream.h>
> > +#include <vlc_url.h>
> > +#include <vlc_tls.h>
> > +#include <vlc_player.h>
> > +#include <vlc_playlist.h>
> > +#include <vlc_vector.h>
> > +#include <vlc_interrupt.h>
> > +
> > +typedef struct listen_t {
> > + char *psz_artist;
> > + char *psz_title;
> > + char *psz_album;
> > + char *psz_track_number;
> > + char *psz_musicbrainz_recording_id;
> > + int i_length;
> > + time_t date;
> > +} listen_t;
> > +
> > +typedef struct VLC_VECTOR (listen_t) vlc_vector_listen_t;
> > +
> > +struct intf_sys_t {
> > + vlc_vector_listen_t queue;
> > +
> > + vlc_player_t *player;
> > + struct vlc_player_listener_id *player_listener;
> > + struct vlc_player_timer_id *timer_listener;
> > +
> > + vlc_mutex_t lock;
> > + vlc_cond_t wait; // song to submit event
> > + vlc_thread_t thread; // thread to submit song
> > + vlc_interrupt_t *interrupt;
> > + bool live;
> > +
> > + vlc_url_t p_submit_url; // where to submit data
> > + char *psz_user_token; // authentication token
> > +
> > + listen_t p_current_song;
> > + bool b_meta_read; // check if song metadata is already
> > read + vlc_tick_t time_played;
> > +};
> > +
> > +static int Open (vlc_object_t *);
> > +
> > +static void Close (vlc_object_t *);
> > +
> > +static void *Run (void *);
> > +
> > +#define USER_TOKEN_TEXT N_("User token")
> > +#define USER_TOKEN_LONGTEXT N_("The user token of your ListenBrainz
> > account") +#define URL_TEXT N_("Submission URL")
> > +#define URL_LONGTEXT N_("The URL set for an alternative
> > ListenBrainz instance") +
> > +vlc_module_begin ()
> > + set_category(CAT_INTERFACE)
> > + set_subcategory(SUBCAT_INTERFACE_CONTROL)
> > + set_shortname (N_ ("ListenBrainz"))
> > + set_description (N_ ("Submit listens to ListenBrainz"))
> > + add_string("listenbrainz-user-token" , "" , USER_TOKEN_TEXT ,
> > USER_TOKEN_LONGTEXT , false) +
> add_string("listenbrainz-submission-url"
> > , "api.listenbrainz.org" , URL_TEXT , URL_LONGTEXT , false) +
> > set_capability("interface" , 0)
> > + set_callbacks(Open , Close)
> > +vlc_module_end ()
> > +
> > +static void DeleteSong (listen_t *p_song)
> > +{
> > + FREENULL (p_song->psz_artist);
> > + FREENULL (p_song->psz_album);
> > + FREENULL (p_song->psz_title);
> > + FREENULL (p_song->psz_musicbrainz_recording_id);
> > + FREENULL (p_song->psz_track_number);
> > + p_song->i_length = 0;
> > + p_song->date = 0;
> > +}
> > +
> > +static void DeleteSongQueue(intf_thread_t *p_this)
> > +{
> > + intf_sys_t *p_sys = p_this->p_sys;
> > +
> > + for (size_t i = 0; i < p_sys->queue.size; ++i)
> > + DeleteSong(&p_sys->queue.data[i]);
> > + vlc_vector_clear (&p_sys->queue);
> > +}
> > +
> > +static void ReadMetaData (intf_thread_t *p_this , input_item_t *item)
> > +{
> > + intf_sys_t *p_sys = p_this->p_sys;
> > +
> > + if (item == NULL)
> > + return;
> > +
> > + vlc_mutex_lock (&p_sys->lock);
> > +
> > + p_sys->b_meta_read = true;
> > + time (&p_sys->p_current_song.date);
> > +
> > +/* The retrieved metadata is encoded and then decoded to avoid UTF
> errors
> > + * while sending the JSON payload. Encoding the metadata prevents all
> the
> > + * errors. But the encoded characters are not decoded automatically by
> the
> > + * server and processed as such. Therefore, vlc_decode_uri is called on
> > + * the output of vlc_encode_uri. */
> > +#define RETRIEVE_METADATA(a , b) do {
> \
> > + char *psz_data = input_item_Get##b(item);
> \
> > + if (psz_data && *psz_data) {
> \
> > + free(a);
> \
> > + char *psz_encoded = vlc_uri_encode(psz_data);
> \
> > + if (psz_encoded && *psz_encoded)
> \
> > + a = vlc_uri_decode(psz_encoded);
> \
> > + else
> \
> > + a = 0;
> \
> > + }
> \
> > + free(psz_data);
> \
> > + } while (0)
> > +
> > + RETRIEVE_METADATA(p_sys->p_current_song.psz_artist , AlbumArtist);
> > + if (!p_sys->p_current_song.psz_artist)
> > + {
> > + RETRIEVE_METADATA(p_sys->p_current_song.psz_artist , Artist);
> > + if (!p_sys->p_current_song.psz_artist)
> > + {
> > + DeleteSong (&p_sys->p_current_song);
> > + goto error;
> > + }
> > + }
> > +
> > + RETRIEVE_METADATA(p_sys->p_current_song.psz_title , Title);
> > + if (!p_sys->p_current_song.psz_title)
> > + {
> > + DeleteSong (&p_sys->p_current_song);
> > + goto error;
> > + }
> > +
> > + RETRIEVE_METADATA(p_sys->p_current_song.psz_album , Album);
> > +
> RETRIEVE_METADATA(p_sys->p_current_song.psz_musicbrainz_recording_id ,
> > TrackID); + RETRIEVE_METADATA(p_sys->p_current_song.psz_track_number ,
> > TrackNum); + p_sys->p_current_song.i_length = SEC_FROM_VLC_TICK
> > (input_item_GetDuration (item)); + msg_Dbg (p_this , "Meta data
> > registered");
> > + vlc_cond_signal (&p_sys->wait);
> > +
> > +error:
> > + vlc_mutex_unlock (&p_sys->lock);
> > +
> > +#undef RETRIEVE_METADATA
> > +}
> > +
> > +static void Enqueue (intf_thread_t *p_this)
> > +{
> > + intf_sys_t *p_sys = p_this->p_sys;
> > +
> > + p_sys->b_meta_read = false;
> > + /* Song not yet initialized */
> > + if(p_sys->p_current_song.date == 0)
> > + return;
> > + vlc_mutex_lock (&p_sys->lock);
> > +
> > + if (EMPTY_STR(p_sys->p_current_song.psz_artist) ||
> > + EMPTY_STR(p_sys->p_current_song.psz_title))
> > + {
> > + msg_Dbg (p_this , "Missing artist or title, not submitting");
> > + goto error;
> > + }
> > +
> > + if (p_sys->p_current_song.i_length == 0)
> > + p_sys->p_current_song.i_length = p_sys->time_played;
> > +
> > + if (p_sys->time_played < 30)
> > + {
> > + msg_Dbg (p_this , "Song not listened long enough, not
> submitting");
> > + goto error;
> > + }
> > +
> > + msg_Dbg (p_this , "Song will be submitted.");
> > + /* Transfer the ownership of allocated datas to the queue */
> > + vlc_vector_push (&p_sys->queue , p_sys->p_current_song);
> > + memset(&p_sys->p_current_song, 0, sizeof(p_sys->p_current_song));
> > +
> > + vlc_cond_signal (&p_sys->wait);
> > + vlc_mutex_unlock (&p_sys->lock);
> > + return;
> > +
> > +error:
> > + DeleteSong (&p_sys->p_current_song);
> > + vlc_mutex_unlock (&p_sys->lock);
> > +}
> > +
> > +static void PlayerStateChanged (vlc_player_t *player , enum
> > vlc_player_state state , void *data) +{
> > + intf_thread_t *intf = data;
> > + intf_sys_t *p_sys = intf->p_sys;
> > +
> > + if (vlc_player_GetVideoTrackCount (player))
> > + return;
> > +
> > + if (!p_sys->b_meta_read && state >= VLC_PLAYER_STATE_PLAYING)
> > + {
> > + input_item_t *item = vlc_player_GetCurrentMedia (p_sys->player);
> > + ReadMetaData (intf , item);
> > + return;
> > + }
> > +
> > + if (state == VLC_PLAYER_STATE_STOPPED)
> > + Enqueue (intf);
> > +}
> > +
> > +static void OnTimerUpdate (const struct vlc_player_timer_point *value ,
> > void *data) +{
> > + intf_thread_t *intf = data;
> > + intf_sys_t *p_sys = intf->p_sys;
> > + p_sys->time_played = SEC_FROM_VLC_TICK (value->ts - VLC_TICK_0);
> > +}
> > +
> > +static void OnTimerStopped (vlc_tick_t system_date , void *data)
> > +{
> > + (void) system_date;
> > + (void) data;
> > +}
> > +
> > +static void OnCurrentMediaChanged (vlc_player_t *player , input_item_t
> > *new_media , void *data) +{
> > + intf_thread_t *intf = data;
> > + Enqueue (intf);
> > +
> > + intf_sys_t *p_sys = intf->p_sys;
> > + p_sys->b_meta_read = false;
> > +
> > + if (!new_media || vlc_player_GetVideoTrackCount (player))
> > + return;
> > +
> > + p_sys->time_played = 0;
> > + if (input_item_IsPreparsed (new_media))
> > + ReadMetaData (intf , new_media);
> > +}
> > +
> > +static void OnMetadataChanged (vlc_player_t *player, input_item_t
> *media,
> > void *data) +{
> > + intf_thread_t *intf = data;
> > + Enqueue (intf);
> > +
> > + intf_sys_t *p_sys = intf->p_sys;
> > + p_sys->b_meta_read = false;
> > +
> > + if (vlc_player_GetVideoTrackCount (player))
> > + return;
> > +
> > + p_sys->time_played = 0;
> > + if (input_item_IsPreparsed (media))
> > + ReadMetaData (intf , media);
> > +}
> > +
> > +static char *PreparePayload (intf_thread_t *p_this)
> > +{
> > + intf_sys_t *p_sys = p_this->p_sys;
> > + struct vlc_memstream payload;
> > + vlc_memstream_open (&payload);
> > +
> > + if (p_sys->queue.size == 1)
> > + vlc_memstream_printf (&payload ,
> > "{\"listen_type\":\"single\",\"payload\":["); + else
> > + vlc_memstream_printf (&payload ,
> > "{\"listen_type\":\"import\",\"payload\":["); +
> > + for (int i_song = 0 ; i_song < ( int ) p_sys->queue.size ; i_song++)
> > + {
> > + listen_t *p_song = &p_sys->queue.data[ i_song ];
> > +
> > + vlc_memstream_printf (&payload , "{\"listened_at\": %"PRIu64 , (
> > uint64_t ) p_song->date); + vlc_memstream_printf (&payload , ",
> > \"track_metadata\": {\"artist_name\": \"%s\", " , +
>
> > p_song->psz_artist);
> > + vlc_memstream_printf (&payload , " \"track_name\": \"%s\", " ,
> > p_song->psz_title); + if (!EMPTY_STR (p_song->psz_album))
> > + vlc_memstream_printf (&payload , " \"release_name\":
> \"%s\"" ,
> > p_song->psz_album); + if (!EMPTY_STR
> > (p_song->psz_musicbrainz_recording_id))
> > + vlc_memstream_printf (&payload , ", \"additional_info\":
> > {\"recording_mbid\":\"%s\"} " , +
> > p_song->psz_musicbrainz_recording_id); + vlc_memstream_printf
> > (&payload , "}}");
> > + }
> > +
> > + vlc_memstream_printf (&payload , "]}");
> > +
> > + int i_status = vlc_memstream_close (&payload);
> > + if (!i_status)
> > + {
> > + msg_Dbg (p_this , "Payload: %s" , payload.ptr);
> > + return payload.ptr;
> > + }
> > + else
> > + return NULL;
> > +}
> > +
> > +static char *PrepareRequest (intf_thread_t *p_this , char *payload)
> > +{
> > + intf_sys_t *p_sys = p_this->p_sys;
> > + struct vlc_memstream request;
> > +
> > + vlc_memstream_open (&request);
> > + vlc_memstream_printf (&request , "POST %s HTTP/1.1\r\n" ,
> > p_sys->p_submit_url.psz_path); + vlc_memstream_printf (&request ,
> "Host:
> > %s\r\n" , p_sys->p_submit_url.psz_host); + vlc_memstream_printf
> > (&request , "Authorization: Token %s\r\n" , p_sys->psz_user_token); +
> > vlc_memstream_puts (&request , "User-Agent: "PACKAGE"/"VERSION"\r\n");
> +
> > vlc_memstream_puts (&request , "Connection: close\r\n");
> > + vlc_memstream_puts (&request , "Accept-Encoding: identity\r\n");
> > + vlc_memstream_printf (&request , "Content-Length: %zu\r\n" , strlen
> > (payload)); + vlc_memstream_puts (&request , "\r\n");
> > + vlc_memstream_puts (&request , payload);
> > + vlc_memstream_puts (&request , "\r\n\r\n");
> > +
> > + free (payload);
> > +
> > + int i_status = vlc_memstream_close (&request);
> > + if (!i_status)
> > + return request.ptr;
> > + else
> > + return NULL;
> > +}
> > +
> > +static int SendRequest (intf_thread_t *p_this , char *request)
> > +{
> > + uint8_t p_buffer[1024];
> > + int i_ret;
> > +
> > + intf_sys_t *p_sys = p_this->p_sys;
> > + vlc_tls_client_t *creds = vlc_tls_ClientCreate (VLC_OBJECT
> (p_this));
> > + vlc_tls_t *sock = vlc_tls_SocketOpenTLS (creds ,
> > p_sys->p_submit_url.psz_host , 443 , NULL , NULL , NULL); +
>
> NULL as service seems suspicious here.
>
> > + if (sock == NULL)
> > + {
> > + vlc_tls_ClientDelete(creds);
> > + return VLC_EGENERIC;
> > + }
> > +
> > + i_ret = vlc_tls_Write (sock , request , strlen (request));
> > +
> > + if (i_ret == -1)
>
> That does not seem right either.
>
> > + {
> > + vlc_tls_Close (sock);
> > + vlc_tls_ClientDelete(creds);
> > + return VLC_EGENERIC;
> > + }
> > +
> > + i_ret = vlc_tls_Read (sock , p_buffer , sizeof (p_buffer) - 1 ,
> false);
>
> I can't make sense out of this. Is it really okay to get just one byte?
>
> I do not understand the one byte thing. It would get 1023 bytes if I am
correct. Please explain the issue here. I have understood the issue at
other two comments.
> > + msg_Dbg (p_this , "Response: %s" , ( char * ) p_buffer);
> > + vlc_tls_Close (sock);
> > + vlc_tls_ClientDelete(creds);
> > + if (i_ret <= 0)
> > + {
> > + msg_Warn (p_this , "No response");
> > + return VLC_EGENERIC;
> > + }
> > + p_buffer[ i_ret ] = '\0';
> > +
> > + if (strstr (( char * ) p_buffer , "HTTP/1") == ( char * ) p_buffer)
> > + {
> > + char *status = strchr((char *)p_buffer, '\n');
> > + if(status)
> > + *status = 0;
> > +
> > + if (strstr (( char * ) p_buffer, "200"))
> > + {
> > + msg_Dbg (p_this, "Submission successful!");
> > + return VLC_SUCCESS;
> > + }
> > + else if (strstr (( char * ) p_buffer, "401"))
> > + msg_Warn (p_this, "Authentication Error");
> > + else
> > + msg_Warn (p_this, "Invalid Request");
> > + }
> > + else
> > + msg_Warn (p_this, "Invalid response");
> > +
> > + return VLC_EGENERIC;
> > +}
> > +
> > +static int Configure (intf_thread_t *p_intf)
> > +{
> > + int i_ret;
> > + char *psz_submission_url , *psz_url;
> > + intf_sys_t *p_sys = p_intf->p_sys;
> > +
> > + p_sys->psz_user_token = var_InheritString (p_intf ,
> > "listenbrainz-user-token"); + if (EMPTY_STR (p_sys->psz_user_token))
> > + {
> > + vlc_dialog_display_error (p_intf ,
> > + _ ("ListenBrainz User Token not set")
> ,
> > "%s" , + _ ("Please set a user token or
> > disable the ListenBrainz plugin, and restart VLC.\n" +
>
> > " Visit https://listenbrainz.org/profile/ to get a user
> > token.")); + return VLC_EGENERIC;
> > + }
> > +
> > + psz_submission_url = var_InheritString (p_intf ,
> > "listenbrainz-submission-url"); + if (psz_submission_url)
> > + {
> > + i_ret = asprintf (&psz_url , "https://%s/1/submit-listens" ,
> > psz_submission_url); + free (psz_submission_url);
> > + if (i_ret != -1)
> > + {
> > + vlc_UrlParse (&p_sys->p_submit_url , psz_url);
> > + free (psz_url);
> > + return VLC_SUCCESS;
> > + }
> > + }
> > +
> > + vlc_dialog_display_error (p_intf ,
> > + _ ("ListenBrainz API URL Invalid") , "%s"
> ,
> > + _ ("Please set a valid endpoint URL. The
> > default value is api.listenbrainz.org .")); + return VLC_EGENERIC;
> > +}
> > +
> > +static int Open (vlc_object_t *p_this)
> > +{
> > + intf_thread_t *p_intf = ( intf_thread_t * ) p_this;
> > + intf_sys_t *p_sys = calloc (1 , sizeof (intf_sys_t));
> > +
> > + if (!p_sys)
> > + return VLC_ENOMEM;
> > +
> > + p_intf->p_sys = p_sys;
> > + p_sys->live = true;
> > +
> > + if (Configure (p_intf) != VLC_SUCCESS)
> > + goto error;
> > +
> > + static struct vlc_player_cbs const player_cbs =
> > + {
> > + .on_state_changed = PlayerStateChanged ,
> > + .on_current_media_changed = OnCurrentMediaChanged ,
> > + .on_media_meta_changed = OnMetadataChanged ,
> > + };
> > + static struct vlc_player_timer_cbs const timer_cbs =
> > + {
> > + .on_update = OnTimerUpdate ,
> > + .on_discontinuity = OnTimerStopped ,
> > + };
> > +
> > + vlc_playlist_t *playlist = vlc_intf_GetMainPlaylist (p_intf);
> > + p_sys->player = vlc_playlist_GetPlayer (playlist);
> > +
> > + vlc_player_Lock (p_sys->player);
> > + p_sys->player_listener = vlc_player_AddListener (p_sys->player ,
> > &player_cbs , p_intf); + vlc_player_Unlock (p_sys->player);
> > +
> > + if (!p_sys->player_listener)
> > + goto error;
> > +
> > + p_sys->timer_listener = vlc_player_AddTimer (p_sys->player ,
> > VLC_TICK_FROM_SEC (1) , &timer_cbs , p_intf); + if
> > (!p_sys->timer_listener)
> > + goto error;
> > +
> > + p_sys->interrupt = vlc_interrupt_create();
> > + if (unlikely(p_sys->interrupt == NULL))
> > + goto error;
> > +
> > + vlc_mutex_init (&p_sys->lock);
> > + vlc_cond_init (&p_sys->wait);
> > +
> > + if (vlc_clone (&p_sys->thread , Run , p_intf ,
> > VLC_THREAD_PRIORITY_LOW)) + {
> > + vlc_interrupt_destroy(p_sys->interrupt);
> > + goto error;
> > + }
> > +
> > + vlc_vector_init(&p_sys->queue);
> > + return VLC_SUCCESS;
> > +
> > +error:
> > + if (p_sys->player_listener)
> > + {
> > + vlc_player_Lock (p_sys->player);
> > + vlc_player_RemoveListener (p_sys->player ,
> p_sys->player_listener);
> > + vlc_player_Unlock (p_sys->player);
> > + }
> > + if (p_sys->timer_listener)
> > + vlc_player_RemoveTimer (p_sys->player , p_sys->timer_listener);
> > + vlc_UrlClean (&p_sys->p_submit_url);
> > + free(p_sys->psz_user_token);
> > + free (p_sys);
> > + return VLC_EGENERIC;
> > +}
> > +
> > +static void Close (vlc_object_t *p_this)
> > +{
> > + intf_thread_t *p_intf = ( intf_thread_t * ) p_this;
> > + intf_sys_t *p_sys = p_intf->p_sys;
> > +
> > + vlc_mutex_lock(&p_sys->lock);
> > + p_sys->live = false;
> > + vlc_cond_signal (&p_sys->wait);
> > + vlc_mutex_unlock(&p_sys->lock);
> > +
> > + vlc_interrupt_kill(p_sys->interrupt);
> > + vlc_join (p_sys->thread , NULL);
> > + vlc_interrupt_destroy(p_sys->interrupt);
> > +
> > + vlc_player_Lock (p_sys->player);
> > + vlc_player_RemoveListener (p_sys->player , p_sys->player_listener);
> > + vlc_player_Unlock (p_sys->player);
> > +
> > + vlc_player_RemoveTimer (p_sys->player , p_sys->timer_listener);
> > +
> > + DeleteSongQueue(p_intf);
> > + DeleteSong(&p_sys->p_current_song);
> > +
> > + vlc_UrlClean (&p_sys->p_submit_url);
> > + free(p_sys->psz_user_token);
> > +
> > + free (p_sys);
> > +}
> > +
> > +static void *Run (void *data)
> > +{
> > + intf_thread_t *p_intf = data;
> > + bool b_wait = 0;
> > + char *request , *payload;
> > +
> > + intf_sys_t *p_sys = p_intf->p_sys;
> > +
> > + vlc_interrupt_set(p_sys->interrupt);
> > +
> > + vlc_mutex_lock (&p_sys->lock);
> > + for (;;)
> > + {
> > + if (b_wait)
> > + {
> > + vlc_tick_t deadline = vlc_tick_now() + VLC_TICK_FROM_SEC
> (60);
> > + int ret = 0;
> > + while (p_sys->live && ret == 0) // wait for 1 min
> > + ret = vlc_cond_timedwait (&p_sys->wait , &p_sys->lock,
> > deadline); + }
> > +
> > + while (p_sys->live && p_sys->queue.size == 0)
> > + vlc_cond_wait (&p_sys->wait , &p_sys->lock);
> > +
> > + if (!p_sys->live)
> > + break;
> > +
> > + payload = PreparePayload (p_intf);
> > + vlc_mutex_unlock (&p_sys->lock);
> > +
> > + if (!payload)
> > + {
> > + msg_Warn (p_intf , "Error: Unable to generate payload");
> > + return NULL;
> > + }
> > +
> > + request = PrepareRequest (p_intf , payload);
> > + if (!request)
> > + {
> > + msg_Warn (p_intf , "Error: Unable to generate request
> body");
> > + return NULL;
> > + }
> > +
> > + int ret = SendRequest (p_intf , request);
> > + free(request);
> > +
> > + vlc_mutex_lock (&p_sys->lock);
> > +
> > + if (ret == VLC_SUCCESS)
> > + {
> > + DeleteSongQueue(p_intf);
> > + b_wait = false;
> > + }
> > + else
> > + {
> > + msg_Warn (p_intf , "Error: Could not transmit request");
> > + b_wait = true;
> > + }
> > + }
> > +
> > + vlc_mutex_unlock (&p_sys->lock);
> > + return NULL;
> > +}
> > +
>
>
> --
> 雷米‧德尼-库尔蒙
> http://www.remlab.net/
> Rémi Denis-Courmont
>
>
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20200421/2b00aef1/attachment.html>
More information about the vlc-devel
mailing list