1 /*
2  *  Copyright (C) 2012-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "guilib/guiinfo/MusicGUIInfo.h"
10 
11 #include "Application.h"
12 #include "FileItem.h"
13 #include "PartyModeManager.h"
14 #include "PlayListPlayer.h"
15 #include "ServiceBroker.h"
16 #include "URL.h"
17 #include "Util.h"
18 #include "guilib/LocalizeStrings.h"
19 #include "guilib/guiinfo/GUIInfo.h"
20 #include "guilib/guiinfo/GUIInfoHelper.h"
21 #include "guilib/guiinfo/GUIInfoLabels.h"
22 #include "music/MusicInfoLoader.h"
23 #include "music/MusicThumbLoader.h"
24 #include "music/tags/MusicInfoTag.h"
25 #include "playlists/PlayList.h"
26 #include "settings/AdvancedSettings.h"
27 #include "settings/SettingsComponent.h"
28 #include "utils/URIUtils.h"
29 #include "utils/log.h"
30 
31 using namespace KODI::GUILIB;
32 using namespace KODI::GUILIB::GUIINFO;
33 using namespace MUSIC_INFO;
34 
InitCurrentItem(CFileItem * item)35 bool CMusicGUIInfo::InitCurrentItem(CFileItem *item)
36 {
37   if (item && (item->IsAudio() || (item->IsInternetStream() && g_application.GetAppPlayer().IsPlayingAudio())))
38   {
39     CLog::Log(LOGDEBUG,"CMusicGUIInfo::InitCurrentItem(%s)", item->GetPath().c_str());
40 
41     item->LoadMusicTag();
42 
43     CMusicInfoTag* tag = item->GetMusicInfoTag(); // creates item if not yet set, so no nullptr checks needed
44     tag->SetLoaded(true);
45 
46     // find a thumb for this file.
47     if (item->IsInternetStream() && !item->IsMusicDb())
48     {
49       if (!g_application.m_strPlayListFile.empty())
50       {
51         CLog::Log(LOGDEBUG,"Streaming media detected... using %s to find a thumb", g_application.m_strPlayListFile.c_str());
52         CFileItem streamingItem(g_application.m_strPlayListFile,false);
53 
54         CMusicThumbLoader loader;
55         loader.FillThumb(streamingItem);
56         if (streamingItem.HasArt("thumb"))
57           item->SetArt("thumb", streamingItem.GetArt("thumb"));
58       }
59     }
60     else
61     {
62       CMusicThumbLoader loader;
63       loader.LoadItem(item);
64     }
65 
66     CMusicInfoLoader::LoadAdditionalTagInfo(item);
67     return true;
68   }
69   return false;
70 }
71 
GetLabel(std::string & value,const CFileItem * item,int contextWindow,const CGUIInfo & info,std::string * fallback) const72 bool CMusicGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contextWindow, const CGUIInfo &info, std::string *fallback) const
73 {
74   // For musicplayer "offset" and "position" info labels check playlist
75   if (info.GetData1() && ((info.m_info >= MUSICPLAYER_OFFSET_POSITION_FIRST &&
76       info.m_info <= MUSICPLAYER_OFFSET_POSITION_LAST) ||
77       (info.m_info >= PLAYER_OFFSET_POSITION_FIRST && info.m_info <= PLAYER_OFFSET_POSITION_LAST)))
78     return GetPlaylistInfo(value, info);
79 
80   const CMusicInfoTag* tag = item->GetMusicInfoTag();
81   if (tag)
82   {
83     switch (info.m_info)
84     {
85       /////////////////////////////////////////////////////////////////////////////////////////////
86       // PLAYER_* / MUSICPLAYER_* / LISTITEM_*
87       /////////////////////////////////////////////////////////////////////////////////////////////
88       case PLAYER_PATH:
89       case PLAYER_FILENAME:
90       case PLAYER_FILEPATH:
91         value = tag->GetURL();
92         if (value.empty())
93           value = item->GetPath();
94         value = GUIINFO::GetFileInfoLabelValueFromPath(info.m_info, value);
95         return true;
96       case PLAYER_TITLE:
97         value = tag->GetTitle();
98         return !value.empty();
99       case MUSICPLAYER_TITLE:
100         value = tag->GetTitle();
101         return !value.empty();
102       case LISTITEM_TITLE:
103         value = tag->GetTitle();
104         return true;
105       case MUSICPLAYER_PLAYCOUNT:
106       case LISTITEM_PLAYCOUNT:
107         if (tag->GetPlayCount() > 0)
108         {
109           value = StringUtils::Format("%i", tag->GetPlayCount());
110           return true;
111         }
112         break;
113       case MUSICPLAYER_LASTPLAYED:
114       case LISTITEM_LASTPLAYED:
115       {
116         const CDateTime& dateTime = tag->GetLastPlayed();
117         if (dateTime.IsValid())
118         {
119           value = dateTime.GetAsLocalizedDate();
120           return true;
121         }
122         break;
123       }
124       case MUSICPLAYER_TRACK_NUMBER:
125       case LISTITEM_TRACKNUMBER:
126         if (tag->Loaded() && tag->GetTrackNumber() > 0)
127         {
128           value = StringUtils::Format("%02i", tag->GetTrackNumber());
129           return true;
130         }
131         break;
132       case MUSICPLAYER_DISC_NUMBER:
133       case LISTITEM_DISC_NUMBER:
134         if (tag->GetDiscNumber() > 0)
135         {
136           value = StringUtils::Format("%i", tag->GetDiscNumber());
137           return true;
138         }
139         break;
140       case MUSICPLAYER_TOTALDISCS:
141       case LISTITEM_TOTALDISCS:
142         value = StringUtils::Format("%i", tag->GetTotalDiscs());
143         return true;
144       case MUSICPLAYER_DISC_TITLE:
145       case LISTITEM_DISC_TITLE:
146         value = tag->GetDiscSubtitle();
147         return true;
148       case MUSICPLAYER_ARTIST:
149       case LISTITEM_ARTIST:
150         value = tag->GetArtistString();
151         return true;
152       case MUSICPLAYER_ALBUM_ARTIST:
153       case LISTITEM_ALBUM_ARTIST:
154         value = tag->GetAlbumArtistString();
155         return true;
156       case MUSICPLAYER_CONTRIBUTORS:
157       case LISTITEM_CONTRIBUTORS:
158         if (tag->HasContributors())
159         {
160           value = tag->GetContributorsText();
161           return true;
162         }
163         break;
164       case MUSICPLAYER_CONTRIBUTOR_AND_ROLE:
165       case LISTITEM_CONTRIBUTOR_AND_ROLE:
166         if (tag->HasContributors())
167         {
168           value = tag->GetContributorsAndRolesText();
169           return true;
170         }
171         break;
172       case MUSICPLAYER_ALBUM:
173       case LISTITEM_ALBUM:
174         value = tag->GetAlbum();
175         return true;
176       case MUSICPLAYER_YEAR:
177       case LISTITEM_YEAR:
178         value = tag->GetYearString();
179         return true;
180       case MUSICPLAYER_GENRE:
181       case LISTITEM_GENRE:
182         value =  StringUtils::Join(tag->GetGenre(), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator);
183         return true;
184       case MUSICPLAYER_LYRICS:
185         value = tag->GetLyrics();
186         return true;
187       case MUSICPLAYER_RATING:
188       case LISTITEM_RATING:
189       {
190         float rating = tag->GetRating();
191         if (rating > 0.f)
192         {
193           value = StringUtils::FormatNumber(rating);
194           return true;
195         }
196         break;
197       }
198       case MUSICPLAYER_RATING_AND_VOTES:
199       case LISTITEM_RATING_AND_VOTES:
200       {
201         float rating = tag->GetRating();
202         if (rating > 0.f)
203         {
204           int votes = tag->GetVotes();
205           if (votes <= 0)
206             value = StringUtils::FormatNumber(rating);
207           else
208             value = StringUtils::Format(g_localizeStrings.Get(20350).c_str(),
209                                         StringUtils::FormatNumber(rating).c_str(),
210                                         StringUtils::FormatNumber(votes).c_str());
211           return true;
212         }
213         break;
214       }
215       case MUSICPLAYER_USER_RATING:
216       case LISTITEM_USER_RATING:
217         if (tag->GetUserrating() > 0)
218         {
219           value = StringUtils::Format("%i", tag->GetUserrating());
220           return true;
221         }
222         break;
223       case MUSICPLAYER_COMMENT:
224       case LISTITEM_COMMENT:
225         value = tag->GetComment();
226         return true;
227       case MUSICPLAYER_MOOD:
228       case LISTITEM_MOOD:
229         value = tag->GetMood();
230         return true;
231       case LISTITEM_DBTYPE:
232         value = tag->GetType();
233         return true;
234       case MUSICPLAYER_DBID:
235       case LISTITEM_DBID:
236       {
237         int dbId = tag->GetDatabaseId();
238         if (dbId > -1)
239         {
240           value = StringUtils::Format("%i", dbId);
241           return true;
242         }
243         break;
244       }
245       case PLAYER_DURATION:
246         if (!g_application.GetAppPlayer().IsPlayingAudio())
247           break;
248         // fall-thru is intended.
249       case MUSICPLAYER_DURATION:
250       case LISTITEM_DURATION:
251       {
252         int iDuration = tag->GetDuration();
253         if (iDuration > 0)
254         {
255           value = StringUtils::SecondsToTimeString(iDuration,
256                                                    static_cast<TIME_FORMAT>(info.m_info == LISTITEM_DURATION
257                                                                             ? info.GetData4()
258                                                                             : info.GetData1()));
259           return true;
260         }
261         break;
262       }
263       case MUSICPLAYER_BPM:
264       case LISTITEM_BPM:
265         if (tag->GetBPM() > 0)
266         {
267           value = StringUtils::Format("%i", tag->GetBPM());
268           return true;
269         }
270         break;
271       case MUSICPLAYER_STATIONNAME:
272         // This property can be used for example by addons to enforce/override the station name.
273         value = item->GetProperty("StationName").asString();
274         if (value.empty())
275           value = tag->GetStationName();
276         return true;
277 
278       /////////////////////////////////////////////////////////////////////////////////////////////
279       // LISTITEM_*
280       /////////////////////////////////////////////////////////////////////////////////////////////
281       case LISTITEM_PROPERTY:
282         if (StringUtils::StartsWithNoCase(info.GetData3(), "Role."))
283         {
284           // "Role.xxxx" properties are held in music tag
285           std::string property = info.GetData3();
286           property.erase(0, 5); //Remove Role.
287           value = tag->GetArtistStringForRole(property);
288           return true;
289         }
290         break;
291       case LISTITEM_VOTES:
292         value = StringUtils::FormatNumber(tag->GetVotes());
293         return true;
294       case MUSICPLAYER_ORIGINALDATE:
295       case LISTITEM_ORIGINALDATE:
296       {
297         value = tag->GetOriginalDate();
298         if (!CServiceBroker::GetSettingsComponent()
299                 ->GetAdvancedSettings()
300                 ->m_bMusicLibraryUseISODates)
301           value = StringUtils::ISODateToLocalizedDate(value);
302         return true;
303       }
304       case MUSICPLAYER_RELEASEDATE:
305       case LISTITEM_RELEASEDATE:
306       {
307         value = tag->GetReleaseDate();
308         if (!CServiceBroker::GetSettingsComponent()
309                 ->GetAdvancedSettings()
310                 ->m_bMusicLibraryUseISODates)
311           value = StringUtils::ISODateToLocalizedDate(value);
312         return true;
313       }
314       break;
315       case LISTITEM_BITRATE:
316       {
317         int BitRate = tag->GetBitRate();
318         if (BitRate > 0)
319         {
320           value = StringUtils::Format("%i", BitRate);
321           return true;
322         }
323         break;
324       }
325       case LISTITEM_SAMPLERATE:
326       {
327         int sampleRate = tag->GetSampleRate();
328         if (sampleRate > 0)
329         {
330           value = StringUtils::Format("%.5g", static_cast<double>(sampleRate) / 1000.0);
331           return true;
332         }
333         break;
334       }
335       case LISTITEM_MUSICCHANNELS:
336       {
337         int channels = tag->GetNoOfChannels();
338         if (channels > 0)
339         {
340           value = StringUtils::Format("%i", channels);
341           return true;
342         }
343         break;
344       }
345       case LISTITEM_ALBUMSTATUS:
346         value = tag->GetAlbumReleaseStatus();
347         return true;
348       case LISTITEM_FILENAME:
349       case LISTITEM_FILE_EXTENSION:
350         if (item->IsMusicDb())
351           value = URIUtils::GetFileName(tag->GetURL());
352         else if (item->HasVideoInfoTag()) // special handling for music videos, which have both a videotag and a musictag
353           break;
354         else
355           value = URIUtils::GetFileName(item->GetPath());
356 
357         if (info.m_info == LISTITEM_FILE_EXTENSION)
358         {
359           std::string strExtension = URIUtils::GetExtension(value);
360           value = StringUtils::TrimLeft(strExtension, ".");
361         }
362         return true;
363       case LISTITEM_FOLDERNAME:
364       case LISTITEM_PATH:
365         if (item->IsMusicDb())
366           value = URIUtils::GetDirectory(tag->GetURL());
367         else if (item->HasVideoInfoTag()) // special handling for music videos, which have both a videotag and a musictag
368           break;
369         else
370           URIUtils::GetParentPath(item->GetPath(), value);
371 
372         value = CURL(value).GetWithoutUserDetails();
373 
374         if (info.m_info == LISTITEM_FOLDERNAME)
375         {
376           URIUtils::RemoveSlashAtEnd(value);
377           value = URIUtils::GetFileName(value);
378         }
379         return true;
380       case LISTITEM_FILENAME_AND_PATH:
381         if (item->IsMusicDb())
382           value = tag->GetURL();
383         else if (item->HasVideoInfoTag()) // special handling for music videos, which have both a videotag and a musictag
384           break;
385         else
386           value = item->GetPath();
387 
388         value = CURL(value).GetWithoutUserDetails();
389         return true;
390       case LISTITEM_DATE_ADDED:
391         if (tag->GetDateAdded().IsValid())
392         {
393           value = tag->GetDateAdded().GetAsLocalizedDate();
394           return true;
395         }
396         break;
397     }
398   }
399 
400   switch (info.m_info)
401   {
402     ///////////////////////////////////////////////////////////////////////////////////////////////
403     // MUSICPLAYER_*
404     ///////////////////////////////////////////////////////////////////////////////////////////////
405     case MUSICPLAYER_PROPERTY:
406       if (StringUtils::StartsWithNoCase(info.GetData3(), "Role.") && item->HasMusicInfoTag())
407       {
408         // "Role.xxxx" properties are held in music tag
409         std::string property = info.GetData3();
410         property.erase(0, 5); //Remove Role.
411         value = item->GetMusicInfoTag()->GetArtistStringForRole(property);
412         return true;
413       }
414       value = item->GetProperty(info.GetData3()).asString();
415       return true;
416     case MUSICPLAYER_PLAYLISTLEN:
417       if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST_MUSIC)
418       {
419         value = GUIINFO::GetPlaylistLabel(PLAYLIST_LENGTH);
420         return true;
421       }
422       break;
423     case MUSICPLAYER_PLAYLISTPOS:
424       if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST_MUSIC)
425       {
426         value = GUIINFO::GetPlaylistLabel(PLAYLIST_POSITION);
427         return true;
428       }
429       break;
430     case MUSICPLAYER_COVER:
431       if (g_application.GetAppPlayer().IsPlayingAudio())
432       {
433         if (fallback)
434           *fallback = "DefaultAlbumCover.png";
435         value = item->HasArt("thumb") ? item->GetArt("thumb") : "DefaultAlbumCover.png";
436         return true;
437       }
438       break;
439     case MUSICPLAYER_BITRATE:
440     {
441       int iBitrate = m_audioInfo.bitrate;
442       if (iBitrate > 0)
443       {
444         value = StringUtils::Format("%li", std::lrint(static_cast<double>(iBitrate) / 1000.0));
445         return true;
446       }
447       break;
448     }
449     case MUSICPLAYER_CHANNELS:
450     {
451       int iChannels = m_audioInfo.channels;
452       if (iChannels > 0)
453       {
454         value = StringUtils::Format("%i", iChannels);
455         return true;
456       }
457       break;
458     }
459     case MUSICPLAYER_BITSPERSAMPLE:
460     {
461       int iBPS = m_audioInfo.bitspersample;
462       if (iBPS > 0)
463       {
464         value = StringUtils::Format("%i", iBPS);
465         return true;
466       }
467       break;
468     }
469     case MUSICPLAYER_SAMPLERATE:
470     {
471       int iSamplerate = m_audioInfo.samplerate;
472       if (iSamplerate > 0)
473       {
474         value = StringUtils::Format("%.5g", static_cast<double>(iSamplerate) / 1000.0);
475         return true;
476       }
477       break;
478     }
479     case MUSICPLAYER_CODEC:
480       value = StringUtils::Format("%s", m_audioInfo.codecName.c_str());
481       return true;
482   }
483 
484   ///////////////////////////////////////////////////////////////////////////////////////////////
485   // MUSICPM_*
486   ///////////////////////////////////////////////////////////////////////////////////////////////
487   if (GetPartyModeLabel(value, info))
488     return true;
489 
490   return false;
491 }
492 
GetPartyModeLabel(std::string & value,const CGUIInfo & info) const493 bool CMusicGUIInfo::GetPartyModeLabel(std::string& value, const CGUIInfo &info) const
494 {
495   int iSongs = -1;
496 
497   switch (info.m_info)
498   {
499     case MUSICPM_SONGSPLAYED:
500       iSongs = g_partyModeManager.GetSongsPlayed();
501       break;
502     case MUSICPM_MATCHINGSONGS:
503       iSongs = g_partyModeManager.GetMatchingSongs();
504       break;
505     case MUSICPM_MATCHINGSONGSPICKED:
506       iSongs = g_partyModeManager.GetMatchingSongsPicked();
507       break;
508     case MUSICPM_MATCHINGSONGSLEFT:
509       iSongs = g_partyModeManager.GetMatchingSongsLeft();
510       break;
511     case MUSICPM_RELAXEDSONGSPICKED:
512       iSongs = g_partyModeManager.GetRelaxedSongs();
513       break;
514     case MUSICPM_RANDOMSONGSPICKED:
515       iSongs = g_partyModeManager.GetRandomSongs();
516       break;
517   }
518 
519   if (iSongs >= 0)
520   {
521     value = StringUtils::Format("%i", iSongs);
522     return true;
523   }
524 
525   return false;
526 }
527 
GetPlaylistInfo(std::string & value,const CGUIInfo & info) const528 bool CMusicGUIInfo::GetPlaylistInfo(std::string& value, const CGUIInfo &info) const
529 {
530   PLAYLIST::CPlayList& playlist = CServiceBroker::GetPlaylistPlayer().GetPlaylist(PLAYLIST_MUSIC);
531   if (playlist.size() < 1)
532     return false;
533 
534   int index = info.GetData2();
535   if (info.GetData1() == 1)
536   { // relative index (requires current playlist is PLAYLIST_MUSIC)
537     if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() != PLAYLIST_MUSIC)
538       return false;
539 
540     index = CServiceBroker::GetPlaylistPlayer().GetNextSong(index);
541   }
542 
543   if (index < 0 || index >= playlist.size())
544     return false;
545 
546   const CFileItemPtr playlistItem = playlist[index];
547   if (playlistItem->HasMusicInfoTag() && !playlistItem->GetMusicInfoTag()->Loaded())
548   {
549     playlistItem->LoadMusicTag();
550     playlistItem->GetMusicInfoTag()->SetLoaded();
551   }
552   // try to set a thumbnail
553   if (!playlistItem->HasArt("thumb"))
554   {
555     CMusicThumbLoader loader;
556     loader.LoadItem(playlistItem.get());
557     // still no thumb? then just the set the default cover
558     if (!playlistItem->HasArt("thumb"))
559       playlistItem->SetArt("thumb", "DefaultAlbumCover.png");
560   }
561   if (info.m_info == MUSICPLAYER_PLAYLISTPOS)
562   {
563     value = StringUtils::Format("%i", index + 1);
564     return true;
565   }
566   else if (info.m_info == MUSICPLAYER_COVER)
567   {
568     value = playlistItem->GetArt("thumb");
569     return true;
570   }
571 
572   return GetLabel(value, playlistItem.get(), 0, CGUIInfo(info.m_info), nullptr);
573 }
574 
GetFallbackLabel(std::string & value,const CFileItem * item,int contextWindow,const CGUIInfo & info,std::string * fallback)575 bool CMusicGUIInfo::GetFallbackLabel(std::string& value,
576                                      const CFileItem* item,
577                                      int contextWindow,
578                                      const CGUIInfo& info,
579                                      std::string* fallback)
580 {
581   // No fallback for musicplayer "offset" and "position" info labels
582   if (info.GetData1() && ((info.m_info >= MUSICPLAYER_OFFSET_POSITION_FIRST &&
583       info.m_info <= MUSICPLAYER_OFFSET_POSITION_LAST) ||
584       (info.m_info >= PLAYER_OFFSET_POSITION_FIRST && info.m_info <= PLAYER_OFFSET_POSITION_LAST)))
585     return false;
586 
587   const CMusicInfoTag* tag = item->GetMusicInfoTag();
588   if (tag)
589   {
590     switch (info.m_info)
591     {
592       /////////////////////////////////////////////////////////////////////////////////////////////
593       // MUSICPLAYER_*
594       /////////////////////////////////////////////////////////////////////////////////////////////
595       case MUSICPLAYER_TITLE:
596         value = item->GetLabel();
597         if (value.empty())
598           value = CUtil::GetTitleFromPath(item->GetPath());
599         return true;
600       default:
601         break;
602     }
603   }
604   return false;
605 }
606 
GetInt(int & value,const CGUIListItem * gitem,int contextWindow,const CGUIInfo & info) const607 bool CMusicGUIInfo::GetInt(int& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
608 {
609   return false;
610 }
611 
GetBool(bool & value,const CGUIListItem * gitem,int contextWindow,const CGUIInfo & info) const612 bool CMusicGUIInfo::GetBool(bool& value, const CGUIListItem *gitem, int contextWindow, const CGUIInfo &info) const
613 {
614   const CFileItem* item = static_cast<const CFileItem*>(gitem);
615   const CMusicInfoTag* tag = item->GetMusicInfoTag();
616 
617   switch (info.m_info)
618   {
619     ///////////////////////////////////////////////////////////////////////////////////////////////
620     // MUSICPLAYER_*
621     ///////////////////////////////////////////////////////////////////////////////////////////////
622     case MUSICPLAYER_CONTENT:
623       value = StringUtils::EqualsNoCase(info.GetData3(), "files");
624       return value; // if no match for this provider, other providers shall be asked.
625     case MUSICPLAYER_HASPREVIOUS:
626       // requires current playlist be PLAYLIST_MUSIC
627       if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST_MUSIC)
628       {
629         value = (CServiceBroker::GetPlaylistPlayer().GetCurrentSong() > 0); // not first song
630         return true;
631       }
632       break;
633     case MUSICPLAYER_HASNEXT:
634       // requires current playlist be PLAYLIST_MUSIC
635       if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST_MUSIC)
636       {
637         value = (CServiceBroker::GetPlaylistPlayer().GetCurrentSong() < (CServiceBroker::GetPlaylistPlayer().GetPlaylist(PLAYLIST_MUSIC).size() - 1)); // not last song
638         return true;
639       }
640       break;
641     case MUSICPLAYER_PLAYLISTPLAYING:
642       if (g_application.GetAppPlayer().IsPlayingAudio() && CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() == PLAYLIST_MUSIC)
643       {
644         value = true;
645         return true;
646       }
647       break;
648     case MUSICPLAYER_EXISTS:
649     {
650       int index = info.GetData2();
651       if (info.GetData1() == 1)
652       { // relative index
653         if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() != PLAYLIST_MUSIC)
654         {
655           value = false;
656           return true;
657         }
658         index += CServiceBroker::GetPlaylistPlayer().GetCurrentSong();
659       }
660       value = (index >= 0 && index < CServiceBroker::GetPlaylistPlayer().GetPlaylist(PLAYLIST_MUSIC).size());
661       return true;
662     }
663     case MUSICPLAYER_ISMULTIDISC:
664       if (tag)
665       {
666         value = (item->GetMusicInfoTag()->GetTotalDiscs() > 1);
667         return true;
668       }
669       break;
670     ///////////////////////////////////////////////////////////////////////////////////////////////
671     // MUSICPM_*
672     ///////////////////////////////////////////////////////////////////////////////////////////////
673     case MUSICPM_ENABLED:
674       value = g_partyModeManager.IsEnabled();
675       return true;
676 
677     ///////////////////////////////////////////////////////////////////////////////////////////////
678     // LISTITEM_*
679     ///////////////////////////////////////////////////////////////////////////////////////////////
680     case LISTITEM_IS_BOXSET:
681       if (tag)
682       {
683         value = tag->GetBoxset() == true;
684         return true;
685       }
686       break;
687   }
688 
689   return false;
690 }
691