File indexing completed on 2024-05-19 04:50:28
0001 /**************************************************************************************** 0002 * Copyright (c) 2012 Matěj Laitl <matej@laitl.cz> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #ifndef STATSYNCING_MATCHTRACKSJOB_H 0018 #define STATSYNCING_MATCHTRACKSJOB_H 0019 0020 #include "statsyncing/Provider.h" 0021 #include "statsyncing/TrackTuple.h" 0022 0023 #include <ThreadWeaver/Job> 0024 0025 #include <QMap> 0026 0027 namespace StatSyncing 0028 { 0029 /** 0030 * Threadweaver job that matches tracks of multiple Providers. 0031 * Because comparisonFields() needs to be static, only one instance of this class is 0032 * allowed to exist at given time. 0033 */ 0034 class MatchTracksJob :public QObject, public ThreadWeaver::Job 0035 { 0036 Q_OBJECT 0037 0038 public: 0039 explicit MatchTracksJob( const ProviderPtrList &providers, QObject *parent = nullptr ); 0040 0041 bool success() const override; 0042 0043 /** 0044 * Binary OR of MetaValues.h Meta::val* flags that are used to compare tracks 0045 * from different providers. Guaranteed to contain at least artist, album, 0046 * title. Valid only after run() has been called. 0047 */ 0048 static qint64 comparisonFields(); 0049 0050 /** 0051 * Return a list of providers participating in the matching 0052 */ 0053 ProviderPtrList providers() const; 0054 0055 // results: 0056 const QList<TrackTuple> &matchedTuples() const { return m_matchedTuples; } 0057 const PerProviderTrackList &uniqueTracks() const { return m_uniqueTracks; } 0058 const PerProviderTrackList &excludedTracks() const { return m_excludedTracks; } 0059 const TrackList &tracksToScrobble() const { return m_tracksToScrobble; } 0060 0061 public Q_SLOTS: 0062 /** 0063 * Abort the job as soon as possible. 0064 */ 0065 void abort(); 0066 0067 Q_SIGNALS: 0068 /** 0069 * Emitted when matcher gets to know total number of steps it will take to 0070 * match all tracks. 0071 */ 0072 void totalSteps( int steps ); 0073 0074 /** 0075 * Emitted when one progress step has been finished. 0076 */ 0077 void incrementProgress(); 0078 0079 /** 0080 * Emitted from worker thread when all time-consuming operations are done. 0081 */ 0082 void endProgressOperation( QObject *owner ); 0083 0084 /** This signal is emitted when this job is being processed by a thread. */ 0085 void started(ThreadWeaver::JobPointer); 0086 /** This signal is emitted when the job has been finished (no matter if it succeeded or not). */ 0087 void done(ThreadWeaver::JobPointer); 0088 /** This job has failed. 0089 * This signal is emitted when success() returns false after the job is executed. */ 0090 void failed(ThreadWeaver::JobPointer); 0091 0092 protected: 0093 void defaultBegin(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override; 0094 void defaultEnd(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override; 0095 void run(ThreadWeaver::JobPointer self = QSharedPointer<ThreadWeaver::Job>(), ThreadWeaver::Thread *thread = nullptr) override; 0096 0097 private: 0098 /** 0099 * Queries each provider from @param artistProviders for tracks from artist 0100 * they specify and separates them into m_uniqueTracks, m_excludedTracks and 0101 * m_matchedTuples. 0102 */ 0103 void matchTracksFromArtist( const QMultiMap<ProviderPtr, QString> &artistProviders ); 0104 0105 /** 0106 * Finds the "smallest" track among provider track lists; assumes individual 0107 * lists are already sorted and non-empty 0108 */ 0109 TrackPtr findSmallestTrack( const PerProviderTrackList &providerTracks ); 0110 0111 /** 0112 * Takes tracks from each provider that are equal to @param track. 0113 * If a list from @param delegateTracks becomes empty, whole entry for that 0114 * provider is removed from @param delegateTracks. 0115 */ 0116 PerProviderTrackList takeTracksEqualTo( const TrackPtr &track, 0117 PerProviderTrackList &providerTracks ); 0118 0119 /** 0120 * Adds @param tuple to m_matchedTuples and updated m_matchedTrackCounts 0121 */ 0122 void addMatchedTuple( const TrackTuple &tuple ); 0123 0124 /** 0125 * Scan for tracks in @param trackList eligible for scrobbling and add them to 0126 * m_tracksToScrobble. 0127 */ 0128 void scanForScrobblableTracks( const TrackList &trackList ); 0129 0130 /** 0131 * Must be static because comparisonFields needs to be static. 0132 * @see comparisonFields() 0133 */ 0134 static qint64 s_comparisonFields; 0135 0136 bool m_abort; 0137 ProviderPtrList m_providers; 0138 0139 /** 0140 * Per-provider list of tracks that are unique to that provider 0141 */ 0142 PerProviderTrackList m_uniqueTracks; 0143 0144 /** 0145 * Per-provider list of tracks that have been excluded from synchronization 0146 * for various reasons, e.g. for being duplicate within that provider 0147 */ 0148 PerProviderTrackList m_excludedTracks; 0149 0150 /** 0151 * Our raison d'etre: tuples of matched tracks 0152 */ 0153 QList<TrackTuple> m_matchedTuples; 0154 0155 /** 0156 * Tracks with non-zero recent playCount, eligible for being scrobbled. 0157 */ 0158 TrackList m_tracksToScrobble; 0159 0160 /** 0161 * Per-provider count of matched tracks 0162 */ 0163 QMap<ProviderPtr, int> m_matchedTrackCounts; 0164 }; 0165 0166 } // namespace StatSyncing 0167 0168 #endif // STATSYNCING_MATCHTRACKSJOB_H