<div dir="ltr">Hi, The reply to option is now working properly for me. I ended mailing up the fixed patch as a new one twice. I could try sending as a reply again but I do not want to spam the list in case it doesn't work out. Can you check out this email <a href="https://mailman.videolan.org/pipermail/vlc-devel/2020-March/131919.html">https://mailman.videolan.org/pipermail/vlc-devel/2020-March/131919.html</a> instead and continue further discussion in it or should I try to send as a reply again here?</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Mar 7, 2020 at 1:17 PM Kartik Ohri <<a href="mailto:kartikohri13@gmail.com">kartikohri13@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr">On Wed, Mar 4, 2020 at 2:19 AM Thomas Guillem <<a href="mailto:thomas@gllm.fr" target="_blank">thomas@gllm.fr</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
<br>
On Tue, Mar 3, 2020, at 20:05, Kartik Ohri <a href="mailto:kartikohri13@gmail.com" target="_blank">kartikohri13@gmail.com</a> wrote:<br>
> VLC already has the audioscrobbler module to submit scrobbles to<br>
> <a href="http://last.fm" rel="noreferrer" target="_blank">last.fm</a> and other services with a similar API. This module extends<br>
> that functionality to allow submission of listens to ListenBrainz.<br>
> The existing audioscrobbler module is incompatible with ListenBrainz<br>
> due to difference in authentication procedures and REST API for<br>
> submissions.<br>
> <br>
> The term scrobble is a trademarked term by Last.fm, therefore the<br>
> term listen used instead. More information about ListenBrainz is<br>
> available at listenbrainz [dot] org.<br>
<br>
Hello,<br>
Thanks a lot for this rewrite.<br>
cf. my coments below:<br>
<br>
> ---<br>
> modules/misc/Makefile.am | 4 +<br>
> modules/misc/listenbrainz.c | 537 ++++++++++++++++++++++++++++++++++++<br>
> 2 files changed, 541 insertions(+)<br>
> create mode 100755 modules/misc/listenbrainz.c<br>
> <br>
> diff --git a/modules/misc/Makefile.am b/modules/misc/Makefile.am<br>
> index 78f9b09710..ed3ef24ee6 100644<br>
> --- a/modules/misc/Makefile.am<br>
> +++ b/modules/misc/Makefile.am<br>
> @@ -8,6 +8,10 @@ libaudioscrobbler_plugin_la_SOURCES = misc/audioscrobbler.c<br>
> libaudioscrobbler_plugin_la_LIBADD = $(SOCKET_LIBS)<br>
> misc_LTLIBRARIES += <a href="http://libaudioscrobbler_plugin.la" rel="noreferrer" target="_blank">libaudioscrobbler_plugin.la</a><br>
> <br>
> +liblistenbrainz_plugin_la_SOURCES = misc/listenbrainz.c<br>
> +liblistenbrainz_plugin_la_LIBADD = $(SOCKET_LIBS)<br>
> +misc_LTLIBRARIES += <a href="http://liblistenbrainz_plugin.la" rel="noreferrer" target="_blank">liblistenbrainz_plugin.la</a><br>
> +<br>
> libexport_plugin_la_SOURCES = \<br>
> misc/playlist/html.c \<br>
> misc/playlist/m3u.c \<br>
> diff --git a/modules/misc/listenbrainz.c b/modules/misc/listenbrainz.c<br>
> new file mode 100755<br>
> index 0000000000..a000bcc6ac<br>
> --- /dev/null<br>
> +++ b/modules/misc/listenbrainz.c<br>
> @@ -0,0 +1,537 @@<br>
> +/*****************************************************************************<br>
> + * listenbrainz.c : ListenBrainz submission plugin<br>
> + * ListenBrainz Submit Listens API 1<br>
> + * <a href="https://api.listenbrainz.org/1/submit-listens" rel="noreferrer" target="_blank">https://api.listenbrainz.org/1/submit-listens</a><br>
<br>
Missing license header, you can take it from any LGPL file.<br>
<br>
> + <br>
> *****************************************************************************<br>
> + * Author: Kartik Ohri <kartikohri13 at gmail dot com><br>
> + <br>
> *****************************************************************************/<br>
> +<br>
> +#ifdef HAVE_CONFIG_H<br>
> +# include "config.h"<br>
> +#endif<br>
> +<br>
> +#include <assert.h><br>
> +#include <time.h><br>
> +<br>
> +#include <vlc_common.h><br>
> +#include <vlc_plugin.h><br>
> +#include <vlc_interface.h><br>
> +#include <vlc_input_item.h><br>
> +#include <vlc_dialog.h><br>
> +#include <vlc_meta.h><br>
> +#include <vlc_memstream.h><br>
> +#include <vlc_stream.h><br>
> +#include <vlc_url.h><br>
> +#include <vlc_tls.h><br>
> +#include <vlc_player.h><br>
> +#include <vlc_playlist.h><br>
> +<br>
> +#define CAPACITY 50<br>
<br>
use vlc_vector instead of limiting the capacity.<br>
<br>
> +<br>
> +typedef struct listen_t<br>
> +{<br>
> + char *psz_artist;<br>
> + char *psz_title;<br>
> + char *psz_album;<br>
> + char *psz_track_number;<br>
> + int i_length;<br>
> + char *psz_musicbrainz_id;<br>
> + time_t date;<br>
> + vlc_tick_t time_start;<br>
> +} listen_t;<br>
> +<br>
> +struct intf_sys_t<br>
> +{<br>
> +<br>
stray line<br>
> + listen_t p_queue[CAPACITY];<br>
> + int i_songs; // number of songs<br>
> +<br>
> + vlc_playlist_t *playlist;<br>
> + struct vlc_playlist_listener_id *playlist_listener;<br>
> + struct vlc_player_listener_id *player_listener;<br>
> +<br>
> + vlc_mutex_t lock;<br>
> + vlc_cond_t wait; // song to submit event<br>
> + vlc_thread_t thread; // thread to submit song<br>
> +<br>
> + vlc_url_t p_submit_url; // where to submit data<br>
> + char *psz_user_token; // authentication token<br>
> +<br>
> +<br>
stray line<br>
<br>
> + listen_t p_current_song;<br>
> + bool b_meta_read; // check if song metadata is <br>
> already read<br>
> +<br>
> + vlc_tick_t time_pause; // time when vlc paused<br>
> + vlc_tick_t time_total_pauses; // total time in pause<br>
> +<br>
> +};<br>
> +<br>
> +static int Open (vlc_object_t *);<br>
> +static void Close (vlc_object_t *);<br>
> +static void *Run (void *);<br>
> +<br>
> +#define USER_TOKEN_TEXT N_("User token")<br>
> +#define USER_TOKEN_LONGTEXT N_("The user token of your ListenBrainz <br>
> account")<br>
> +#define URL_TEXT N_("Submission URL")<br>
> +#define URL_LONGTEXT N_("The URL set for an alternative <br>
> ListenBrainz instance")<br>
> +<br>
> +/****************************************************************************<br>
> + * Module descriptor<br>
> + <br>
> ****************************************************************************/<br>
> +<br>
> +vlc_module_begin ()<br>
> + set_category(CAT_INTERFACE)<br>
> + set_subcategory(SUBCAT_INTERFACE_CONTROL)<br>
> + set_shortname (N_ ("ListenBrainz"))<br>
> + set_description (N_ ("Submit listens to ListenBrainz"))<br>
> + add_string("listenbrainz_user_token", "", USER_TOKEN_TEXT, <br>
> USER_TOKEN_LONGTEXT, false)<br>
> + add_string("listenbrainz_submission_url", "<a href="http://api.listenbrainz.org" rel="noreferrer" target="_blank">api.listenbrainz.org</a>", <br>
> URL_TEXT, URL_LONGTEXT, false)<br>
<br>
options name use generally '-' instead of '_'.<br>
<br>
> + set_capability("interface", 0)<br>
> + set_callbacks(Open, Close)<br>
> +vlc_module_end ()<br>
> +<br>
> +static void DeleteSong (listen_t *p_song)<br>
> +{<br>
> + p_song->psz_artist = NULL;<br>
> + p_song->psz_album = NULL;<br>
> + p_song->psz_title = NULL;<br>
> + p_song->psz_musicbrainz_id = NULL;<br>
> + p_song->psz_track_number = NULL;<br>
<br>
You are missing some free here.<br>
RETRIEVE_METADATA return an allocated str.<br>
<br>
> +}<br>
> +<br>
> +static void ReadMetaData (intf_thread_t *p_this)<br>
> +{<br>
> + bool b_skip = 0;<br>
> + intf_sys_t *p_sys = p_this->p_sys;<br>
> +<br>
> + vlc_player_t *player = vlc_playlist_GetPlayer (p_sys->playlist);<br>
> + input_item_t *item = vlc_player_GetCurrentMedia (player);<br>
> + if ( item == NULL )<br>
> + return;<br>
> +<br>
> + vlc_mutex_lock (&p_sys->lock);<br>
> +<br>
> + p_sys->b_meta_read = true;<br>
> +<br>
> +#define RETRIEVE_METADATA(a, b) do { \<br>
> + char *psz_data = input_item_Get##b(item); \<br>
> + if (psz_data && *psz_data) \<br>
> + a = vlc_uri_encode(psz_data); \<br>
> + free(psz_data); \<br>
> + } while (0)<br>
> +<br>
> + RETRIEVE_METADATA(p_sys->p_current_song.psz_artist, Artist);<br>
> + if ( !p_sys->p_current_song.psz_artist )<br>
> + {<br>
> + msg_Dbg (p_this, "Artist missing.");<br>
> + DeleteSong (&p_sys->p_current_song);<br>
> + b_skip = 1;<br>
> + }<br>
> +<br>
> + RETRIEVE_METADATA(p_sys->p_current_song.psz_title, Title);<br>
> + if ( b_skip || !p_sys->p_current_song.psz_title )<br>
> + {<br>
> + msg_Dbg (p_this, "Track name missing.");<br>
> + DeleteSong (&p_sys->p_current_song);<br>
> + b_skip = 1;<br>
> + }<br>
> +<br>
> + if ( !b_skip )<br>
> + {<br>
> + RETRIEVE_METADATA(p_sys->p_current_song.psz_album, Album);<br>
> + RETRIEVE_METADATA(p_sys->p_current_song.psz_musicbrainz_id, <br>
> TrackID);<br>
> + RETRIEVE_METADATA(p_sys->p_current_song.psz_track_number, <br>
> TrackNum);<br>
> + p_sys->p_current_song.i_length = SEC_FROM_VLC_TICK <br>
> (input_item_GetDuration (item));<br>
> + msg_Dbg (p_this, "Meta data registered");<br>
> + vlc_cond_signal (&p_sys->wait);<br>
> + }<br>
> + vlc_mutex_unlock (&p_sys->lock);<br>
> +<br>
> +#undef RETRIEVE_METADATA<br>
> +<br>
> +}<br>
> +<br>
> +static void Enqueue (intf_thread_t *p_this)<br>
> +{<br>
> + bool b_skip = 0;<br>
> + int64_t i_played_time;<br>
> + intf_sys_t *p_sys = p_this->p_sys;<br>
> +<br>
> + vlc_mutex_lock (&p_sys->lock);<br>
> +<br>
> + if ( !p_sys->p_current_song.psz_artist || <br>
> !*p_sys->p_current_song.psz_artist ||<br>
> + !p_sys->p_current_song.psz_title || <br>
> !*p_sys->p_current_song.psz_title )<br>
> + {<br>
> + msg_Dbg (p_this, "Missing artist or title, not submitting");<br>
> + b_skip = 1;<br>
> + }<br>
> +<br>
> + i_played_time = SEC_FROM_VLC_TICK (vlc_tick_now () - <br>
> p_sys->p_current_song.time_start - p_sys->time_total_pauses);<br>
> +<br>
> + if ( p_sys->p_current_song.i_length == 0 )<br>
> + p_sys->p_current_song.i_length = i_played_time;<br>
> +<br>
> + if ( !b_skip && i_played_time < 30 )<br>
> + {<br>
> + msg_Dbg (p_this, "Song not listened long enough, not <br>
> submitting");<br>
> + b_skip = 1;<br>
> + }<br>
> +<br>
> + if ( !b_skip && p_sys->i_songs >= CAPACITY )<br>
> + {<br>
> + msg_Warn (p_this, "Submission queue is full, not submitting");<br>
> + b_skip = 1;<br>
> + }<br>
> +<br>
> + if ( !b_skip )<br>
> + {<br>
> + msg_Dbg (p_this, "Song will be submitted.");<br>
> +<br>
> + p_sys->p_queue[p_sys->i_songs].psz_artist = <br>
> p_sys->p_current_song.psz_artist;<br>
> + p_sys->p_queue[p_sys->i_songs].psz_title = <br>
> p_sys->p_current_song.psz_title;<br>
> + p_sys->p_queue[p_sys->i_songs].psz_album = <br>
> p_sys->p_current_song.psz_album;<br>
> + p_sys->p_queue[p_sys->i_songs].psz_musicbrainz_id = <br>
> p_sys->p_current_song.psz_musicbrainz_id;<br>
> + p_sys->p_queue[p_sys->i_songs].psz_track_number = <br>
> p_sys->p_current_song.psz_track_number;<br>
> + p_sys->p_queue[p_sys->i_songs].i_length = <br>
> p_sys->p_current_song.i_length;<br>
> + p_sys->p_queue[p_sys->i_songs].date = <br>
> p_sys->p_current_song.date;<br>
> +<br>
> + p_sys->i_songs++;<br>
> + }<br>
> +<br>
> + vlc_cond_signal (&p_sys->wait);<br>
> + DeleteSong (&p_sys->p_current_song);<br>
> + vlc_mutex_unlock (&p_sys->lock);<br>
> +}<br>
> +<br>
> +static void PlayerStateChanged (vlc_player_t *player, enum <br>
> vlc_player_state state, void *data)<br>
> +{<br>
> + intf_thread_t *intf = data;<br>
> + intf_sys_t *p_sys = intf->p_sys;<br>
> +<br>
> + if ( vlc_player_GetVideoTrackCount (player) )<br>
> + {<br>
> + msg_Dbg (intf, "Not an audio-only input, not submitting");<br>
> + return;<br>
> + }<br>
> +<br>
> + if ( !p_sys->b_meta_read && state >= VLC_PLAYER_STATE_PLAYING )<br>
> + {<br>
> + ReadMetaData (intf);<br>
> + return;<br>
> + }<br>
> +<br>
> + switch (state)<br>
> + {<br>
> + case VLC_PLAYER_STATE_STOPPED:<br>
> + Enqueue (intf);<br>
> + break;<br>
> + case VLC_PLAYER_STATE_PAUSED:<br>
> + p_sys->time_pause = vlc_tick_now ();<br>
> + break;<br>
> + case VLC_PLAYER_STATE_PLAYING:<br>
> + if ( p_sys->time_pause > 0 )<br>
> + {<br>
> + vlc_tick_t time_current = vlc_tick_now ();<br>
> + vlc_tick_t time_paused = time_current - <br>
> p_sys->time_pause;<br>
> + p_sys->time_total_pauses += time_paused;<br>
> +<br>
> + // If pause duration more than 60s, check for if <br>
> played part qualifies for individual listen<br>
> + if ( SEC_FROM_VLC_TICK (time_paused) > 60 )<br>
> + {<br>
> + int64_t i_played_time = SEC_FROM_VLC_TICK (<br>
> + time_current - <br>
> p_sys->p_current_song.time_start - p_sys->time_total_pauses);<br>
> +<br>
> + // check whether the item as of now qualifies as a <br>
> listen<br>
> + if ( i_played_time > 30 )<br>
> + {<br>
> + Enqueue (intf);<br>
> + ReadMetaData (intf); // Enqueueing deletes the <br>
> current song so reset the song for the next listen.<br>
> + p_sys->p_current_song.time_start = <br>
> time_current;<br>
> + time (&p_sys->p_current_song.date);<br>
> + p_sys->time_total_pauses = 0;<br>
> + }<br>
> + }<br>
> + p_sys->time_pause = 0;<br>
<br>
YOu should listen to the player time event instead. Cf. the vlc_player_timer API.<br></blockquote><div>To confirm, while checking the time for which a song is played I should vlc_player_timer API instead of manually calculating it. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
> + }<br>
> + break;<br>
> + default:<br>
> + break;<br>
> + }<br>
> +}<br>
> +<br>
> +static void PlaylistItemChanged (vlc_playlist_t *playlist, ssize_t <br>
> index, void *data)<br>
> +{<br>
> + VLC_UNUSED (index);<br>
> +<br>
> + intf_thread_t *intf = data;<br>
> + if ( index > 0 )<br>
> + Enqueue (intf);<br>
> +<br>
> + intf_sys_t *p_sys = intf->p_sys;<br>
> + p_sys->b_meta_read = false;<br>
> +<br>
> + vlc_player_t *player = vlc_playlist_GetPlayer (playlist);<br>
> + input_item_t *item = vlc_player_GetCurrentMedia (player);<br>
> +<br>
> + if ( !item || vlc_player_GetVideoTrackCount (player) )<br>
> + {<br>
> + msg_Dbg (intf, "Invalid item or not an audio-only input.");<br>
> + return;<br>
> + }<br>
> +<br>
> + p_sys->time_total_pauses = 0;<br>
> + time (&p_sys->p_current_song.date); // time sent <br>
> to ListenBrainz<br>
> + p_sys->p_current_song.time_start = vlc_tick_now (); // time used <br>
> locally to check duration of play<br>
> +<br>
> + if ( input_item_IsPreparsed (item) )<br>
> + ReadMetaData (intf);<br>
> +}<br>
> +<br>
> +static int Open (vlc_object_t *p_this)<br>
> +{<br>
> +<br>
> + intf_thread_t *p_intf = (intf_thread_t *) p_this;<br>
> + intf_sys_t *p_sys = calloc (1, sizeof (intf_sys_t));<br>
> + bool b_fail = 0;<br>
> +<br>
> + if ( !p_sys )<br>
> + return VLC_ENOMEM;<br>
> +<br>
> + p_intf->p_sys = p_sys;<br>
> +<br>
> + static struct vlc_playlist_callbacks const playlist_cbs =<br>
> + {<br>
> + .on_current_index_changed = PlaylistItemChanged,<br>
> + };<br>
> + static struct vlc_player_cbs const player_cbs =<br>
> + {<br>
> + .on_state_changed = PlayerStateChanged,<br>
> + };<br>
> +<br>
> + vlc_playlist_t *playlist = p_sys->playlist = <br>
> vlc_intf_GetMainPlaylist (p_intf);<br>
> + vlc_player_t *player = vlc_playlist_GetPlayer (playlist);<br>
> +<br>
> + vlc_playlist_Lock (playlist);<br>
> + p_sys->playlist_listener = vlc_playlist_AddListener (playlist, <br>
> &playlist_cbs, p_intf, false);<br>
> + if ( !p_sys->playlist_listener )<br>
> + {<br>
> + vlc_playlist_Unlock (playlist);<br>
> + b_fail = 1;<br>
> + } else<br>
> + {<br>
> + p_sys->player_listener = vlc_player_AddListener (player, <br>
> &player_cbs, p_intf);<br>
> + vlc_playlist_Unlock (playlist);<br>
> + if ( !p_sys->player_listener )<br>
> + b_fail = 1;<br>
> + }<br>
> + if ( !b_fail )<br>
> + {<br>
> + vlc_mutex_init (&p_sys->lock);<br>
> + vlc_cond_init (&p_sys->wait);<br>
> +<br>
> + if ( vlc_clone (&p_sys->thread, Run, p_intf, <br>
> VLC_THREAD_PRIORITY_LOW) )<br>
> + b_fail = 1;<br>
> + }<br>
> + if ( b_fail )<br>
> + {<br>
> + if ( p_sys->playlist_listener )<br>
> + {<br>
> + vlc_playlist_Lock (playlist);<br>
> + if ( p_sys->player_listener )<br>
> + vlc_player_RemoveListener (player, <br>
> p_sys->player_listener);<br>
> + vlc_playlist_RemoveListener (playlist, <br>
> p_sys->playlist_listener);<br>
> + vlc_playlist_Unlock (playlist);<br>
> + }<br>
> + free (p_sys);<br>
> + return VLC_EGENERIC;<br>
> + }<br>
> + return VLC_SUCCESS;<br>
> +}<br>
> +<br>
> +static void Close (vlc_object_t *p_this)<br>
> +{<br>
> + intf_thread_t *p_intf = (intf_thread_t *) p_this;<br>
> + intf_sys_t *p_sys = p_intf->p_sys;<br>
> + vlc_playlist_t *playlist = p_sys->playlist;<br>
> +<br>
> + vlc_cancel (p_sys->thread);<br>
> + vlc_join (p_sys->thread, NULL);<br>
> +<br>
> + int i;<br>
> + for ( i = 0; i < p_sys->i_songs; i++ )<br>
> + DeleteSong (&p_sys->p_queue[i]);<br>
> + vlc_UrlClean (&p_sys->p_submit_url);<br>
> +<br>
> + vlc_playlist_Lock (playlist);<br>
> + vlc_player_RemoveListener (vlc_playlist_GetPlayer (playlist), <br>
> p_sys->player_listener);<br>
> + vlc_playlist_RemoveListener (playlist, p_sys->playlist_listener);<br>
> + vlc_playlist_Unlock (playlist);<br>
> +<br>
> + free (p_sys);<br>
> +}<br>
> +<br>
> +static void *Run (void *data)<br>
> +{<br>
> + intf_thread_t *p_intf = data;<br>
> + uint8_t p_buffer[1024];<br>
> + int canc = vlc_savecancel ();<br>
> + char *psz_url, *psz_submission_url;<br>
> + int i_ret;<br>
> + bool b_wait = 1;<br>
> +<br>
> + intf_sys_t *p_sys = p_intf->p_sys;<br>
> +<br>
> + while ( 1 )<br>
> + {<br>
> + vlc_restorecancel (canc);<br>
> + if ( b_wait )<br>
> + vlc_tick_wait (vlc_tick_now () + VLC_TICK_FROM_SEC (60)); <br>
> // wait for 1 min<br>
<br>
Why are you waiting for 1min here ?<br></blockquote><div>If the http request fails, wait for 1 min before retrying. <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
> +<br>
> + vlc_mutex_lock (&p_sys->lock);<br>
> + mutex_cleanup_push (&p_sys->lock) ;<br>
> +<br>
> + while ( p_sys->i_songs == 0 )<br>
> + vlc_cond_wait (&p_sys->wait, &p_sys->lock);<br>
> +<br>
> + msg_Dbg (p_intf, "Waiting Over");<br>
> + vlc_cleanup_pop ();<br>
> + vlc_mutex_unlock (&p_sys->lock);<br>
> + canc = vlc_savecancel ();<br>
> +<br>
> + p_sys->psz_user_token = var_InheritString (p_intf, <br>
> "listenbrainz_user_token");<br>
> + msg_Dbg (p_intf, "Begin");<br>
> +<br>
> + if ( EMPTY_STR (p_sys->psz_user_token) )<br>
> + {<br>
> + free (p_sys->psz_user_token);<br>
> + vlc_dialog_display_error (p_intf,<br>
> + _ ("Listenbrainz User Token not <br>
> set"), "%s",<br>
> + _ ("Please set a user token or <br>
> disable the ListenBrainz plugin, and restart VLC.\n"<br>
> + " Visit <br>
> <a href="https://listenbrainz.org/profile/" rel="noreferrer" target="_blank">https://listenbrainz.org/profile/</a> to get a user token."));<br>
> + break;<br>
> + }<br>
<br>
It should be checked from Open() instead (and return VLC_EGENERIC from Open() in that case).<br>
<br>
> +<br>
> + psz_submission_url = var_InheritString (p_intf, <br>
> "listenbrainz_submission_url");<br>
> + if ( !psz_submission_url )<br>
> + break;<br>
> + msg_Dbg (p_intf, "Submission URL Retrieved");<br>
> +<br>
> + i_ret = asprintf (&psz_url, "https://%s/1/submit-listens", <br>
> psz_submission_url);<br>
> + free (psz_submission_url);<br>
> + if ( i_ret == -1 )<br>
> + break;<br>
> + msg_Dbg (p_intf, "Submission URL Parsed");<br>
> +<br>
> + vlc_UrlParse (&p_sys->p_submit_url, psz_url);<br>
> + free (psz_url);<br>
> + msg_Dbg (p_intf, "Submit data");<br>
> +<br>
> + vlc_url_t *url;<br>
> + struct vlc_memstream req, payload;<br>
> + vlc_memstream_open (&payload);<br>
> +<br>
> + vlc_mutex_lock (&p_sys->lock);<br>
> +<br>
> + url = &p_sys->p_submit_url;<br>
> + b_wait = 0;<br>
> +<br>
> + if ( p_sys->i_songs == 1 )<br>
> + vlc_memstream_printf (&payload, <br>
> "{\"listen_type\":\"single\",\"payload\":[");<br>
> + else<br>
> + vlc_memstream_printf (&payload, <br>
> "{\"listen_type\":\"import\",\"payload\":[");<br>
> +<br>
> + for ( int i_song = 0; i_song < p_sys->i_songs; i_song++ )<br>
> + {<br>
> + listen_t *p_song = &p_sys->p_queue[i_song];<br>
> +<br>
> + vlc_memstream_printf (&payload, "{\"listened_at\": %"<br>
> + PRIu64, (uint64_t) <br>
> p_song->date);<br>
> + vlc_memstream_printf (&payload, ", \"track_metadata\": <br>
> {\"artist_name\": \"%s\", ",<br>
> + vlc_uri_decode (p_song->psz_artist));<br>
> + vlc_memstream_printf (&payload, " \"track_name\": \"%s\", <br>
> ", vlc_uri_decode (p_song->psz_title));<br>
> + if ( p_song->psz_album != NULL )<br>
> + vlc_memstream_printf (&payload, " \"release_name\": <br>
> \"%s\"", vlc_uri_decode (p_song->psz_album));<br>
> + if ( p_song->psz_musicbrainz_id != NULL )<br>
> + vlc_memstream_printf (&payload, ", <br>
> \"additional_info\": {\"recording_mbid\":\"%s\"} ",<br>
> + vlc_uri_decode <br>
> (p_song->psz_musicbrainz_id));<br>
> + vlc_memstream_printf (&payload, "}}");<br>
> + }<br>
> +<br>
> + vlc_memstream_printf (&payload, "]}");<br>
> + vlc_mutex_unlock (&p_sys->lock);<br>
> +<br>
> + if ( vlc_memstream_close (&payload) )<br>
> + break;<br>
> +<br>
> + vlc_memstream_open (&req);<br>
> + vlc_memstream_printf (&req, "POST %s HTTP/1.1\r\n", <br>
> url->psz_path);<br>
> + vlc_memstream_printf (&req, "Host: %s\r\n", url->psz_host);<br>
> + vlc_memstream_printf (&req, "Authorization: Token %s\r\n", <br>
> p_sys->psz_user_token);<br>
> + vlc_memstream_puts (&req, "User-Agent: <br>
> "PACKAGE"/"VERSION"\r\n");<br>
> + vlc_memstream_puts (&req, "Connection: close\r\n");<br>
> + vlc_memstream_puts (&req, "Accept-Encoding: identity\r\n");<br>
> + vlc_memstream_printf (&req, "Content-Length: %zu\r\n", <br>
> payload.length);<br>
> + vlc_memstream_puts (&req, "\r\n");<br>
> + vlc_memstream_write (&req, payload.ptr, payload.length);<br>
> + vlc_memstream_puts (&req, "\r\n\r\n");<br>
> +<br>
> + free (payload.ptr);<br>
> +<br>
> + if ( vlc_memstream_close (&req) )<br>
> + break;<br>
> +<br>
> + msg_Dbg (p_intf, "%s", req.ptr);<br>
> + msg_Dbg (p_intf, "Open socket");<br>
> + vlc_tls_client_t *creds = vlc_tls_ClientCreate (VLC_OBJECT <br>
> (p_intf));<br>
> + vlc_tls_t *sock = vlc_tls_SocketOpenTLS (creds, url->psz_host, <br>
> 443, NULL, NULL, NULL);<br>
> +<br>
> + if ( sock == NULL )<br>
> + {<br>
> + b_wait = 1;<br>
> + free (req.ptr);<br>
> + continue;<br>
> + }<br>
> +<br>
> + msg_Warn (p_intf, "Begin transmission");<br>
> + i_ret = vlc_tls_Write (sock, req.ptr, req.length);<br>
> + msg_Warn (p_intf, "Transmission End");<br>
> + free (req.ptr);<br>
> +<br>
> + if ( i_ret == -1 )<br>
> + {<br>
> + b_wait = 1;<br>
> + vlc_tls_Close (sock);<br>
> + msg_Dbg (p_intf, "Close socket");<br>
> + continue;<br>
> + }<br>
> +<br>
> + msg_Warn (p_intf, "Checking response");<br>
> + i_ret = vlc_tls_Read (sock, p_buffer, sizeof (p_buffer) - 1, <br>
> false);<br>
> + msg_Warn (p_intf, "Response: %s", (char *) p_buffer);<br>
> + vlc_tls_Close (sock);<br>
> + if ( i_ret <= 0 )<br>
> + {<br>
> + msg_Warn (p_intf, "No response");<br>
> + continue;<br>
> + }<br>
> + p_buffer[i_ret] = '\0';<br>
> + if ( strstr ((char *) p_buffer, "OK") )<br>
> + {<br>
> + for ( int i = 0; i < p_sys->i_songs; i++ )<br>
> + DeleteSong (&p_sys->p_queue[i]);<br>
> + p_sys->i_songs = 0;<br>
> +<br>
> + b_wait = 1;<br>
> + msg_Dbg (p_intf, "Submission successful!");<br>
> + } else<br>
> + {<br>
> + msg_Warn (p_intf, "Error: %s", (char *) p_buffer);<br>
> + b_wait = 1;<br>
> + continue;<br>
> + }<br>
<br>
YOu should split the Run function into several one:<br>
- prepare payload<br>
- prepare http request<br>
- tls/http post<br>
- etc...<br>
<br>
> + }<br>
> +<br>
> + vlc_restorecancel (canc);<br>
> + return NULL;<br>
> +}<br>
> +<br>
> -- <br>
> 2.20.1<br>
> <br>
> _______________________________________________<br>
> vlc-devel mailing list<br>
> To unsubscribe or modify your subscription options:<br>
> <a href="https://mailman.videolan.org/listinfo/vlc-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/vlc-devel</a><br>
_______________________________________________<br>
vlc-devel mailing list<br>
To unsubscribe or modify your subscription options:<br>
<a href="https://mailman.videolan.org/listinfo/vlc-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/vlc-devel</a></blockquote></div></div>
</blockquote></div>