1 /*****************************************************************************
2 * media_library.c: SQL-based media library: ML creators and destructors
3 *****************************************************************************
4 * Copyright (C) 2009-2010 VLC authors and VideoLAN and AUTHORS
7 * Authors: Srikanth Raju <srikiraju at gmail dot com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
28 #if defined(MEDIA_LIBRARY)
31 #include <vlc_media_library.h>
32 #include <vlc_modules.h>
33 #include "../libvlc.h"
36 * @brief Destroy the medialibrary object
37 * @param Parent object that holds the media library object
39 void ml_Destroy( vlc_object_t * p_this )
41 media_library_t* p_ml = ( media_library_t* )p_this;
42 module_unneed( p_ml, p_ml->p_module );
47 * Atomically set the reference count to 1.
48 * @param p_gc reference counted object
49 * @param pf_destruct destruction calback
52 static void *ml_gc_init (ml_gc_object_t *p_gc, void (*pf_destruct) (ml_gc_object_t *))
54 /* There is no point in using the GC if there is no destructor... */
56 p_gc->pf_destructor = pf_destruct;
66 * @brief Create an instance of the media library
67 * @param p_this Parent object
68 * @param psz_name Name which is passed to module_need (not needed)
69 * @return p_ml created and attached, module loaded. NULL if
72 media_library_t *ml_Create( vlc_object_t *p_this, char *psz_name )
74 media_library_t *p_ml;
76 p_ml = ( media_library_t * ) vlc_custom_create(
77 p_this, sizeof( media_library_t ),
81 msg_Err( p_this, "unable to create media library object" );
85 p_ml->p_module = module_need( p_ml, "media-library", psz_name, false );
88 vlc_object_release( p_ml );
89 msg_Err( p_this, "Media Library provider not found" );
98 * @brief Acquire a reference to the media library singleton
99 * @param p_this Object that holds the reference
100 * @return media_library_t The ml object. NULL if not compiled with
101 * media library or if unable to load
103 media_library_t* ml_Get( vlc_object_t* p_this )
105 media_library_t* p_ml;
106 vlc_mutex_lock( &( libvlc_priv( p_this->p_libvlc )->ml_lock ) );
107 p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
108 assert( VLC_OBJECT( p_ml ) != p_this );
110 !var_GetBool( p_this->p_libvlc, "load-media-library-on-startup" ) )
112 libvlc_priv (p_this->p_libvlc)->p_ml
113 = ml_Create( VLC_OBJECT( p_this->p_libvlc ), NULL );
114 p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
116 vlc_mutex_unlock( &( libvlc_priv( p_this->p_libvlc )->ml_lock ) );
121 * @brief Destructor for ml_media_t
123 static void media_Destroy( ml_gc_object_t *p_gc )
125 ml_media_t* p_media = ml_priv( p_gc, ml_media_t );
126 vlc_mutex_destroy( &p_media->lock );
127 ml_FreeMediaContent( p_media );
132 * @brief Object constructor for ml_media_t
133 * @param p_ml The media library object
134 * @param id If 0, this item isn't in database. If non zero, it is and
135 * it will be a singleton
136 * @param select Type of object
137 * @param reload Whether to reload from database
139 ml_media_t* media_New( media_library_t* p_ml, int id,
140 ml_select_e select, bool reload )
144 ml_media_t* p_media = NULL;
145 p_media = ( ml_media_t* )calloc( 1, sizeof( ml_media_t ) );
146 ml_gc_init( &p_media->ml_gc_data, media_Destroy );
147 vlc_mutex_init( &p_media->lock );
151 return p_ml->functions.pf_GetMedia( p_ml, id, select, reload );
154 #undef ml_UpdateSimple
156 * @brief Update a given table
157 * @param p_media_library The media library object
158 * @param selected_type The table to update
159 * @param psz_lvalue The role of the person if selected_type = ML_PEOPLE
160 * @param id The id of the row to update
161 * @param ... The update data. [SelectType [RoleType] Value] ... ML_END
163 int ml_UpdateSimple( media_library_t *p_media_library,
164 ml_select_e selected_type,
165 const char* psz_lvalue,
168 ml_element_t *update;
169 vlc_array_t *array = vlc_array_new();
170 int i_ret = VLC_SUCCESS;
173 va_start( args, id );
177 update = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) );
178 sel = ( ml_select_e ) va_arg( args, int );
179 update->criteria = sel;
180 if( sel == ML_PEOPLE )
182 update->lvalue.str = va_arg( args, char* );
183 update->value.str = va_arg( args, char* );
184 vlc_array_append( array, update );
186 else if( sel == ML_PEOPLE_ID )
188 update->lvalue.str = va_arg( args, char* );
189 update->value.i = va_arg( args, int );
190 vlc_array_append( array, update );
192 else if( sel == ML_PEOPLE_ROLE )
195 msg_Dbg( p_media_library,
196 "this argument is invalid for Update: %d",
202 switch( ml_AttributeIsString( sel ) )
208 msg_Dbg( p_media_library,
209 "this argument is invalid for Update: %d",
214 else if( sel == ML_END )
215 vlc_array_append( array, update );
218 update->value.str = va_arg( args, char* );
219 vlc_array_append( array, update );
222 update->value.i = va_arg( args, int );
223 vlc_array_append( array, update );
227 } while( sel != ML_END );
231 ml_ftree_t* p_where = NULL;
232 ml_ftree_t* find = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
233 find->criteria = ML_ID;
235 find->comp = ML_COMP_EQUAL;
236 p_where = ml_FtreeFastAnd( p_where, find );
238 /* Let's update the database ! */
239 if( i_ret == VLC_SUCCESS )
240 i_ret = ml_Update( p_media_library, selected_type, psz_lvalue,
243 /* Destroying array */
244 for( int i = 0; i < vlc_array_count( array ); i++ )
246 free( vlc_array_item_at_index( array, i ) );
248 vlc_array_destroy( array );
249 ml_FreeFindTree( p_where );
255 * @brief Connect up a find tree
256 * @param op operator to connect with
257 * If op = ML_OP_NONE, then you are connecting to a tree consisting of
258 * only SPECIAL nodes.
259 * If op = ML_OP_NOT, then right MUST be NULL
260 * op must not be ML_OP_SPECIAL, @see ml_FtreeSpec
261 * @param left part of the tree
262 * @param right part of the tree
263 * @return Pointer to new tree
264 * @note Use the helpers!
266 ml_ftree_t* ml_OpConnectChilds( ml_op_e op, ml_ftree_t* left,
269 /* Use this Op for fresh trees (with only special nodes/none at all!) */
270 if( op == ML_OP_NONE )
272 assert( ml_FtreeHasOp( left ) == 0 );
275 /* Percolate down tree only for special nodes */
276 assert( left->op == ML_OP_SPECIAL );
277 if( left->left == NULL )
284 return ml_OpConnectChilds( ML_OP_NONE, left->left, right );
287 else if( op == ML_OP_NOT )
289 assert( right == NULL && left != NULL );
290 assert( ml_FtreeHasOp( left ) > 0 );
292 else if( op == ML_OP_SPECIAL )
298 assert( right != NULL && left != NULL );
299 assert( ml_FtreeHasOp( left ) > 0 );
300 assert( ml_FtreeHasOp( right ) > 0 );
302 ml_ftree_t* p_parent = (ml_ftree_t *) calloc( 1, sizeof( ml_ftree_t ) );
304 p_parent->left = left;
305 p_parent->right = right;
311 * @brief Attaches a special node to a tree
312 * @param tree Tree to attach special node to
313 * @param crit Criteria may be SORT_ASC, SORT_DESC, LIMIT or DISTINCT
314 * @param limit Limit used if LIMIT criteria used
315 * @param Sort string used if SORT criteria is used
316 * @return Pointer to new tree
317 * @note Use the helpers
319 ml_ftree_t* ml_FtreeSpec( ml_ftree_t* tree,
324 assert( crit == ML_SORT_ASC || crit == ML_LIMIT || crit == ML_SORT_DESC ||
325 crit == ML_DISTINCT );
326 ml_ftree_t* right = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
327 right->criteria = crit;
328 if( crit == ML_LIMIT )
329 right->value.i = limit;
330 else if( crit == ML_SORT_ASC || crit == ML_SORT_DESC )
331 right->value.str = strdup( sort );
332 right->op = ML_OP_NONE;
333 ml_ftree_t* p_parent = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
334 p_parent->right = right;
335 p_parent->op = ML_OP_SPECIAL;
336 p_parent->left = tree;
342 * @brief Returns a person list of given type
343 * @param p_ml The ML object
344 * @param p_media The Media object
345 * @param i_type The person type
346 * @note This function is thread safe
348 ml_person_t* ml_GetPersonsFromMedia( media_library_t* p_ml,
350 const char *psz_role )
353 assert( p_media != NULL );
354 ml_person_t* p_return = NULL;
355 ml_LockMedia( p_media );
356 ml_person_t* p_person = p_media->p_people;
359 if( strcmp( p_person->psz_role, psz_role ) == 0 )
361 int i_ret = ml_CreateAppendPerson( &p_return, p_person );
362 if( i_ret != VLC_SUCCESS )
364 ml_UnlockMedia( p_media );
365 ml_FreePeople( p_return );
369 p_person = p_person->p_next;
371 ml_UnlockMedia( p_media );
372 //TODO: Fill up empty names + clean up list
377 * @brief Delete a certain type of people from a media
378 * @param p_media Media to delete from
379 * @param i_type Type of person to delete
380 * @note This function is threadsafe
382 void ml_DeletePersonTypeFromMedia( ml_media_t* p_media, const char *psz_role )
385 ml_LockMedia( p_media );
386 ml_person_t* p_prev = NULL;
387 ml_person_t* p_person = p_media->p_people;
391 if( strcmp( p_person->psz_role, psz_role ) == 0 )
395 p_media->p_people = p_person->p_next;
396 p_person->p_next = NULL;
397 ml_FreePeople( p_person );
398 p_person = p_media->p_people;
402 p_prev->p_next = p_person->p_next;
403 p_person->p_next = NULL;
404 ml_FreePeople( p_person );
405 p_person = p_prev->p_next;
411 p_person = p_person->p_next;
414 ml_UnlockMedia( p_media );
417 #endif /* MEDIA_LIBRARY */