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 *****************************************************************************/
34 vlc_playlist_ClearItems(vlc_playlist_t
*playlist
)
36 vlc_playlist_item_t
*item
;
37 vlc_vector_foreach(item
, &playlist
->items
)
38 vlc_playlist_item_Release(item
);
39 vlc_vector_clear(&playlist
->items
);
43 vlc_playlist_ItemsReset(vlc_playlist_t
*playlist
)
45 if (playlist
->order
== VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
)
46 randomizer_Clear(&playlist
->randomizer
);
48 struct vlc_playlist_state state
;
49 vlc_playlist_state_Save(playlist
, &state
);
51 playlist
->current
= -1;
52 playlist
->has_prev
= vlc_playlist_ComputeHasPrev(playlist
);
53 playlist
->has_next
= vlc_playlist_ComputeHasNext(playlist
);
55 vlc_playlist_Notify(playlist
, on_items_reset
, playlist
->items
.data
,
56 playlist
->items
.size
);
57 vlc_playlist_state_NotifyChanges(playlist
, &state
);
61 vlc_playlist_ItemsInserted(vlc_playlist_t
*playlist
, size_t index
, size_t count
)
63 if (playlist
->order
== VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
)
64 randomizer_Add(&playlist
->randomizer
,
65 &playlist
->items
.data
[index
], count
);
67 struct vlc_playlist_state state
;
68 vlc_playlist_state_Save(playlist
, &state
);
70 if (playlist
->current
>= (ssize_t
) index
)
71 playlist
->current
+= count
;
72 playlist
->has_prev
= vlc_playlist_ComputeHasPrev(playlist
);
73 playlist
->has_next
= vlc_playlist_ComputeHasNext(playlist
);
75 vlc_playlist_item_t
**items
= &playlist
->items
.data
[index
];
76 vlc_playlist_Notify(playlist
, on_items_added
, index
, items
, count
);
77 vlc_playlist_state_NotifyChanges(playlist
, &state
);
79 for (size_t i
= index
; i
< index
+ count
; ++i
)
81 vlc_playlist_item_t
*item
= playlist
->items
.data
[i
];
82 vlc_playlist_AutoPreparse(playlist
, item
->media
);
87 vlc_playlist_ItemsMoved(vlc_playlist_t
*playlist
, size_t index
, size_t count
,
90 struct vlc_playlist_state state
;
91 vlc_playlist_state_Save(playlist
, &state
);
93 if (playlist
->current
!= -1) {
94 size_t current
= (size_t) playlist
->current
;
97 if (current
>= index
&& current
< index
+ count
)
98 /* current item belongs to the moved block */
99 playlist
->current
+= target
- index
;
100 else if (current
>= index
+ count
&& current
< target
+ count
)
101 /* current item was shifted backwards to the moved block */
102 playlist
->current
-= count
;
103 /* else the current item does not move */
107 if (current
>= index
&& current
< index
+ count
)
108 /* current item belongs to the moved block */
109 playlist
->current
-= index
- target
;
110 else if (current
>= target
&& current
< index
)
111 /* current item was shifted forward to the moved block */
112 playlist
->current
+= count
;
113 /* else the current item does not move */
117 playlist
->has_prev
= vlc_playlist_ComputeHasPrev(playlist
);
118 playlist
->has_next
= vlc_playlist_ComputeHasNext(playlist
);
120 vlc_playlist_Notify(playlist
, on_items_moved
, index
, count
, target
);
121 vlc_playlist_state_NotifyChanges(playlist
, &state
);
125 vlc_playlist_ItemsRemoving(vlc_playlist_t
*playlist
, size_t index
, size_t count
)
127 if (playlist
->order
== VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
)
128 randomizer_Remove(&playlist
->randomizer
,
129 &playlist
->items
.data
[index
], count
);
132 /* return whether the current media has changed */
134 vlc_playlist_ItemsRemoved(vlc_playlist_t
*playlist
, size_t index
, size_t count
)
136 struct vlc_playlist_state state
;
137 vlc_playlist_state_Save(playlist
, &state
);
139 bool current_media_changed
= false;
140 if (playlist
->current
!= -1) {
141 size_t current
= (size_t) playlist
->current
;
142 if (current
>= index
&& current
< index
+ count
) {
143 /* current item has been removed */
144 if (index
+ count
< playlist
->items
.size
) {
145 /* select the first item after the removed block */
146 playlist
->current
= index
;
149 playlist
->current
= -1;
151 current_media_changed
= true;
152 } else if (current
>= index
+ count
) {
153 playlist
->current
-= count
;
156 playlist
->has_prev
= vlc_playlist_ComputeHasPrev(playlist
);
157 playlist
->has_next
= vlc_playlist_ComputeHasNext(playlist
);
159 vlc_playlist_Notify(playlist
, on_items_removed
, index
, count
);
160 vlc_playlist_state_NotifyChanges(playlist
, &state
);
162 return current_media_changed
;
166 vlc_playlist_ItemReplaced(vlc_playlist_t
*playlist
, size_t index
)
168 struct vlc_playlist_state state
;
169 vlc_playlist_state_Save(playlist
, &state
);
171 playlist
->has_prev
= vlc_playlist_ComputeHasPrev(playlist
);
172 playlist
->has_next
= vlc_playlist_ComputeHasNext(playlist
);
174 vlc_playlist_Notify(playlist
, on_items_updated
, index
,
175 &playlist
->items
.data
[index
], 1);
176 vlc_playlist_state_NotifyChanges(playlist
, &state
);
178 vlc_playlist_AutoPreparse(playlist
, playlist
->items
.data
[index
]->media
);
182 vlc_playlist_Count(vlc_playlist_t
*playlist
)
184 vlc_playlist_AssertLocked(playlist
);
185 return playlist
->items
.size
;
188 vlc_playlist_item_t
*
189 vlc_playlist_Get(vlc_playlist_t
*playlist
, size_t index
)
191 vlc_playlist_AssertLocked(playlist
);
192 return playlist
->items
.data
[index
];
196 vlc_playlist_IndexOf(vlc_playlist_t
*playlist
, const vlc_playlist_item_t
*item
)
198 vlc_playlist_AssertLocked(playlist
);
201 vlc_vector_index_of(&playlist
->items
, item
, &index
);
206 vlc_playlist_IndexOfMedia(vlc_playlist_t
*playlist
, const input_item_t
*media
)
208 vlc_playlist_AssertLocked(playlist
);
210 playlist_item_vector_t
*items
= &playlist
->items
;
211 for (size_t i
= 0; i
< items
->size
; ++i
)
212 if (items
->data
[i
]->media
== media
)
218 vlc_playlist_IndexOfId(vlc_playlist_t
*playlist
, uint64_t id
)
220 vlc_playlist_AssertLocked(playlist
);
222 playlist_item_vector_t
*items
= &playlist
->items
;
223 for (size_t i
= 0; i
< items
->size
; ++i
)
224 if (items
->data
[i
]->id
== id
)
230 vlc_playlist_Clear(vlc_playlist_t
*playlist
)
232 vlc_playlist_AssertLocked(playlist
);
234 int ret
= vlc_player_SetCurrentMedia(playlist
->player
, NULL
);
235 VLC_UNUSED(ret
); /* what could we do? */
237 vlc_playlist_ClearItems(playlist
);
238 vlc_playlist_ItemsReset(playlist
);
242 vlc_playlist_MediaToItems(vlc_playlist_t
*playlist
, input_item_t
*const media
[],
243 size_t count
, vlc_playlist_item_t
*items
[])
245 vlc_playlist_AssertLocked(playlist
);
247 for (i
= 0; i
< count
; ++i
)
249 uint64_t id
= playlist
->idgen
++;
250 items
[i
] = vlc_playlist_item_New(media
[i
], id
);
251 if (unlikely(!items
[i
]))
256 /* allocation failure, release partial items */
258 vlc_playlist_item_Release(items
[--i
]);
265 vlc_playlist_Insert(vlc_playlist_t
*playlist
, size_t index
,
266 input_item_t
*const media
[], size_t count
)
268 vlc_playlist_AssertLocked(playlist
);
269 assert(index
<= playlist
->items
.size
);
271 /* make space in the vector */
272 if (!vlc_vector_insert_hole(&playlist
->items
, index
, count
))
275 /* create playlist items in place */
276 int ret
= vlc_playlist_MediaToItems(playlist
, media
, count
,
277 &playlist
->items
.data
[index
]);
278 if (ret
!= VLC_SUCCESS
)
280 /* we were optimistic, it failed, restore the vector state */
281 vlc_vector_remove_slice(&playlist
->items
, index
, count
);
285 vlc_playlist_ItemsInserted(playlist
, index
, count
);
286 vlc_player_InvalidateNextMedia(playlist
->player
);
292 vlc_playlist_Move(vlc_playlist_t
*playlist
, size_t index
, size_t count
,
295 vlc_playlist_AssertLocked(playlist
);
296 assert(index
+ count
<= playlist
->items
.size
);
297 assert(target
+ count
<= playlist
->items
.size
);
299 vlc_vector_move_slice(&playlist
->items
, index
, count
, target
);
301 vlc_playlist_ItemsMoved(playlist
, index
, count
, target
);
302 vlc_player_InvalidateNextMedia(playlist
->player
);
306 vlc_playlist_Remove(vlc_playlist_t
*playlist
, size_t index
, size_t count
)
308 vlc_playlist_AssertLocked(playlist
);
309 assert(index
< playlist
->items
.size
);
311 vlc_playlist_ItemsRemoving(playlist
, index
, count
);
313 for (size_t i
= 0; i
< count
; ++i
)
314 vlc_playlist_item_Release(playlist
->items
.data
[index
+ i
]);
316 vlc_vector_remove_slice(&playlist
->items
, index
, count
);
318 bool current_media_changed
= vlc_playlist_ItemsRemoved(playlist
, index
,
320 if (current_media_changed
)
321 vlc_playlist_SetCurrentMedia(playlist
, playlist
->current
);
323 vlc_player_InvalidateNextMedia(playlist
->player
);
327 vlc_playlist_Replace(vlc_playlist_t
*playlist
, size_t index
,
330 vlc_playlist_AssertLocked(playlist
);
331 assert(index
< playlist
->items
.size
);
333 uint64_t id
= playlist
->idgen
++;
334 vlc_playlist_item_t
*item
= vlc_playlist_item_New(media
, id
);
338 if (playlist
->order
== VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
)
340 randomizer_Remove(&playlist
->randomizer
,
341 &playlist
->items
.data
[index
], 1);
342 randomizer_Add(&playlist
->randomizer
, &item
, 1);
345 vlc_playlist_item_Release(playlist
->items
.data
[index
]);
346 playlist
->items
.data
[index
] = item
;
348 vlc_playlist_ItemReplaced(playlist
, index
);
353 vlc_playlist_Expand(vlc_playlist_t
*playlist
, size_t index
,
354 input_item_t
*const media
[], size_t count
)
356 vlc_playlist_AssertLocked(playlist
);
357 assert(index
< playlist
->items
.size
);
360 vlc_playlist_RemoveOne(playlist
, index
);
363 int ret
= vlc_playlist_Replace(playlist
, index
, media
[0]);
364 if (ret
!= VLC_SUCCESS
)
369 /* make space in the vector */
370 if (!vlc_vector_insert_hole(&playlist
->items
, index
+ 1, count
- 1))
373 /* create playlist items in place */
374 ret
= vlc_playlist_MediaToItems(playlist
, &media
[1], count
- 1,
375 &playlist
->items
.data
[index
+ 1]);
376 if (ret
!= VLC_SUCCESS
)
378 /* we were optimistic, it failed, restore the vector state */
379 vlc_vector_remove_slice(&playlist
->items
, index
+ 1, count
- 1);
382 vlc_playlist_ItemsInserted(playlist
, index
+ 1, count
- 1);
385 if ((ssize_t
) index
== playlist
->current
)
386 vlc_playlist_SetCurrentMedia(playlist
, playlist
->current
);
388 vlc_player_InvalidateNextMedia(playlist
->player
);