2 * Copyright (C) 2005-2008 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "VideoInfoTag.h"
23 #include "utils/XMLUtils.h"
24 #include "guilib/LocalizeStrings.h"
25 #include "settings/GUISettings.h"
26 #include "settings/AdvancedSettings.h"
27 #include "utils/log.h"
28 #include "utils/StringUtils.h"
29 #include "utils/Variant.h"
30 #include "utils/CharsetConverter.h"
31 #include "TextureCache.h"
32 #include "filesystem/File.h"
38 void CVideoInfoTag::Reset()
41 m_writingCredits.clear();
45 m_strPlotOutline.clear();
47 m_strPictureURL.Clear();
49 m_strShowTitle.clear();
50 m_strOriginalTitle.clear();
51 m_strSortTitle.clear();
59 m_strIMDBNumber.clear();
60 m_strMPAARating.clear();
61 m_strFileNameAndPath.clear();
64 m_strProductionCode.clear();
74 m_iSpecialSortSeason = -1;
75 m_iSpecialSortEpisode = -1;
81 m_fanart.m_xml.clear();
85 m_streamDetails.Reset();
90 m_resumePoint.Reset();
91 m_resumePoint.type = CBookmark::RESUME;
94 m_strShowPath.clear();
99 bool CVideoInfoTag::Save(TiXmlNode *node, const CStdString &tag, bool savePathInfo, const TiXmlElement *additionalNode)
101 if (!node) return false;
103 // we start with a <tag> tag
104 TiXmlElement movieElement(tag.c_str());
105 TiXmlNode *movie = node->InsertEndChild(movieElement);
107 if (!movie) return false;
109 XMLUtils::SetString(movie, "title", m_strTitle);
110 if (!m_strOriginalTitle.IsEmpty())
111 XMLUtils::SetString(movie, "originaltitle", m_strOriginalTitle);
112 if (!m_strShowTitle.IsEmpty())
113 XMLUtils::SetString(movie, "showtitle", m_strShowTitle);
114 if (!m_strSortTitle.IsEmpty())
115 XMLUtils::SetString(movie, "sorttitle", m_strSortTitle);
116 XMLUtils::SetFloat(movie, "rating", m_fRating);
117 XMLUtils::SetFloat(movie, "epbookmark", m_fEpBookmark);
118 XMLUtils::SetInt(movie, "year", m_iYear);
119 XMLUtils::SetInt(movie, "top250", m_iTop250);
120 if (tag == "episodedetails" || tag == "tvshow")
122 XMLUtils::SetInt(movie, "season", m_iSeason);
123 XMLUtils::SetInt(movie, "episode", m_iEpisode);
124 XMLUtils::SetInt(movie, "displayseason",m_iSpecialSortSeason);
125 XMLUtils::SetInt(movie, "displayepisode",m_iSpecialSortEpisode);
127 if (tag == "musicvideo")
129 XMLUtils::SetInt(movie, "track", m_iTrack);
130 XMLUtils::SetString(movie, "album", m_strAlbum);
132 XMLUtils::SetString(movie, "votes", m_strVotes);
133 XMLUtils::SetString(movie, "outline", m_strPlotOutline);
134 XMLUtils::SetString(movie, "plot", m_strPlot);
135 XMLUtils::SetString(movie, "tagline", m_strTagLine);
136 XMLUtils::SetString(movie, "runtime", m_strRuntime);
137 if (!m_strPictureURL.m_xml.empty())
140 doc.Parse(m_strPictureURL.m_xml);
141 const TiXmlNode* thumb = doc.FirstChild("thumb");
144 movie->InsertEndChild(*thumb);
145 thumb = thumb->NextSibling("thumb");
148 if (m_fanart.m_xml.size())
151 doc.Parse(m_fanart.m_xml);
152 movie->InsertEndChild(*doc.RootElement());
154 XMLUtils::SetString(movie, "mpaa", m_strMPAARating);
155 XMLUtils::SetInt(movie, "playcount", m_playCount);
156 XMLUtils::SetDate(movie, "lastplayed", m_lastPlayed);
159 XMLUtils::SetString(movie, "file", m_strFile);
160 XMLUtils::SetString(movie, "path", m_strPath);
161 XMLUtils::SetString(movie, "filenameandpath", m_strFileNameAndPath);
162 XMLUtils::SetString(movie, "basepath", m_basePath);
164 if (!m_strEpisodeGuide.IsEmpty())
167 doc.Parse(m_strEpisodeGuide);
168 if (doc.RootElement())
169 movie->InsertEndChild(*doc.RootElement());
171 XMLUtils::SetString(movie, "episodeguide", m_strEpisodeGuide);
174 XMLUtils::SetString(movie, "id", m_strIMDBNumber);
175 XMLUtils::SetStringArray(movie, "genre", m_genre);
176 XMLUtils::SetStringArray(movie, "country", m_country);
177 XMLUtils::SetStringArray(movie, "set", m_set);
178 XMLUtils::SetStringArray(movie, "tag", m_tags);
179 XMLUtils::SetStringArray(movie, "credits", m_writingCredits);
180 XMLUtils::SetStringArray(movie, "director", m_director);
181 XMLUtils::SetDate(movie, "premiered", m_premiered);
182 XMLUtils::SetString(movie, "status", m_strStatus);
183 XMLUtils::SetString(movie, "code", m_strProductionCode);
184 XMLUtils::SetDate(movie, "aired", m_firstAired);
185 XMLUtils::SetStringArray(movie, "studio", m_studio);
186 XMLUtils::SetString(movie, "trailer", m_strTrailer);
188 if (m_streamDetails.HasItems())
190 // it goes fileinfo/streamdetails/[video|audio|subtitle]
191 TiXmlElement fileinfo("fileinfo");
192 TiXmlElement streamdetails("streamdetails");
193 for (int iStream=1; iStream<=m_streamDetails.GetVideoStreamCount(); iStream++)
195 TiXmlElement stream("video");
196 XMLUtils::SetString(&stream, "codec", m_streamDetails.GetVideoCodec(iStream));
197 XMLUtils::SetFloat(&stream, "aspect", m_streamDetails.GetVideoAspect(iStream));
198 XMLUtils::SetInt(&stream, "width", m_streamDetails.GetVideoWidth(iStream));
199 XMLUtils::SetInt(&stream, "height", m_streamDetails.GetVideoHeight(iStream));
200 XMLUtils::SetInt(&stream, "durationinseconds", m_streamDetails.GetVideoDuration(iStream));
201 streamdetails.InsertEndChild(stream);
203 for (int iStream=1; iStream<=m_streamDetails.GetAudioStreamCount(); iStream++)
205 TiXmlElement stream("audio");
206 XMLUtils::SetString(&stream, "codec", m_streamDetails.GetAudioCodec(iStream));
207 XMLUtils::SetString(&stream, "language", m_streamDetails.GetAudioLanguage(iStream));
208 XMLUtils::SetInt(&stream, "channels", m_streamDetails.GetAudioChannels(iStream));
209 streamdetails.InsertEndChild(stream);
211 for (int iStream=1; iStream<=m_streamDetails.GetSubtitleStreamCount(); iStream++)
213 TiXmlElement stream("subtitle");
214 XMLUtils::SetString(&stream, "language", m_streamDetails.GetSubtitleLanguage(iStream));
215 streamdetails.InsertEndChild(stream);
217 fileinfo.InsertEndChild(streamdetails);
218 movie->InsertEndChild(fileinfo);
219 } /* if has stream details */
222 for (iCast it = m_cast.begin(); it != m_cast.end(); ++it)
225 TiXmlElement cast("actor");
226 TiXmlNode *node = movie->InsertEndChild(cast);
227 TiXmlElement actor("name");
228 TiXmlNode *actorNode = node->InsertEndChild(actor);
229 TiXmlText name(it->strName);
230 actorNode->InsertEndChild(name);
231 TiXmlElement role("role");
232 TiXmlNode *roleNode = node->InsertEndChild(role);
233 TiXmlText character(it->strRole);
234 roleNode->InsertEndChild(character);
235 TiXmlElement thumb("thumb");
236 TiXmlNode *thumbNode = node->InsertEndChild(thumb);
237 TiXmlText th(it->thumbUrl.GetFirstThumb().m_url);
238 thumbNode->InsertEndChild(th);
240 XMLUtils::SetStringArray(movie, "artist", m_artist);
241 XMLUtils::SetStringArray(movie, "showlink", m_showLink);
243 TiXmlElement resume("resume");
244 XMLUtils::SetFloat(&resume, "position", (float)m_resumePoint.timeInSeconds);
245 XMLUtils::SetFloat(&resume, "total", (float)m_resumePoint.totalTimeInSeconds);
246 movie->InsertEndChild(resume);
248 XMLUtils::SetString(movie, "dateadded", m_dateAdded.GetAsDBDateTime());
251 movie->InsertEndChild(*additionalNode);
256 bool CVideoInfoTag::Load(const TiXmlElement *element, bool append, bool prioritise)
262 ParseNative(element, prioritise);
266 void CVideoInfoTag::Archive(CArchive& ar)
271 ar << m_writingCredits;
275 ar << m_strPlotOutline;
277 ar << m_strPictureURL.m_spoof;
278 ar << m_strPictureURL.m_xml;
279 ar << m_fanart.m_xml;
281 ar << m_strSortTitle;
285 ar << (int)m_cast.size();
286 for (unsigned int i=0;i<m_cast.size();++i)
288 ar << m_cast[i].strName;
289 ar << m_cast[i].strRole;
290 ar << m_cast[i].thumb;
291 ar << m_cast[i].thumbUrl.m_xml;
300 ar << m_strIMDBNumber;
301 ar << m_strMPAARating;
302 ar << m_strFileNameAndPath;
303 ar << m_strOriginalTitle;
304 ar << m_strEpisodeGuide;
307 ar << m_strProductionCode;
309 ar << m_strShowTitle;
321 ar << m_iSpecialSortSeason;
322 ar << m_iSpecialSortEpisode;
325 ar << dynamic_cast<IArchivable&>(m_streamDetails);
329 ar << m_parentPathID;
330 ar << m_resumePoint.timeInSeconds;
331 ar << m_resumePoint.totalTimeInSeconds;
334 ar << m_dateAdded.GetAsDBDateTime();
341 ar >> m_writingCredits;
345 ar >> m_strPlotOutline;
347 ar >> m_strPictureURL.m_spoof;
348 ar >> m_strPictureURL.m_xml;
349 m_strPictureURL.Parse();
350 ar >> m_fanart.m_xml;
353 ar >> m_strSortTitle;
359 for (int i=0;i<iCastSize;++i)
367 info.thumbUrl.ParseString(strXml);
368 m_cast.push_back(info);
377 ar >> m_strIMDBNumber;
378 ar >> m_strMPAARating;
379 ar >> m_strFileNameAndPath;
380 ar >> m_strOriginalTitle;
381 ar >> m_strEpisodeGuide;
384 ar >> m_strProductionCode;
386 ar >> m_strShowTitle;
398 ar >> m_iSpecialSortSeason;
399 ar >> m_iSpecialSortEpisode;
402 ar >> dynamic_cast<IArchivable&>(m_streamDetails);
406 ar >> m_parentPathID;
407 ar >> m_resumePoint.timeInSeconds;
408 ar >> m_resumePoint.totalTimeInSeconds;
412 CStdString dateAdded;
414 m_dateAdded.SetFromDBDateTime(dateAdded);
420 void CVideoInfoTag::Serialize(CVariant& value)
423 All the StringUtils::Join() calls can be removed once backwards-compatibility to
424 JSON-RPC v4 can be broken */
425 value["director"] = StringUtils::Join(m_director, " / ");
426 value["writer"] = StringUtils::Join(m_writingCredits, " / ");
427 value["genre"] = StringUtils::Join(m_genre, " / ");
428 value["country"] = StringUtils::Join(m_country, " / ");
429 value["tagline"] = m_strTagLine;
430 value["plotoutline"] = m_strPlotOutline;
431 value["plot"] = m_strPlot;
432 value["title"] = m_strTitle;
433 value["votes"] = m_strVotes;
434 value["studio"] = StringUtils::Join(m_studio, " / ");
435 value["trailer"] = m_strTrailer;
436 value["cast"] = CVariant(CVariant::VariantTypeArray);
437 for (unsigned int i = 0; i < m_cast.size(); ++i)
440 actor["name"] = m_cast[i].strName;
441 actor["role"] = m_cast[i].strRole;
442 if (!m_cast[i].thumb.IsEmpty())
443 actor["thumbnail"] = CTextureCache::GetWrappedImageURL(m_cast[i].thumb);
444 value["cast"].push_back(actor);
446 value["set"] = m_set;
447 value["setid"] = CVariant(CVariant::VariantTypeArray);
448 for (unsigned int i = 0; i < m_setId.size(); i++)
449 value["setid"].push_back(m_setId[i]);
450 value["tags"] = m_tags;
451 value["runtime"] = m_strRuntime;
452 value["file"] = m_strFile;
453 value["path"] = m_strPath;
454 value["imdbnumber"] = m_strIMDBNumber;
455 value["mpaa"] = m_strMPAARating;
456 value["filenameandpath"] = m_strFileNameAndPath;
457 value["originaltitle"] = m_strOriginalTitle;
458 value["sorttitle"] = m_strSortTitle;
459 value["episodeguide"] = m_strEpisodeGuide;
460 value["premiered"] = m_premiered.IsValid() ? m_premiered.GetAsDBDate() : StringUtils::EmptyString;
461 value["status"] = m_strStatus;
462 value["productioncode"] = m_strProductionCode;
463 value["firstaired"] = m_firstAired.IsValid() ? m_firstAired.GetAsDBDate() : StringUtils::EmptyString;
464 value["showtitle"] = m_strShowTitle;
465 value["album"] = m_strAlbum;
466 value["artist"] = StringUtils::Join(m_artist, " / ");
467 value["playcount"] = m_playCount;
468 value["lastplayed"] = m_lastPlayed.IsValid() ? m_lastPlayed.GetAsDBDateTime() : StringUtils::EmptyString;
469 value["top250"] = m_iTop250;
470 value["year"] = m_iYear;
471 value["season"] = m_iSeason;
472 value["episode"] = m_iEpisode;
473 value["rating"] = m_fRating;
474 value["dbid"] = m_iDbId;
475 value["fileid"] = m_iFileId;
476 value["track"] = m_iTrack;
477 value["showlink"] = StringUtils::Join(m_showLink, " / ");
478 m_streamDetails.Serialize(value["streamdetails"]);
479 CVariant resume = CVariant(CVariant::VariantTypeObject);
480 resume["position"] = (float)m_resumePoint.timeInSeconds;
481 resume["total"] = (float)m_resumePoint.totalTimeInSeconds;
482 value["resume"] = resume;
483 value["tvshowid"] = m_iIdShow;
484 value["tvshowpath"] = m_strShowPath;
485 value["dateadded"] = m_dateAdded.IsValid() ? m_dateAdded.GetAsDBDateTime() : StringUtils::EmptyString;
486 value["type"] = m_type;
487 value["seasonid"] = m_iIdSeason;
490 void CVideoInfoTag::ToSortable(SortItem& sortable)
492 sortable[FieldDirector] = m_director;
493 sortable[FieldWriter] = m_writingCredits;
494 sortable[FieldGenre] = m_genre;
495 sortable[FieldCountry] = m_country;
496 sortable[FieldTagline] = m_strTagLine;
497 sortable[FieldPlotOutline] = m_strPlotOutline;
498 sortable[FieldPlot] = m_strPlot;
499 sortable[FieldTitle] = m_strTitle;
500 sortable[FieldVotes] = m_strVotes;
501 sortable[FieldStudio] = m_studio;
502 sortable[FieldTrailer] = m_strTrailer;
503 sortable[FieldSet] = m_set;
504 sortable[FieldTime] = m_strRuntime;
505 sortable[FieldFilename] = m_strFile;
506 sortable[FieldMPAA] = m_strMPAARating;
507 sortable[FieldPath] = m_strFileNameAndPath;
508 sortable[FieldSortTitle] = m_strSortTitle;
509 sortable[FieldTvShowStatus] = m_strStatus;
510 sortable[FieldProductionCode] = m_strProductionCode;
511 sortable[FieldAirDate] = m_firstAired.IsValid() ? m_firstAired.GetAsDBDate() : (m_premiered.IsValid() ? m_premiered.GetAsDBDate() : StringUtils::EmptyString);
512 sortable[FieldTvShowTitle] = m_strShowTitle;
513 sortable[FieldAlbum] = m_strAlbum;
514 sortable[FieldArtist] = m_artist;
515 sortable[FieldPlaycount] = m_playCount;
516 sortable[FieldLastPlayed] = m_lastPlayed.IsValid() ? m_lastPlayed.GetAsDBDateTime() : StringUtils::EmptyString;
517 sortable[FieldTop250] = m_iTop250;
518 sortable[FieldYear] = m_iYear;
519 sortable[FieldSeason] = m_iSeason;
520 sortable[FieldEpisodeNumber] = m_iEpisode;
521 sortable[FieldRating] = m_fRating;
522 sortable[FieldId] = m_iDbId;
523 sortable[FieldTrackNumber] = m_iTrack;
525 sortable[FieldTime] = m_streamDetails.GetVideoDuration();
526 sortable[FieldVideoResolution] = m_streamDetails.GetVideoHeight();
527 sortable[FieldVideoAspectRatio] = m_streamDetails.GetVideoAspect();
528 sortable[FieldVideoCodec] = m_streamDetails.GetVideoCodec();
530 sortable[FieldAudioChannels] = m_streamDetails.GetAudioChannels();
531 sortable[FieldAudioCodec] = m_streamDetails.GetAudioCodec();
532 sortable[FieldAudioLanguage] = m_streamDetails.GetAudioLanguage();
534 sortable[FieldSubtitleLanguage] = m_streamDetails.GetSubtitleLanguage();
536 sortable[FieldInProgress] = m_resumePoint.timeInSeconds > 0 && m_resumePoint.totalTimeInSeconds > 0;
537 sortable[FieldDateAdded] = m_dateAdded.IsValid() ? m_dateAdded.GetAsDBDateTime() : StringUtils::EmptyString;
538 sortable[FieldMediaType] = DatabaseUtils::MediaTypeFromString(m_type);
541 const CStdString CVideoInfoTag::GetCast(bool bIncludeRole /*= false*/) const
544 for (iCast it = m_cast.begin(); it != m_cast.end(); ++it)
546 CStdString character;
547 if (it->strRole.IsEmpty() || !bIncludeRole)
548 character.Format("%s\n", it->strName.c_str());
550 character.Format("%s %s %s\n", it->strName.c_str(), g_localizeStrings.Get(20347).c_str(), it->strRole.c_str());
551 strLabel += character;
553 return strLabel.TrimRight("\n");
556 void CVideoInfoTag::ParseNative(const TiXmlElement* movie, bool prioritise)
558 XMLUtils::GetString(movie, "title", m_strTitle);
559 XMLUtils::GetString(movie, "originaltitle", m_strOriginalTitle);
560 XMLUtils::GetString(movie, "showtitle", m_strShowTitle);
561 XMLUtils::GetString(movie, "sorttitle", m_strSortTitle);
562 XMLUtils::GetFloat(movie, "rating", m_fRating);
563 XMLUtils::GetFloat(movie, "epbookmark", m_fEpBookmark);
565 const TiXmlElement* rElement = movie->FirstChildElement("rating");
566 if (rElement && (rElement->QueryIntAttribute("max", &max_value) == TIXML_SUCCESS) && max_value>=1)
568 m_fRating = m_fRating / max_value * 10; // Normalise the Movie Rating to between 1 and 10
570 XMLUtils::GetInt(movie, "year", m_iYear);
571 XMLUtils::GetInt(movie, "top250", m_iTop250);
572 XMLUtils::GetInt(movie, "season", m_iSeason);
573 XMLUtils::GetInt(movie, "episode", m_iEpisode);
574 XMLUtils::GetInt(movie, "track", m_iTrack);
575 XMLUtils::GetInt(movie, "displayseason", m_iSpecialSortSeason);
576 XMLUtils::GetInt(movie, "displayepisode", m_iSpecialSortEpisode);
578 XMLUtils::GetInt(movie, "displayafterseason",after);
581 m_iSpecialSortSeason = after;
582 m_iSpecialSortEpisode = 0x1000; // should be more than any realistic episode number
584 XMLUtils::GetString(movie, "votes", m_strVotes);
585 XMLUtils::GetString(movie, "outline", m_strPlotOutline);
586 XMLUtils::GetString(movie, "plot", m_strPlot);
587 XMLUtils::GetString(movie, "tagline", m_strTagLine);
588 XMLUtils::GetString(movie, "runtime", m_strRuntime);
589 XMLUtils::GetString(movie, "mpaa", m_strMPAARating);
590 XMLUtils::GetInt(movie, "playcount", m_playCount);
591 XMLUtils::GetDate(movie, "lastplayed", m_lastPlayed);
592 XMLUtils::GetString(movie, "file", m_strFile);
593 XMLUtils::GetString(movie, "path", m_strPath);
594 XMLUtils::GetString(movie, "id", m_strIMDBNumber);
595 XMLUtils::GetString(movie, "filenameandpath", m_strFileNameAndPath);
596 XMLUtils::GetDate(movie, "premiered", m_premiered);
597 XMLUtils::GetString(movie, "status", m_strStatus);
598 XMLUtils::GetString(movie, "code", m_strProductionCode);
599 XMLUtils::GetDate(movie, "aired", m_firstAired);
600 XMLUtils::GetString(movie, "album", m_strAlbum);
601 XMLUtils::GetString(movie, "trailer", m_strTrailer);
602 XMLUtils::GetString(movie, "basepath", m_basePath);
604 size_t iThumbCount = m_strPictureURL.m_url.size();
605 CStdString xmlAdd = m_strPictureURL.m_xml;
607 const TiXmlElement* thumb = movie->FirstChildElement("thumb");
610 m_strPictureURL.ParseElement(thumb);
615 xmlAdd = temp+xmlAdd;
617 thumb = thumb->NextSiblingElement("thumb");
620 // prioritise thumbs from nfos
621 if (prioritise && iThumbCount && iThumbCount != m_strPictureURL.m_url.size())
623 rotate(m_strPictureURL.m_url.begin(),
624 m_strPictureURL.m_url.begin()+iThumbCount,
625 m_strPictureURL.m_url.end());
626 m_strPictureURL.m_xml = xmlAdd;
629 XMLUtils::GetStringArray(movie, "genre", m_genre, prioritise, g_advancedSettings.m_videoItemSeparator);
630 XMLUtils::GetStringArray(movie, "country", m_country, prioritise, g_advancedSettings.m_videoItemSeparator);
631 XMLUtils::GetStringArray(movie, "credits", m_writingCredits, prioritise, g_advancedSettings.m_videoItemSeparator);
632 XMLUtils::GetStringArray(movie, "director", m_director, prioritise, g_advancedSettings.m_videoItemSeparator);
633 XMLUtils::GetStringArray(movie, "showlink", m_showLink, prioritise, g_advancedSettings.m_videoItemSeparator);
636 const TiXmlElement* node = movie->FirstChildElement("actor");
637 if (node && node->FirstChild() && prioritise)
641 const TiXmlNode *actor = node->FirstChild("name");
642 if (actor && actor->FirstChild())
645 info.strName = actor->FirstChild()->Value();
646 const TiXmlNode *roleNode = node->FirstChild("role");
647 if (roleNode && roleNode->FirstChild())
648 info.strRole = roleNode->FirstChild()->Value();
649 const TiXmlElement* thumb = node->FirstChildElement("thumb");
652 info.thumbUrl.ParseElement(thumb);
653 thumb = thumb->NextSiblingElement("thumb");
655 const char* clear=node->Attribute("clear");
656 if (clear && stricmp(clear,"true"))
658 m_cast.push_back(info);
660 node = node->NextSiblingElement("actor");
663 XMLUtils::GetStringArray(movie, "set", m_set, prioritise, g_advancedSettings.m_videoItemSeparator);
664 XMLUtils::GetStringArray(movie, "tag", m_tags, prioritise, g_advancedSettings.m_videoItemSeparator);
665 XMLUtils::GetStringArray(movie, "studio", m_studio, prioritise, g_advancedSettings.m_videoItemSeparator);
667 node = movie->FirstChildElement("artist");
668 if (node && node->FirstChild() && prioritise)
672 const TiXmlNode* pNode = node->FirstChild("name");
673 const char* pValue=NULL;
674 if (pNode && pNode->FirstChild())
675 pValue = pNode->FirstChild()->Value();
676 else if (node->FirstChild())
677 pValue = node->FirstChild()->Value();
680 const char* clear=node->Attribute("clear");
681 if (clear && stricmp(clear,"true")==0)
683 vector<string> artists = StringUtils::Split(pValue, g_advancedSettings.m_videoItemSeparator);
684 m_artist.insert(m_artist.end(), artists.begin(), artists.end());
686 node = node->NextSiblingElement("artist");
689 node = movie->FirstChildElement("fileinfo");
692 // Try to pull from fileinfo/streamdetails/[video|audio|subtitle]
693 const TiXmlNode *nodeStreamDetails = node->FirstChild("streamdetails");
694 if (nodeStreamDetails)
696 const TiXmlNode *nodeDetail = NULL;
697 while ((nodeDetail = nodeStreamDetails->IterateChildren("audio", nodeDetail)))
699 CStreamDetailAudio *p = new CStreamDetailAudio();
700 XMLUtils::GetString(nodeDetail, "codec", p->m_strCodec);
701 XMLUtils::GetString(nodeDetail, "language", p->m_strLanguage);
702 XMLUtils::GetInt(nodeDetail, "channels", p->m_iChannels);
703 p->m_strCodec.MakeLower();
704 p->m_strLanguage.MakeLower();
705 m_streamDetails.AddStream(p);
708 while ((nodeDetail = nodeStreamDetails->IterateChildren("video", nodeDetail)))
710 CStreamDetailVideo *p = new CStreamDetailVideo();
711 XMLUtils::GetString(nodeDetail, "codec", p->m_strCodec);
712 XMLUtils::GetFloat(nodeDetail, "aspect", p->m_fAspect);
713 XMLUtils::GetInt(nodeDetail, "width", p->m_iWidth);
714 XMLUtils::GetInt(nodeDetail, "height", p->m_iHeight);
715 XMLUtils::GetInt(nodeDetail, "durationinseconds", p->m_iDuration);
716 p->m_strCodec.MakeLower();
717 m_streamDetails.AddStream(p);
720 while ((nodeDetail = nodeStreamDetails->IterateChildren("subtitle", nodeDetail)))
722 CStreamDetailSubtitle *p = new CStreamDetailSubtitle();
723 XMLUtils::GetString(nodeDetail, "language", p->m_strLanguage);
724 p->m_strLanguage.MakeLower();
725 m_streamDetails.AddStream(p);
728 m_streamDetails.DetermineBestStreams();
731 const TiXmlElement *epguide = movie->FirstChildElement("episodeguide");
734 // DEPRECIATE ME - support for old XML-encoded <episodeguide> blocks.
735 if (epguide->FirstChild() && strnicmp("<episodeguide", epguide->FirstChild()->Value(), 13) == 0)
736 m_strEpisodeGuide = epguide->FirstChild()->Value();
741 m_strEpisodeGuide = stream.str();
746 const TiXmlElement *fanart = movie->FirstChildElement("fanart");
749 // we prioritise mixed-mode nfo's with fanart set
754 m_fanart.m_xml = temp+m_fanart.m_xml;
757 m_fanart.m_xml << *fanart;
762 const TiXmlNode *resume = movie->FirstChild("resume");
765 XMLUtils::GetDouble(resume, "position", m_resumePoint.timeInSeconds);
766 XMLUtils::GetDouble(resume, "total", m_resumePoint.totalTimeInSeconds);
770 CStdString dateAdded;
771 XMLUtils::GetString(movie, "dateadded", dateAdded);
772 m_dateAdded.SetFromDBDateTime(dateAdded);
775 bool CVideoInfoTag::HasStreamDetails() const
777 return m_streamDetails.HasItems();
780 bool CVideoInfoTag::IsEmpty() const
782 return (m_strTitle.IsEmpty() &&
783 m_strFile.IsEmpty() &&
784 m_strPath.IsEmpty());