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>
36 #include <vlc_playlist.h>
38 /*****************************************************************************
40 *****************************************************************************/
42 #define ML_PERSON_ARTIST "Artist"
43 #define ML_PERSON_ALBUM_ARTIST "Album Artist"
44 #define ML_PERSON_ENCODER "Encoder"
45 #define ML_PERSON_PUBLISHER "Publisher"
48 #define ml_priv( gc, t ) ((t *)(((char *)(gc)) - offsetof(t, ml_gc_data)))
50 /** List of Query select types.
51 * In a query array or variable argument list, each select type is followed
52 * by an argument (X) of variable type (char* or int, @see ml_element_t).
53 * These types can be used either in the query list or in the result array.
54 * Some types are reserved for the result array:
58 ML_ALBUM
= 1, /**< Album Title */
59 ML_ALBUM_ID
, /**< Album ID */
60 ML_ALBUM_COVER
, /**< Album Cover art url */
61 /* FIXME: Remove ML_ARTIST */
62 ML_ARTIST
, /**< Artist, interpreted as ML_PEOPLE
63 && ML_PEOPLE_ROLE = ML_PERSON_ARTIST */
64 ML_ARTIST_ID
, /**< Artist ID, interpreted as ML_PEOPLE_ID
65 && ML_PEOPLE_ROLE = ML_PERSON_ARTIST */
66 ML_COMMENT
, /**< Comment about media */
67 ML_COUNT_MEDIA
, /**< Number of medias */
68 ML_COUNT_ALBUM
, /**< Number of albums */
69 ML_COUNT_PEOPLE
, /**< Number of people */
70 ML_COVER
, /**< Cover art url */
71 ML_DURATION
, /**< Duration in ms */
72 ML_DISC_NUMBER
, /**< Disc number of the track */
73 ML_EXTRA
, /**< Extra/comment (string) on the media */
74 ML_FIRST_PLAYED
, /**< First time media was played */
75 ML_FILESIZE
, /**< Size of the media file */
76 ML_GENRE
, /**< Genre of the media (if any) */
77 ML_ID
, /**< Media ID */
78 ML_IMPORT_TIME
, /**< Date when media was imported */
79 ML_LANGUAGE
, /**< Language */
80 ML_LAST_PLAYED
, /**< Last play UNIX timestamp */
81 ML_LAST_SKIPPED
, /**< Time when media was last skipped */
82 ML_ORIGINAL_TITLE
, /**< Media original title (if any) */
83 ML_PEOPLE
, /**< Any People associated with this media */
84 ML_PEOPLE_ID
, /**< Id of a person */
85 ML_PEOPLE_ROLE
, /**< Person role */
86 ML_PLAYED_COUNT
, /**< Media play count */
87 ML_PREVIEW
, /**< Url of the video preview */
88 ML_SKIPPED_COUNT
, /**< Number of times skipped */
89 ML_SCORE
, /**< Computed media score */
90 ML_TITLE
, /**< Media title */
91 ML_TRACK_NUMBER
, /**< Media track number (if any) */
92 ML_TYPE
, /**< Media type. @see ml_type_e */
93 ML_URI
, /**< Media full URI. */
94 ML_VOTE
, /**< Media user vote value */
95 ML_YEAR
, /**< Media publishing year */
96 ML_DIRECTORY
, /**< Monitored directory */
97 ML_MEDIA
, /**< Full media descriptor. @see ml_media_t */
98 ML_MEDIA_SPARSE
, /**< Sparse media. @see ml_media_t */
99 ML_MEDIA_EXTRA
, /**< Sparse + Extra = Full media */
101 /* Some special elements */
102 ML_LIMIT
= -1, /**< Limit a query to X results */
103 ML_SORT_DESC
= -2, /**< Sort a query descending on argument X */
104 ML_SORT_ASC
= -3, /**< Sort a query ascending on argument X */
105 ML_DISTINCT
= -4, /**< Add DISTINCT to SELECT statements. */
106 ML_END
= -42 /**< End of argument list */
109 /** Media types (audio, video, etc...) */
112 ML_UNKNOWN
= 0, /**< Unknown media type */
113 ML_AUDIO
= 1 << 0, /**< Audio only media */
114 ML_VIDEO
= 1 << 1, /**< Video media. May contain audio channels */
115 ML_STREAM
= 1 << 2, /**< Streamed media = not a local file */
116 ML_NODE
= 1 << 3, /**< Nodes like simple nodes, directories, playlists, etc */
117 ML_REMOVABLE
= 1 << 4, /**< Removable media: CD/DVD/Card/... */
120 /** Query result item/list type: integers, strings, medias, timestamps */
122 ML_TYPE_INT
, /**< Object is an int */
123 ML_TYPE_PSZ
, /**< A string char* */
124 ML_TYPE_TIME
, /**< A timestamp mtime_t */
125 ML_TYPE_MEDIA
, /**< A pointer to a media ml_media_t* */
128 /** Arguments for VLC Control for the media library */
131 ML_SET_DATABASE
, /**< arg1 = char *psz_host
133 arg3 = char *psz_user
134 arg4 = char *psz_pass */
135 ML_INIT_DATABASE
, /**< No arg */
136 ML_ADD_INPUT_ITEM
, /**< arg1 = input_item_t* */
137 ML_ADD_PLAYLIST_ITEM
, /**< arg1 = playlist_item_t * */
138 ML_ADD_MONITORED
, /**< arg1 = char* */
139 ML_DEL_MONITORED
, /**< arg1 = char* */
140 ML_GET_MONITORED
, /**< arg1 = vlc_array_t* */
143 /* Operations that can be specified between find conditions */
146 ML_OP_NONE
= 0, /**< This is to specify an actual condition */
147 ML_OP_AND
, /**< AND condition */
148 ML_OP_OR
, /**< OR condition */
149 ML_OP_NOT
, /**< NOT condition */
150 ML_OP_SPECIAL
/**< This is for inclusion of
151 * special stuffs like LIMIT */
154 /* Comparison operators used in a single find condition */
158 ML_COMP_LESSER
, ///< <
159 ML_COMP_LESSER_OR_EQUAL
, ///< <=
160 ML_COMP_EQUAL
, ///< ==
161 ML_COMP_GREATER_OR_EQUAL
, ///< >=
162 ML_COMP_GREATER
, ///< >
163 ML_COMP_HAS
, ///< "Contains", equivalent to SQL "LIKE %x%"
164 ML_COMP_STARTS_WITH
, ///< Equivalent to SQL "LIKE %x"
165 ML_COMP_ENDS_WITH
, ///< Equivalent to SQL "LIKE x%"
168 /*****************************************************************************
169 * ML Structures and types
170 *****************************************************************************/
172 typedef struct media_library_t media_library_t
;
173 typedef struct media_library_sys_t media_library_sys_t
;
175 typedef struct ml_media_t ml_media_t
;
176 typedef struct ml_result_t ml_result_t
;
177 typedef struct ml_element_t ml_element_t
;
178 typedef struct ml_person_t ml_person_t
;
179 typedef struct ml_ftree_t ml_ftree_t
;
182 typedef struct ml_gc_object_t
187 void (*pf_destructor
) (struct ml_gc_object_t
*);
190 #define ML_GC_MEMBERS ml_gc_object_t ml_gc_data;
192 /** Main structure of the media library. VLC object. */
193 struct media_library_t
197 module_t
*p_module
; /**< the media library module */
198 media_library_sys_t
*p_sys
; /**< internal struture */
200 /** Member functions */
203 /**< Search in the database */
204 int ( * pf_Find
) ( media_library_t
*p_media_library
,
205 vlc_array_t
*p_result_array
,
208 /**< Search in the database using an array of arguments */
209 int ( * pf_FindAdv
) ( media_library_t
*p_media_library
,
210 vlc_array_t
*p_result_array
,
211 ml_select_e selected_type
,
212 const char *psz_lvalue
,
215 /**< Update the database using an array of arguments */
216 int ( * pf_Update
) ( media_library_t
*p_media_library
,
217 ml_select_e selected_type
,
218 const char *psz_lvalue
,
220 vlc_array_t
*changes
);
222 /**< Delete many medias in the database */
223 int ( * pf_Delete
) ( media_library_t
*p_media_library
,
224 vlc_array_t
*p_array
);
226 /**< Control the media library */
227 int ( * pf_Control
) ( media_library_t
*p_media_library
,
228 int i_query
, va_list args
);
230 /**< Create associated input item */
231 input_item_t
* ( * pf_InputItemFromMedia
) (
232 media_library_t
*p_media_library
, int i_media
);
235 ml_media_t
* ( * pf_GetMedia
) (
236 media_library_t
*p_media_library
, int i_media
,
237 ml_select_e select
, bool reload
);
243 * @brief Structure to describe a media
245 * This is the main structure holding the meta data in ML.
246 * @see b_sparse indicates whether the media struct has valid values
247 * in its Extra fields. Otherwise, it must be loaded with the API
249 * @see i_id indicates whether this struct is saved in the ML if i_id > 0
250 * Otherwise, it can be added to the database
255 vlc_mutex_t lock
; /**< Mutex for multithreaded access */
256 bool b_sparse
; /**< Specifies if media is loaded fully */
257 ml_type_e i_type
; /**< Type of the media (ml_type_e) */
258 int8_t i_vote
; /**< User vote */
259 int16_t i_disc_number
; /**< Disc number of media */
260 int16_t i_track_number
; /**< Track number */
261 int16_t i_year
; /**< Year of release */
262 int32_t i_id
; /**< Media ID in the database */
263 int32_t i_score
; /**< Score computed about the media */
264 int32_t i_album_id
; /**< Album id */
265 int32_t i_played_count
; /**< How many time the media was played */
266 int32_t i_skipped_count
; /**< No. of times file was skipped */
267 int32_t i_bitrate
; /**< Extra: Bitrate of the media */
268 int32_t i_samplerate
; /**< Extra: Samplerate of the media */
269 int32_t i_bpm
; /**< Extra: Beats per minute */
270 char *psz_uri
; /**< URI to find the media */
271 char *psz_title
; /**< Title of the media */
272 char *psz_orig_title
; /**< Original title (mainly for movies) */
273 char *psz_album
; /**< Name of the album */
274 char *psz_cover
; /**< URI of the cover */
275 char *psz_genre
; /**< Genre of the media */
276 char *psz_preview
; /**< Preview thumbnail for video, if any */
277 char *psz_comment
; /**< Comment or description about media */
278 char *psz_language
; /**< Extra: Language */
279 char *psz_extra
; /**< Extra: Some extra datas like lyrics */
280 ml_person_t
*p_people
; /**< Extra: People associated with this
281 media This meta holds only one
282 artist if b_sparse = true */
283 int64_t i_filesize
; /**< Size of the file */
284 mtime_t i_duration
; /**< Duration in microseconds */
285 mtime_t i_last_played
; /**< Time when the media was last played */
286 mtime_t i_last_skipped
; /**< Time when the media was last skipped */
287 mtime_t i_first_played
; /**< First played */
288 mtime_t i_import_time
; /**< Time when media was added */
294 * @brief Main communication struct between GUI and sql_media_library.
295 * Generic representation of an ML/SQL query result.
299 int32_t id
; /**< Media/Album/Artist... ID (if any) */
300 ml_result_type_e type
; /**< Type of value */
303 /* Classical results */
308 /* Complex result: media descriptor */
310 } value
; /**< Value of the result obtained */
315 * @brief Element of a query: criteria type/value pair
316 * Used for update and delete queries
320 ml_select_e criteria
; /**< SELECT criteria type. @see ml_select_e */
325 } value
; /**< SELECT criteria value (string or int) */
330 } lvalue
; /**< Refer to @see ml_ftree_t lvalue docs */
334 * Binary tree used to parse the WHERE condition for a search
336 * Let [expr] indicate a valid expression
337 * [expr] = [expr] AND [expr], where the left and right are respective
338 * [expr] = [expr] OR [expr]
339 * [expr] = [expr] NOT [NULL]
340 * [expr] = [expr] SPEC [spec_expr]
341 * [expr] = [criteria=val]
342 * [spec_expr] = [DISTINCT/LIMIT/ASC/DESC = val ]
346 ml_op_e op
; /**< Operator. ML_OP_NONE means this is a leaf
347 * node. Criteria and value gives its data.
348 * ML_OP_SPECIAL specifies a special node
349 * that does not form a part of the WHERE.
350 * The right node consists of the data
351 * with its criteria set to the special val
352 * and the left node is the corresponding
353 * subtree of the parent node.
354 * ML_OP_NOT only left sub tree is considered
355 * ML_OP_AND and ML_OP_OR consider both
356 * left and right subtrees */
357 ml_ftree_t
*left
; /**< Left child of Bin tree */
358 ml_ftree_t
*right
; /**< Right child of Bin tree */
359 ml_select_e criteria
; /**< SELECT criteria type @see ml_select_e
360 * The criteria value is considered only when
361 * op = ML_OP_NONE i.e. in leaf nodes */
362 ml_comp_e comp
; /**< Condition between type and value */
367 } value
; /**< SELECT criteria value ( string or int ) */
372 } lvalue
; /**< Used as key value for people types/roles.
373 An empty string "" denotes ANY person role.
374 NULL is used for all other criterias */
379 * Person class. Implemented as a linked list
383 char *psz_role
; /**< Type of person */
384 char *psz_name
; /**< Name of the person */
385 int i_id
; /**< ID in the database */
386 ml_person_t
*p_next
; /**< Next person in list */
390 /*****************************************************************************
391 * ML Function headers
392 *****************************************************************************/
395 * @brief Acquire a reference to the media library singleton
396 * @param p_this The object holding the media library
397 * @return The media library object. NULL if the media library
398 * object could not be loaded
400 VLC_EXPORT( media_library_t
*, ml_Hold
, ( vlc_object_t
* p_this
) );
401 #define ml_Hold( a ) ml_Hold( VLC_OBJECT(a) )
404 * @brief Discard your ref to media library
405 * @param p_this The object holding the media library
407 VLC_EXPORT( void, ml_Release
, ( vlc_object_t
* p_this
) );
408 #define ml_Release(a) ml_Release( VLC_OBJECT(a) )
411 * @brief Create a Media Library VLC object.
412 * @param p_this Parent to attach the ML object to.
413 * @param psz_name Name for the module
414 * @return The ML object.
416 VLC_EXPORT( media_library_t
*, ml_Create
, ( vlc_object_t
*p_this
, char* psz_name
) );
419 * @brief Destructor for the Media library singleton
420 * @param p_this Parent the ML object is attached to
422 VLC_EXPORT( void, ml_Destroy
, ( vlc_object_t
* p_this
) );
425 * @brief Control the Media Library
426 * @param p_media_library the media library object
427 * @param i_type one of ml_control_e values @see ml_control_e.
428 * @param ... optional arguments.
429 * @return VLC_SUCCESS or an error
431 static inline int ml_ControlVa( media_library_t
*p_media_library
,
432 ml_control_e i_type
, va_list args
)
434 return p_media_library
->functions
.pf_Control( p_media_library
,
440 * @brief Control the Media Library
441 * @param i_type one of ml_control_e values @see ml_control_e.
442 * Variable arguments list equivalent
444 #define ml_Control( a, b, args... ) __ml_Control( a, b, ## args )
445 static inline int __ml_Control( media_library_t
*p_media_library
,
446 ml_control_e i_type
, ... )
451 va_start( args
, i_type
);
452 returned
= ml_ControlVa( p_media_library
, i_type
, args
);
459 * @brief Determine an attribute's type (int or string)
460 * @param meta Attribute to test @see ml_select_e
461 * @return -1 if invalid, 0 if this is an integer, 1 if this is a string
463 static inline int ml_AttributeIsString( ml_select_e meta
)
478 case ML_ORIGINAL_TITLE
:
490 case ML_COUNT_PEOPLE
:
492 case ML_FIRST_PLAYED
:
497 case ML_PLAYED_COUNT
:
500 case ML_SKIPPED_COUNT
:
501 case ML_TRACK_NUMBER
:
507 /* Invalid or no following value (in a SELECT statement) */
513 /* Reference Counting Functions */
515 * @brief Increment reference count of media
516 * @param p_media The media object
518 static inline void ml_gc_incref( ml_media_t
* p_media
)
520 ml_gc_object_t
* p_gc
= &p_media
->ml_gc_data
;
524 vlc_spin_lock (&p_gc
->spin
);
526 vlc_spin_unlock (&p_gc
->spin
);
530 * @brief Decrease reference count of media
531 * @param p_media The media object
533 static inline void ml_gc_decref( ml_media_t
* p_media
)
535 /* The below code is from vlc_release(). */
538 ml_gc_object_t
* p_gc
= &p_media
->ml_gc_data
;
542 vlc_spin_lock (&p_gc
->spin
);
545 vlc_spin_unlock (&p_gc
->spin
);
547 if( refs
== 0 && pool
== false )
549 vlc_spin_destroy (&p_gc
->spin
);
550 p_gc
->pf_destructor (p_gc
);
554 /*****************************************************************************
556 *****************************************************************************/
559 * @brief Free a person object
560 * @param p_media Person object to free
561 * @note This function is NOT threadsafe
563 static inline void ml_FreePeople( ml_person_t
*p_person
)
565 if( p_person
== NULL
)
567 ml_FreePeople( p_person
->p_next
);
568 free( p_person
->psz_name
);
569 free( p_person
->psz_role
);
574 * @brief Free only the content of a media. @see ml_media_t
575 * @param p_media Media object
576 * @note This function is NOT threadsafe.
578 static inline void ml_FreeMediaContent( ml_media_t
*p_media
)
580 free( p_media
->psz_uri
);
581 free( p_media
->psz_title
);
582 free( p_media
->psz_orig_title
);
583 free( p_media
->psz_cover
);
584 free( p_media
->psz_comment
);
585 free( p_media
->psz_extra
);
586 free( p_media
->psz_genre
);
587 free( p_media
->psz_album
);
588 free( p_media
->psz_preview
);
589 free( p_media
->psz_language
);
590 ml_FreePeople( p_media
->p_people
);
591 p_media
->b_sparse
= true;
593 p_media
->i_type
= ML_UNKNOWN
;
594 p_media
->i_album_id
= 0;
595 p_media
->i_disc_number
= 0;
596 p_media
->i_track_number
= 0;
599 p_media
->i_score
= 0;
600 p_media
->i_filesize
= 0;
601 p_media
->i_duration
= 0;
602 p_media
->i_played_count
= 0;
603 p_media
->i_last_played
= 0;
604 p_media
->i_skipped_count
= 0;
605 p_media
->i_last_skipped
= 0;
606 p_media
->i_first_played
= 0;
607 p_media
->i_import_time
= 0;
608 p_media
->i_bitrate
= 0;
609 p_media
->i_samplerate
= 0;
614 * @brief Free a result item. @see ml_result_t
615 * @param p_result Result item to free
616 * @note This will free any strings and decref medias.
618 static inline void ml_FreeResult( ml_result_t
*p_result
)
622 switch( p_result
->type
)
625 free( p_result
->value
.psz
);
628 ml_gc_decref( p_result
->value
.p_media
);
639 * @brief Free a ml_element_t item.
640 * @param p_find Find object to free
641 * @see ml_element_t */
642 static inline void ml_FreeElement( ml_element_t
*p_elt
)
646 if( ml_AttributeIsString( p_elt
->criteria
) )
648 free( p_elt
->value
.str
);
650 if( p_elt
->criteria
== ML_PEOPLE
)
652 free( p_elt
->lvalue
.str
);
660 * @brief Destroy a vlc_array_t of ml_result_t
661 * @param ml_result_array The result array to free
662 * @note Frees all results and contents of the results
664 static inline void ml_DestroyResultArray( vlc_array_t
*p_result_array
)
666 for( int i
= 0; i
< vlc_array_count( p_result_array
); i
++ )
668 ml_FreeResult( ( ml_result_t
* ) vlc_array_item_at_index(
669 p_result_array
, i
) );
675 /*****************************************************************************
676 * ML Object Management Functions
677 *****************************************************************************/
679 /** Helpers for locking and unlocking */
680 #define ml_LockMedia( a ) vlc_mutex_lock( &a->lock )
681 #define ml_UnlockMedia( a ) vlc_mutex_unlock( &a->lock )
684 * @brief Object constructor for ml_media_t
685 * @param p_ml The media library object
686 * @param id If 0, this item isn't in database. If non zero, it is and
687 * it will be a singleton
688 * @param select Type of object
689 * @param reload Whether to reload from database
691 VLC_EXPORT( ml_media_t
*, media_New
, ( media_library_t
* p_ml
, int id
,
692 ml_select_e select
, bool reload
) );
695 /* Forward declaration */
696 static inline int ml_CopyPersons( ml_person_t
** a
, ml_person_t
* b
);
699 * @brief Copy all members of a ml_media_t to another.
700 * @param b Destination media, already allocated
701 * @param a Source media, cannot be NULL, const
702 * @note This does not check memory allocation (for strdup). It is threadsafe
703 * @todo Free b content, before inserting a?
705 static inline int ml_CopyMedia( ml_media_t
*b
, ml_media_t
*a
)
707 if( !a
|| !b
) return VLC_EGENERIC
;
708 if( a
== b
) return VLC_SUCCESS
;
711 b
->b_sparse
= a
->b_sparse
;
713 b
->i_type
= a
->i_type
;
714 b
->i_album_id
= a
->i_album_id
;
715 b
->i_disc_number
= a
->i_disc_number
;
716 b
->i_track_number
= a
->i_track_number
;
717 b
->i_year
= a
->i_year
;
718 b
->i_vote
= a
->i_vote
;
719 b
->i_score
= a
->i_score
;
720 b
->i_filesize
= a
->i_filesize
;
721 b
->i_duration
= a
->i_duration
;
722 b
->i_played_count
= a
->i_played_count
;
723 b
->i_last_played
= a
->i_last_played
;
724 b
->i_skipped_count
= a
->i_skipped_count
;
725 b
->i_last_skipped
= a
->i_last_skipped
;
726 b
->i_first_played
= a
->i_first_played
;
727 b
->i_import_time
= a
->i_import_time
;
728 b
->i_bitrate
= a
->i_bitrate
;
729 b
->i_samplerate
= a
->i_samplerate
;
733 b
->psz_uri
= strdup( a
->psz_uri
);
734 free( b
->psz_title
);
736 b
->psz_title
= strdup( a
->psz_title
);
737 free( b
->psz_orig_title
);
738 if( a
->psz_orig_title
)
739 b
->psz_orig_title
= strdup( a
->psz_orig_title
);
740 free( b
->psz_album
);
742 b
->psz_album
= strdup( a
->psz_album
);
743 free( b
->psz_cover
);
745 b
->psz_cover
= strdup( a
->psz_cover
);
746 free( b
->psz_genre
);
748 b
->psz_genre
= strdup( a
->psz_genre
);
749 free( b
->psz_comment
);
751 b
->psz_comment
= strdup( a
->psz_comment
);
752 free( b
->psz_extra
);
754 b
->psz_extra
= strdup( a
->psz_extra
);
755 free( b
->psz_preview
);
757 b
->psz_preview
= strdup( a
->psz_preview
);
758 free( b
->psz_language
);
759 if( a
->psz_language
)
760 b
->psz_language
= strdup( a
->psz_language
);
761 ml_FreePeople( b
->p_people
);
762 if( a
->p_people
) ml_CopyPersons( &( b
->p_people
), a
->p_people
);
768 /*****************************************************************************
769 * ML Find Tree Related Functions
770 *****************************************************************************/
771 #define ml_FreeFindTree( tree ) ml_GenericFreeFindTree( tree, true )
772 #define ml_ShallowFreeFindTree( tree ) ml_GenericFreeFindTree( tree, false )
774 * @brief Free a find tree
775 * @param Find tree to free
776 * @param true to free any associated strings, false to not free them
778 static inline void ml_GenericFreeFindTree( ml_ftree_t
* tree
, bool freestrings
)
784 ml_GenericFreeFindTree( tree
->left
, freestrings
);
789 ml_GenericFreeFindTree( tree
->right
, freestrings
);
792 if( tree
->op
== ML_OP_NONE
&& ml_AttributeIsString( tree
->criteria
)
793 && freestrings
== true)
795 free( tree
->value
.str
);
796 if( tree
->criteria
== ML_PEOPLE
)
797 free( tree
->lvalue
.str
);
802 * @brief Checks if a given find tree has leaf nodes
804 * @return Number of leaf nodes
806 static inline int ml_FtreeHasOp( ml_ftree_t
* tree
)
810 if( tree
->criteria
> 0 && tree
->op
== ML_OP_NONE
)
813 return ml_FtreeHasOp( tree
->left
) + ml_FtreeHasOp( tree
->right
);
818 * @brief Connect up a find tree
819 * @param op operator to connect with
820 * If op = ML_OP_NONE, then you are connecting to a tree consisting of
821 * only SPECIAL nodes.
822 * If op = ML_OP_NOT, then right MUST be NULL
823 * op must not be ML_OP_SPECIAL, @see ml_FtreeSpec
824 * @param left part of the tree
825 * @param right part of the tree
826 * @return Pointer to new tree
827 * @note Use the helpers!
829 VLC_EXPORT( ml_ftree_t
*, ml_OpConnectChilds
, ( ml_op_e op
, ml_ftree_t
* left
,
830 ml_ftree_t
* right
) );
833 * @brief Attaches a special node to a tree
834 * @param tree Tree to attach special node to
835 * @param crit Criteria may be SORT_ASC, SORT_DESC, LIMIT or DISTINCT
836 * @param limit Limit used if LIMIT criteria used
837 * @param Sort string used if SORT criteria is used
838 * @return Pointer to new tree
839 * @note Use the helpers
841 VLC_EXPORT( ml_ftree_t
*, ml_FtreeSpec
, ( ml_ftree_t
* tree
,
847 * @brief This function gives quick sequential adding capability
848 * @param left Tree to add to. This may be NULL
849 * @param right Tree to append. May not be NULL
850 * @return Pointer to new tree.*/
851 static inline ml_ftree_t
* ml_FtreeFastAnd( ml_ftree_t
* left
,
854 if( ml_FtreeHasOp( left
) == 0 )
856 return ml_OpConnectChilds( ML_OP_NONE
, left
, right
);
860 return ml_OpConnectChilds( ML_OP_AND
, left
, right
);
863 #define ml_FtreeAnd( left, right ) ml_OpConnectChilds( ML_OP_AND, left, right )
864 #define ml_FtreeOr( left, right ) ml_OpConnectChilds( ML_OP_OR, left, right )
865 #define ml_FtreeNot( left ) ml_OpConnectChilds( ML_OP_NOT, left, NULL )
867 #define ml_FtreeSpecAsc( tree, str ) ml_FtreeSpec( tree, ML_SORT_ASC, 0, str )
868 #define ml_FtreeSpecDesc( tree, str ) ml_FtreeSpec( tree, ML_SORT_DESC, 0, str )
869 #define ml_FtreeSpecLimit( tree, limit ) ml_FtreeSpec( tree, ML_LIMIT, limit, NULL )
870 #define ml_FtreeSpecDistinct( tree ) ml_FtreeSpec( tree, ML_DISTINCT, 0, NULL )
873 /*****************************************************************************
875 *****************************************************************************/
878 * @brief Create input item from media
879 * @param p_media_library This ML instance.
880 * @param i_media_id ID of the media to use to create an input_item.
881 * @return The media item.
883 static inline input_item_t
* ml_CreateInputItem(
884 media_library_t
*p_media_library
, int i_media_id
)
886 return p_media_library
->functions
.pf_InputItemFromMedia( p_media_library
,
891 * @brief Search in the database according some criterias
893 * @param p_media_library the media library object
894 * @param result a pointer to a result array
895 * @param ... parameters to select the data
896 * @return VLC_SUCCESS or an error
898 static inline int __ml_Find( media_library_t
*p_media_library
,
899 vlc_array_t
*p_result_array
, ... )
904 va_start( args
, p_result_array
);
905 returned
= p_media_library
->functions
.pf_Find( p_media_library
,
906 p_result_array
, args
);
914 * @brief Search in the database according some criterias (threaded)
915 * @param p_media_library the media library object
916 * @param result_array a pointer to a result array
917 * @param result_type type of data to retrieve
918 * @param psz_lvalue This should contain any necessary lvalue/key
919 * for the given result_type. Used for ML_PEOPLE. Otherwise NULL
920 * @param args parameters to select the data
921 * @return VLC_SUCCESS or an error
923 static inline int ml_FindAdv( media_library_t
*p_media_library
,
924 vlc_array_t
*p_result_array
,
925 ml_select_e result_type
,
929 return p_media_library
->functions
.pf_FindAdv( p_media_library
,
938 * @brief Find a value in the ML database, fill p_result with it.
939 * @param p_media_library Media library object
940 * @param p_result Object to put result into
941 * @param Args [ SelectType [ PersonType ] Value ] ... ML_END
942 * @note Do not use this function directly.
944 static inline int __ml_GetValue( media_library_t
*p_media_library
,
945 ml_result_t
*p_result
,
948 vlc_array_t
*p_result_array
= vlc_array_new();
949 int i_ret
= p_media_library
->functions
.pf_Find( p_media_library
,
952 if( i_ret
!= VLC_SUCCESS
)
954 if( vlc_array_count( p_result_array
) > 0 )
956 ( ml_result_t
* ) vlc_array_item_at_index( p_result_array
, 0 ),
957 sizeof( ml_result_t
) );
959 i_ret
= VLC_EGENERIC
;
962 /* Note: Do not free the results, because of memcpy */
963 vlc_array_destroy( p_result_array
);
968 * @brief Search an INTEGER in the database
969 * This uses a Query but returns only one integer (>0), or an error code.
971 * @param p_media_library the media library object
972 * @param va_args parameters to select the data
973 * @return Found INTEGER >= 0 or an error
975 #define ml_GetInt( ml, ... ) __ml_GetInt( ml, __VA_ARGS__, ML_LIMIT, 1, ML_END )
976 static inline int __ml_GetInt( media_library_t
*p_media_library
, ... )
979 va_start( args
, p_media_library
);
981 int i_ret
= __ml_GetValue( p_media_library
, &result
, args
);
983 if( i_ret
!= VLC_SUCCESS
)
986 return result
.value
.i
;
991 * @brief Search a string (VARCHAR) in the database
992 * This uses a Query but returns only one integer (>0), or an error code.
994 * @param p_media_library the media library object
995 * @param va_args parameters to select the data
996 * @return Found string, or NULL if not found or in case of error
998 #define ml_FindPsz( ml, ... ) __ml_GetPsz( ml, __VA_ARGS__, ML_LIMIT, 1, ML_END )
999 static inline char* __ml_GetPsz( media_library_t
*p_media_library
, ... )
1002 va_start( args
, p_media_library
);
1004 int i_ret
= __ml_GetValue( p_media_library
, &result
, args
);
1006 if( i_ret
!= VLC_SUCCESS
)
1009 return result
.value
.psz
; // no need to duplicate
1013 * @brief Generic update in Media Library database
1015 * @param p_media_library the media library object
1016 * @param selected_type the type of the element we're selecting
1017 * @param where list of ids/uris to be changed
1018 * @param changes list of changes to make in the entries
1019 * @return VLC_SUCCESS or VLC_EGENERIC
1021 static inline int ml_Update( media_library_t
*p_media_library
,
1022 ml_select_e selected_type
,
1023 const char* psz_lvalue
,
1025 vlc_array_t
*changes
)
1027 return p_media_library
->functions
.pf_Update( p_media_library
,
1028 selected_type
, psz_lvalue
,
1033 * @brief Update a given table
1034 * @param p_media_library The media library object
1035 * @param selected_type The table to update
1036 * @param psz_lvalue The role of the person if selected_type = ML_PEOPLE
1037 * @param id The id of the row to update
1038 * @param ... The update data. [SelectType [RoleType] Value]
1040 VLC_EXPORT( int, ml_UpdateSimple
, ( media_library_t
*p_media_library
,
1041 ml_select_e selected_type
,
1042 const char* psz_lvalue
,
1044 #define ml_UpdateSimple( ml, sel, lval, id, ... ) \
1045 ml_UpdateSimple( ml, sel, lval, id, __VA_ARGS__, ML_END )
1048 * @brief Generic DELETE function
1049 * Delete a media and all its references which don't point
1052 * @param p_media_library This media_library_t object
1053 * @param id the id of the media to delete
1054 * @return VLC_SUCCESS or VLC_EGENERIC
1057 ml_DeleteSimple( media_library_t
*p_media_library
, int id
)
1059 vlc_array_t
* p_where
= vlc_array_new();
1060 ml_element_t
* p_find
= (ml_element_t
*) calloc( 1, sizeof( ml_element_t
) );
1061 p_find
->criteria
= ML_ID
;
1062 p_find
->value
.i
= id
;
1063 vlc_array_append( p_where
, p_find
);
1064 int i_return
= p_media_library
->functions
.pf_Delete( p_media_library
,
1067 vlc_array_destroy( p_where
);
1072 * @brief Delete many medias in the media library
1073 * @param p_media_library Media library object
1074 * @param p_array Array of ids to delete
1075 * @return VLC_SUCCESS or VLC_EGENERIC
1078 ml_Delete( media_library_t
*p_media_library
, vlc_array_t
* p_array
)
1080 return p_media_library
->functions
.pf_Delete( p_media_library
,
1085 /*****************************************************************************
1086 * ML Person Related Functions
1087 *****************************************************************************/
1090 * @brief Create and append a person object to the given list
1091 * @param pp_person pointer to person list. Set the address to null to create new list
1092 * @param i_role The role of the person
1093 * @param psz_name The name string. Will be strdup'd
1094 * @param i_id The id in the database
1095 * @note This function is NOT thread safe. Please lock any associated media
1097 static inline int ml_CreateAppendPersonAdv( ml_person_t
**pp_person
,
1098 const char* psz_role
, const char* psz_name
, int i_id
)
1100 if( i_id
== 0 || !( psz_name
&& *psz_name
&& psz_role
&& *psz_role
) )
1103 return VLC_EGENERIC
;
1104 if( *pp_person
!= NULL
)
1105 return ml_CreateAppendPersonAdv( &((**pp_person
).p_next
),
1106 psz_role
, psz_name
, i_id
);
1107 *pp_person
= ( ml_person_t
* ) calloc( 1, sizeof( ml_person_t
) );
1108 (*pp_person
)->psz_name
= (psz_name
&& *psz_name
) ? strdup( psz_name
): NULL
;
1109 (*pp_person
)->psz_role
= (psz_role
&& *psz_role
) ? strdup( psz_role
): NULL
;
1110 (*pp_person
)->i_id
= i_id
;
1111 (*pp_person
)->p_next
= NULL
;
1116 * @brief Create and append a person object to the given list
1117 * @param pp_person pointer to person list.
1118 * Set the address to NULL to create a new list
1119 * @param personfrom Person object to copy from
1120 * @note Ignores the next variable and copies only the variables.
1121 * Uses ml_CreateAppendPersonAdv
1122 * @note This function is NOT threadsafe
1124 static inline int ml_CreateAppendPerson( ml_person_t
**pp_person
,
1125 ml_person_t
*p_personfrom
)
1127 return ml_CreateAppendPersonAdv( pp_person
,
1128 p_personfrom
->psz_role
,
1129 p_personfrom
->psz_name
,
1130 p_personfrom
->i_id
);
1134 * @brief Copy one person list into another
1136 * @param b From list
1137 * @note On errors, you have to free any allocated persons yourself
1138 * @note This function is NOT threadsafe. Please ensure your medias are locked
1140 static inline int ml_CopyPersons( ml_person_t
** a
, ml_person_t
* b
)
1145 i_ret
= ml_CreateAppendPerson( a
, b
);
1146 if( i_ret
!= VLC_SUCCESS
)
1155 * @brief Returns a person list of given type
1156 * @param p_ml The ML object
1157 * @param p_media The Media object
1158 * @param i_type The person type
1159 * @note This function is thread safe
1161 VLC_EXPORT( ml_person_t
*, ml_GetPersonsFromMedia
, ( media_library_t
* p_ml
,
1162 ml_media_t
* p_media
,
1163 const char *psz_role
) );
1166 #define ml_GetAlbumArtistsFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_ALBUM_ARTIST );
1167 #define ml_GetArtistsFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_ARTIST );
1168 #define ml_GetEncodersFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_ENCODER );
1169 #define ml_GetPublishersFromMedia( a, b ) ml_GetPersonsFromMedia( a, b, ML_PERSON_PUBLISHER );
1172 * @brief Delete a certain type of people from a media
1173 * @param p_media Media to delete from
1174 * @param i_type Type of person to delete
1175 * @note This function is threadsafe
1177 VLC_EXPORT( void, ml_DeletePersonTypeFromMedia
, ( ml_media_t
* p_media
,
1178 const char *psz_role
) );
1182 * @brief Creates and adds the playlist based on a given find tree
1183 * @param p_ml Media library object
1184 * @param p_tree Find tree to create SELECT
1187 VLC_EXPORT( void, ml_PlaySmartPlaylistBasedOn
, ( media_library_t
* p_ml
,
1188 ml_ftree_t
* p_tree
) );
1192 * Convenience Macros
1196 * Get information using the *media* ID. This returns only 1 information.
1197 * @note You have to free the string returned (if that's a string!).
1199 #define ml_GetAlbumById( a, id ) ml_GetPsz( a, ML_ALBUM, ML_ID, id )
1200 #define ml_GetArtistById( a, id ) ml_GetPsz( a, ML_PEOPLE, ML_PERSON_ARTIST, ML_ID, id )
1201 #define ml_GetCoverUriById( a, id ) ml_GetPsz( a, ML_COVER, ML_ID, id )
1202 #define ml_GetEncoderById( a, id ) ml_GetPsz( a, ML_PEOPLE, ML_PERSON_ENCODER, ML_ID, id )
1203 #define ml_GetExtraById( a, id ) ml_GetPsz( a, ML_EXTRA, ML_ID, id )
1204 #define ml_GetGenreById( a, id ) ml_GetPsz( a, ML_GENRE, ML_ID, id )
1205 #define ml_GetOriginalTitleById( a, id ) ml_GetPsz( a, ML_ORIGINAL_TITLE, ML_ID, id )
1206 #define ml_GetPublisherById( a, id ) ml_GetPsz( a, ML_PEOPLE, ML_PERSON_PUBLISHER, ML_ID, id )
1207 #define ml_GetTitleById( a, id ) ml_GetPsz( a, ML_TITLE, ML_ID, id )
1208 #define ml_GetUriById( a, id ) ml_GetPsz( a, ML_URI, ML_ID, id )
1210 #define ml_GetAlbumIdById( a, id ) ml_GetInt( a, ML_ALBUM_ID, ML_ID, id )
1211 #define ml_GetArtistIdById( a, id ) ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_ARTIST, ML_ID, id )
1212 #define ml_GetDurationById( a, id ) ml_GetInt( a, ML_DURATION, ML_ID, id )
1213 #define ml_GetEncoderIdById( a, id ) ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_ENCODER, ML_ID, id )
1214 #define ml_GetLastPlayedById( a, id ) ml_GetInt( a, ML_LAST_PLAYED, ML_ID, id )
1215 #define ml_GetPlayedCountById( a, id ) ml_GetInt( a, ML_PLAYED_COUNT, ML_ID, id )
1216 #define ml_GetPublisherIdById( a, id ) ml_GetInt( a, ML_PEOPLE_ID, ML_PERSON_PUBLISHER, ML_ID, id )
1217 #define ml_GetScoreById( a, id ) ml_GetInt( a, ML_SCORE, ML_ID, id )
1218 #define ml_GetTrackNumberById( a, id ) ml_GetInt( a, ML_TRACK_NUMBER, ML_ID, id )
1219 #define ml_GetTypeById( a, id ) ml_GetInt( a, ML_TYPE, ML_ID, id )
1220 #define ml_GetYearById( a, id ) ml_GetInt( a, ML_YEAR, ML_ID, id )
1221 #define ml_GetVoteById( a, id ) ml_GetInt( a, ML_VOTE, ML_ID, id )
1223 /** Albums handling */
1224 #define ml_GetAlbumId( a, b ) ml_GetInt( a, ML_ALBUM_ID, ML_ALBUM, b )
1226 /** People handling */
1227 #define ml_GetArtistId( a, b ) ml_GetInt( a, ML_PERSON_ID, ML_PERSON_ARTIST, ML_PERSON, ML_PERSON_ARTIST, b )
1228 #define ml_GetEncoderId( a, b ) ml_GetInt( a, ML_PERSON_ID, ML_PERSON_ENCODER, ML_PERSON, ML_PERSON_ENCODER, b )
1229 #define ml_GetPublisherId( a, b ) ml_GetInt( a, ML_PERSON_ID, ML_PERSON_PUBLISHER, ML_PERSON, ML_PERSON_PUBLISHER, b )
1231 /** Counts handling */
1232 #define ml_GetMediaCount( a, ... ) __ml_GetInt( a, ML_COUNT_MEDIA, __VA_ARGS__, ML_END )
1233 #define ml_GetAlbumCount( a, ... ) __ml_GetInt( a, ML_COUNT_ALBUM, __VA_ARGS__, ML_END )
1234 #define ml_GetPeopleCount( a, ... ) __ml_GetInt( a, ML_COUNT_PEOPLE, __VA_ARGS__, ML_END )
1236 #define ml_Find( a, b, ... ) __ml_Find( a, b, __VA_ARGS__, ML_END )
1238 #define ml_FindAlbum( a, b, ... ) __ml_Find( a, b, ML_ALBUM, __VA_ARGS__, ML_END )
1239 #define ml_FindArtist( a, b, ... ) __ml_Find( a, b, ML_PERSON, ML_PERSON_ARTIST, __VA_ARGS__, ML_END )
1240 #define ml_FindEncoder( a, b, ... ) __ml_Find( a, b, ML_PERSON, ML_PERSON_ENCODER, __VA_ARGS__, ML_END )
1241 #define ml_FindGenre( a, b, ... ) __ml_Find( a, b, ML_GENRE, __VA_ARGS__, ML_END )
1242 #define ml_FindMedia( a, b, ... ) __ml_Find( a, b, ML_MEDIA, __VA_ARGS__, ML_END )
1243 #define ml_FindOriginalTitle( a, b, ... ) __ml_Find( a, b, ML_ORIGINAL_TITLE, __VA_ARGS__, ML_END )
1244 #define ml_FindPublisher( a, b, ... ) __ml_Find( a, b, ML_PERSON, ML_PERSON_PUBLISHER, __VA_ARGS__, ML_END )
1245 #define ml_FindTitle( a, b, ... ) __ml_Find( a, b, ML_TITLE, __VA_ARGS__, ML_END )
1246 #define ml_FindType( a, b, ... ) __ml_Find( a, b, ML_TYPE, __VA_ARGS__, ML_END )
1247 #define ml_FindUri( a, b, ... ) __ml_Find( a, b, ML_URI, __VA_ARGS__, ML_END )
1248 #define ml_FindYear( a, b, ... ) __ml_Find( a, b, ML_YEAR, __VA_ARGS__, ML_END )
1250 #define ml_FindAllAlbums( a, b ) ml_FindAlbum( a, b, ML_DISTINCT )
1251 #define ml_FindAllArtists( a, b ) ml_FindArtist( a, b, ML_DISTINCT )
1252 #define ml_FindAllGenres( a, b ) ml_FindGenre( a, b, ML_DISTINCT )
1253 #define ml_FindAllMedias( a, b ) ml_FindMedia( a, b, ML_DISTINCT )
1254 #define ml_FindAllOriginalTitles( a, b ) ml_FindOriginalTitle( a, b, ML_DISTINCT )
1255 #define ml_FindAllPublishers( a, b, ... ) ml_FindPublisher( a, b, ML_DISTINCT )
1256 #define ml_FindAllTitles( a, b ) ml_FindTitle( a, b, ML_DISTINCT )
1257 #define ml_FindAllTypes( a, b ) ml_FindType( a, b, ML_DISTINCT )
1258 #define ml_FindAllUris( a, b ) ml_FindUri( a, b, ML_DISTINCT )
1259 #define ml_FindAllYears( a, b ) ml_FindYear( a, b, ML_DISTINCT )
1261 #define ml_FindAlbumAdv( a, b, c ) ml_FindAdv( a, b, ML_ALBUM, NULL, c )
1262 #define ml_FindArtistAdv( a, b, c ) ml_FindAdv( a, b, ML_PERSON, ML_PERSON_ARTIST, c )
1263 #define ml_FindEncoderAdv( a, b, c ) ml_FindAdv( a, b, ML_PERSON, ML_PERSON_ENCODER, c )
1264 #define ml_FindGenreAdv( a, b, c ) ml_FindAdv( a, b, ML_GENRE, NULL, c )
1265 #define ml_FindMediaAdv( a, b, c ) ml_FindAdv( a, b, ML_MEDIA, NULL, c )
1266 #define ml_FindOriginalTitleAdv( a, b, c ) ml_FindAdv( a, b, ML_ORIGINAL_TITLE,NULL, c )
1267 #define ml_FindPublisherAdv( a, b, c ) ml_FindAdv( a, b, ML_PUBLISHER, ML_PERSON_PUBLISHER, c )
1268 #define ml_FindTitleAdv( a, b, c ) ml_FindAdv( a, b, ML_TITLE, NULL, c )
1269 #define ml_FindTypeAdv( a, b, c ) ml_FindAdv( a, b, ML_TYPE, NULL, c )
1270 #define ml_FindUriAdv( a, b, c ) ml_FindAdv( a, b, ML_URI, NULL, c )
1271 #define ml_FindYearAdv( a, b, c ) ml_FindAdv( a, b, ML_YEAR, NULL, c )
1279 #endif /* VLC_MEDIA_LIBRARY_H */