/** * @brief Update a ml_media_t * * @param p_ml the media library object * @param p_media media to synchronise in the database * @return VLC_SUCCESS or VLC_EGENERIC * @note: the media id may be 0, in this case, the update is based * on the url (less powerful). This function is threadsafe * * This synchronises all non NULL and non zero fields of p_media * Synchronization of album and people is TODO */ int UpdateMedia( media_library_t *p_ml, ml_media_t *p_media ) { assert( p_media->i_id || ( p_media->psz_uri && *p_media->psz_uri ) ); vlc_array_t *changes = vlc_array_new(); ml_element_t *find = NULL; int i_ret = VLC_EGENERIC; ml_LockMedia( p_media ); #define APPEND_ICHANGES( cond, crit ) \ if( cond ) { \ find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) ); \ find->criteria = crit; \ find->value.i = cond; \ vlc_array_append( changes, find ); \ } #define APPEND_SCHANGES( cond, crit ) \ if( cond ) { \ find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) ); \ find->criteria = crit; \ find->value.str = cond; \ vlc_array_append( changes, find ); \ } APPEND_SCHANGES( p_media->psz_title, ML_TITLE ); APPEND_ICHANGES( p_media->i_type, ML_TYPE ); APPEND_ICHANGES( p_media->i_duration, ML_DURATION ); APPEND_SCHANGES( p_media->psz_preview, ML_PREVIEW ); APPEND_SCHANGES( p_media->psz_cover, ML_COVER ); APPEND_ICHANGES( p_media->i_disc_number, ML_DISC_NUMBER ); APPEND_ICHANGES( p_media->i_track_number, ML_TRACK_NUMBER ); APPEND_ICHANGES( p_media->i_year, ML_YEAR); APPEND_SCHANGES( p_media->psz_genre, ML_GENRE ); APPEND_ICHANGES( p_media->i_album_id, ML_ALBUM_ID ); APPEND_SCHANGES( p_media->psz_album, ML_ALBUM ); APPEND_ICHANGES( p_media->i_skipped_count, ML_SKIPPED_COUNT ); APPEND_ICHANGES( p_media->i_last_skipped, ML_LAST_SKIPPED ); APPEND_ICHANGES( p_media->i_played_count, ML_PLAYED_COUNT ); APPEND_ICHANGES( p_media->i_last_played, ML_LAST_PLAYED ); APPEND_ICHANGES( p_media->i_first_played, ML_FIRST_PLAYED ); APPEND_ICHANGES( p_media->i_vote, ML_VOTE ); APPEND_ICHANGES( p_media->i_score, ML_SCORE ); APPEND_SCHANGES( p_media->psz_comment, ML_COMMENT ); APPEND_SCHANGES( p_media->psz_extra, ML_EXTRA ); APPEND_SCHANGES( p_media->psz_language, ML_LANGUAGE ); if( p_media->psz_uri && p_media->i_id ) { find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) ); find->criteria = ML_URI; find->value.str = p_media->psz_uri; vlc_array_append( changes, find ); } /*TODO: implement extended meta */ /* We're not taking import time! Good */ #undef APPEND_ICHANGES #undef APPEND_SCHANGES ml_person_t* person = p_media->p_people; while( person ) { if( person->i_id > 0 ) { find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) ); find->criteria = ML_PEOPLE_ID; find->lvalue.str = person->psz_role; find->value.i = person->i_id; vlc_array_append( changes, find ); } else if( person->psz_name && *person->psz_name ) { find = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) ); find->criteria = ML_PEOPLE; find->lvalue.str = person->psz_role; find->value.str = person->psz_name; vlc_array_append( changes, find ); } person = person->p_next; } ml_ftree_t* p_where = NULL; ml_ftree_t* p_where_elt = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) ); if( p_media->i_id ) { p_where_elt->criteria = ML_ID; p_where_elt->value.i = p_media->i_id ; p_where_elt->comp = ML_COMP_EQUAL; p_where = ml_FtreeFastAnd( p_where, p_where_elt ); } else if( p_media->psz_uri ) { p_where_elt->criteria = ML_URI; p_where_elt->value.str = p_media->psz_uri; p_where_elt->comp = ML_COMP_EQUAL; p_where = ml_FtreeFastAnd( p_where, p_where_elt ); } else { goto quit1; } i_ret = Update( p_ml, ML_MEDIA, NULL, p_where, changes ); quit1: ml_FreeFindTree( p_where ); for( int i = 0; i < vlc_array_count( changes ); i++ ) /* Note: DO NOT free the strings because * they belong to the ml_media_t object */ free( vlc_array_item_at_index( changes, i ) ); vlc_array_destroy( changes ); ml_UnlockMedia( p_media ); return i_ret; }
/** * @brief Generic SELECT query builder with va_list parameter * * @param p_ml This media_library_t object * @param ppsz_query *ppsz_query will contain query * @param p_result_type see enum ml_result_type_e * @param criterias list of criterias used in SELECT * @return VLC_SUCCESS or a VLC error code * NOTE va_list criterias must end with ML_END or this will fail (segfault) * * This function handles results of only one column (or two if ID is included), * of 'normal' types: int and strings */ int BuildSelectVa( media_library_t *p_ml, char **ppsz_query, ml_result_type_e *p_result_type, va_list criterias ) { int i_continue = 1; ml_ftree_t* p_ftree = NULL; char* psz_lvalue = NULL; /* Get the name of the data we want */ ml_select_e selected_type = va_arg( criterias, int ); if( selected_type == ML_PEOPLE || selected_type == ML_PEOPLE_ID || selected_type == ML_PEOPLE_ROLE ) psz_lvalue = va_arg( criterias, char * ); /* Loop on every arguments */ while( i_continue ) { ml_ftree_t *p_find = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) ); if( !p_find ) return VLC_ENOMEM; p_find->criteria = va_arg( criterias, int ); p_find->comp = ML_COMP_EQUAL; switch( p_find->criteria ) { case ML_SORT_ASC: p_ftree = ml_FtreeSpecAsc( p_ftree, va_arg( criterias, char* ) ); break; case ML_SORT_DESC: p_ftree = ml_FtreeSpecDesc( p_ftree, va_arg( criterias, char* ) ); break; case ML_DISTINCT: p_ftree = ml_FtreeSpecDistinct( p_ftree ); break; case ML_LIMIT: p_ftree = ml_FtreeSpecLimit( p_ftree, va_arg( criterias, int ) ); break; case ML_ARTIST: /* This is OK because of a shallow free find */ p_find->lvalue.str = (char *)ML_PERSON_ARTIST; p_find->value.str = va_arg( criterias, char* ); p_ftree = ml_FtreeFastAnd( p_ftree, p_find ); break; case ML_PEOPLE: p_find->lvalue.str = va_arg( criterias, char* ); p_find->value.str = va_arg( criterias, char* ); p_ftree = ml_FtreeFastAnd( p_ftree, p_find ); break; case ML_PEOPLE_ID: p_find->lvalue.str = va_arg( criterias, char* ); p_find->value.i = va_arg( criterias, int ); p_ftree = ml_FtreeFastAnd( p_ftree, p_find ); break; case ML_END: i_continue = 0; break; default: switch( ml_AttributeIsString( p_find->criteria ) ) { case 0: p_find->value.i = va_arg( criterias, int ); break; case 1: p_find->value.str = va_arg( criterias, char* ); break; } p_ftree = ml_FtreeFastAnd( p_ftree, p_find ); break; } } int i_ret = BuildSelect( p_ml, ppsz_query, p_result_type, psz_lvalue, selected_type, p_ftree ); ml_ShallowFreeFindTree( p_ftree ); return i_ret; }