* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
-/* audioscrobbler protocol version: 1.1
+/* audioscrobbler protocol version: 1.1
* http://audioscrobbler.net/wiki/Protocol1.1
* */
* Preamble
*****************************************************************************/
-#define _GNU_SOURCE
-#include <string.h>
#if defined( WIN32 )
#include <time.h>
#endif
-/*
- * TODO :
- * check meta_engine's state, and remove delaying of metadata reading
- */
+
#include <vlc/vlc.h>
#include <vlc_interface.h>
#include <vlc_meta.h>
vlc_mutex_t lock; /* p_sys mutex */
/* data about audioscrobbler session */
- int i_interval; /* last interval recorded */
- time_t time_last_interval; /* when was it recorded ? */
+ time_t time_next_exchange; /* when can we send data? */
char *psz_submit_host; /* where to submit data ? */
int i_submit_port; /* at which port ? */
char *psz_submit_file; /* in which file ? */
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static void Run ( intf_thread_t * );
+static void Main ( intf_thread_t * );
static int ItemChange ( vlc_object_t *, const char *, vlc_value_t,
vlc_value_t, void * );
static int PlayingChange( vlc_object_t *, const char *, vlc_value_t,
static int AddToQueue ( intf_thread_t *p_this );
static int Handshake ( intf_thread_t *p_sd );
static int ReadMetaData ( intf_thread_t *p_this );
-static int ReadLocalMetaData( intf_thread_t *p_this, input_thread_t *p_input );
void DeleteQueue ( audioscrobbler_queue_t *p_queue );
/*****************************************************************************
set_description( N_("Audioscrobbler submission Plugin") );
add_string( "lastfm-username", "", NULL,
USERNAME_TEXT, USERNAME_LONGTEXT, VLC_FALSE );
- add_string( "lastfm-password", "", NULL,
+ add_password( "lastfm-password", "", NULL,
PASSWORD_TEXT, PASSWORD_LONGTEXT, VLC_FALSE );
set_capability( "interface", 0 );
set_callbacks( Open, Close );
free( p_sys ); \
return VLC_ENOMEM;
-
if( !p_sys )
{
MEM_ERROR
}
+ p_intf->p_sys = p_sys;
+
vlc_mutex_init( p_this, &p_sys->lock );
p_sys_global = p_sys;
p_sys->psz_submit_host = NULL;
p_sys->psz_submit_file = NULL;
p_sys->b_handshaked = VLC_FALSE;
- p_sys->i_interval = 0;
- p_sys->time_last_interval = time( NULL );
+ p_sys->time_next_exchange = time( NULL );
p_sys->psz_username = NULL;
p_sys->b_paused = VLC_FALSE;
p_sys->p_current_song = malloc( sizeof( audioscrobbler_song_t ) );
MALLOC_CHECK( p_sys->p_current_song )
+ time( &p_sys->p_current_song->time_playing );
/* queues can't contain more than 10 songs */
p_sys->p_first_queue->p_queue =
free( p_sys );
}
+/****************************************************************************
+ * Run : create Main() thread
+ * **************************************************************************/
+static void Run( intf_thread_t *p_intf )
+{
+ if( vlc_thread_create( p_intf, "Audioscrobbler", Main, 0, VLC_TRUE ) )
+ msg_Err( p_intf, "failed to create Audioscrobbler thread" );
+}
+
/*****************************************************************************
- * Run : call Handshake() then submit songs
+ * Main : call Handshake() then submit songs
*****************************************************************************/
-static void Run( intf_thread_t *p_this )
+static void Main( intf_thread_t *p_this )
{
char *psz_submit = NULL;
char *psz_submit_song = NULL;
char *p_buffer_pos = NULL;
audioscrobbler_queue_t *p_first_queue;
int i_post_socket;
- /* TODO: remove when meta_engine works */
time_t played_time;
+ vlc_thread_ready( p_this );
+
p_this->p_sys = p_sys_global;
intf_sys_t *p_sys = p_this->p_sys;
/* main loop */
while( !p_this->b_die )
{
- /* verify if there is data to submit
+ /* verify if there is data to submit
* and if waiting interval is elapsed */
if ( ( p_sys->p_first_queue->i_songs_nb > 0 ) &&
- ( time( NULL ) >=
- ( p_sys->time_last_interval + p_sys->i_interval ) ) )
+ ( time( NULL ) >= p_sys->time_next_exchange ) )
{
/* handshake if needed */
if( p_sys->b_handshaked == VLC_FALSE )
{
msg_Dbg( p_this, "Handshaking with last.fm ..." );
-
+
switch( Handshake( p_this ) )
{
case VLC_ENOMEM:
vlc_mutex_unlock ( &p_sys->lock );
intf_UserFatal( p_this, VLC_FALSE,
_("Last.fm username not set"),
- _("Please set an username or disable"
+ _("Please set an username or disable "
"audioscrobbler plugin, and then restart VLC.\n"
"Visit https://www.last.fm/join/ to get an account")
);
default:
/* protocol error : we'll try later */
vlc_mutex_lock ( &p_sys->lock );
- p_sys->i_interval = DEFAULT_INTERVAL;
- time( &p_sys->time_last_interval );
+ time( &p_sys->time_next_exchange );
+ p_sys->time_next_exchange += DEFAULT_INTERVAL;
vlc_mutex_unlock ( &p_sys->lock );
break;
}
+ /* handshake is done or failed, lets start from
+ * beginning to check it out and wait INTERVAL if needed
+ */
+ continue;
}
msg_Dbg( p_this, "Going to submit some data..." );
i_post_socket = net_ConnectTCP( p_this,
p_sys->psz_submit_host, p_sys->i_submit_port);
+ if ( i_post_socket == -1 )
+ {
+ /* If connection fails, we assume we must handshake again */
+ time( &p_sys->time_next_exchange );
+ p_sys->time_next_exchange += DEFAULT_INTERVAL;
+ p_sys->b_handshaked = VLC_FALSE;
+ vlc_mutex_unlock( &p_sys->lock );
+ continue;
+ }
+
/* we transmit the data */
i_net_ret = net_Printf(
VLC_OBJECT(p_this), i_post_socket, NULL,
if ( i_net_ret == -1 )
{
/* If connection fails, we assume we must handshake again */
- p_sys->i_interval = DEFAULT_INTERVAL;
- time( &p_sys->time_last_interval );
+ time( &p_sys->time_next_exchange );
+ p_sys->time_next_exchange += DEFAULT_INTERVAL;
p_sys->b_handshaked = VLC_FALSE;
vlc_mutex_unlock( &p_sys->lock );
continue;
p_buffer_pos = strstr( ( char * ) p_buffer, "INTERVAL" );
if ( p_buffer_pos )
{
- p_sys->i_interval = atoi( p_buffer_pos +
+ time( &p_sys->time_next_exchange );
+ p_sys->time_next_exchange += atoi( p_buffer_pos +
strlen( "INTERVAL " ) );
- time( &p_sys->time_last_interval );
}
p_buffer_pos = strstr( ( char * ) p_buffer, "FAILED" );
if ( p_buffer_pos )
{
/* woops, submission failed */
- msg_Dbg( p_this, p_buffer_pos );
+ msg_Dbg( p_this, "%s", p_buffer_pos );
vlc_mutex_unlock ( &p_sys->lock );
continue;
}
if( p_sys->b_metadata_read == VLC_FALSE )
{
/* we read the metadata of the playing song */
- /* TODO: remove when meta_engine works */
time( &played_time );
played_time -= p_sys->p_current_song->time_playing;
played_time -= p_sys->time_total_pauses;
vlc_mutex_unlock( &p_sys->lock );
- /* TODO: remove when meta_engine works */
- if( played_time > 10 )
+ if( played_time > 20 )
+ /* wait at least 20 secondes before reading the meta data
+ * since the songs must be at least 30s */
{
if ( ReadMetaData( p_this ) == VLC_ENOMEM )
{
{
PL_UNLOCK;
pl_Release( p_playlist );
+
vlc_mutex_lock( &p_sys->lock );
p_sys->b_queued = VLC_TRUE;
p_sys->b_metadata_read = VLC_TRUE;
vlc_mutex_unlock( &p_sys->lock );
+
return VLC_SUCCESS;
}
p_sys->p_current_song->psz_i = encode_URI_component( psz_date );
p_sys->p_current_song->time_playing = epoch;
- p_sys->b_paused = ( p_input->b_dead || !input_GetItem(p_input)->psz_name )
+ char *psz_name = input_item_GetName( input_GetItem( p_input ) );
+ p_sys->b_paused = ( p_input->b_dead || !psz_name )
? VLC_TRUE : VLC_FALSE;
+ free( psz_name );
vlc_mutex_unlock( &p_sys->lock );
stream_t *p_stream;
char *psz_handshake_url = NULL;
uint8_t *p_buffer = NULL;
- char *p_buffer_pos = NULL;
+ char *p_buffer_pos = NULL;
char *psz_url_parser = NULL;
char *psz_buffer_substring;
int i_url_pos, i;
p_buffer_pos = strstr( ( char* ) p_buffer, "INTERVAL" );
if ( p_buffer_pos )
{
- p_sys->i_interval = atoi( p_buffer_pos + strlen( "INTERVAL " ) );
- time( &p_sys->time_last_interval );
+ time( &p_sys->time_next_exchange );
+ p_sys->time_next_exchange +=
+ atoi( p_buffer_pos + strlen( "INTERVAL " ) );
}
p_buffer_pos = strstr( ( char* ) p_buffer, "FAILED" );
if ( p_buffer_pos )
{
/* handshake request failed, sorry */
- msg_Dbg( p_this, p_buffer_pos );
+ msg_Dbg( p_this, "%s", p_buffer_pos );
PROTOCOL_ERROR
}
{
/* protocol has been updated, time to update the code */
msg_Dbg( p_intf, "Protocol updated : plugin may be outdated" );
- msg_Dbg( p_intf, p_buffer_pos );
+ msg_Dbg( p_intf, "%s", p_buffer_pos );
}
else
static int ReadMetaData( intf_thread_t *p_this )
{
playlist_t *p_playlist;
- input_thread_t *p_input = NULL;
+ input_thread_t *p_input = NULL;
vlc_value_t video_val;
- intf_sys_t *p_sys = p_this->p_sys;
+ char *psz_title = NULL;
+ char *psz_artist = NULL;
+ char *psz_album = NULL;
+ char *psz_trackid = NULL;
+ int i_length = -1;
+ vlc_bool_t b_waiting;
+ intf_sys_t *p_sys = p_this->p_sys;
+ int i_status;
p_playlist = pl_Yield( p_this );
PL_LOCK;
var_Change( p_input, "video-es", VLC_VAR_CHOICESCOUNT, &video_val, NULL );
if( ( video_val.i_int > 0 ) || \
- ( input_GetItem(p_input)->i_type == ITEM_TYPE_NET ) )
+ ( input_GetItem( p_input )->i_type == ITEM_TYPE_NET ) )
{
msg_Dbg( p_this, "Not an audio only local file -> no submission");
vlc_object_release( p_input );
return VLC_SUCCESS;
}
- return ReadLocalMetaData( p_this, p_input );
-}
-
-/*****************************************************************************
- * ReadLocalMetaData : Puts current song's meta data in p_sys->p_current_song
- *****************************************************************************/
-static int ReadLocalMetaData( intf_thread_t *p_this, input_thread_t *p_input )
-{
- char *psz_title = NULL;
- char *psz_artist = NULL;
- char *psz_album = NULL;
- char *psz_trackid = NULL;
- int i_length = -1;
- vlc_bool_t b_waiting;
- intf_sys_t *p_sys = p_this->p_sys;
- int i_status;
-
- i_status = input_GetItem(p_input)->p_meta->i_status;
-
#define FREE_INPUT_AND_CHARS \
vlc_object_release( p_input ); \
free( psz_title ); \
return VLC_SUCCESS; \
}
+ char *psz_meta;
#define ALLOC_ITEM_META( a, b ) \
- if ( input_GetItem(p_input)->b ) \
+ psz_meta = input_item_Get##b( input_GetItem( p_input ) ); \
+ if( psz_meta ) \
{ \
- a = encode_URI_component( \
- input_GetItem(p_input)->b ); \
+ a = encode_URI_component( psz_meta ); \
if( !a ) \
{ \
+ free( psz_meta ); \
FREE_INPUT_AND_CHARS \
return VLC_ENOMEM; \
} \
+ free( psz_meta ); \
}
+ i_status = input_GetItem(p_input)->p_meta->i_status;
+
vlc_mutex_lock( &p_sys->lock );
b_waiting = p_sys->b_waiting_meta;
vlc_mutex_unlock( &p_sys->lock );
- /* TODO : replace 1 with ( i_status & ITEM_PREPARSED )
- * when meta_engine works */
- if ( ( b_waiting == VLC_FALSE ) ? 1 : ( i_status & ITEM_META_FETCHED ) )
+ if( i_status & ( !b_waiting ? ITEM_PREPARSED : ITEM_META_FETCHED ) )
{
- ALLOC_ITEM_META( psz_artist, p_meta->psz_artist )
+ ALLOC_ITEM_META( psz_artist, Artist )
else
{
msg_Dbg( p_this, "No artist.." );
WAIT_METADATA_FETCHING( psz_artist )
}
-
- ALLOC_ITEM_META( psz_title, psz_name )
+ psz_meta = input_item_GetTitle( input_GetItem( p_input ) );
+ if( psz_meta )
+ {
+ psz_title = encode_URI_component( psz_meta );
+ if( !psz_title )
+ {
+ free( psz_meta );
+ FREE_INPUT_AND_CHARS
+ return VLC_ENOMEM;
+ }
+ free( psz_meta );
+ }
else
{
msg_Dbg( p_this, "No track name.." );
WAIT_METADATA_FETCHING( psz_title );
}
- ALLOC_ITEM_META( psz_album, p_meta->psz_album )
+ ALLOC_ITEM_META( psz_album, Album )
else
psz_album = calloc( 1, 1 );
- ALLOC_ITEM_META( psz_trackid, p_meta->psz_trackid )
+ ALLOC_ITEM_META( psz_trackid, TrackID )
else
psz_trackid = calloc( 1, 1 );
- i_length = input_GetItem(p_input)->i_duration / 1000000;
+ i_length = input_item_GetDuration( input_GetItem( p_input ) ) / 1000000;
vlc_mutex_lock ( &p_sys->lock );
vlc_mutex_unlock( &p_sys->lock );
msg_Dbg( p_this, "Meta data registered, waiting to be queued" );
-
- FREE_INPUT_AND_CHARS
}
-
- vlc_object_release( p_input );
+
+ FREE_INPUT_AND_CHARS
return VLC_SUCCESS;
#undef FREE_INPUT_AND_CHARS
#undef ALLOC_ITEM_META