TTKMusicPlayer  3.7.0.0
TTKMusicPlayer imitates Kugou UI, the music player uses of qmmp core library based on Qt for windows and linux
musicmprisplayer.cpp
Go to the documentation of this file.
1 #include "musicmprisplayer.h"
2 #include "musicapplication.h"
3 #include "musicplayer.h"
4 #include "musicplaylist.h"
5 #include "ttktime.h"
6 
7 #include <QDBusMessage>
8 #include <qmmp/soundcore.h>
9 #include <qmmp/metadatamanager.h>
10 #include <qmmp/abstractengine.h>
11 
13  : QObject(parent)
14 {
15  QDBusConnection connection = QDBusConnection::sessionBus();
16  //MPRISv2.0
17  m_root = new MusicMPRISPlayerRoot(this);
18  m_player = new MusicMPRISPlayerCore(this);
19  //
20  connection.registerService("org.mpris.MediaPlayer2." TTK_APP_NAME);
21  connection.registerObject("/org/mpris/MediaPlayer2", this);
22 }
23 
25 {
26  QDBusConnection::sessionBus().unregisterService("org.mpris.MediaPlayer2." TTK_APP_NAME);
27  delete m_root;
28  delete m_player;
29 }
30 
32 {
34 }
35 
36 
38  : QDBusAbstractAdaptor(parent)
39 {
40 
41 }
42 
44 {
45  return true;
46 }
47 
49 {
50  return true;
51 }
52 
54 {
55  return TTK_APP_NAME;
56 }
57 
59 {
60  return false;
61 }
62 
64 {
65  return TTK_APP_NAME;
66 }
67 
69 {
70  QStringList mimeTypes;
71  mimeTypes << Decoder::contentTypes();
72  mimeTypes << AbstractEngine::contentTypes();
73  mimeTypes.removeDuplicates();
74  return mimeTypes;
75 }
76 
78 {
79  QStringList protocols = MetaDataManager::instance()->protocols();
80  if(!protocols.contains("file")) //append file if needed
81  {
82  protocols.append("file");
83  }
84  return protocols;
85 }
86 
88 {
90 }
91 
93 {
95 }
96 
97 
99  : QDBusAbstractAdaptor(parent)
100 {
101  TTK::initRandom();
102 
103  m_prevTrack = 0;
104  m_prevPos = 0;
107 
108  connect(m_core, SIGNAL(trackInfoChanged()), SLOT(trackInfoChanged()));
109  connect(m_core, SIGNAL(stateChanged(Qmmp::State)), SLOT(stateChanged()));
110  connect(m_core, SIGNAL(volumeChanged(int)), SLOT(volumeChanged()));
111  connect(m_core, SIGNAL(elapsedChanged(qint64)), SLOT(elapsedChanged(qint64)));
113 
114  updateTrackID();
115  syncProperties();
116 }
117 
119 {
120  return true;
121 }
122 
124 {
125  return !m_application->m_playlist->isEmpty();
126 }
127 
129 {
130  return !m_application->m_playlist->isEmpty();
131 }
132 
134 {
135  return !m_application->m_playlist->isEmpty();
136 }
137 
139 {
140  return !m_application->m_playlist->isEmpty();
141 }
142 
144 {
145  return m_core->duration() > 0;
146 }
147 
149 {
150  switch(m_application->playMode())
151  {
152  case TTK::PlayMode::OneLoop: return "Track";
153  case TTK::PlayMode::ListLoop: return "Playlist";
154  default: return "None";
155  }
156 }
157 
158 void MusicMPRISPlayerCore::setLoopStatus(const QString &value)
159 {
160  if(value == "Track")
161  {
163  }
164  else if(value == "Playlist")
165  {
167  }
168  else
169  {
171  }
172 }
173 
175 {
176  return 1.0;
177 }
178 
180 {
181  if(m_core->path().isEmpty())
182  {
183  return QVariantMap();
184  }
185 
186  QVariantMap map;
187  TrackInfo info = m_core->trackInfo();
188  map["mpris:length"] = qMax(m_core->duration() * TTK_DN_S2MS, qint64(0));
189  if(!MetaDataManager::instance()->getCoverPath(info.path()).isEmpty())
190  {
191  map["mpris:artUrl"] = QUrl::fromLocalFile(MetaDataManager::instance()->getCoverPath(info.path())).toString();
192  }
193 
194  if(!info.value(Qmmp::ALBUM).isEmpty())
195  {
196  map["xesam:album"] = info.value(Qmmp::ALBUM);
197  }
198 
199  if(!info.value(Qmmp::ARTIST).isEmpty())
200  {
201  map["xesam:artist"] = QStringList(info.value(Qmmp::ARTIST));
202  }
203 
204  if(!info.value(Qmmp::ALBUMARTIST).isEmpty())
205  {
206  map["xesam:albumArtist"] = QStringList(info.value(Qmmp::ALBUMARTIST));
207  }
208 
209  if(!info.value(Qmmp::COMMENT).isEmpty())
210  {
211  map["xesam:comment"] = QStringList(info.value(Qmmp::COMMENT));
212  }
213 
214  if(!info.value(Qmmp::COMPOSER).isEmpty())
215  {
216  map["xesam:composer"] = QStringList(info.value(Qmmp::COMPOSER));
217  }
218 
219  if(!info.value(Qmmp::DISCNUMBER).isEmpty())
220  {
221  map["xesam:discNumber"] = info.value(Qmmp::DISCNUMBER).toInt();
222  }
223 
224  if(!info.value(Qmmp::GENRE).isEmpty())
225  {
226  map["xesam:genre"] = QStringList(info.value(Qmmp::GENRE));
227  }
228 
229  if(!info.value(Qmmp::TITLE).isEmpty())
230  {
231  map["xesam:title"] = info.value(Qmmp::TITLE);
232  }
233 
234  if(!info.value(Qmmp::TRACK).isEmpty())
235  {
236  map["xesam:trackNumber"] = info.value(Qmmp::TRACK).toInt();
237  }
238 
239  if(!info.value(Qmmp::YEAR).isEmpty())
240  {
241  map["xesam:contentCreated"] = info.value(Qmmp::YEAR);
242  }
243 
244  map["mpris:trackid"] = QVariant::fromValue<QDBusObjectPath>(m_trackID);
245  map["xesam:url"] = info.path().startsWith(TTK_SEPARATOR) ? QUrl::fromLocalFile(info.path()).toString() : info.path();
246  return map;
247 }
248 
250 {
251  return 1.0;
252 }
253 
255 {
256  if(m_core->state() == Qmmp::Playing)
257  {
258  return "Playing";
259  }
260  else if(m_core->state() == Qmmp::Paused)
261  {
262  return "Paused";
263  }
264  return "Stopped";
265 }
266 
268 {
269  return qMax(m_core->elapsed() * TTK_DN_S2MS, qint64(0));
270 }
271 
273 {
274  return 1.0;
275 }
276 
278 {
279  Q_UNUSED(value)
280 }
281 
283 {
285 }
286 
288 {
290 }
291 
293 {
294  return m_application->m_player->volume();
295 }
296 
298 {
300 }
301 
303 {
305 }
306 
308 {
310 }
311 
312 void MusicMPRISPlayerCore::OpenUri(const QString &uri)
313 {
314  QString path = uri;
315  if(uri.startsWith("file://"))
316  {
317  path = QUrl(uri).toLocalFile();
318  if(!QFile::exists(path))
319  {
320  return; //error
321  }
322  }
323 
324  m_application->importSongsByOutside(path, true);
325 }
326 
328 {
330 }
331 
333 {
335 }
336 
338 {
340 }
341 
343 {
345 }
346 
348 {
349  m_core->seek(qMax(qint64(0), m_core->elapsed() + offset / 1000));
350 }
351 
352 void MusicMPRISPlayerCore::SetPosition(const QDBusObjectPath &trackId, qlonglong position)
353 {
354  if(m_trackID == trackId)
355  {
356  m_core->seek(position / 1000);
357  }
358  else
359  {
360  TTK_WARN_STREAM("SetPosition called with a invalid trackId");
361  }
362 }
363 
365 {
366  updateTrackID();
367  sendProperties();
368 }
369 
371 {
372  if(m_core->state() == Qmmp::Playing)
373  {
374  updateTrackID();
375  m_prevPos = 0;
376  }
377  sendProperties();
378 }
379 
381 {
382  sendProperties();
383 }
384 
386 {
387  if(abs(elapsed - m_prevPos) > 2 * TTK_DN_S2MS)
388  {
389  Q_EMIT Seeked(elapsed * TTK_DN_S2MS);
390  }
391  m_prevPos = elapsed;
392 }
393 
395 {
396  sendProperties();
397 }
398 
400 {
402  {
403  m_trackID = QDBusObjectPath(QString("%1/Track/%2").arg("/org/qmmp/MediaPlayer2").arg(TTK::random()));
405  }
406 }
407 
409 {
410  m_properties["CanGoNext"] = canGoNext();
411  m_properties["CanGoPrevious"] = canGoPrevious();
412  m_properties["CanPause"] = canPause();
413  m_properties["CanPlay"] = canPlay();
414  m_properties["CanSeek"] = canSeek();
415  m_properties["LoopStatus"] = loopStatus();
416  m_properties["MaximumRate"] = maximumRate();
417  m_properties["MinimumRate"] = minimumRate();
418  m_properties["PlaybackStatus"] = playbackStatus();
419  m_properties["Rate"] = rate();
420  m_properties["Shuffle"] = shuffle();
421  m_properties["Volume"] = volume();
422  m_properties["Metadata"] = metadata();
423 }
424 
426 {
427  TTKVariantMap prevProps = m_properties;
428  syncProperties();
429 
430  QVariantMap map;
431  for(auto it = m_properties.constBegin(); it != m_properties.constEnd(); ++it)
432  {
433  if(it.value() != prevProps.value(it.key()))
434  {
435  map.insert(it.key(), it.value());
436  }
437  }
438 
439  if(map.isEmpty())
440  {
441  return;
442  }
443 
444  QDBusMessage msg = QDBusMessage::createSignal("/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "PropertiesChanged");
445  msg << "org.mpris.MediaPlayer2.Player";
446  msg << map;
447  msg << QStringList();
448  QDBusConnection::sessionBus().send(msg);
449 }
The class of the app mpris player object.
QStringList supportedUriSchemes() const
static QStringList contentTypes()
qint64 elapsed() const
void OpenUri(const QString &uri)
void seek(qint64 time)
static MusicApplication * instance()
MusicMPRISPlayerCore * m_player
MusicApplication * m_application
bool hasTrackList() const
double maximumRate() const
QDBusObjectPath m_trackID
static SoundCore * instance()
const TrackInfo & trackInfo() const
void setRate(double value)
QString getCoverPath(const QString &url) const
const QString & path() const
void setLoopStatus(const QString &value)
QStringList protocols() const
TTK::PlayMode playMode() const
#define TTK_APP_NAME
Definition: ttkobject.h:25
qint64 duration() const
TTK_MODULE_EXPORT void initRandom()
Definition: ttktime.cpp:7
MusicPlayer * m_player
MusicMPRISPlayer(QObject *parent=nullptr)
MusicMPRISPlayerCore(QObject *parent=nullptr)
void setVolume(int volume)
Definition: musicplayer.cpp:70
TTK_MODULE_EXPORT int random(int value=RAND_MAX)
Definition: ttktime.cpp:14
#define TTK_WARN_STREAM(msg)
Definition: ttklogger.h:68
voidpf uLong offset
Definition: ioapi.h:142
QStringList supportedMimeTypes() const
bool isEmpty() const
QString path() const
void elapsedChanged(qint64 elapsed)
The TrackInfo class stores metadata and other information about track.
Definition: trackinfo.h:32
PlayMode
Definition: musicobject.h:171
int currentIndex() const
QMap< QString, QVariant > TTKVariantMap
Definition: ttkqtglobal.h:191
MusicPlaylist * m_playlist
void Seek(qlonglong offset)
qlonglong position() const
void setPlaybackMode(TTK::PlayMode mode)
#define TTK_SEPARATOR
Definition: ttkglobal.h:195
void Seeked(qlonglong position)
State
Definition: qmmp.h:76
MusicMPRISPlayerRoot(QObject *parent=nullptr)
QVariantMap metadata() const
void SetPosition(const QDBusObjectPath &trackId, qlonglong position)
void importSongsByOutside(const QString &path, bool play)
QString loopStatus() const
QString desktopEntry() const
MusicMPRISPlayerRoot * m_root
#define TTK_DN_S2MS
Definition: ttkglobal.h:276
const QString value(Qmmp::MetaData key) const
TTK_MODULE_EXPORT QString toString(Record type)
QString playbackStatus() const
void setVolume(double value)
static QStringList contentTypes()
int volume() const
Definition: musicplayer.cpp:65
double minimumRate() const
void setShuffle(bool value)
The class of the app mpris root object.
static MetaDataManager * instance()
TTKVariantMap m_properties
Qmmp::State state() const
QString identity() const