Пример #1
0
void Resume::ReadVlcResumeFile()
{

	Sleep(100); //wait for VLC to write file (TODO: make threaded)

	//get username
	TCHAR username[UNLEN + 1];
	DWORD username_len = UNLEN + 1;
	GetUserName(username, &username_len);

	RString strTemp;
	RString strVlcFile;

	//build path to vlc info file
	RString strFilePath = _T("C:\\Users\\");
	strFilePath += username;
	strFilePath += _T("\\AppData\\Roaming\\vlc\\vlc-qt-interface.ini");

	//read VLC resume file into str
	if (!FileToString(strFilePath, strVlcFile))
		return;

	if (GetFirstMatch(strVlcFile, _T("list=([^$]*?$)"), &strTemp))
	{
		strTemp.Replace(_T(" "), _T(""));
		RArray<const TCHAR*> moviesTemp = SplitString(strTemp, _T(","), true);
		size = moviesTemp.GetSize();
		if (size > MAX_SIZE) size = MAX_SIZE;

		for(int i=0; i<size; i++)
		{
			//remove % codes and turn + to space
			RString strTempMovie = URLDecode(moviesTemp[i]);

			//remove file:/// or file://
			if (strTempMovie.Left(8) == _T("file:///"))
				strTempMovie = strTempMovie.Right(strTempMovie.GetLength() - 8);
			else
				strTempMovie = strTempMovie.Right(strTempMovie.GetLength() - 5);

			strTempMovie.Replace(_T("/"), _T("\\\\"));
			movies[i] = strTempMovie;
		}
	}

	if (GetFirstMatch(strVlcFile, _T("times=([^$]*?$)"), &strTemp))
	{
		strTemp.Replace(_T(" "), _T(""));
		RArray<const TCHAR*> strTimes = SplitString(strTemp, _T(","), true);
		for(int i=0; i<strTimes.GetSize(); i++)
			times[i] = StringToNumber(strTimes[i])/1000;  //milliseconds to seconds
	}

	UpdateResumeTimes();
}
Пример #2
0
bool RandomSample::LoadSoundDir( RString sDir, int iMaxToLoad )
{
	if( sDir == "" )
		return true;

#if 0
	/* (don't want to do this just yet) */
	/* If this is actually a directory, add a backslash to the filename,
	 * so we'll look for eg. themes\Default\sounds\sDir\*.mp3.  Otherwise,
	 * don't, so we'll look for all of the files starting with sDir,
	 * eg. themes\Default\sounds\sDir*.mp3. */
	if(IsADirectory(sDir) && sDir[sDir.size()-1] != "/" )
		sDir += "/";
#else
	// make sure there's a slash at the end of this path
	if( sDir.Right(1) != "/" )
		sDir += "/";
#endif

	vector<RString> arraySoundFiles;
	GetDirListing( sDir + "*.mp3", arraySoundFiles );
	GetDirListing( sDir + "*.oga", arraySoundFiles );
	GetDirListing( sDir + "*.ogg", arraySoundFiles );
	GetDirListing( sDir + "*.wav", arraySoundFiles );

	random_shuffle( arraySoundFiles.begin(), arraySoundFiles.end() );
	arraySoundFiles.resize( min( arraySoundFiles.size(), (unsigned)iMaxToLoad ) );

	for( unsigned i=0; i<arraySoundFiles.size(); i++ )
		LoadSound( sDir + arraySoundFiles[i] );

	return true;
}
Пример #3
0
bool IniFile::ReadFile( RageFileBasic &f )
{
	RString keyname;
	while( 1 )
	{
		RString line;
		/* Read lines until we reach a line that doesn't end in a backslash */
		while( true )
		{
			RString s;
			switch( f.GetLine(s) )
			{
			case -1:
				m_sError = f.GetError();
				return false;
			case 0:
				return true; /* eof */
			}

			utf8_remove_bom( s );

			line += s;

			if( line.empty() || line[line.size()-1] != '\\' )
				break;

			line.erase( line.end()-1 );
		}


		if( line.size() == 0 )
			continue;
		if( line[0] == '#' )
			continue; /* comment */
		if( line.size() > 1 && line[0] == '/' && line[1] == '/' )
			continue; /* comment */

		if( line[0] == '[' && line[line.size()-1] == ']'  )
		{
			/* New section. */
			keyname = line.substr(1, line.size()-2);
		}
		else
		{
			/* New value. */
			size_t iEqualIndex = line.find("=");
			if( iEqualIndex != string::npos )
			{
				RString valuename = line.Left( (int) iEqualIndex );
				RString value = line.Right( line.size()-valuename.size()-1 );
				Trim( valuename );
				if( keyname.size() && valuename.size() )
					SetValue( keyname, valuename, value );
			}
		}
	}
}
void ScreenGameplaySyncMachine::Init()
{
	m_bForceNoNetwork = true;

	GAMESTATE->m_PlayMode.Set( PLAY_MODE_REGULAR );
	GAMESTATE->SetCurrentStyle( GAMEMAN->GetHowToPlayStyleForGame(GAMESTATE->m_pCurGame) );
	AdjustSync::ResetOriginalSyncData();

	RString sFile = THEME->GetPathO("ScreenGameplaySyncMachine","music");
	// Allow themers to use either a .ssc or .sm file for this. -aj
	SSCLoader loaderSSC;
	SMLoader loaderSM;
	if(sFile.Right(4) == ".ssc")
		loaderSSC.LoadFromSimfile( sFile, m_Song );
	else
		loaderSM.LoadFromSimfile( sFile, m_Song );

	m_Song.SetSongDir( Dirname(sFile) );
	m_Song.TidyUpData();

	GAMESTATE->m_pCurSong.Set( &m_Song );
	// Needs proper StepsType -freem
	vector<Steps*> vpSteps;
	SongUtil::GetPlayableSteps( &m_Song, vpSteps );
	ASSERT_M(vpSteps.size() > 0, "No playable steps for ScreenGameplaySyncMachine");
	Steps *pSteps = vpSteps[0];
	GAMESTATE->m_pCurSteps[GAMESTATE->GetFirstHumanPlayer()].Set( pSteps );

	GamePreferences::m_AutoPlay.Set( PC_HUMAN );

	ScreenGameplayNormal::Init();

	SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_AutosyncType, SongOptions::AUTOSYNC_MACHINE );

	ClearMessageQueue();	// remove all of the messages set in ScreenGameplay that animate "ready", "here we go", etc.

	GAMESTATE->m_bGameplayLeadIn.Set( false );

	m_DancingState = STATE_DANCING;

	m_textSyncInfo.SetName( "SyncInfo" );
	m_textSyncInfo.LoadFromFont( THEME->GetPathF(m_sName,"SyncInfo") );
	ActorUtil::LoadAllCommands( m_textSyncInfo, m_sName );
	this->AddChild( &m_textSyncInfo );

	this->SubscribeToMessage( Message_AutosyncChanged );

	RefreshText();
}
Пример #5
0
static void FileNameToMetricsGroupAndElement( const RString &sFileName, RString &sMetricsGroupOut, RString &sElementOut )
{
	// split into class name and file name
	RString::size_type iIndexOfFirstSpace = sFileName.find(" ");
	if( iIndexOfFirstSpace == string::npos ) // no space
	{
		sMetricsGroupOut = "";
		sElementOut = sFileName;
	}
	else
	{
		sMetricsGroupOut = sFileName.Left( iIndexOfFirstSpace );
		sElementOut = sFileName.Right( sFileName.size() - iIndexOfFirstSpace - 1 );
	}
}
Пример #6
0
void ParseFileName(RString_ strFileName, RString &strTitle, RString &strYear)
{
	INT_PTR m, n;
	RString strTemp;

	strTitle = strFileName;
	strYear.Empty();

	// only keep file name

	n = strTitle.ReverseFind(_T('\\'));
	if (n != -1)
		strTitle = strTitle.Mid(n + 1);
	//strTitle.MakeLower();

	// strip file extension (max 4 chars)

	n = strTitle.ReverseFind(_T('.'));
	if (n != -1 && strTitle.GetLength() - n < 6)
		strTitle = strTitle.Left(n);

	// replace []{} by ()

	strTitle.Replace(_T('['), _T('('));
	strTitle.Replace(_T(']'), _T(')'));
	strTitle.Replace(_T('{'), _T('('));
	strTitle.Replace(_T('}'), _T(')'));

	/*
	// replace anything not ,()0-9a-zA-Z by a space

	for (int i = 0; i < strTitle.GetLength(); i++)
		if (!(strTitle[i] == _T(',')) &&
			!(strTitle[i] == _T('\'')) &&
			!(strTitle[i] == _T('(')) &&
			!(strTitle[i] == _T(')')) &&
			!(strTitle[i] >= _T('0') && strTitle[i] <= _T('9')) &&
			!(strTitle[i] >= _T('A') && strTitle[i] <= _T('Z')) &&
			!(strTitle[i] >= _T('a') && strTitle[i] <= _T('z')))
			*((LPTSTR)(LPCTSTR)strTitle + i) = _T(' ');
	*/

	// replace ._ by a space

	strTitle.Replace(_T('.'), _T(' '));
	strTitle.Replace(_T('_'), _T(' '));

	// remove redundant space

	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	// find year between (), strip anything following it

	for (n = 0; (n = strTitle.Find(_T('('), n)) != -1; n++)
	{
		if (n+5 < strTitle.GetLength() && strTitle[n+5] == _T(')'))
		{
			strTemp = strTitle.Mid(n+1, 4);
			if (StringToNumber(strTemp) > 1900)
			{
				strYear = strTemp;
				strTitle = strTitle.Left(n);
				break;
			}
		}
	}

	// remove anything between ()

	for (m = 0, n = 0; (m = strTitle.Find(_T('('), n)) != -1 &&
			(n = strTitle.Find(_T(')'), m)) != -1; m = 0, n = 0)
		strTitle = strTitle.Left(m) + strTitle.Mid(n+1);

	// find year not in (), but not as first word, strip anything following it

	strTitle.Replace(_T('('), _T(' '));
	strTitle.Replace(_T(')'), _T(' '));
	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	if (strYear.IsEmpty())
	{
		m = 0;
		while (true)
		{
			if (m >= strTitle.GetLength())
				break;

			n = strTitle.Find(_T(' '), m);

			if (n == -1)
				n = strTitle.GetLength();

			if (m == n)
				{m = n + 1; continue;}

			if (n - m == 4)
			{
				strTemp = strTitle.Mid(m, n - m);
				if (StringToNumber(strTemp) > 1900 && m > 0)
				{
					strYear = strTemp;
					strTitle = strTitle.Left(m);
					break;
				}
			}

			m = n + 1;
		}
	}

	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	// place some literals in front

	if (strTitle.GetLength() > 5 && strTitle.Right(5) == _T(", the"))
		strTitle = _T("the ") + strTitle.Left(strTitle.GetLength() - 5);
	if (strTitle.GetLength() > 5 && strTitle.Right(5) == _T(", The"))
		strTitle = _T("The ") + strTitle.Left(strTitle.GetLength() - 5);
	if (strTitle.GetLength() > 3 && strTitle.Right(3) == _T(", a"))
		strTitle = _T("a ") + strTitle.Left(strTitle.GetLength() - 3);
	if (strTitle.GetLength() > 3 && strTitle.Right(3) == _T(", A"))
		strTitle = _T("A ") + strTitle.Left(strTitle.GetLength() - 3);
	
	strTitle.Replace(_T(','), _T(' '));
	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	//TRACE0(_T("ParseFileName\n  strFileName = ") + strFileName + _T("\n  strTitle = ") +
	//		strTitle + _T("\n  strYear = ") + strYear + _T("\n"));
}
void FileTransfer::StartTransfer( TransferType type, const RString &sURL, const RString &sSrcFile, const RString &sDestFile )
{
	RString Proto;
	RString Server;
	int Port=80;
	RString sAddress;

	if( !ParseHTTPAddress( sURL, Proto, Server, Port, sAddress ) )
	{
		m_sStatus = "Invalid URL.";
		m_bFinished = true;
		UpdateProgress();
		return;
	}

	m_bSavingFile = sDestFile != "";

	m_sBaseAddress = "http://" + Server;
	if( Port != 80 )
		m_sBaseAddress += ssprintf( ":%d", Port );
	m_sBaseAddress += "/";

	if( sAddress.Right(1) != "/" )
	{
		m_sEndName = Basename( sAddress );
		m_sBaseAddress += Dirname( sAddress );
	}
	else
	{
		m_sEndName = "";
	}

	// Open the file...

	// First find out if a file by this name already exists if so, then we gotta
	// ditch out.
	// XXX: This should be fixed by a prompt or something?

	// if we are not talking about a file, let's not worry
	if( m_sEndName != "" && m_bSavingFile )
	{
		if( !m_fOutputFile.Open( sDestFile, RageFile::WRITE | RageFile::STREAMED ) )
		{
			m_sStatus = m_fOutputFile.GetError();
			UpdateProgress();
			return;
		}
	}
	// Continue...

	sAddress = URLEncode( sAddress );

	if ( sAddress != "/" )
		sAddress = "/" + sAddress;

	m_wSocket.close();
	m_wSocket.create();

	m_wSocket.blocking = true;

	if( !m_wSocket.connect( Server, (short) Port ) )
	{
		m_sStatus = "Failed to connect.";
		UpdateProgress();
		return;
	}

	// Produce HTTP header
	RString sAction;
	switch( type )
	{
	case upload: sAction = "POST"; break;
	case download: sAction = "GET"; break;
	}

	vector<RString> vsHeaders;
	vsHeaders.push_back( sAction+" "+sAddress+" HTTP/1.0" );
	vsHeaders.push_back( "Host: " + Server );
	vsHeaders.push_back( "Cookie: " + g_sCookie.Get() );
	vsHeaders.push_back( "Connection: closed" );
	string sBoundary = "--ZzAaB03x";
	vsHeaders.push_back( "Content-Type: multipart/form-data; boundary=" + sBoundary );
	RString sRequestPayload;
	if( type == upload )
	{
		RageFile f;
		if( !f.Open( sSrcFile ) )
			FAIL_M( f.GetError() );
		sRequestPayload.reserve( f.GetFileSize() );
		int iBytesRead = f.Read( sRequestPayload );
		if( iBytesRead == -1 )
			FAIL_M( f.GetError() );

		sRequestPayload = "--" + sBoundary + "\r\n" + 
			"Content-Disposition: form-data; name=\"name\"\r\n" +
			"\r\n" +
			"Chris\r\n" +
			"--" + sBoundary + "\r\n" + 
			"Content-Disposition: form-data; name=\"userfile\"; filename=\"" + Basename(sSrcFile) + "\"\r\n" +
			"Content-Type: application/zip\r\n" + 
			"\r\n" +
			sRequestPayload + "\r\n" +
			"--" + sBoundary + "--";
	}
	/*
	if( sRequestPayload.size() > 0 )
	{
		sHeader += "Content-Type: application/octet-stream\r\n";
		sHeader += "Content-Length: multipart/form-data; boundary=" + sBoundary + "\r\n";
		//sHeader += "Content-Length: " + ssprintf("%d",sRequestPayload.size()) + "\r\n";
	}
	*/

	vsHeaders.push_back( "Content-Length: " + ssprintf("%zd",sRequestPayload.size()) );

	RString sHeader;
	FOREACH_CONST( RString, vsHeaders, h )
		sHeader += *h + "\r\n";
	sHeader += "\r\n";

	m_wSocket.SendData( sHeader.c_str(), sHeader.length() );
	m_wSocket.SendData( "\r\n" );

	m_wSocket.SendData( sRequestPayload.GetBuffer(), sRequestPayload.size() );

	m_sStatus = "Header Sent.";
	m_wSocket.blocking = false;
	m_bIsDownloading = true;
	m_sBUFFER = "";
	m_bGotHeader = false;
	UpdateProgress();
}
void DirectFilenameDB::PopulateFileSet( FileSet &fs, const RString &path )
{
	RString sPath = path;

#if defined(XBOX)
	/* Xbox doesn't handle path names which end with ".", which are used when using an
	 * alternative song directory */
	if( sPath.size() > 0 && sPath.Right(1) == "." )
		sPath.erase( sPath.size() - 1 );
#endif

	/* Resolve path cases (path/Path -> PATH/path). */
	ResolvePath( sPath );

	fs.age.GetDeltaTime(); /* reset */
	fs.files.clear();

#if defined(WIN32)
	WIN32_FIND_DATA fd;

	if ( sPath.size() > 0  && sPath.Right(1) == "/" )
		sPath.erase( sPath.size() - 1 );

	HANDLE hFind = DoFindFirstFile( root+sPath+"/*", &fd );
	CHECKPOINT_M( root+sPath+"/*" );

	if( hFind == INVALID_HANDLE_VALUE )
		return;

	do {
		if( !strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..") )
			continue;

		File f;
		f.SetName( fd.cFileName );
		f.dir = !!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
		f.size = fd.nFileSizeLow;
		f.hash = fd.ftLastWriteTime.dwLowDateTime;

		fs.files.insert( f );
	} while( FindNextFile( hFind, &fd ) );
	FindClose( hFind );
#else
	/* Ugly: POSIX threads are not guaranteed to have per-thread cwds, and only
	 * a few systems have openat() or equivalent; one or the other is needed
	 * to do efficient, thread-safe directory traversal.  Instead, we have to
	 * use absolute paths, which forces the system to re-parse the directory
	 * for each file.  This isn't a major issue, since most large directory
	 * scans are I/O-bound. */
	 
	DIR *pDir = opendir(root+sPath);
	if( pDir == NULL )
		return;

	while( struct dirent *pEnt = readdir(pDir) )
	{
		if( !strcmp(pEnt->d_name, ".") )
			continue;
		if( !strcmp(pEnt->d_name, "..") )
			continue;
		
		File f( pEnt->d_name );
		
		struct stat st;
		if( DoStat(root+sPath + "/" + pEnt->d_name, &st) == -1 )
		{
			int iError = errno;
			/* If it's a broken symlink, ignore it.  Otherwise, warn. */
			if( lstat(root+sPath + "/" + pEnt->d_name, &st) == 0 )
				continue;
			
			/* Huh? */
			WARN( ssprintf("Got file '%s' in '%s' from list, but can't stat? (%s)",
					pEnt->d_name, sPath.c_str(), strerror(iError)) );
			continue;
		}
		else
		{
			f.dir = (st.st_mode & S_IFDIR);
			f.size = (int)st.st_size;
			f.hash = st.st_mtime;
		}

		fs.files.insert(f);
	}
	       
	closedir( pDir );
#endif

	/*
	 * Check for any ".ignore" markers.  If a marker exists, hide the marker and its 
	 * corresponding file.
	 * For example, if "file.xml.ignore" exists, hide both it and "file.xml" by 
	 * removing them from the file set.
	 * Ignore markers are used for convenience during build staging and are not used in 
	 * performance-critical situations.  To avoid incurring some of the overheard 
	 * due to ignore markers, delete the file instead instead of using an ignore marker.
	 */
	static const RString IGNORE_MARKER_BEGINNING = "ignore-";

	vector<RString> vsFilesToRemove;
	for( set<File>::iterator iter = fs.files.lower_bound(IGNORE_MARKER_BEGINNING); 
		 iter != fs.files.end(); 
		 ++iter )
	{
		if( !BeginsWith( iter->lname, IGNORE_MARKER_BEGINNING ) )
			break;
		RString sFileLNameToIgnore = iter->lname.Right( iter->lname.length() - IGNORE_MARKER_BEGINNING.length() );
		vsFilesToRemove.push_back( iter->name );
		vsFilesToRemove.push_back( sFileLNameToIgnore );
	}
	
	FOREACH_CONST( RString, vsFilesToRemove, iter )
	{
		// Erase the file corresponding to the ignore marker
		File fileToDelete;
		fileToDelete.SetName( *iter );
		set<File>::iterator iter2 = fs.files.find( fileToDelete );
		if( iter2 != fs.files.end() )
			fs.files.erase( iter2 );
	}
Пример #9
0
void ParseFileName(RString_ strFileName, RString &strTitle, RString &strYear, INT_PTR &nSeason, INT_PTR &nEpisode, RString &strAirDate, BYTE &bType)
{
	INT_PTR m, n;
	RString strTemp, strSeason, strEpisode;
	RString strYearTmp, strMonthTmp, strDayTmp;

	strTitle = strFileName;
	strYear.Empty();

	// only keep file name

	n = strTitle.ReverseFind(_T('\\'));
	if (n != -1)
		strTitle = strTitle.Mid(n + 1);
	//strTitle.MakeLower();

	// strip file extension (max 4 chars)

	n = strTitle.ReverseFind(_T('.'));
	if (n != -1 && strTitle.GetLength() - n < 6)
		strTitle = strTitle.Left(n);

	// replace []{} by ()

	strTitle.Replace(_T('['), _T('('));
	strTitle.Replace(_T(']'), _T(')'));
	strTitle.Replace(_T('{'), _T('('));
	strTitle.Replace(_T('}'), _T(')'));

	/*
	// replace anything not ,()0-9a-zA-Z by a space

	for (int i = 0; i < strTitle.GetLength(); i++)
	if (!(strTitle[i] == _T(',')) &&
	!(strTitle[i] == _T('\'')) &&
	!(strTitle[i] == _T('(')) &&
	!(strTitle[i] == _T(')')) &&
	!(strTitle[i] >= _T('0') && strTitle[i] <= _T('9')) &&
	!(strTitle[i] >= _T('A') && strTitle[i] <= _T('Z')) &&
	!(strTitle[i] >= _T('a') && strTitle[i] <= _T('z')))
	*((LPTSTR)(LPCTSTR)strTitle + i) = _T(' ');
	*/

	// remove urls

	RString strUrl;
	if (GetFirstMatch(strTitle, _T("([wW][wW][wW]\\.[^\\.]*?\\.[cC][oO][mM])"), &strUrl, NULL))
	{
		m = strTitle.Find(strUrl, 0);
		if (m >= 0)
			strTitle = strTitle.Left(m) + strTitle.Right(strTitle.GetLength() - (m + strUrl.GetLength()));
	}

	// replace ._ -by a space

	strTitle.Replace(_T('.'), _T(' '));
	strTitle.Replace(_T('_'), _T(' '));
	strTitle.Replace(_T('-'), _T(' '));

	// remove redundant space

	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	// find year between (), strip anything following it

	for (n = 0; (n = strTitle.Find(_T('('), n)) != -1; n++)
	{
		if (n + 5 < strTitle.GetLength() && strTitle[n + 5] == _T(')'))
		{
			strTemp = strTitle.Mid(n + 1, 4);
			if (StringToNumber(strTemp) > 1900)
			{
				strYear = strTemp;
				strTitle = strTitle.Left(n);
				break;
			}
		}
	}

	// remove anything between ()

	for (m = 0, n = 0; (m = strTitle.Find(_T('('), n)) != -1 &&
		(n = strTitle.Find(_T(')'), m)) != -1; m = 0, n = 0)
		strTitle = strTitle.Left(m) + strTitle.Mid(n + 1);

	// for TV shows. Find the season and episode and remove everything following it

	if (GetFirstMatch(strTitle, _T("([Ss]\\d?\\d[Ee]\\d?\\d)"), &strTemp, NULL))
	{
		m = strTitle.Find(strTemp, 0);
		if (GetFirstMatch(strTemp, _T("[Ss](\\d?\\d)[Ee](\\d?\\d)"), &strSeason, &strEpisode, NULL))
		{
			nSeason = StringToNumber(strSeason);
			nEpisode = StringToNumber(strEpisode);
			bType = DB_TYPE_TV;
		}

		if (m >= 0)
			strTitle = strTitle.Left(m);
	}

	// for TV shows by date and parse date aired

	if (GetFirstMatch(strTitle, _T("(\\d\\d\\d\\d) (\\d?\\d) (\\d?\\d)"), &strYearTmp, &strMonthTmp, &strDayTmp, NULL))
	{
		const RString Month[12] = { _T("Jan"), _T("Feb"), _T("Mar"), _T("Apr"),
			_T("May"), _T("Jun"), _T("Jul"), _T("Aug"), _T("Sep"), _T("Oct"), _T("Nov"), _T("Dec") };

		strAirDate = strDayTmp + _T(" ") + Month[StringToNumber(strMonthTmp) - 1] + _T(". ") + strYearTmp;
		bType = DB_TYPE_TV;
	}

	// find year not in (), but not as first word, strip anything following it

	strTitle.Replace(_T('('), _T(' '));
	strTitle.Replace(_T(')'), _T(' '));
	while (strTitle.Replace(_T("  "), _T(" ")));
	strTitle.Trim();

	if (strYear.IsEmpty())
	{
		m = 0;
		while (m < strTitle.GetLength())
		{
			n = strTitle.Find(_T(' '), m);

			if (n == -1)
				n = strTitle.GetLength();

			if (m == n)
			{
				m = n + 1; continue;
			}

			if (n - m == 4)
			{
				strTemp = strTitle.Mid(m, n - m);
				if (StringToNumber(strTemp) > 1900 && m > 0)
				{
					strYear = strTemp;
					strTitle = strTitle.Left(m);
					break;
				}
			}

			m = n + 1;
		}
	}

	// strip 'season[s] \\d' and anything following it
	RString strSeasons;
	if (GetFirstMatch(strTitle, _T("([Ss]eason[s]? ?\\d?\\d(?: ?- ?\\d?\\d)?)"), &strSeasons, NULL))
	{
		m = strTitle.Find(strSeasons, 0);
		if (m >= 0)
			strTitle = strTitle.Left(m);
		bType = DB_TYPE_TV;
	}

	//Remove episode numbers of the form XXofYY - TODO: process to return episode number

	RString strOf;
	if (GetFirstMatch(strTitle, _T("(\\d?\\d[oO][fF]\\d?\\d)"), &strOf, NULL))
	{
		m = strTitle.Find(strOf, 0);
		if (m > 0)
			strTitle = strTitle.Left(m);
		bType = DB_TYPE_TV;
	}

	// strip common movie descriptors and everything after

	static const RString strDescriptors[] = { _T("webrip"), _T("dvdrip"), _T("dvdscr"), _T("xvid"), _T("bdrip"),
		_T("brrip"), _T("hdtv"), _T("pdtv"), _T("box set"), _T("box-set"), _T("x264") };
	foreach(strDescriptors, strD)
	{
		m = strTitle.FindNoCase(strD, 0);
		if (m > 0)
			strTitle = strTitle.Left(m);
	}