]> git.sesse.net Git - vlc/blob - src/playlist/item-ext.c
8b3c3a3b44e12eec0c15bd5c14a06dc26d17bd3e
[vlc] / src / playlist / item-ext.c
1 /*****************************************************************************
2  * item-ext.c : Playlist item management functions
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          ClĂ©ment Stenac <zorglub@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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24 #include <stdlib.h>                                      /* free(), strtol() */
25 #include <stdio.h>                                              /* sprintf() */
26 #include <string.h>                                            /* strerror() */
27
28 #include <vlc/vlc.h>
29 #include <vlc/input.h>
30
31 #include "vlc_playlist.h"
32
33 /***************************************************************************
34  * Item creation/addition functions
35  ***************************************************************************/
36
37 /**
38  * Add a MRL into the playlist, duration and options given
39  *
40  * \param p_playlist the playlist to add into
41  * \param psz_uri the mrl to add to the playlist
42  * \param psz_name a text giving a name or description of this item
43  * \param i_mode the mode used when adding
44  * \param i_pos the position in the playlist where to add. If this is
45  *        PLAYLIST_END the item will be added at the end of the playlist
46  *        regardless of it's size
47  * \param i_duration length of the item in milliseconds.
48  * \param ppsz_options an array of options
49  * \param i_options the number of options
50  * \return The id of the playlist item
51 */
52 int playlist_AddExt( playlist_t *p_playlist, const char * psz_uri,
53                      const char *psz_name, int i_mode, int i_pos,
54                      mtime_t i_duration, const char **ppsz_options,
55                      int i_options )
56 {
57     playlist_item_t *p_item =
58         playlist_ItemNew( p_playlist , psz_uri, psz_name );
59
60     if( p_item == NULL )
61     {
62         msg_Err( p_playlist, "unable to add item to playlist" );
63         return -1;
64     }
65
66     p_item->input.i_duration = i_duration;
67     p_item->input.i_options = i_options;
68     p_item->input.ppsz_options = NULL;
69
70     for( p_item->input.i_options = 0; p_item->input.i_options < i_options;
71          p_item->input.i_options++ )
72     {
73         if( !p_item->input.i_options )
74         {
75             p_item->input.ppsz_options = malloc( i_options * sizeof(char *) );
76             if( !p_item->input.ppsz_options ) break;
77         }
78
79         p_item->input.ppsz_options[p_item->input.i_options] =
80             strdup( ppsz_options[p_item->input.i_options] );
81     }
82
83     return playlist_AddItem( p_playlist, p_item, i_mode, i_pos );
84 }
85
86 /**
87  * Add a MRL into the playlist.
88  *
89  * \param p_playlist the playlist to add into
90  * \param psz_uri the mrl to add to the playlist
91  * \param psz_name a text giving a name or description of this item
92  * \param i_mode the mode used when adding
93  * \param i_pos the position in the playlist where to add. If this is
94  *        PLAYLIST_END the item will be added at the end of the playlist
95  *        regardless of it's size
96  * \return The id of the playlist item
97 */
98 int playlist_Add( playlist_t *p_playlist, const char *psz_uri,
99                   const char *psz_name, int i_mode, int i_pos )
100 {
101     return playlist_AddExt( p_playlist, psz_uri, psz_name, i_mode, i_pos,
102                             -1, NULL, 0 );
103 }
104
105 /***************************************************************************
106  * Item search functions
107  ***************************************************************************/
108
109 /**
110  * Search the position of an item by its id
111  * This function must be entered with the playlist lock
112  *
113  * \param p_playlist the playlist
114  * \param i_id the id to find
115  * \return the position, or VLC_EGENERIC on failure
116  */
117 int playlist_GetPositionById( playlist_t * p_playlist , int i_id )
118 {
119     int i;
120     for( i =  0 ; i < p_playlist->i_size ; i++ )
121     {
122         if( p_playlist->pp_items[i]->i_id == i_id )
123         {
124             return i;
125         }
126     }
127     return VLC_EGENERIC;
128 }
129
130 /**
131  * Search an item by its id
132  *
133  * \param p_playlist the playlist
134  * \param i_id the id to find
135  * \return the item, or NULL on failure
136  */
137 playlist_item_t * playlist_ItemGetById( playlist_t * p_playlist , int i_id )
138 {
139     int i;
140     for( i =  0 ; i < p_playlist->i_size ; i++ )
141     {
142         if( p_playlist->pp_items[i]->i_id == i_id )
143         {
144             return p_playlist->pp_items[i];
145         }
146     }
147     return NULL;
148 }
149
150 /**
151  * Search an item by its position
152  * This function must be entered with the playlist lock
153  *
154  * \param p_playlist the playlist
155  * \param i_pos the position of the item to find
156  * \return the item, or NULL on failure
157  */
158 playlist_item_t * playlist_ItemGetByPos( playlist_t * p_playlist , int i_pos )
159 {
160     if( i_pos >= 0 && i_pos < p_playlist->i_size)
161     {
162         return p_playlist->pp_items[i_pos];
163     }
164     else if( p_playlist->i_size > 0)
165     {
166         return p_playlist->pp_items[p_playlist->i_index];
167     }
168     else
169     {
170         return NULL;
171     }
172 }
173
174 /**********************************************************************
175  * playlist_item_t structure accessors
176  * These functions give access to the fields of the playlist_item_t
177  * structure
178  **********************************************************************/
179
180 /**
181  * Set the group of a playlist item
182  *
183  * \param p_item the item
184  * \param i_group the group to set
185  * \return VLC_SUCCESS on success
186  */
187 int playlist_ItemSetGroup( playlist_item_t *p_item, int i_group)
188 {
189     p_item->i_group = i_group;
190     return VLC_SUCCESS;
191 }
192
193 /**
194  * Set the group of a playlist item (by position)
195  * This function must be entered with the playlist lock
196  * Legacy function due to disappear (locks the whole playlist)
197  *
198  * \param p_playlist the playlist
199  * \param i_pos the postition of the item of which we change the group
200  * \param i_group the new group
201  * \return VLC_SUCCESS on success, VLC_EGENERIC on failure
202  */
203 int playlist_SetGroup( playlist_t *p_playlist, int i_pos, int i_group )
204 {
205     vlc_value_t val;
206     playlist_item_t *p_item;
207     if( !p_playlist )
208     {
209         return VLC_ENOOBJ;
210     }
211
212     p_item = playlist_ItemGetByPos( p_playlist , i_pos );
213     if( !p_item )
214     {
215         return VLC_ENOOBJ;
216     }
217
218     vlc_mutex_lock( &p_item->input.lock );
219     playlist_ItemSetGroup( p_item , i_group );
220     vlc_mutex_unlock( &p_item->input.lock );
221
222     val.b_bool = (i_pos >= 0 && i_pos < p_playlist->i_size ) ? i_pos : -1;
223     var_Set( p_playlist, "item-change", val );
224
225     return VLC_SUCCESS;
226 }
227
228 /**
229  * Set the name of a playlist item
230  *
231  * \param p_item the item
232  * \param psz_name the new name
233  * \return VLC_SUCCESS on success, VLC_EGENERIC on failure
234  */
235 int playlist_ItemSetName( playlist_item_t *p_item, char *psz_name )
236 {
237     if( psz_name && p_item )
238     {
239         p_item->input.psz_name = strdup( psz_name );
240         return VLC_SUCCESS;
241     }
242     return VLC_EGENERIC;
243 }
244
245 /**
246  * Set the name of a playlist item (by position)
247  * This function must be entered with the playlist lock
248  * Legacy function due to disappear (locks the whole playlist)
249  *
250  * \param p_playlist the playlist
251  * \param i_pos the position of the item of which we change the name
252  * \param psz_name the new name
253  * \return VLC_SUCCESS on success, VLC_EGENERIC on failure
254  */
255 int playlist_SetName( playlist_t *p_playlist, int i_pos, char *psz_name )
256 {
257     vlc_value_t val;
258     playlist_item_t *p_item;
259     if( !p_playlist )
260     {
261         return VLC_ENOOBJ;
262     }
263
264     p_item = playlist_ItemGetByPos( p_playlist , i_pos );
265     if( !p_item )
266     {
267         return VLC_ENOOBJ;
268     }
269
270     vlc_mutex_lock( &p_item->input.lock );
271     playlist_ItemSetName( p_item , psz_name );
272     vlc_mutex_unlock( &p_item->input.lock );
273
274     val.b_bool = (i_pos >= 0 && i_pos < p_playlist->i_size ) ? i_pos : -1;
275     var_Set( p_playlist, "item-change", val );
276
277     return VLC_SUCCESS;
278 }
279
280 /**
281  * Set the duration of a playlist item
282  * This function must be entered with the item lock
283  *
284  * \param p_item the item
285  * \param i_duration the new duration
286  * \return VLC_SUCCESS on success, VLC_EGENERIC on failure
287  */
288 int playlist_ItemSetDuration( playlist_item_t *p_item, mtime_t i_duration )
289 {
290     char psz_buffer[MSTRTIME_MAX_SIZE];
291     if( p_item )
292     {
293         p_item->input.i_duration = i_duration;
294         if( i_duration != -1 )
295         {
296             secstotimestr( psz_buffer, i_duration/1000000 );
297         }
298         else
299         {
300             memcpy( psz_buffer, "--:--:--", sizeof("--:--:--") );
301         }
302         playlist_ItemAddInfo( p_item, _("General") , _("Duration"),
303                               "%s", psz_buffer );
304
305         return VLC_SUCCESS;
306     }
307     return VLC_EGENERIC;
308 }
309
310 /**
311  * Set the duration of a playlist item
312  * This function must be entered with the playlist lock
313  * Legacy function due to disappear (locks the whole playlist)
314  *
315  * \param p_playlist the playlist
316  * \param i_pos the position of the item of which we change the duration
317  * \param i_duration the duration to set
318  * \return VLC_SUCCESS on success, VLC_EGENERIC on failure
319  */
320 int playlist_SetDuration( playlist_t *p_playlist, int i_pos, mtime_t i_duration )
321 {
322     vlc_value_t val;
323     playlist_item_t *p_item;
324     if( !p_playlist )
325     {
326         return VLC_ENOOBJ;
327     }
328
329     p_item = playlist_ItemGetByPos( p_playlist , i_pos );
330     if( !p_item )
331     {
332         return VLC_ENOOBJ;
333     }
334
335     vlc_mutex_lock( &p_item->input.lock );
336     playlist_ItemSetDuration( p_item , i_duration );
337     vlc_mutex_unlock( &p_item->input.lock );
338
339     val.b_bool = (i_pos >= 0 && i_pos < p_playlist->i_size ) ? i_pos : -1;
340     var_Set( p_playlist, "item-change", val );
341
342     return VLC_SUCCESS;
343 }
344
345 /**********************************************************************
346  * Actions on existing playlist items
347  **********************************************************************/
348
349 /**
350  * delete an item from a playlist.
351  *
352  * \param p_playlist the playlist to remove from.
353  * \param i_pos the position of the item to remove
354  * \return returns 0
355  */
356 int playlist_Delete( playlist_t * p_playlist, int i_pos )
357 {
358     vlc_value_t     val;
359
360     /* if i_pos is the current played item, playlist should stop playing it */
361     if( ( p_playlist->i_status == PLAYLIST_RUNNING) &&
362                     (p_playlist->i_index == i_pos) )
363     {
364         playlist_Command( p_playlist, PLAYLIST_STOP, 0 );
365     }
366
367     vlc_mutex_lock( &p_playlist->object_lock );
368     if( i_pos >= 0 && i_pos < p_playlist->i_size )
369     {
370         playlist_item_t *p_item = p_playlist->pp_items[i_pos];
371
372         msg_Dbg( p_playlist, "deleting playlist item `%s'",
373                  p_item->input.psz_name );
374
375         playlist_ItemDelete( p_item );
376
377         if( i_pos <= p_playlist->i_index )
378         {
379             p_playlist->i_index--;
380         }
381
382         /* Renumber the playlist */
383         REMOVE_ELEM( p_playlist->pp_items, p_playlist->i_size, i_pos );
384
385         if( p_playlist->i_enabled > 0 ) p_playlist->i_enabled--;
386     }
387
388     vlc_mutex_unlock( &p_playlist->object_lock );
389
390     val.b_bool = VLC_TRUE;
391     var_Set( p_playlist, "intf-change", val );
392
393     return 0;
394 }
395
396 /**
397  * Clear all playlist items
398  *
399  * \param p_playlist the playlist to be cleared.
400  * \return returns 0
401  */
402 int playlist_Clear( playlist_t * p_playlist )
403 {
404
405     while( p_playlist->i_groups > 0 )
406     {
407         playlist_DeleteGroup( p_playlist, p_playlist->pp_groups[0]->i_id );
408     }
409
410     while( p_playlist->i_size > 0 )
411     {
412         playlist_Delete( p_playlist, 0 );
413     }
414
415     p_playlist->i_index = -1;
416     p_playlist->i_size = 0;
417     p_playlist->pp_items = NULL;
418
419     p_playlist->i_groups = 0;
420     p_playlist->pp_groups = NULL;
421
422     return 0;
423 }
424
425 /**
426  * Disables a playlist item
427  *
428  * \param p_playlist the playlist to disable from.
429  * \param i_pos the position of the item to disable
430  * \return returns 0
431  */
432 int playlist_Disable( playlist_t * p_playlist, int i_pos )
433 {
434     vlc_value_t     val;
435     vlc_mutex_lock( &p_playlist->object_lock );
436
437
438     if( i_pos >= 0 && i_pos < p_playlist->i_size )
439     {
440         msg_Dbg( p_playlist, "disabling playlist item `%s'",
441                  p_playlist->pp_items[i_pos]->input.psz_name );
442
443         if( p_playlist->pp_items[i_pos]->b_enabled == VLC_TRUE )
444             p_playlist->i_enabled--;
445         p_playlist->pp_items[i_pos]->b_enabled = VLC_FALSE;
446     }
447
448     vlc_mutex_unlock( &p_playlist->object_lock );
449
450     val.b_bool = i_pos;
451     var_Set( p_playlist, "item-change", val );
452
453     return 0;
454 }
455
456 /**
457  * Enables a playlist item
458  *
459  * \param p_playlist the playlist to enable from.
460  * \param i_pos the position of the item to enable
461  * \return returns 0
462  */
463 int playlist_Enable( playlist_t * p_playlist, int i_pos )
464 {
465     vlc_value_t     val;
466     vlc_mutex_lock( &p_playlist->object_lock );
467
468     if( i_pos >= 0 && i_pos < p_playlist->i_size )
469     {
470         msg_Dbg( p_playlist, "enabling playlist item `%s'",
471                  p_playlist->pp_items[i_pos]->input.psz_name );
472
473         if( p_playlist->pp_items[i_pos]->b_enabled == VLC_FALSE )
474             p_playlist->i_enabled++;
475
476         p_playlist->pp_items[i_pos]->b_enabled = VLC_TRUE;
477     }
478
479     vlc_mutex_unlock( &p_playlist->object_lock );
480
481     val.b_bool = i_pos;
482     var_Set( p_playlist, "item-change", val );
483
484     return 0;
485 }
486
487 /**
488  * Disables a playlist group
489  *
490  * \param p_playlist the playlist to disable from.
491  * \param i_group the id of the group to disable
492  * \return returns 0
493  */
494 int playlist_DisableGroup( playlist_t * p_playlist, int i_group )
495 {
496     vlc_value_t     val;
497     int i;
498     vlc_mutex_lock( &p_playlist->object_lock );
499
500     msg_Dbg( p_playlist, "disabling group %i", i_group );
501     for( i = 0 ; i< p_playlist->i_size; i++ )
502     {
503         if( p_playlist->pp_items[i]->i_group == i_group )
504         {
505             msg_Dbg( p_playlist, "disabling playlist item `%s'",
506                      p_playlist->pp_items[i]->input.psz_name );
507
508             if( p_playlist->pp_items[i]->b_enabled == VLC_TRUE )
509                 p_playlist->i_enabled--;
510
511             p_playlist->pp_items[i]->b_enabled = VLC_FALSE;
512             val.b_bool = i;
513             var_Set( p_playlist, "item-change", val );
514         }
515     }
516     vlc_mutex_unlock( &p_playlist->object_lock );
517
518     return 0;
519 }
520
521 /**
522  * Enables a playlist group
523  *
524  * \param p_playlist the playlist to enable from.
525  * \param i_group the id of the group to enable
526  * \return returns 0
527  */
528 int playlist_EnableGroup( playlist_t * p_playlist, int i_group )
529 {
530     vlc_value_t val;
531     int i;
532     vlc_mutex_lock( &p_playlist->object_lock );
533
534     for( i = 0; i< p_playlist->i_size; i++ )
535     {
536         if( p_playlist->pp_items[i]->i_group == i_group )
537         {
538             msg_Dbg( p_playlist, "enabling playlist item `%s'",
539                      p_playlist->pp_items[i]->input.psz_name );
540
541             if( p_playlist->pp_items[i]->b_enabled == VLC_FALSE )
542                 p_playlist->i_enabled++;
543
544             p_playlist->pp_items[i]->b_enabled = VLC_TRUE;
545             val.b_bool = i;
546             var_Set( p_playlist, "item-change", val );
547         }
548     }
549     vlc_mutex_unlock( &p_playlist->object_lock );
550
551     return 0;
552 }
553
554 /**
555  * Move an item in a playlist
556  *
557  * Move the item in the playlist with position i_pos before the current item
558  * at position i_newpos.
559  * \param p_playlist the playlist to move items in
560  * \param i_pos the position of the item to move
561  * \param i_newpos the position of the item that will be behind the moved item
562  *        after the move
563  * \return returns VLC_SUCCESS
564  */
565 int playlist_Move( playlist_t * p_playlist, int i_pos, int i_newpos )
566 {
567     vlc_value_t val;
568     vlc_mutex_lock( &p_playlist->object_lock );
569
570     /* take into account that our own row disappears. */
571     if( i_pos < i_newpos ) i_newpos--;
572
573     if( i_pos >= 0 && i_newpos >=0 && i_pos <= p_playlist->i_size &&
574         i_newpos <= p_playlist->i_size )
575     {
576         playlist_item_t * temp;
577
578         msg_Dbg( p_playlist, "moving playlist item `%s' (%i -> %i)",
579                  p_playlist->pp_items[i_pos]->input.psz_name, i_pos, i_newpos);
580
581         if( i_pos == p_playlist->i_index )
582         {
583             p_playlist->i_index = i_newpos;
584         }
585         else if( i_pos > p_playlist->i_index && i_newpos <= p_playlist->i_index )
586         {
587             p_playlist->i_index++;
588         }
589         else if( i_pos < p_playlist->i_index && i_newpos >= p_playlist->i_index )
590         {
591             p_playlist->i_index--;
592         }
593
594         if ( i_pos < i_newpos )
595         {
596             temp = p_playlist->pp_items[i_pos];
597             while ( i_pos < i_newpos )
598             {
599                 p_playlist->pp_items[i_pos] = p_playlist->pp_items[i_pos+1];
600                 i_pos++;
601             }
602             p_playlist->pp_items[i_newpos] = temp;
603         }
604         else if ( i_pos > i_newpos )
605         {
606             temp = p_playlist->pp_items[i_pos];
607             while ( i_pos > i_newpos )
608             {
609                 p_playlist->pp_items[i_pos] = p_playlist->pp_items[i_pos-1];
610                 i_pos--;
611             }
612             p_playlist->pp_items[i_newpos] = temp;
613         }
614     }
615
616     vlc_mutex_unlock( &p_playlist->object_lock );
617
618     val.b_bool = VLC_TRUE;
619     var_Set( p_playlist, "intf-change", val );
620
621     return VLC_SUCCESS;
622 }