mirror of https://code.videolan.org/videolan/vlc
855 lines
24 KiB
C++
855 lines
24 KiB
C++
/*****************************************************************************
|
|
* Copyright (C) 2019 VLC authors and VideoLAN
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* ( at your option ) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
*****************************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "playlist_controller.hpp"
|
|
#include "playlist_controller_p.hpp"
|
|
#include <vlc_player.h>
|
|
#include <vlc_url.h>
|
|
#include "util/shared_input_item.hpp"
|
|
#include <algorithm>
|
|
#include <QVariant>
|
|
#include <QDesktopServices>
|
|
|
|
namespace vlc {
|
|
namespace playlist {
|
|
|
|
static QVector<PlaylistItem> toVec(vlc_playlist_item_t *const items[],
|
|
size_t len)
|
|
{
|
|
QVector<PlaylistItem> vec;
|
|
for (size_t i = 0; i < len; ++i)
|
|
vec.push_back(items[i]);
|
|
return vec;
|
|
}
|
|
|
|
template <typename RAW, typename WRAPPER>
|
|
static QVector<RAW> toRaw(const QVector<WRAPPER> &items)
|
|
{
|
|
QVector<RAW> vec;
|
|
int count = items.size();
|
|
vec.reserve(count);
|
|
for (int i = 0; i < count; ++i)
|
|
vec.push_back(items[i].raw());
|
|
return vec;
|
|
}
|
|
|
|
static QUrl resolveWinSymlinks(const QUrl &mrl)
|
|
{
|
|
#ifdef _WIN32
|
|
QFileInfo info (mrl.toLocalFile());
|
|
if ( info.isSymLink() )
|
|
{
|
|
QString target = info.symLinkTarget();
|
|
return QFile::exists(target) ? QUrl::fromLocalFile(target) : mrl;
|
|
}
|
|
#endif
|
|
return mrl;
|
|
}
|
|
|
|
QVector<Media> toMediaList(const QVariantList &sources)
|
|
{
|
|
QVector<Media> mediaList;
|
|
std::transform(sources.begin(), sources.end(),
|
|
std::back_inserter(mediaList), [](const QVariant& value) {
|
|
if (value.canConvert<QUrl>() || value.canConvert<QString>())
|
|
{
|
|
QUrl mrl = value.canConvert<QString>()
|
|
? QUrl::fromUserInput(value.value<QString>())
|
|
: value.value<QUrl>();
|
|
|
|
if (mrl.isLocalFile())
|
|
mrl = resolveWinSymlinks(mrl);
|
|
|
|
return Media(mrl.toString(QUrl::FullyEncoded), mrl.fileName());
|
|
} else if (value.canConvert<SharedInputItem>())
|
|
{
|
|
return Media(value.value<SharedInputItem>().get());
|
|
}
|
|
return Media{};
|
|
});
|
|
|
|
return mediaList;
|
|
}
|
|
|
|
|
|
extern "C" { // for C callbacks
|
|
|
|
static void
|
|
on_playlist_items_reset(vlc_playlist_t *playlist,
|
|
vlc_playlist_item_t *const items[],
|
|
size_t len, void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
auto vec = toVec(items, len);
|
|
size_t totalCount = vlc_playlist_Count(playlist);
|
|
|
|
that->callAsync([=](){
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
PlaylistController* q = that->q_func();
|
|
bool empty = vec.size() == 0;
|
|
if (that->m_empty != empty)
|
|
{
|
|
that->m_empty = empty;
|
|
emit q->isEmptyChanged(empty);
|
|
}
|
|
emit q->itemsReset(vec);
|
|
|
|
if (totalCount != that->m_count)
|
|
{
|
|
that->m_count = totalCount;
|
|
emit q->countChanged(totalCount);
|
|
}
|
|
});
|
|
}
|
|
|
|
static void
|
|
on_playlist_items_added(vlc_playlist_t *playlist, size_t index,
|
|
vlc_playlist_item_t *const items[], size_t len,
|
|
void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
auto vec = toVec(items, len);
|
|
size_t totalCount = vlc_playlist_Count(playlist);
|
|
that->callAsync([=](){
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
PlaylistController* q = that->q_func();
|
|
if (that->m_empty && vec.size() > 0)
|
|
{
|
|
that->m_empty = false;
|
|
emit q->isEmptyChanged(that->m_empty);
|
|
}
|
|
emit q->itemsAdded(index, vec);
|
|
|
|
if (totalCount != that->m_count)
|
|
{
|
|
that->m_count = totalCount;
|
|
emit q->countChanged(totalCount);
|
|
}
|
|
});
|
|
}
|
|
|
|
static void
|
|
on_playlist_items_moved(vlc_playlist_t *playlist, size_t index, size_t count,
|
|
size_t target, void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
that->callAsync([=](){
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
emit that->q_func()->itemsMoved(index, count, target);
|
|
});
|
|
}
|
|
|
|
static void
|
|
on_playlist_items_removed(vlc_playlist_t *playlist, size_t index, size_t count,
|
|
void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
size_t totalCount = vlc_playlist_Count(playlist);
|
|
bool empty = (totalCount == 0);
|
|
that->callAsync([=](){
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
PlaylistController* q = that->q_func();
|
|
if (that->m_empty != empty)
|
|
{
|
|
that->m_empty = empty;
|
|
emit q->isEmptyChanged(empty);
|
|
}
|
|
emit q->itemsRemoved(index, count);
|
|
if (totalCount != that->m_count)
|
|
{
|
|
that->m_count = totalCount;
|
|
emit q->countChanged(totalCount);
|
|
}
|
|
});
|
|
}
|
|
|
|
static void
|
|
on_playlist_items_updated(vlc_playlist_t *playlist, size_t index,
|
|
vlc_playlist_item_t *const items[], size_t len,
|
|
void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
auto vec = toVec(items, len);
|
|
that->callAsync([=](){
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
emit that->q_func()->itemsUpdated(index, vec);
|
|
if (that->m_currentIndex != -1) {
|
|
size_t currentIndex = static_cast<size_t>(that->m_currentIndex);
|
|
if (currentIndex >= index && currentIndex < index + len)
|
|
{
|
|
that->m_currentItem = vec[currentIndex - index];
|
|
emit that->q_func()->currentItemChanged();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
static void
|
|
on_playlist_playback_repeat_changed(vlc_playlist_t *playlist,
|
|
enum vlc_playlist_playback_repeat repeat,
|
|
void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
that->callAsync([=](){
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
PlaylistController::PlaybackRepeat repeatMode = static_cast<PlaylistController::PlaybackRepeat>(repeat);
|
|
if (that->m_repeat != repeatMode )
|
|
{
|
|
that->m_repeat = repeatMode;
|
|
emit that->q_func()->repeatModeChanged(repeatMode);
|
|
}
|
|
});
|
|
}
|
|
|
|
static void
|
|
on_playlist_playback_order_changed(vlc_playlist_t *playlist,
|
|
enum vlc_playlist_playback_order order,
|
|
void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
that->callAsync([=](){
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
bool isRandom = order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM;
|
|
if (that->m_random != isRandom)
|
|
{
|
|
that->m_random = isRandom;
|
|
emit that->q_func()->randomChanged(isRandom);
|
|
}
|
|
});
|
|
}
|
|
|
|
static void
|
|
on_playlist_current_item_changed(vlc_playlist_t *playlist, ssize_t index,
|
|
void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
|
|
|
|
vlc_playlist_item_t* playlistItem = nullptr;
|
|
if (index >= 0)
|
|
playlistItem = vlc_playlist_Get(playlist, index);
|
|
PlaylistItem newItem{ playlistItem };
|
|
|
|
that->callAsync([=](){
|
|
PlaylistController* q = that->q_func();
|
|
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
if (that->m_currentIndex != index)
|
|
{
|
|
that->m_currentIndex = index;
|
|
emit q->currentIndexChanged(that->m_currentIndex);
|
|
}
|
|
that->m_currentItem = newItem;
|
|
emit q->currentItemChanged();
|
|
});
|
|
}
|
|
|
|
static void
|
|
on_playlist_has_prev_changed(vlc_playlist_t *playlist, bool has_prev,
|
|
void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
that->callAsync([=](){
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
if (that->m_hasPrev != has_prev)
|
|
{
|
|
that->m_hasPrev = has_prev;
|
|
emit that->q_func()->hasPrevChanged(has_prev);
|
|
}
|
|
});
|
|
}
|
|
|
|
static void
|
|
on_playlist_has_next_changed(vlc_playlist_t *playlist, bool has_next,
|
|
void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
that->callAsync([=](){
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
if (that->m_hasNext != has_next)
|
|
{
|
|
that->m_hasNext = has_next;
|
|
emit that->q_func()->hasNextChanged(has_next);
|
|
}
|
|
});
|
|
}
|
|
|
|
static void
|
|
on_media_stopped_action_changed(vlc_playlist_t *playlist,
|
|
enum vlc_playlist_media_stopped_action new_action,
|
|
void *userdata)
|
|
{
|
|
PlaylistControllerPrivate *that = static_cast<PlaylistControllerPrivate *>(userdata);
|
|
that->callAsync([=](){
|
|
auto action = static_cast<PlaylistController::MediaStopAction>(new_action);
|
|
if (that->m_playlist != playlist)
|
|
return;
|
|
if (that->m_mediaStopAction == action)
|
|
return;
|
|
that->m_mediaStopAction = action;
|
|
emit that->q_func()->mediaStopActionChanged(action);
|
|
});
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
static const struct vlc_playlist_callbacks playlist_callbacks = []{
|
|
struct vlc_playlist_callbacks cbs {};
|
|
cbs.on_items_reset = on_playlist_items_reset;
|
|
cbs.on_items_added = on_playlist_items_added;
|
|
cbs.on_items_moved = on_playlist_items_moved;
|
|
cbs.on_items_removed = on_playlist_items_removed;
|
|
cbs.on_items_updated = on_playlist_items_updated;
|
|
cbs.on_playback_repeat_changed = on_playlist_playback_repeat_changed;
|
|
cbs.on_playback_order_changed= on_playlist_playback_order_changed;
|
|
cbs.on_current_index_changed = on_playlist_current_item_changed;
|
|
cbs.on_has_next_changed = on_playlist_has_next_changed;
|
|
cbs.on_has_prev_changed = on_playlist_has_prev_changed;
|
|
cbs.on_media_stopped_action_changed = on_media_stopped_action_changed;
|
|
return cbs;
|
|
}();
|
|
|
|
|
|
//private API
|
|
|
|
PlaylistControllerPrivate::PlaylistControllerPrivate(PlaylistController* playlistController)
|
|
: q_ptr(playlistController)
|
|
{
|
|
fillSortKeyTitleList();
|
|
}
|
|
|
|
PlaylistControllerPrivate::~PlaylistControllerPrivate()
|
|
{
|
|
if (m_playlist && m_listener)
|
|
{
|
|
vlc_playlist_locker lock(m_playlist);
|
|
vlc_playlist_RemoveListener(m_playlist, m_listener);
|
|
}
|
|
}
|
|
|
|
//public API
|
|
|
|
PlaylistController::PlaylistController(QObject *parent)
|
|
: QObject(parent)
|
|
, d_ptr( new PlaylistControllerPrivate(this) )
|
|
{
|
|
connect(this, &PlaylistController::itemsMoved, this, &PlaylistController::resetSortKey);
|
|
connect(this, &PlaylistController::itemsAdded, this, &PlaylistController::resetSortKey);
|
|
connect(this, &PlaylistController::isEmptyChanged, [this](bool isEmpty) {if (isEmpty) emit resetSortKey();});
|
|
}
|
|
|
|
PlaylistController::PlaylistController(vlc_playlist_t *playlist, QObject *parent)
|
|
: QObject(parent)
|
|
, d_ptr( new PlaylistControllerPrivate(this) )
|
|
{
|
|
setPlaylist(playlist);
|
|
}
|
|
|
|
PlaylistController::~PlaylistController()
|
|
{
|
|
}
|
|
|
|
PlaylistItem PlaylistController::getCurrentItem() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return d->m_currentItem;
|
|
}
|
|
|
|
void PlaylistController::append(const QVariantList& sourceList, bool startPlaying)
|
|
{
|
|
append(toMediaList(sourceList), startPlaying);
|
|
}
|
|
|
|
void PlaylistController::insert(unsigned index, const QVariantList& sourceList, bool startPlaying)
|
|
{
|
|
insert(index, toMediaList(sourceList), startPlaying);
|
|
}
|
|
|
|
void
|
|
PlaylistController::append(const QVector<Media> &media, bool startPlaying)
|
|
{
|
|
Q_D(PlaylistController);
|
|
|
|
vlc_playlist_locker locker(d->m_playlist);
|
|
|
|
auto rawMedia = toRaw<input_item_t *>(media);
|
|
/* We can't append an empty media. */
|
|
assert(rawMedia.size() > 0);
|
|
|
|
int ret = vlc_playlist_Append(d->m_playlist,
|
|
rawMedia.constData(), rawMedia.size());
|
|
if (ret != VLC_SUCCESS)
|
|
throw std::bad_alloc();
|
|
if (startPlaying)
|
|
{
|
|
ssize_t playIndex = (ssize_t)vlc_playlist_Count( d->m_playlist ) - rawMedia.size();
|
|
ret = vlc_playlist_GoTo(d->m_playlist, playIndex);
|
|
if (ret != VLC_SUCCESS)
|
|
return;
|
|
vlc_playlist_Start(d->m_playlist);
|
|
}
|
|
}
|
|
|
|
void
|
|
PlaylistController::insert(size_t index, const QVector<Media> &media, bool startPlaying)
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker locker(d->m_playlist);
|
|
|
|
auto rawMedia = toRaw<input_item_t *>(media);
|
|
/* We can't insert an empty media. */
|
|
assert(rawMedia.size() > 0);
|
|
|
|
int ret = vlc_playlist_RequestInsert(d->m_playlist, index,
|
|
rawMedia.constData(), rawMedia.size());
|
|
if (ret != VLC_SUCCESS)
|
|
throw std::bad_alloc();
|
|
if (startPlaying)
|
|
{
|
|
ret = vlc_playlist_GoTo(d->m_playlist, index);
|
|
if (ret != VLC_SUCCESS)
|
|
return;
|
|
vlc_playlist_Start(d->m_playlist);
|
|
}
|
|
}
|
|
|
|
void
|
|
PlaylistController::move(const QVector<PlaylistItem> &items, size_t target,
|
|
ssize_t indexHint)
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker locker(d->m_playlist);
|
|
|
|
auto rawItems = toRaw<vlc_playlist_item_t *>(items);
|
|
int ret = vlc_playlist_RequestMove(d->m_playlist, rawItems.constData(),
|
|
rawItems.size(), target, indexHint);
|
|
if (ret != VLC_SUCCESS)
|
|
throw std::bad_alloc();
|
|
}
|
|
|
|
void
|
|
PlaylistController::remove(const QVector<PlaylistItem> &items, ssize_t indexHint)
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker locker(d->m_playlist);
|
|
auto rawItems = toRaw<vlc_playlist_item_t *>(items);
|
|
int ret = vlc_playlist_RequestRemove(d->m_playlist, rawItems.constData(),
|
|
rawItems.size(), indexHint);
|
|
if (ret != VLC_SUCCESS)
|
|
throw std::bad_alloc();
|
|
}
|
|
|
|
void
|
|
PlaylistController::shuffle()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker locker(d->m_playlist);
|
|
vlc_playlist_Shuffle(d->m_playlist);
|
|
}
|
|
|
|
void
|
|
PlaylistController::sort(const QVector<vlc_playlist_sort_criterion> &criteria)
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker locker(d->m_playlist);
|
|
vlc_playlist_Sort(d->m_playlist, criteria.constData(), criteria.size());
|
|
}
|
|
|
|
void PlaylistController::sort(PlaylistController::SortKey key, PlaylistController::SortOrder order)
|
|
{
|
|
if(key != SortKey::SORT_KEY_NONE)
|
|
setSortKey(key);
|
|
setSortOrder(order);
|
|
|
|
sort();
|
|
}
|
|
|
|
void PlaylistController::sort(PlaylistController::SortKey key)
|
|
{
|
|
if (key == SortKey::SORT_KEY_NONE)
|
|
return;
|
|
|
|
if (getSortKey() != key)
|
|
{
|
|
setSortOrder(SortOrder::SORT_ORDER_ASC);
|
|
setSortKey(key);
|
|
}
|
|
else
|
|
{
|
|
switchSortOrder();
|
|
}
|
|
|
|
sort();
|
|
}
|
|
|
|
void PlaylistController::sort(void)
|
|
{
|
|
Q_D(PlaylistController);
|
|
|
|
if (d->m_sortKey == SortKey::SORT_KEY_NONE)
|
|
return;
|
|
|
|
vlc_playlist_sort_criterion crit = {
|
|
static_cast<vlc_playlist_sort_key>(d->m_sortKey),
|
|
static_cast<vlc_playlist_sort_order>(d->m_sortOrder)
|
|
};
|
|
QVector<vlc_playlist_sort_criterion> criteria { crit };
|
|
sort( criteria );
|
|
}
|
|
|
|
void PlaylistController::explore(const PlaylistItem& pItem)
|
|
{
|
|
vlc_playlist_item_t * const playlistItem = pItem.raw();
|
|
if( playlistItem )
|
|
{
|
|
input_item_t * const p_input = vlc_playlist_item_GetMedia(playlistItem);
|
|
auto uri = vlc::wrap_cptr( input_item_GetURI(p_input) );
|
|
|
|
if( uri && uri.get()[0] != '\0')
|
|
{
|
|
auto path = vlc::wrap_cptr( vlc_uri2path( uri.get() ) );
|
|
|
|
if( !path )
|
|
return;
|
|
|
|
QString containingDir = QFileInfo( path.get() ).absolutePath();
|
|
if( !QFileInfo( containingDir ).isDir() )
|
|
return;
|
|
|
|
QUrl file = QUrl::fromLocalFile( containingDir );
|
|
if( !file.isLocalFile() )
|
|
return;
|
|
|
|
QDesktopServices::openUrl( file );
|
|
}
|
|
}
|
|
}
|
|
|
|
int PlaylistController::currentIndex() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return d->m_currentIndex;
|
|
}
|
|
|
|
void PlaylistController::play()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_playlist_Start( d->m_playlist );
|
|
}
|
|
|
|
void PlaylistController::pause()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_playlist_Pause( d->m_playlist );
|
|
}
|
|
|
|
void PlaylistController::stop()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_playlist_Stop( d->m_playlist );
|
|
}
|
|
|
|
void PlaylistController::next()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_playlist_Next( d->m_playlist );
|
|
}
|
|
|
|
void PlaylistController::prev()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_playlist_Prev( d->m_playlist );
|
|
}
|
|
|
|
void PlaylistController::prevOrReset()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
bool seek = false;
|
|
vlc_player_t* player = vlc_playlist_GetPlayer( d->m_playlist );
|
|
Q_ASSERT(player);
|
|
if( !vlc_player_IsStarted(player) || vlc_player_GetTime(player) < VLC_TICK_FROM_MS(10) )
|
|
{
|
|
int ret = vlc_playlist_Prev( d->m_playlist );
|
|
if (ret == VLC_SUCCESS)
|
|
vlc_playlist_Start( d->m_playlist );
|
|
}
|
|
else
|
|
seek = true;
|
|
if (seek)
|
|
vlc_player_JumpPos( player, 0.f );
|
|
}
|
|
|
|
void PlaylistController::togglePlayPause()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_player_t* player = vlc_playlist_GetPlayer( d->m_playlist );
|
|
if ( vlc_player_IsStarted(player) )
|
|
vlc_player_TogglePause( player );
|
|
else
|
|
vlc_playlist_Start( d->m_playlist );
|
|
}
|
|
|
|
void PlaylistController::toggleRandom()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_playback_order new_order;
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
if ( d->m_random )
|
|
new_order = VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL;
|
|
else
|
|
new_order = VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM;
|
|
vlc_playlist_SetPlaybackOrder( d->m_playlist, new_order );
|
|
config_PutInt( "random", new_order );
|
|
}
|
|
|
|
void PlaylistController::toggleRepeatMode()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_playback_repeat new_repeat;
|
|
/* Toggle Normal -> Loop -> Repeat -> Normal ... */
|
|
switch ( d->m_repeat ) {
|
|
case PlaybackRepeat::PLAYBACK_REPEAT_NONE:
|
|
new_repeat = VLC_PLAYLIST_PLAYBACK_REPEAT_ALL;
|
|
break;
|
|
case PlaybackRepeat::PLAYBACK_REPEAT_ALL:
|
|
new_repeat = VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT;
|
|
break;
|
|
case PlaybackRepeat::PLAYBACK_REPEAT_CURRENT:
|
|
default:
|
|
new_repeat = VLC_PLAYLIST_PLAYBACK_REPEAT_NONE;
|
|
break;
|
|
}
|
|
{
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_playlist_SetPlaybackRepeat( d->m_playlist, new_repeat );
|
|
}
|
|
config_PutInt( "repeat", new_repeat );
|
|
}
|
|
|
|
void PlaylistController::clear()
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_playlist_Clear( d->m_playlist );
|
|
}
|
|
|
|
void PlaylistController::goTo(uint index, bool startPlaying)
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
size_t count = vlc_playlist_Count( d->m_playlist );
|
|
if (count == 0 || index > count-1)
|
|
return;
|
|
vlc_playlist_GoTo( d->m_playlist, index );
|
|
if (startPlaying)
|
|
vlc_playlist_Start( d->m_playlist );
|
|
}
|
|
|
|
bool PlaylistController::isRandom() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return d->m_random;
|
|
}
|
|
|
|
void PlaylistController::setRandom(bool random)
|
|
{
|
|
Q_D(const PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_playlist_SetPlaybackOrder( d->m_playlist, random ? VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM : VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL );
|
|
}
|
|
|
|
Playlist PlaylistController::getPlaylist() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return Playlist(d->m_playlist);
|
|
}
|
|
|
|
void PlaylistController::setPlaylist(vlc_playlist_t* newPlaylist)
|
|
{
|
|
Q_D(PlaylistController);
|
|
if (d->m_playlist && d->m_listener)
|
|
{
|
|
vlc_playlist_locker locker(d->m_playlist);
|
|
vlc_playlist_RemoveListener(d->m_playlist, d->m_listener);
|
|
d->m_playlist = nullptr;
|
|
d->m_listener = nullptr;
|
|
}
|
|
if (newPlaylist)
|
|
{
|
|
vlc_playlist_locker locker(newPlaylist);
|
|
d->m_playlist = newPlaylist;
|
|
d->m_listener = vlc_playlist_AddListener(d->m_playlist, &playlist_callbacks, d, true);
|
|
/*
|
|
* Queue a playlistInitialized to be sent after the initial state callbacks
|
|
* vlc_playlist_AddListener will synchronously call each callback in
|
|
* playlist_callbacks, which will in turn queue an async call on the Qt
|
|
* main thread
|
|
*/
|
|
d->callAsync([=](){
|
|
emit playlistInitialized();
|
|
});
|
|
}
|
|
emit playlistChanged( Playlist(newPlaylist) );
|
|
}
|
|
|
|
void PlaylistController::resetSortKey()
|
|
{
|
|
Q_D(PlaylistController);
|
|
d->m_sortKey = SortKey::SORT_KEY_NONE;
|
|
emit sortKeyChanged();
|
|
}
|
|
|
|
void PlaylistController::setPlaylist(const Playlist& playlist)
|
|
{
|
|
setPlaylist(playlist.m_playlist);
|
|
}
|
|
|
|
PlaylistController::PlaybackRepeat PlaylistController::getRepeatMode() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return d->m_repeat;
|
|
}
|
|
|
|
void PlaylistController::setRepeatMode(PlaylistController::PlaybackRepeat mode)
|
|
{
|
|
Q_D(const PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_playlist_SetPlaybackRepeat( d->m_playlist, static_cast<vlc_playlist_playback_repeat>(mode) );
|
|
}
|
|
|
|
PlaylistController::MediaStopAction PlaylistController::getMediaStopAction() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return d->m_mediaStopAction;
|
|
}
|
|
|
|
void PlaylistController::setMediaStopAction(PlaylistController::MediaStopAction action)
|
|
{
|
|
Q_D(PlaylistController);
|
|
vlc_playlist_locker lock{ d->m_playlist };
|
|
vlc_playlist_SetMediaStoppedAction(d->m_playlist, static_cast<vlc_playlist_media_stopped_action>(action) );
|
|
}
|
|
|
|
bool PlaylistController::isEmpty() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return d->m_empty;
|
|
}
|
|
|
|
int PlaylistController::count() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
assert(d->m_count <= (size_t)INT_MAX);
|
|
return d->m_count;
|
|
}
|
|
|
|
void PlaylistController::setSortKey(SortKey sortKey)
|
|
{
|
|
Q_D(PlaylistController);
|
|
|
|
if (sortKey == d->m_sortKey)
|
|
return;
|
|
|
|
d->m_sortKey = sortKey;
|
|
emit sortKeyChanged();
|
|
}
|
|
|
|
void PlaylistController::setSortOrder(SortOrder sortOrder)
|
|
{
|
|
Q_D(PlaylistController);
|
|
|
|
SortOrder order = d->m_sortOrder;
|
|
if(sortOrder == order)
|
|
return;
|
|
|
|
d->m_sortOrder = sortOrder;
|
|
emit sortOrderChanged();
|
|
}
|
|
|
|
void PlaylistController::switchSortOrder()
|
|
{
|
|
Q_D(PlaylistController);
|
|
|
|
SortOrder order = d->m_sortOrder;
|
|
if (order == SortOrder::SORT_ORDER_ASC)
|
|
order = SortOrder::SORT_ORDER_DESC;
|
|
else if (order == SortOrder::SORT_ORDER_DESC)
|
|
order = SortOrder::SORT_ORDER_ASC;
|
|
else
|
|
return;
|
|
|
|
d->m_sortOrder = order;
|
|
emit sortOrderChanged();
|
|
}
|
|
|
|
PlaylistController::SortKey PlaylistController::getSortKey() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return d->m_sortKey;
|
|
}
|
|
|
|
PlaylistController::SortOrder PlaylistController::getSortOrder() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return d->m_sortOrder;
|
|
}
|
|
|
|
bool PlaylistController::hasNext() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return d->m_hasNext;
|
|
}
|
|
|
|
bool PlaylistController::hasPrev() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
return d->m_hasPrev;
|
|
}
|
|
|
|
QVariantList PlaylistController::getSortKeyTitleList() const
|
|
{
|
|
Q_D(const PlaylistController);
|
|
|
|
return d->sortKeyTitleList;
|
|
}
|
|
|
|
|
|
} // namespace playlist
|
|
} // namespace vlc
|