29 #include <QRandomGenerator>
30 #include <QSharedPointer>
42 using namespace media;
45 namespace MediaHubService {
55 const QSharedPointer<media::Engine::MetaDataExtractor> &extractor,
60 return it == m_tracks.begin();
63 return it == m_tracks.end();
67 void set_current_track(
const Track::Id &
id);
71 void add_track_with_uri_at(
const QUrl &uri,
74 void add_tracks_with_uri_at(
const QVector<QUrl> &uris,
78 void do_remove_track(
const Track::Id &
id);
82 auto i = meta_data_cache.find(
id);
83 if (i == meta_data_cache.end()) {
86 i.value().first = uri;
92 auto random_it = shuffled_tracks.begin();
93 if (random_it == shuffled_tracks.end())
96 uint32_t random = QRandomGenerator::global()->generate();
100 std::advance(random_it, random % (shuffled_tracks.count() + 1));
121 const QSharedPointer<media::Engine::MetaDataExtractor> &extractor,
124 extractor(extractor),
139 MH_DEBUG(
"Wrapping d->current_track back to begin()");
144 MH_ERROR(
"TrackList is empty therefore there is no valid current track");
181 MH_DEBUG(
"Adding Track::Id: %s", qUtf8Printable(
id));
182 MH_DEBUG(
"\tURI: %s", qUtf8Printable(uri.toString()));
201 MH_DEBUG(
"Signaling that we just added track id: %s", qUtf8Printable(
id));
203 Q_EMIT q->trackAdded(
id);
208 Q_EMIT q->trackChanged(
id);
213 const QVector<QUrl> &uris,
222 for (
const auto uri : uris)
227 MH_DEBUG(
"Adding Track::Id: %s", qUtf8Printable(
id));
228 MH_DEBUG(
"\tURI: %s", qUtf8Printable(uri.toString()));
238 insert_position = id;
251 MH_DEBUG(
"Signaling that we just added %d tracks to the TrackList", tmp.size());
252 Q_EMIT q->tracksAdded(tmp);
254 if (!current_id.isEmpty()) {
255 Q_EMIT q->trackChanged(current_id);
263 MH_DEBUG(
"-----------------------------------------------------");
264 if (
id.isEmpty() or to.isEmpty())
266 MH_ERROR(
"Can't move track since 'id' or 'to' are empty");
272 MH_ERROR(
"Can't move track to it's same position");
278 MH_ERROR(
"Can't move track since TrackList contains only one track");
285 if (insert_point_it ==
m_tracks.end()) {
286 throw media::TrackList::Errors::FailedToFindMoveTrackSource
287 (
"Failed to find source track " +
id);
298 throw media::TrackList::Errors::FailedToFindMoveTrackDest
299 (
"Failed to find destination track " + to);
303 m_tracks.insert(insert_point_it,
id);
307 MH_ERROR(
"Can't update current_iterator - failed to find track after move");
308 throw media::TrackList::Errors::FailedToMoveTrack();
314 MH_DEBUG(
"%s", qUtf8Printable(track));
317 Q_EMIT q->trackMoved(
id, to);
319 MH_DEBUG(
"-----------------------------------------------------");
332 QString err_str = QString(
"Track ") + track +
" not found in track list";
334 throw media::TrackList::Errors::TrackNotFound(err_str);
338 bool deleting_current =
false;
343 deleting_current =
true;
345 auto next_it = std::next(id_it);
348 loop_status == media::Player::LoopStatus::playlist)
359 Q_EMIT q->endOfTrackList();
376 int removed =
m_tracks.removeAll(
id);
385 Q_EMIT q->trackRemoved(
id);
389 Q_EMIT q->endOfTrackList();
398 Q_EMIT q->onGoToTrack(track);
399 Q_EMIT q->trackChanged(track);
403 const QSharedPointer<media::Engine::MetaDataExtractor> &extractor,
420 d->shuffled_tracks = d->m_tracks;
421 std::random_shuffle(d->shuffled_tracks.begin(),
422 d->shuffled_tracks.end());
435 const auto it = d->meta_data_cache.find(
id);
437 if (it == d->meta_data_cache.end())
440 return it.value().first;
446 const auto it = d->meta_data_cache.find(
id);
448 if (it == d->meta_data_cache.end())
451 return it.value().second;
461 d->add_track_with_uri_at(uri, position, make_current);
469 d->add_tracks_with_uri_at(uris, position);
477 return d->move_track(
id, to);
496 return d->shuffled_tracks;
504 d->current_track.clear();
507 Q_EMIT endOfTrackList();
510 d->track_counter = 0;
511 d->shuffled_tracks.clear();
513 Q_EMIT trackListReset();
530 const auto n_tracks = d->m_tracks.count();
541 if (d->current_track == d->empty_iterator())
551 auto it = d->get_current_shuffled();
552 return ++it != d->shuffled_tracks.end();
556 const auto next_track = std::next(d->current_iterator());
557 return !d->is_last_track(next_track);
569 if (d->m_tracks.isEmpty() || d->current_track == d->empty_iterator())
574 return d->get_current_shuffled() != d->shuffled_tracks.begin();
576 return d->current_track != d->m_tracks.begin();
583 if (d->m_tracks.isEmpty()) {
585 MH_ERROR(
"No tracks, cannot go to next");
589 bool go_to_track =
false;
592 if (d->loop_status == media::Player::LoopStatus::track)
594 MH_INFO(
"Looping on the current track since LoopStatus is set to track");
598 else if (d->loop_status == media::Player::LoopStatus::playlist && not hasNext())
600 MH_INFO(
"Looping on the tracklist since LoopStatus is set to playlist");
606 const auto currentId = d->get_current_track();
607 std::random_shuffle(d->shuffled_tracks.begin(),
608 d->shuffled_tracks.end());
609 auto id = *d->shuffled_tracks.begin();
610 if (
id == currentId) {
611 std::iter_swap(d->shuffled_tracks.begin(),
612 d->shuffled_tracks.end() - 1);
613 id = *d->shuffled_tracks.begin();
615 d->set_current_track(
id);
619 d->current_track = d->m_tracks.first();
627 auto it = d->get_current_shuffled();
628 if (it == d->shuffled_tracks.end()) {
629 d->set_current_track(d->shuffled_tracks.first());
631 }
else if (++it != d->shuffled_tracks.end()) {
632 MH_INFO(
"Advancing to next track: %s", qUtf8Printable(*it));
633 d->set_current_track(*it);
639 const auto it = std::next(d->current_iterator());
640 if (not d->is_last_track(it))
642 MH_INFO(
"Advancing to next track: %s", qUtf8Printable(*it));
643 d->current_track = *it;
653 MH_DEBUG(
"next track id is %s", qUtf8Printable(
id));
654 Q_EMIT trackChanged(
id);
656 Q_EMIT onGoToTrack(
id);
661 MH_INFO(
"End of tracklist reached");
662 Q_EMIT endOfTrackList();
672 if (d->m_tracks.isEmpty()) {
674 MH_ERROR(
"No tracks, cannot go to previous");
678 bool go_to_track =
false;
680 const uint64_t max_position = 5 * UINT64_C(1000000000);
684 if (d->current_position > max_position)
686 MH_INFO(
"Repeating current track...");
690 else if (d->loop_status == media::Player::LoopStatus::track)
692 MH_INFO(
"Looping on the current track...");
696 else if (d->loop_status == media::Player::LoopStatus::playlist && not hasPrevious())
698 MH_INFO(
"Looping on the entire TrackList...");
702 const auto id = *std::prev(d->shuffled_tracks.end());
703 d->set_current_track(
id);
707 d->current_track = d->m_tracks.last();
716 auto it = d->get_current_shuffled();
717 if (it != d->shuffled_tracks.begin()) {
718 d->set_current_track(*(--it));
722 else if (not d->is_first_track(d->current_iterator()))
725 d->current_track = *std::prev(d->current_iterator());
733 Q_EMIT trackChanged(
id);
734 Q_EMIT onGoToTrack(
id);
739 MH_INFO(
"Beginning of tracklist reached");
740 Q_EMIT endOfTrackList();
749 return *(d->current_iterator());
755 d->loop_status = loop_status;
761 return d->loop_status;
767 d->current_position = position;
777 static const media::Track::Id id{
"/org/mpris/MediaPlayer2/TrackList/NoTrack"};