📄 audioscrobbler.c
字号:
"&t%%5B%d%%5D=%s" "&i%%5B%d%%5D=%u" "&o%%5B%d%%5D=P" "&r%%5B%d%%5D=" "&l%%5B%d%%5D=%d" "&b%%5B%d%%5D=%s" "&n%%5B%d%%5D=%s" "&m%%5B%d%%5D=%s", i_song, p_song->psz_a, i_song, p_song->psz_t, i_song, (unsigned)p_song->date, /* HACK: %ju (uintmax_t) unsupported on Windows */ i_song, i_song, i_song, p_song->i_l, i_song, p_song->psz_b, i_song, p_song->psz_n, i_song, p_song->psz_m ) ) { /* Out of memory */ vlc_mutex_unlock( &p_sys->lock ); return; } psz_submit_tmp = psz_submit; if( !asprintf( &psz_submit, "%s%s", psz_submit_tmp, psz_submit_song ) ) { /* Out of memory */ free( psz_submit_tmp ); free( psz_submit_song ); vlc_mutex_unlock( &p_sys->lock ); return; } free( psz_submit_song ); free( psz_submit_tmp ); } vlc_mutex_unlock( &p_sys->lock ); i_post_socket = net_ConnectTCP( p_intf, p_sys->psz_submit_host, p_sys->i_submit_port ); if ( i_post_socket == -1 ) { /* If connection fails, we assume we must handshake again */ HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); p_sys->b_handshaked = false; free( psz_submit ); continue; } /* we transmit the data */ i_net_ret = net_Printf( VLC_OBJECT( p_intf ), i_post_socket, NULL, POST_REQUEST, p_sys->psz_submit_file, (unsigned)strlen( psz_submit ), p_sys->psz_submit_file, VERSION, psz_submit ); free( psz_submit ); if ( i_net_ret == -1 ) { /* If connection fails, we assume we must handshake again */ HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); p_sys->b_handshaked = false; continue; } i_net_ret = net_Read( p_intf, i_post_socket, NULL, p_buffer, 1023, false ); if ( i_net_ret <= 0 ) { /* if we get no answer, something went wrong : try again */ continue; } net_Close( i_post_socket ); p_buffer[i_net_ret] = '\0'; p_buffer_pos = strstr( ( char * ) p_buffer, "FAILED" ); if ( p_buffer_pos ) { msg_Warn( p_intf, "%s", p_buffer_pos ); HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); continue; } p_buffer_pos = strstr( ( char * ) p_buffer, "BADSESSION" ); if ( p_buffer_pos ) { msg_Err( p_intf, "Authentication failed (BADSESSION), are you connected to last.fm with another program ?" ); p_sys->b_handshaked = false; HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); continue; } p_buffer_pos = strstr( ( char * ) p_buffer, "OK" ); if ( p_buffer_pos ) { int i; for( i = 0; i < p_sys->i_songs; i++ ) DeleteSong( &p_sys->p_queue[i] ); p_sys->i_songs = 0; p_sys->i_interval = 0; p_sys->next_exchange = mdate(); msg_Dbg( p_intf, "Submission successful!" ); } else { msg_Err( p_intf, "Authentication failed, handshaking again (%s)", p_buffer ); p_sys->b_handshaked = false; HandleInterval( &p_sys->next_exchange, &p_sys->i_interval ); continue; } }}/***************************************************************************** * PlayingChange: Playing status change callback *****************************************************************************/static int PlayingChange( vlc_object_t *p_this, const char *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data ){ intf_thread_t *p_intf = ( intf_thread_t* ) p_data; intf_sys_t *p_sys = p_intf->p_sys; VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); if( p_intf->b_dead ) return VLC_SUCCESS; if( p_sys->b_meta_read == false && newval.i_int >= PLAYING_S ) { ReadMetaData( p_intf ); return VLC_SUCCESS; } if( newval.i_int >= END_S ) AddToQueue( p_intf ); else if( oldval.i_int == PLAYING_S && newval.i_int == PAUSE_S ) p_sys->time_pause = mdate(); else if( oldval.i_int == PAUSE_S && newval.i_int == PLAYING_S ) p_sys->time_total_pauses += ( mdate() - p_sys->time_pause ); return VLC_SUCCESS;}/***************************************************************************** * ItemChange: Playlist item change callback *****************************************************************************/static int ItemChange( vlc_object_t *p_this, const char *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data ){ playlist_t *p_playlist; input_thread_t *p_input; intf_thread_t *p_intf = ( intf_thread_t* ) p_data; intf_sys_t *p_sys = p_intf->p_sys; input_item_t *p_item; vlc_value_t video_val; VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval ); VLC_UNUSED( newval ); if( p_intf->b_dead ) return VLC_SUCCESS; p_sys->b_state_cb = false; p_sys->b_meta_read = false; p_sys->b_submit = false; p_playlist = pl_Yield( p_intf ); PL_LOCK; p_input = p_playlist->p_input; if( !p_input || p_input->b_dead ) { PL_UNLOCK; pl_Release( p_intf ); return VLC_SUCCESS; } vlc_object_yield( p_input ); PL_UNLOCK; pl_Release( p_intf ); p_item = input_GetItem( p_input ); if( !p_item ) { vlc_object_release( p_input ); return VLC_SUCCESS; } var_Change( p_input, "video-es", VLC_VAR_CHOICESCOUNT, &video_val, NULL ); if( ( video_val.i_int > 0 ) || p_item->i_type == ITEM_TYPE_NET ) { msg_Dbg( p_this, "Not an audio local file, not submitting"); vlc_object_release( p_input ); return VLC_SUCCESS; } p_sys->time_total_pauses = 0; time( &p_sys->p_current_song.date ); /* to be sent to last.fm */ p_sys->p_current_song.i_start = mdate(); /* only used locally */ var_AddCallback( p_input, "state", PlayingChange, p_intf ); p_sys->b_state_cb = true; if( input_item_IsPreparsed( p_item ) ) ReadMetaData( p_intf ); /* if the input item was not preparsed, we'll do it in PlayingChange() * callback, when "state" == PLAYING_S */ vlc_object_release( p_input ); return VLC_SUCCESS;}/***************************************************************************** * AddToQueue: Add the played song to the queue to be submitted *****************************************************************************/static void AddToQueue ( intf_thread_t *p_this ){ mtime_t played_time; intf_sys_t *p_sys = p_this->p_sys; vlc_mutex_lock( &p_sys->lock ); if( !p_sys->b_submit ) goto end; /* wait for the user to listen enough before submitting */ played_time = mdate() - p_sys->p_current_song.i_start - p_sys->time_total_pauses; played_time /= 1000000; /* µs → s */ /*HACK: it seam that the preparsing sometime fail, so use the playing time as the song length */ if( p_sys->p_current_song.i_l == 0 ) p_sys->p_current_song.i_l = played_time; /* Don't send song shorter than 30s */ if( p_sys->p_current_song.i_l < 30 ) { msg_Dbg( p_this, "Song too short (< 30s), not submitting" ); goto end; } /* Send if the user had listen more than 240s OR half the track length */ if( ( played_time < 240 ) && ( played_time < ( p_sys->p_current_song.i_l / 2 ) ) ) { msg_Dbg( p_this, "Song not listened long enough, not submitting" ); goto end; } /* Check that all meta are present */ if( !p_sys->p_current_song.psz_a || !*p_sys->p_current_song.psz_a || !p_sys->p_current_song.psz_t || !*p_sys->p_current_song.psz_t ) { msg_Dbg( p_this, "Missing artist or title, not submitting" ); goto end; } if( p_sys->i_songs >= QUEUE_MAX ) { msg_Warn( p_this, "Submission queue is full, not submitting" ); goto end; } msg_Dbg( p_this, "Song will be submitted." );#define QUEUE_COPY( a ) \ p_sys->p_queue[p_sys->i_songs].a = p_sys->p_current_song.a#define QUEUE_COPY_NULL( a ) \ QUEUE_COPY( a ); \ p_sys->p_current_song.a = NULL QUEUE_COPY( i_l ); QUEUE_COPY_NULL( psz_n ); QUEUE_COPY_NULL( psz_a ); QUEUE_COPY_NULL( psz_t ); QUEUE_COPY_NULL( psz_b ); QUEUE_COPY_NULL( psz_m ); QUEUE_COPY( date );#undef QUEUE_COPY_NULL#undef QUEUE_COPY p_sys->i_songs++; /* signal the main loop we have something to submit */ vlc_object_signal( VLC_OBJECT( p_this ) );end: DeleteSong( &p_sys->p_current_song ); p_sys->b_submit = false; vlc_mutex_unlock( &p_sys->lock );}/***************************************************************************** * ParseURL : Split an http:// URL into host, file, and port * * Example: "62.216.251.205:80/protocol_1.2" * will be split into "62.216.251.205", 80, "protocol_1.2" * * psz_url will be freed before returning * *psz_file & *psz_host will be freed before use * * Return value: * VLC_ENOMEM Out Of Memory * VLC_EGENERIC Invalid url provided * VLC_SUCCESS Success *****************************************************************************/static int ParseURL( char *psz_url, char **psz_host, char **psz_file, int *i_port ){ int i_pos; int i_len = strlen( psz_url ); FREENULL( *psz_host ); FREENULL( *psz_file ); i_pos = strcspn( psz_url, ":" ); if( i_pos == i_len ) return VLC_EGENERIC; *psz_host = strndup( psz_url, i_pos ); if( !*psz_host ) return VLC_ENOMEM; i_pos++; /* skip the ':' */ *i_port = atoi( psz_url + i_pos ); if( *i_port <= 0 ) { FREENULL( *psz_host ); return VLC_EGENERIC; } i_pos = strcspn( psz_url, "/" ); if( i_pos == i_len ) return VLC_EGENERIC; i_pos++; /* skip the '/' */ *psz_file = strdup( psz_url + i_pos ); if( !*psz_file ) { FREENULL( *psz_host ); return VLC_ENOMEM; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -