From b34959917446ac5d47ddec7bb6d98a6397045558 Mon Sep 17 00:00:00 2001 From: ailurux Date: Tue, 30 Jul 2024 04:36:48 +0000 Subject: daniel/playlist-queue (#84) Support for playlist files being opened along side the queue's own playlist. Playlists can be opened from the file browser, if the file ends in ".playlist" (will add support for .m3u as well eventually) Reviewed-on: https://codeberg.org/cool-tech-zone/tangara-fw/pulls/84 Co-authored-by: ailurux Co-committed-by: ailurux --- src/tangara/audio/track_queue.cpp | 115 ++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 42 deletions(-) (limited to 'src/tangara/audio/track_queue.cpp') diff --git a/src/tangara/audio/track_queue.cpp b/src/tangara/audio/track_queue.cpp index 1aeecf8a..399d6717 100644 --- a/src/tangara/audio/track_queue.cpp +++ b/src/tangara/audio/track_queue.cpp @@ -84,18 +84,25 @@ auto notifyChanged(bool current_changed, Reason reason) -> void { events::Audio().Dispatch(ev); } + TrackQueue::TrackQueue(tasks::WorkerPool& bg_worker, database::Handle db) : mutex_(), bg_worker_(bg_worker), db_(db), - playlist_("queue.playlist"), // TODO + playlist_(".queue.playlist"), + position_(0), shuffle_(), repeat_(false), replay_(false) {} auto TrackQueue::current() const -> TrackItem { const std::shared_lock lock(mutex_); - std::string val = playlist_.value(); + std::string val; + if (opened_playlist_ && position_ < opened_playlist_->size()) { + val = opened_playlist_->value(); + } else { + val = playlist_.value(); + } if (val.empty()) { return {}; } @@ -104,12 +111,21 @@ auto TrackQueue::current() const -> TrackItem { auto TrackQueue::currentPosition() const -> size_t { const std::shared_lock lock(mutex_); - return playlist_.currentPosition(); + return position_; } auto TrackQueue::totalSize() const -> size_t { - const std::shared_lock lock(mutex_); - return playlist_.size(); + size_t sum = playlist_.size(); + if (opened_playlist_) { + sum += opened_playlist_->size(); + } + return sum; +} + +auto TrackQueue::updateShuffler() -> void { + if (shuffle_) { + shuffle_->resize(totalSize()); + } } auto TrackQueue::open() -> bool { @@ -118,6 +134,17 @@ auto TrackQueue::open() -> bool { return playlist_.open(); } +auto TrackQueue::openPlaylist(const std::string& playlist_file) -> bool { + opened_playlist_.emplace(playlist_file); + auto res = opened_playlist_->open(); + if (!res) { + return false; + } + updateShuffler(); + notifyChanged(true, Reason::kExplicitUpdate); + return true; +} + auto TrackQueue::getFilepath(database::TrackId id) -> std::optional { auto db = db_.lock(); if (!db) { @@ -142,20 +169,15 @@ auto TrackQueue::append(Item i) -> void { current_changed = was_queue_empty; // Dont support inserts yet } - auto update_shuffler = [=, this]() { - if (shuffle_) { - shuffle_->resize(playlist_.size()); - // If there wasn't anything already playing, then we should make sure we - // begin playback at a random point, instead of always starting with - // whatever was inserted first and *then* shuffling. - // We don't base this purely off of current_changed because we would like - // 'play this track now' (by inserting at the current pos) to work even - // when shuffling is enabled. - if (was_queue_empty) { - playlist_.skipTo(shuffle_->current()); - } - } - }; + // If there wasn't anything already playing, then we should make sure we + // begin playback at a random point, instead of always starting with + // whatever was inserted first and *then* shuffling. + // We don't base this purely off of current_changed because we would like + // 'play this track now' (by inserting at the current pos) to work even + // when shuffling is enabled. + if (was_queue_empty && shuffle_) { + playlist_.skipTo(shuffle_->current()); + } if (std::holds_alternative(i)) { { @@ -164,7 +186,7 @@ auto TrackQueue::append(Item i) -> void { if (!filename.empty()) { playlist_.append(filename); } - update_shuffler(); + updateShuffler(); } notifyChanged(current_changed, Reason::kExplicitUpdate); } else if (std::holds_alternative(i)) { @@ -191,7 +213,7 @@ auto TrackQueue::append(Item i) -> void { } { const std::unique_lock lock(mutex_); - update_shuffler(); + updateShuffler(); } notifyChanged(current_changed, Reason::kExplicitUpdate); }); @@ -202,6 +224,20 @@ auto TrackQueue::next() -> void { next(Reason::kExplicitUpdate); } +auto TrackQueue::goTo(size_t position) { + position_ = position; + if (opened_playlist_) { + if (position_ < opened_playlist_->size()) { + opened_playlist_->skipTo(position_); + } else { + playlist_.skipTo(position_ - opened_playlist_->size()); + } + } else { + playlist_.skipTo(position_); + } +} + + auto TrackQueue::next(Reason r) -> void { bool changed = true; @@ -209,18 +245,13 @@ auto TrackQueue::next(Reason r) -> void { const std::unique_lock lock(mutex_); if (shuffle_) { shuffle_->next(); - playlist_.skipTo(shuffle_->current()); + position_ = shuffle_->current(); } else { - if (playlist_.atEnd()) { - if (replay_) { - playlist_.skipTo(0); - } else { - changed = false; - } - } else { - playlist_.next(); + if (position_ + 1 < totalSize()) { + position_++; } } + goTo(position_); } notifyChanged(changed, r); @@ -233,18 +264,13 @@ auto TrackQueue::previous() -> void { const std::unique_lock lock(mutex_); if (shuffle_) { shuffle_->prev(); - playlist_.skipTo(shuffle_->current()); + position_ = shuffle_->current(); } else { - if (playlist_.currentPosition() == 0) { - if (repeat_) { - playlist_.skipTo(playlist_.size()-1); - } else { - changed = false; - } - } else { - playlist_.prev(); + if (position_ > 0) { + position_--; } } + goTo(position_); } notifyChanged(changed, Reason::kExplicitUpdate); @@ -262,6 +288,7 @@ auto TrackQueue::clear() -> void { { const std::unique_lock lock(mutex_); playlist_.clear(); + opened_playlist_.reset(); if (shuffle_) { shuffle_->resize(0); } @@ -274,7 +301,7 @@ auto TrackQueue::random(bool en) -> void { { const std::unique_lock lock(mutex_); if (en) { - shuffle_.emplace(playlist_.size()); + shuffle_.emplace(totalSize()); shuffle_->replay(replay_); } else { shuffle_.reset(); @@ -326,7 +353,8 @@ auto TrackQueue::serialise() -> std::string { encoded.add(cppbor::Uint{0}, cppbor::Array{ cppbor::Bool{repeat_}, cppbor::Bool{replay_}, - cppbor::Uint{playlist_.currentPosition()}, + cppbor::Uint{position_}, + cppbor::Tstr{opened_playlist_->filepath()} }); if (shuffle_) { encoded.add(cppbor::Uint{1}, cppbor::Array{ @@ -368,7 +396,10 @@ cppbor::ParseClient* TrackQueue::QueueParseClient::item( i_ = 0; } else if (item->type() == cppbor::UINT) { auto val = item->asUint()->unsignedValue(); - queue_.playlist_.skipTo(val); + queue_.goTo(val); + } else if (item->type() == cppbor::TSTR) { + auto val = item->asTstr(); + queue_.openPlaylist(val->value()); } else if (item->type() == cppbor::SIMPLE) { bool val = item->asBool()->value(); if (i_ == 0) { -- cgit v1.2.3