Skip to content
Snippets Groups Projects
Commit cdb7b9d8 authored by François Cartegnie's avatar François Cartegnie :fingers_crossed:
Browse files

acoustid: refactor

parent 6065ecc4
No related branches found
No related tags found
No related merge requests found
......@@ -18,6 +18,7 @@ misc_LTLIBRARIES += libexport_plugin.la
libfingerprinter_plugin_la_SOURCES = \
misc/webservices/acoustid.c misc/webservices/acoustid.h \
misc/webservices/json.c misc/webservices/json.h \
misc/webservices/json_helper.h \
misc/fingerprinter.c
libfingerprinter_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/misc
libfingerprinter_plugin_la_LIBADD = $(LIBM)
......
......@@ -353,11 +353,11 @@ static void *Run( void *opaque )
DoFingerprint( p_fingerprinter, &acoustid_print, psz_uri );
free( psz_uri );
DoAcoustIdWebRequest( VLC_OBJECT(p_fingerprinter), &acoustid_print );
acoustid_lookup_fingerprint( VLC_OBJECT(p_fingerprinter), &acoustid_print );
fill_metas_with_results( p_data, &acoustid_print );
for( unsigned j = 0; j < acoustid_print.results.count; j++ )
free_acoustid_result_t( &acoustid_print.results.p_results[j] );
acoustid_result_release( &acoustid_print.results.p_results[j] );
if( acoustid_print.results.count )
free( acoustid_print.results.p_results );
free( acoustid_print.psz_fingerprint );
......
......@@ -22,17 +22,13 @@
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_stream.h>
#include <limits.h>
#include "json_helper.h"
#include "acoustid.h"
#include "json.h"
/*****************************************************************************
* Requests lifecycle
*****************************************************************************/
void free_acoustid_result_t( acoustid_result_t * r )
void acoustid_result_release( acoustid_result_t * r )
{
free( r->psz_id );
for ( unsigned int i=0; i<r->recordings.count; i++ )
......@@ -43,26 +39,15 @@ void free_acoustid_result_t( acoustid_result_t * r )
free( r->recordings.p_recordings );
}
static json_value * jsongetbyname( json_value *object, const char *psz_name )
{
if ( object->type != json_object ) return NULL;
for ( unsigned int i=0; i < object->u.object.length; i++ )
if ( strcmp( object->u.object.values[i].name, psz_name ) == 0 )
return object->u.object.values[i].value;
return NULL;
}
static void parse_artists( json_value *node, acoustid_mb_result_t *record )
static void parse_artists( const json_value *node, acoustid_mb_result_t *record )
{
/* take only main */
if ( !node || node->type != json_array || node->u.array.length < 1 ) return;
json_value *artistnode = node->u.array.values[ 0 ];
json_value *value = jsongetbyname( artistnode, "name" );
if ( value && value->type == json_string )
record->psz_artist = strdup( value->u.string.ptr );
if ( !node || node->type != json_array || node->u.array.length < 1 )
return;
record->psz_artist = json_dupstring( node->u.array.values[ 0 ], "name" );
}
static void parse_recordings( vlc_object_t *p_obj, json_value *node, acoustid_result_t *p_result )
static void parse_recordings( vlc_object_t *p_obj, const json_value *node, acoustid_result_t *p_result )
{
if ( !node || node->type != json_array ) return;
p_result->recordings.p_recordings = calloc( node->u.array.length, sizeof(acoustid_mb_result_t) );
......@@ -72,40 +57,30 @@ static void parse_recordings( vlc_object_t *p_obj, json_value *node, acoustid_re
for( unsigned int i=0; i<node->u.array.length; i++ )
{
acoustid_mb_result_t *record = & p_result->recordings.p_recordings[ i ];
json_value *recordnode = node->u.array.values[ i ];
if ( !recordnode || recordnode->type != json_object ) break;
json_value *value = jsongetbyname( recordnode, "title" );
if ( value && value->type == json_string )
record->psz_title = strdup( value->u.string.ptr );
value = jsongetbyname( recordnode, "id" );
const json_value *recordnode = node->u.array.values[ i ];
if ( !recordnode || recordnode->type != json_object )
break;
record->psz_title = json_dupstring( recordnode, "title" );
const json_value *value = json_getbyname( recordnode, "id" );
if ( value && value->type == json_string )
{
size_t i_len = strlen( value->u.string.ptr );
i_len = __MIN( i_len, MB_ID_SIZE );
memcpy( record->s_musicbrainz_id, value->u.string.ptr, i_len );
}
parse_artists( jsongetbyname( recordnode, "artists" ), record );
msg_Dbg( p_obj, "recording %d title %s %36s %s", i, record->psz_title, record->s_musicbrainz_id, record->psz_artist );
parse_artists( json_getbyname( recordnode, "artists" ), record );
msg_Dbg( p_obj, "recording %d title %s %36s %s", i, record->psz_title,
record->s_musicbrainz_id, record->psz_artist );
}
}
static bool ParseJson( vlc_object_t *p_obj, const char *psz_buffer, acoustid_results_t *p_results )
static bool ParseJson( vlc_object_t *p_obj, const void *p_buffer, acoustid_results_t *p_results )
{
json_settings settings;
char psz_error[128];
memset (&settings, 0, sizeof (json_settings));
json_value *root = json_parse_ex( &settings, psz_buffer, psz_error );
if ( root == NULL )
{
msg_Warn( p_obj, "Can't parse json data: %s", psz_error );
goto error;
}
if ( root->type != json_object )
{
msg_Warn( p_obj, "wrong json root node" );
goto error;
}
json_value *node = jsongetbyname( root, "status" );
json_value *root = json_parse_document( p_obj, p_buffer );
if( !root )
return false;
const json_value *node = json_getbyname( root, "status" );
if ( !node || node->type != json_string )
{
msg_Warn( p_obj, "status node not found or invalid" );
......@@ -116,7 +91,7 @@ static bool ParseJson( vlc_object_t *p_obj, const char *psz_buffer, acoustid_res
msg_Warn( p_obj, "Bad request status" );
goto error;
}
node = jsongetbyname( root, "results" );
node = json_getbyname( root, "results" );
if ( !node || node->type != json_array )
{
msg_Warn( p_obj, "Bad results array or no results" );
......@@ -127,17 +102,15 @@ static bool ParseJson( vlc_object_t *p_obj, const char *psz_buffer, acoustid_res
p_results->count = node->u.array.length;
for( unsigned int i=0; i<node->u.array.length; i++ )
{
json_value *resultnode = node->u.array.values[i];
const json_value *resultnode = node->u.array.values[i];
if ( resultnode && resultnode->type == json_object )
{
acoustid_result_t *p_result = & p_results->p_results[i];
json_value *value = jsongetbyname( resultnode, "score" );
const json_value *value = json_getbyname( resultnode, "score" );
if ( value && value->type == json_double )
p_result->d_score = value->u.dbl;
value = jsongetbyname( resultnode, "id" );
if ( value && value->type == json_string )
p_result->psz_id = strdup( value->u.string.ptr );
parse_recordings( p_obj, jsongetbyname( resultnode, "recordings" ), p_result );
p_result->psz_id = json_dupstring( resultnode, "id" );
parse_recordings( p_obj, json_getbyname( resultnode, "recordings" ), p_result );
}
}
json_value_free( root );
......@@ -148,9 +121,10 @@ error:
return false;
}
int DoAcoustIdWebRequest( vlc_object_t *p_obj, acoustid_fingerprint_t *p_data )
int acoustid_lookup_fingerprint( vlc_object_t *p_obj, acoustid_fingerprint_t *p_data )
{
if ( !p_data->psz_fingerprint ) return VLC_SUCCESS;
if ( !p_data->psz_fingerprint )
return VLC_SUCCESS;
char *psz_url;
if( unlikely(asprintf( &psz_url, "https://fingerprint.videolan.org/"
......@@ -160,46 +134,11 @@ int DoAcoustIdWebRequest( vlc_object_t *p_obj, acoustid_fingerprint_t *p_data )
return VLC_EGENERIC;
msg_Dbg( p_obj, "Querying AcoustID from %s", psz_url );
bool saved_no_interact = p_obj->no_interact;
p_obj->no_interact = true;
stream_t *p_stream = vlc_stream_NewURL( p_obj, psz_url );
void *p_buffer = json_retrieve_document( p_obj, psz_url );
free( psz_url );
p_obj->no_interact = saved_no_interact;
if ( p_stream == NULL )
if( !p_buffer )
return VLC_EGENERIC;
stream_t *p_chain = vlc_stream_FilterNew( p_stream, "inflate" );
if( p_chain )
p_stream = p_chain;
/* read answer */
char *p_buffer = NULL;
int i_ret = 0;
for( ;; )
{
int i_read = 65536;
if( i_ret >= INT_MAX - i_read )
break;
p_buffer = realloc_or_free( p_buffer, 1 + i_ret + i_read );
if( unlikely(p_buffer == NULL) )
{
vlc_stream_Delete( p_stream );
return VLC_ENOMEM;
}
i_read = vlc_stream_Read( p_stream, &p_buffer[i_ret], i_read );
if( i_read <= 0 )
break;
i_ret += i_read;
}
vlc_stream_Delete( p_stream );
p_buffer[i_ret] = 0;
if ( ParseJson( p_obj, p_buffer, & p_data->results ) )
msg_Dbg( p_obj, "results count == %d", p_data->results.count );
else
......
......@@ -55,5 +55,5 @@ struct acoustid_fingerprint_t
};
typedef struct acoustid_fingerprint_t acoustid_fingerprint_t;
int DoAcoustIdWebRequest( vlc_object_t *p_obj, acoustid_fingerprint_t *p_data );
void free_acoustid_result_t( acoustid_result_t * r );
int acoustid_lookup_fingerprint( vlc_object_t *, acoustid_fingerprint_t * );
void acoustid_result_release( acoustid_result_t * );
/*****************************************************************************
* json_helper.h:
*****************************************************************************
* Copyright (C) 2012-2019 VLC authors, VideoLabs and VideoLAN
*
* 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.
*****************************************************************************/
#ifndef JSON_HELPER_H
#define JSON_HELPER_H
#include <vlc_common.h>
#include <vlc_stream.h>
#include <limits.h>
#include "json.h"
static inline
const json_value * json_getbyname(const json_value *object, const char *psz_name)
{
if (object->type != json_object) return NULL;
for (unsigned int i=0; i < object->u.object.length; i++)
if (strcmp(object->u.object.values[i].name, psz_name) == 0)
return object->u.object.values[i].value;
return NULL;
}
static inline
char * jsongetstring(const json_value *node, const char *key)
{
node = json_getbyname(node, key);
if (node && node->type == json_string)
return node->u.string.ptr;
return NULL;
}
static inline
char * json_dupstring(const json_value *node, const char *key)
{
const char *str = jsongetstring(node, key);
return (str) ? strdup(str) : NULL;
}
static inline
json_value * json_parse_document(vlc_object_t *p_obj, const char *psz_buffer)
{
json_settings settings;
char psz_error[128];
memset (&settings, 0, sizeof (json_settings));
json_value *root = json_parse_ex(&settings, psz_buffer, psz_error);
if (root == NULL)
{
msg_Warn(p_obj, "Can't parse json data: %s", psz_error);
goto error;
}
if (root->type != json_object)
{
msg_Warn(p_obj, "wrong json root node");
goto error;
}
return root;
error:
if (root) json_value_free(root);
return NULL;
}
static inline
void * json_retrieve_document(vlc_object_t *p_obj, const char *psz_url)
{
bool saved_no_interact = p_obj->no_interact;
p_obj->no_interact = true;
stream_t *p_stream = vlc_stream_NewURL(p_obj, psz_url);
p_obj->no_interact = saved_no_interact;
if (p_stream == NULL)
return NULL;
stream_t *p_chain = vlc_stream_FilterNew(p_stream, "inflate");
if(p_chain)
p_stream = p_chain;
/* read answer */
char *p_buffer = NULL;
int i_ret = 0;
for(;;)
{
int i_read = 65536;
if(i_ret >= INT_MAX - i_read)
break;
p_buffer = realloc_or_free(p_buffer, 1 + i_ret + i_read);
if(unlikely(p_buffer == NULL))
{
vlc_stream_Delete(p_stream);
return NULL;
}
i_read = vlc_stream_Read(p_stream, &p_buffer[i_ret], i_read);
if(i_read <= 0)
break;
i_ret += i_read;
}
vlc_stream_Delete(p_stream);
p_buffer[i_ret] = 0;
return p_buffer;
}
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment