aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xbmc/addons/Scraper.cpp8
-rw-r--r--xbmc/interfaces/legacy/ListItem.cpp339
-rw-r--r--xbmc/interfaces/legacy/ListItem.h123
-rw-r--r--xbmc/utils/Fanart.cpp17
-rw-r--r--xbmc/utils/Fanart.h5
-rw-r--r--xbmc/utils/ScraperUrl.cpp37
-rw-r--r--xbmc/utils/ScraperUrl.h1
-rw-r--r--xbmc/video/VideoInfoTag.cpp5
8 files changed, 377 insertions, 158 deletions
diff --git a/xbmc/addons/Scraper.cpp b/xbmc/addons/Scraper.cpp
index e47fd35836..0fcf5d04f2 100644
--- a/xbmc/addons/Scraper.cpp
+++ b/xbmc/addons/Scraper.cpp
@@ -672,11 +672,7 @@ static void ParseThumbs(CScraperUrl& scurl, const CFileItem& item,
prefix << tag << i+1;
std::string url = FromString(item, prefix.str()+".url");
std::string aspect = FromString(item, prefix.str()+".aspect");
- TiXmlElement thumb("thumb");
- thumb.SetAttribute("aspect", aspect);
- TiXmlText text(url);
- thumb.InsertEndChild(text);
- scurl.ParseElement(&thumb);
+ scurl.AddElement(url, aspect);
}
}
@@ -691,9 +687,7 @@ static std::string ParseFanart(const CFileItem& item,
prefix << tag << i+1;
std::string url = FromString(item, prefix.str()+".url");
std::string preview = FromString(item, prefix.str()+".preview");
- std::string res = FromString(item, prefix.str()+".dim");
TiXmlElement thumb("thumb");
- thumb.SetAttribute("dim", res);
thumb.SetAttribute("preview", preview);
TiXmlText text(url);
thumb.InsertEndChild(text);
diff --git a/xbmc/interfaces/legacy/ListItem.cpp b/xbmc/interfaces/legacy/ListItem.cpp
index c82be42828..1f301327c0 100644
--- a/xbmc/interfaces/legacy/ListItem.cpp
+++ b/xbmc/interfaces/legacy/ListItem.cpp
@@ -139,36 +139,44 @@ namespace XBMCAddon
if (!item) return;
{
LOCKGUIIF(m_offscreen);
- for (Properties::const_iterator it = dictionary.begin(); it != dictionary.end(); ++it)
+ for (const auto& it: dictionary)
{
- std::string artName = it->first;
+ std::string artName = it.first;
StringUtils::ToLower(artName);
if (artName == "icon")
- item->SetIconImage(it->second);
+ item->SetIconImage(it.second);
else
- item->SetArt(artName, it->second);
+ item->SetArt(artName, it.second);
}
}
}
- void ListItem::setUniqueIDs(const Properties& dictionary)
+ void ListItem::setUniqueIDs(const Properties& dictionary, const String& defaultrating /* = "" */)
{
if (!item) return;
- LOCKGUI;
+ LOCKGUIIF(m_offscreen);
CVideoInfoTag& vtag = *item->GetVideoInfoTag();
- for (Properties::const_iterator it = dictionary.begin(); it != dictionary.end(); ++it)
- vtag.SetUniqueID(it->second, it->first);
+ for (const auto& it : dictionary)
+ vtag.SetUniqueID(it.second, it.first, it.first == defaultrating);
}
void ListItem::setRating(std::string type, float rating, int votes /* = 0 */, bool defaultt /* = false */)
{
if (!item) return;
- LOCKGUI;
+ LOCKGUIIF(m_offscreen);
item->GetVideoInfoTag()->SetRating(rating, votes, type, defaultt);
}
+ void ListItem::addSeason(int number, std::string name /* = "" */)
+ {
+ if (!item) return;
+
+ LOCKGUIIF(m_offscreen);
+ item->GetVideoInfoTag()->m_namedSeasons[number] = name;
+ }
+
void ListItem::select(bool selected)
{
if (!item) return;
@@ -209,13 +217,13 @@ namespace XBMCAddon
else if (lowerKey == "totaltime")
{
CBookmark resumePoint(item->GetVideoInfoTag()->GetResumePoint());
- resumePoint.totalTimeInSeconds = (float)atof(value.c_str());
+ resumePoint.totalTimeInSeconds = static_cast<float>(atof(value.c_str()));
item->GetVideoInfoTag()->SetResumePoint(resumePoint);
}
else if (lowerKey == "resumetime")
{
CBookmark resumePoint(item->GetVideoInfoTag()->GetResumePoint());
- resumePoint.timeInSeconds = (float)atof(value.c_str());
+ resumePoint.timeInSeconds = static_cast<float>(atof(value.c_str()));
item->GetVideoInfoTag()->SetResumePoint(resumePoint);
}
else if (lowerKey == "specialsort")
@@ -262,19 +270,19 @@ namespace XBMCAddon
String ListItem::getUniqueID(const char* key)
{
- LOCKGUI;
+ LOCKGUIIF(m_offscreen);
return item->GetVideoInfoTag()->GetUniqueID(key);
}
float ListItem::getRating(const char* key)
{
- LOCKGUI;
+ LOCKGUIIF(m_offscreen);
return item->GetVideoInfoTag()->GetRating(key).rating;
}
int ListItem::getVotes(const char* key)
{
- LOCKGUI;
+ LOCKGUIIF(m_offscreen);
return item->GetVideoInfoTag()->GetRating(key).votes;
}
@@ -326,7 +334,7 @@ namespace XBMCAddon
String ListItem::getPath()
{
- LOCKGUI;
+ LOCKGUIIF(m_offscreen);
return item->GetPath();
}
@@ -336,64 +344,72 @@ namespace XBMCAddon
if (strcmpi(type, "video") == 0)
{
- for (InfoLabelDict::const_iterator it = infoLabels.begin(); it != infoLabels.end(); ++it)
+ auto& videotag = *item->GetVideoInfoTag();
+ for (const auto& it: infoLabels)
{
- String key = it->first;
+ String key = it.first;
StringUtils::ToLower(key);
- const InfoLabelValue& alt = it->second;
+ const InfoLabelValue& alt = it.second;
const String value(alt.which() == first ? alt.former() : emptyString);
if (key == "dbid")
- item->GetVideoInfoTag()->m_iDbId = strtol(value.c_str(), NULL, 10);
+ videotag.m_iDbId = strtol(value.c_str(), nullptr, 10);
else if (key == "year")
- item->GetVideoInfoTag()->SetYear(strtol(value.c_str(), NULL, 10));
+ videotag.SetYear(strtol(value.c_str(), nullptr, 10));
else if (key == "episode")
- item->GetVideoInfoTag()->m_iEpisode = strtol(value.c_str(), NULL, 10);
+ videotag.m_iEpisode = strtol(value.c_str(), nullptr, 10);
else if (key == "season")
- item->GetVideoInfoTag()->m_iSeason = strtol(value.c_str(), NULL, 10);
+ videotag.m_iSeason = strtol(value.c_str(), nullptr, 10);
+ else if (key == "sortepisode")
+ videotag.m_iSpecialSortEpisode = strtol(value.c_str(), nullptr, 10);
+ else if (key == "sortseason")
+ videotag.m_iSpecialSortSeason = strtol(value.c_str(), nullptr, 10);
+ else if (key == "episodeguide")
+ videotag.SetEpisodeGuide(value);
+ else if (key == "showlink")
+ videotag.SetShowLink(getStringArray(alt, key, value));
else if (key == "top250")
- item->GetVideoInfoTag()->m_iTop250 = strtol(value.c_str(), NULL, 10);
+ videotag.m_iTop250 = strtol(value.c_str(), nullptr, 10);
else if (key == "setid")
- item->GetVideoInfoTag()->m_iSetId = strtol(value.c_str(), NULL, 10);
+ videotag.m_iSetId = strtol(value.c_str(), nullptr, 10);
else if (key == "tracknumber")
- item->GetVideoInfoTag()->m_iTrack = strtol(value.c_str(), NULL, 10);
+ videotag.m_iTrack = strtol(value.c_str(), nullptr, 10);
else if (key == "count")
- item->m_iprogramCount = strtol(value.c_str(), NULL, 10);
+ item->m_iprogramCount = strtol(value.c_str(), nullptr, 10);
else if (key == "rating")
- item->GetVideoInfoTag()->SetRating((float)strtod(value.c_str(), NULL));
+ videotag.SetRating(static_cast<float>(strtod(value.c_str(), nullptr)));
else if (key == "userrating")
- item->GetVideoInfoTag()->m_iUserRating = strtol(value.c_str(), NULL, 10);
+ videotag.m_iUserRating = strtol(value.c_str(), nullptr, 10);
else if (key == "size")
- item->m_dwSize = (int64_t)strtoll(value.c_str(), NULL, 10);
+ item->m_dwSize = (int64_t)strtoll(value.c_str(), nullptr, 10);
else if (key == "watched") // backward compat - do we need it?
- item->GetVideoInfoTag()->SetPlayCount(strtol(value.c_str(), NULL, 10));
+ videotag.SetPlayCount(strtol(value.c_str(), nullptr, 10));
else if (key == "playcount")
- item->GetVideoInfoTag()->SetPlayCount(strtol(value.c_str(), NULL, 10));
+ videotag.SetPlayCount(strtol(value.c_str(), nullptr, 10));
else if (key == "overlay")
{
- long overlay = strtol(value.c_str(), NULL, 10);
+ long overlay = strtol(value.c_str(), nullptr, 10);
if (overlay >= 0 && overlay <= 8)
- item->SetOverlayImage((CGUIListItem::GUIIconOverlay)overlay);
+ item->SetOverlayImage(static_cast<CGUIListItem::GUIIconOverlay>(overlay));
}
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");
- item->GetVideoInfoTag()->m_cast.clear();
+ videotag.m_cast.clear();
const std::vector<InfoLabelStringOrTuple>& listValue = alt.later();
- for (std::vector<InfoLabelStringOrTuple>::const_iterator viter = listValue.begin(); viter != listValue.end(); ++viter)
+ for (const auto& castEntry: alt.later())
{
- const InfoLabelStringOrTuple& castEntry = *viter;
// 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 = (const String&)(castEntry.later().second());
- item->GetVideoInfoTag()->m_cast.push_back(info);
+ info.strRole = static_cast<const String&>(castEntry.later().second());
+ videotag.m_cast.push_back(info);
}
}
else if (key == "artist")
@@ -401,73 +417,73 @@ namespace XBMCAddon
if (alt.which() != second)
throw WrongTypeException("When using \"artist\" you need to supply a list of strings for the value in the dictionary");
- item->GetVideoInfoTag()->m_artist.clear();
+ videotag.m_artist.clear();
const std::vector<InfoLabelStringOrTuple>& listValue = alt.later();
- for (std::vector<InfoLabelStringOrTuple>::const_iterator viter = listValue.begin(); viter != listValue.end(); ++viter)
+ for (const auto& castEntry: alt.later())
{
-
- const InfoLabelStringOrTuple& castEntry = *viter;
const String& actor = castEntry.which() == first ? castEntry.former() : castEntry.later().first();
- item->GetVideoInfoTag()->m_artist.push_back(actor);
+ videotag.m_artist.push_back(actor);
}
}
else if (key == "genre")
- item->GetVideoInfoTag()->m_genre = StringUtils::Split(value, g_advancedSettings.m_videoItemSeparator);
+ videotag.SetGenre(getStringArray(alt, key, value));
else if (key == "country")
- item->GetVideoInfoTag()->m_country = StringUtils::Split(value, g_advancedSettings.m_videoItemSeparator);
+ videotag.SetCountry(getStringArray(alt, key, value));
else if (key == "director")
- item->GetVideoInfoTag()->m_director = StringUtils::Split(value, g_advancedSettings.m_videoItemSeparator);
+ videotag.SetDirector(getStringArray(alt, key, value));
else if (key == "mpaa")
- item->GetVideoInfoTag()->m_strMPAARating = value;
+ videotag.SetMPAARating(value);
else if (key == "plot")
- item->GetVideoInfoTag()->m_strPlot = value;
+ videotag.SetPlot(value);
else if (key == "plotoutline")
- item->GetVideoInfoTag()->m_strPlotOutline = value;
+ videotag.SetPlotOutline(value);
else if (key == "title")
- item->GetVideoInfoTag()->m_strTitle = value;
+ videotag.SetTitle(value);
else if (key == "originaltitle")
- item->GetVideoInfoTag()->m_strOriginalTitle = value;
+ videotag.SetOriginalTitle(value);
else if (key == "sorttitle")
- item->GetVideoInfoTag()->m_strSortTitle = value;
+ videotag.SetSortTitle(value);
else if (key == "duration")
- item->GetVideoInfoTag()->SetDuration(strtol(value.c_str(), NULL, 10));
+ videotag.SetDuration(strtol(value.c_str(), nullptr, 10));
else if (key == "studio")
- item->GetVideoInfoTag()->m_studio = StringUtils::Split(value, g_advancedSettings.m_videoItemSeparator);
+ videotag.SetStudio(getStringArray(alt, key, value));
else if (key == "tagline")
- item->GetVideoInfoTag()->m_strTagLine = value;
- else if (key == "writer")
- item->GetVideoInfoTag()->m_writingCredits = StringUtils::Split(value, g_advancedSettings.m_videoItemSeparator);
+ videotag.SetTagLine(value);
+ else if (key == "writer" || key == "credits")
+ videotag.SetWritingCredits(getStringArray(alt, key, value));
else if (key == "tvshowtitle")
- item->GetVideoInfoTag()->m_strShowTitle = value;
+ videotag.SetShowTitle(value);
else if (key == "premiered")
{
CDateTime premiered;
premiered.SetFromDateString(value);
- item->GetVideoInfoTag()->SetPremiered(premiered);
+ videotag.SetPremiered(premiered);
}
else if (key == "status")
- item->GetVideoInfoTag()->m_strStatus = value;
+ videotag.SetStatus(value);
else if (key == "set")
- item->GetVideoInfoTag()->m_strSet = value;
+ videotag.SetSet(value);
+ else if (key == "setoverview")
+ videotag.SetSetOverview(value);
+ else if (key == "tag")
+ videotag.SetTags(getStringArray(alt, key, value));
else if (key == "imdbnumber")
- item->GetVideoInfoTag()->SetUniqueID(value);
+ videotag.SetUniqueID(value);
else if (key == "code")
- item->GetVideoInfoTag()->m_strProductionCode = value;
+ videotag.SetProductionCode(value);
else if (key == "aired")
- item->GetVideoInfoTag()->m_firstAired.SetFromDateString(value);
- else if (key == "credits")
- item->GetVideoInfoTag()->m_writingCredits = StringUtils::Split(value, g_advancedSettings.m_videoItemSeparator);
+ videotag.m_firstAired.SetFromDateString(value);
else if (key == "lastplayed")
- item->GetVideoInfoTag()->m_lastPlayed.SetFromDBDateTime(value);
+ videotag.m_lastPlayed.SetFromDBDateTime(value);
else if (key == "album")
- item->GetVideoInfoTag()->m_strAlbum = value;
+ videotag.SetAlbum(value);
else if (key == "votes")
- item->GetVideoInfoTag()->SetVotes(StringUtils::ReturnDigits(value));
+ videotag.SetVotes(StringUtils::ReturnDigits(value));
else if (key == "trailer")
- item->GetVideoInfoTag()->m_strTrailer = value;
+ videotag.SetTrailer(value);
else if (key == "path")
- item->GetVideoInfoTag()->m_strPath = value;
+ videotag.SetPath(value);
else if (key == "date")
{
if (value.length() == 10)
@@ -481,11 +497,11 @@ namespace XBMCAddon
CLog::Log(LOGERROR,"NEWADDON Invalid Date Format \"%s\"",value.c_str());
}
else if (key == "dateadded")
- item->GetVideoInfoTag()->m_dateAdded.SetFromDBDateTime(value.c_str());
+ videotag.m_dateAdded.SetFromDBDateTime(value.c_str());
else if (key == "mediatype")
{
if (CMediaTypes::IsValidMediaType(value))
- item->GetVideoInfoTag()->m_type = value;
+ videotag.m_type = value;
else
CLog::Log(LOGWARNING, "Invalid media type \"%s\"", value.c_str());
}
@@ -514,59 +530,60 @@ namespace XBMCAddon
CLog::Log(LOGWARNING, "Invalid media type \"%s\"", value.c_str());
}
}
- for (InfoLabelDict::const_iterator it = infoLabels.begin(); it != infoLabels.end(); ++it)
+ auto& musictag = *item->GetMusicInfoTag();
+ for (const auto& it : infoLabels)
{
- String key = it->first;
+ String key = it.first;
StringUtils::ToLower(key);
- const InfoLabelValue& alt = it->second;
+ const InfoLabelValue& alt = it.second;
const String value(alt.which() == first ? alt.former() : emptyString);
//! @todo add the rest of the infolabels
if (key == "dbid" && !type.empty())
- item->GetMusicInfoTag()->SetDatabaseId(strtol(value.c_str(), NULL, 10), type);
+ musictag.SetDatabaseId(strtol(value.c_str(), NULL, 10), type);
else if (key == "tracknumber")
- item->GetMusicInfoTag()->SetTrackNumber(strtol(value.c_str(), NULL, 10));
+ musictag.SetTrackNumber(strtol(value.c_str(), NULL, 10));
else if (key == "discnumber")
- item->GetMusicInfoTag()->SetDiscNumber(strtol(value.c_str(), NULL, 10));
+ musictag.SetDiscNumber(strtol(value.c_str(), nullptr, 10));
else if (key == "count")
- item->m_iprogramCount = strtol(value.c_str(), NULL, 10);
+ item->m_iprogramCount = strtol(value.c_str(), nullptr, 10);
else if (key == "size")
- item->m_dwSize = (int64_t)strtoll(value.c_str(), NULL, 10);
+ item->m_dwSize = static_cast<int64_t>(strtoll(value.c_str(), nullptr, 10));
else if (key == "duration")
- item->GetMusicInfoTag()->SetDuration(strtol(value.c_str(), NULL, 10));
+ musictag.SetDuration(strtol(value.c_str(), nullptr, 10));
else if (key == "year")
- item->GetMusicInfoTag()->SetYear(strtol(value.c_str(), NULL, 10));
+ musictag.SetYear(strtol(value.c_str(), nullptr, 10));
else if (key == "listeners")
- item->GetMusicInfoTag()->SetListeners(strtol(value.c_str(), NULL, 10));
+ musictag.SetListeners(strtol(value.c_str(), nullptr, 10));
else if (key == "playcount")
- item->GetMusicInfoTag()->SetPlayCount(strtol(value.c_str(), NULL, 10));
+ musictag.SetPlayCount(strtol(value.c_str(), nullptr, 10));
else if (key == "genre")
- item->GetMusicInfoTag()->SetGenre(value);
+ musictag.SetGenre(value);
else if (key == "album")
- item->GetMusicInfoTag()->SetAlbum(value);
+ musictag.SetAlbum(value);
else if (key == "artist")
- item->GetMusicInfoTag()->SetArtist(value);
+ musictag.SetArtist(value);
else if (key == "title")
- item->GetMusicInfoTag()->SetTitle(value);
+ musictag.SetTitle(value);
else if (key == "rating")
- item->GetMusicInfoTag()->SetRating((float)strtod(value.c_str(), NULL));
+ musictag.SetRating(static_cast<float>(strtod(value.c_str(), nullptr)));
else if (key == "userrating")
- item->GetMusicInfoTag()->SetUserrating(strtol(value.c_str(), NULL, 10));
+ musictag.SetUserrating(strtol(value.c_str(), nullptr, 10));
else if (key == "lyrics")
- item->GetMusicInfoTag()->SetLyrics(value);
+ musictag.SetLyrics(value);
else if (key == "lastplayed")
- item->GetMusicInfoTag()->SetLastPlayed(value);
+ musictag.SetLastPlayed(value);
else if (key == "musicbrainztrackid")
- item->GetMusicInfoTag()->SetMusicBrainzTrackID(value);
+ musictag.SetMusicBrainzTrackID(value);
else if (key == "musicbrainzartistid")
- item->GetMusicInfoTag()->SetMusicBrainzArtistID(StringUtils::Split(value, g_advancedSettings.m_musicItemSeparator));
+ musictag.SetMusicBrainzArtistID(StringUtils::Split(value, g_advancedSettings.m_musicItemSeparator));
else if (key == "musicbrainzalbumid")
- item->GetMusicInfoTag()->SetMusicBrainzAlbumID(value);
+ musictag.SetMusicBrainzAlbumID(value);
else if (key == "musicbrainzalbumartistid")
- item->GetMusicInfoTag()->SetMusicBrainzAlbumArtistID(StringUtils::Split(value, g_advancedSettings.m_musicItemSeparator));
+ musictag.SetMusicBrainzAlbumArtistID(StringUtils::Split(value, g_advancedSettings.m_musicItemSeparator));
else if (key == "comment")
- item->GetMusicInfoTag()->SetComment(value);
+ musictag.SetComment(value);
else if (key == "date")
{
if (strlen(value.c_str()) == 10)
@@ -582,23 +599,23 @@ namespace XBMCAddon
// 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.
- item->GetMusicInfoTag()->SetLoaded(true);
+ musictag.SetLoaded(true);
}
}
else if (strcmpi(type,"pictures") == 0)
{
- for (InfoLabelDict::const_iterator it = infoLabels.begin(); it != infoLabels.end(); ++it)
+ for (const auto& it: infoLabels)
{
- String key = it->first;
+ String key = it.first;
StringUtils::ToLower(key);
- const InfoLabelValue& alt = it->second;
+ const InfoLabelValue& alt = it.second;
const String value(alt.which() == first ? alt.former() : emptyString);
if (key == "count")
- item->m_iprogramCount = strtol(value.c_str(), NULL, 10);
+ item->m_iprogramCount = strtol(value.c_str(), nullptr, 10);
else if (key == "size")
- item->m_dwSize = (int64_t)strtoll(value.c_str(), NULL, 10);
+ item->m_dwSize = static_cast<int64_t>(strtoll(value.c_str(), nullptr, 10));
else if (key == "title")
item->m_strTitle = value;
else if (key == "picturepath")
@@ -624,21 +641,22 @@ namespace XBMCAddon
}
else if (StringUtils::EqualsNoCase(type, "game"))
{
- for (InfoLabelDict::const_iterator it = infoLabels.begin(); it != infoLabels.end(); it++)
+ auto& gametag = *item->GetGameInfoTag();
+ for (const auto& it: infoLabels)
{
- String key = it->first;
+ String key = it.first;
StringUtils::ToLower(key);
- const InfoLabelValue& alt = it->second;
+ const InfoLabelValue& alt = it.second;
const String value(alt.which() == first ? alt.former() : emptyString);
if (key == "title")
{
item->m_strTitle = value;
- item->GetGameInfoTag()->SetTitle(value);
+ gametag.SetTitle(value);
}
else if (key == "platform")
- item->GetGameInfoTag()->SetPlatform(value);
+ gametag.SetPlatform(value);
else if (key == "genres")
{
if (alt.which() != second)
@@ -646,34 +664,31 @@ namespace XBMCAddon
std::vector<std::string> genres;
- const std::vector<InfoLabelStringOrTuple>& listValue = alt.later();
- for (std::vector<InfoLabelStringOrTuple>::const_iterator viter = listValue.begin(); viter != listValue.end(); ++viter)
+ for (const auto& genreEntry: alt.later())
{
-
- const InfoLabelStringOrTuple& genreEntry = *viter;
const String& genre = genreEntry.which() == first ? genreEntry.former() : genreEntry.later().first();
genres.emplace_back(std::move(genre));
}
- item->GetGameInfoTag()->SetGenres(genres);
+ gametag.SetGenres(genres);
}
else if (key == "publisher")
- item->GetGameInfoTag()->SetPublisher(value);
+ gametag.SetPublisher(value);
else if (key == "developer")
- item->GetGameInfoTag()->SetDeveloper(value);
+ gametag.SetDeveloper(value);
else if (key == "overview")
- item->GetGameInfoTag()->SetOverview(value);
+ gametag.SetOverview(value);
else if (key == "year")
- item->GetGameInfoTag()->SetYear(strtol(value.c_str(), NULL, 10));
+ gametag.SetYear(strtol(value.c_str(), nullptr, 10));
else if (key == "gameclient")
- item->GetGameInfoTag()->SetGameClient(value);
+ gametag.SetGameClient(value);
}
}
} // end ListItem::setInfo
void ListItem::setCast(const std::vector<Properties>& actors)
{
- LOCKGUI;
+ LOCKGUIIF(m_offscreen);
item->GetVideoInfoTag()->m_cast.clear();
for (const auto& dictionary: actors)
{
@@ -689,12 +704,43 @@ namespace XBMCAddon
else if (key == "thumbnail")
info.thumbUrl = value;
else if (key == "order")
- info.order = strtol(value.c_str(), NULL, 10);
+ info.order = strtol(value.c_str(), nullptr, 10);
}
item->GetVideoInfoTag()->m_cast.push_back(std::move(info));
}
}
+ void ListItem::setAvailableFanart(const std::vector<Properties>& images)
+ {
+ LOCKGUIIF(m_offscreen);
+ item->GetVideoInfoTag()->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;
+ }
+ item->GetVideoInfoTag()->m_fanart.AddFanart(image, preview, colors);
+ }
+ item->GetVideoInfoTag()->m_fanart.Pack();
+ }
+
+ void ListItem::addAvailableThumb(std::string url, std::string aspect, std::string referrer, std::string cache, bool post, bool isgz, int season)
+ {
+ LOCKGUIIF(m_offscreen);
+ item->GetVideoInfoTag()->m_strPictureURL.AddElement(url, aspect, referrer, cache, post, isgz, season);
+ }
+
void ListItem::addStreamInfo(const char* cType, const Properties& dictionary)
{
LOCKGUIIF(m_offscreen);
@@ -702,21 +748,21 @@ namespace XBMCAddon
if (strcmpi(cType, "video") == 0)
{
CStreamDetailVideo* video = new CStreamDetailVideo;
- for (Properties::const_iterator it = dictionary.begin(); it != dictionary.end(); ++it)
+ for (const auto& it: dictionary)
{
- const String& key = it->first;
- const String value(it->second.c_str());
+ 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 = (float)atof(value.c_str());
+ video->m_fAspect = static_cast<float>(atof(value.c_str()));
else if (key == "width")
- video->m_iWidth = strtol(value.c_str(), NULL, 10);
+ video->m_iWidth = strtol(value.c_str(), nullptr, 10);
else if (key == "height")
- video->m_iHeight = strtol(value.c_str(), NULL, 10);
+ video->m_iHeight = strtol(value.c_str(), nullptr, 10);
else if (key == "duration")
- video->m_iDuration = strtol(value.c_str(), NULL, 10);
+ video->m_iDuration = strtol(value.c_str(), nullptr, 10);
else if (key == "stereomode")
video->m_strStereoMode = value;
else if (key == "language")
@@ -727,27 +773,27 @@ namespace XBMCAddon
else if (strcmpi(cType, "audio") == 0)
{
CStreamDetailAudio* audio = new CStreamDetailAudio;
- for (Properties::const_iterator it = dictionary.begin(); it != dictionary.end(); ++it)
+ for (const auto& it: dictionary)
{
- const String& key = it->first;
- const String& value = it->second;
+ 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(), NULL, 10);
+ audio->m_iChannels = strtol(value.c_str(), nullptr, 10);
}
item->GetVideoInfoTag()->m_streamDetails.AddStream(audio);
}
else if (strcmpi(cType, "subtitle") == 0)
{
CStreamDetailSubtitle* subtitle = new CStreamDetailSubtitle;
- for (Properties::const_iterator it = dictionary.begin(); it != dictionary.end(); ++it)
+ for (const auto& it: dictionary)
{
- const String& key = it->first;
- const String& value = it->second;
+ const String& key = it.first;
+ const String& value = it.second;
if (key == "language")
subtitle->m_strLanguage = value;
@@ -775,10 +821,10 @@ namespace XBMCAddon
{
LOCKGUIIF(m_offscreen);
unsigned int i = 1;
- for (std::vector<String>::const_iterator it = paths.begin(); it != paths.end(); ++it, i++)
+ for (const auto& it: paths)
{
String property = StringUtils::Format("subtitle:%u", i);
- item->SetProperty(property, *it);
+ item->SetProperty(property, it);
}
}
@@ -797,5 +843,24 @@ namespace XBMCAddon
return new xbmc::InfoTagMusic(*item->GetMusicInfoTag());
return new xbmc::InfoTagMusic();
}
+
+ std::vector<std::string> ListItem::getStringArray(const InfoLabelValue& alt, const std::string& tag, std::string value)
+ {
+ if (alt.which() == first)
+ {
+ if (value.empty())
+ value = alt.former();
+ return StringUtils::Split(value, g_advancedSettings.m_videoItemSeparator);
+ }
+
+ std::vector<std::string> els;
+ for (const auto& el : alt.later())
+ {
+ if (el.which() == second)
+ throw WrongTypeException(StringUtils::Format("When using \"%s\" you need to supply a string or list of strings for the value in the dictionary", tag.c_str()).c_str());
+ els.emplace_back(el.former());
+ }
+ return els;
+ }
}
}
diff --git a/xbmc/interfaces/legacy/ListItem.h b/xbmc/interfaces/legacy/ListItem.h
index 85e4a70134..197373bb5d 100644
--- a/xbmc/interfaces/legacy/ListItem.h
+++ b/xbmc/interfaces/legacy/ListItem.h
@@ -272,11 +272,13 @@ namespace XBMCAddon
#ifdef DOXYGEN_SHOULD_USE_THIS
///
/// \ingroup python_xbmcgui_listitem
- /// @brief \python_func{ setUniqueIDs(values) }
+ /// @brief \python_func{ setUniqueIDs(values, defaultrating) }
///-----------------------------------------------------------------------
/// Sets the listitem's uniqueID
///
/// @param values dictionary - pairs of `{ label: value }`.
+ /// @param defaultrating [opt] string - the name of default rating.
+ ///
/// - Some example values (any string possible):
/// | Label | Type |
/// |:-------------:|:--------------------------------------------------|
@@ -292,14 +294,14 @@ namespace XBMCAddon
/// **Example:**
/// ~~~~~~~~~~~~~{.py}
/// ...
- /// # setUniqueIDs(values)
- /// listitem.setUniqueIDs({ 'imdb': 'tt8938399', 'tmdb' : '9837493' })
+ /// # setUniqueIDs(values, defaultrating)
+ /// listitem.setUniqueIDs({ 'imdb': 'tt8938399', 'tmdb' : '9837493' }, "imdb")
/// ...
/// ~~~~~~~~~~~~~
///
setUniqueIDs(...);
#else
- void setUniqueIDs(const Properties& dictionary);
+ void setUniqueIDs(const Properties& dictionary, const String& defaultrating = "");
#endif
#ifdef DOXYGEN_SHOULD_USE_THIS
@@ -341,6 +343,33 @@ namespace XBMCAddon
#ifdef DOXYGEN_SHOULD_USE_THIS
///
/// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ addSeason(number, name = "") }
+ ///-----------------------------------------------------------------------
+ /// Add a season with name to a listitem. It needs at least the season number
+ ///
+ /// @param number int - the number of the season.
+ /// @param name string - the name of the season. Default "".
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # addSeason(number, name))
+ /// listitem.addSeason(1, "Murder House")
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addSeason(...);
+#else
+ void addSeason(int number, std::string name = "");
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
/// @brief \python_func{ getArt(key) }
///-----------------------------------------------------------------------
/// Returns a listitem art path as a string, similar to an infolabel.\n
@@ -557,11 +586,15 @@ namespace XBMCAddon
/// __Video Values__:
/// | Info label | Description |
/// |--------------:|:---------------------------------------------------|
- /// | genre | string (Comedy)
- /// | country | string (Germany)
+ /// | genre | string (Comedy) or list of strings (["Comedy", "Animation", "Drama"])
+ /// | country | string (Germany) or list of strings (["Germany", "Italy", "France"])
/// | year | integer (2009)
/// | episode | integer (4)
/// | season | integer (1)
+ /// | sortepisode | integer (4)
+ /// | sortseason | integer (1)
+ /// | episodeguide | string (Episode guide)
+ /// | showlink | string (Battlestar Galactica) or list of strings (["Battlestar Galactica", "Caprica"])
/// | top250 | integer (192)
/// | setid | integer (14)
/// | tracknumber | integer (3)
@@ -572,7 +605,7 @@ namespace XBMCAddon
/// | overlay | integer (2) - range is `0..7`. See \ref kodi_guilib_listitem_iconoverlay "Overlay icon types" for values
/// | cast | list (["Michal C. Hall","Jennifer Carpenter"]) - if provided a list of tuples cast will be interpreted as castandrole
/// | castandrole | list of tuples ([("Michael C. Hall","Dexter"),("Jennifer Carpenter","Debra")])
- /// | director | string (Dagur Kari)
+ /// | director | string (Dagur Kari) or list of strings (["Dagur Kari", "Quentin Tarantino", "Chrstopher Nolan"])
/// | mpaa | string (PG-13)
/// | plot | string (Long Description)
/// | plotoutline | string (Short Description)
@@ -580,17 +613,19 @@ namespace XBMCAddon
/// | originaltitle | string (Big Fan)
/// | sorttitle | string (Big Fan)
/// | duration | integer (245) - duration in seconds
- /// | studio | string (Warner Bros.)
+ /// | studio | string (Warner Bros.) or list of strings (["Warner Bros.", "Disney", "Paramount"])
/// | tagline | string (An awesome movie) - short description of movie
- /// | writer | string (Robert D. Siegel)
+ /// | writer | string (Robert D. Siegel) or list of strings (["Robert D. Siegel", "Jonathan Nolan", "J.K. Rowling"])
/// | tvshowtitle | string (Heroes)
/// | premiered | string (2005-03-04)
/// | status | string (Continuing) - status of a TVshow
/// | set | string (Batman Collection) - name of the collection
+ /// | setoverview | string (All Batman movies) - overview of the collection
+ /// | tag | string (cult) or list of strings (["cult", "documentary", "best movies"]) - movie tag
/// | imdbnumber | string (tt0110293) - IMDb code
/// | code | string (101) - Production code
/// | aired | string (2008-12-07)
- /// | credits | string (Andy Kaufman) - writing credits
+ /// | credits | string (Andy Kaufman) or list of strings (["Dagur Kari", "Quentin Tarantino", "Chrstopher Nolan"]) - writing credits
/// | lastplayed | string (%Y-%m-%d %h:%m:%s = 2009-04-05 23:16:04)
/// | album | string (The Joshua Tree)
/// | artist | list (['U2'])
@@ -654,6 +689,8 @@ namespace XBMCAddon
/// Added labels **setid**, **set**, **imdbnumber**, **code**, **dbid**, **path** and **userrating**.
/// Expanded the possible infoLabels for the option **mediatype**.
/// @python_v18 Added new **game** type and associated infolabels.
+ /// Added labels **setoverview**, **tag**, **sortepisode**, **sortseason**, **episodeguide**, **showlink**.
+ /// Extended labels **genre**, **country**, **director**, **studio**, **writer**, **tag**, **credits** to also use a list of strings.
///
/// **Example:**
/// ~~~~~~~~~~~~~{.py}
@@ -704,6 +741,69 @@ namespace XBMCAddon
#ifdef DOXYGEN_SHOULD_USE_THIS
///
/// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setAvailableFanart(images) }
+ ///-----------------------------------------------------------------------
+ /// @brief Set available images (needed for scrapers)
+ ///
+ /// @param images list of dictionaries (see below for relevant keys)
+ ///
+ /// - Keys:
+ /// | Label | Description |
+ /// |--------------:|:------------------------------------------------|
+ /// | image | string (http://www.someurl.com/someimage.png)
+ /// | preview | [opt] string (http://www.someurl.com/somepreviewimage.png)
+ /// | colors | [opt] string (either comma separated Kodi hex values ("FFFFFFFF,DDDDDDDD") or TVDB RGB Int Triplets ("|68,69,59|69,70,58|78,78,68|"))
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// fanart = [{"image": path_to_image_1, "preview": path_to_preview_1}, {"image": path_to_image_2, "preview": path_to_preview_2}]
+ /// listitem.setAvailableFanart(fanart)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setAvailableFanart(...);
+#else
+ void setAvailableFanart(const std::vector<Properties>& images);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ addAvailableThumb(images) }
+ ///-----------------------------------------------------------------------
+ /// @brief Add a thumb to available thumbs (needed for scrapers)
+ ///
+ /// @param url string (image path url)
+ /// @param aspect [opt] string (image type)
+ /// @param referrer [opt] string (referr url)
+ /// @param cache [opt] string (filename in cache)
+ /// @param post [opt] bool (use post to retrieve the image, default false)
+ /// @param isgz [opt] bool (use gzip to retrieve the image, default false)
+ /// @param season [opt] integer (number of season in case of season thumb)
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem.addAvailableThumb(path_to_image_1, "1.77")
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addAvailableThumb(...);
+#else
+ void addAvailableThumb(std::string url, std::string aspect = "", std::string referrer = "", std::string cache = "", bool post = false, bool isgz = false, int season = -1);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
/// @brief \python_func{ addStreamInfo(type, values) }
///-----------------------------------------------------------------------
/// @brief Add a stream with details.
@@ -1029,6 +1129,9 @@ namespace XBMCAddon
/// Function completely removed and replaced with context menu add-ons.
///
#endif
+
+private:
+ std::vector<std::string> getStringArray(const InfoLabelValue& alt, const std::string& tag, std::string value = "");
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
diff --git a/xbmc/utils/Fanart.cpp b/xbmc/utils/Fanart.cpp
index 95744448cc..6ed6db142c 100644
--- a/xbmc/utils/Fanart.cpp
+++ b/xbmc/utils/Fanart.cpp
@@ -46,7 +46,6 @@ void CFanart::Pack()
for (std::vector<SFanartData>::const_iterator it = m_fanart.begin(); it != m_fanart.end(); ++it)
{
TiXmlElement thumb("thumb");
- thumb.SetAttribute("dim", it->strResolution.c_str());
thumb.SetAttribute("colors", it->strColors.c_str());
thumb.SetAttribute("preview", it->strPreview.c_str());
TiXmlText text(it->strImage);
@@ -56,6 +55,21 @@ void CFanart::Pack()
m_xml << fanart;
}
+void CFanart::AddFanart(const std::string& image, const std::string& preview, const std::string& colors)
+{
+ SFanartData info;
+ info.strPreview = preview;
+ info.strImage = image;
+ ParseColors(colors, info.strColors);
+ m_fanart.push_back(std::move(info));
+}
+
+void CFanart::Clear()
+{
+ m_fanart.clear();
+ m_xml.clear();
+}
+
bool CFanart::Unpack()
{
CXBMCTinyXML doc;
@@ -84,7 +98,6 @@ bool CFanart::Unpack()
if (fanartThumb->Attribute("preview"))
data.strPreview = URIUtils::AddFileToFolder(url, fanartThumb->Attribute("preview"));
}
- data.strResolution = XMLUtils::GetAttribute(fanartThumb, "dim");
ParseColors(XMLUtils::GetAttribute(fanartThumb, "colors"), data.strColors);
m_fanart.push_back(data);
}
diff --git a/xbmc/utils/Fanart.h b/xbmc/utils/Fanart.h
index 040a85124b..d6d2f25d35 100644
--- a/xbmc/utils/Fanart.h
+++ b/xbmc/utils/Fanart.h
@@ -82,6 +82,10 @@ public:
/// Returns how many fanarts are stored
/// \return An integer indicating how many fanarts are stored in the class. Fanart indices are 0 to (GetNumFanarts() - 1)
unsigned int GetNumFanarts() const;
+ /// Adds an image to internal fanart data
+ void AddFanart(const std::string& image, const std::string& preview, const std::string& colors);
+ /// Clear all internal fanart data
+ void Clear();
///
/// m_xml contains an XML formatted string which is all fanart packed into one string.
///
@@ -107,7 +111,6 @@ private:
struct SFanartData
{
std::string strImage;
- std::string strResolution;
std::string strColors;
std::string strPreview;
};
diff --git a/xbmc/utils/ScraperUrl.cpp b/xbmc/utils/ScraperUrl.cpp
index bf2e09beb3..9eb09c48a6 100644
--- a/xbmc/utils/ScraperUrl.cpp
+++ b/xbmc/utils/ScraperUrl.cpp
@@ -339,6 +339,43 @@ bool CScraperUrl::ParseEpisodeGuide(std::string strUrls)
return true;
}
+void CScraperUrl::AddElement(std::string url, std::string aspect, std::string referrer, std::string cache, bool post, bool isgz, int season)
+{
+ TiXmlElement thumb("thumb");
+ thumb.SetAttribute("spoof", referrer);
+ thumb.SetAttribute("cache", cache);
+ if (post)
+ thumb.SetAttribute("post", "yes");
+ if (isgz)
+ thumb.SetAttribute("gzip", "yes");
+ if (season >= 0)
+ {
+ thumb.SetAttribute("season", StringUtils::Format("%i", season));
+ thumb.SetAttribute("type", "season");
+ }
+ thumb.SetAttribute("aspect", aspect);
+ TiXmlText text(url);
+ thumb.InsertEndChild(text);
+ m_xml << thumb;
+ SUrlEntry nUrl;
+ nUrl.m_url = url;
+ nUrl.m_spoof = referrer;
+ nUrl.m_post = post;
+ nUrl.m_isgz = isgz;
+ nUrl.m_cache = cache;
+ if (season >= 0)
+ {
+ nUrl.m_type = URL_TYPE_SEASON;
+ nUrl.m_season = season;
+ }
+ else
+ nUrl.m_type = URL_TYPE_GENERAL;
+
+ nUrl.m_aspect = aspect;
+
+ m_url.push_back(nUrl);
+}
+
std::string CScraperUrl::GetThumbURL(const CScraperUrl::SUrlEntry &entry)
{
if (entry.m_spoof.empty())
diff --git a/xbmc/utils/ScraperUrl.h b/xbmc/utils/ScraperUrl.h
index d9871e8f8f..7fe69b2377 100644
--- a/xbmc/utils/ScraperUrl.h
+++ b/xbmc/utils/ScraperUrl.h
@@ -58,6 +58,7 @@ public:
bool ParseString(std::string); // copies by intention
bool ParseElement(const TiXmlElement*);
bool ParseEpisodeGuide(std::string strUrls); // copies by intention
+ void AddElement(std::string url, std::string aspect = "", std::string referrer = "", std::string cache = "", bool post = false, bool isgz = false, int season = -1);
const SUrlEntry GetFirstThumb(const std::string &type = "") const;
const SUrlEntry GetSeasonThumb(int season, const std::string &type = "") const;
diff --git a/xbmc/video/VideoInfoTag.cpp b/xbmc/video/VideoInfoTag.cpp
index 74bfef9989..79ae1a34ce 100644
--- a/xbmc/video/VideoInfoTag.cpp
+++ b/xbmc/video/VideoInfoTag.cpp
@@ -1453,7 +1453,10 @@ void CVideoInfoTag::SetOriginalTitle(std::string originalTitle)
void CVideoInfoTag::SetEpisodeGuide(std::string episodeGuide)
{
- m_strEpisodeGuide = Trim(std::move(episodeGuide));
+ if (StringUtils::StartsWith(episodeGuide, "<episodeguide"))
+ m_strEpisodeGuide = Trim(std::move(episodeGuide));
+ else
+ m_strEpisodeGuide = StringUtils::Format("<episodeguide>%s</episodeguide>", Trim(std::move(episodeGuide)).c_str());
}
void CVideoInfoTag::SetStatus(std::string status)