Playlist: fix scrolling events in selector
[vlc/vlc-skelet.git] / src / misc / media_library.c
blobe855703452363a942427ea405d56c93f7c101872
1 /*****************************************************************************
2 * media_library.c: SQL-based media library: ML creators and destructors
3 *****************************************************************************
4 * Copyright (C) 2009-2010 the VideoLAN team and AUTHORS
5 * $Id$
7 * Authors: Srikanth Raju <srikiraju at gmail dot com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
28 #if defined(MEDIA_LIBRARY)
30 #include <assert.h>
31 #include <vlc_media_library.h>
32 #include <vlc_modules.h>
33 #include "../libvlc.h"
35 /**
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 );
46 /**
47 * Atomically set the reference count to 1.
48 * @param p_gc reference counted object
49 * @param pf_destruct destruction calback
50 * @return p_gc.
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... */
55 assert (pf_destruct);
56 p_gc->pf_destructor = pf_destruct;
58 p_gc->pool = false;
59 p_gc->refs = 1;
60 /* Nobody else can possibly lock the spin - it's there as a barrier */
61 vlc_spin_init (&p_gc->spin);
62 vlc_spin_lock (&p_gc->spin);
63 vlc_spin_unlock (&p_gc->spin);
64 return p_gc;
69 /**
70 * @brief Create an instance of the media library
71 * @param p_this Parent object
72 * @param psz_name Name which is passed to module_need (not needed)
73 * @return p_ml created and attached, module loaded. NULL if
74 * not able to load
76 media_library_t *ml_Create( vlc_object_t *p_this, char *psz_name )
78 media_library_t *p_ml;
80 p_ml = ( media_library_t * ) vlc_custom_create(
81 p_this, sizeof( media_library_t ),
82 VLC_OBJECT_GENERIC, "media-library" );
83 if( !p_ml )
85 msg_Err( p_this, "unable to create media library object" );
86 return NULL;
88 vlc_object_attach( p_ml, p_this );
90 p_ml->p_module = module_need( p_ml, "media-library", psz_name, false );
91 if( !p_ml->p_module )
93 vlc_object_release( p_ml );
94 msg_Err( p_this, "Media Library provider not found" );
95 return NULL;
98 return p_ml;
101 #undef ml_Get
103 * @brief Acquire a reference to the media library singleton
104 * @param p_this Object that holds the reference
105 * @return media_library_t The ml object. NULL if not compiled with
106 * media library or if unable to load
108 media_library_t* ml_Get( vlc_object_t* p_this )
110 media_library_t* p_ml;
111 vlc_mutex_lock( &( libvlc_priv( p_this->p_libvlc )->ml_lock ) );
112 p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
113 assert( VLC_OBJECT( p_ml ) != p_this );
114 if( p_ml == NULL &&
115 !var_GetBool( p_this->p_libvlc, "load-media-library-on-startup" ) )
117 libvlc_priv (p_this->p_libvlc)->p_ml
118 = ml_Create( VLC_OBJECT( p_this->p_libvlc ), NULL );
119 p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
121 vlc_mutex_unlock( &( libvlc_priv( p_this->p_libvlc )->ml_lock ) );
122 return p_ml;
126 * @brief Destructor for ml_media_t
128 static void media_Destroy( ml_gc_object_t *p_gc )
130 ml_media_t* p_media = ml_priv( p_gc, ml_media_t );
131 vlc_mutex_destroy( &p_media->lock );
132 ml_FreeMediaContent( p_media );
133 free( p_media );
137 * @brief Object constructor for ml_media_t
138 * @param p_ml The media library object
139 * @param id If 0, this item isn't in database. If non zero, it is and
140 * it will be a singleton
141 * @param select Type of object
142 * @param reload Whether to reload from database
144 ml_media_t* media_New( media_library_t* p_ml, int id,
145 ml_select_e select, bool reload )
147 if( id == 0 )
149 ml_media_t* p_media = NULL;
150 p_media = ( ml_media_t* )calloc( 1, sizeof( ml_media_t ) );
151 ml_gc_init( &p_media->ml_gc_data, media_Destroy );
152 vlc_mutex_init( &p_media->lock );
153 return p_media;
155 else
156 return p_ml->functions.pf_GetMedia( p_ml, id, select, reload );
159 #undef ml_UpdateSimple
161 * @brief Update a given table
162 * @param p_media_library The media library object
163 * @param selected_type The table to update
164 * @param psz_lvalue The role of the person if selected_type = ML_PEOPLE
165 * @param id The id of the row to update
166 * @param ... The update data. [SelectType [RoleType] Value] ... ML_END
168 int ml_UpdateSimple( media_library_t *p_media_library,
169 ml_select_e selected_type,
170 const char* psz_lvalue,
171 int id, ... )
173 ml_element_t *update;
174 vlc_array_t *array = vlc_array_new();
175 int i_ret = VLC_SUCCESS;
177 va_list args;
178 va_start( args, id );
180 ml_select_e sel;
181 do {
182 update = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) );
183 sel = ( ml_select_e ) va_arg( args, int );
184 update->criteria = sel;
185 if( sel == ML_PEOPLE )
187 update->lvalue.str = va_arg( args, char* );
188 update->value.str = va_arg( args, char* );
189 vlc_array_append( array, update );
191 else if( sel == ML_PEOPLE_ID )
193 update->lvalue.str = va_arg( args, char* );
194 update->value.i = va_arg( args, int );
195 vlc_array_append( array, update );
197 else if( sel == ML_PEOPLE_ROLE )
199 #ifndef NDEBUG
200 msg_Dbg( p_media_library,
201 "this argument is invalid for Update: %d",
202 (int)sel );
203 #endif
205 else
207 switch( ml_AttributeIsString( sel ) )
209 case -1:
210 if( sel != ML_END )
212 #ifndef NDEBUG
213 msg_Dbg( p_media_library,
214 "this argument is invalid for Update: %d",
215 (int)sel );
216 #endif
217 i_ret = VLC_EGENERIC;
219 else if( sel == ML_END )
220 vlc_array_append( array, update );
221 break;
222 case 0:
223 update->value.str = va_arg( args, char* );
224 vlc_array_append( array, update );
225 break;
226 case 1:
227 update->value.i = va_arg( args, int );
228 vlc_array_append( array, update );
229 break;
232 } while( sel != ML_END );
234 va_end( args );
236 ml_ftree_t* p_where = NULL;
237 ml_ftree_t* find = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
238 find->criteria = ML_ID;
239 find->value.i = id ;
240 find->comp = ML_COMP_EQUAL;
241 p_where = ml_FtreeFastAnd( p_where, find );
243 /* Let's update the database ! */
244 if( i_ret == VLC_SUCCESS )
245 i_ret = ml_Update( p_media_library, selected_type, psz_lvalue,
246 p_where, array );
248 /* Destroying array */
249 for( int i = 0; i < vlc_array_count( array ); i++ )
251 free( vlc_array_item_at_index( array, i ) );
253 vlc_array_destroy( array );
254 ml_FreeFindTree( p_where );
256 return i_ret;
260 * @brief Connect up a find tree
261 * @param op operator to connect with
262 * If op = ML_OP_NONE, then you are connecting to a tree consisting of
263 * only SPECIAL nodes.
264 * If op = ML_OP_NOT, then right MUST be NULL
265 * op must not be ML_OP_SPECIAL, @see ml_FtreeSpec
266 * @param left part of the tree
267 * @param right part of the tree
268 * @return Pointer to new tree
269 * @note Use the helpers!
271 ml_ftree_t* ml_OpConnectChilds( ml_op_e op, ml_ftree_t* left,
272 ml_ftree_t* right )
274 /* Use this Op for fresh trees (with only special nodes/none at all!) */
275 if( op == ML_OP_NONE )
277 assert( ml_FtreeHasOp( left ) == 0 );
278 if( left == NULL )
279 return right;
280 /* Percolate down tree only for special nodes */
281 assert( left->op == ML_OP_SPECIAL );
282 if( left->left == NULL )
284 left->left = right;
285 return left;
287 else
289 return ml_OpConnectChilds( ML_OP_NONE, left->left, right );
292 else if( op == ML_OP_NOT )
294 assert( right == NULL && left != NULL );
295 assert( ml_FtreeHasOp( left ) > 0 );
297 else if( op == ML_OP_SPECIAL )
299 assert( 0 );
301 else
303 assert( right != NULL && left != NULL );
304 assert( ml_FtreeHasOp( left ) > 0 );
305 assert( ml_FtreeHasOp( right ) > 0 );
307 ml_ftree_t* p_parent = (ml_ftree_t *) calloc( 1, sizeof( ml_ftree_t ) );
308 p_parent->op = op;
309 p_parent->left = left;
310 p_parent->right = right;
311 return p_parent;
314 #undef ml_FtreeSpec
316 * @brief Attaches a special node to a tree
317 * @param tree Tree to attach special node to
318 * @param crit Criteria may be SORT_ASC, SORT_DESC, LIMIT or DISTINCT
319 * @param limit Limit used if LIMIT criteria used
320 * @param Sort string used if SORT criteria is used
321 * @return Pointer to new tree
322 * @note Use the helpers
324 ml_ftree_t* ml_FtreeSpec( ml_ftree_t* tree,
325 ml_select_e crit,
326 int limit,
327 char* sort )
329 assert( crit == ML_SORT_ASC || crit == ML_LIMIT || crit == ML_SORT_DESC ||
330 crit == ML_DISTINCT );
331 ml_ftree_t* right = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
332 right->criteria = crit;
333 if( crit == ML_LIMIT )
334 right->value.i = limit;
335 else if( crit == ML_SORT_ASC || crit == ML_SORT_DESC )
336 right->value.str = strdup( sort );
337 right->op = ML_OP_NONE;
338 ml_ftree_t* p_parent = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
339 p_parent->right = right;
340 p_parent->op = ML_OP_SPECIAL;
341 p_parent->left = tree;
342 return p_parent;
347 * @brief Creates and adds the playlist based on a given find tree
348 * @param p_ml Media library object
349 * @param p_tree Find tree to create SELECT
351 void ml_PlaySmartPlaylistBasedOn( media_library_t* p_ml,
352 ml_ftree_t* p_tree )
354 assert( p_tree );
355 vlc_array_t* p_results = vlc_array_new();
356 ml_FindAdv( p_ml, p_results, ML_ID, NULL, p_tree );
357 playlist_t* p_pl = pl_Get( p_ml );
358 playlist_Lock( p_pl );
359 playlist_Clear( p_pl, true );
360 for( int i = 0; i < vlc_array_count( p_results ); i++ )
362 ml_result_t* p_res = ( ml_result_t* ) vlc_array_item_at_index( p_results, i );
363 input_item_t* p_item;
364 if( p_res )
366 p_item = ml_CreateInputItem( p_ml, p_res->value.i );
367 playlist_AddInput( p_pl, p_item, PLAYLIST_APPEND,
368 PLAYLIST_END, true, true );
371 playlist_Unlock( p_pl );
372 ml_DestroyResultArray( p_results );
373 vlc_array_destroy( p_results );
377 * @brief Returns a person list of given type
378 * @param p_ml The ML object
379 * @param p_media The Media object
380 * @param i_type The person type
381 * @note This function is thread safe
383 ml_person_t* ml_GetPersonsFromMedia( media_library_t* p_ml,
384 ml_media_t* p_media,
385 const char *psz_role )
387 VLC_UNUSED( p_ml );
388 assert( p_media != NULL );
389 ml_person_t* p_return = NULL;
390 ml_LockMedia( p_media );
391 ml_person_t* p_person = p_media->p_people;
392 while( p_person )
394 if( strcmp( p_person->psz_role, psz_role ) == 0 )
396 int i_ret = ml_CreateAppendPerson( &p_return, p_person );
397 if( i_ret != VLC_SUCCESS )
399 ml_UnlockMedia( p_media );
400 ml_FreePeople( p_return );
401 return NULL;
404 p_person = p_person->p_next;
406 ml_UnlockMedia( p_media );
407 //TODO: Fill up empty names + clean up list
408 return p_return;
412 * @brief Delete a certain type of people from a media
413 * @param p_media Media to delete from
414 * @param i_type Type of person to delete
415 * @note This function is threadsafe
417 void ml_DeletePersonTypeFromMedia( ml_media_t* p_media, const char *psz_role )
419 assert( p_media );
420 ml_LockMedia( p_media );
421 ml_person_t* p_prev = NULL;
422 ml_person_t* p_person = p_media->p_people;
424 while( p_person )
426 if( strcmp( p_person->psz_role, psz_role ) == 0 )
428 if( p_prev == NULL )
430 p_media->p_people = p_person->p_next;
431 p_person->p_next = NULL;
432 ml_FreePeople( p_person );
433 p_person = p_media->p_people;
435 else
437 p_prev->p_next = p_person->p_next;
438 p_person->p_next = NULL;
439 ml_FreePeople( p_person );
440 p_person = p_prev->p_next;
443 else
445 p_prev = p_person;
446 p_person = p_person->p_next;
449 ml_UnlockMedia( p_media );
452 #endif /* MEDIA_LIBRARY */