1 /*****************************************************************************
2 * vlc_media_library.h: SQL-based media library
3 *****************************************************************************
4 * Copyright (C) 2008-2010 the VideoLAN Team and AUTHORS
7 * Authors: Antoine Lejeune <phytos@videolan.org>
8 * Jean-Philippe André <jpeg@videolan.org>
9 * Rémi Duraffort <ivoire@videolan.org>
10 * Adrien Maglo <magsoft@videolan.org>
11 * Srikanth Raju <srikiraju at gmail dot com>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 #ifndef VLC_MEDIA_LIBRARY_H
29 # define VLC_MEDIA_LIBRARY_H
35 #include <vlc_common.h>
37 #include <vlc_playlist.h>
39 /*****************************************************************************
41 *****************************************************************************/
43 #define ML_PERSON_ARTIST "Artist"
44 #define ML_PERSON_ALBUM_ARTIST "Album Artist"
45 #define ML_PERSON_ENCODER "Encoder"
46 #define ML_PERSON_PUBLISHER "Publisher"
49 #define ml_priv( gc, t ) ((t *)(((char *)(gc)) - offsetof(t, ml_gc_data)))
51 /** List of Query select types.
52 * In a query array or variable argument list, each select type is followed
53 * by an argument (X) of variable type (char* or int, @see ml_element_t).
54 * These types can be used either in the query list or in the result array.
55 * Some types are reserved for the result array:
59 ML_ALBUM = 1, /**< Album Title */
60 ML_ALBUM_ID, /**< Album ID */
61 ML_ALBUM_COVER, /**< Album Cover art url */
62 /* FIXME: Remove ML_ARTIST */
63 ML_ARTIST, /**< Artist, interpreted as ML_PEOPLE
64 && ML_PEOPLE_ROLE = ML_PERSON_ARTIST */
65 ML_ARTIST_ID, /**< Artist ID, interpreted as ML_PEOPLE_ID
66 && ML_PEOPLE_ROLE = ML_PERSON_ARTIST */
67 ML_COMMENT, /**< Comment about media */
68 ML_COUNT_MEDIA, /**< Number of medias */
69 ML_COUNT_ALBUM, /**< Number of albums */
70 ML_COUNT_PEOPLE, /**< Number of people */
71 ML_COVER, /**< Cover art url */
72 ML_DURATION, /**< Duration in ms */
73 ML_DISC_NUMBER, /**< Disc number of the track */
74 ML_EXTRA, /**< Extra/comment (string) on the media */
75 ML_FIRST_PLAYED, /**< First time media was played */
76 ML_FILESIZE, /**< Size of the media file */
77 ML_GENRE, /**< Genre of the media (if any) */
78 ML_ID, /**< Media ID */
79 ML_IMPORT_TIME, /**< Date when media was imported */
80 ML_LANGUAGE, /**< Language */
81 ML_LAST_PLAYED, /**< Last play UNIX timestamp */
82 ML_LAST_SKIPPED, /**< Time when media was last skipped */
83 ML_ORIGINAL_TITLE, /**< Media original title (if any) */
84 ML_PEOPLE, /**< Any People associated with this media */
85 ML_PEOPLE_ID, /**< Id of a person */
86 ML_PEOPLE_ROLE, /**< Person role */
87 ML_PLAYED_COUNT, /**< Media play count */
88 ML_PREVIEW, /**< Url of the video preview */
89 ML_SKIPPED_COUNT, /**< Number of times skipped */
90 ML_SCORE, /**< Computed media score */
91 ML_TITLE, /**< Media title */
92 ML_TRACK_NUMBER, /**< Media track number (if any) */
93 ML_TYPE, /**< Media type. @see ml_type_e */
94 ML_URI, /**< Media full URI. */
95 ML_VOTE, /**< Media user vote value */
96 ML_YEAR, /**< Media publishing year */
97 ML_DIRECTORY, /**< Monitored directory */
98 ML_MEDIA, /**< Full media descriptor. @see ml_media_t */
99 ML_MEDIA_SPARSE, /**< Sparse media. @see ml_media_t */
100 ML_MEDIA_EXTRA, /**< Sparse + Extra = Full media */
102 /* Some special elements */
103 ML_LIMIT = -1, /**< Limit a query to X results */
104 ML_SORT_DESC = -2, /**< Sort a query descending on argument X */
105 ML_SORT_ASC = -3, /**< Sort a query ascending on argument X */
106 ML_DISTINCT = -4, /**< Add DISTINCT to SELECT statements. */
107 ML_END = -42 /**< End of argument list */
110 /** Media types (audio, video, etc...) */
113 ML_UNKNOWN = 0, /**< Unknown media type */
114 ML_AUDIO = 1 << 0, /**< Audio only media */
115 ML_VIDEO = 1 << 1, /**< Video media. May contain audio channels */
116 ML_STREAM = 1 << 2, /**< Streamed media = not a local file */
117 ML_NODE = 1 << 3, /**< Nodes like simple nodes, directories, playlists, etc */
118 ML_REMOVABLE = 1 << 4, /**< Removable media: CD/DVD/Card/... */
121 /** Query result item/list type: integers, strings, medias, timestamps */
123 ML_TYPE_INT, /**< Object is an int */
124 ML_TYPE_PSZ, /**< A string char* */
125 ML_TYPE_TIME, /**< A timestamp mtime_t */
126 ML_TYPE_MEDIA, /**< A pointer to a media ml_media_t* */
129 /** Arguments for VLC Control for the media library */
132 ML_SET_DATABASE, /**< arg1 = char *psz_host
134 arg3 = char *psz_user
135 arg4 = char *psz_pass */
136 ML_INIT_DATABASE, /**< No arg */
137 ML_ADD_INPUT_ITEM, /**< arg1 = input_item_t* */
138 ML_ADD_PLAYLIST_ITEM, /**< arg1 = playlist_item_t * */
139 ML_ADD_MONITORED, /**< arg1 = char* */
140 ML_DEL_MONITORED, /**< arg1 = char* */
141 ML_GET_MONITORED, /**< arg1 = vlc_array_t* */
144 /* Operations that can be specified between find conditions */
147 ML_OP_NONE = 0, /**< This is to specify an actual condition */
148 ML_OP_AND, /**< AND condition */
149 ML_OP_OR, /**< OR condition */
150 ML_OP_NOT, /**< NOT condition */
151 ML_OP_SPECIAL /**< This is for inclusion of
152 * special stuffs like LIMIT */
155 /* Comparison operators used in a single find condition */
159 ML_COMP_LESSER, ///< <
160 ML_COMP_LESSER_OR_EQUAL, ///< <=
161 ML_COMP_EQUAL, ///< ==
162 ML_COMP_GREATER_OR_EQUAL, ///< >=
163 ML_COMP_GREATER, ///< >
164 ML_COMP_HAS, ///< "Contains", equivalent to SQL "LIKE %x%"
165 ML_COMP_STARTS_WITH, ///< Equivalent to SQL "LIKE %x"
166 ML_COMP_ENDS_WITH, ///< Equivalent to SQL "LIKE x%"
169 /*****************************************************************************
170 * ML Structures and types
171 *****************************************************************************/
173 typedef struct media_library_t media_library_t;
174 typedef struct media_library_sys_t media_library_sys_t;
176 typedef struct ml_media_t ml_media_t;
177 typedef struct ml_result_t ml_result_t;
178 typedef struct ml_element_t ml_element_t;
179 typedef struct ml_person_t ml_person_t;
180 typedef struct ml_ftree_t ml_ftree_t;
183 typedef struct ml_gc_object_t
188 void (*pf_destructor) (struct ml_gc_object_t *);
191 #define ML_GC_MEMBERS ml_gc_object_t ml_gc_data;
193 /** Main structure of the media library. VLC object. */
194 struct media_library_t
198 module_t *p_module; /**< the media library module */
199 media_library_sys_t *p_sys; /**< internal struture */
201 /** Member functions */
204 /**< Search in the database */
205 int ( * pf_Find ) ( media_library_t *p_media_library,
206 vlc_array_t *p_result_array,
209 /**< Search in the database using an array of arguments */
210 int ( * pf_FindAdv ) ( media_library_t *p_media_library,
211 vlc_array_t *p_result_array,
212 ml_select_e selected_type,
213 const char *psz_lvalue,
216 /**< Update the database using an array of arguments */
217 int ( * pf_Update ) ( media_library_t *p_media_library,
218 ml_select_e selected_type,
219 const char *psz_lvalue,
221 vlc_array_t *changes );
223 /**< Delete many medias in the database */
224 int ( * pf_Delete ) ( media_library_t *p_media_library,
225 vlc_array_t *p_array );
227 /**< Control the media library */
228 int ( * pf_Control ) ( media_library_t *p_media_library,
229 int i_query, va_list args );
231 /**< Create associated input item */
232 input_item_t* ( * pf_InputItemFromMedia ) (
233 media_library_t *p_media_library, int i_media );
236 ml_media_t* ( * pf_GetMedia ) (
237 media_library_t *p_media_library, int i_media,
238 ml_select_e select, bool reload );
244 * @brief Structure to describe a media
246 * This is the main structure holding the meta data in ML.
247 * @see b_sparse indicates whether the media struct has valid values
248 * in its Extra fields. Otherwise, it must be loaded with the API
250 * @see i_id indicates whether this struct is saved in the ML if i_id > 0
251 * Otherwise, it can be added to the database
256 vlc_mutex_t lock; /**< Mutex for multithreaded access */
257 bool b_sparse; /**< Specifies if media is loaded fully */
258 ml_type_e i_type; /**< Type of the media (ml_type_e) */
259 int8_t i_vote; /**< User vote */
260 int16_t i_disc_number; /**< Disc number of media */
261 int16_t i_track_number; /**< Track number */
262 int16_t i_year; /**< Year of release */
263 int32_t i_id; /**< Media ID in the database */
264 int32_t i_score; /**< Score computed about the media */
265 int32_t i_album_id; /**< Album id */
266 int32_t i_played_count; /**< How many time the media was played */
267 int32_t i_skipped_count; /**< No. of times file was skipped */
268 int32_t i_bitrate; /**< Extra: Bitrate of the media */
269 int32_t i_samplerate; /**< Extra: Samplerate of the media */
270 int32_t i_bpm; /**< Extra: Beats per minute */
271 char *psz_uri; /**< URI to find the media */
272 char *psz_title; /**< Title of the media */
273 char *psz_orig_title; /**< Original title (mainly for movies) */
274 char *psz_album; /**< Name of the album */
275 char *psz_cover; /**< URI of the cover */
276 char *psz_genre; /**< Genre of the media */
277 char *psz_preview; /**< Preview thumbnail for video, if any */
278 char *psz_comment; /**< Comment or description about media */
279 char *psz_language; /**< Extra: Language */
280 char *psz_extra; /**< Extra: Some extra datas like lyrics */
281 ml_person_t *p_people; /**< Extra: People associated with this
282 media This meta holds only one
283 artist if b_sparse = true */
284 int64_t i_filesize; /**< Size of the file */
285 mtime_t i_duration; /**< Duration in microseconds */
286 mtime_t i_last_played; /**< Time when the media was last played */
287 mtime_t i_last_skipped; /**< Time when the media was last skipped */
288 mtime_t i_first_played; /**< First played */
289 mtime_t i_import_time; /**< Time when media was added */
295 * @brief Main communication struct between GUI and sql_media_library.
296 * Generic representation of an ML/SQL query result.
300 int32_t id; /**< Media/Album/Artist... ID (if any) */
301 ml_result_type_e type; /**< Type of value */
304 /* Classical results */
309 /* Complex result: media descriptor */
311 } value; /**< Value of the result obtained */
316 * @brief Element of a query: criteria type/value pair
317 * Used for update and delete queries
321 ml_select_e criteria; /**< SELECT criteria type. @see ml_select_e */
326 } value; /**< SELECT criteria value (string or int) */
331 } lvalue; /**< Refer to @see ml_ftree_t lvalue docs */
335 * Binary tree used to parse the WHERE condition for a search
337 * Let [expr] indicate a valid expression
338 * [expr] = [expr] AND [expr], where the left and right are respective
339 * [expr] = [expr] OR [expr]
340 * [expr] = [expr] NOT [NULL]
341 * [expr] = [expr] SPEC [spec_expr]
342 * [expr] = [criteria=val]
343 * [spec_expr] = [DISTINCT/LIMIT/ASC/DESC = val ]
347 ml_op_e op; /**< Operator. ML_OP_NONE means this is a leaf
348 * node. Criteria and value gives its data.
349 * ML_OP_SPECIAL specifies a special node
350 * that does not form a part of the WHERE.
351 * The right node consists of the data
352 * with its criteria set to the special val
353 * and the left node is the corresponding
354 * subtree of the parent node.
355 * ML_OP_NOT only left sub tree is considered
356 * ML_OP_AND and ML_OP_OR consider both
357 * left and right subtrees */
358 ml_ftree_t *left; /**< Left child of Bin tree */
359 ml_ftree_t *right; /**< Right child of Bin tree */
360 ml_select_e criteria; /**< SELECT criteria type @see ml_select_e
361 * The criteria value is considered only when
362 * op = ML_OP_NONE i.e. in leaf nodes */
363 ml_comp_e comp; /**< Condition between type and value */
368 } value; /**< SELECT criteria value ( string or int ) */
373 } lvalue; /**< Used as key value for people types/roles.
374 An empty string "" denotes ANY person role.
375 NULL is used for all other criterias */
380 * Person class. Implemented as a linked list
384 char *psz_role; /**< Type of person */
385 char *psz_name; /**< Name of the person */
386 int i_id; /**< ID in the database */
387 ml_person_t *p_next; /**< Next person in list */
391 /*****************************************************************************
392 * ML Function headers
393 *****************************************************************************/
396 * @brief Acquire a reference to the media library singleton
397 * @param p_this The object holding the media library
398 * @return The media library object. NULL if the media library
399 * object could not be loaded
401 VLC_EXPORT( media_library_t*, __ml_Hold, ( vlc_object_t* p_this ) );
402 #define ml_Hold( a ) __ml_Hold( VLC_OBJECT(a) )
405 * @brief Discard your ref to media library
406 * @param p_this The object holding the media library
408 VLC_EXPORT( void, __ml_Release, ( vlc_object_t* p_this ) );
409 #define ml_Release(a) __ml_Release( VLC_OBJECT(a))
412 * @brief Create a Media Library VLC object.
413 * @param p_this Parent to attach the ML object to.
414 * @param psz_name Name for the module
415 * @return The ML object.
417 VLC_EXPORT( media_library_t*, __ml_Create, ( vlc_object_t *p_this, char* psz_name ) );
420 * @brief Destructor for the Media library singleton
421 * @param p_this Parent the ML object is attached to
423 VLC_EXPORT( void, __ml_Destroy, ( vlc_object_t* p_this ) );
426 * @brief Control the Media Library
427 * @param p_media_library the media library object
428 * @param i_type one of ml_control_e values @see ml_control_e.
429 * @param ... optional arguments.
430 * @return VLC_SUCCESS or an error
432 static inline int ml_ControlVa( media_library_t *p_media_library,
433 ml_control_e i_type, va_list args )
435 return p_media_library->functions.pf_Control( p_media_library,
441 * @brief Control the Media Library
442 * @param i_type one of ml_control_e values @see ml_control_e.
443 * Variable arguments list equivalent
445 #define ml_Control( a, b, args... ) __ml_Control( a, b, ## args )
446 static inline int __ml_Control( media_library_t *p_media_library,
447 ml_control_e i_type, ... )
452 va_start( args, i_type );
453 returned = ml_ControlVa( p_media_library, i_type, args );
460 * @brief Determine an attribute's type (int or string)
461 * @param meta Attribute to test @see ml_select_e
462 * @return -1 if invalid, 0 if this is an integer, 1 if this is a string
464 static inline int ml_AttributeIsString( ml_select_e meta )
479 case ML_ORIGINAL_TITLE:
491 case ML_COUNT_PEOPLE:
493 case ML_FIRST_PLAYED:
498 case ML_PLAYED_COUNT:
501 case ML_SKIPPED_COUNT:
502 case ML_TRACK_NUMBER:
508 /* Invalid or no following value (in a SELECT statement) */
514 /* Reference Counting Functions */
516 * @brief Increment reference count of media
517 * @param p_media The media object
519 static inline void ml_gc_incref( ml_media_t* p_media )
522 ml_gc_object_t* p_gc = &p_media->ml_gc_data;
525 vlc_spin_lock (&p_gc->spin);
527 vlc_spin_unlock (&p_gc->spin);
528 assert (refs != 1); /* there had to be a reference already */
532 * @brief Decrease reference count of media
533 * @param p_media The media object
535 static inline void ml_gc_decref( ml_media_t* p_media )
537 /* The below code is from vlc_release(). */
540 ml_gc_object_t* p_gc = &p_media->ml_gc_data;
543 vlc_spin_lock (&p_gc->spin);
544 assert( p_gc->refs != 0 );
547 assert( ( refs != 0 && p_gc->pool == true ) || ( refs == 0 && p_gc->pool == false ) );
548 vlc_spin_unlock (&p_gc->spin);
550 if( refs == 0 && pool == false )
552 vlc_spin_destroy (&p_gc->spin);
553 p_gc->pf_destructor (p_gc);
557 /*****************************************************************************
559 *****************************************************************************/
562 * @brief Free a person object
563 * @param p_media Person object to free
564 * @note This function is NOT threadsafe
566 static inline void ml_FreePeople( ml_person_t *p_person )
568 if( p_person == NULL )
570 ml_FreePeople( p_person->p_next );
571 free( p_person->psz_name );
572 free( p_person->psz_role );
577 * @brief Free only the content of a media. @see ml_media_t
578 * @param p_media Media object
579 * @note This function is NOT threadsafe.
581 static inline void ml_FreeMediaContent( ml_media_t *p_media )
583 free( p_media->psz_uri );
584 free( p_media->psz_title );
585 free( p_media->psz_orig_title );
586 free( p_media->psz_cover );
587 free( p_media->psz_comment );
588 free( p_media->psz_extra );
589 free( p_media->psz_genre );
590 free( p_media->psz_album );
591 free( p_media->psz_preview );
592 free( p_media->psz_language );
593 ml_FreePeople( p_media->p_people );
594 p_media->b_sparse = true;
596 p_media->i_type = ML_UNKNOWN;
597 p_media->i_album_id = 0;
598 p_media->i_disc_number = 0;
599 p_media->i_track_number = 0;
602 p_media->i_score = 0;
603 p_media->i_filesize = 0;
604 p_media->i_duration = 0;
605 p_media->i_played_count = 0;
606 p_media->i_last_played = 0;
607 p_media->i_skipped_count = 0;
608 p_media->i_last_skipped = 0;
609 p_media->i_first_played = 0;
610 p_media->i_import_time = 0;
611 p_media->i_bitrate = 0;
612 p_media->i_samplerate = 0;
617 * @brief Free a result item. @see ml_result_t
618 * @param p_result Result item to free
619 * @note This will free any strings and decref medias.
621 static inline void ml_FreeResult( ml_result_t *p_result )
625 switch( p_result->type )
628 free( p_result->value.psz );
631 ml_gc_decref( p_result->value.p_media );
642 * @brief Free a ml_element_t item.
643 * @param p_find Find object to free
644 * @see ml_element_t */
645 static inline void ml_FreeElement( ml_element_t *p_elt )
649 if( ml_AttributeIsString( p_elt->criteria ) )
651 free( p_elt->value.str );
653 if( p_elt->criteria == ML_PEOPLE )
655 free( p_elt->lvalue.str );
663 * @brief Destroy a vlc_array_t of ml_result_t
664 * @param ml_result_array The result array to free
665 * @note Frees all results and contents of the results
667 static inline void ml_DestroyResultArray( vlc_array_t *p_result_array )
669 for( int i = 0; i < vlc_array_count( p_result_array ); i++ )
671 ml_FreeResult( ( ml_result_t* ) vlc_array_item_at_index(
672 p_result_array, i ) );
678 /*****************************************************************************
679 * ML Object Management Functions
680 *****************************************************************************/
682 /** Helpers for locking and unlocking */
683 #define ml_LockMedia( a ) vlc_mutex_lock( &a->lock )
684 #define ml_UnlockMedia( a ) vlc_mutex_unlock( &a->lock )
687 * @brief Object constructor for ml_media_t
688 * @param p_ml The media library object
689 * @param id If 0, this item isn't in database. If non zero, it is and
690 * it will be a singleton
691 * @param select Type of object
692 * @param reload Whether to reload from database
694 VLC_EXPORT( ml_media_t*, media_New, ( media_library_t* p_ml, int id,
695 ml_select_e select, bool reload ) );
698 /* Forward declaration */
699 static inline int ml_CopyPersons( ml_person_t** a, ml_person_t* b );
702 * @brief Copy all members of a ml_media_t to another.
703 * @param b Destination media, already allocated
704 * @param a Source media, cannot be NULL, const
705 * @note This does not check memory allocation (for strdup). It is threadsafe
706 * @todo Free b content, before inserting a?
708 static inline int ml_CopyMedia( ml_media_t *b, ml_media_t *a )
710 if( !a || !b ) return VLC_EGENERIC;
714 b->b_sparse = a->b_sparse;
716 b->i_type = a->i_type;
717 b->i_album_id = a->i_album_id;
718 b->i_disc_number = a->i_disc_number;
719 b->i_track_number = a->i_track_number;
720 b->i_year = a->i_year;
721 b->i_vote = a->i_vote;
722 b->i_score = a->i_score;
723 b->i_filesize = a->i_filesize;
724 b->i_duration = a->i_duration;
725 b->i_played_count = a->i_played_count;
726 b->i_last_played = a->i_last_played;
727 b->i_skipped_count = a->i_skipped_count;
728 b->i_last_skipped = a->i_last_skipped;
729 b->i_first_played = a->i_first_played;
730 b->i_import_time = a->i_import_time;
731 b->i_bitrate = a->i_bitrate;
732 b->i_samplerate = a->i_samplerate;
736 b->psz_uri = strdup( a->psz_uri );
737 free( b->psz_title );
739 b->psz_title = strdup( a->psz_title );
740 free( b->psz_orig_title );
741 if( a->psz_orig_title )
742 b->psz_orig_title = strdup( a->psz_orig_title );
743 free( b->psz_album );
745 b->psz_album = strdup( a->psz_album );
746 free( b->psz_cover );
748 b->psz_cover = strdup( a->psz_cover );
749 free( b->psz_genre );
751 b->psz_genre = strdup( a->psz_genre );
752 free( b->psz_comment );
754 b->psz_comment = strdup( a->psz_comment );
755 free( b->psz_extra );
757 b->psz_extra = strdup( a->psz_extra );
758 free( b->psz_preview );
760 b->psz_preview = strdup( a->psz_preview );
761 free( b->psz_language );
762 if( a->psz_language )
763 b->psz_language = strdup( a->psz_language );
764 ml_FreePeople( b->p_people );
765 if( a->p_people ) ml_CopyPersons( &( b->p_people ), a->p_people );
771 /*****************************************************************************
772 * ML Find Tree Related Functions
773 *****************************************************************************/
774 #define ml_FreeFindTree( tree ) ml_GenericFreeFindTree( tree, true )
775 #define ml_ShallowFreeFindTree( tree ) ml_GenericFreeFindTree( tree, false )
777 * @brief Free a find tree
778 * @param Find tree to free
779 * @param true to free any associated strings, false to not free them
781 static inline void ml_GenericFreeFindTree( ml_ftree_t* tree, bool freestrings )
787 ml_GenericFreeFindTree( tree->left, freestrings );
792 ml_GenericFreeFindTree( tree->right, freestrings );
795 if( tree->op == ML_OP_NONE && ml_AttributeIsString( tree->criteria )
796 && freestrings == true)
798 free( tree->value.str );
799 if( tree->criteria == ML_PEOPLE )
800 free( tree->lvalue.str );
805 * @brief Checks if a given find tree has leaf nodes
807 * @return Number of leaf nodes
809 static inline int ml_FtreeHasOp( ml_ftree_t* tree )
813 if( tree->criteria > 0 && tree->op == ML_OP_NONE )
816 return ml_FtreeHasOp( tree->left ) + ml_FtreeHasOp( tree->right );
821 * @brief Connect up a find tree
822 * @param op operator to connect with
823 * If op = ML_OP_NONE, then you are connecting to a tree consisting of
824 * only SPECIAL nodes.
825 * If op = ML_OP_NOT, then right MUST be NULL
826 * op must not be ML_OP_SPECIAL, @see __ml_FtreeSpec
827 * @param left part of the tree
828 * @param right part of the tree
829 * @return Pointer to new tree
830 * @note Use the helpers!
832 VLC_EXPORT( ml_ftree_t*, ml_OpConnectChilds, ( ml_op_e op, ml_ftree_t* left,
833 ml_ftree_t* right ) );
836 * @brief Attaches a special node to a tree
837 * @param tree Tree to attach special node to
838 * @param crit Criteria may be SORT_ASC, SORT_DESC, LIMIT or DISTINCT
839 * @param limit Limit used if LIMIT criteria used
840 * @param Sort string used if SORT criteria is used
841 * @return Pointer to new tree
842 * @note Use the helpers
844 VLC_EXPORT( ml_ftree_t*, __ml_FtreeSpec, ( ml_ftree_t* tree,
850 * @brief This function gives quick sequential adding capability
851 * @param left Tree to add to. This may be NULL
852 * @param right Tree to append. May not be NULL
853 * @return Pointer to new tree.*/
854 static inline ml_ftree_t* ml_FtreeFastAnd( ml_ftree_t* left,
857 if( ml_FtreeHasOp( left ) == 0 )
859 return ml_OpConnectChilds( ML_OP_NONE, left, right );
863 return ml_OpConnectChilds( ML_OP_AND, left, right );
866 #define ml_FtreeAnd( left, right ) ml_OpConnectChilds( ML_OP_AND, left, right )
867 #define ml_FtreeOr( left, right ) ml_OpConnectChilds( ML_OP_OR, left, right )
868 #define ml_FtreeNot( left ) ml_OpConnectChilds( ML_OP_NOT, left, NULL )
870 #define ml_FtreeSpecAsc( tree, str ) __ml_FtreeSpec( tree, ML_SORT_ASC, 0, str )
871 #define ml_FtreeSpecDesc( tree, str ) __ml_FtreeSpec( tree, ML_SORT_DESC, 0, str )
872 #define ml_FtreeSpecLimit( tree, limit ) __ml_FtreeSpec( tree, ML_LIMIT, limit, NULL )
873 #define ml_FtreeSpecDistinct( tree ) __ml_FtreeSpec( tree, ML_DISTINCT, 0, NULL )
876 /*****************************************************************************
878 *****************************************************************************/
881 * @brief Create input item from media
882 * @param p_media_library This ML instance.
883 * @param i_media_id ID of the media to use to create an input_item.
884 * @return The media item.
886 static inline input_item_t* ml_CreateInputItem(
887 media_library_t *p_media_library, int i_media_id )
889 return p_media_library->functions.pf_InputItemFromMedia( p_media_library,
894 * @brief Search in the database according some criterias
896 * @param p_media_library the media library object
897 * @param result a pointer to a result array
898 * @param ... parameters to select the data
899 * @return VLC_SUCCESS or an error
901 static inline int __ml_Find( media_library_t *p_media_library,
902 vlc_array_t *p_result_array, ... )
907 va_start( args, p_result_array );
908 returned = p_media_library->functions.pf_Find( p_media_library,
909 p_result_array, args );
917 * @brief Search in the database according some criterias (threaded)
918 * @param p_media_library the media library object
919 * @param result_array a pointer to a result array
920 * @param result_type type of data to retrieve
921 * @param psz_lvalue This should contain any necessary lvalue/key
922 * for the given result_type. Used for ML_PEOPLE. Otherwise NULL
923 * @param args parameters to select the data
924 * @return VLC_SUCCESS or an error
926 static inline int ml_FindAdv( media_library_t *p_media_library,
927 vlc_array_t *p_result_array,
928 ml_select_e result_type,
932 return p_media_library->functions.pf_FindAdv( p_media_library,
941 * @brief Find a value in the ML database, fill p_result with it.
942 * @param p_media_library Media library object
943 * @param p_result Object to put result into
944 * @param Args [ SelectType [ PersonType ] Value ] ... ML_END
945 * @note Do not use this function directly.
947 static inline int __ml_GetValue( media_library_t *p_media_library,
948 ml_result_t *p_result,
951 vlc_array_t *p_result_array = vlc_array_new();
952 int i_ret = p_media_library->functions.pf_Find( p_media_library,
955 if( i_ret != VLC_SUCCESS )
957 if( vlc_array_count( p_result_array ) > 0 )
959 ( ml_result_t* ) vlc_array_item_at_index( p_result_array, 0 ),
960 sizeof( ml_result_t) );
962 i_ret = VLC_EGENERIC;
965 /* Note: Do not free the results, because of memcpy */
966 vlc_array_destroy( p_result_array );
971 * @brief Search an INTEGER in the database
972 * This uses a Query but returns only one integer (>0), or an error code.
974 * @param p_media_library the media library object
975 * @param va_args parameters to select the data
976 * @return Found INTEGER >= 0 or an error
978 #define ml_GetInt( ml, ... ) __ml_GetInt( ml, __VA_ARGS__, ML_LIMIT, 1, ML_END )
979 static inline int __ml_GetInt( media_library_t *p_media_library, ... )
982 va_start( args, p_media_library );
984 int i_ret = __ml_GetValue( p_media_library, &result, args );
986 if( i_ret != VLC_SUCCESS )
989 return result.value.i;
994 * @brief Search a string (VARCHAR) in the database
995 * This uses a Query but returns only one integer (>0), or an error code.
997 * @param p_media_library the media library object
998 * @param va_args parameters to select the data
999 * @return Found string, or NULL if not found or in case of error
1001 #define ml_FindPsz( ml, ... ) __ml_GetPsz( ml, __VA_ARGS__, ML_LIMIT, 1, ML_END )
1002 static inline char* __ml_GetPsz( media_library_t *p_media_library, ... )
1005 va_start( args, p_media_library );
1007 int i_ret = __ml_GetValue( p_media_library, &result, args );
1009 if( i_ret != VLC_SUCCESS )
1012 return result.value.psz; // no need to duplicate
1016 * @brief Generic update in Media Library database
1018 * @param p_media_library the media library object
1019 * @param selected_type the type of the element we're selecting
1020 * @param where list of ids/uris to be changed
1021 * @param changes list of changes to make in the entries
1022 * @return VLC_SUCCESS or VLC_EGENERIC
1024 static inline int ml_Update( media_library_t *p_media_library,
1025 ml_select_e selected_type,
1026 const char* psz_lvalue,
1028 vlc_array_t *changes )
1030 return p_media_library->functions.pf_Update( p_media_library,
1031 selected_type, psz_lvalue,
1036 * @brief Update a given table
1037 * @param p_media_library The media library object
1038 * @param selected_type The table to update
1039 * @param psz_lvalue The role of the person if selected_type = ML_PEOPLE
1040 * @param id The id of the row to update
1041 * @param ... The update data. [SelectType [RoleType] Value]
1043 #define ml_UpdateSimple( ml, sel, lval, id, ... ) \
1044 __ml_UpdateSimple( ml, sel, lval, id, __VA_ARGS__, ML_END )
1045 VLC_EXPORT( int, __ml_UpdateSimple, ( media_library_t *p_media_library,
1046 ml_select_e selected_type,
1047 const char* psz_lvalue,
1051 * @brief Generic DELETE function
1052 * Delete a media and all its references which don't point
1055 * @param p_media_library This media_library_t object
1056 * @param id the id of the media to delete
1057 * @return VLC_SUCCESS or VLC_EGENERIC
1060 ml_DeleteSimple( media_library_t *p_media_library, int id )
1062 vlc_array_t* p_where = vlc_array_new();
1063 ml_element_t* p_find = (ml_element_t *) calloc( 1, sizeof( ml_element_t ) );
1064 p_find->criteria = ML_ID;
1065 p_find->value.i = id;
1066 vlc_array_append( p_where, p_find );
1067 int i_return = p_media_library->functions.pf_Delete( p_media_library,
1070 vlc_array_destroy( p_where );
1075 * @brief Delete many medias in the media library
1076 * @param p_media_library Media library object
1077 * @param p_array Array of ids to delete
1078 * @return VLC_SUCCESS or VLC_EGENERIC
1081 ml_Delete( media_library_t *p_media_library, vlc_array_t* p_array )
1083 return p_media_library->functions.pf_Delete( p_media_library,
1088 /*****************************************************************************
1089 * ML Person Related Functions
1090 *****************************************************************************/
1093 * @brief Create and append a person object to the given list
1094 * @param pp_person pointer to person list. Set the address to null to create new list
1095 * @param i_role The role of the person
1096 * @param psz_name The name string. Will be strdup'd
1097 * @param i_id The id in the database
1098 * @note This function is NOT thread safe. Please lock any associated media
1100 static inline int ml_CreateAppendPersonAdv( ml_person_t **pp_person,
1101 const char* psz_role, const char* psz_name, int i_id )
1103 assert( i_id || ( psz_name && *psz_name && psz_role && *psz_role ) );
1105 return VLC_EGENERIC;
1106 if( *pp_person != NULL )
1107 return ml_CreateAppendPersonAdv( &((**pp_person).p_next),
1108 psz_role, psz_name, i_id);
1109 *pp_person = ( ml_person_t * ) calloc( 1, sizeof( ml_person_t ) );
1110 (*pp_person)->psz_name = (psz_name && *psz_name) ? strdup( psz_name ): NULL;
1111 (*pp_person)->psz_role = (psz_role && *psz_role) ? strdup( psz_role ): NULL;
1112 (*pp_person)->i_id = i_id;
1113 (*pp_person)->p_next = NULL;
1118 * @brief Create and append a person object to the given list
1119 * @param pp_person pointer to person list.
1120 * Set the address to NULL to create a new list
1121 * @param personfrom Person object to copy from
1122 * @note Ignores the next variable and copies only the variables.
1123 * Uses ml_CreateAppendPersonAdv
1124 * @note This function is NOT threadsafe
1126 static inline int ml_CreateAppendPerson( ml_person_t **pp_person,
1127 ml_person_t *p_personfrom )
1129 return ml_CreateAppendPersonAdv( pp_person,
1130 p_personfrom->psz_role,
1131 p_personfrom->psz_name,
1132 p_personfrom->i_id );
1136 * @brief Copy one person list into another
1138 * @param b From list
1139 * @note On errors, you have to free any allocated persons yourself
1140 * @note This function is NOT threadsafe. Please ensure your medias are locked
1142 static inline int ml_CopyPersons( ml_person_t** a, ml_person_t* b )
1147 i_ret = ml_CreateAppendPerson( a, b );
1148 if( i_ret != VLC_SUCCESS )
1157 * @brief Returns a person list of given type
1158 * @param p_ml The ML object
1159 * @param p_media The Media object
1160 * @param i_type The person type
1161 * @note This function is thread safe
1163 VLC_EXPORT( ml_person_t*, ml_GetPersonsFromMedia, ( media_library_t* p_ml,
1164 ml_media_t* p_media,
1165 const char *psz_role ) );
1168 #define ml_GetAlbumArtistsFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_ALBUM_ARTIST );
1169 #define ml_GetArtistsFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_ARTIST );
1170 #define ml_GetEncodersFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_ENCODER );
1171 #define ml_GetPublishersFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_PUBLISHER );
1174 * @brief Delete a certain type of people from a media
1175 * @param p_media Media to delete from
1176 * @param i_type Type of person to delete
1177 * @note This function is threadsafe
1179 VLC_EXPORT( void, ml_DeletePersonTypeFromMedia, ( ml_media_t* p_media,
1180 const char *psz_role ) );
1184 * @brief Creates and adds the playlist based on a given find tree
1185 * @param p_ml Media library object
1186 * @param p_tree Find tree to create SELECT
1189 VLC_EXPORT( void, ml_PlaySmartPlaylistBasedOn, ( media_library_t* p_ml,
1190 ml_ftree_t* p_tree ) );
1194 * Convenience Macros
1198 * Get information using the *media* ID. This returns only 1 information.
1199 * @note You have to free the string returned (if that's a string!).
1201 #define ml_GetAlbumById( a, id ) ml_GetPsz( a, ML_ALBUM, ML_ID, id )
1202 #define ml_GetArtistById( a, id ) ml_GetPsz( a, ML_PEOPLE, ML_PERSON_ARTIST, ML_ID, id )
1203 #define ml_GetCoverUriById( a, id ) ml_GetPsz( a, ML_COVER, ML_ID, id )
1204 #define ml_GetEncoderById( a, id ) ml_GetPsz( a, ML_PEOPLE, ML_PERSON_ENCODER, ML_ID, id )
1205 #define ml_GetExtraById( a, id ) ml_GetPsz( a, ML_EXTRA, ML_ID, id )
1206 #define ml_GetGenreById( a, id ) ml_GetPsz( a, ML_GENRE, ML_ID, id )
1207 #define ml_GetOriginalTitleById( a, id ) ml_GetPsz( a, ML_ORIGINAL_TITLE, ML_ID, id )
1208 #define ml_GetPublisherById( a, id ) ml_GetPsz( a, ML_PEOPLE, ML_PERSON_PUBLISHER, ML_ID, id )
1209 #define ml_GetTitleById( a, id ) ml_GetPsz( a, ML_TITLE, ML_ID, id )
1210 #define ml_GetUriById( a, id ) ml_GetPsz( a, ML_URI, ML_ID, id )
1212 #define ml_GetAlbumIdById( a, id ) ml_GetInt( a, ML_ALBUM_ID, ML_ID, id )
1213 #define ml_GetArtistIdById( a, id ) ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_ARTIST, ML_ID, id )
1214 #define ml_GetDurationById( a, id ) ml_GetInt( a, ML_DURATION, ML_ID, id )
1215 #define ml_GetEncoderIdById( a, id ) ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_ENCODER, ML_ID, id )
1216 #define ml_GetLastPlayedById( a, id ) ml_GetInt( a, ML_LAST_PLAYED, ML_ID, id )
1217 #define ml_GetPlayedCountById( a, id ) ml_GetInt( a, ML_PLAYED_COUNT, ML_ID, id )
1218 #define ml_GetPublisherIdById( a, id ) ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_PUBLISHER, ML_ID, id )
1219 #define ml_GetScoreById( a, id ) ml_GetInt( a, ML_SCORE, ML_ID, id )
1220 #define ml_GetTrackNumberById( a, id ) ml_GetInt( a, ML_TRACK_NUMBER, ML_ID, id )
1221 #define ml_GetTypeById( a, id ) ml_GetInt( a, ML_TYPE, ML_ID, id )
1222 #define ml_GetYearById( a, id ) ml_GetInt( a, ML_YEAR, ML_ID, id )
1223 #define ml_GetVoteById( a, id ) ml_GetInt( a, ML_VOTE, ML_ID, id )
1225 /** Albums handling */
1226 #define ml_GetAlbumId( a, b ) ml_GetInt( a, ML_ALBUM_ID, ML_ALBUM, b )
1228 /** People handling */
1229 #define ml_GetArtistId( a, b ) ml_GetInt( a, ML_PERSON_ID, ML_PERSON_ARTIST, ML_PERSON, ML_PERSON_ARTIST, b )
1230 #define ml_GetEncoderId( a, b ) ml_GetInt( a, ML_PERSON_ID, ML_PERSON_ENCODER, ML_PERSON, ML_PERSON_ENCODER, b )
1231 #define ml_GetPublisherId( a, b ) ml_GetInt( a, ML_PERSON_ID, ML_PERSON_PUBLISHER, ML_PERSON, ML_PERSON_PUBLISHER, b )
1233 /** Counts handling */
1234 #define ml_GetMediaCount( a, ... ) __ml_GetInt( a, ML_COUNT_MEDIA, __VA_ARGS__, ML_END )
1235 #define ml_GetAlbumCount( a, ... ) __ml_GetInt( a, ML_COUNT_ALBUM, __VA_ARGS__, ML_END )
1236 #define ml_GetPeopleCount( a, ... ) __ml_GetInt( a, ML_COUNT_PEOPLE, __VA_ARGS__, ML_END )
1238 #define ml_Find( a, b, ... ) __ml_Find( a, b, __VA_ARGS__, ML_END )
1240 #define ml_FindAlbum( a, b, ... ) __ml_Find( a, b, ML_ALBUM, __VA_ARGS__, ML_END )
1241 #define ml_FindArtist( a, b, ... ) __ml_Find( a, b, ML_PERSON, ML_PERSON_ARTIST, __VA_ARGS__, ML_END )
1242 #define ml_FindEncoder( a, b, ... ) __ml_Find( a, b, ML_PERSON, ML_PERSON_ENCODER, __VA_ARGS__, ML_END )
1243 #define ml_FindGenre( a, b, ... ) __ml_Find( a, b, ML_GENRE, __VA_ARGS__, ML_END )
1244 #define ml_FindMedia( a, b, ... ) __ml_Find( a, b, ML_MEDIA, __VA_ARGS__, ML_END )
1245 #define ml_FindOriginalTitle( a, b, ... ) __ml_Find( a, b, ML_ORIGINAL_TITLE, __VA_ARGS__, ML_END )
1246 #define ml_FindPublisher( a, b, ... ) __ml_Find( a, b, ML_PERSON, ML_PERSON_PUBLISHER, __VA_ARGS__, ML_END )
1247 #define ml_FindTitle( a, b, ... ) __ml_Find( a, b, ML_TITLE, __VA_ARGS__, ML_END )
1248 #define ml_FindType( a, b, ... ) __ml_Find( a, b, ML_TYPE, __VA_ARGS__, ML_END )
1249 #define ml_FindUri( a, b, ... ) __ml_Find( a, b, ML_URI, __VA_ARGS__, ML_END )
1250 #define ml_FindYear( a, b, ... ) __ml_Find( a, b, ML_YEAR, __VA_ARGS__, ML_END )
1252 #define ml_FindAllAlbums( a, b ) ml_FindAlbum( a, b, ML_DISTINCT )
1253 #define ml_FindAllArtists( a, b ) ml_FindArtist( a, b, ML_DISTINCT )
1254 #define ml_FindAllGenres( a, b ) ml_FindGenre( a, b, ML_DISTINCT )
1255 #define ml_FindAllMedias( a, b ) ml_FindMedia( a, b, ML_DISTINCT )
1256 #define ml_FindAllOriginalTitles( a, b ) ml_FindOriginalTitle( a, b, ML_DISTINCT )
1257 #define ml_FindAllPublishers( a, b, ... ) ml_FindPublisher( a, b, ML_DISTINCT )
1258 #define ml_FindAllTitles( a, b ) ml_FindTitle( a, b, ML_DISTINCT )
1259 #define ml_FindAllTypes( a, b ) ml_FindType( a, b, ML_DISTINCT )
1260 #define ml_FindAllUris( a, b ) ml_FindUri( a, b, ML_DISTINCT )
1261 #define ml_FindAllYears( a, b ) ml_FindYear( a, b, ML_DISTINCT )
1263 #define ml_FindAlbumAdv( a, b, c ) ml_FindAdv( a, b, ML_ALBUM, NULL, c )
1264 #define ml_FindArtistAdv( a, b, c ) ml_FindAdv( a, b, ML_PERSON, ML_PERSON_ARTIST, c )
1265 #define ml_FindEncoderAdv( a, b, c ) ml_FindAdv( a, b, ML_PERSON, ML_PERSON_ENCODER, c )
1266 #define ml_FindGenreAdv( a, b, c ) ml_FindAdv( a, b, ML_GENRE, NULL, c )
1267 #define ml_FindMediaAdv( a, b, c ) ml_FindAdv( a, b, ML_MEDIA, NULL, c )
1268 #define ml_FindOriginalTitleAdv( a, b, c ) ml_FindAdv( a, b, ML_ORIGINAL_TITLE,NULL, c )
1269 #define ml_FindPublisherAdv( a, b, c ) ml_FindAdv( a, b, ML_PUBLISHER, ML_PERSON_PUBLISHER, c )
1270 #define ml_FindTitleAdv( a, b, c ) ml_FindAdv( a, b, ML_TITLE, NULL, c )
1271 #define ml_FindTypeAdv( a, b, c ) ml_FindAdv( a, b, ML_TYPE, NULL, c )
1272 #define ml_FindUriAdv( a, b, c ) ml_FindAdv( a, b, ML_URI, NULL, c )
1273 #define ml_FindYearAdv( a, b, c ) ml_FindAdv( a, b, ML_YEAR, NULL, c )
1281 #endif /* VLC_MEDIA_LIBRARY_H */