Commit 628b01be authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

core: remove media library support

parent acee3359
......@@ -3959,17 +3959,6 @@ dnl Libnotify notification plugin
dnl
PKG_ENABLE_MODULES_VLC([NOTIFY], [], [libnotify gtk+-2.0], [libnotify notification], [auto])
dnl
dnl media library
dnl
AC_ARG_ENABLE(media-library,
[ --enable-media-library media library (default disabled)])
AS_IF([test "${enable_media_library}" = "yes"], [
AC_DEFINE([MEDIA_LIBRARY], 1, [Define if you want to use the VLC media library])
VLC_ADD_CPPFLAGS([qt4],"-DMEDIA_LIBRARY")
])
dnl
dnl Endianness check
dnl
......
......@@ -32,9 +32,6 @@
extern "C" {
# endif
#include <vlc_common.h>
#include <vlc_playlist.h>
/*****************************************************************************
* ML Enums
*****************************************************************************/
......@@ -45,8 +42,6 @@ extern "C" {
#define ML_PERSON_PUBLISHER "Publisher"
#define ml_priv( gc, t ) ((t *)(((char *)(gc)) - offsetof(t, ml_gc_data)))
/** List of Query select types.
* In a query array or variable argument list, each select type is followed
* by an argument (X) of variable type (char* or int, @see ml_element_t).
......@@ -125,1131 +120,6 @@ typedef enum {
ML_TYPE_MEDIA, /**< A pointer to a media ml_media_t* */
} ml_result_type_e;
/** Arguments for VLC Control for the media library */
typedef enum
{
ML_SET_DATABASE, /**< arg1 = char *psz_host
arg2 = int i_port
arg3 = char *psz_user
arg4 = char *psz_pass */
ML_INIT_DATABASE, /**< No arg */
ML_ADD_INPUT_ITEM, /**< arg1 = input_item_t* */
ML_ADD_PLAYLIST_ITEM, /**< arg1 = playlist_item_t * */
ML_ADD_MONITORED, /**< arg1 = char* */
ML_DEL_MONITORED, /**< arg1 = char* */
ML_GET_MONITORED, /**< arg1 = vlc_array_t* */
} ml_control_e;
/* Operations that can be specified between find conditions */
typedef enum
{
ML_OP_NONE = 0, /**< This is to specify an actual condition */
ML_OP_AND, /**< AND condition */
ML_OP_OR, /**< OR condition */
ML_OP_NOT, /**< NOT condition */
ML_OP_SPECIAL /**< This is for inclusion of
* special stuffs like LIMIT */
} ml_op_e;
/* Comparison operators used in a single find condition */
typedef enum
{
ML_COMP_NONE = 0,
ML_COMP_LESSER, ///< <
ML_COMP_LESSER_OR_EQUAL, ///< <=
ML_COMP_EQUAL, ///< ==
ML_COMP_GREATER_OR_EQUAL, ///< >=
ML_COMP_GREATER, ///< >
ML_COMP_HAS, ///< "Contains", equivalent to SQL "LIKE %x%"
ML_COMP_STARTS_WITH, ///< Equivalent to SQL "LIKE %x"
ML_COMP_ENDS_WITH, ///< Equivalent to SQL "LIKE x%"
} ml_comp_e;
/*****************************************************************************
* ML Structures and types
*****************************************************************************/
typedef struct media_library_t media_library_t;
typedef struct media_library_sys_t media_library_sys_t;
typedef struct ml_media_t ml_media_t;
typedef struct ml_result_t ml_result_t;
typedef struct ml_element_t ml_element_t;
typedef struct ml_person_t ml_person_t;
typedef struct ml_ftree_t ml_ftree_t;
typedef struct ml_gc_object_t
{
bool pool;
uintptr_t refs;
void (*pf_destructor) (struct ml_gc_object_t *);
} ml_gc_object_t;
#define ML_GC_MEMBERS ml_gc_object_t ml_gc_data;
/** Main structure of the media library. VLC object. */
struct media_library_t
{
VLC_COMMON_MEMBERS
module_t *p_module; /**< the media library module */
media_library_sys_t *p_sys; /**< internal struture */
/** Member functions */
struct
{
/**< Search in the database */
int ( * pf_Find ) ( media_library_t *p_media_library,
vlc_array_t *p_result_array,
va_list args );
/**< Search in the database using an array of arguments */
int ( * pf_FindAdv ) ( media_library_t *p_media_library,
vlc_array_t *p_result_array,
ml_select_e selected_type,
const char *psz_lvalue,
ml_ftree_t *tree );
/**< Update the database using an array of arguments */
int ( * pf_Update ) ( media_library_t *p_media_library,
ml_select_e selected_type,
const char *psz_lvalue,
ml_ftree_t *where,
vlc_array_t *changes );
/**< Delete many medias in the database */
int ( * pf_Delete ) ( media_library_t *p_media_library,
vlc_array_t *p_array );
/**< Control the media library */
int ( * pf_Control ) ( media_library_t *p_media_library,
int i_query, va_list args );
/**< Create associated input item */
input_item_t* ( * pf_InputItemFromMedia ) (
media_library_t *p_media_library, int i_media );
/**< Get a media */
ml_media_t* ( * pf_GetMedia ) (
media_library_t *p_media_library, int i_media,
ml_select_e select, bool reload );
} functions;
};
/**
* @brief Structure to describe a media
*
* This is the main structure holding the meta data in ML.
* @see b_sparse indicates whether the media struct has valid values
* in its Extra fields. Otherwise, it must be loaded with the API
* function.
* @see i_id indicates whether this struct is saved in the ML if i_id > 0
* Otherwise, it can be added to the database
*/
struct ml_media_t
{
ML_GC_MEMBERS
vlc_mutex_t lock; /**< Mutex for multithreaded access */
bool b_sparse; /**< Specifies if media is loaded fully */
ml_type_e i_type; /**< Type of the media (ml_type_e) */
int8_t i_vote; /**< User vote */
int16_t i_disc_number; /**< Disc number of media */
int16_t i_track_number; /**< Track number */
int16_t i_year; /**< Year of release */
int32_t i_id; /**< Media ID in the database */
int32_t i_score; /**< Score computed about the media */
int32_t i_album_id; /**< Album id */
int32_t i_played_count; /**< How many time the media was played */
int32_t i_skipped_count; /**< No. of times file was skipped */
int32_t i_bitrate; /**< Extra: Bitrate of the media */
int32_t i_samplerate; /**< Extra: Samplerate of the media */
int32_t i_bpm; /**< Extra: Beats per minute */
char *psz_uri; /**< URI to find the media */
char *psz_title; /**< Title of the media */
char *psz_orig_title; /**< Original title (mainly for movies) */
char *psz_album; /**< Name of the album */
char *psz_cover; /**< URI of the cover */
char *psz_genre; /**< Genre of the media */
char *psz_preview; /**< Preview thumbnail for video, if any */
char *psz_comment; /**< Comment or description about media */
char *psz_language; /**< Extra: Language */
char *psz_extra; /**< Extra: Some extra datas like lyrics */
ml_person_t *p_people; /**< Extra: People associated with this
media This meta holds only one
artist if b_sparse = true */
int64_t i_filesize; /**< Size of the file */
mtime_t i_duration; /**< Duration in microseconds */
mtime_t i_last_played; /**< Time when the media was last played */
mtime_t i_last_skipped; /**< Time when the media was last skipped */
mtime_t i_first_played; /**< First played */
mtime_t i_import_time; /**< Time when media was added */
};
/**
* @brief Main communication struct between GUI and sql_media_library.
* Generic representation of an ML/SQL query result.
*/
struct ml_result_t
{
int32_t id; /**< Media/Album/Artist... ID (if any) */
ml_result_type_e type; /**< Type of value */
union
{
/* Classical results */
int i;
char *psz;
mtime_t time;
/* Complex result: media descriptor */
ml_media_t *p_media;
} value; /**< Value of the result obtained */
};
/**
* @brief Element of a query: criteria type/value pair
* Used for update and delete queries
*/
struct ml_element_t
{
ml_select_e criteria; /**< SELECT criteria type. @see ml_select_e */
union
{
int i;
char* str;
} value; /**< SELECT criteria value (string or int) */
union
{
int i;
char* str;
} lvalue; /**< Refer to @see ml_ftree_t lvalue docs */
};
/**
* Binary tree used to parse the WHERE condition for a search
*
* Let [expr] indicate a valid expression
* [expr] = [expr] AND [expr], where the left and right are respective
* [expr] = [expr] OR [expr]
* [expr] = [expr] NOT [NULL]
* [expr] = [expr] SPEC [spec_expr]
* [expr] = [criteria=val]
* [spec_expr] = [DISTINCT/LIMIT/ASC/DESC = val ]
*/
struct ml_ftree_t
{
ml_op_e op; /**< Operator. ML_OP_NONE means this is a leaf
* node. Criteria and value gives its data.
* ML_OP_SPECIAL specifies a special node
* that does not form a part of the WHERE.
* The right node consists of the data
* with its criteria set to the special val
* and the left node is the corresponding
* subtree of the parent node.
* ML_OP_NOT only left sub tree is considered
* ML_OP_AND and ML_OP_OR consider both
* left and right subtrees */
ml_ftree_t *left; /**< Left child of Bin tree */
ml_ftree_t *right; /**< Right child of Bin tree */
ml_select_e criteria; /**< SELECT criteria type @see ml_select_e
* The criteria value is considered only when
* op = ML_OP_NONE i.e. in leaf nodes */
ml_comp_e comp; /**< Condition between type and value */
union
{
int i;
char *str;
} value; /**< SELECT criteria value ( string or int ) */
union
{
int i;
char *str;
} lvalue; /**< Used as key value for people types/roles.
An empty string "" denotes ANY person role.
NULL is used for all other criterias */
};
/**
* Person class. Implemented as a linked list
*/
struct ml_person_t
{
char *psz_role; /**< Type of person */
char *psz_name; /**< Name of the person */
int i_id; /**< ID in the database */
ml_person_t *p_next; /**< Next person in list */
};
/*****************************************************************************
* ML Function headers
*****************************************************************************/
/**
* @brief Acquire a reference to the media library singleton
* @param p_this The object holding the media library
* @return The media library object. NULL if the media library
* object could not be loaded
*/
VLC_API media_library_t* ml_Get( vlc_object_t* p_this );
#define ml_Get( a ) ml_Get( VLC_OBJECT(a) )
/**
* @brief Create a Media Library VLC object.
* @param p_this Parent to attach the ML object to.
* @param psz_name Name for the module
* @return The ML object.
*/
media_library_t* ml_Create( vlc_object_t *p_this, char* psz_name );
/**
* @brief Destructor for the Media library singleton
* @param p_this Parent the ML object is attached to
*/
void ml_Destroy( vlc_object_t* p_this );
/**
* @brief Control the Media Library
* @param p_media_library the media library object
* @param i_type one of ml_control_e values @see ml_control_e.
* @param ... optional arguments.
* @return VLC_SUCCESS or an error
*/
static inline int ml_ControlVa( media_library_t *p_media_library,
ml_control_e i_type, va_list args )
{
return p_media_library->functions.pf_Control( p_media_library,
i_type,
args );
}
/**
* @brief Control the Media Library
* @param i_type one of ml_control_e values @see ml_control_e.
* Variable arguments list equivalent
*/
#define ml_Control( a, b, args... ) __ml_Control( a, b, ## args )
static inline int __ml_Control( media_library_t *p_media_library,
ml_control_e i_type, ... )
{
va_list args;
int returned;
va_start( args, i_type );
returned = ml_ControlVa( p_media_library, i_type, args );
va_end( args );
return returned;
}
/**
* @brief Determine an attribute's type (int or string)
* @param meta Attribute to test @see ml_select_e
* @return -1 if invalid, 0 if this is an integer, 1 if this is a string
*/
static inline int ml_AttributeIsString( ml_select_e meta )
{
switch( meta )
{
/* Strings */
case ML_ALBUM:
case ML_ARTIST:
case ML_COMMENT:
case ML_COVER:
case ML_EXTRA:
case ML_GENRE:
case ML_LANGUAGE:
case ML_PREVIEW:
case ML_PEOPLE:
case ML_PEOPLE_ROLE:
case ML_ORIGINAL_TITLE:
case ML_TITLE:
case ML_URI:
return 1;
/* Integers */
case ML_ALBUM_ID:
case ML_ARTIST_ID:
case ML_DURATION:
case ML_DISC_NUMBER:
case ML_COUNT_MEDIA:
case ML_COUNT_ALBUM:
case ML_COUNT_PEOPLE:
case ML_FILESIZE:
case ML_FIRST_PLAYED:
case ML_ID:
case ML_IMPORT_TIME:
case ML_LAST_PLAYED:
case ML_LIMIT:
case ML_PLAYED_COUNT:
case ML_PEOPLE_ID:
case ML_SCORE:
case ML_SKIPPED_COUNT:
case ML_TRACK_NUMBER:
case ML_TYPE:
case ML_VOTE:
case ML_YEAR:
return 0;
/* Invalid or no following value (in a SELECT statement) */
default:
return -1;
}
}
/* Reference Counting Functions */
/**
* @brief Increment reference count of media
* @param p_media The media object
*/
static inline void ml_gc_incref( ml_media_t* p_media )
{
ml_gc_object_t* p_gc = &p_media->ml_gc_data;
if( p_gc == NULL )
return;
++p_gc->refs;
}
/**
* @brief Decrease reference count of media
* @param p_media The media object
*/
static inline void ml_gc_decref( ml_media_t* p_media )
{
/* The below code is from vlc_release(). */
unsigned refs;
bool pool;
ml_gc_object_t* p_gc = &p_media->ml_gc_data;
if( p_gc == NULL )
return;
refs = --p_gc->refs;
pool = p_gc->pool;
if( refs == 0 && !pool )
{
p_gc->pf_destructor (p_gc);
}
}
/*****************************************************************************
* ML Free Functions
*****************************************************************************/
/**
* @brief Free a person object
* @param p_media Person object to free
* @note This function is NOT threadsafe
*/
static inline void ml_FreePeople( ml_person_t *p_person )
{
if( p_person == NULL )
return;
ml_FreePeople( p_person->p_next );
free( p_person->psz_name );
free( p_person->psz_role );
free( p_person );
}
/**
* @brief Free only the content of a media. @see ml_media_t
* @param p_media Media object
* @note This function is NOT threadsafe.
*/
static inline void ml_FreeMediaContent( ml_media_t *p_media )
{
FREENULL( p_media->psz_uri );
FREENULL( p_media->psz_title );
FREENULL( p_media->psz_orig_title );
FREENULL( p_media->psz_cover );
FREENULL( p_media->psz_comment );
FREENULL( p_media->psz_extra );
FREENULL( p_media->psz_genre );
FREENULL( p_media->psz_album );
FREENULL( p_media->psz_preview );
FREENULL( p_media->psz_language );
ml_FreePeople( p_media->p_people );
p_media->b_sparse = true;
p_media->i_id = 0;
p_media->i_type = ML_UNKNOWN;
p_media->i_album_id = 0;
p_media->i_disc_number = 0;
p_media->i_track_number = 0;
p_media->i_year = 0;
p_media->i_vote = 0;
p_media->i_score = 0;
p_media->i_filesize = 0;
p_media->i_duration = 0;
p_media->i_played_count = 0;
p_media->i_last_played = 0;
p_media->i_skipped_count = 0;
p_media->i_last_skipped = 0;
p_media->i_first_played = 0;
p_media->i_import_time = 0;
p_media->i_bitrate = 0;
p_media->i_samplerate = 0;
p_media->i_bpm = 0;
}
/**
* @brief Free a result item. @see ml_result_t
* @param p_result Result item to free
* @note This will free any strings and decref medias.
*/
static inline void ml_FreeResult( ml_result_t *p_result )
{
if( p_result )
{
switch( p_result->type )
{
case ML_TYPE_PSZ:
free( p_result->value.psz );
break;
case ML_TYPE_MEDIA:
ml_gc_decref( p_result->value.p_media );
break;
default:
break;
}
free( p_result );
}
}
/**
* @brief Free a ml_element_t item.
* @param p_find Find object to free
* @see ml_element_t */
static inline void ml_FreeElement( ml_element_t *p_elt )
{
if( p_elt )
{
if( ml_AttributeIsString( p_elt->criteria ) )
{
free( p_elt->value.str );
}
if( p_elt->criteria == ML_PEOPLE )
{
free( p_elt->lvalue.str );
}
free( p_elt );
}
}
/**
* @brief Destroy a vlc_array_t of ml_result_t
* @param ml_result_array The result array to free
* @note Frees all results and contents of the results
*/
static inline void ml_DestroyResultArray( vlc_array_t *p_result_array )
{
for( int i = 0; i < vlc_array_count( p_result_array ); i++ )
{
ml_FreeResult( ( ml_result_t* ) vlc_array_item_at_index(
p_result_array, i ) );
}
}
/*****************************************************************************
* ML Object Management Functions
*****************************************************************************/
/** Helpers for locking and unlocking */
#define ml_LockMedia( a ) vlc_mutex_lock( &a->lock )
#define ml_UnlockMedia( a ) vlc_mutex_unlock( &a->lock )
/**
* @brief Object constructor for ml_media_t
* @param p_ml The media library object
* @param id If 0, this item isn't in database. If non zero, it is and
* it will be a singleton
* @param select Type of object
* @param reload Whether to reload from database
*/
VLC_API ml_media_t *media_New( media_library_t* p_ml, int id,
ml_select_e select, bool reload );
/* Forward declaration */
static inline int ml_CopyPersons( ml_person_t** a, ml_person_t* b );
/**
* @brief Copy all members of a ml_media_t to another.
* @param b Destination media, already allocated
* @param a Source media, cannot be NULL, const
* @note This does not check memory allocation (for strdup). It is threadsafe
* @todo Free b content, before inserting a?
*/
static inline int ml_CopyMedia( ml_media_t *b, ml_media_t *a )
{
if( !a || !b ) return VLC_EGENERIC;
if( a == b ) return VLC_SUCCESS;
ml_LockMedia( a );
ml_LockMedia( b );
b->b_sparse = a->b_sparse;
b->i_id = a->i_id;
b->i_type = a->i_type;
b->i_album_id = a->i_album_id;
b->i_disc_number = a->i_disc_number;
b->i_track_number = a->i_track_number;
b->i_year = a->i_year;
b->i_vote = a->i_vote;
b->i_score = a->i_score;
b->i_filesize = a->i_filesize;
b->i_duration = a->i_duration;
b->i_played_count = a->i_played_count;
b->i_last_played = a->i_last_played;
b->i_skipped_count = a->i_skipped_count;
b->i_last_skipped = a->i_last_skipped;
b->i_first_played = a->i_first_played;
b->i_import_time = a->i_import_time;
b->i_bitrate = a->i_bitrate;
b->i_samplerate = a->i_samplerate;
b->i_bpm = a->i_bpm;
FREENULL( b->psz_uri );
if( a->psz_uri )
b->psz_uri = strdup( a->psz_uri );
FREENULL( b->psz_title );
if( a->psz_title )
b->psz_title = strdup( a->psz_title );
FREENULL( b->psz_orig_title );
if( a->psz_orig_title )
b->psz_orig_title = strdup( a->psz_orig_title );
FREENULL( b->psz_album );
if( a->psz_album )
b->psz_album = strdup( a->psz_album );
FREENULL( b->psz_cover );
if( a->psz_cover )
b->psz_cover = strdup( a->psz_cover );
FREENULL( b->psz_genre );
if( a->psz_genre )
b->psz_genre = strdup( a->psz_genre );
FREENULL( b->psz_comment );
if( a->psz_comment )
b->psz_comment = strdup( a->psz_comment );
FREENULL( b->psz_extra );
if( a->psz_extra )
b->psz_extra = strdup( a->psz_extra );
FREENULL( b->psz_preview );
if( a->psz_preview )
b->psz_preview = strdup( a->psz_preview );
FREENULL( b->psz_language );
if( a->psz_language )
b->psz_language = strdup( a->psz_language );
ml_FreePeople( b->p_people );
b->p_people = NULL;
if( a->p_people ) ml_CopyPersons( &( b->p_people ), a->p_people );
ml_UnlockMedia( b );
ml_UnlockMedia( a );
return VLC_SUCCESS;
}
/*****************************************************************************
* ML Find Tree Related Functions
*****************************************************************************/
#define ml_FreeFindTree( tree ) ml_GenericFreeFindTree( tree, true )
#define ml_ShallowFreeFindTree( tree ) ml_GenericFreeFindTree( tree, false )
/**
* @brief Free a find tree
* @param Find tree to free
* @param true to free any associated strings, false to not free them
*/
static inline void ml_GenericFreeFindTree( ml_ftree_t* tree, bool freestrings )
{
if( tree == NULL )
return;
if( tree->left )
{
ml_GenericFreeFindTree( tree->left, freestrings );
free( tree->left );
}
if( tree->right )
{
ml_GenericFreeFindTree( tree->right, freestrings );
free( tree->right );
}
if( tree->op == ML_OP_NONE && ml_AttributeIsString( tree->criteria )
&& freestrings)
{
free( tree->value.str );
if( tree->criteria == ML_PEOPLE )
free( tree->lvalue.str );
}
}
/**
* @brief Checks if a given find tree has leaf nodes
* @param Find tree
* @return Number of leaf nodes
*/
static inline int ml_FtreeHasOp( ml_ftree_t* tree )
{
if( tree == NULL )
return 0;
if( tree->criteria > 0 && tree->op == ML_OP_NONE )
return 1;
else
return ml_FtreeHasOp( tree->left ) + ml_FtreeHasOp( tree->right );
}
/**
* @brief Connect up a find tree
* @param op operator to connect with
* If op = ML_OP_NONE, then you are connecting to a tree consisting of
* only SPECIAL nodes.
* If op = ML_OP_NOT, then right MUST be NULL
* op must not be ML_OP_SPECIAL, @see ml_FtreeSpec
* @param left part of the tree
* @param right part of the tree
* @return Pointer to new tree
* @note Use the helpers!
*/
VLC_API ml_ftree_t *ml_OpConnectChilds( ml_op_e op, ml_ftree_t* left,
ml_ftree_t* right );
/**
* @brief Attaches a special node to a tree
* @param tree Tree to attach special node to
* @param crit Criteria may be SORT_ASC, SORT_DESC, LIMIT or DISTINCT
* @param limit Limit used if LIMIT criteria used
* @param Sort string used if SORT criteria is used
* @return Pointer to new tree
* @note Use the helpers
*/
VLC_API ml_ftree_t *ml_FtreeSpec( ml_ftree_t* tree,
ml_select_e crit,
int limit,
char* sort );
/**
* @brief This function gives quick sequential adding capability
* @param left Tree to add to. This may be NULL
* @param right Tree to append. May not be NULL
* @return Pointer to new tree.*/
static inline ml_ftree_t* ml_FtreeFastAnd( ml_ftree_t* left,
ml_ftree_t* right )
{
if( ml_FtreeHasOp( left ) == 0 )
{
return ml_OpConnectChilds( ML_OP_NONE, left, right );
}
else
{
return ml_OpConnectChilds( ML_OP_AND, left, right );
}
}
#define ml_FtreeAnd( left, right ) ml_OpConnectChilds( ML_OP_AND, left, right )
#define ml_FtreeOr( left, right ) ml_OpConnectChilds( ML_OP_OR, left, right )
#define ml_FtreeNot( left ) ml_OpConnectChilds( ML_OP_NOT, left, NULL )
#define ml_FtreeSpecAsc( tree, str ) ml_FtreeSpec( tree, ML_SORT_ASC, 0, str )
#define ml_FtreeSpecDesc( tree, str ) ml_FtreeSpec( tree, ML_SORT_DESC, 0, str )
#define ml_FtreeSpecLimit( tree, limit ) ml_FtreeSpec( tree, ML_LIMIT, limit, NULL )
#define ml_FtreeSpecDistinct( tree ) ml_FtreeSpec( tree, ML_DISTINCT, 0, NULL )
/*****************************************************************************
* ML Core Functions
*****************************************************************************/
/**
* @brief Create input item from media
* @param p_media_library This ML instance.
* @param i_media_id ID of the media to use to create an input_item.
* @return The media item.
*/
static inline input_item_t* ml_CreateInputItem(
media_library_t *p_media_library, int i_media_id )
{
return p_media_library->functions.pf_InputItemFromMedia( p_media_library,
i_media_id );
}
/**
* @brief Search in the database according some criterias
*
* @param p_media_library the media library object
* @param result a pointer to a result array
* @param ... parameters to select the data
* @return VLC_SUCCESS or an error
*/
static inline int __ml_Find( media_library_t *p_media_library,
vlc_array_t *p_result_array, ... )
{
va_list args;
int returned;
va_start( args, p_result_array );
returned = p_media_library->functions.pf_Find( p_media_library,
p_result_array, args );
va_end( args );
return returned;
}
/**
* @brief Search in the database according some criterias (threaded)
* @param p_media_library the media library object
* @param result_array a pointer to a result array
* @param result_type type of data to retrieve
* @param psz_lvalue This should contain any necessary lvalue/key
* for the given result_type. Used for ML_PEOPLE. Otherwise NULL
* @param args parameters to select the data
* @return VLC_SUCCESS or an error
*/
static inline int ml_FindAdv( media_library_t *p_media_library,
vlc_array_t *p_result_array,
ml_select_e result_type,
char* psz_lvalue,
ml_ftree_t *tree )
{
return p_media_library->functions.pf_FindAdv( p_media_library,
p_result_array,
result_type,
psz_lvalue,
tree );
}
/**
* @brief Find a value in the ML database, fill p_result with it.
* @param p_media_library Media library object
* @param p_result Object to put result into
* @param Args [ SelectType [ PersonType ] Value ] ... ML_END
* @note Do not use this function directly.
*/
static inline int __ml_GetValue( media_library_t *p_media_library,
ml_result_t *p_result,
va_list args )
{
vlc_array_t *p_result_array = vlc_array_new();
int i_ret = p_media_library->functions.pf_Find( p_media_library,
p_result_array,
args );
if( i_ret != VLC_SUCCESS )
goto exit;
if( vlc_array_count( p_result_array ) > 0 )
memcpy( p_result,
( ml_result_t* ) vlc_array_item_at_index( p_result_array, 0 ),
sizeof( ml_result_t) );
else
i_ret = VLC_EGENERIC;
exit:
/* Note: Do not free the results, because of memcpy */
vlc_array_destroy( p_result_array );
return i_ret;
}
/**
* @brief Search an INTEGER in the database
* This uses a Query but returns only one integer (>0), or an error code.
*
* @param p_media_library the media library object
* @param va_args parameters to select the data
* @return Found INTEGER >= 0 or an error
*/
#define ml_GetInt( ml, ... ) __ml_GetInt( ml, __VA_ARGS__, ML_LIMIT, 1, ML_END )
static inline int __ml_GetInt( media_library_t *p_media_library, ... )
{
va_list args;
va_start( args, p_media_library );
ml_result_t result;
int i_ret = __ml_GetValue( p_media_library, &result, args );
va_end( args );
if( i_ret != VLC_SUCCESS )
return i_ret;
else
return result.value.i;
}
/**
* @brief Search a string (VARCHAR) in the database
* This uses a Query but returns only one integer (>0), or an error code.
*
* @param p_media_library the media library object
* @param va_args parameters to select the data
* @return Found string, or NULL if not found or in case of error
*/
#define ml_FindPsz( ml, ... ) __ml_GetPsz( ml, __VA_ARGS__, ML_LIMIT, 1, ML_END )
static inline char* __ml_GetPsz( media_library_t *p_media_library, ... )
{
va_list args;
va_start( args, p_media_library );
ml_result_t result;
int i_ret = __ml_GetValue( p_media_library, &result, args );
va_end( args );
if( i_ret != VLC_SUCCESS )
return NULL;
else
return result.value.psz; // no need to duplicate
}
/**
* @brief Generic update in Media Library database
*
* @param p_media_library the media library object
* @param selected_type the type of the element we're selecting
* @param where list of ids/uris to be changed
* @param changes list of changes to make in the entries
* @return VLC_SUCCESS or VLC_EGENERIC
*/
static inline int ml_Update( media_library_t *p_media_library,
ml_select_e selected_type,
const char* psz_lvalue,
ml_ftree_t *where,
vlc_array_t *changes )
{
return p_media_library->functions.pf_Update( p_media_library,
selected_type, psz_lvalue,
where, changes );
}
/**
* @brief Update a given table
* @param p_media_library The media library object
* @param selected_type The table to update
* @param psz_lvalue The role of the person if selected_type = ML_PEOPLE
* @param id The id of the row to update
* @param ... The update data. [SelectType [RoleType] Value]
*/
VLC_API int ml_UpdateSimple( media_library_t *p_media_library,
ml_select_e selected_type,
const char* psz_lvalue,
int id, ... );
#define ml_UpdateSimple( ml, sel, lval, id, ... ) \
ml_UpdateSimple( ml, sel, lval, id, __VA_ARGS__, ML_END )
/**
* @brief Generic DELETE function
* Delete a media and all its references which don't point
* to anything else.
*
* @param p_media_library This media_library_t object
* @param id the id of the media to delete
* @return VLC_SUCCESS or VLC_EGENERIC
*/
static inline int
ml_DeleteSimple( media_library_t *p_media_library, int id )
{
vlc_array_t* p_where = vlc_array_new();
ml_element_t* p_find = (ml_element_t *) calloc( 1, sizeof( ml_element_t ) );
p_find->criteria = ML_ID;
p_find->value.i = id;
vlc_array_append( p_where, p_find );
int i_return = p_media_library->functions.pf_Delete( p_media_library,
p_where );
free( p_find );
vlc_array_destroy( p_where );
return i_return;
}
/**
* @brief Delete many medias in the media library
* @param p_media_library Media library object
* @param p_array Array of ids to delete
* @return VLC_SUCCESS or VLC_EGENERIC
*/
static inline int
ml_Delete( media_library_t *p_media_library, vlc_array_t* p_array )
{
return p_media_library->functions.pf_Delete( p_media_library,
p_array );
}
/*****************************************************************************
* ML Person Related Functions
*****************************************************************************/
/**
* @brief Create and append a person object to the given list
* @param pp_person pointer to person list. Set the address to null to create new list
* @param i_role The role of the person
* @param psz_name The name string. Will be strdup'd
* @param i_id The id in the database
* @note This function is NOT thread safe. Please lock any associated media
*/
static inline int ml_CreateAppendPersonAdv( ml_person_t **pp_person,
const char* psz_role, const char* psz_name, int i_id )
{
if( i_id == 0 || !( psz_name && *psz_name && psz_role && *psz_role ) )
return VLC_SUCCESS;
if( !pp_person )
return VLC_EGENERIC;
if( *pp_person != NULL )
return ml_CreateAppendPersonAdv( &((**pp_person).p_next),
psz_role, psz_name, i_id);
*pp_person = ( ml_person_t * ) calloc( 1, sizeof( ml_person_t ) );
(*pp_person)->psz_name = (psz_name && *psz_name) ? strdup( psz_name ): NULL;
(*pp_person)->psz_role = (psz_role && *psz_role) ? strdup( psz_role ): NULL;
(*pp_person)->i_id = i_id;
(*pp_person)->p_next = NULL;
return VLC_SUCCESS;
}
/**
* @brief Create and append a person object to the given list
* @param pp_person pointer to person list.
* Set the address to NULL to create a new list
* @param personfrom Person object to copy from
* @note Ignores the next variable and copies only the variables.
* Uses ml_CreateAppendPersonAdv
* @note This function is NOT threadsafe
*/
static inline int ml_CreateAppendPerson( ml_person_t **pp_person,
ml_person_t *p_personfrom )
{
return ml_CreateAppendPersonAdv( pp_person,
p_personfrom->psz_role,
p_personfrom->psz_name,
p_personfrom->i_id );
}
/**
* @brief Copy one person list into another
* @param a To list
* @param b From list
* @note On errors, you have to free any allocated persons yourself
* @note This function is NOT threadsafe. Please ensure your medias are locked
*/
static inline int ml_CopyPersons( ml_person_t** a, ml_person_t* b )
{
int i_ret;
while( b )
{
i_ret = ml_CreateAppendPerson( a, b );
if( i_ret != VLC_SUCCESS )
return i_ret;
b = b->p_next;
}
return VLC_SUCCESS;
}
/**
* @brief Returns a person list of given type
* @param p_ml The ML object
* @param p_media The Media object
* @param i_type The person type
* @note This function is thread safe
*/
VLC_API ml_person_t *ml_GetPersonsFromMedia( media_library_t* p_ml,
ml_media_t* p_media,
const char *psz_role );
#define ml_GetAlbumArtistsFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_ALBUM_ARTIST );
#define ml_GetArtistsFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_ARTIST );
#define ml_GetEncodersFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_ENCODER );
#define ml_GetPublishersFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_PUBLISHER );
/**
* @brief Delete a certain type of people from a media
* @param p_media Media to delete from
* @param i_type Type of person to delete
* @note This function is threadsafe
*/
VLC_API void ml_DeletePersonTypeFromMedia( ml_media_t* p_media,
const char *psz_role );
/**
* Convenience Macros
*/
/**
* Get information using the *media* ID. This returns only 1 information.
* @note You have to free the string returned (if that's a string!).
*/
#define ml_GetAlbumById( a, id ) ml_GetPsz( a, ML_ALBUM, ML_ID, id )
#define ml_GetArtistById( a, id ) ml_GetPsz( a, ML_PEOPLE, ML_PERSON_ARTIST, ML_ID, id )
#define ml_GetCoverUriById( a, id ) ml_GetPsz( a, ML_COVER, ML_ID, id )
#define ml_GetEncoderById( a, id ) ml_GetPsz( a, ML_PEOPLE, ML_PERSON_ENCODER, ML_ID, id )
#define ml_GetExtraById( a, id ) ml_GetPsz( a, ML_EXTRA, ML_ID, id )
#define ml_GetGenreById( a, id ) ml_GetPsz( a, ML_GENRE, ML_ID, id )
#define ml_GetOriginalTitleById( a, id ) ml_GetPsz( a, ML_ORIGINAL_TITLE, ML_ID, id )
#define ml_GetPublisherById( a, id ) ml_GetPsz( a, ML_PEOPLE, ML_PERSON_PUBLISHER, ML_ID, id )
#define ml_GetTitleById( a, id ) ml_GetPsz( a, ML_TITLE, ML_ID, id )
#define ml_GetUriById( a, id ) ml_GetPsz( a, ML_URI, ML_ID, id )
#define ml_GetAlbumIdById( a, id ) ml_GetInt( a, ML_ALBUM_ID, ML_ID, id )
#define ml_GetArtistIdById( a, id ) ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_ARTIST, ML_ID, id )
#define ml_GetDurationById( a, id ) ml_GetInt( a, ML_DURATION, ML_ID, id )
#define ml_GetEncoderIdById( a, id ) ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_ENCODER, ML_ID, id )
#define ml_GetLastPlayedById( a, id ) ml_GetInt( a, ML_LAST_PLAYED, ML_ID, id )
#define ml_GetPlayedCountById( a, id ) ml_GetInt( a, ML_PLAYED_COUNT, ML_ID, id )
#define ml_GetPublisherIdById( a, id ) ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_PUBLISHER, ML_ID, id )
#define ml_GetScoreById( a, id ) ml_GetInt( a, ML_SCORE, ML_ID, id )
#define ml_GetTrackNumberById( a, id ) ml_GetInt( a, ML_TRACK_NUMBER, ML_ID, id )
#define ml_GetTypeById( a, id ) ml_GetInt( a, ML_TYPE, ML_ID, id )
#define ml_GetYearById( a, id ) ml_GetInt( a, ML_YEAR, ML_ID, id )
#define ml_GetVoteById( a, id ) ml_GetInt( a, ML_VOTE, ML_ID, id )
/** Albums handling */
#define ml_GetAlbumId( a, b ) ml_GetInt( a, ML_ALBUM_ID, ML_ALBUM, b )
/** People handling */
#define ml_GetArtistId( a, b ) ml_GetInt( a, ML_PERSON_ID, ML_PERSON_ARTIST, ML_PERSON, ML_PERSON_ARTIST, b )
#define ml_GetEncoderId( a, b ) ml_GetInt( a, ML_PERSON_ID, ML_PERSON_ENCODER, ML_PERSON, ML_PERSON_ENCODER, b )
#define ml_GetPublisherId( a, b ) ml_GetInt( a, ML_PERSON_ID, ML_PERSON_PUBLISHER, ML_PERSON, ML_PERSON_PUBLISHER, b )
/** Counts handling */
#define ml_GetMediaCount( a, ... ) __ml_GetInt( a, ML_COUNT_MEDIA, __VA_ARGS__, ML_END )
#define ml_GetAlbumCount( a, ... ) __ml_GetInt( a, ML_COUNT_ALBUM, __VA_ARGS__, ML_END )
#define ml_GetPeopleCount( a, ... ) __ml_GetInt( a, ML_COUNT_PEOPLE, __VA_ARGS__, ML_END )
#define ml_Find( a, b, ... ) __ml_Find( a, b, __VA_ARGS__, ML_END )
#define ml_FindAlbum( a, b, ... ) __ml_Find( a, b, ML_ALBUM, __VA_ARGS__, ML_END )
#define ml_FindArtist( a, b, ... ) __ml_Find( a, b, ML_PERSON, ML_PERSON_ARTIST, __VA_ARGS__, ML_END )
#define ml_FindEncoder( a, b, ... ) __ml_Find( a, b, ML_PERSON, ML_PERSON_ENCODER, __VA_ARGS__, ML_END )
#define ml_FindGenre( a, b, ... ) __ml_Find( a, b, ML_GENRE, __VA_ARGS__, ML_END )
#define ml_FindMedia( a, b, ... ) __ml_Find( a, b, ML_MEDIA, __VA_ARGS__, ML_END )
#define ml_FindOriginalTitle( a, b, ... ) __ml_Find( a, b, ML_ORIGINAL_TITLE, __VA_ARGS__, ML_END )
#define ml_FindPublisher( a, b, ... ) __ml_Find( a, b, ML_PERSON, ML_PERSON_PUBLISHER, __VA_ARGS__, ML_END )
#define ml_FindTitle( a, b, ... ) __ml_Find( a, b, ML_TITLE, __VA_ARGS__, ML_END )
#define ml_FindType( a, b, ... ) __ml_Find( a, b, ML_TYPE, __VA_ARGS__, ML_END )
#define ml_FindUri( a, b, ... ) __ml_Find( a, b, ML_URI, __VA_ARGS__, ML_END )
#define ml_FindYear( a, b, ... ) __ml_Find( a, b, ML_YEAR, __VA_ARGS__, ML_END )
#define ml_FindAllAlbums( a, b ) ml_FindAlbum( a, b, ML_DISTINCT )
#define ml_FindAllArtists( a, b ) ml_FindArtist( a, b, ML_DISTINCT )
#define ml_FindAllGenres( a, b ) ml_FindGenre( a, b, ML_DISTINCT )
#define ml_FindAllMedias( a, b ) ml_FindMedia( a, b, ML_DISTINCT )
#define ml_FindAllOriginalTitles( a, b ) ml_FindOriginalTitle( a, b, ML_DISTINCT )
#define ml_FindAllPublishers( a, b, ... ) ml_FindPublisher( a, b, ML_DISTINCT )
#define ml_FindAllTitles( a, b ) ml_FindTitle( a, b, ML_DISTINCT )
#define ml_FindAllTypes( a, b ) ml_FindType( a, b, ML_DISTINCT )
#define ml_FindAllUris( a, b ) ml_FindUri( a, b, ML_DISTINCT )
#define ml_FindAllYears( a, b ) ml_FindYear( a, b, ML_DISTINCT )
#define ml_FindAlbumAdv( a, b, c ) ml_FindAdv( a, b, ML_ALBUM, NULL, c )
#define ml_FindArtistAdv( a, b, c ) ml_FindAdv( a, b, ML_PERSON, ML_PERSON_ARTIST, c )
#define ml_FindEncoderAdv( a, b, c ) ml_FindAdv( a, b, ML_PERSON, ML_PERSON_ENCODER, c )
#define ml_FindGenreAdv( a, b, c ) ml_FindAdv( a, b, ML_GENRE, NULL, c )
#define ml_FindMediaAdv( a, b, c ) ml_FindAdv( a, b, ML_MEDIA, NULL, c )
#define ml_FindOriginalTitleAdv( a, b, c ) ml_FindAdv( a, b, ML_ORIGINAL_TITLE,NULL, c )
#define ml_FindPublisherAdv( a, b, c ) ml_FindAdv( a, b, ML_PUBLISHER, ML_PERSON_PUBLISHER, c )
#define ml_FindTitleAdv( a, b, c ) ml_FindAdv( a, b, ML_TITLE, NULL, c )
#define ml_FindTypeAdv( a, b, c ) ml_FindAdv( a, b, ML_TYPE, NULL, c )
#define ml_FindUriAdv( a, b, c ) ml_FindAdv( a, b, ML_URI, NULL, c )
#define ml_FindYearAdv( a, b, c ) ml_FindAdv( a, b, ML_YEAR, NULL, c )
#ifdef __cplusplus
}
#endif /* C++ */
......
......@@ -461,7 +461,6 @@ SOURCES_libvlc_common = \
misc/update.c \
misc/update_crypto.c \
misc/xml.c \
misc/media_library.c \
extras/libc.c \
extras/tdestroy.c \
misc/filter.c \
......
......@@ -2033,10 +2033,6 @@ vlc_module_begin ()
PLAYLISTENQUEUE_LONGTEXT, true )
#endif
add_bool( "media-library", 0, ML_TEXT, ML_LONGTEXT, false )
#if defined( MEDIA_LIBRARY )
add_bool( "load-media-library-on-startup", 1, LOAD_ML_TEXT,
LOAD_ML_LONGTEXT, false )
#endif
add_bool( "playlist-tree", 0, PLTREE_TEXT, PLTREE_LONGTEXT, false )
add_string( "open", "", OPEN_TEXT, OPEN_LONGTEXT, false )
......
......@@ -55,7 +55,6 @@
#endif
#include <vlc_media_library.h>
#include <vlc_playlist.h>
#include <vlc_interface.h>
......@@ -109,12 +108,9 @@ libvlc_int_t * libvlc_InternalCreate( void )
priv = libvlc_priv (p_libvlc);
priv->p_playlist = NULL;
priv->p_ml = NULL;
priv->p_dialog_provider = NULL;
priv->p_vlm = NULL;
/* Initialize mutexes */
vlc_mutex_init( &priv->ml_lock );
vlc_ExitInit( &priv->exit );
return p_libvlc;
......@@ -395,23 +391,6 @@ dbus_out:
/* System specific configuration */
system_Configure( p_libvlc, i_argc - vlc_optind, ppsz_argv + vlc_optind );
#if defined(MEDIA_LIBRARY)
/* Get the ML */
if( var_GetBool( p_libvlc, "load-media-library-on-startup" ) )
{
priv->p_ml = ml_Create( VLC_OBJECT( p_libvlc ), NULL );
if( !priv->p_ml )
{
msg_Err( p_libvlc, "ML initialization failed" );
return VLC_EGENERIC;
}
}
else
{
priv->p_ml = NULL;
}
#endif
#ifdef ENABLE_VLM
/* Initialize VLM if vlm-conf is specified */
psz_parser = var_CreateGetNonEmptyString( p_libvlc, "vlm-conf" );
......@@ -551,16 +530,6 @@ void libvlc_InternalCleanup( libvlc_int_t *p_libvlc )
}
#endif
#if defined(MEDIA_LIBRARY)
media_library_t* p_ml = priv->p_ml;
if( p_ml )
{
ml_Destroy( VLC_OBJECT( p_ml ) );
vlc_object_release( p_ml );
libvlc_priv(p_playlist->p_libvlc)->p_ml = NULL;
}
#endif
/* Free playlist now, all threads are gone */
playlist_t *p_playlist = libvlc_priv (p_libvlc)->p_playlist;
if( p_playlist != NULL )
......@@ -612,9 +581,7 @@ void libvlc_InternalDestroy( libvlc_int_t *p_libvlc )
{
libvlc_priv_t *priv = libvlc_priv( p_libvlc );
/* Destroy mutexes */
vlc_ExitDestroy( &priv->exit );
vlc_mutex_destroy( &priv->ml_lock );
assert( atomic_load(&(vlc_internals(p_libvlc)->refs)) == 1 );
vlc_object_release( p_libvlc );
......
......@@ -159,8 +159,6 @@ typedef struct libvlc_priv_t
/* Singleton objects */
playlist_t *p_playlist; ///< the playlist singleton
struct media_library_t *p_ml; ///< the ML singleton
vlc_mutex_t ml_lock; ///< Mutex for ML creation
vlm_t *p_vlm; ///< the VLM singleton (or NULL)
vlc_object_t *p_dialog_provider; ///< dialog provider
#ifdef ENABLE_SOUT
......
......@@ -230,13 +230,7 @@ vlc_UrlClean
vlc_path2uri
make_path
mdate
ml_Get
media_New
ml_OpConnectChilds
ml_FtreeSpec
ml_UpdateSimple
ml_GetPersonsFromMedia
ml_DeletePersonTypeFromMedia
module_config_free
module_config_get
module_exists
......
/*****************************************************************************
* media_library.c: SQL-based media library: ML creators and destructors
*****************************************************************************
* Copyright (C) 2009-2010 VLC authors and VideoLAN and AUTHORS
* $Id$
*
* Authors: Srikanth Raju <srikiraju at gmail dot com>
*
* 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(MEDIA_LIBRARY)
#include <assert.h>
#include <vlc_media_library.h>
#include <vlc_modules.h>
#include "../libvlc.h"
/**
* @brief Destroy the medialibrary object
* @param Parent object that holds the media library object
*/
void ml_Destroy( vlc_object_t * p_this )
{
media_library_t* p_ml = ( media_library_t* )p_this;
module_unneed( p_ml, p_ml->p_module );
}
/**
* Atomically set the reference count to 1.
* @param p_gc reference counted object
* @param pf_destruct destruction calback
* @return p_gc.
*/
static void *ml_gc_init (ml_gc_object_t *p_gc, void (*pf_destruct) (ml_gc_object_t *))
{
/* There is no point in using the GC if there is no destructor... */
assert (pf_destruct);
p_gc->pf_destructor = pf_destruct;
p_gc->pool = false;
p_gc->refs = 1;
return p_gc;
}
/**
* @brief Create an instance of the media library
* @param p_this Parent object
* @param psz_name Name which is passed to module_need (not needed)
* @return p_ml created and attached, module loaded. NULL if
* not able to load
*/
media_library_t *ml_Create( vlc_object_t *p_this, char *psz_name )
{
media_library_t *p_ml;
p_ml = ( media_library_t * ) vlc_custom_create(
p_this, sizeof( media_library_t ),
"media-library" );
if( !p_ml )
{
msg_Err( p_this, "unable to create media library object" );
return NULL;
}
p_ml->p_module = module_need( p_ml, "media-library", psz_name, false );
if( !p_ml->p_module )
{
vlc_object_release( p_ml );
msg_Err( p_this, "Media Library provider not found" );
return NULL;
}
return p_ml;
}
#undef ml_Get
/**
* @brief Acquire a reference to the media library singleton
* @param p_this Object that holds the reference
* @return media_library_t The ml object. NULL if not compiled with
* media library or if unable to load
*/
media_library_t* ml_Get( vlc_object_t* p_this )
{
media_library_t* p_ml;
vlc_mutex_lock( &( libvlc_priv( p_this->p_libvlc )->ml_lock ) );
p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
assert( VLC_OBJECT( p_ml ) != p_this );
if( p_ml == NULL &&
!var_GetBool( p_this->p_libvlc, "load-media-library-on-startup" ) )
{
libvlc_priv (p_this->p_libvlc)->p_ml
= ml_Create( VLC_OBJECT( p_this->p_libvlc ), NULL );
p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
}
vlc_mutex_unlock( &( libvlc_priv( p_this->p_libvlc )->ml_lock ) );
return p_ml;
}
/**
* @brief Destructor for ml_media_t
*/
static void media_Destroy( ml_gc_object_t *p_gc )
{
ml_media_t* p_media = ml_priv( p_gc, ml_media_t );
vlc_mutex_destroy( &p_media->lock );
ml_FreeMediaContent( p_media );
free( p_media );
}
/**
* @brief Object constructor for ml_media_t
* @param p_ml The media library object
* @param id If 0, this item isn't in database. If non zero, it is and
* it will be a singleton
* @param select Type of object
* @param reload Whether to reload from database
*/
ml_media_t* media_New( media_library_t* p_ml, int id,
ml_select_e select, bool reload )
{
if( id == 0 )
{
ml_media_t* p_media = NULL;
p_media = ( ml_media_t* )calloc( 1, sizeof( ml_media_t ) );
ml_gc_init( &p_media->ml_gc_data, media_Destroy );
vlc_mutex_init( &p_media->lock );
return p_media;
}
else
return p_ml->functions.pf_GetMedia( p_ml, id, select, reload );
}
#undef ml_UpdateSimple
/**
* @brief Update a given table
* @param p_media_library The media library object
* @param selected_type The table to update
* @param psz_lvalue The role of the person if selected_type = ML_PEOPLE
* @param id The id of the row to update
* @param ... The update data. [SelectType [RoleType] Value] ... ML_END
*/
int ml_UpdateSimple( media_library_t *p_media_library,
ml_select_e selected_type,
const char* psz_lvalue,
int id, ... )
{
ml_element_t *update;
vlc_array_t *array = vlc_array_new();
int i_ret = VLC_SUCCESS;
va_list args;
va_start( args, id );
ml_select_e sel;
do {
update = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) );
sel = ( ml_select_e ) va_arg( args, int );
update->criteria = sel;
if( sel == ML_PEOPLE )
{
update->lvalue.str = va_arg( args, char* );
update->value.str = va_arg( args, char* );
vlc_array_append( array, update );
}
else if( sel == ML_PEOPLE_ID )
{
update->lvalue.str = va_arg( args, char* );
update->value.i = va_arg( args, int );
vlc_array_append( array, update );
}
else if( sel == ML_PEOPLE_ROLE )
{
#ifndef NDEBUG
msg_Dbg( p_media_library,
"this argument is invalid for Update: %d",
(int)sel );
#endif
}
else
{
switch( ml_AttributeIsString( sel ) )
{
case -1:
if( sel != ML_END )
{
#ifndef NDEBUG
msg_Dbg( p_media_library,
"this argument is invalid for Update: %d",
(int)sel );
#endif
i_ret = VLC_EBADVAR;
}
else if( sel == ML_END )
vlc_array_append( array, update );
break;
case 1:
update->value.str = va_arg( args, char* );
vlc_array_append( array, update );
break;
case 0:
update->value.i = va_arg( args, int );
vlc_array_append( array, update );
break;
}
}
} while( sel != ML_END );
va_end( args );
ml_ftree_t* p_where = NULL;
ml_ftree_t* find = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
find->criteria = ML_ID;
find->value.i = id ;
find->comp = ML_COMP_EQUAL;
p_where = ml_FtreeFastAnd( p_where, find );
/* Let's update the database ! */
if( i_ret == VLC_SUCCESS )
i_ret = ml_Update( p_media_library, selected_type, psz_lvalue,
p_where, array );
/* Destroying array */
for( int i = 0; i < vlc_array_count( array ); i++ )
{
free( vlc_array_item_at_index( array, i ) );
}
vlc_array_destroy( array );
ml_FreeFindTree( p_where );
return i_ret;
}
/**
* @brief Connect up a find tree
* @param op operator to connect with
* If op = ML_OP_NONE, then you are connecting to a tree consisting of
* only SPECIAL nodes.
* If op = ML_OP_NOT, then right MUST be NULL
* op must not be ML_OP_SPECIAL, @see ml_FtreeSpec
* @param left part of the tree
* @param right part of the tree
* @return Pointer to new tree
* @note Use the helpers!
*/
ml_ftree_t* ml_OpConnectChilds( ml_op_e op, ml_ftree_t* left,
ml_ftree_t* right )
{
/* Use this Op for fresh trees (with only special nodes/none at all!) */
if( op == ML_OP_NONE )
{
assert( ml_FtreeHasOp( left ) == 0 );
if( left == NULL )
return right;
/* Percolate down tree only for special nodes */
assert( left->op == ML_OP_SPECIAL );
if( left->left == NULL )
{
left->left = right;
return left;
}
else
{
return ml_OpConnectChilds( ML_OP_NONE, left->left, right );
}
}
else if( op == ML_OP_NOT )
{
assert( right == NULL && left != NULL );
assert( ml_FtreeHasOp( left ) > 0 );
}
else if( op == ML_OP_SPECIAL )
{
assert( 0 );
}
else
{
assert( right != NULL && left != NULL );
assert( ml_FtreeHasOp( left ) > 0 );
assert( ml_FtreeHasOp( right ) > 0 );
}
ml_ftree_t* p_parent = (ml_ftree_t *) calloc( 1, sizeof( ml_ftree_t ) );
p_parent->op = op;
p_parent->left = left;
p_parent->right = right;
return p_parent;
}
#undef ml_FtreeSpec
/**
* @brief Attaches a special node to a tree
* @param tree Tree to attach special node to
* @param crit Criteria may be SORT_ASC, SORT_DESC, LIMIT or DISTINCT
* @param limit Limit used if LIMIT criteria used
* @param Sort string used if SORT criteria is used
* @return Pointer to new tree
* @note Use the helpers
*/
ml_ftree_t* ml_FtreeSpec( ml_ftree_t* tree,
ml_select_e crit,
int limit,
char* sort )
{
assert( crit == ML_SORT_ASC || crit == ML_LIMIT || crit == ML_SORT_DESC ||
crit == ML_DISTINCT );
ml_ftree_t* right = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
right->criteria = crit;
if( crit == ML_LIMIT )
right->value.i = limit;
else if( crit == ML_SORT_ASC || crit == ML_SORT_DESC )
right->value.str = strdup( sort );
right->op = ML_OP_NONE;
ml_ftree_t* p_parent = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
p_parent->right = right;
p_parent->op = ML_OP_SPECIAL;
p_parent->left = tree;
return p_parent;
}
/**
* @brief Returns a person list of given type
* @param p_ml The ML object
* @param p_media The Media object
* @param i_type The person type
* @note This function is thread safe
*/
ml_person_t* ml_GetPersonsFromMedia( media_library_t* p_ml,
ml_media_t* p_media,
const char *psz_role )
{
VLC_UNUSED( p_ml );
assert( p_media != NULL );
ml_person_t* p_return = NULL;
ml_LockMedia( p_media );
ml_person_t* p_person = p_media->p_people;
while( p_person )
{
if( strcmp( p_person->psz_role, psz_role ) == 0 )
{
int i_ret = ml_CreateAppendPerson( &p_return, p_person );
if( i_ret != VLC_SUCCESS )
{
ml_UnlockMedia( p_media );
ml_FreePeople( p_return );
return NULL;
}
}
p_person = p_person->p_next;
}
ml_UnlockMedia( p_media );
//TODO: Fill up empty names + clean up list
return p_return;
}
/**
* @brief Delete a certain type of people from a media
* @param p_media Media to delete from
* @param i_type Type of person to delete
* @note This function is threadsafe
*/
void ml_DeletePersonTypeFromMedia( ml_media_t* p_media, const char *psz_role )
{
assert( p_media );
ml_LockMedia( p_media );
ml_person_t* p_prev = NULL;
ml_person_t* p_person = p_media->p_people;
while( p_person )
{
if( strcmp( p_person->psz_role, psz_role ) == 0 )
{
if( p_prev == NULL )
{
p_media->p_people = p_person->p_next;
p_person->p_next = NULL;
ml_FreePeople( p_person );
p_person = p_media->p_people;
}
else
{
p_prev->p_next = p_person->p_next;
p_person->p_next = NULL;
ml_FreePeople( p_person );
p_person = p_prev->p_next;
}
}
else
{
p_prev = p_person;
p_person = p_person->p_next;
}
}
ml_UnlockMedia( p_media );
}
#endif /* MEDIA_LIBRARY */
......@@ -368,74 +368,3 @@ vlm_t *vlm_New (vlc_object_t *obj)
return NULL;
}
#endif /* !ENABLE_VLM */
#ifndef MEDIA_LIBRARY
#include<vlc_media_library.h>
#undef ml_Get
media_library_t* ml_Get ( vlc_object_t* p_this )
{
VLC_UNUSED( p_this );
return NULL;
}
ml_media_t* media_New( media_library_t* p_ml, int id, ml_select_e select, bool reload )
{
VLC_UNUSED( p_ml );
VLC_UNUSED( id );
VLC_UNUSED( select );
VLC_UNUSED( reload );
assert( 0 );
return NULL;
}
#undef ml_UpdateSimple
int ml_UpdateSimple( media_library_t *p_media_library, ml_select_e selected_type,
const char* psz_lvalue, int id, ... )
{
VLC_UNUSED( p_media_library );
VLC_UNUSED( selected_type );
VLC_UNUSED( psz_lvalue );
VLC_UNUSED( id );
assert( 0 );
return 0;
}
ml_ftree_t* ml_OpConnectChilds( ml_op_e op, ml_ftree_t* left, ml_ftree_t* right )
{
VLC_UNUSED( op );
VLC_UNUSED( left );
VLC_UNUSED( right );
assert( 0 );
return NULL;
}
ml_ftree_t* ml_FtreeSpec( ml_ftree_t* tree, ml_select_e crit, int limit,
char* sort )
{
VLC_UNUSED( tree );
VLC_UNUSED( crit );
VLC_UNUSED( limit );
VLC_UNUSED( sort );
assert( 0 );
return NULL;
}
void ml_DeletePersonTypeFromMedia( ml_media_t* p_media, const char *psz_role )
{
VLC_UNUSED( p_media );
VLC_UNUSED( psz_role );
assert( 0 );
}
ml_person_t* ml_GetPersonsFromMedia( media_library_t* p_ml,
ml_media_t* p_media,
const char *psz_role )
{
VLC_UNUSED( p_ml );
VLC_UNUSED( p_media );
VLC_UNUSED( psz_role );
assert( 0 );
return NULL;
}
#endif /* !MEDIA_LIBRARY */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment