summaryrefslogtreecommitdiffstats
path: root/xbmc/interfaces/legacy/ListItem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/interfaces/legacy/ListItem.cpp')
-rw-r--r--xbmc/interfaces/legacy/ListItem.cpp1056
1 files changed, 1056 insertions, 0 deletions
diff --git a/xbmc/interfaces/legacy/ListItem.cpp b/xbmc/interfaces/legacy/ListItem.cpp
new file mode 100644
index 0000000..64410ad
--- /dev/null
+++ b/xbmc/interfaces/legacy/ListItem.cpp
@@ -0,0 +1,1056 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "ListItem.h"
+
+#include "AddonUtils.h"
+#include "ServiceBroker.h"
+#include "Util.h"
+#include "games/GameTypes.h"
+#include "games/tags/GameInfoTag.h"
+#include "music/tags/MusicInfoTag.h"
+#include "pictures/PictureInfoTag.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
+#include "video/VideoInfoTag.h"
+
+#include <cstdlib>
+#include <sstream>
+#include <utility>
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ ListItem::ListItem(const String& label,
+ const String& label2,
+ const String& path,
+ bool offscreen) :
+ m_offscreen(offscreen)
+ {
+ item.reset();
+
+ // create CFileItem
+ item.reset(new CFileItem());
+ if (!item) // not sure if this is really possible
+ return;
+
+ if (!label.empty())
+ item->SetLabel( label );
+ if (!label2.empty())
+ item->SetLabel2( label2 );
+ if (!path.empty())
+ item->SetPath(path);
+ }
+
+ ListItem::~ListItem()
+ {
+ item.reset();
+ }
+
+ String ListItem::getLabel()
+ {
+ if (!item) return "";
+
+ String ret;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ ret = item->GetLabel();
+ }
+
+ return ret;
+ }
+
+ String ListItem::getLabel2()
+ {
+ if (!item) return "";
+
+ String ret;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ ret = item->GetLabel2();
+ }
+
+ return ret;
+ }
+
+ void ListItem::setLabel(const String& label)
+ {
+ if (!item) return;
+ // set label
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ item->SetLabel(label);
+ }
+ }
+
+ void ListItem::setLabel2(const String& label)
+ {
+ if (!item) return;
+ // set label
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ item->SetLabel2(label);
+ }
+ }
+
+ String ListItem::getDateTime()
+ {
+ if (!item)
+ return "";
+
+ String ret;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ if (item->m_dateTime.IsValid())
+ ret = item->m_dateTime.GetAsW3CDateTime();
+ }
+
+ return ret;
+ }
+
+ void ListItem::setDateTime(const String& dateTime)
+ {
+ if (!item)
+ return;
+ // set datetime
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ setDateTimeRaw(dateTime);
+ }
+ }
+
+ void ListItem::setArt(const Properties& dictionary)
+ {
+ if (!item) return;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ for (const auto& it : dictionary)
+ addArtRaw(it.first, it.second);
+ }
+ }
+
+ void ListItem::setIsFolder(bool isFolder)
+ {
+ if (!item)
+ return;
+
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ setIsFolderRaw(isFolder);
+ }
+ }
+
+ void ListItem::setUniqueIDs(const Properties& dictionary, const String& defaultrating /* = "" */)
+ {
+ CLog::Log(
+ LOGWARNING,
+ "ListItem.setUniqueIDs() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.setUniqueIDs().");
+
+ if (!item)
+ return;
+
+ std::map<String, String> uniqueIDs;
+ for (const auto& it : dictionary)
+ uniqueIDs.emplace(it.first, it.second);
+
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ xbmc::InfoTagVideo::setUniqueIDsRaw(GetVideoInfoTag(), uniqueIDs, defaultrating);
+ }
+ }
+
+ void ListItem::setRating(const std::string& type,
+ float rating,
+ int votes /* = 0 */,
+ bool defaultt /* = false */)
+ {
+ CLog::Log(LOGWARNING,
+ "ListItem.setRating() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.setRating().");
+
+ if (!item) return;
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ xbmc::InfoTagVideo::setRatingRaw(GetVideoInfoTag(), rating, votes, type, defaultt);
+ }
+
+ void ListItem::addSeason(int number, std::string name /* = "" */)
+ {
+ CLog::Log(LOGWARNING,
+ "ListItem.addSeason() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.addSeason().");
+
+ if (!item) return;
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ xbmc::InfoTagVideo::addSeasonRaw(GetVideoInfoTag(), number, std::move(name));
+ }
+
+ void ListItem::select(bool selected)
+ {
+ if (!item) return;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ item->Select(selected);
+ }
+ }
+
+
+ bool ListItem::isSelected()
+ {
+ if (!item) return false;
+
+ bool ret;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ ret = item->IsSelected();
+ }
+
+ return ret;
+ }
+
+ void ListItem::setProperty(const char * key, const String& value)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ String lowerKey = key;
+ StringUtils::ToLower(lowerKey);
+ if (lowerKey == "startoffset")
+ { // special case for start offset - don't actually store in a property
+ setStartOffsetRaw(strtod(value.c_str(), nullptr));
+ }
+ else if (lowerKey == "mimetype")
+ { // special case for mime type - don't actually stored in a property,
+ item->SetMimeType(value);
+ }
+ else if (lowerKey == "totaltime")
+ {
+ CLog::Log(LOGWARNING,
+ "\"{}\" in ListItem.setProperty() is deprecated and might be removed in future "
+ "Kodi versions. Please use InfoTagVideo.setResumePoint().",
+ lowerKey);
+
+ CBookmark resumePoint(GetVideoInfoTag()->GetResumePoint());
+ resumePoint.totalTimeInSeconds = atof(value.c_str());
+ GetVideoInfoTag()->SetResumePoint(resumePoint);
+ }
+ else if (lowerKey == "resumetime")
+ {
+ CLog::Log(LOGWARNING,
+ "\"{}\" in ListItem.setProperty() is deprecated and might be removed in future "
+ "Kodi versions. Please use InfoTagVideo.setResumePoint().",
+ lowerKey);
+
+ xbmc::InfoTagVideo::setResumePointRaw(GetVideoInfoTag(), atof(value.c_str()));
+ }
+ else if (lowerKey == "specialsort")
+ setSpecialSortRaw(value);
+ else if (lowerKey == "fanart_image")
+ item->SetArt("fanart", value);
+ else
+ addPropertyRaw(lowerKey, value);
+ }
+
+ void ListItem::setProperties(const Properties& dictionary)
+ {
+ for (const auto& it : dictionary)
+ setProperty(it.first.c_str(), it.second);
+ }
+
+ String ListItem::getProperty(const char* key)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ String lowerKey = key;
+ StringUtils::ToLower(lowerKey);
+ std::string value;
+ if (lowerKey == "startoffset")
+ { // special case for start offset - don't actually store in a property,
+ // we store it in item.m_lStartOffset instead
+ value = StringUtils::Format("{:f}", CUtil::ConvertMilliSecsToSecs(item->GetStartOffset()));
+ }
+ else if (lowerKey == "totaltime")
+ {
+ CLog::Log(LOGWARNING,
+ "\"{}\" in ListItem.getProperty() is deprecated and might be removed in future "
+ "Kodi versions. Please use InfoTagVideo.getResumeTimeTotal().",
+ lowerKey);
+
+ value = StringUtils::Format("{:f}", GetVideoInfoTag()->GetResumePoint().totalTimeInSeconds);
+ }
+ else if (lowerKey == "resumetime")
+ {
+ CLog::Log(LOGWARNING,
+ "\"{}\" in ListItem.getProperty() is deprecated and might be removed in future "
+ "Kodi versions. Please use InfoTagVideo.getResumeTime().",
+ lowerKey);
+
+ value = StringUtils::Format("{:f}", GetVideoInfoTag()->GetResumePoint().timeInSeconds);
+ }
+ else if (lowerKey == "fanart_image")
+ value = item->GetArt("fanart");
+ else
+ value = item->GetProperty(lowerKey).asString();
+
+ return value;
+ }
+
+ String ListItem::getArt(const char* key)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return item->GetArt(key);
+ }
+
+ bool ListItem::isFolder() const
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return item->m_bIsFolder;
+ }
+
+ String ListItem::getUniqueID(const char* key)
+ {
+ CLog::Log(
+ LOGWARNING,
+ "ListItem.getUniqueID() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.getUniqueID().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return GetVideoInfoTag()->GetUniqueID(key);
+ }
+
+ float ListItem::getRating(const char* key)
+ {
+ CLog::Log(LOGWARNING,
+ "ListItem.getRating() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.getRating().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return GetVideoInfoTag()->GetRating(key).rating;
+ }
+
+ int ListItem::getVotes(const char* key)
+ {
+ CLog::Log(LOGWARNING,
+ "ListItem.getVotes() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.getVotesAsInt().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return GetVideoInfoTag()->GetRating(key).votes;
+ }
+
+ void ListItem::setPath(const String& path)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ setPathRaw(path);
+ }
+
+ void ListItem::setMimeType(const String& mimetype)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ setMimeTypeRaw(mimetype);
+ }
+
+ void ListItem::setContentLookup(bool enable)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ setContentLookupRaw(enable);
+ }
+
+ String ListItem::getPath()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return item->GetPath();
+ }
+
+ void ListItem::setInfo(const char* type, const InfoLabelDict& infoLabels)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+
+ bool hasDeprecatedInfoLabel = false;
+ if (StringUtils::CompareNoCase(type, "video") == 0)
+ {
+ using InfoTagVideo = xbmc::InfoTagVideo;
+ auto videotag = GetVideoInfoTag();
+ for (const auto& it : infoLabels)
+ {
+ const auto key = StringUtils::ToLower(it.first);
+ const InfoLabelValue& alt = it.second;
+ const String value(alt.which() == first ? alt.former() : emptyString);
+
+ if (key == "count")
+ setCountRaw(strtol(value.c_str(), nullptr, 10));
+ else if (key == "size")
+ setSizeRaw(static_cast<int64_t>(strtoll(value.c_str(), nullptr, 10)));
+ else if (key == "overlay")
+ {
+ long overlay = strtol(value.c_str(), nullptr, 10);
+ if (overlay >= 0 && overlay <= 8)
+ item->SetOverlayImage(static_cast<CGUIListItem::GUIIconOverlay>(overlay));
+ }
+ else if (key == "date")
+ setDateTimeRaw(value);
+ else
+ {
+ hasDeprecatedInfoLabel = true;
+
+ if (key == "dbid")
+ InfoTagVideo::setDbIdRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "year")
+ InfoTagVideo::setYearRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "episode")
+ InfoTagVideo::setEpisodeRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "season")
+ InfoTagVideo::setSeasonRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "sortepisode")
+ InfoTagVideo::setSortEpisodeRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "sortseason")
+ InfoTagVideo::setSortSeasonRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "episodeguide")
+ InfoTagVideo::setEpisodeGuideRaw(videotag, value);
+ else if (key == "showlink")
+ InfoTagVideo::setShowLinksRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "top250")
+ InfoTagVideo::setTop250Raw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "setid")
+ InfoTagVideo::setSetIdRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "tracknumber")
+ InfoTagVideo::setTrackNumberRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "rating")
+ InfoTagVideo::setRatingRaw(videotag,
+ static_cast<float>(strtod(value.c_str(), nullptr)));
+ else if (key == "userrating")
+ InfoTagVideo::setUserRatingRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "watched") // backward compat - do we need it?
+ InfoTagVideo::setPlaycountRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "playcount")
+ InfoTagVideo::setPlaycountRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "cast" || key == "castandrole")
+ {
+ if (alt.which() != second)
+ throw WrongTypeException("When using \"cast\" or \"castandrole\" you need to "
+ "supply a list of tuples for the value in the dictionary");
+
+ std::vector<SActorInfo> cast;
+ cast.reserve(alt.later().size());
+ for (const auto& castEntry : alt.later())
+ {
+ // castEntry can be a string meaning it's the actor or it can be a tuple meaning it's the
+ // actor and the role.
+ const String& actor =
+ castEntry.which() == first ? castEntry.former() : castEntry.later().first();
+ SActorInfo info;
+ info.strName = actor;
+ if (castEntry.which() == second)
+ info.strRole = static_cast<const String&>(castEntry.later().second());
+ cast.push_back(std::move(info));
+ }
+ InfoTagVideo::setCastRaw(videotag, std::move(cast));
+ }
+ else if (key == "artist")
+ {
+ if (alt.which() != second)
+ throw WrongTypeException("When using \"artist\" you need to supply a list of "
+ "strings for the value in the dictionary");
+
+ std::vector<String> artists;
+ artists.reserve(alt.later().size());
+ for (const auto& castEntry : alt.later())
+ {
+ auto actor =
+ castEntry.which() == first ? castEntry.former() : castEntry.later().first();
+ artists.push_back(std::move(actor));
+ }
+ InfoTagVideo::setArtistsRaw(videotag, artists);
+ }
+ else if (key == "genre")
+ InfoTagVideo::setGenresRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "country")
+ InfoTagVideo::setCountriesRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "director")
+ InfoTagVideo::setDirectorsRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "mpaa")
+ InfoTagVideo::setMpaaRaw(videotag, value);
+ else if (key == "plot")
+ InfoTagVideo::setPlotRaw(videotag, value);
+ else if (key == "plotoutline")
+ InfoTagVideo::setPlotOutlineRaw(videotag, value);
+ else if (key == "title")
+ InfoTagVideo::setTitleRaw(videotag, value);
+ else if (key == "originaltitle")
+ InfoTagVideo::setOriginalTitleRaw(videotag, value);
+ else if (key == "sorttitle")
+ InfoTagVideo::setSortTitleRaw(videotag, value);
+ else if (key == "duration")
+ InfoTagVideo::setDurationRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "studio")
+ InfoTagVideo::setStudiosRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "tagline")
+ InfoTagVideo::setTagLineRaw(videotag, value);
+ else if (key == "writer" || key == "credits")
+ InfoTagVideo::setWritersRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "tvshowtitle")
+ InfoTagVideo::setTvShowTitleRaw(videotag, value);
+ else if (key == "premiered")
+ InfoTagVideo::setPremieredRaw(videotag, value);
+ else if (key == "status")
+ InfoTagVideo::setTvShowStatusRaw(videotag, value);
+ else if (key == "set")
+ InfoTagVideo::setSetRaw(videotag, value);
+ else if (key == "setoverview")
+ InfoTagVideo::setSetOverviewRaw(videotag, value);
+ else if (key == "tag")
+ InfoTagVideo::setTagsRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "imdbnumber")
+ InfoTagVideo::setIMDBNumberRaw(videotag, value);
+ else if (key == "code")
+ InfoTagVideo::setProductionCodeRaw(videotag, value);
+ else if (key == "aired")
+ InfoTagVideo::setFirstAiredRaw(videotag, value);
+ else if (key == "lastplayed")
+ InfoTagVideo::setLastPlayedRaw(videotag, value);
+ else if (key == "album")
+ InfoTagVideo::setAlbumRaw(videotag, value);
+ else if (key == "votes")
+ InfoTagVideo::setVotesRaw(videotag, StringUtils::ReturnDigits(value));
+ else if (key == "trailer")
+ InfoTagVideo::setTrailerRaw(videotag, value);
+ else if (key == "path")
+ InfoTagVideo::setPathRaw(videotag, value);
+ else if (key == "filenameandpath")
+ InfoTagVideo::setFilenameAndPathRaw(videotag, value);
+ else if (key == "dateadded")
+ InfoTagVideo::setDateAddedRaw(videotag, value);
+ else if (key == "mediatype")
+ InfoTagVideo::setMediaTypeRaw(videotag, value);
+ else
+ CLog::Log(LOGERROR, "NEWADDON Unknown Video Info Key \"{}\"", key);
+ }
+ }
+
+ if (hasDeprecatedInfoLabel)
+ {
+ CLog::Log(
+ LOGWARNING,
+ "Setting most video properties through ListItem.setInfo() is deprecated and might be "
+ "removed in future Kodi versions. Please use the respective setter in InfoTagVideo.");
+ }
+ }
+ else if (StringUtils::CompareNoCase(type, "music") == 0)
+ {
+ String mediaType;
+ int dbId = -1;
+
+ using InfoTagMusic = xbmc::InfoTagMusic;
+ auto musictag = GetMusicInfoTag();
+ for (const auto& it : infoLabels)
+ {
+ const auto key = StringUtils::ToLower(it.first);
+ const auto& alt = it.second;
+ const String value(alt.which() == first ? alt.former() : emptyString);
+
+ //! @todo add the rest of the infolabels
+ if (key == "count")
+ setCountRaw(strtol(value.c_str(), nullptr, 10));
+ else if (key == "size")
+ setSizeRaw(static_cast<int64_t>(strtoll(value.c_str(), nullptr, 10)));
+ else if (key == "date")
+ setDateTimeRaw(value);
+ else
+ {
+ hasDeprecatedInfoLabel = true;
+
+ if (key == "dbid")
+ dbId = static_cast<int>(strtol(value.c_str(), NULL, 10));
+ else if (key == "mediatype")
+ mediaType = value;
+ else if (key == "tracknumber")
+ InfoTagMusic::setTrackRaw(musictag, strtol(value.c_str(), NULL, 10));
+ else if (key == "discnumber")
+ InfoTagMusic::setDiscRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "duration")
+ InfoTagMusic::setDurationRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "year")
+ InfoTagMusic::setYearRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "listeners")
+ InfoTagMusic::setListenersRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "playcount")
+ InfoTagMusic::setPlayCountRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "genre")
+ InfoTagMusic::setGenresRaw(musictag, getMusicStringArray(alt, key, value));
+ else if (key == "album")
+ InfoTagMusic::setAlbumRaw(musictag, value);
+ else if (key == "artist")
+ InfoTagMusic::setArtistRaw(musictag, value);
+ else if (key == "title")
+ InfoTagMusic::setTitleRaw(musictag, value);
+ else if (key == "rating")
+ InfoTagMusic::setRatingRaw(musictag,
+ static_cast<float>(strtod(value.c_str(), nullptr)));
+ else if (key == "userrating")
+ InfoTagMusic::setUserRatingRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "lyrics")
+ InfoTagMusic::setLyricsRaw(musictag, value);
+ else if (key == "lastplayed")
+ InfoTagMusic::setLastPlayedRaw(musictag, value);
+ else if (key == "musicbrainztrackid")
+ InfoTagMusic::setMusicBrainzTrackIDRaw(musictag, value);
+ else if (key == "musicbrainzartistid")
+ InfoTagMusic::setMusicBrainzArtistIDRaw(musictag,
+ getMusicStringArray(alt, key, value));
+ else if (key == "musicbrainzalbumid")
+ InfoTagMusic::setMusicBrainzAlbumIDRaw(musictag, value);
+ else if (key == "musicbrainzalbumartistid")
+ InfoTagMusic::setMusicBrainzAlbumArtistIDRaw(musictag,
+ getMusicStringArray(alt, key, value));
+ else if (key == "comment")
+ InfoTagMusic::setCommentRaw(musictag, value);
+ else
+ CLog::Log(LOGERROR, "NEWADDON Unknown Music Info Key \"{}\"", key);
+ }
+
+ // This should probably be set outside of the loop but since the original
+ // implementation set it inside of the loop, I'll leave it that way. - Jim C.
+ musictag->SetLoaded(true);
+ }
+
+ if (dbId > 0 && !mediaType.empty())
+ InfoTagMusic::setDbIdRaw(musictag, dbId, mediaType);
+
+ if (hasDeprecatedInfoLabel)
+ {
+ CLog::Log(
+ LOGWARNING,
+ "Setting most music properties through ListItem.setInfo() is deprecated and might be "
+ "removed in future Kodi versions. Please use the respective setter in InfoTagMusic.");
+ }
+ }
+ else if (StringUtils::CompareNoCase(type, "pictures") == 0)
+ {
+ for (const auto& it : infoLabels)
+ {
+ const auto key = StringUtils::ToLower(it.first);
+ const auto& alt = it.second;
+ const String value(alt.which() == first ? alt.former() : emptyString);
+
+ if (key == "count")
+ setCountRaw(strtol(value.c_str(), nullptr, 10));
+ else if (key == "size")
+ setSizeRaw(static_cast<int64_t>(strtoll(value.c_str(), nullptr, 10)));
+ else if (key == "title")
+ setTitleRaw(value);
+ else if (key == "picturepath")
+ setPathRaw(value);
+ else if (key == "date")
+ setDateTimeRaw(value);
+ else
+ {
+ hasDeprecatedInfoLabel = true;
+
+ String exifkey = key;
+ if (!StringUtils::StartsWithNoCase(exifkey, "exif:") || exifkey.length() < 6)
+ {
+ CLog::Log(LOGWARNING, "ListItem.setInfo: unknown pictures info key \"{}\"", key);
+ continue;
+ }
+
+ exifkey = StringUtils::Mid(exifkey, 5);
+ if (exifkey == "resolution")
+ xbmc::InfoTagPicture::setResolutionRaw(item->GetPictureInfoTag(), value);
+ else if (exifkey == "exiftime")
+ xbmc::InfoTagPicture::setDateTimeTakenRaw(item->GetPictureInfoTag(), value);
+ else
+ CLog::Log(LOGWARNING, "ListItem.setInfo: unknown pictures info key \"{}\"", key);
+ }
+ }
+
+ if (hasDeprecatedInfoLabel)
+ {
+ CLog::Log(LOGWARNING, "Setting most picture properties through ListItem.setInfo() is "
+ "deprecated and might be removed in future Kodi versions. Please "
+ "use the respective setter in InfoTagPicture.");
+ }
+ }
+ else if (StringUtils::EqualsNoCase(type, "game"))
+ {
+ auto gametag = item->GetGameInfoTag();
+ for (const auto& it : infoLabels)
+ {
+ const auto key = StringUtils::ToLower(it.first);
+ const auto& alt = it.second;
+ const String value(alt.which() == first ? alt.former() : emptyString);
+
+ if (key == "title")
+ {
+ setTitleRaw(value);
+ xbmc::InfoTagGame::setTitleRaw(gametag, value);
+ }
+ else if (key == "platform")
+ xbmc::InfoTagGame::setPlatformRaw(gametag, value);
+ else if (key == "genres")
+ xbmc::InfoTagGame::setGenresRaw(gametag, getStringArray(alt, key, value, ","));
+ else if (key == "publisher")
+ xbmc::InfoTagGame::setPublisherRaw(gametag, value);
+ else if (key == "developer")
+ xbmc::InfoTagGame::setDeveloperRaw(gametag, value);
+ else if (key == "overview")
+ xbmc::InfoTagGame::setOverviewRaw(gametag, value);
+ else if (key == "year")
+ xbmc::InfoTagGame::setYearRaw(gametag, strtoul(value.c_str(), nullptr, 10));
+ else if (key == "gameclient")
+ xbmc::InfoTagGame::setGameClientRaw(gametag, value);
+ }
+
+ if (!infoLabels.empty())
+ {
+ CLog::Log(
+ LOGWARNING,
+ "Setting game properties through ListItem.setInfo() is deprecated and might be "
+ "removed in future Kodi versions. Please use the respective setter in InfoTagGame.");
+ }
+ }
+ else
+ CLog::Log(LOGWARNING, "ListItem.setInfo: unknown \"type\" parameter value: {}", type);
+ } // end ListItem::setInfo
+
+ void ListItem::setCast(const std::vector<Properties>& actors)
+ {
+ CLog::Log(LOGWARNING,
+ "ListItem.setCast() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.setCast().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ std::vector<SActorInfo> cast;
+ cast.reserve(actors.size());
+ for (const auto& dictionary : actors)
+ {
+ SActorInfo info;
+ for (auto it = dictionary.begin(); it != dictionary.end(); ++it)
+ {
+ const String& key = it->first;
+ const String& value = it->second;
+ if (key == "name")
+ info.strName = value;
+ else if (key == "role")
+ info.strRole = value;
+ else if (key == "thumbnail")
+ {
+ info.thumbUrl = CScraperUrl(value);
+ if (!info.thumbUrl.GetFirstThumbUrl().empty())
+ info.thumb = CScraperUrl::GetThumbUrl(info.thumbUrl.GetFirstUrlByType());
+ }
+ else if (key == "order")
+ info.order = strtol(value.c_str(), nullptr, 10);
+ }
+ cast.push_back(std::move(info));
+ }
+ xbmc::InfoTagVideo::setCastRaw(GetVideoInfoTag(), std::move(cast));
+ }
+
+ void ListItem::setAvailableFanart(const std::vector<Properties>& images)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ auto infoTag = GetVideoInfoTag();
+ infoTag->m_fanart.Clear();
+ for (const auto& dictionary : images)
+ {
+ std::string image;
+ std::string preview;
+ std::string colors;
+ for (const auto& it : dictionary)
+ {
+ const String& key = it.first;
+ const String& value = it.second;
+ if (key == "image")
+ image = value;
+ else if (key == "preview")
+ preview = value;
+ else if (key == "colors")
+ colors = value;
+ }
+ infoTag->m_fanart.AddFanart(image, preview, colors);
+ }
+ infoTag->m_fanart.Pack();
+ }
+
+ void ListItem::addAvailableArtwork(const std::string& url,
+ const std::string& art_type,
+ const std::string& preview,
+ const std::string& referrer,
+ const std::string& cache,
+ bool post,
+ bool isgz,
+ int season)
+ {
+ CLog::Log(LOGWARNING, "ListItem.addAvailableArtwork() is deprecated and might be removed in "
+ "future Kodi versions. Please use InfoTagVideo.addAvailableArtwork().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ xbmc::InfoTagVideo::addAvailableArtworkRaw(GetVideoInfoTag(), url, art_type, preview,
+ referrer, cache, post, isgz, season);
+ }
+
+ void ListItem::addStreamInfo(const char* cType, const Properties& dictionary)
+ {
+ CLog::Log(
+ LOGWARNING,
+ "ListItem.addStreamInfo() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.addVideoStream(), InfoTagVideo.addAudioStream() and "
+ "InfoTagVideo.addSubtitleStream().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+
+ auto infoTag = GetVideoInfoTag();
+ if (StringUtils::CompareNoCase(cType, "video") == 0)
+ {
+ CStreamDetailVideo* video = new CStreamDetailVideo;
+ for (const auto& it : dictionary)
+ {
+ const String& key = it.first;
+ const String value(it.second.c_str());
+
+ if (key == "codec")
+ video->m_strCodec = value;
+ else if (key == "aspect")
+ video->m_fAspect = static_cast<float>(atof(value.c_str()));
+ else if (key == "width")
+ video->m_iWidth = strtol(value.c_str(), nullptr, 10);
+ else if (key == "height")
+ video->m_iHeight = strtol(value.c_str(), nullptr, 10);
+ else if (key == "duration")
+ video->m_iDuration = strtol(value.c_str(), nullptr, 10);
+ else if (key == "stereomode")
+ video->m_strStereoMode = value;
+ else if (key == "language")
+ video->m_strLanguage = value;
+ }
+ xbmc::InfoTagVideo::addStreamRaw(infoTag, video);
+ }
+ else if (StringUtils::CompareNoCase(cType, "audio") == 0)
+ {
+ CStreamDetailAudio* audio = new CStreamDetailAudio;
+ for (const auto& it : dictionary)
+ {
+ const String& key = it.first;
+ const String& value = it.second;
+
+ if (key == "codec")
+ audio->m_strCodec = value;
+ else if (key == "language")
+ audio->m_strLanguage = value;
+ else if (key == "channels")
+ audio->m_iChannels = strtol(value.c_str(), nullptr, 10);
+ }
+ xbmc::InfoTagVideo::addStreamRaw(infoTag, audio);
+ }
+ else if (StringUtils::CompareNoCase(cType, "subtitle") == 0)
+ {
+ CStreamDetailSubtitle* subtitle = new CStreamDetailSubtitle;
+ for (const auto& it : dictionary)
+ {
+ const String& key = it.first;
+ const String& value = it.second;
+
+ if (key == "language")
+ subtitle->m_strLanguage = value;
+ }
+ xbmc::InfoTagVideo::addStreamRaw(infoTag, subtitle);
+ }
+ xbmc::InfoTagVideo::finalizeStreamsRaw(infoTag);
+ } // end ListItem::addStreamInfo
+
+ void ListItem::addContextMenuItems(const std::vector<Tuple<String,String> >& items, bool replaceItems /* = false */)
+ {
+ for (size_t i = 0; i < items.size(); ++i)
+ {
+ auto& tuple = items[i];
+ if (tuple.GetNumValuesSet() != 2)
+ throw ListItemException("Must pass in a list of tuples of pairs of strings. One entry in the list only has %d elements.",tuple.GetNumValuesSet());
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ item->SetProperty(StringUtils::Format("contextmenulabel({})", i), tuple.first());
+ item->SetProperty(StringUtils::Format("contextmenuaction({})", i), tuple.second());
+ }
+ }
+
+ void ListItem::setSubtitles(const std::vector<String>& paths)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ addSubtitlesRaw(paths);
+ }
+
+ xbmc::InfoTagVideo* ListItem::getVideoInfoTag()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return new xbmc::InfoTagVideo(GetVideoInfoTag(), m_offscreen);
+ }
+
+ xbmc::InfoTagMusic* ListItem::getMusicInfoTag()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return new xbmc::InfoTagMusic(GetMusicInfoTag(), m_offscreen);
+ }
+
+ xbmc::InfoTagPicture* ListItem::getPictureInfoTag()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return new xbmc::InfoTagPicture(item->GetPictureInfoTag(), m_offscreen);
+ }
+
+ xbmc::InfoTagGame* ListItem::getGameInfoTag()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return new xbmc::InfoTagGame(item->GetGameInfoTag(), m_offscreen);
+ }
+
+ std::vector<std::string> ListItem::getStringArray(const InfoLabelValue& alt,
+ const std::string& tag,
+ std::string value,
+ const std::string& separator)
+ {
+ if (alt.which() == first)
+ {
+ if (value.empty())
+ value = alt.former();
+ return StringUtils::Split(value, separator);
+ }
+
+ std::vector<std::string> els;
+ for (const auto& el : alt.later())
+ {
+ if (el.which() == second)
+ throw WrongTypeException("When using \"%s\" you need to supply a string or list of strings for the value in the dictionary", tag.c_str());
+ els.emplace_back(el.former());
+ }
+ return els;
+ }
+
+ std::vector<std::string> ListItem::getVideoStringArray(const InfoLabelValue& alt,
+ const std::string& tag,
+ std::string value /* = "" */)
+ {
+ return getStringArray(
+ alt, tag, std::move(value),
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ }
+
+ std::vector<std::string> ListItem::getMusicStringArray(const InfoLabelValue& alt,
+ const std::string& tag,
+ std::string value /* = "" */)
+ {
+ return getStringArray(
+ alt, tag, std::move(value),
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator);
+ }
+
+ CVideoInfoTag* ListItem::GetVideoInfoTag()
+ {
+ return item->GetVideoInfoTag();
+ }
+
+ const CVideoInfoTag* ListItem::GetVideoInfoTag() const
+ {
+ return item->GetVideoInfoTag();
+ }
+
+ MUSIC_INFO::CMusicInfoTag* ListItem::GetMusicInfoTag()
+ {
+ return item->GetMusicInfoTag();
+ }
+
+ const MUSIC_INFO::CMusicInfoTag* ListItem::GetMusicInfoTag() const
+ {
+ return item->GetMusicInfoTag();
+ }
+
+ void ListItem::setTitleRaw(std::string title)
+ {
+ item->m_strTitle = std::move(title);
+ }
+
+ void ListItem::setPathRaw(const std::string& path)
+ {
+ item->SetPath(path);
+ }
+
+ void ListItem::setCountRaw(int count)
+ {
+ item->m_iprogramCount = count;
+ }
+
+ void ListItem::setSizeRaw(int64_t size)
+ {
+ item->m_dwSize = size;
+ }
+
+ void ListItem::setDateTimeRaw(const std::string& dateTime)
+ {
+ if (dateTime.length() == 10)
+ {
+ int year = strtol(dateTime.substr(dateTime.size() - 4).c_str(), nullptr, 10);
+ int month = strtol(dateTime.substr(3, 4).c_str(), nullptr, 10);
+ int day = strtol(dateTime.substr(0, 2).c_str(), nullptr, 10);
+ item->m_dateTime.SetDate(year, month, day);
+ }
+ else
+ item->m_dateTime.SetFromW3CDateTime(dateTime);
+ }
+
+ void ListItem::setIsFolderRaw(bool isFolder)
+ {
+ item->m_bIsFolder = isFolder;
+ }
+
+ void ListItem::setStartOffsetRaw(double startOffset)
+ {
+ // we store the offset in frames, or 1/75th of a second
+ item->SetStartOffset(CUtil::ConvertSecsToMilliSecs(startOffset));
+ }
+
+ void ListItem::setMimeTypeRaw(const std::string& mimetype)
+ {
+ item->SetMimeType(mimetype);
+ }
+
+ void ListItem::setSpecialSortRaw(std::string specialSort)
+ {
+ StringUtils::ToLower(specialSort);
+
+ if (specialSort == "bottom")
+ item->SetSpecialSort(SortSpecialOnBottom);
+ else if (specialSort == "top")
+ item->SetSpecialSort(SortSpecialOnTop);
+ }
+
+ void ListItem::setContentLookupRaw(bool enable)
+ {
+ item->SetContentLookup(enable);
+ }
+
+ void ListItem::addArtRaw(std::string type, const std::string& url)
+ {
+ StringUtils::ToLower(type);
+ item->SetArt(type, url);
+ }
+
+ void ListItem::addPropertyRaw(std::string type, const CVariant& value)
+ {
+ StringUtils::ToLower(type);
+ item->SetProperty(type, value);
+ }
+
+ void ListItem::addSubtitlesRaw(const std::vector<std::string>& subtitles)
+ {
+ for (size_t i = 0; i < subtitles.size(); ++i)
+ // subtitle:{} index starts from 1
+ addPropertyRaw(StringUtils::Format("subtitle:{}", i + 1), subtitles[i]);
+ }
+ }
+}