1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2018 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
33 vlc_playlist_ClearItems(vlc_playlist_t
*playlist
)
35 vlc_playlist_item_t
*item
;
36 vlc_vector_foreach(item
, &playlist
->items
)
37 vlc_playlist_item_Release(item
);
38 vlc_vector_clear(&playlist
->items
);
42 vlc_playlist_ItemsReset(vlc_playlist_t
*playlist
)
44 if (playlist
->order
== VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
)
45 randomizer_Clear(&playlist
->randomizer
);
47 struct vlc_playlist_state state
;
48 vlc_playlist_state_Save(playlist
, &state
);
50 playlist
->current
= -1;
51 playlist
->has_prev
= vlc_playlist_ComputeHasPrev(playlist
);
52 playlist
->has_next
= vlc_playlist_ComputeHasNext(playlist
);
54 vlc_playlist_Notify(playlist
, on_items_reset
, playlist
->items
.data
,
55 playlist
->items
.size
);
56 vlc_playlist_state_NotifyChanges(playlist
, &state
);
60 vlc_playlist_ItemsInserted(vlc_playlist_t
*playlist
, size_t index
, size_t count
)
62 if (playlist
->order
== VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
)
63 randomizer_Add(&playlist
->randomizer
,
64 &playlist
->items
.data
[index
], count
);
66 struct vlc_playlist_state state
;
67 vlc_playlist_state_Save(playlist
, &state
);
69 if (playlist
->current
>= (ssize_t
) index
)
70 playlist
->current
+= count
;
71 playlist
->has_prev
= vlc_playlist_ComputeHasPrev(playlist
);
72 playlist
->has_next
= vlc_playlist_ComputeHasNext(playlist
);
74 vlc_playlist_item_t
**items
= &playlist
->items
.data
[index
];
75 vlc_playlist_Notify(playlist
, on_items_added
, index
, items
, count
);
76 vlc_playlist_state_NotifyChanges(playlist
, &state
);
80 vlc_playlist_ItemsMoved(vlc_playlist_t
*playlist
, size_t index
, size_t count
,
83 struct vlc_playlist_state state
;
84 vlc_playlist_state_Save(playlist
, &state
);
86 if (playlist
->current
!= -1) {
87 size_t current
= (size_t) playlist
->current
;
90 if (current
>= index
&& current
< index
+ count
)
91 /* current item belongs to the moved block */
92 playlist
->current
+= target
- index
;
93 else if (current
>= index
+ count
&& current
< target
+ count
)
94 /* current item was shifted backwards to the moved block */
95 playlist
->current
-= count
;
96 /* else the current item does not move */
100 if (current
>= index
&& current
< index
+ count
)
101 /* current item belongs to the moved block */
102 playlist
->current
-= index
- target
;
103 else if (current
>= target
&& current
< index
)
104 /* current item was shifted forward to the moved block */
105 playlist
->current
+= count
;
106 /* else the current item does not move */
110 playlist
->has_prev
= vlc_playlist_ComputeHasPrev(playlist
);
111 playlist
->has_next
= vlc_playlist_ComputeHasNext(playlist
);
113 vlc_playlist_Notify(playlist
, on_items_moved
, index
, count
, target
);
114 vlc_playlist_state_NotifyChanges(playlist
, &state
);
118 vlc_playlist_ItemsRemoving(vlc_playlist_t
*playlist
, size_t index
, size_t count
)
120 if (playlist
->order
== VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
)
121 randomizer_Remove(&playlist
->randomizer
,
122 &playlist
->items
.data
[index
], count
);
125 /* return whether the current media has changed */
127 vlc_playlist_ItemsRemoved(vlc_playlist_t
*playlist
, size_t index
, size_t count
)
129 struct vlc_playlist_state state
;
130 vlc_playlist_state_Save(playlist
, &state
);
132 bool current_media_changed
= false;
133 if (playlist
->current
!= -1) {
134 size_t current
= (size_t) playlist
->current
;
135 if (current
>= index
&& current
< index
+ count
) {
136 /* current item has been removed */
137 if (index
+ count
< playlist
->items
.size
) {
138 /* select the first item after the removed block */
139 playlist
->current
= index
;
142 playlist
->current
= -1;
144 current_media_changed
= true;
145 } else if (current
>= index
+ count
) {
146 playlist
->current
-= count
;
149 playlist
->has_prev
= vlc_playlist_ComputeHasPrev(playlist
);
150 playlist
->has_next
= vlc_playlist_ComputeHasNext(playlist
);
152 vlc_playlist_Notify(playlist
, on_items_removed
, index
, count
);
153 vlc_playlist_state_NotifyChanges(playlist
, &state
);
155 return current_media_changed
;
159 vlc_playlist_ItemReplaced(vlc_playlist_t
*playlist
, size_t index
)
161 struct vlc_playlist_state state
;
162 vlc_playlist_state_Save(playlist
, &state
);
164 playlist
->has_prev
= vlc_playlist_ComputeHasPrev(playlist
);
165 playlist
->has_next
= vlc_playlist_ComputeHasNext(playlist
);
167 vlc_playlist_Notify(playlist
, on_items_updated
, index
,
168 &playlist
->items
.data
[index
], 1);
169 vlc_playlist_state_NotifyChanges(playlist
, &state
);
173 vlc_playlist_Count(vlc_playlist_t
*playlist
)
175 vlc_playlist_AssertLocked(playlist
);
176 return playlist
->items
.size
;
179 vlc_playlist_item_t
*
180 vlc_playlist_Get(vlc_playlist_t
*playlist
, size_t index
)
182 vlc_playlist_AssertLocked(playlist
);
183 return playlist
->items
.data
[index
];
187 vlc_playlist_IndexOf(vlc_playlist_t
*playlist
, const vlc_playlist_item_t
*item
)
189 vlc_playlist_AssertLocked(playlist
);
192 vlc_vector_index_of(&playlist
->items
, item
, &index
);
197 vlc_playlist_IndexOfMedia(vlc_playlist_t
*playlist
, const input_item_t
*media
)
199 vlc_playlist_AssertLocked(playlist
);
201 playlist_item_vector_t
*items
= &playlist
->items
;
202 for (size_t i
= 0; i
< items
->size
; ++i
)
203 if (items
->data
[i
]->media
== media
)
209 vlc_playlist_Clear(vlc_playlist_t
*playlist
)
211 vlc_playlist_AssertLocked(playlist
);
213 int ret
= vlc_player_SetCurrentMedia(playlist
->player
, NULL
);
214 VLC_UNUSED(ret
); /* what could we do? */
216 vlc_playlist_ClearItems(playlist
);
217 vlc_playlist_ItemsReset(playlist
);
221 vlc_playlist_MediaToItems(input_item_t
*const media
[], size_t count
,
222 vlc_playlist_item_t
*items
[])
225 for (i
= 0; i
< count
; ++i
)
227 items
[i
] = vlc_playlist_item_New(media
[i
]);
228 if (unlikely(!items
[i
]))
233 /* allocation failure, release partial items */
235 vlc_playlist_item_Release(items
[--i
]);
242 vlc_playlist_Insert(vlc_playlist_t
*playlist
, size_t index
,
243 input_item_t
*const media
[], size_t count
)
245 vlc_playlist_AssertLocked(playlist
);
246 assert(index
<= playlist
->items
.size
);
248 /* make space in the vector */
249 if (!vlc_vector_insert_hole(&playlist
->items
, index
, count
))
252 /* create playlist items in place */
253 int ret
= vlc_playlist_MediaToItems(media
, count
,
254 &playlist
->items
.data
[index
]);
255 if (ret
!= VLC_SUCCESS
)
257 /* we were optimistic, it failed, restore the vector state */
258 vlc_vector_remove_slice(&playlist
->items
, index
, count
);
262 vlc_playlist_ItemsInserted(playlist
, index
, count
);
263 vlc_player_InvalidateNextMedia(playlist
->player
);
269 vlc_playlist_Move(vlc_playlist_t
*playlist
, size_t index
, size_t count
,
272 vlc_playlist_AssertLocked(playlist
);
273 assert(index
+ count
<= playlist
->items
.size
);
274 assert(target
+ count
<= playlist
->items
.size
);
276 vlc_vector_move_slice(&playlist
->items
, index
, count
, target
);
278 vlc_playlist_ItemsMoved(playlist
, index
, count
, target
);
279 vlc_player_InvalidateNextMedia(playlist
->player
);
283 vlc_playlist_Remove(vlc_playlist_t
*playlist
, size_t index
, size_t count
)
285 vlc_playlist_AssertLocked(playlist
);
286 assert(index
< playlist
->items
.size
);
288 vlc_playlist_ItemsRemoving(playlist
, index
, count
);
290 for (size_t i
= 0; i
< count
; ++i
)
291 vlc_playlist_item_Release(playlist
->items
.data
[index
+ i
]);
293 vlc_vector_remove_slice(&playlist
->items
, index
, count
);
295 bool current_media_changed
= vlc_playlist_ItemsRemoved(playlist
, index
,
297 if (current_media_changed
)
298 vlc_playlist_SetCurrentMedia(playlist
, playlist
->current
);
300 vlc_player_InvalidateNextMedia(playlist
->player
);
304 vlc_playlist_Replace(vlc_playlist_t
*playlist
, size_t index
,
307 vlc_playlist_AssertLocked(playlist
);
308 assert(index
< playlist
->items
.size
);
310 vlc_playlist_item_t
*item
= vlc_playlist_item_New(media
);
314 if (playlist
->order
== VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
)
316 randomizer_Remove(&playlist
->randomizer
,
317 &playlist
->items
.data
[index
], 1);
318 randomizer_Add(&playlist
->randomizer
, &item
, 1);
321 vlc_playlist_item_Release(playlist
->items
.data
[index
]);
322 playlist
->items
.data
[index
] = item
;
324 vlc_playlist_ItemReplaced(playlist
, index
);
329 vlc_playlist_Expand(vlc_playlist_t
*playlist
, size_t index
,
330 input_item_t
*const media
[], size_t count
)
332 vlc_playlist_AssertLocked(playlist
);
333 assert(index
< playlist
->items
.size
);
336 vlc_playlist_RemoveOne(playlist
, index
);
339 int ret
= vlc_playlist_Replace(playlist
, index
, media
[0]);
340 if (ret
!= VLC_SUCCESS
)
345 /* make space in the vector */
346 if (!vlc_vector_insert_hole(&playlist
->items
, index
+ 1, count
- 1))
349 /* create playlist items in place */
350 ret
= vlc_playlist_MediaToItems(&media
[1], count
- 1,
351 &playlist
->items
.data
[index
+ 1]);
352 if (ret
!= VLC_SUCCESS
)
354 /* we were optimistic, it failed, restore the vector state */
355 vlc_vector_remove_slice(&playlist
->items
, index
+ 1, count
- 1);
358 vlc_playlist_ItemsInserted(playlist
, index
+ 1, count
- 1);
361 if ((ssize_t
) index
== playlist
->current
)
362 vlc_playlist_SetCurrentMedia(playlist
, playlist
->current
);
364 vlc_player_InvalidateNextMedia(playlist
->player
);