示例#1
0
文件: IMDB.cpp 项目: flyingtime/boxee
void CIMDB::GetURL(const CStdString &movieFile, const CStdString &movieName, const CStdString &movieYear, CScraperUrl& scrURL)
{
  bool bOkay=false;
  if (m_info.strContent.Equals("musicvideos"))
  {
    CVideoInfoTag tag;
    if (ScrapeFilename(movieFile,tag))
    {
      m_parser.m_param[0] = tag.m_strArtist;
      m_parser.m_param[1] = tag.m_strTitle;
      CUtil::URLEncode(m_parser.m_param[0]);
      CUtil::URLEncode(m_parser.m_param[1]);
      bOkay = true;
    }
  }
  if (!bOkay)
  {
    if (!movieYear.IsEmpty())
      m_parser.m_param[1] = movieYear;

    // convert to the encoding requested by the parser
    g_charsetConverter.utf8To(m_parser.GetSearchStringEncoding(), movieName, m_parser.m_param[0]);
    CUtil::URLEncode(m_parser.m_param[0]);
  }
  scrURL.ParseString(m_parser.Parse("CreateSearchUrl",&m_info.settings));
}
示例#2
0
TEST(TestScraperUrl, General)
{
  CScraperUrl a;
  std::string xmlstring;

  xmlstring = "<data spoof=\"blah\" gzip=\"yes\">\n"
              "  <someurl>\n"
              "  </someurl>\n"
              "  <someotherurl>\n"
              "  </someotherurl>\n"
              "</data>\n";
  EXPECT_TRUE(a.ParseString(xmlstring));

  EXPECT_STREQ("blah", a.GetFirstThumb().m_spoof.c_str());
  EXPECT_STREQ("someurl", a.GetFirstThumb().m_url.c_str());
  EXPECT_STREQ("", a.GetFirstThumb().m_cache.c_str());
  EXPECT_EQ(CScraperUrl::URL_TYPE_GENERAL, a.GetFirstThumb().m_type);
  EXPECT_FALSE(a.GetFirstThumb().m_post);
  EXPECT_TRUE(a.GetFirstThumb().m_isgz);
  EXPECT_EQ(-1, a.GetFirstThumb().m_season);
}
bool CVideoLibraryRefreshingJob::Work(CVideoDatabase &db)
{
  if (m_item == nullptr)
    return false;

  // determine the scraper for the item's path
  VIDEO::SScanSettings scanSettings;
  ADDON::ScraperPtr scraper = db.GetScraperForPath(m_item->GetPath(), scanSettings);
  if (scraper == nullptr)
    return false;

  // copy the scraper in case we need it again
  ADDON::ScraperPtr originalScraper(scraper);

  // get the item's correct title
  std::string itemTitle = m_searchTitle;
  if (itemTitle.empty())
    itemTitle = m_item->GetMovieName(scanSettings.parent_name);

  CScraperUrl scraperUrl;
  VIDEO::CVideoInfoScanner scanner;
  bool needsRefresh = m_forceRefresh;
  bool hasDetails = false;
  bool ignoreNfo = m_ignoreNfo;

  // run this in a loop in case we need to refresh again
  bool failure = false;
  do
  {
    if (!ignoreNfo)
    {
      // check if there's an NFO for the item
      CNfoFile::NFOResult nfoResult = scanner.CheckForNFOFile(m_item.get(), scanSettings.parent_name_root, scraper, scraperUrl);
      // if there's no NFO remember it in case we have to refresh again
      if (nfoResult == CNfoFile::ERROR_NFO)
        ignoreNfo = true;
      else if (nfoResult != CNfoFile::NO_NFO)
        hasDetails = true;


      // if we are performing a forced refresh ask the user to choose between using a valid NFO and a valid scraper
      if (needsRefresh && IsModal() && !scraper->IsNoop() &&
         (nfoResult == CNfoFile::URL_NFO || nfoResult == CNfoFile::COMBINED_NFO || nfoResult == CNfoFile::FULL_NFO))
      {
        int heading = 20159;
        if (scraper->Content() == CONTENT_MOVIES)
          heading = 13346;
        else if (scraper->Content() == CONTENT_TVSHOWS)
          heading = m_item->m_bIsFolder ? 20351 : 20352;
        else if (scraper->Content() == CONTENT_MUSICVIDEOS)
          heading = 20393;
        if (CGUIDialogYesNo::ShowAndGetInput(heading, 20446))
        {
          hasDetails = false;
          ignoreNfo = true;
          scraperUrl.Clear();
          scraper = originalScraper;
        }
      }
    }

    // no need to re-fetch the episode guide for episodes
    if (scraper->Content() == CONTENT_TVSHOWS && !m_item->m_bIsFolder)
      hasDetails = true;

    // if we don't have an url or need to refresh anyway do the web search
    if (!hasDetails && (needsRefresh || scraperUrl.m_url.empty()))
    {
      SetTitle(StringUtils::Format(g_localizeStrings.Get(197).c_str(), scraper->Name().c_str()));
      SetText(itemTitle);
      SetProgress(0);

      // clear any cached data from the scraper
      scraper->ClearCache();

      // create the info downloader for the scraper
      CVideoInfoDownloader infoDownloader(scraper);

      // try to find a matching item
      MOVIELIST itemResultList;
      int result = infoDownloader.FindMovie(itemTitle, itemResultList, GetProgressDialog());

      // close the progress dialog
      MarkFinished();

      if (result > 0)
      {
        // there are multiple matches for the item
        if (!itemResultList.empty())
        {
          // choose the first match
          if (!IsModal())
            scraperUrl = itemResultList.at(0);
          else
          {
            // ask the user what to do
            CGUIDialogSelect* selectDialog = static_cast<CGUIDialogSelect*>(g_windowManager.GetWindow(WINDOW_DIALOG_SELECT));
            selectDialog->Reset();
            selectDialog->SetHeading(scraper->Content() == CONTENT_TVSHOWS ? 20356 : 196);
            for (const auto& itemResult : itemResultList)
              selectDialog->Add(itemResult.strTitle);
            selectDialog->EnableButton(true, 413); // "Manual"
            selectDialog->Open();

            // check if the user has chosen one of the results
            int selectedItem = selectDialog->GetSelectedItem();
            if (selectedItem >= 0)
              scraperUrl = itemResultList.at(selectedItem);
            // the user hasn't chosen one of the results and but has chosen to manually enter a title to use
            else if (selectDialog->IsButtonPressed())
            {
              // ask the user to input a title to use
              if (!CGUIKeyboardFactory::ShowAndGetInput(itemTitle, g_localizeStrings.Get(scraper->Content() == CONTENT_TVSHOWS ? 20357 : 16009), false))
                return false;

              // go through the whole process again
              needsRefresh = true;
              continue;
            }
            // nothing else we can do
            else
              return false;
          }

          CLog::Log(LOGDEBUG, "CVideoLibraryRefreshingJob: user selected item '%s' with URL '%s'", scraperUrl.strTitle.c_str(), scraperUrl.m_url.at(0).m_url.c_str());
        }
      }
      else if (result < 0 || !VIDEO::CVideoInfoScanner::DownloadFailed(GetProgressDialog()))
      {
        failure = true;
        break;
      }
    }

    // if the URL is still empty, check whether or not we're allowed
    // to prompt and ask the user to input a new search title
    if (!hasDetails && scraperUrl.m_url.empty())
    {
      if (IsModal())
      {
        // ask the user to input a title to use
        if (!CGUIKeyboardFactory::ShowAndGetInput(itemTitle, g_localizeStrings.Get(scraper->Content() == CONTENT_TVSHOWS ? 20357 : 16009), false))
          return false;

        // go through the whole process again
        needsRefresh = true;
        continue;
      }

      // nothing else we can do
      failure = true;
      break;
    }

    // before we start downloading all the necessary information cleanup any existing artwork and hashes
    CTextureDatabase textureDb;
    if (textureDb.Open())
    {
      for (const auto& artwork : m_item->GetArt())
        textureDb.InvalidateCachedTexture(artwork.second);

      textureDb.Close();
    }
    m_item->ClearArt();

    // put together the list of items to refresh
    std::string path = m_item->GetPath();
    CFileItemList items;
    if (m_item->HasVideoInfoTag() && m_item->GetVideoInfoTag()->m_iDbId > 0)
    {
      // for a tvshow we need to handle all paths of it
      std::vector<std::string> tvshowPaths;
      if (CMediaTypes::IsMediaType(m_item->GetVideoInfoTag()->m_type, MediaTypeTvShow) && m_refreshAll &&
          db.GetPathsLinkedToTvShow(m_item->GetVideoInfoTag()->m_iDbId, tvshowPaths))
      {
        for (const auto& tvshowPath : tvshowPaths)
        {
          CFileItemPtr tvshowItem(new CFileItem(*m_item->GetVideoInfoTag()));
          tvshowItem->SetPath(tvshowPath);
          items.Add(tvshowItem);
        }
      }
      // otherwise just add a copy of the item
      else
        items.Add(CFileItemPtr(new CFileItem(*m_item->GetVideoInfoTag())));

      // update the path to the real path (instead of a videodb:// one)
      path = m_item->GetVideoInfoTag()->m_strPath;
    }
    else
      items.Add(CFileItemPtr(new CFileItem(*m_item)));

    // set the proper path of the list of items to lookup
    items.SetPath(m_item->m_bIsFolder ? URIUtils::GetParentPath(path) : URIUtils::GetDirectory(path));

    int headingLabel = 198;
    if (scraper->Content() == CONTENT_TVSHOWS)
    {
      if (m_item->m_bIsFolder)
        headingLabel = 20353;
      else
        headingLabel = 20361;
    }
    else if (scraper->Content() == CONTENT_MUSICVIDEOS)
      headingLabel = 20394;

    // prepare the progress dialog for downloading all the necessary information
    SetTitle(g_localizeStrings.Get(headingLabel));
    SetText(scraperUrl.strTitle);
    SetProgress(0);

    // remove any existing data for the item we're going to refresh
    if (m_item->GetVideoInfoTag()->m_iDbId > 0)
    {
      int dbId = m_item->GetVideoInfoTag()->m_iDbId;
      if (scraper->Content() == CONTENT_MOVIES)
        db.DeleteMovie(dbId);
      else if (scraper->Content() == CONTENT_MUSICVIDEOS)
        db.DeleteMusicVideo(dbId);
      else if (scraper->Content() == CONTENT_TVSHOWS)
      {
        if (!m_item->m_bIsFolder)
          db.DeleteEpisode(dbId);
        else if (m_refreshAll)
          db.DeleteTvShow(dbId);
        else
          db.DeleteDetailsForTvShow(dbId);
      }
    }

    // finally download the information for the item
    if (!scanner.RetrieveVideoInfo(items, scanSettings.parent_name, scraper->Content(), !ignoreNfo, &scraperUrl, m_refreshAll, GetProgressDialog()))
    {
      // something went wrong
      MarkFinished();

      // check if the user cancelled
      if (!IsCancelled() && IsModal())
        CGUIDialogOK::ShowAndGetInput(195, itemTitle);

      return false;
    }

    // retrieve the updated information from the database
    if (scraper->Content() == CONTENT_MOVIES)
      db.GetMovieInfo(m_item->GetPath(), *m_item->GetVideoInfoTag());
    else if (scraper->Content() == CONTENT_MUSICVIDEOS)
      db.GetMusicVideoInfo(m_item->GetPath(), *m_item->GetVideoInfoTag());
    else if (scraper->Content() == CONTENT_TVSHOWS)
    {
      // update tvshow info to get updated episode numbers
      if (m_item->m_bIsFolder)
        db.GetTvShowInfo(m_item->GetPath(), *m_item->GetVideoInfoTag());
      else
        db.GetEpisodeInfo(m_item->GetPath(), *m_item->GetVideoInfoTag());
    }

    // we're finally done
    MarkFinished();
    break;
  } while (needsRefresh);

  if (failure && IsModal())
    CGUIDialogOK::ShowAndGetInput(195, itemTitle);

  return true;
}
示例#4
0
void CMusicInfoScraper::FindAlbuminfo()
{
  CStdString strAlbum=m_strAlbum;
  CStdString strHTML;
  m_vecAlbums.erase(m_vecAlbums.begin(), m_vecAlbums.end());

  CScraperParser parser;
  if (!parser.Load(_P("q:\\system\\scrapers\\music\\"+m_info.strPath)))
    return;

  if (!m_info.settings.GetPluginRoot() || m_info.settings.GetSettings().IsEmpty())
  {
    m_info.settings.LoadSettingsXML(_P("q:\\system\\scrapers\\music\\"+m_info.strPath));
    m_info.settings.SaveFromDefault();
  }

  parser.m_param[0] = strAlbum;
  parser.m_param[1] = m_strArtist;
  CUtil::URLEncode(parser.m_param[0]);
  CUtil::URLEncode(parser.m_param[1]);

  CScraperUrl scrURL;
  scrURL.ParseString(parser.Parse("CreateAlbumSearchUrl"));
  if (!CScraperUrl::Get(scrURL.m_url[0], strHTML, m_http) || strHTML.size() == 0)
  {
    CLog::Log(LOGERROR, "%s: Unable to retrieve web site",__FUNCTION__);
    return;
  }

  parser.m_param[0] = strHTML;
  CStdString strXML = parser.Parse("GetAlbumSearchResults",&m_info.settings);
  if (strXML.IsEmpty())
  {
    CLog::Log(LOGERROR, "%s: Unable to parse web site",__FUNCTION__);
    return;
  }

  if (strXML.Find("encoding=\"utf-8\"") < 0)
    g_charsetConverter.unknownToUTF8(strXML);

  // ok, now parse the xml file
  TiXmlDocument doc;
  doc.Parse(strXML.c_str(),0,TIXML_ENCODING_UTF8);
  if (!doc.RootElement())
  {
    CLog::Log(LOGERROR, "%s: Unable to parse xml",__FUNCTION__);
    return;
  }
  TiXmlHandle docHandle( &doc );
  TiXmlElement* album = docHandle.FirstChild( "results" ).FirstChild( "entity" ).Element();
  if (!album)
    return;

  while (album)
  {
    TiXmlNode* title = album->FirstChild("title");
    TiXmlElement* link = album->FirstChildElement("url");
    TiXmlNode* artist = album->FirstChild("artist");
    TiXmlNode* year = album->FirstChild("year");
    if (title && title->FirstChild())
    {
      CStdString strTitle = title->FirstChild()->Value();
      CStdString strArtist;
      CStdString strAlbumName;

      if (artist && artist->FirstChild())
      {
        strArtist = artist->FirstChild()->Value();
        strAlbumName.Format("%s - %s",strArtist.c_str(),strTitle.c_str());
      }
      else
        strAlbumName = strTitle;

      if (year && year->FirstChild())
        strAlbumName.Format("%s (%s)",strAlbumName.c_str(),year->FirstChild()->Value());

      CScraperUrl url;
      if (!link)
        url.ParseString(scrURL.m_xml);

      while (link && link->FirstChild())
      {
        url.ParseElement(link);
        link = link->NextSiblingElement("url");
      }
      CMusicAlbumInfo newAlbum(strTitle, strArtist, strAlbumName, url);
      m_vecAlbums.push_back(newAlbum);
    }
    album = album->NextSiblingElement();
  }
  
  if (m_vecAlbums.size()>0)
    m_bSuccessfull=true;

  return;
}
示例#5
0
void CMusicInfoScraper::FindAlbumInfo()
{
  CStdString strAlbum=m_strAlbum;
  CStdString strHTML;
  m_vecAlbums.erase(m_vecAlbums.begin(), m_vecAlbums.end());

  if (!m_scraper->Load() || !m_scraper->GetParser().HasFunction("CreateAlbumSearchUrl"))
    return;

  CLog::Log(LOGDEBUG, "%s: Searching for '%s - %s' using %s scraper (path: '%s', content: '%s', version: '%s')",
    __FUNCTION__, m_strArtist.c_str(), strAlbum.c_str(), m_scraper->Name().c_str(), m_scraper->Path().c_str(),
    ADDON::TranslateContent(m_scraper->Content()).c_str(), m_scraper->Version().c_str());
  
  vector<CStdString> extras;
  extras.push_back(strAlbum);
  extras.push_back(m_strArtist);
  g_charsetConverter.utf8To(m_scraper->GetParser().GetSearchStringEncoding(), strAlbum, extras[0]);
  g_charsetConverter.utf8To(m_scraper->GetParser().GetSearchStringEncoding(), m_strArtist, extras[1]);
  CURL::Encode(extras[0]);
  CURL::Encode(extras[1]);

  CScraperUrl scrURL;
  vector<CStdString> url = m_scraper->Run("CreateAlbumSearchUrl",scrURL,m_http,&extras);
  if (url.empty())
    return;
  scrURL.ParseString(url[0]);
  vector<CStdString> xml = m_scraper->Run("GetAlbumSearchResults",scrURL,m_http);

  for (vector<CStdString>::iterator it  = xml.begin();
                                    it != xml.end(); ++it)
  {
    // ok, now parse the xml file
    TiXmlDocument doc;
    doc.Parse(it->c_str(),0,TIXML_ENCODING_UTF8);
    TiXmlHandle docHandle( &doc );
    TiXmlElement* album = docHandle.FirstChild( "results" ).FirstChild( "entity" ).Element();

    while (album)
    {
      TiXmlNode* title = album->FirstChild("title");
      TiXmlElement* link = album->FirstChildElement("url");
      TiXmlNode* artist = album->FirstChild("artist");
      TiXmlNode* year = album->FirstChild("year");
      TiXmlElement* relevance = album->FirstChildElement("relevance");
      if (title && title->FirstChild())
      {
        CStdString strTitle = title->FirstChild()->Value();
        CStdString strArtist;
        CStdString strAlbumName;

        if (artist && artist->FirstChild())
        {
          strArtist = artist->FirstChild()->Value();
          strAlbumName.Format("%s - %s",strArtist.c_str(),strTitle.c_str());
        }
        else
          strAlbumName = strTitle;

        if (year && year->FirstChild())
          strAlbumName.Format("%s (%s)",strAlbumName.c_str(),year->FirstChild()->Value());

        CScraperUrl url;
        if (!link)
          url.ParseString(scrURL.m_xml);

        while (link && link->FirstChild())
        {
          url.ParseElement(link);
          link = link->NextSiblingElement("url");
        }
        CMusicAlbumInfo newAlbum(strTitle, strArtist, strAlbumName, url);
        if (relevance && relevance->FirstChild())
        {
          float scale=1;
          const char* newscale = relevance->Attribute("scale");
          if (newscale)
            scale = (float)atof(newscale);
          newAlbum.SetRelevance((float)atof(relevance->FirstChild()->Value())/scale);
        }
        m_vecAlbums.push_back(newAlbum);
      }
      album = album->NextSiblingElement();
    }
  }

  if (m_vecAlbums.size()>0)
    m_bSucceeded=true;

  return;
}
示例#6
0
void CMusicInfoScraper::FindArtistInfo()
{
  CStdString strArtist=m_strArtist;
  CStdString strHTML;
  m_vecArtists.erase(m_vecArtists.begin(), m_vecArtists.end());

  if (!m_scraper->Load())
    return;

  vector<CStdString> extras;
  extras.push_back(m_strArtist);
  g_charsetConverter.utf8To(m_scraper->GetParser().GetSearchStringEncoding(), m_strArtist, extras[0]);
  CURL::Encode(extras[0]);
  
  CLog::Log(LOGDEBUG, "%s: Searching for '%s' using %s scraper (file: '%s', content: '%s', version: '%s')",
    __FUNCTION__, m_strArtist.c_str(), m_scraper->Name().c_str(), m_scraper->Path().c_str(),
    ADDON::TranslateContent(m_scraper->Content()).c_str(), m_scraper->Version().c_str());

  CScraperUrl scrURL;
  vector<CStdString> url = m_scraper->Run("CreateArtistSearchUrl",scrURL,m_http,&extras);
  if (url.empty())
    return;
  scrURL.ParseString(url[0]);

  vector<CStdString> xml = m_scraper->Run("GetArtistSearchResults",scrURL,m_http,&extras);

  for (vector<CStdString>::iterator it  = xml.begin();
                                    it != xml.end(); ++it)
  {
    // ok, now parse the xml file
    TiXmlDocument doc;
    doc.Parse(it->c_str(),0,TIXML_ENCODING_UTF8);
    if (!doc.RootElement())
    {
      CLog::Log(LOGERROR, "%s: Unable to parse xml",__FUNCTION__);
      continue;
    }

    TiXmlHandle docHandle( &doc );
    TiXmlElement* artist = docHandle.FirstChild( "results" ).FirstChild( "entity" ).Element();

    while (artist)
    {
      TiXmlNode* title = artist->FirstChild("title");
      TiXmlNode* year = artist->FirstChild("year");
      TiXmlNode* genre = artist->FirstChild("genre");
      TiXmlElement* link = artist->FirstChildElement("url");
      if (title && title->FirstChild())
      {
        CStdString strTitle = title->FirstChild()->Value();
        CScraperUrl url;
        if (!link)
          url.ParseString(scrURL.m_xml);
        while (link && link->FirstChild())
        {
          url.ParseElement(link);
          link = link->NextSiblingElement("url");
        }
        CMusicArtistInfo newArtist(strTitle, url);
        if (genre && genre->FirstChild())
          newArtist.GetArtist().strGenre = genre->FirstChild()->Value();
        if (year && year->FirstChild())
          newArtist.GetArtist().strBorn = year->FirstChild()->Value();
        m_vecArtists.push_back(newArtist);
      }
      artist = artist->NextSiblingElement();
    }
  }

  if (m_vecArtists.size()>0)
    m_bSucceeded=true;

  return;
}
示例#7
0
文件: IMDB.cpp 项目: flyingtime/boxee
int CIMDB::InternalFindMovie(const CStdString &strMovie, IMDB_MOVIELIST& movielist, bool& sortMovieList, const CStdString& strFunction, CScraperUrl* pUrl)
{
  movielist.clear();

  CScraperUrl scrURL;
  
  CStdString strName = strMovie;
  CStdString movieTitle, movieTitleAndYear, movieYear;
  CUtil::CleanString(strName, movieTitle, movieTitleAndYear, movieYear, true);

  movieTitle.ToLower();

  CLog::Log(LOGDEBUG, "%s: Searching for '%s' using %s scraper (file: '%s', content: '%s', language: '%s', date: '%s', framework: '%s')",
    __FUNCTION__, movieTitle.c_str(), m_info.strTitle.c_str(), m_info.strPath.c_str(), m_info.strContent.c_str(), m_info.strLanguage.c_str(), m_info.strDate.c_str(), m_info.strFramework.c_str());

  if (!pUrl)
  {
  if (m_parser.HasFunction("CreateSearchUrl"))
  {
      GetURL(strMovie, movieTitle, movieYear, scrURL);
  }
  else if (m_info.strContent.Equals("musicvideos"))
  {
    if (!m_parser.HasFunction("FileNameScrape"))
      return false;
    
    CScraperUrl scrURL("filenamescrape");
    scrURL.strTitle = strMovie;
    movielist.push_back(scrURL);
      return 1;
  }
    if (scrURL.m_xml.IsEmpty())
      return 0;
  }
  else
    scrURL = *pUrl;  

  vector<CStdString> strHTML;
  for (unsigned int i=0;i<scrURL.m_url.size();++i)
  {
    CStdString strCurrHTML;
    if (!CScraperUrl::Get(scrURL.m_url[i],strCurrHTML,m_http) || strCurrHTML.size() == 0)
      return 0;
    strHTML.push_back(strCurrHTML);
  }
  
  // now grab our details using the scraper
  for (unsigned int i=0;i<strHTML.size();++i)
    m_parser.m_param[i] = strHTML[i];
  m_parser.m_param[strHTML.size()] = scrURL.m_url[0].m_url;
  CStdString strXML = m_parser.Parse(strFunction,&m_info.settings);
  //CLog::Log(LOGDEBUG,"scraper: %s returned %s",strFunction.c_str(),strXML.c_str());
  if (strXML.IsEmpty())
  {
    CLog::Log(LOGERROR, "%s: Unable to parse web site",__FUNCTION__);
    return 0;
  }
  
  if (!XMLUtils::HasUTF8Declaration(strXML))
    g_charsetConverter.unknownToUTF8(strXML);

  // ok, now parse the xml file
  TiXmlDocument doc;
  doc.Parse(strXML.c_str(),0,TIXML_ENCODING_UTF8);
  if (!doc.RootElement())
  {
    CLog::Log(LOGERROR, "%s: Unable to parse xml",__FUNCTION__);
    return 0;
  }
  if (stricmp(doc.RootElement()->Value(),"error")==0)
  {
    TiXmlElement* title = doc.RootElement()->FirstChildElement("title");
    CStdString strTitle;
    if (title && title->FirstChild() && title->FirstChild()->Value())
      strTitle = title->FirstChild()->Value();
    TiXmlElement* message = doc.RootElement()->FirstChildElement("message");
    CStdString strMessage;
    if (message && message->FirstChild() && message->FirstChild()->Value())
      strMessage = message->FirstChild()->Value();
    CGUIDialogOK* dialog = (CGUIDialogOK*)g_windowManager.GetWindow(WINDOW_DIALOG_OK);
    dialog->SetHeading(strTitle);
    dialog->SetLine(0,strMessage);
    g_application.getApplicationMessenger().DoModal(dialog,WINDOW_DIALOG_OK);
    return -1;
  }
 
  TiXmlHandle docHandle( &doc );

  TiXmlElement* xurl = doc.RootElement()->FirstChildElement("url");
  while (xurl && xurl->FirstChild())
  {
    const char* szFunction = xurl->Attribute("function");
    if (szFunction)
    {
      CScraperUrl scrURL(xurl);
      InternalFindMovie(strMovie,movielist,sortMovieList,szFunction,&scrURL);
    }
    xurl = xurl->NextSiblingElement("url");
  }

  TiXmlElement *movie = docHandle.FirstChild( "results" ).FirstChild( "entity" ).Element();
  if (!movie)
    return 0;

  while (movie)
  {
    // is our result already sorted correctly when handed over from scraper? if so, do not let xbmc sort it
    if (sortMovieList)
    {
      TiXmlElement* results = docHandle.FirstChild("results").Element();
      if (results)
      {
        CStdString szSorted = results->Attribute("sorted");
        sortMovieList = (szSorted.CompareNoCase("yes") != 0);
      }
    }

    CScraperUrl url;
    TiXmlNode *title = movie->FirstChild("title");
    TiXmlElement *link = movie->FirstChildElement("url");
    TiXmlNode *year = movie->FirstChild("year");
    TiXmlNode* id = movie->FirstChild("id");
    TiXmlNode* language = movie->FirstChild("language");
    if (title && title->FirstChild() && link && link->FirstChild())
    {
      url.strTitle = title->FirstChild()->Value();
      while (link && link->FirstChild())
      {
        url.ParseElement(link);
        link = link->NextSiblingElement("url");
      }
      if (id && id->FirstChild())
        url.strId = id->FirstChild()->Value();

      // calculate the relavance of this hit
      CStdString compareTitle = url.strTitle;
      compareTitle.ToLower();
      CStdString matchTitle = movieTitle;
      matchTitle.ToLower();
      // see if we need to add year information
      CStdString compareYear;
        if(year && year->FirstChild())
        compareYear = year->FirstChild()->Value();
      if (!movieYear.IsEmpty() && !compareYear.IsEmpty())
          {
        matchTitle.AppendFormat(" (%s)", movieYear.c_str());
        compareTitle.AppendFormat(" (%s)", compareYear.c_str());
          }
      url.relevance = fstrcmp(matchTitle.c_str(), compareTitle.c_str(), 0);
      // reconstruct a title for the user
      CStdString title = url.strTitle;
      if (!compareYear.IsEmpty())
        title.AppendFormat(" (%s)", compareYear.c_str());
      if (language && language->FirstChild())
        title.AppendFormat(" (%s)", language->FirstChild()->Value());
      url.strTitle = title;
        movielist.push_back(url);
    }
    movie = movie->NextSiblingElement();
  }

  return 1;
}