]> git.sesse.net Git - vlc/blob - src/playlist/sort.c
Add a function to get the Title and fallback to the name if the title is empty.
[vlc] / src / playlist / sort.c
1 /*****************************************************************************
2  * sort.c : Playlist sorting functions
3  *****************************************************************************
4  * Copyright (C) 1999-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *          Ilkka Ollakka <ileoo@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <vlc_common.h>
29 #include "vlc_playlist.h"
30 #include "playlist_internal.h"
31
32
33 static int playlist_ItemArraySort( playlist_t *p_playlist, int i_items,
34                                    playlist_item_t **pp_items, int i_mode,
35                                    int i_type );
36 static int playlist_cmp(const void *, const void *);
37
38 /**
39  * Sort a node.
40  * This function must be entered with the playlist lock !
41  *
42  * \param p_playlist the playlist
43  * \param p_node the node to sort
44  * \param i_mode: SORT_ID, SORT_TITLE, SORT_ARTIST, SORT_ALBUM, SORT_RANDOM
45  * \param i_type: ORDER_NORMAL or ORDER_REVERSE (reversed order)
46  * \return VLC_SUCCESS on success
47  */
48 static int playlist_NodeSort( playlist_t * p_playlist , playlist_item_t *p_node,
49                               int i_mode, int i_type )
50 {
51     playlist_ItemArraySort( p_playlist,p_node->i_children,
52                             p_node->pp_children, i_mode, i_type );
53     return VLC_SUCCESS;
54 }
55
56 /**
57  * Sort a node recursively.
58  *
59  * This function must be entered with the playlist lock !
60  *
61  * \param p_playlist the playlist
62  * \param p_node the node to sort
63  * \param i_mode: SORT_ID, SORT_TITLE, SORT_ARTIST, SORT_ALBUM, SORT_RANDOM
64  * \param i_type: ORDER_NORMAL or ORDER_REVERSE (reversed order)
65  * \return VLC_SUCCESS on success
66  */
67 int playlist_RecursiveNodeSort( playlist_t *p_playlist, playlist_item_t *p_node,
68                                 int i_mode, int i_type )
69 {
70     int i;
71     playlist_NodeSort( p_playlist, p_node, i_mode, i_type );
72     for( i = 0 ; i< p_node->i_children; i++ )
73     {
74         if( p_node->pp_children[i]->i_children != -1 )
75         {
76             playlist_RecursiveNodeSort( p_playlist, p_node->pp_children[i],
77                                         i_mode,i_type );
78         }
79     }
80     return VLC_SUCCESS;
81 }
82
83 static int sort_mode = 0;
84 static int sort_type = 0;
85
86 static int playlist_ItemArraySort( playlist_t *p_playlist, int i_items,
87                                    playlist_item_t **pp_items, int i_mode,
88                                    int i_type )
89 {
90     int i_position;
91     playlist_item_t *p_temp;
92     sort_mode = i_mode;
93     sort_type = i_type;
94
95     (void)p_playlist; // a bit surprising we don't need p_playlist!
96
97     if( i_mode == SORT_RANDOM )
98     {
99         for( i_position = 0; i_position < i_items ; i_position ++ )
100         {
101             int i_new;
102
103             if( i_items > 1 )
104                 i_new = rand() % (i_items - 1);
105             else
106                 i_new = 0;
107             p_temp = pp_items[i_position];
108             pp_items[i_position] = pp_items[i_new];
109             pp_items[i_new] = p_temp;
110         }
111
112         return VLC_SUCCESS;
113     }
114     qsort(pp_items,i_items,sizeof(pp_items[0]),playlist_cmp);
115     return VLC_SUCCESS;
116 }
117
118 static int playlist_cmp(const void *first, const void *second)
119 {
120
121 #define META_STRCASECMP_NAME( ) { \
122     char *psz_i = input_item_GetTitleFbName( (*(playlist_item_t **)first)->p_input ); \
123     char *psz_ismall = input_item_GetTitleFbName( (*(playlist_item_t **)second)->p_input ); \
124     if( psz_i != NULL && psz_ismall != NULL ) i_test = strcasecmp( psz_i, psz_ismall ); \
125     else if ( psz_i == NULL && psz_ismall != NULL ) i_test = 1; \
126     else if ( psz_ismall == NULL && psz_i != NULL ) i_test = -1; \
127     else i_test = 0; \
128     free( psz_i ); \
129     free( psz_ismall ); \
130 }
131
132
133 #define DO_META_SORT_ADV( node, integer ) { \
134     char *psz_a = input_item_GetMeta( (*(playlist_item_t **)first)->p_input, vlc_meta_##node ); \
135     char *psz_b = input_item_GetMeta( (*(playlist_item_t **)second)->p_input, vlc_meta_##node ); \
136     /* Nodes go first */ \
137     if( (*(playlist_item_t **)first)->i_children == -1 && (*(playlist_item_t **)second)->i_children >= 0 ) \
138         i_test = 1;\
139     else if( (*(playlist_item_t **)first)->i_children >= 0 &&\
140              (*(playlist_item_t **)second)->i_children == -1 ) \
141        i_test = -1; \
142     /* Both are nodes, sort by name */ \
143     else if( (*(playlist_item_t **)first)->i_children >= 0 && \
144                (*(playlist_item_t **)second)->i_children >= 0 ) \
145     { \
146         META_STRCASECMP_NAME( ) \
147     } \
148     /* Both are items */ \
149     else if( psz_a == NULL && psz_b != NULL ) \
150         i_test = 1; \
151     else if( psz_a != NULL && psz_b == NULL ) \
152         i_test = -1;\
153     /* No meta, sort by name */ \
154     else if( psz_a == NULL && psz_b == NULL ) \
155     { \
156         META_STRCASECMP_NAME( ); \
157     } \
158     else \
159     { \
160         if( !integer ) i_test = strcasecmp( psz_a, psz_b ); \
161         else           i_test = atoi( psz_a ) - atoi( psz_b ); \
162     } \
163     free( psz_a ); \
164     free( psz_b ); \
165 }
166 #define DO_META_SORT( node ) DO_META_SORT_ADV( node, false )
167
168     int i_test = 0;
169
170     if( sort_mode == SORT_TITLE )
171     {
172         META_STRCASECMP_NAME( );
173     }
174     else if( sort_mode == SORT_TITLE_NUMERIC )
175     {
176         char *psz_i = input_item_GetName( (*(playlist_item_t **)first)->p_input );
177         char *psz_ismall =
178                 input_item_GetName( (*(playlist_item_t **)second)->p_input );
179         i_test = atoi( psz_i ) - atoi( psz_ismall );
180         free( psz_i );
181         free( psz_ismall );
182     }
183     else if( sort_mode == SORT_DURATION )
184     {
185         i_test = input_item_GetDuration( (*(playlist_item_t **)first)->p_input ) -
186                  input_item_GetDuration( (*(playlist_item_t **)second)->p_input );
187     }
188     else if( sort_mode == SORT_ARTIST )
189     {
190         DO_META_SORT( Artist );
191         /* sort by artist, album, tracknumber */
192         if( i_test == 0 )
193             DO_META_SORT( Album );
194         if( i_test == 0 )
195             DO_META_SORT_ADV( TrackNumber, true );
196     }
197     else if( sort_mode == SORT_GENRE )
198     {
199         DO_META_SORT( Genre );
200     }
201     else if( sort_mode == SORT_ALBUM )
202     {
203         DO_META_SORT( Album );
204         /* Sort by tracknumber if albums are the same */
205         if( i_test == 0 )
206             DO_META_SORT_ADV( TrackNumber, true );
207     }
208     else if( sort_mode == SORT_TRACK_NUMBER )
209     {
210         DO_META_SORT_ADV( TrackNumber, true );
211     }
212     else if( sort_mode == SORT_DESCRIPTION )
213     {
214         DO_META_SORT( Description );
215     }
216     else if( sort_mode == SORT_ID )
217     {
218         i_test = (*(playlist_item_t **)first)->i_id - (*(playlist_item_t **)second)->i_id;
219     }
220     else if( sort_mode == SORT_TITLE_NODES_FIRST )
221     {
222         /* Alphabetic sort, all nodes first */
223
224         if( (*(playlist_item_t **)first)->i_children == -1 &&
225             (*(playlist_item_t **)second)->i_children >= 0 )
226         {
227             i_test = 1;
228         }
229         else if( (*(playlist_item_t **)first)->i_children >= 0 &&
230                  (*(playlist_item_t **)second)->i_children == -1 )
231         {
232             i_test = -1;
233         }
234         else
235         {
236             META_STRCASECMP_NAME();
237         }
238     }
239     else if( sort_mode == SORT_URI )
240     {
241         char *psz_i = input_item_GetURI( (*(playlist_item_t **)first)->p_input );
242         char *psz_ismall =
243                 input_item_GetURI( (*(playlist_item_t **)second)->p_input );
244         i_test = strcasecmp( psz_i, psz_ismall );
245         free( psz_i );
246         free( psz_ismall );
247     }
248
249     if ( sort_type == ORDER_REVERSE )
250         i_test = i_test * -1;
251 #undef DO_META_SORT
252 #undef DO_META_SORT_ADV
253
254     return i_test;
255 }