Exemplo n.º 1
0
//-------------------------------------------------------------------------------------------------------------------
void Xcddb::parseData(const char *buffer)
{
  //writeLog("parseData Start");

  std::map<CStdString, CStdString> keywords;
  std::list<CStdString> keywordsOrder; // remember order of keywords as it appears in data received from CDDB

  // Collect all the keywords and put them in map. 
  // Multiple occurrences of the same keyword indicate that 
  // the data contained on those lines should be concatenated
  char *line;
  const char trenner[3] = {'\n', '\r', '\0'};
  line = strtok((char*)buffer, trenner); // skip first line
  while ((line = strtok(0, trenner)))
  {
    // Lines that begin with # are comments, should be ignored
    if (line[0] != '#')
    {
      char *s = strstr(line, "=");
      if (s != NULL)
      {
        CStdString strKeyword(line, s - line);
        strKeyword.TrimRight(" ");

        CStdString strValue(s+1);
        strValue.Replace("\\n", "\n"); 
        strValue.Replace("\\t", "\t"); 
        strValue.Replace("\\\\", "\\"); 
        g_charsetConverter.unknownToUTF8(strValue);

        std::map<CStdString, CStdString>::const_iterator it = keywords.find(strKeyword);
        if (it != keywords.end())
          strValue = it->second + strValue; // keyword occured before, concatenate
        else
          keywordsOrder.push_back(strKeyword);

        keywords[strKeyword] = strValue;
      }
    }
  }

  // parse keywords 
  for (std::list<CStdString>::const_iterator it = keywordsOrder.begin(); it != keywordsOrder.end(); ++it)
  {
    CStdString strKeyword = *it;
    CStdString strValue = keywords[strKeyword];

    if (strKeyword == "DTITLE")
    {
      // DTITLE may contain artist and disc title, separated with " / ",
      // for example: DTITLE=Modern Talking / Album: Victory (The 11th Album)
      bool found = false;
      for (int i = 0; i < strValue.GetLength() - 2; i++)
      {
        if (strValue[i] == ' ' && strValue[i + 1] == '/' && strValue[i + 2] == ' ')
        {
          m_strDisk_artist = TrimToUTF8(strValue.Left(i));
          m_strDisk_title = TrimToUTF8(strValue.Mid(i+3));
          found = true;
          break;
        }
      }

      if (!found)
        m_strDisk_title = TrimToUTF8(strValue);
    }
    else if (strKeyword == "DYEAR")
      m_strYear = TrimToUTF8(strValue);
    else if (strKeyword== "DGENRE")
      m_strGenre = TrimToUTF8(strValue);
    else if (strKeyword.Left(6) == "TTITLE")
      addTitle(strKeyword + "=" + strValue);
    else if (strKeyword == "EXTD")
    {
      CStdString strExtd(strValue);

      if (m_strYear.IsEmpty())
      {
        // Extract Year from extended info
        // as a fallback
        int iPos = strExtd.Find("YEAR:");
        if (iPos > -1) // You never know if you really get UTF-8 strings from cddb
          g_charsetConverter.unknownToUTF8(strExtd.Mid(iPos + 6, 4), m_strYear);
      }

      if (m_strGenre.IsEmpty())
      {
        // Extract ID3 Genre
        // as a fallback
        int iPos = strExtd.Find("ID3G:");
        if (iPos > -1)
        {
          CStdString strGenre = strExtd.Mid(iPos + 5, 4);
          strGenre.TrimLeft(' ');
          if (StringUtils::IsNaturalNumber(strGenre))
          {
            CID3Tag tag;
            m_strGenre=tag.ParseMP3Genre(strGenre);
          }
        }
      }
    }
    else if (strKeyword.Left(4) == "EXTT")
      addExtended(strKeyword + "=" + strValue);
  }

  //writeLog("parseData Ende");
}
Exemplo n.º 2
0
bool URIUtils::IsMultiPath(const CStdString& strPath)
{
  return strPath.Left(10).Equals("multipath:");
}
Exemplo n.º 3
0
bool URIUtils::IsCDDA(const CStdString& strFile)
{
  return strFile.Left(5).Equals("cdda:");
}
Exemplo n.º 4
0
CFileItem* CHDDirectory::BuildResolvedFileItem(const CStdString& strRoot, WIN32_FIND_DATA& wfd)
{
  CFileItem* pItem = 0;

#ifdef __APPLE__
  // Attempt to resolve aliases.
  FSRef   fsRef;
  Boolean isDir;
  Boolean isAlias;
  char    resolvedAliasPath[MAX_PATH];
  bool    useAlias = false;

  // Convert to FSRef.
  CStdString strPath = strRoot;
  CStdString strFile = strPath + wfd.cFileName;
  if (FSPathMakeRef((const UInt8* )strFile.c_str(), &fsRef, &isDir) == noErr)
  {
    if (FSResolveAliasFileWithMountFlags(&fsRef, TRUE, &isDir, &isAlias, kResolveAliasFileNoUI) == noErr)
    {
      // If it was an alias, use the reference instead.
      if (isAlias)
      {
        if (FSRefMakePath(&fsRef, (UInt8* )resolvedAliasPath, MAX_PATH) == noErr)
          useAlias = true;
      }
    }
    else
    {
      // Broken item.
      return 0;
    }
  }

  // Compute the *final* name/path of the file.
  if (useAlias)
  {
    strPath = resolvedAliasPath;
    strFile = CUtil::GetFileName(strPath);
    strPath = strPath.Left(strPath.length()-strFile.length());
  }
  else
  {
    strFile = wfd.cFileName;
  }

  // Check for smart folders.
  if (CUtil::IsSmartFolder(strFile))
  {
    // Use the original name, without extension.
    CStdString smartFolder = strFile;
    int iPos = smartFolder.ReverseFind(".");
    if (iPos > 0)
      smartFolder = smartFolder.Left(iPos);

    strFile.Replace(':', '/');
    pItem = new CFileItem(smartFolder);
    //pItem->m_strPath = "smartfolder:/" + strPath + strFile;
    pItem->m_strPath = strPath + strFile;
    pItem->m_bIsFolder = true;
  }
  else if (useAlias)
  {
    // Add the alias.
    strFile.Replace(':', '/');
    pItem = new CFileItem(strFile);
    pItem->m_strPath = resolvedAliasPath;
    pItem->m_bIsFolder = isDir ? true : false;

    if (isDir == false)
    {
      // Get the size of the file.
      struct stat64 statInfo;
      stat64(resolvedAliasPath, &statInfo);
      pItem->m_dwSize = statInfo.st_size;
    }
  }
  else
#endif
  {
    // Go the default route.
    pItem = BuildFileItem(strRoot, wfd);
  }

  // Save file time.
  FILETIME localTime;
  FileTimeToLocalFileTime(&wfd.ftLastWriteTime, &localTime);
  pItem->m_dateTime = localTime;

  return pItem;
}
Exemplo n.º 5
0
void CMythSession::SetSeasonAndEpisode(const cmyth_proginfo_t &program, int *season, int *episode) {
  /*
   * A valid programid generated from an XMLTV source should look like:
   * [EP|MV|SH|SP][seriesid][episode][season]([partnumber][parttotal])
   * mythtv/trunk/programs/mytfilldatabaseline/xmltvparser.cpp - Line 522 onwards.
   * 
   * Season changed to a base36 character for XMLTV in Myth 0.24. http://svn.mythtv.org/trac/changeset/24724
   * 
   * A valid SchedulesDirect programid appears to have a similar format to the XMLTV programid but
   * doesn't have any obvious way to parse out the season and episode information. The number at the
   * end of the programid could possibly be the completely sequential number for the episode, but
   * even that doesn't seem to match up with TVDB. SchedulesDirect data does seem to have a valid
   * original air date though, so if we identify a SchedulesDirect programid, leave the season and
   * episode as 0. 
   */
  CStdString programid = GetValue(m_dll->proginfo_programid(program));
  CStdString seriesid = GetValue(m_dll->proginfo_seriesid(program));

  /*
   * Default the season and episode to 0 so XBMC treats the content as an episode and displays tag
   * information. If the season and episode can be parsed from the programid these will be
   * overwritten.
   */
  *season  = 0;
  *episode = 0;
  
  if (programid.IsEmpty() // Can't do anything if the program ID is empty
  ||  seriesid.IsEmpty()) // Can't figure out the end parsing if the series ID is empty  {
    return;
  
  CStdString category = programid.Left(2); // Valid for both XMLTV and SchedulesDirect sources
  if (category != "MV"  // Movie
  &&  category != "EP"  // Series
  &&  category != "SH"  // TV Show
  &&  category != "SP") // Sports
    return;
  
  if (programid.Mid(category.length(), seriesid.length()) != seriesid) // Series ID does not follow the category
    return;
  
  CStdString remainder = programid.Mid(category.length() + seriesid.length()); // Whatever is after series ID
  
  /*
   * All SchedulesDirect remainders appear to be 4 characters and start with a 0. If the assumption
   * is correct that the number somehow relates to the sequential episode number across all seasons
   * then we can ignore remainders that start with 0. It will be very unlikely for a sequential
   * episode number for a series to be > 999.
   */
  if (remainder.length() == 4     // All SchedulesDirect codes seem to be 4 characters
  &&  remainder.Left(0)  == "0")  // Padded with 0's for low number. No valid XMLTV remainder will start with 0.
    return;
  
  /*
   * If the remainder is more than 5 characters, it must include the optional part number and total
   * number of parts. Strip off the last 2 characters assuming that there are ridiculously few
   * cases where the number of parts for a single episode is > 9.
   */
  if (remainder.length() >= 5) // Must include optional part number and total number of parts
    remainder = remainder.Left(remainder.length() - 2); // Assumes part number and total are both < 10
  
  /*
   * Now for some heuristic black magic.
   */
  if (remainder.length() == 2)  // Single character season and episode.
  {
    *season = atoi(remainder.Right(1)); // TODO: Fix for base 36 in Myth 0.24. Assume season < 10
    *episode = atoi(remainder.Left(1));
  }
  else if (remainder.length() == 3) // Ambiguous in Myth 0.23. Single character season in Myth 0.24
  {
    /*
     * Following heuristics are intended to work with largest possible number of cases. It won't be
     * perfect, but way better than just assuming the season is < 10.
     */
    if (remainder.Right(1) == "0") // e.g. 610. Unlikely to have a season of 0 (specials) with more than 9 special episodes.
    {
      *season = atoi(remainder.Right(2));
      *episode = atoi(remainder.Left(1));
    }
    else if (remainder.Mid(2, 1) == "0") // e.g. 203. Can't have a season start with 0. Must be end of episode.
    {
      *season = atoi(remainder.Right(1)); // TODO: Fix for base 36 in Myth 0.24. Assume season < 10
      *episode = atoi(remainder.Left(2));
    }
    else if (atoi(remainder.Left(1)) > 3) // e.g. 412. Very unlikely to have more than 39 episodes per season if season > 9.
    {
      /*
       * TODO: See if a check for > 2 is better, e.g. is it still unlike to have more than 29 episodes
       * per season if season > 9?
       */
      *season = atoi(remainder.Right(2));
      *episode = atoi(remainder.Left(1));
    }
    else // e.g. 129. Assume season is < 10 or Myth 0.24 Base 36 season.
    {
      *season = atoi(remainder.Right(1)); // TODO: Fix for base 36 in Myth 0.24. Assume season < 10
      *episode = atoi(remainder.Left(2));
    }
  }
  else if (remainder.length() == 4) // Double digit season and episode in Myth 0.23 OR TODO: has part number and total number of parts
  {
    *season = atoi(remainder.Right(2));
    *episode = atoi(remainder.Left(2));
  }
  return;
}
Exemplo n.º 6
0
bool URIUtils::IsVideoDb(const CStdString& strFile)
{
  return strFile.Left(8).Equals("videodb:");
}
Exemplo n.º 7
0
bool URIUtils::IsBluray(const CStdString& strFile)
{
  return strFile.Left(7).Equals("bluray:");
}
Exemplo n.º 8
0
void FileRecursiveMkdir(CStdString& path, int permissions, CStdString owner, CStdString group, CStdString rootDirectory)
{
	int position = 0, newPermissions = permissions;
	bool done = false;

	/*
	 * Create the directories first. We have separated this because
	 * we do not want the introduction of rootDirectory to break
	 * any old functionality.
	 */
	while (!done)
	{
		position = path.Find('/', position+1);
		if (position == -1)
		{
			done = true;
		}
		else
		{
			CStdString level = path.Left(position);
			ACE_OS::mkdir((PCSTR)level);
		}
	}

	done = false;
	position = 0;
	if(rootDirectory.size())
	{
	        if(path.Find(rootDirectory) >= 0)
		{
			position = 1 + rootDirectory.size();
	        }
	}

	if(newPermissions & S_IRUSR)
	{
		newPermissions |= S_IXUSR;
	}

	if(newPermissions & S_IRGRP)
	{
		newPermissions |= S_IXGRP;
	}

	if(newPermissions & S_IROTH)
	{
		newPermissions |= S_IXOTH;
	}

	while (!done)
	{
		position = path.Find('/', position+1);
		if (position == -1)
		{
			done = true;
		}
		else
		{
			CStdString level = path.Left(position);

			if(owner.size() && group.size())
			{
				FileSetOwnership(level, owner, group);
			}

			if(newPermissions)
			{
				FileSetPermissions(level, newPermissions);
			}
		}
	}
}
Exemplo n.º 9
0
//*********************************************************************************************
bool CRTVDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
{
  CURL url(strPath);

  CStdString strRoot = strPath;
  URIUtils::AddSlashAtEnd(strRoot);

  // Host name is "*" so we try to discover all ReplayTVs.  This requires some trickery but works.
  if (url.GetHostName() == "*")
  {
    // Check to see whether the URL's path is blank or "Video"
    if (url.GetFileName() == "" || url.GetFileName() == "Video")
    {
      int iOldSize=items.Size();
      struct RTV * rtv = NULL;
      int numRTV;

      // Request that all ReplayTVs on the LAN identify themselves.  Each ReplayTV
      // is given 3000ms to respond to the request.  rtv_discovery returns an array
      // of structs containing the IP and friendly name of all ReplayTVs found on the LAN.
      // For some reason, DVArchive doesn't respond to this request (probably only responds
      // to requests from an IP address of a real ReplayTV).
      numRTV = rtv_discovery(&rtv, 3000);

      // Run through the array and add the ReplayTVs found as folders in XBMC.
      // We must add the IP of each ReplayTV as if it is a file name at the end of a the
      // auto-discover URL--e.g. rtv://*/192.168.1.100--because XBMC does not permit
      // dyamically added shares and will not play from them.  This little trickery is
      // the best workaround I could come up with.
      for (int i = 0; i < numRTV; i++)
      {
        CFileItemPtr pItem(new CFileItem(rtv[i].friendlyName));
        // This will keep the /Video or / and allow one to set up an auto ReplayTV
        // share of either type--simple file listing or ReplayGuide listing.
        pItem->SetPath(strRoot + rtv[i].hostname);
        pItem->m_bIsFolder = true;
        pItem->SetLabelPreformated(true);
        items.Add(pItem);
      }
      free(rtv);
      return (items.Size()>iOldSize);
      // Else the URL's path should be an IP address of the ReplayTV
    }
    else
    {
      CStdString strURL, strRTV;
      int pos;

      // Isolate the IP from the URL and replace the "*" with the real IP
      // of the ReplayTV.  E.g., rtv://*/Video/192.168.1.100/ becomes
      // rtv://192.168.1.100/Video/ .  This trickery makes things work.
      strURL = strRoot.TrimRight('/');
      pos = strURL.ReverseFind('/');
      strRTV = strURL.Left(pos + 1);
      strRTV.Replace("*", strURL.Mid(pos + 1));
      CURL tmpURL(strRTV);

      // Force the newly constructed share into the right variables to
      // be further processed by the remainder of GetDirectory.
      url = tmpURL;
      strRoot = strRTV;
    }
  }

  // Allow for ReplayTVs on ports other than 80
  CStdString strHostAndPort;
  strHostAndPort = url.GetHostName();
  if (url.HasPort())
  {
    char buffer[10];
    sprintf(buffer,"%i",url.GetPort());
    strHostAndPort += ':';
    strHostAndPort += buffer;
  }

  // No path given, list shows from ReplayGuide
  if (url.GetFileName() == "")
  {
    unsigned char * data = NULL;

    // Get the RTV guide data in XML format
    rtv_get_guide_xml(&data, strHostAndPort.c_str());

    // Begin parsing the XML data
    CXBMCTinyXML xmlDoc;
    xmlDoc.Parse( (const char *) data );
    if ( xmlDoc.Error() )
    {
      free(data);
      return false;
    }
    TiXmlElement* pRootElement = xmlDoc.RootElement();
    if (!pRootElement)
    {
      free(data);
      return false;
    }

    const TiXmlNode *pChild = pRootElement->FirstChild();
    while (pChild > 0)
    {
      CStdString strTagName = pChild->Value();

      if ( !strcmpi(strTagName.c_str(), "ITEM") )
      {
        const TiXmlNode *nameNode = pChild->FirstChild("DISPLAYNAME");
//        const TiXmlNode *qualityNode = pChild->FirstChild("QUALITY");
        const TiXmlNode *recordedNode = pChild->FirstChild("RECORDED");
        const TiXmlNode *pathNode = pChild->FirstChild("PATH");
//        const TiXmlNode *durationNode = pChild->FirstChild("DURATION");
        const TiXmlNode *sizeNode = pChild->FirstChild("SIZE");
        const TiXmlNode *atrbNode = pChild->FirstChild("ATTRIB");

        SYSTEMTIME dtDateTime;
        DWORD dwFileSize = 0;
        memset(&dtDateTime, 0, sizeof(dtDateTime));

        // DISPLAYNAME
        const char* szName = NULL;
        if (nameNode)
        {
          szName = nameNode->FirstChild()->Value() ;
        }
        else
        {
          // Something went wrong, the recording has no name
          free(data);
          return false;
        }

        // QUALITY
//        const char* szQuality = NULL;
//        if (qualityNode)
//        {
//          szQuality = qualityNode->FirstChild()->Value() ;
//        }

        // RECORDED
        if (recordedNode)
        {
          CStdString strRecorded = recordedNode->FirstChild()->Value();
          int iYear, iMonth, iDay;

          iYear = atoi(strRecorded.Left(4).c_str());
          iMonth = atoi(strRecorded.Mid(5, 2).c_str());
          iDay = atoi(strRecorded.Mid(8, 2).c_str());
          dtDateTime.wYear = iYear;
          dtDateTime.wMonth = iMonth;
          dtDateTime.wDay = iDay;

          int iHour, iMin, iSec;
          iHour = atoi(strRecorded.Mid(11, 2).c_str());
          iMin = atoi(strRecorded.Mid(14, 2).c_str());
          iSec = atoi(strRecorded.Mid(17, 2).c_str());
          dtDateTime.wHour = iHour;
          dtDateTime.wMinute = iMin;
          dtDateTime.wSecond = iSec;
        }

        // PATH
        const char* szPath = NULL;
        if (pathNode)
        {
          szPath = pathNode->FirstChild()->Value() ;
        }
        else
        {
          // Something went wrong, the recording has no filename
          free(data);
          return false;
        }

        // DURATION
//        const char* szDuration = NULL;
//        if (durationNode)
//        {
//          szDuration = durationNode->FirstChild()->Value() ;
//        }

        // SIZE
        // NOTE: Size here is actually just duration in minutes because
        // filesize is not reported by the stripped down GuideParser I use
        if (sizeNode)
        {
          dwFileSize = atol( sizeNode->FirstChild()->Value() );
        }

        // ATTRIB
        // NOTE: Not currently reported in the XML guide data, nor is it particularly
        // needed unless someone wants to add the ability to sub-divide the recordings
        // into categories, as on a real RTV.
        int attrib = 0;
        if (atrbNode)
        {
          attrib = atoi( atrbNode->FirstChild()->Value() );
        }

        bool bIsFolder(false);
        if (attrib & FILE_ATTRIBUTE_DIRECTORY)
          bIsFolder = true;

        CFileItemPtr pItem(new CFileItem(szName));
        pItem->m_dateTime=dtDateTime;
        pItem->SetPath(strRoot + szPath);
        // Hack to show duration of show in minutes as KB in XMBC because
        // it doesn't currently permit showing duration in minutes.
        // E.g., a 30 minute show will show as 29.3 KB in XBMC.
        pItem->m_dwSize = dwFileSize * 1000;
        pItem->m_bIsFolder = bIsFolder;
        pItem->SetLabelPreformated(true);
        items.Add(pItem);
      }

      pChild = pChild->NextSibling();
    }

    free(data);

    // Path given (usually Video), list filenames only
  }
  else
  {

    unsigned char * data;
    char * p, * q;
    unsigned long status;

    // Return a listing of all files in the given path
    status = rtv_list_files(&data, strHostAndPort.c_str(), url.GetFileName().c_str());
    if (status == 0)
    {
      return false;
    }

    // Loop through the file list using pointers p and q, where p will point to the current
    // filename and q will point to the next filename
    p = (char *) data;
    while (p)
    {
      // Look for the end of the current line of the file listing
      q = strchr(p, '\n');
      // If found, replace the newline character with the NULL terminator
      if (q)
      {
        *q = '\0';
        // Increment q so that it points to the next filename
        q++;
        // *p should be the current null-terminated filename in the list
        if (*p)
        {
          // Only display MPEG files in XBMC (but not circular.mpg, as that is the RTV
          // video buffer and XBMC may cause problems if it tries to play it)
          if (strstr(p, ".mpg") && !strstr(p, "circular"))
          {
            CFileItemPtr pItem(new CFileItem(p));
            pItem->SetPath(strRoot + p);
            pItem->m_bIsFolder = false;
            // The list returned by the RTV doesn't include file sizes, unfortunately
            //pItem->m_dwSize = atol(szSize);
            pItem->SetLabelPreformated(true);
            items.Add(pItem);
          }
        }
      }
      // Point p to the next filename in the list and loop
      p = q;
    }

    free(data);
  }

  return true;
}
Exemplo n.º 10
0
// TODO: Currently no support for "embedded thumb" as there is no easy way to grab it
//       without sending a file that has this as it's album to this class
void CGUIDialogMusicInfo::OnGetThumb()
{
  CFileItemList items;

  // Current thumb
  if (CFile::Exists(m_albumItem->GetThumbnailImage()))
  {
    CFileItemPtr item(new CFileItem("thumb://Current", false));
    item->SetThumbnailImage(m_albumItem->GetThumbnailImage());
    item->SetLabel(g_localizeStrings.Get(20016));
    items.Add(item);
  }

  // Grab the thumbnail(s) from the web
  vector<CStdString> thumbs;
  if (m_bArtistInfo)
    m_artist.thumbURL.GetThumbURLs(thumbs);
  else
    m_album.thumbURL.GetThumbURLs(thumbs);

  for (unsigned int i = 0; i < thumbs.size(); ++i)
  {
    CStdString strItemPath;
    strItemPath.Format("thumb://Remote%i", i);
    CFileItemPtr item(new CFileItem(strItemPath, false));
    item->SetThumbnailImage(thumbs[i]);
    item->SetIconImage("DefaultPicture.png");
    item->SetLabel(g_localizeStrings.Get(20015));
    
    // TODO: Do we need to clear the cached image?
    //    CTextureCache::Get().ClearCachedImage(thumb);
    items.Add(item);
  }

  // local thumb
  CStdString localThumb;
  if (m_bArtistInfo)
  {
    CMusicDatabase database;
    database.Open();
    CStdString strArtistPath;
    if (database.GetArtistPath(m_artist.idArtist,strArtistPath))
      URIUtils::AddFileToFolder(strArtistPath,"folder.jpg",localThumb);
  }
  else
    localThumb = m_albumItem->GetUserMusicThumb();
  if (CFile::Exists(localThumb))
  {
    CFileItemPtr item(new CFileItem("thumb://Local", false));
    item->SetThumbnailImage(localThumb);
    item->SetLabel(g_localizeStrings.Get(20017));
    items.Add(item);
  }
  else
  {
    CFileItemPtr item(new CFileItem("thumb://None", false));
    if (m_bArtistInfo)
      item->SetIconImage("DefaultArtist.png");
    else
      item->SetIconImage("DefaultAlbumCover.png");
    item->SetLabel(g_localizeStrings.Get(20018));
    items.Add(item);
  }

  CStdString result;
  bool flip=false;
  VECSOURCES sources(g_settings.m_musicSources);
  g_mediaManager.GetLocalDrives(sources);
  if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(1030), result, &flip))
    return;   // user cancelled

  if (result == "thumb://Current")
    return;   // user chose the one they have

  // delete the thumbnail if that's what the user wants, else overwrite with the
  // new thumbnail
  CStdString cachedThumb;
  if (m_bArtistInfo)
    cachedThumb = m_albumItem->GetCachedArtistThumb();
  else
    cachedThumb = CThumbnailCache::GetAlbumThumb(m_album);

  CTextureCache::Get().ClearCachedImage(cachedThumb, true);
  if (result.Left(14) == "thumb://Remote")
  {
    int number = atoi(result.Mid(14));
    CFile::Cache(thumbs[number], cachedThumb);
  }
  else if (result == "thumb://Local")
    CFile::Cache(localThumb, cachedThumb);
  else if (CFile::Exists(result))
    CPicture::CreateThumbnail(result, cachedThumb);
  else
    result = "thumb://None";

  if (result == "thumb://None")
  { // clear this thumb (note - it'll likely be recached, nothing we can do about that at this point)
    CTextureCache::Get().ClearCachedImage(cachedThumb, true);
    cachedThumb = "";
  }

  m_albumItem->SetThumbnailImage(cachedThumb);
  m_hasUpdatedThumb = true;

  // tell our GUI to completely reload all controls (as some of them
  // are likely to have had this image in use so will need refreshing)
  CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
  g_windowManager.SendMessage(msg);
  // Update our screen
  Update();
}
Exemplo n.º 11
0
// Allow user to select a Fanart
void CGUIDialogMusicInfo::OnGetFanart()
{
  CFileItemList items;

  CStdString cachedThumb(CThumbnailCache::GetThumb(m_artist.strArtist,g_settings.GetMusicFanartFolder()));
  if (CFile::Exists(cachedThumb))
  {
    CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
    itemCurrent->SetThumbnailImage(cachedThumb);
    itemCurrent->SetLabel(g_localizeStrings.Get(20440));
    items.Add(itemCurrent);
  }

  // Grab the thumbnails from the web
  for (unsigned int i = 0; i < m_artist.fanart.GetNumFanarts(); i++)
  {
    CStdString strItemPath;
    strItemPath.Format("fanart://Remote%i",i);
    CFileItemPtr item(new CFileItem(strItemPath, false));
    CStdString thumb = m_artist.fanart.GetPreviewURL(i);
    item->SetThumbnailImage(CTextureCache::GetWrappedThumbURL(thumb));
    item->SetIconImage("DefaultPicture.png");
    item->SetLabel(g_localizeStrings.Get(20441));

    // TODO: Do we need to clear the cached image?
    //    CTextureCache::Get().ClearCachedImage(thumb);
    items.Add(item);
  }

  // Grab a local thumb
  CMusicDatabase database;
  database.Open();
  CStdString strArtistPath;
  database.GetArtistPath(m_artist.idArtist,strArtistPath);
  CFileItem item(strArtistPath,true);
  CStdString strLocal = item.GetLocalFanart();
  if (!strLocal.IsEmpty())
  {
    CFileItemPtr itemLocal(new CFileItem("fanart://Local",false));
    itemLocal->SetThumbnailImage(strLocal);
    itemLocal->SetLabel(g_localizeStrings.Get(20438));

    // TODO: Do we need to clear the cached image?
    CTextureCache::Get().ClearCachedImage(strLocal);
    items.Add(itemLocal);
  }
  else
  {
    CFileItemPtr itemNone(new CFileItem("fanart://None", false));
    itemNone->SetIconImage("DefaultArtist.png");
    itemNone->SetLabel(g_localizeStrings.Get(20439));
    items.Add(itemNone);
  }

  CStdString result;
  VECSOURCES sources(g_settings.m_musicSources);
  g_mediaManager.GetLocalDrives(sources);
  bool flip=false;
  if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445))
    return;   // user cancelled

  // delete the thumbnail if that's what the user wants, else overwrite with the
  // new thumbnail
  if (result.Equals("fanart://Current"))
   return;

  if (result.Equals("fanart://Local"))
    result = strLocal;

  CTextureCache::Get().ClearCachedImage(cachedThumb, true);

  if (!result.Equals("fanart://None"))
  { // local file
    if (result.Left(15)  == "fanart://Remote")
    {
      int iFanart = atoi(result.Mid(15).c_str());
      m_artist.fanart.SetPrimaryFanart(iFanart);
      // download the fullres fanart image
      CStdString tempFile = "special://temp/fanart_download.jpg";
      CAsyncFileCopy downloader;
      if (!downloader.Copy(m_artist.fanart.GetImageURL(), tempFile, g_localizeStrings.Get(13413)))
        return;
      result = tempFile;
    }

    if (flip)
      CPicture::ConvertFile(result, cachedThumb,0,1920,-1,100,true);
    else
      CPicture::CacheFanart(result, cachedThumb);

    m_albumItem->SetProperty("fanart_image",cachedThumb);
    m_hasUpdatedThumb = true;
  }

  // tell our GUI to completely reload all controls (as some of them
  // are likely to have had this image in use so will need refreshing)
  CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
  g_windowManager.SendMessage(msg);
  // Update our screen
  Update();
}
Exemplo n.º 12
0
bool CAVPlayerOperations::IsCorrectPlayer(const CStdString &method)
{
  return (method.Left(5).Equals("audio") && g_application.IsPlayingAudio()) || (method.Left(5).Equals("video") && g_application.IsPlayingVideo());
}
Exemplo n.º 13
0
bool IsRoutableAddress(const CStdString& address)
{
	if (address.Find(_T(":")) != -1)
	{
		CStdString long_address = GetIPV6LongForm(address);
		if (long_address.IsEmpty())
			return false;
		if (long_address[0] == '0')
		{
			// ::/128
			if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0000"))
				return false;
			// ::1/128
			if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0001"))
				return false;

			if (long_address.Left(30) == _T("0000:0000:0000:0000:0000:ffff:"))
			{
				// IPv4 mapped
				CStdString ipv4;
				ipv4.Format(_T("%d.%d.%d.%d"),
						DigitHexToDecNum(long_address[30]) * 16 + DigitHexToDecNum(long_address[31]),
						DigitHexToDecNum(long_address[32]) * 16 + DigitHexToDecNum(long_address[33]),
						DigitHexToDecNum(long_address[35]) * 16 + DigitHexToDecNum(long_address[36]),
						DigitHexToDecNum(long_address[37]) * 16 + DigitHexToDecNum(long_address[38]));
				return IsRoutableAddress(ipv4);
			}

			return true;
		}
		if (long_address[0] == 'f')
		{
			if (long_address[1] == 'e')
			{
				// fe80::/10 (link local)
				const TCHAR& c = long_address[2];
				int v;
				if (c >= 'a')
					v = c - 'a' + 10;
				else
					v = c - '0';
				if ((v & 0xc) == 0x8)
					return false;

				return true;
			}
			else if (long_address[1] == 'c' || long_address[1] == 'd')
			{
				// fc00::/7 (site local)
				return false;
			}
		}

		return true;
	}
	else
	{
		// Assumes address is already a valid IP address
		if (address.Left(3) == _T("127") ||
			address.Left(3) == _T("10.") ||
			address.Left(7) == _T("192.168") ||
			address.Left(7) == _T("169.254"))
			return false;

		if (address.Left(3) == _T("172"))
		{
			CStdString middle = address.Mid(4);
			int pos = address.Find(_T("."));
			if (pos == -1)
				return false;
			int part = _ttoi(middle.Left(pos));

			if (part >= 16 && part <= 31)
				return false;
		}

		return true;
	}
}
Exemplo n.º 14
0
bool MatchesFilter(CStdString filter, CStdString ip)
{
	// A single asterix matches all IPs.
	if (filter == _T("*"))
		return true;

	// Check for IP range syntax.
	int pos = filter.Find('/');
	if (pos != -1)
	{
		// CIDR filter
		int prefixLength = _ttoi(filter.Mid(pos+1));

		if (ip.Find(':') != -1)
		{
			// IPv6 address
			CStdString left = GetIPV6LongForm(filter.Left(pos));
			if (left.Find(':') == -1)
				return false;
			ip = GetIPV6LongForm(ip);
			LPCTSTR i = ip;
			LPCTSTR f = left;
			while (prefixLength >= 4)
			{
				if (*i != *f)
					return false;

				if (!*i)
					return true;

				if (*i == ':')
				{
					++i;
					++f;
				}
				++i;
				++f;

				prefixLength -= 4;
			}
			if (!prefixLength)
				return true;
			
			int mask;
			if (prefixLength == 1)
				mask = 0x8;
			else if (prefixLength == 2)
				mask = 0xc;
			else
				mask = 0xe;

			return (DigitHexToDecNum(*i) & mask) == (DigitHexToDecNum(*f) & mask);
		}
		else
		{
			if (prefixLength < 0)
				prefixLength = 0;
			else if (prefixLength > 32)
				prefixLength = 32;

			// IPv4 address
			CStdString left = filter.Left(pos);
			if (left.Find(':') != -1)
				return false;

			unsigned long i = ntohl(inet_addr(ConvToLocal(ip)));
			unsigned long f = ntohl(inet_addr(ConvToLocal(left)));

			i &= prefixMasksV4[prefixLength];
			f &= prefixMasksV4[prefixLength];
			return i == f;
		}
	}
	else
	{
		// Literal filter
		if (filter.Find(':') != -1)
			return filter == GetIPV6ShortForm(ip);
		else
			return filter == ip;
	}
}
Exemplo n.º 15
0
bool URIUtils::IsHTSP(const CStdString& strFile)
{
  return strFile.Left(5).Equals("htsp:");
}
Exemplo n.º 16
0
bool URIUtils::IsDAAP(const CStdString& strFile)
{
  return strFile.Left(5).Equals("daap:");
}
Exemplo n.º 17
0
bool URIUtils::IsMusicDb(const CStdString& strFile)
{
  return strFile.Left(8).Equals("musicdb:");
}
Exemplo n.º 18
0
bool URIUtils::IsUPnP(const CStdString& strFile)
{
  return strFile.Left(5).Equals("upnp:");
}
Exemplo n.º 19
0
bool URIUtils::IsLastFM(const CStdString& strFile)
{
  return strFile.Left(7).Equals("lastfm:");
}
Exemplo n.º 20
0
bool URIUtils::IsTuxBox(const CStdString& strFile)
{
  return strFile.Left(7).Equals("tuxbox:");
}
Exemplo n.º 21
0
bool URIUtils::IsAndroidApp(const CStdString &path)
{
  return path.Left(11).Equals("androidapp:");
}
Exemplo n.º 22
0
bool URIUtils::IsMythTV(const CStdString& strFile)
{
  return strFile.Left(5).Equals("myth:");
}
Exemplo n.º 23
0
void CURL::Parse(const CStdString& strURL1)
{
  Reset();
  // start by validating the path
  CStdString strURL = CUtil::ValidatePath(strURL1);

  // strURL can be one of the following:
  // format 1: protocol://[username:password]@hostname[:port]/directoryandfile
  // format 2: protocol://file
  // format 3: drive:directoryandfile
  //
  // first need 2 check if this is a protocol or just a normal drive & path
  if (!strURL.size()) return ;
  if (strURL.Equals("?", true)) return;

  if (strURL.size() > 1 && strURL[1] == ':')
  {
    // form is drive:directoryandfile

    // set filename and update extension

    SetFileName(strURL);
    return ;
  }

  // form is format 1 or 2
  // format 1: protocol://[domain;][username:password]@hostname[:port]/directoryandfile
  // format 2: protocol://file

  // decode protocol
  int iPos = strURL.Find("://");
  if (iPos < 0)
  {
    // This is an ugly hack that needs some work.
    // example: filename /foo/bar.zip/alice.rar/bob.avi
    // This should turn into zip://rar:///foo/bar.zip/alice.rar/bob.avi
    iPos = 0;
    while (1)
    {
      iPos = strURL.Find(".zip/", iPos);
      int extLen = 3;
      if (iPos < 0)
      {
#ifndef _LINUX
        // check for misconstructed protocols
        iPos = strURL.Find(":");
        if (iPos == strURL.GetLength() - 1)
        {
          SetProtocol(strURL.Left(iPos));
          iPos += 1;
          break;
        }
        else
#endif
        {
          /* set filename and update extension*/
          SetFileName(strURL);
          return ;
        }
      }
      iPos += extLen + 1;
      CStdString archiveName = strURL.Left(iPos);
      struct __stat64 s;
      if (XFILE::CFile::Stat(archiveName, &s) == 0)
      {
#ifdef _LINUX
        if (!S_ISDIR(s.st_mode))
#else
        if (!(s.st_mode & S_IFDIR))
#endif
        {
          CUtil::URLEncode(archiveName);
          CURL c((CStdString)"zip" + "://" + archiveName + '/' + strURL.Right(strURL.size() - iPos - 1));
          *this = c;
          return;
        }
      }
    }
  }
  else
  {
    SetProtocol(strURL.Left(iPos));
    iPos += 3;
  }

  // virtual protocols
  // why not handle all format 2 (protocol://file) style urls here?
  // ones that come to mind are iso9660, cdda, musicdb, etc.
  // they are all local protocols and have no server part, port number, special options, etc.
  // this removes the need for special handling below.
  if (
    m_strProtocol.Equals("stack") ||
    m_strProtocol.Equals("virtualpath") ||
    m_strProtocol.Equals("multipath") ||
    m_strProtocol.Equals("filereader") ||
    m_strProtocol.Equals("special")
    )
  {
    SetFileName(strURL.Mid(iPos));
    return;
  }

  // check for username/password - should occur before first /
  if (iPos == -1) iPos = 0;

  // for protocols supporting options, chop that part off here
  // maybe we should invert this list instead?
  int iEnd = strURL.length();
  const char* sep = NULL;

  CStdString strProtocol2 = GetTranslatedProtocol();
  if(m_strProtocol.Equals("rss") ||
     m_strProtocol.Equals("addons"))
    sep = "?";
  else
  if(strProtocol2.Equals("http")
    || strProtocol2.Equals("https")
    || strProtocol2.Equals("plugin")
    || strProtocol2.Equals("hdhomerun")
    || strProtocol2.Equals("rtsp")
    || strProtocol2.Equals("zip"))
    sep = "?;#|";
  else if(strProtocol2.Equals("ftp")
       || strProtocol2.Equals("ftps"))
    sep = "?;";

  if(sep)
  {
    int iOptions = strURL.find_first_of(sep, iPos);
    if (iOptions >= 0 )
    {
      // we keep the initial char as it can be any of the above
      int iProto = strURL.find_first_of("|",iOptions);
      if (iProto >= 0)
      {
        m_strProtocolOptions = strURL.substr(iProto+1);
        m_strOptions = strURL.substr(iOptions,iProto-iOptions);
      }
      else
        m_strOptions = strURL.substr(iOptions);
      iEnd = iOptions;
    }
  }

  int iSlash = strURL.Find("/", iPos);
  if(iSlash >= iEnd)
    iSlash = -1; // was an invalid slash as it was contained in options

  if( !m_strProtocol.Equals("iso9660") )
  {
    int iAlphaSign = strURL.Find("@", iPos);
    if (iAlphaSign >= 0 && iAlphaSign < iEnd && (iAlphaSign < iSlash || iSlash < 0))
    {
      // username/password found
      CStdString strUserNamePassword = strURL.Mid(iPos, iAlphaSign - iPos);

      // first extract domain, if protocol is smb
      if (m_strProtocol.Equals("smb"))
      {
        int iSemiColon = strUserNamePassword.Find(";");

        if (iSemiColon >= 0)
        {
          m_strDomain = strUserNamePassword.Left(iSemiColon);
          strUserNamePassword.Delete(0, iSemiColon + 1);
        }
      }

      // username:password
      int iColon = strUserNamePassword.Find(":");
      if (iColon >= 0)
      {
        m_strUserName = strUserNamePassword.Left(iColon);
        iColon++;
        m_strPassword = strUserNamePassword.Right(strUserNamePassword.size() - iColon);
      }
      // username
      else
      {
        m_strUserName = strUserNamePassword;
      }

      iPos = iAlphaSign + 1;
      iSlash = strURL.Find("/", iAlphaSign);

      if(iSlash >= iEnd)
        iSlash = -1;
    }
  }

  // detect hostname:port/
  if (iSlash < 0)
  {
    CStdString strHostNameAndPort = strURL.Mid(iPos, iEnd - iPos);
    int iColon = strHostNameAndPort.Find(":");
    if (iColon >= 0)
    {
      m_strHostName = strHostNameAndPort.Left(iColon);
      iColon++;
      CStdString strPort = strHostNameAndPort.Right(strHostNameAndPort.size() - iColon);
      m_iPort = atoi(strPort.c_str());
    }
    else
    {
      m_strHostName = strHostNameAndPort;
    }

  }
  else
  {
    CStdString strHostNameAndPort = strURL.Mid(iPos, iSlash - iPos);
    int iColon = strHostNameAndPort.Find(":");
    if (iColon >= 0)
    {
      m_strHostName = strHostNameAndPort.Left(iColon);
      iColon++;
      CStdString strPort = strHostNameAndPort.Right(strHostNameAndPort.size() - iColon);
      m_iPort = atoi(strPort.c_str());
    }
    else
    {
      m_strHostName = strHostNameAndPort;
    }
    iPos = iSlash + 1;
    if (iEnd > iPos)
    {
      m_strFileName = strURL.Mid(iPos, iEnd - iPos);

      iSlash = m_strFileName.Find("/");
      if(iSlash < 0)
        m_strShareName = m_strFileName;
      else
        m_strShareName = m_strFileName.Left(iSlash);
    }
  }

  // iso9960 doesnt have an hostname;-)
  if (m_strProtocol.CompareNoCase("iso9660") == 0
    || m_strProtocol.CompareNoCase("musicdb") == 0
    || m_strProtocol.CompareNoCase("videodb") == 0
    || m_strProtocol.CompareNoCase("lastfm") == 0
    || m_strProtocol.Left(3).CompareNoCase("mem") == 0)
  {
    if (m_strHostName != "" && m_strFileName != "")
    {
      CStdString strFileName = m_strFileName;
      m_strFileName.Format("%s/%s", m_strHostName.c_str(), strFileName.c_str());
      m_strHostName = "";
    }
    else
    {
      if (!m_strHostName.IsEmpty() && strURL[iEnd-1]=='/')
        m_strFileName = m_strHostName + "/";
      else
        m_strFileName = m_strHostName;
      m_strHostName = "";
    }
  }

  m_strFileName.Replace("\\", "/");

  /* update extension */
  SetFileName(m_strFileName);

  /* decode urlencoding on this stuff */
  if( m_strProtocol.Equals("rar") || m_strProtocol.Equals("zip") || m_strProtocol.Equals("musicsearch"))
  {
    CUtil::URLDecode(m_strHostName);
    // Validate it as it is likely to contain a filename
    SetHostName(CUtil::ValidatePath(m_strHostName));
  }

  CUtil::URLDecode(m_strUserName);
  CUtil::URLDecode(m_strPassword);
}
Exemplo n.º 24
0
bool URIUtils::IsHDHomeRun(const CStdString& strFile)
{
  return strFile.Left(10).Equals("hdhomerun:");
}
Exemplo n.º 25
0
bool URIUtils::GetParentPath(const CStdString& strPath, CStdString& strParent)
{
  strParent = "";

  CURL url(strPath);
  CStdString strFile = url.GetFileName();
  if ( URIUtils::ProtocolHasParentInHostname(url.GetProtocol()) && strFile.IsEmpty())
  {
    strFile = url.GetHostName();
    return GetParentPath(strFile, strParent);
  }
  else if (url.GetProtocol() == "stack")
  {
    CStackDirectory dir;
    CFileItemList items;
    dir.GetDirectory(strPath,items);
    GetDirectory(items[0]->GetPath(),items[0]->m_strDVDLabel);
    if (items[0]->m_strDVDLabel.Mid(0,6).Equals("rar://") || items[0]->m_strDVDLabel.Mid(0,6).Equals("zip://"))
      GetParentPath(items[0]->m_strDVDLabel, strParent);
    else
      strParent = items[0]->m_strDVDLabel;
    for( int i=1;i<items.Size();++i)
    {
      GetDirectory(items[i]->GetPath(),items[i]->m_strDVDLabel);
      if (items[0]->m_strDVDLabel.Mid(0,6).Equals("rar://") || items[0]->m_strDVDLabel.Mid(0,6).Equals("zip://"))
        items[i]->SetPath(GetParentPath(items[i]->m_strDVDLabel));
      else
        items[i]->SetPath(items[i]->m_strDVDLabel);

      GetCommonPath(strParent,items[i]->GetPath());
    }
    return true;
  }
  else if (url.GetProtocol() == "multipath")
  {
    // get the parent path of the first item
    return GetParentPath(CMultiPathDirectory::GetFirstPath(strPath), strParent);
  }
  else if (url.GetProtocol() == "plugin")
  {
    if (!url.GetOptions().IsEmpty())
    {
      url.SetOptions("");
      strParent = url.Get();
      return true;
    }
    if (!url.GetFileName().IsEmpty())
    {
      url.SetFileName("");
      strParent = url.Get();
      return true;
    }
    if (!url.GetHostName().IsEmpty())
    {
      url.SetHostName("");
      strParent = url.Get();
      return true;
    }
    return true;  // already at root
  }
  else if (url.GetProtocol() == "special")
  {
    if (HasSlashAtEnd(strFile) )
      strFile = strFile.Left(strFile.size() - 1);
    if(strFile.ReverseFind('/') < 0)
      return false;
  }
  else if (strFile.size() == 0)
  {
    if (url.GetHostName().size() > 0)
    {
      // we have an share with only server or workgroup name
      // set hostname to "" and return true to get back to root
      url.SetHostName("");
      strParent = url.Get();
      return true;
    }
    return false;
  }

  if (HasSlashAtEnd(strFile) )
  {
    strFile = strFile.Left(strFile.size() - 1);
  }

  int iPos = strFile.ReverseFind('/');
#ifndef _LINUX
  if (iPos < 0)
  {
    iPos = strFile.ReverseFind('\\');
  }
#endif
  if (iPos < 0)
  {
    url.SetFileName("");
    strParent = url.Get();
    return true;
  }

  strFile = strFile.Left(iPos);

  AddSlashAtEnd(strFile);

  url.SetFileName(strFile);
  strParent = url.Get();
  return true;
}
Exemplo n.º 26
0
bool URIUtils::IsSlingbox(const CStdString& strFile)
{
  return strFile.Left(6).Equals("sling:");
}
Exemplo n.º 27
0
bool URIUtils::IsStack(const CStdString& strFile)
{
  return strFile.Left(6).Equals("stack:");
}
Exemplo n.º 28
0
bool URIUtils::IsVTP(const CStdString& strFile)
{
  return strFile.Left(4).Equals("vtp:");
}
Exemplo n.º 29
0
bool URIUtils::IsISO9660(const CStdString& strFile)
{
  return strFile.Left(8).Equals("iso9660:");
}
Exemplo n.º 30
0
bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
{
  CFileItemPtr item;
  if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
    item = m_vecItems->Get(itemNumber);
  switch (button)
  {
  case CONTEXT_BUTTON_SET_DEFAULT:
    g_settings.m_defaultVideoLibSource = GetQuickpathName(item->m_strPath);
    g_settings.Save();
    return true;

  case CONTEXT_BUTTON_CLEAR_DEFAULT:
    g_settings.m_defaultVideoLibSource.Empty();
    g_settings.Save();
    return true;

  case CONTEXT_BUTTON_EDIT:
    UpdateVideoTitle(item.get());
    CUtil::DeleteVideoDatabaseDirectoryCache();
    Update(m_vecItems->m_strPath);
    return true;

  case CONTEXT_BUTTON_SET_SEASON_THUMB:
  case CONTEXT_BUTTON_SET_ACTOR_THUMB:
  case CONTEXT_BUTTON_SET_ARTIST_THUMB:
  case CONTEXT_BUTTON_SET_MOVIESET_THUMB:
    {
      // Grab the thumbnails from the web
      CStdString strPath;
      CFileItemList items;
      CUtil::AddFileToFolder(g_advancedSettings.m_cachePath,"imdbthumbs",strPath);
      CUtil::WipeDir(strPath);
      XFILE::CDirectory::Create(strPath);
      CFileItemPtr noneitem(new CFileItem("thumb://None", false));
      CStdString cachedThumb = m_vecItems->Get(itemNumber)->GetCachedSeasonThumb();
      if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
        cachedThumb = m_vecItems->Get(itemNumber)->GetCachedActorThumb();
      if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
        cachedThumb = m_vecItems->Get(itemNumber)->GetCachedArtistThumb();
      if (button == CONTEXT_BUTTON_SET_MOVIESET_THUMB)
        cachedThumb = m_vecItems->Get(itemNumber)->GetCachedVideoThumb();
      if (CFile::Exists(cachedThumb))
      {
        CFileItemPtr item(new CFileItem("thumb://Current", false));
        item->SetThumbnailImage(cachedThumb);
        item->SetLabel(g_localizeStrings.Get(20016));
        items.Add(item);
      }
      noneitem->SetIconImage("DefaultFolder.png");
      noneitem->SetLabel(g_localizeStrings.Get(20018));

      vector<CStdString> thumbs;
      if (button != CONTEXT_BUTTON_SET_ARTIST_THUMB)
      {
        CVideoInfoTag tag;
        if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
          m_database.GetTvShowInfo("",tag,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId);
        else
          tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
        if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
          tag.m_strPictureURL.GetThumbURLs(thumbs, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
        else
          tag.m_strPictureURL.GetThumbURLs(thumbs);

        for (unsigned int i = 0; i < thumbs.size(); i++)
        {
          CStdString strItemPath;
          strItemPath.Format("thumb://Remote%i",i);
          CFileItemPtr item(new CFileItem(strItemPath, false));
          item->SetThumbnailImage(thumbs[i]);
          item->SetIconImage("DefaultPicture.png");
          item->SetLabel(g_localizeStrings.Get(20015));
          items.Add(item);

          // TODO: Do we need to clear the cached image?
          //    CTextureCache::Get().ClearCachedImage(thumbs[i]);
        }
      }

      bool local=false;
      if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
      {
        CStdString picturePath;

        CStdString strPath = m_vecItems->Get(itemNumber)->m_strPath;
        CUtil::RemoveSlashAtEnd(strPath);

        int nPos=strPath.ReverseFind("/");
        if (nPos>-1)
        {
          //  try to guess where the user should start
          //  browsing for the artist thumb
          CMusicDatabase database;
          database.Open();
          long idArtist=database.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
          database.GetArtistPath(idArtist, picturePath);
        }

        CStdString strThumb;
        CUtil::AddFileToFolder(picturePath,"folder.jpg",strThumb);
        if (XFILE::CFile::Exists(strThumb))
        {
          CFileItemPtr pItem(new CFileItem(strThumb,false));
          pItem->SetLabel(g_localizeStrings.Get(20017));
          pItem->SetThumbnailImage(strThumb);
          items.Add(pItem);
          local = true;
        }
        else
          noneitem->SetIconImage("DefaultArtist.png");
      }

      if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
      {
        CStdString picturePath;
        CStdString strThumb;
        CUtil::AddFileToFolder(picturePath,"folder.jpg",strThumb);
        if (XFILE::CFile::Exists(strThumb))
        {
          CFileItemPtr pItem(new CFileItem(strThumb,false));
          pItem->SetLabel(g_localizeStrings.Get(20017));
          pItem->SetThumbnailImage(strThumb);
          items.Add(pItem);
          local = true;
        }
        else
          noneitem->SetIconImage("DefaultActor.png");
      }

      if (button == CONTEXT_BUTTON_SET_MOVIESET_THUMB)
        noneitem->SetIconImage("DefaultVideo.png");

      if (!local)
        items.Add(noneitem);

      VECSOURCES sources=g_settings.m_videoSources;
      g_mediaManager.GetLocalDrives(sources);
      CStdString result;
      if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources,
                                                  g_localizeStrings.Get(20019), result))
      {
        return false;   // user cancelled
      }

      if (result == "thumb://Current")
        return false;   // user chose the one they have

      // delete the thumbnail if that's what the user wants, else overwrite with the
      // new thumbnail
      CTextureCache::Get().ClearCachedImage(cachedThumb, true);
      if (result.Left(14) == "thumb://Remote")
      {
        int number = atoi(result.Mid(14));
        CFile::Cache(thumbs[number], cachedThumb);
      }
      if (result == "thumb://None")
        CTextureCache::Get().ClearCachedImage(cachedThumb, true);
      else
        CFile::Cache(result,cachedThumb);

      CUtil::DeleteVideoDatabaseDirectoryCache();
      CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
      g_windowManager.SendMessage(msg);
      Update(m_vecItems->m_strPath);

      return true;
    }
  case CONTEXT_BUTTON_UPDATE_LIBRARY:
    {
      OnScan("");
      return true;
    }
  case CONTEXT_BUTTON_UNLINK_MOVIE:
    {
      OnLinkMovieToTvShow(itemNumber, true);
      Update(m_vecItems->m_strPath);
      return true;
    }
  case CONTEXT_BUTTON_LINK_MOVIE:
    {
      OnLinkMovieToTvShow(itemNumber, false);
      return true;
    }
  case CONTEXT_BUTTON_GO_TO_ARTIST:
    {
      CStdString strPath;
      CMusicDatabase database;
      database.Open();
      strPath.Format("musicdb://2/%ld/",database.GetArtistByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist));
      g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
      return true;
    }
  case CONTEXT_BUTTON_GO_TO_ALBUM:
    {
      CStdString strPath;
      CMusicDatabase database;
      database.Open();
      strPath.Format("musicdb://3/%ld/",database.GetAlbumByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum));
      g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
      return true;
    }
  case CONTEXT_BUTTON_PLAY_OTHER:
    {
      CMusicDatabase database;
      database.Open();
      CSong song;
      if (database.GetSongById(database.GetSongByArtistAndAlbumAndTitle(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum,
                                                                        m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strTitle),
                                                                        song))
      {
        g_application.getApplicationMessenger().PlayFile(song);
      }
      return true;
    }

  case CONTEXT_BUTTON_UNLINK_BOOKMARK:
    {
      m_database.Open();
      m_database.DeleteBookMarkForEpisode(*m_vecItems->Get(itemNumber)->GetVideoInfoTag());
      m_database.Close();
      CUtil::DeleteVideoDatabaseDirectoryCache();
      Update(m_vecItems->m_strPath);
      return true;
    }

  default:
    break;

  }
  return CGUIWindowVideoBase::OnContextButton(itemNumber, button);
}