Exemplo n.º 1
0
bool CFileItemHandler::GetField(const std::string &field, const CVariant &info, const CFileItemPtr &item, CVariant &result, bool &fetchedArt, CThumbLoader *thumbLoader /* = NULL */)
{
  if (result.isMember(field) && !result[field].empty())
    return true;

  // overwrite serialized values
  if (item)
  {
    if (field == "mimetype" && item->GetMimeType().empty())
    {
      item->FillInMimeType(false);
      result[field] = item->GetMimeType();
      return true;
    }
  }

  // check for serialized values
  if (info.isMember(field) && !info[field].isNull())
  {
    result[field] = info[field];
    return true;
  }

  // check if the field requires special handling
  if (item)
  {
    if (item->IsAlbum())
    {
      if (field == "albumlabel")
      {
        result[field] = item->GetProperty("album_label");
        return true;
      }
      if (item->HasProperty("album_" + field + "_array"))
      {
        result[field] = item->GetProperty("album_" + field + "_array");
        return true;
      }
      if (item->HasProperty("album_" + field))
      {
        result[field] = item->GetProperty("album_" + field);
        return true;
      }
    }
    
    if (item->HasProperty("artist_" + field + "_array"))
    {
      result[field] = item->GetProperty("artist_" + field + "_array");
      return true;
    }
    if (item->HasProperty("artist_" + field))
    {
      result[field] = item->GetProperty("artist_" + field);
      return true;
    }

    if (field == "art")
    {
      if (thumbLoader != NULL && item->GetArt().size() <= 0 && !fetchedArt &&
        ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
      {
        thumbLoader->FillLibraryArt(*item);
        fetchedArt = true;
      }

      CGUIListItem::ArtMap artMap = item->GetArt();
      CVariant artObj(CVariant::VariantTypeObject);
      for (CGUIListItem::ArtMap::const_iterator artIt = artMap.begin(); artIt != artMap.end(); ++artIt)
      {
        if (!artIt->second.empty())
          artObj[artIt->first] = CTextureCache::GetWrappedImageURL(artIt->second);
      }

      result["art"] = artObj;
      return true;
    }
    
    if (field == "thumbnail")
    {
      if (thumbLoader != NULL && !item->HasArt("thumb") && !fetchedArt &&
        ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
      {
        thumbLoader->FillLibraryArt(*item);
        fetchedArt = true;
      }
      else if (item->HasPictureInfoTag() && !item->HasArt("thumb"))
        item->SetArt("thumb", CTextureCache::GetWrappedThumbURL(item->GetPath()));
      
      if (item->HasArt("thumb"))
        result["thumbnail"] = CTextureCache::GetWrappedImageURL(item->GetArt("thumb"));
      else
        result["thumbnail"] = "";
      
      return true;
    }
    
    if (field == "fanart")
    {
      if (thumbLoader != NULL && !item->HasArt("fanart") && !fetchedArt &&
        ((item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > -1) || (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetDatabaseId() > -1)))
      {
        thumbLoader->FillLibraryArt(*item);
        fetchedArt = true;
      }
      
      if (item->HasArt("fanart"))
        result["fanart"] = CTextureCache::GetWrappedImageURL(item->GetArt("fanart"));
      else
        result["fanart"] = "";
      
      return true;
    }
    
    if (item->HasVideoInfoTag() && item->GetVideoContentType() == VIDEODB_CONTENT_TVSHOWS)
    {
      if (item->GetVideoInfoTag()->m_iSeason < 0 && field == "season")
      {
        result[field] = (int)item->GetProperty("totalseasons").asInteger();
        return true;
      }
      if (field == "watchedepisodes")
      {
        result[field] = (int)item->GetProperty("watchedepisodes").asInteger();
        return true;
      }
    }
    
    if (field == "lastmodified" && item->m_dateTime.IsValid())
    {
      result[field] = item->m_dateTime.GetAsLocalizedDateTime();
      return true;
    }

    if (item->HasProperty(field))
    {
      result[field] = item->GetProperty(field);
      return true;
    }
  }

  return false;
}
Exemplo n.º 2
0
JSONRPC_STATUS CAudioLibrary::GetSongs(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
{
  CMusicDatabase musicdatabase;
  if (!musicdatabase.Open())
    return InternalError;

  CMusicDbUrl musicUrl;
  if (!musicUrl.FromString("musicdb://songs/"))
    return InternalError;

  if (parameterObject["singlesonly"].asBoolean())
    musicUrl.AddOption("singles", true);
  else if (!parameterObject["includesingles"].asBoolean())
    musicUrl.AddOption("singles", false);

  bool allroles = false;
  if (parameterObject["allroles"].isBoolean())
    allroles = parameterObject["allroles"].asBoolean();

  const CVariant &filter = parameterObject["filter"];

  if (allroles)
    musicUrl.AddOption("roleid", -1000); //All roles, override implicit roleid=1 filter required for backward compatibility
  else if (filter.isMember("roleid"))
    musicUrl.AddOption("roleid", static_cast<int>(filter["roleid"].asInteger()));
  else if (filter.isMember("role"))
    musicUrl.AddOption("role", filter["role"].asString());
  // Only one of genreid/genre, artistid/artist, albumid/album or rules type filter is allowed by filter syntax
  if (filter.isMember("artistid"))
    musicUrl.AddOption("artistid", static_cast<int>(filter["artistid"].asInteger()));
  else if (filter.isMember("artist"))
    musicUrl.AddOption("artist", filter["artist"].asString());
  else if (filter.isMember("genreid"))
    musicUrl.AddOption("genreid", static_cast<int>(filter["genreid"].asInteger()));
  else if (filter.isMember("genre"))
    musicUrl.AddOption("genre", filter["genre"].asString());
  else if (filter.isMember("albumid"))
    musicUrl.AddOption("albumid", static_cast<int>(filter["albumid"].asInteger()));
  else if (filter.isMember("album"))
    musicUrl.AddOption("album", filter["album"].asString());
  else if (filter.isObject())
  {
    std::string xsp;
    if (!GetXspFiltering("songs", filter, xsp))
      return InvalidParams;

    musicUrl.AddOption("xsp", xsp);
  }

  SortDescription sorting;
  ParseLimits(parameterObject, sorting.limitStart, sorting.limitEnd);
  if (!ParseSorting(parameterObject, sorting.sortBy, sorting.sortOrder, sorting.sortAttributes))
    return InvalidParams;

  int total;
  std::set<std::string> fields;
  if (parameterObject.isMember("properties") && parameterObject["properties"].isArray())
  {
    for (CVariant::const_iterator_array field = parameterObject["properties"].begin_array();
      field != parameterObject["properties"].end_array(); field++)
      fields.insert(field->asString());
  }

  if (!musicdatabase.GetSongsByWhereJSON(fields, musicUrl.ToString(), result, total, sorting))
    return InternalError;

  if (!result.isNull())
  {
    bool bFetchArt = fields.find("art") != fields.end();
    bool bFetchFanart = fields.find("fanart") != fields.end();
    bool bFetchThumb = fields.find("thumbnail") != fields.end();
    if (bFetchArt || bFetchFanart || bFetchThumb)
    {
      CThumbLoader* thumbLoader = new CMusicThumbLoader();
      thumbLoader->OnLoaderStart();

      std::set<std::string> artfields;
      if (bFetchArt)
        artfields.insert("art");
      if (bFetchFanart)
        artfields.insert("fanart");
      if (bFetchThumb)
        artfields.insert("thumbnail");

      for (unsigned int index = 0; index < result["songs"].size(); index++)
      {
        CFileItem item;
        // Only needs song and album id (if we have it) set to get art
        // Getting art is quicker if "albumid" has been fetched
        item.GetMusicInfoTag()->SetDatabaseId(result["songs"][index]["songid"].asInteger(), MediaTypeSong);
        if (result["songs"][index].isMember("albumid"))
          item.GetMusicInfoTag()->SetAlbumId(result["songs"][index]["albumid"].asInteger());
        else
          item.GetMusicInfoTag()->SetAlbumId(-1);

        // Could use FillDetails, but it does unnecessary serialization of empty MusiInfoTag
        // CFileItemPtr itemptr(new CFileItem(item));
        // FillDetails(item.GetMusicInfoTag(), itemptr, artfields, result["songs"][index], thumbLoader);

        thumbLoader->FillLibraryArt(item);

        if (bFetchThumb)
        {
          if (item.HasArt("thumb"))
            result["songs"][index]["thumbnail"] = CTextureUtils::GetWrappedImageURL(item.GetArt("thumb"));
          else
            result["songs"][index]["thumbnail"] = "";
        }
        if (bFetchFanart)
        {
          if (item.HasArt("fanart"))
            result["songs"][index]["fanart"] = CTextureUtils::GetWrappedImageURL(item.GetArt("fanart"));
          else
            result["songs"][index]["fanart"] = "";
        }
        if (bFetchArt)
        {
          CGUIListItem::ArtMap artMap = item.GetArt();
          CVariant artObj(CVariant::VariantTypeObject);
          for (CGUIListItem::ArtMap::const_iterator artIt = artMap.begin(); artIt != artMap.end(); ++artIt)
          {
            if (!artIt->second.empty())
              artObj[artIt->first] = CTextureUtils::GetWrappedImageURL(artIt->second);
          }
          result["songs"][index]["art"] = artObj;
        }
      }

      delete thumbLoader;
    }
  }

  int start, end;
  HandleLimits(parameterObject, result, total, start, end);
  
  return OK;
}
Exemplo n.º 3
0
void CGUIDialogVideoInfo::SetMovie(const CFileItem *item)
{
  *m_movieItem = *item;
  // setup cast list + determine type.  We need to do this here as it makes
  // sure that content type (among other things) is set correctly for the
  // old fixed id labels that we have floating around (they may be using
  // content type to determine visibility, so we'll set the wrong label)
  ClearCastList();
  VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)m_movieItem->GetVideoContentType();
  if (type == VIDEODB_CONTENT_MUSICVIDEOS)
  { // music video
    CMusicDatabase database;
    database.Open();
    const std::vector<std::string> &artists = m_movieItem->GetVideoInfoTag()->m_artist;
    for (std::vector<std::string>::const_iterator it = artists.begin(); it != artists.end(); ++it)
    {
      int idArtist = database.GetArtistByName(*it);
      CStdString thumb = database.GetArtForItem(idArtist, "artist", "thumb");
      CFileItemPtr item(new CFileItem(*it));
      if (!thumb.empty())
        item->SetArt("thumb", thumb);
      item->SetIconImage("DefaultArtist.png");
      m_castList->Add(item);
    }
    m_castList->SetContent("musicvideos");
  }
  else
  { // movie/show/episode
    for (CVideoInfoTag::iCast it = m_movieItem->GetVideoInfoTag()->m_cast.begin(); it != m_movieItem->GetVideoInfoTag()->m_cast.end(); ++it)
    {
      CStdString character;
      if (it->strRole.IsEmpty())
        character = it->strName;
      else
        character.Format("%s %s %s", it->strName.c_str(), g_localizeStrings.Get(20347).c_str(), it->strRole.c_str());
      CFileItemPtr item(new CFileItem(it->strName));
      if (!it->thumb.IsEmpty())
        item->SetArt("thumb", it->thumb);
      else if (g_guiSettings.GetBool("videolibrary.actorthumbs"))
      { // backward compatibility
        CStdString thumb = CScraperUrl::GetThumbURL(it->thumbUrl.GetFirstThumb());
        if (!thumb.IsEmpty())
        {
          item->SetArt("thumb", thumb);
          CTextureCache::Get().BackgroundCacheImage(thumb);
        }
      }
      item->SetIconImage("DefaultActor.png");
      item->SetLabel(character);
      m_castList->Add(item);
    }
    // determine type:
    if (type == VIDEODB_CONTENT_TVSHOWS)
    {
      m_castList->SetContent("tvshows");
      // special case stuff for shows (not currently retrieved from the library in filemode (ref: GetTvShowInfo vs GetTVShowsByWhere)
      m_movieItem->m_dateTime = m_movieItem->GetVideoInfoTag()->m_premiered;
      if(m_movieItem->GetVideoInfoTag()->m_iYear == 0 && m_movieItem->m_dateTime.IsValid())
        m_movieItem->GetVideoInfoTag()->m_iYear = m_movieItem->m_dateTime.GetYear();
      m_movieItem->SetProperty("totalepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode);
      m_movieItem->SetProperty("numepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode); // info view has no concept of current watched/unwatched filter as we could come here from files view, but set for consistency
      m_movieItem->SetProperty("watchedepisodes", m_movieItem->GetVideoInfoTag()->m_playCount);
      m_movieItem->SetProperty("unwatchedepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode - m_movieItem->GetVideoInfoTag()->m_playCount);
      m_movieItem->GetVideoInfoTag()->m_playCount = (m_movieItem->GetVideoInfoTag()->m_iEpisode == m_movieItem->GetVideoInfoTag()->m_playCount) ? 1 : 0;
    }
    else if (type == VIDEODB_CONTENT_EPISODES)
    {
      m_castList->SetContent("episodes");
      // special case stuff for episodes (not currently retrieved from the library in filemode (ref: GetEpisodeInfo vs GetEpisodesByWhere)
      m_movieItem->m_dateTime = m_movieItem->GetVideoInfoTag()->m_firstAired;
      if(m_movieItem->GetVideoInfoTag()->m_iYear == 0 && m_movieItem->m_dateTime.IsValid())
        m_movieItem->GetVideoInfoTag()->m_iYear = m_movieItem->m_dateTime.GetYear();
      // retrieve the season thumb.
      // TODO: should we use the thumbloader for this?
      CVideoDatabase db;
      if (db.Open())
      {
        if (m_movieItem->GetVideoInfoTag()->m_iSeason > -1)
        {
          int seasonID = m_movieItem->GetVideoInfoTag()->m_iIdSeason;
          if (seasonID < 0)
            seasonID = db.GetSeasonId(m_movieItem->GetVideoInfoTag()->m_iIdShow,
                                      m_movieItem->GetVideoInfoTag()->m_iSeason);
          CGUIListItem::ArtMap thumbs;
          if (db.GetArtForItem(seasonID, "season", thumbs))
          {
            for (CGUIListItem::ArtMap::iterator i = thumbs.begin(); i != thumbs.end(); i++)
              m_movieItem->SetArt("season." + i->first, i->second);
          }
        }
        db.Close();
      }
    }
    else if (type == VIDEODB_CONTENT_MOVIES)
    {
      m_castList->SetContent("movies");

      // local trailers should always override non-local, so check 
      // for a local one if the registered trailer is online
      if (m_movieItem->GetVideoInfoTag()->m_strTrailer.IsEmpty() ||
          URIUtils::IsInternetStream(m_movieItem->GetVideoInfoTag()->m_strTrailer))
      {
        CStdString localTrailer = m_movieItem->FindTrailer();
        if (!localTrailer.IsEmpty())
        {
          m_movieItem->GetVideoInfoTag()->m_strTrailer = localTrailer;
          CVideoDatabase database;
          if(database.Open())
          {
            database.SetDetail(m_movieItem->GetVideoInfoTag()->m_strTrailer,
                               m_movieItem->GetVideoInfoTag()->m_iDbId,
                               VIDEODB_ID_TRAILER, VIDEODB_CONTENT_MOVIES);
            database.Close();
            CUtil::DeleteVideoDatabaseDirectoryCache();
          }
        }
      }
    }
  }
  CVideoThumbLoader loader;
  loader.LoadItem(m_movieItem.get());
}
Exemplo n.º 4
0
/*
Allow user to choose artwork for the artist or album
For each type of art the options are:
1.  Current art
2.  Local art (thumb found by filename)
3.  Remote art (scraped list of urls from online sources e.g. fanart.tv)
5.  Embedded art (@todo)
6.  None
*/
void CGUIDialogMusicInfo::OnGetArt()
{
  std::string type = MUSIC_UTILS::ShowSelectArtTypeDialog(m_artTypeList);
  if (type.empty())
    return; // Cancelled

  CFileItemList items;
  CGUIListItem::ArtMap primeArt = m_item->GetArt(); // art without fallbacks
  bool bHasArt = m_item->HasArt(type);
  bool bFallback(false);
  if (bHasArt)
  {
    // Check if that type of art is actually a fallback, e.g. artist fanart
    CGUIListItem::ArtMap::const_iterator i = primeArt.find(type);
    bFallback = (i == primeArt.end());
  }

  // Build list of possible images of that art type
  if (bHasArt)
  {
    // Add item for current artwork
    // For album it could be a fallback from artist
    CFileItemPtr item(new CFileItem("thumb://Current", false));
    item->SetArt("thumb", m_item->GetArt(type));
    item->SetIconImage("DefaultPicture.png");
    item->SetLabel(g_localizeStrings.Get(13512));
    items.Add(item);
  }
  else if (m_item->HasArt("thumb"))
  {
    // For missing art of that type add the thumb (when it exists and not a fallback)
    CGUIListItem::ArtMap::const_iterator i = primeArt.find("thumb");
    if (i != primeArt.end())
    {
      CFileItemPtr item(new CFileItem("thumb://Thumb", false));
      item->SetArt("thumb", m_item->GetArt("thumb"));
      if (m_bArtistInfo)
        item->SetIconImage("DefaultArtistCover.png");
      else
        item->SetIconImage("DefaultAlbumCover.png");
      item->SetLabel(g_localizeStrings.Get(21371));
      items.Add(item);
    }
  }

 // Grab the thumbnails of this art type scraped from the web
  std::vector<std::string> remotethumbs;
  if (type == "fanart" && m_bArtistInfo)
  {
    // Scraped artist fanart URLs are held separately from other art types
    //! @todo Change once scraping all art types is unified
    for (unsigned int i = 0; i < m_artist.fanart.GetNumFanarts(); i++)
    {
      std::string strItemPath;
      strItemPath = StringUtils::Format("fanart://Remote%i", i);
      CFileItemPtr item(new CFileItem(strItemPath, false));
      // Preview "thumb" of fanart image for browsing
      std::string thumb = m_artist.fanart.GetPreviewURL(i);
      std::string wrappedthumb = CTextureUtils::GetWrappedThumbURL(thumb);
      item->SetArt("thumb", wrappedthumb);
      item->SetIconImage("DefaultPicture.png");
      item->SetLabel(g_localizeStrings.Get(20441));

      items.Add(item);
    }
  }
  else
  {
    // Art type is encoded into the scraper XML as optional "aspect=" field
    // Type "thumb" returns URLs for all types of art including those without aspect.
    // Those URL without aspect are also returned for all other type values.
    if (m_bArtistInfo)
      m_artist.thumbURL.GetThumbURLs(remotethumbs, type);
    else
      m_album.thumbURL.GetThumbURLs(remotethumbs, type);

    for (unsigned int i = 0; i < remotethumbs.size(); ++i)
    {
      std::string strItemPath;
      strItemPath = StringUtils::Format("thumb://Remote%i", i);
      CFileItemPtr item(new CFileItem(strItemPath, false));
      item->SetArt("thumb", remotethumbs[i]);
      item->SetIconImage("DefaultPicture.png");
      item->SetLabel(g_localizeStrings.Get(13513));

      items.Add(item);
    }
  }

  // Local art
  std::string localArt;
  std::vector<std::string> paths;
  if (m_bArtistInfo)
  {
    // Individual artist subfolder within the Artist Information Folder
    paths.emplace_back(m_artist.strPath);
    // Fallback local to music files (when there is a unique folder)
    paths.emplace_back(m_fallbackartpath);
  }
  else
    // Album folder, when a unique one exists, no fallback
    paths.emplace_back(m_album.strPath);
  for (const auto& path : paths)
  {
    if (!localArt.empty() && CFile::Exists(localArt))
      break;
    if (!path.empty())
    {
      CFileItem item(path, true);
      if (type == "thumb")
        // Local music thumbnail images named by <musicthumbs>
        localArt = item.GetUserMusicThumb(true);
      else if (type == "fanart")
        // Local fanart images named by <fanart>
        localArt = item.GetLocalFanart();
      else
      { // Check case and ext insenitively for local images with type as name
        // e.g. <arttype>.jpg
        CFileItemList items;
        CDirectory::GetDirectory(path, items,
            CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(),
            DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_READ_CACHE | DIR_FLAG_NO_FILE_INFO);

        for (int j = 0; j < items.Size(); j++)
        {
          std::string strCandidate = URIUtils::GetFileName(items[j]->GetPath());
          URIUtils::RemoveExtension(strCandidate);
          if (StringUtils::EqualsNoCase(strCandidate, type))
          {
            localArt = items[j]->GetPath();
            break;
          }
        }
      }
    }
  }
  if (!localArt.empty() && CFile::Exists(localArt))
  {
    CFileItemPtr item(new CFileItem("Local Art: " + localArt, false));
    item->SetArt("thumb", localArt);
    item->SetLabel(g_localizeStrings.Get(13514)); // "Local art"
    items.Add(item);
  }

  // No art
  if (bHasArt && !bFallback)
  { // Actually has this type of art (not a fallback) so
    // allow the user to delete it by selecting "no art".
    CFileItemPtr item(new CFileItem("thumb://None", false));
    if (m_bArtistInfo)
      item->SetIconImage("DefaultArtist.png");
    else
      item->SetIconImage("DefaultAlbumCover.png");
    item->SetLabel(g_localizeStrings.Get(13515));
    items.Add(item);
  }

  //! @todo: Add support for extracting embedded art from song files to use for album

  // Clear local images of this type from cache so user will see any recent
  // local file changes immediately
  for (auto& item : items)
  {
    // Skip images from remote sources, recache done by refresh (could be slow)
    if (StringUtils::StartsWith(item->GetPath(), "fanart://Remote") ||
        StringUtils::StartsWith(item->GetPath(), "thumb://Remote"))
      continue;
    std::string thumb(item->GetArt("thumb"));
    if (thumb.empty())
      continue;
    CURL url(CTextureUtils::UnwrapImageURL(thumb));
    // Skip images from remote sources (current thumb could be remote)
    if (url.IsProtocol("http") || url.IsProtocol("https"))
      continue;
    CTextureCache::GetInstance().ClearCachedImage(thumb);
    // Remove any thumbnail of local image too (created when browsing files)
    std::string thumbthumb(CTextureUtils::GetWrappedThumbURL(thumb));
    CTextureCache::GetInstance().ClearCachedImage(thumbthumb);
  }

  // Show list of possible art for user selection
  // Note that during selection thumbs of *all* images shown are cached. When
  // browsing folders there could be many irrelevant thumbs cached that are
  // never used by Kodi again, but there is no obvious way to clear these
  // thumbs from the cache automatically.
  std::string result;
  VECSOURCES sources(*CMediaSourceSettings::GetInstance().GetSources("music"));
  CGUIDialogMusicInfo::AddItemPathToFileBrowserSources(sources, *m_item);
  g_mediaManager.GetLocalDrives(sources);
  if (CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(13511), result) &&
    result != "thumb://Current")
  {
    // User didn't choose the one they have.
    // Overwrite with the new art or clear it
    std::string newArt;
    if (StringUtils::StartsWith(result, "thumb://Remote"))
    {
      int number = atoi(result.substr(14).c_str());
      newArt = remotethumbs[number];
    }
    else if (StringUtils::StartsWith(result, "fanart://Remote"))
    {
      int iFanart = atoi(result.substr(15).c_str());
      m_artist.fanart.SetPrimaryFanart(iFanart);
      newArt = m_artist.fanart.GetImageURL();
    }
    else if (result == "thumb://Thumb")
      newArt = m_item->GetArt("thumb");
    else if (StringUtils::StartsWith(result, "Local Art: "))
      newArt = localArt;
    else if (CFile::Exists(result))
      newArt = result;
    else // none
      newArt.clear();

    // Asynchronously update that type of art in the database and then
    // refresh artist, album and fallback art of currently playing song
    MUSIC_UTILS::UpdateArtJob(m_item, type, newArt);

    // Update local item and art list with current art
    m_item->SetArt(type, newArt);
    for (const auto artitem : m_artTypeList)
    {
      if (artitem->GetProperty("artType") == type)
      {
        artitem->SetArt("thumb", newArt);
        break;
      }
    }

    // Get new artwork to show in other places e.g. on music lib window, but this does
    // not update artist, album or fallback art for the currently playing song as it
    // is a different item with different ID and media type
    CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_ITEM, 0, m_item);
    CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
  }

  // Re-open the art type selection dialog as we come back from
  // the image selection dialog
  OnGetArt();
}