Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

931 lines
26 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #if defined( WIN32 ) && !defined( _X360 )
  8. #include "winlite.h"
  9. #include <WinInet.h>
  10. #endif
  11. #include "youtubeapi.h"
  12. #include "platform.h"
  13. #include "convar.h"
  14. #include "fmtstr.h"
  15. #include "igamesystem.h"
  16. #include "strtools.h"
  17. #include "cdll_util.h"
  18. #include "utlmap.h"
  19. #include "utlstring.h"
  20. #include "vstdlib/jobthread.h"
  21. #include <steam/steam_api.h>
  22. #include <steam/isteamhttp.h>
  23. #include "cdll_client_int.h"
  24. #include "utlbuffer.h"
  25. #include "filesystem.h"
  26. // memdbgon must be the last include file in a .cpp file!!!
  27. #include "tier0/memdbgon.h"
  28. //=============================================================================
  29. static ConVar youtube_http_proxy( "youtube_http_proxy", "", FCVAR_ARCHIVE, "HTTP proxy. Specify if you have have problems uploading to YouTube." );
  30. //=============================================================================
  31. static bool GetStandardTagValue( const char *pTag, const char *pXML, CUtlString &strResult )
  32. {
  33. const char *pStart = strstr( pXML, pTag );
  34. if ( pStart != NULL )
  35. {
  36. pStart = strstr( pStart, ">" );
  37. if ( pStart != NULL )
  38. {
  39. pStart += 1;
  40. const char *pEnd = strstr( pStart, CFmtStr1024( "</%s", pTag ) );
  41. if ( pEnd != NULL )
  42. {
  43. strResult.SetDirect( pStart, pEnd - pStart );
  44. return true;
  45. }
  46. }
  47. }
  48. return false;
  49. }
  50. //=============================================================================
  51. class CYouTubeRetrieveInfoJob;
  52. namespace
  53. {
  54. class CYouTubeSystem : public CAutoGameSystemPerFrame
  55. {
  56. public:
  57. CYouTubeSystem();
  58. ~CYouTubeSystem();
  59. // CAutoGameSystem
  60. virtual bool Init();
  61. virtual void PostInit();
  62. virtual void Shutdown();
  63. virtual bool IsPerFrame() { return true; }
  64. virtual void Update( float frametime );
  65. void Login( const char *pUserName, const char *pPassword, const char *pSource );
  66. void LoginCancel();
  67. YouTubeUploadHandle_t Upload( const char* pFilePath, const char *pMimeType, const char *pTitle, const char *pDescription, const char *pCategory, const char *pKeywords, eYouTubeAccessControl access );
  68. bool IsUploadFinished( YouTubeUploadHandle_t handle );
  69. bool GetUploadProgress( YouTubeUploadHandle_t handle, double &ultotal, double &ulnow );
  70. bool GetUploadResults( YouTubeUploadHandle_t handle, bool &bSuccess, CUtlString &strURLToVideo, CUtlString &strURLToVideoStats );
  71. void ClearUploadResults( YouTubeUploadHandle_t handle );
  72. void CancelUpload( YouTubeUploadHandle_t handle );
  73. void SetUploadFinished( YouTubeUploadHandle_t handle, bool bSuccess, const char *pURLToVideo, const char *pURLToVideoStats );
  74. void SetUserProfile( const char *pUserProfile );
  75. bool GetProfileURL( CUtlString &strProfileURL ) const;
  76. YouTubeInfoHandle_t GetInfo( const char *pURLToVideoStats, CYouTubeResponseHandler &responseHandler );
  77. void CancelGetInfo( YouTubeInfoHandle_t handle );
  78. const char *GetDeveloperKey() const;
  79. const char *GetDeveloperTag() const;
  80. void SetDeveloperSettings( const char *pDeveloperKey, const char *pDeveloperTag );
  81. const char *GetLoginName() const;
  82. eYouTubeLoginStatus GetLoginStatus() const;
  83. void SetLoginStatus( eYouTubeLoginStatus status );
  84. const char* GetAuthToken() const;
  85. void SetAuthToken( const char *pAuthToken );
  86. private:
  87. struct uploadstatus_t
  88. {
  89. bool bFinished;
  90. bool bSuccess;
  91. CUtlString strURLToVideo;
  92. CUtlString strURLToVideoStats;
  93. };
  94. uploadstatus_t *GetStatus( YouTubeUploadHandle_t handle );
  95. eYouTubeLoginStatus m_eLoginStatus;
  96. CUtlString m_strYouTubeUserName;
  97. CUtlString m_strDeveloperKey;
  98. CUtlString m_strDeveloperTag;
  99. CUtlString m_strAuthToken;
  100. CUtlString m_strUserProfile;
  101. CThreadMutex m_Mutex;
  102. IThreadPool* m_pThreadPool;
  103. CUtlMap< YouTubeUploadHandle_t, uploadstatus_t > m_mapUploads;
  104. CUtlVector< CYouTubeRetrieveInfoJob * > m_vecRetrieveInfoJobs;
  105. };
  106. };
  107. static CYouTubeSystem gYouTube;
  108. static ISteamHTTP *GetISteamHTTP()
  109. {
  110. if ( steamapicontext != NULL && steamapicontext->SteamHTTP() )
  111. {
  112. return steamapicontext->SteamHTTP();
  113. }
  114. #ifndef CLIENT_DLL
  115. if ( steamgameserverapicontext != NULL )
  116. {
  117. return steamgameserverapicontext->SteamHTTP();
  118. }
  119. #endif
  120. return NULL;
  121. }
  122. //=============================================================================
  123. // Base class for all YouTube jobs
  124. class CYouTubeJob : public CJob
  125. {
  126. public:
  127. CYouTubeJob( CYouTubeSystem *pSystem )
  128. {
  129. SetFlags( JF_IO );
  130. // store local ones so we don't have to go through a mutex
  131. m_strDeveloperKey = pSystem->GetDeveloperKey();
  132. m_strDeveloperTag = pSystem->GetDeveloperTag();
  133. }
  134. virtual ~CYouTubeJob()
  135. {
  136. }
  137. void CancelUpload()
  138. {
  139. m_bCancelled = true;
  140. }
  141. bool IsCancelled() const
  142. {
  143. return m_bCancelled;
  144. }
  145. protected:
  146. void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam, bool bIOFailure )
  147. {
  148. m_bHTTPRequestPending = false;
  149. if ( (!m_bAllowRequestFailure && pParam->m_eStatusCode != k_EHTTPStatusCode200OK) || bIOFailure || !pParam->m_bRequestSuccessful )
  150. {
  151. Warning( "Failed to get youtube url: HTTP status %d fetching %s\n", pParam->m_eStatusCode, m_sURL.String() );
  152. }
  153. else
  154. {
  155. OnHTTPRequestCompleted( pParam );
  156. }
  157. }
  158. virtual void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam ) { Assert( false ); }
  159. void DoRequest( HTTPRequestHandle hRequest, const char *pchRequestURL )
  160. {
  161. m_sURL = pchRequestURL;
  162. SteamAPICall_t hSteamAPICall;
  163. if ( GetISteamHTTP()->SendHTTPRequest( hRequest, &hSteamAPICall ) )
  164. {
  165. m_HTTPRequestCompleted.Set( hSteamAPICall, this, &CYouTubeJob::OnHTTPRequestCompleted );
  166. }
  167. // Wait for it to finish.
  168. while ( m_bHTTPRequestPending && !m_bCancelled )
  169. {
  170. ThreadSleep( 100 );
  171. }
  172. GetISteamHTTP()->ReleaseHTTPRequest( hSteamAPICall );
  173. }
  174. CCallResult<CYouTubeJob, HTTPRequestCompleted_t> m_HTTPRequestCompleted;
  175. CUtlString m_strDeveloperKey;
  176. CUtlString m_strDeveloperTag;
  177. CUtlString m_sURL;
  178. CUtlString m_strResponse;
  179. bool m_bHTTPRequestPending = true;
  180. bool m_bAllowRequestFailure = false;
  181. bool m_bCancelled = false;
  182. };
  183. //=============================================================================
  184. class CYouTubeRetrieveUserProfile : public CYouTubeJob
  185. {
  186. public:
  187. CYouTubeRetrieveUserProfile( CYouTubeSystem *pSystem )
  188. : CYouTubeJob( pSystem )
  189. {
  190. }
  191. private:
  192. void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam ) OVERRIDE
  193. {
  194. uint32 unBodySize;
  195. if ( !GetISteamHTTP()->GetHTTPResponseBodySize( pParam->m_hRequest, &unBodySize ) )
  196. {
  197. Assert( false );
  198. }
  199. else
  200. {
  201. m_strResponse.SetLength( unBodySize );
  202. if ( GetISteamHTTP()->GetHTTPResponseBodyData( pParam->m_hRequest, (uint8*)m_strResponse.String(), unBodySize ) )
  203. {
  204. gYouTube.SetUserProfile( m_strResponse.Get() );
  205. }
  206. }
  207. }
  208. virtual JobStatus_t DoExecute()
  209. {
  210. HTTPRequestHandle hRequest = GetISteamHTTP()->CreateHTTPRequest( k_EHTTPMethodGET, "http://gdata.youtube.com/feeds/api/users/default" );
  211. GetISteamHTTP()->SetHTTPRequestNetworkActivityTimeout( hRequest, 30 );
  212. GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "Authorization", CFmtStr1024( "GoogleLogin auth=%s", gYouTube.GetAuthToken() ) );
  213. DoRequest( hRequest, "http://gdata.youtube.com/feeds/api/users/default" );
  214. return JOB_OK;
  215. }
  216. };
  217. //=============================================================================
  218. class CYouTubeRetrieveInfoJob : public CYouTubeJob
  219. {
  220. public:
  221. CYouTubeRetrieveInfoJob( CYouTubeSystem *pSystem, const char *pVideoURL, CYouTubeResponseHandler &responseHandler )
  222. : CYouTubeJob( pSystem )
  223. , m_strURL( pVideoURL )
  224. , m_responseHandler( responseHandler )
  225. {
  226. }
  227. void NotifyResponseHandler()
  228. {
  229. m_responseHandler.HandleResponse( 200, m_strResponse.Get() );
  230. }
  231. private:
  232. void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam ) OVERRIDE
  233. {
  234. uint32 unBodySize;
  235. if ( !GetISteamHTTP()->GetHTTPResponseBodySize( pParam->m_hRequest, &unBodySize ) )
  236. {
  237. Assert( false );
  238. }
  239. else
  240. {
  241. m_strResponse.SetLength( unBodySize );
  242. GetISteamHTTP()->GetHTTPResponseBodyData( pParam->m_hRequest, (uint8*)m_strResponse.String(), unBodySize );
  243. }
  244. }
  245. virtual JobStatus_t DoExecute()
  246. {
  247. HTTPRequestHandle hRequest = GetISteamHTTP()->CreateHTTPRequest( k_EHTTPMethodGET, m_strURL.Get() );
  248. GetISteamHTTP()->SetHTTPRequestNetworkActivityTimeout( hRequest, 30 );
  249. DoRequest( hRequest, m_strURL.Get() );
  250. return JOB_OK;
  251. }
  252. // data
  253. CUtlString m_strURL;
  254. CYouTubeResponseHandler &m_responseHandler;
  255. };
  256. class CYouTubeLoginJob : public CYouTubeJob
  257. {
  258. public:
  259. CYouTubeLoginJob( CYouTubeSystem *pSystem, const char *pUserName, const char *pPassword, const char *pSource )
  260. : CYouTubeJob( pSystem )
  261. , m_strUserName( pUserName )
  262. , m_strPassword( pPassword )
  263. , m_strSource( pSource )
  264. {
  265. }
  266. private:
  267. void SetLoginResults( const char *pLoginResults )
  268. {
  269. const char *pStart = strstr( pLoginResults, "Auth=" );
  270. if ( pStart != NULL )
  271. {
  272. pStart += strlen( "Auth=" );
  273. const char *pEnd = strstr( pStart, "\r\n" );
  274. if ( pEnd == NULL )
  275. {
  276. pEnd = strstr( pStart, "\n" );
  277. }
  278. CUtlString strAuthToken;
  279. if ( pEnd != NULL )
  280. {
  281. strAuthToken.SetDirect( pStart, pEnd - pStart );
  282. }
  283. else
  284. {
  285. strAuthToken.SetDirect( pStart, strlen( pStart ) );
  286. }
  287. gYouTube.SetAuthToken( strAuthToken.Get() );
  288. }
  289. }
  290. void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam ) OVERRIDE
  291. {
  292. eYouTubeLoginStatus loginStatus = kYouTubeLogin_LoggedIn;
  293. if ( pParam->m_eStatusCode == 403 )
  294. {
  295. loginStatus = kYouTubeLogin_Forbidden;
  296. }
  297. else if ( pParam->m_eStatusCode != 200 )
  298. {
  299. loginStatus = kYouTubeLogin_GenericFailure;
  300. }
  301. else
  302. {
  303. uint32 unBodySize;
  304. if ( !GetISteamHTTP()->GetHTTPResponseBodySize( pParam->m_hRequest, &unBodySize ) )
  305. {
  306. Assert( false );
  307. }
  308. else
  309. {
  310. m_strResponse.SetLength( unBodySize );
  311. if ( GetISteamHTTP()->GetHTTPResponseBodyData( pParam->m_hRequest, (uint8*)m_strResponse.String(), unBodySize ) )
  312. {
  313. SetLoginResults( m_strResponse );
  314. }
  315. }
  316. }
  317. gYouTube.SetLoginStatus( loginStatus );
  318. }
  319. virtual JobStatus_t DoExecute()
  320. {
  321. m_bAllowRequestFailure = true;
  322. HTTPRequestHandle hRequest = GetISteamHTTP()->CreateHTTPRequest( k_EHTTPMethodPOST, "https://www.google.com/accounts/ClientLogin" );
  323. GetISteamHTTP()->SetHTTPRequestNetworkActivityTimeout( hRequest, 30 );
  324. // GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "Content-Type", "application/x-www-form-urlencoded" );
  325. GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "X-GData-Key", CFmtStr1024( "key=%s", m_strDeveloperKey.Get() ) );
  326. char szUserNameEncoded[256];
  327. char szPasswordEncoded[256];
  328. char szSourceEncoded[256];
  329. Q_URLEncode( szUserNameEncoded, sizeof( szUserNameEncoded ), m_strUserName.Get(), m_strUserName.Length() );
  330. Q_URLEncode( szPasswordEncoded, sizeof( szPasswordEncoded ), m_strPassword.Get(), m_strPassword.Length() );
  331. Q_URLEncode( szSourceEncoded, sizeof( szSourceEncoded ), m_strSource.Get(), m_strSource.Length() );
  332. CFmtStr1024 data( "Email=%s&Passwd=%s&service=youtube&source=%s", szUserNameEncoded, szPasswordEncoded, szSourceEncoded );
  333. GetISteamHTTP()->SetHTTPRequestRawPostBody( hRequest, "application/x-www-form-urlencoded", (uint8 *)data.Access(), data.Length() );
  334. DoRequest( hRequest, "https://www.google.com/accounts/ClientLogin" );
  335. return JOB_OK;
  336. }
  337. // data
  338. CUtlString m_strUserName;
  339. CUtlString m_strPassword;
  340. CUtlString m_strSource;
  341. };
  342. // Job for uploading a file
  343. class CYouTubeUploadJob : public CYouTubeJob
  344. {
  345. public:
  346. CYouTubeUploadJob( CYouTubeSystem *pSystem, const char* pFilePath, const char *pMimeType, const char *pTitle, const char *pDescription, const char *pCategory, const char *pKeywords, eYouTubeAccessControl access )
  347. : CYouTubeJob( pSystem )
  348. , m_strFilePath( pFilePath )
  349. , m_strMimeType( pMimeType )
  350. , m_strTitle( pTitle )
  351. , m_strDesc( pDescription )
  352. , m_strCategory( pCategory )
  353. , m_strKeywords( pKeywords )
  354. , m_eAccess( access )
  355. {
  356. }
  357. void GetProgress( double &ultotal, double &ulnow )
  358. {
  359. ultotal = 0;
  360. ulnow = 0;
  361. }
  362. private:
  363. virtual JobStatus_t DoExecute()
  364. {
  365. m_bAllowRequestFailure = true;
  366. HTTPRequestHandle hRequest = GetISteamHTTP()->CreateHTTPRequest( k_EHTTPMethodPUT, "http://uploads.gdata.youtube.com/feeds/api/users/default/uploads" );
  367. GetISteamHTTP()->SetHTTPRequestNetworkActivityTimeout( hRequest, 30 );
  368. const char *pFileName = Q_UnqualifiedFileName( m_strFilePath.Get() );
  369. GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "Authorization", CFmtStr1024( "GoogleLogin auth=%s", gYouTube.GetAuthToken() ) );
  370. GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "X-GData-Key", CFmtStr1024( "key=%s", m_strDeveloperKey.Get() ) );
  371. GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "GData-Version", "2" );
  372. //GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "Content-Type", "multipart/form-data;boundary=-x" );
  373. GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "Slug", CFmtStr1024( "%s", pFileName ) );
  374. const char *pPrivateString = "";
  375. const char *pAccessControlString = "";
  376. switch ( m_eAccess )
  377. {
  378. case kYouTubeAccessControl_Public:
  379. break;
  380. case kYouTubeAccessControl_Private:
  381. pPrivateString = "<yt:private/>";
  382. break;
  383. case kYouTubeAccessControl_Unlisted:
  384. pAccessControlString = "<yt:accessControl action=\"list\" permission=\"denied\"/>";
  385. break;
  386. }
  387. CFmtStr1024 strAPIRequest( "<?xml version=\"1.0\"?>"
  388. "<entry "
  389. "xmlns=\"http://www.w3.org/2005/Atom\" "
  390. "xmlns:media=\"http://search.yahoo.com/mrss/\" "
  391. "xmlns:yt=\"http://gdata.youtube.com/schemas/2007\">"
  392. "<media:group>"
  393. "<media:title type=\"plain\">%s</media:title>"
  394. "<media:description type=\"plain\">%s</media:description>"
  395. "<media:category scheme=\"http://gdata.youtube.com/schemas/2007/categories.cat\">"
  396. "%s"
  397. "</media:category>"
  398. "%s"
  399. "<media:keywords>%s</media:keywords>"
  400. "<media:category scheme=\"http://gdata.youtube.com/schemas/2007/developertags.cat\">"
  401. "%s"
  402. "</media:category>"
  403. "</media:group>"
  404. "%s"
  405. "</entry>",
  406. m_strTitle.Get(),
  407. m_strDesc.Get(),
  408. m_strCategory.Get(),
  409. pPrivateString,
  410. m_strKeywords.Get(),
  411. m_strDeveloperTag.Get(),
  412. pAccessControlString );
  413. CFmtStr1024 fmtstrBody(
  414. "\r\nContent-Type: application/atom+xml; charset=UTF-8\r\n"
  415. "\r\n---x\r\nContent-Disposition: form-data; name=\"apirequest\"\r\n\r\n%s"
  416. "\r\n---x\r\nContent-Disposition: form-data; name=\"video\"\r\nContent-Type: %s\r\nContent-Transfer-Encoding: binary\r\n\r\n",
  417. strAPIRequest.Access(), m_strMimeType.Get()
  418. );
  419. CUtlBuffer postDataRaw( 0, 0, 0 );
  420. postDataRaw.Put( fmtstrBody.Access(), fmtstrBody.Length() );
  421. CUtlBuffer fileData( 0, 0, 0 );
  422. bool bReadFileOK = g_pFullFileSystem->ReadFile( m_strFilePath, nullptr, fileData );
  423. if ( bReadFileOK )
  424. {
  425. postDataRaw.Put( fileData.Base(), fileData.TellPut() );
  426. fileData.Clear();
  427. static const char rgchFooter[] = "\r\n---x--\r\n";
  428. postDataRaw.Put( rgchFooter, V_strlen( rgchFooter ) );
  429. GetISteamHTTP()->SetHTTPRequestRawPostBody( hRequest, "multipart/form-data;boundary=-x", (uint8 *)postDataRaw.Base(), postDataRaw.TellPut() );
  430. // BUGBUG: use SendHTTPRequestAndStreamResponse
  431. DoRequest( hRequest, "http://uploads.gdata.youtube.com/feeds/api/users/default/uploads" );
  432. }
  433. return JOB_OK;
  434. }
  435. void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam ) OVERRIDE
  436. {
  437. bool bSuccess = false;
  438. CUtlString strURLToVideoStats;
  439. CUtlString strURLToVideo;
  440. if ( pParam->m_eStatusCode == 200 )
  441. {
  442. bSuccess = true;
  443. uint32 unBodySize;
  444. if ( !GetISteamHTTP()->GetHTTPResponseBodySize( pParam->m_hRequest, &unBodySize ) )
  445. {
  446. Assert( false );
  447. }
  448. else
  449. {
  450. m_strResponse.SetLength( unBodySize );
  451. if ( GetISteamHTTP()->GetHTTPResponseBodyData( pParam->m_hRequest, (uint8*)m_strResponse.String(), unBodySize ) )
  452. {
  453. // @note Tom Bui: wish I had an xml parser...
  454. {
  455. strURLToVideo = "";
  456. // "<link rel='alternate' type='text/html' href='http://www.youtube.com/watch?v=7D4pb3irM_0&feature=youtube_gdata' /> ";
  457. const char *kLinkStartTag = "<link rel='alternate' type='text/html' href='";
  458. const char *kLinkTagEnd = "'/>";
  459. const char *pStart = strstr( m_strResponse.Get(), kLinkStartTag );
  460. if ( pStart != NULL )
  461. {
  462. pStart += strlen( kLinkStartTag );
  463. const char *pEnd = strstr( pStart, kLinkTagEnd );
  464. if ( pEnd != NULL )
  465. {
  466. strURLToVideo.SetDirect( pStart, pEnd - pStart );
  467. }
  468. }
  469. }
  470. {
  471. strURLToVideoStats = "";
  472. // "<link rel='self' type='text/html' href='http://www.youtube.com/watch?v=7D4pb3irM_0&feature=youtube_gdata' /> ";
  473. const char *kLinkStartTag = "<link rel='self' type='application/atom+xml' href='";
  474. const char *kLinkTagEnd = "'/>";
  475. const char *pStart = strstr( m_strResponse.Get(), kLinkStartTag );
  476. if ( pStart != NULL )
  477. {
  478. pStart += strlen( kLinkStartTag );
  479. const char *pEnd = strstr( pStart, kLinkTagEnd );
  480. if ( pEnd != NULL )
  481. {
  482. strURLToVideoStats.SetDirect( pStart, pEnd - pStart );
  483. // @note Tom Bui: we want at least version 2
  484. if ( V_strstr( strURLToVideoStats.Get(), "?v=" ) == NULL )
  485. {
  486. strURLToVideoStats += "?v=2";
  487. }
  488. }
  489. }
  490. }
  491. }
  492. }
  493. }
  494. gYouTube.SetUploadFinished( (YouTubeUploadHandle_t)this, bSuccess, strURLToVideo.Get(), strURLToVideoStats.Get() );
  495. }
  496. // data
  497. CUtlString m_strFilePath;
  498. CUtlString m_strMimeType;
  499. CUtlString m_strTitle;
  500. CUtlString m_strDesc;
  501. CUtlString m_strCategory;
  502. CUtlString m_strKeywords;
  503. eYouTubeAccessControl m_eAccess;
  504. };
  505. //=============================================================================
  506. CYouTubeSystem::CYouTubeSystem()
  507. : m_eLoginStatus( kYouTubeLogin_NotLoggedIn )
  508. , m_pThreadPool( NULL )
  509. , m_mapUploads( DefLessFunc( YouTubeUploadHandle_t ) )
  510. {
  511. }
  512. CYouTubeSystem::~CYouTubeSystem()
  513. {
  514. }
  515. bool CYouTubeSystem::Init()
  516. {
  517. m_pThreadPool = CreateThreadPool();
  518. m_pThreadPool->Start( ThreadPoolStartParams_t( false, 4 ), "YouTubeSystem" );
  519. return true;
  520. }
  521. void CYouTubeSystem::PostInit()
  522. {
  523. }
  524. void CYouTubeSystem::Shutdown()
  525. {
  526. DestroyThreadPool( m_pThreadPool );
  527. m_pThreadPool = NULL;
  528. }
  529. void CYouTubeSystem::Update( float frametime )
  530. {
  531. AUTO_LOCK( m_Mutex );
  532. FOR_EACH_VEC( m_vecRetrieveInfoJobs, i )
  533. {
  534. CYouTubeRetrieveInfoJob *pJob = m_vecRetrieveInfoJobs[i];
  535. if ( pJob->IsFinished() )
  536. {
  537. pJob->NotifyResponseHandler();
  538. // cleanup the job
  539. pJob->Release();
  540. // and remove
  541. m_vecRetrieveInfoJobs.FastRemove( i );
  542. }
  543. else
  544. {
  545. ++i;
  546. }
  547. }
  548. }
  549. void CYouTubeSystem::Login( const char *pUserName, const char *pPassword, const char *pSource )
  550. {
  551. m_eLoginStatus = kYouTubeLogin_NotLoggedIn;
  552. CYouTubeLoginJob *pJob = new CYouTubeLoginJob( this, pUserName, pPassword, pSource );
  553. m_pThreadPool->AddJob( pJob );
  554. pJob->Release();
  555. }
  556. void CYouTubeSystem::LoginCancel()
  557. {
  558. m_eLoginStatus = kYouTubeLogin_Cancelled;
  559. }
  560. YouTubeUploadHandle_t CYouTubeSystem::Upload( const char* pFilePath, const char *pMimeType, const char *pTitle, const char *pDescription, const char *pCategory, const char *pKeywords, eYouTubeAccessControl access )
  561. {
  562. if ( m_eLoginStatus != kYouTubeLogin_LoggedIn )
  563. {
  564. return NULL;
  565. }
  566. CYouTubeUploadJob *pJob = new CYouTubeUploadJob( this, pFilePath, pMimeType, pTitle, pDescription, pCategory, pKeywords, access );
  567. m_pThreadPool->AddJob( pJob );
  568. uploadstatus_t status = { false, false, "", "" };
  569. m_mapUploads.Insert( (YouTubeUploadHandle_t)pJob, status );
  570. return (YouTubeUploadHandle_t)pJob;
  571. }
  572. CYouTubeSystem::uploadstatus_t *CYouTubeSystem::GetStatus( YouTubeUploadHandle_t handle )
  573. {
  574. int idx = m_mapUploads.Find( handle );
  575. if ( m_mapUploads.IsValidIndex( idx ) )
  576. {
  577. return &m_mapUploads[idx];
  578. }
  579. return NULL;
  580. }
  581. bool CYouTubeSystem::IsUploadFinished( YouTubeUploadHandle_t handle )
  582. {
  583. AUTO_LOCK( m_Mutex );
  584. uploadstatus_t *pStatus = GetStatus( handle );
  585. if ( pStatus != NULL )
  586. {
  587. return pStatus->bFinished;
  588. }
  589. return true;
  590. }
  591. bool CYouTubeSystem::GetUploadProgress( YouTubeUploadHandle_t handle, double &ultotal, double &ulnow )
  592. {
  593. AUTO_LOCK( m_Mutex );
  594. uploadstatus_t *pStatus = GetStatus( handle );
  595. if ( pStatus != NULL )
  596. {
  597. CYouTubeUploadJob *pJob = (CYouTubeUploadJob*)handle;
  598. pJob->GetProgress( ultotal, ulnow );
  599. return true;
  600. }
  601. return false;
  602. }
  603. bool CYouTubeSystem::GetUploadResults( YouTubeUploadHandle_t handle, bool &bSuccess, CUtlString &strURLToVideo, CUtlString &strURLToVideoStats )
  604. {
  605. AUTO_LOCK( m_Mutex );
  606. uploadstatus_t *pStatus = GetStatus( handle );
  607. if ( pStatus != NULL )
  608. {
  609. bSuccess = pStatus->bSuccess;
  610. strURLToVideo = pStatus->strURLToVideo;
  611. strURLToVideoStats = pStatus->strURLToVideoStats;
  612. return true;
  613. }
  614. return false;
  615. }
  616. void CYouTubeSystem::ClearUploadResults( YouTubeUploadHandle_t handle )
  617. {
  618. AUTO_LOCK( m_Mutex );
  619. if ( m_mapUploads.Remove( handle ) )
  620. {
  621. CYouTubeUploadJob *pJob = (CYouTubeUploadJob*)handle;
  622. pJob->Release();
  623. }
  624. }
  625. void CYouTubeSystem::CancelUpload( YouTubeUploadHandle_t handle )
  626. {
  627. AUTO_LOCK( m_Mutex );
  628. if ( m_mapUploads.Remove( handle ) )
  629. {
  630. CYouTubeUploadJob *pJob = (CYouTubeUploadJob*)handle;
  631. pJob->CancelUpload();
  632. pJob->Release();
  633. }
  634. }
  635. void CYouTubeSystem::SetUploadFinished( YouTubeUploadHandle_t handle, bool bSuccess, const char *pURLToVideo, const char *pURLToVideoStats )
  636. {
  637. AUTO_LOCK( m_Mutex );
  638. uploadstatus_t *pStatus = GetStatus( handle );
  639. if ( pStatus )
  640. {
  641. pStatus->bFinished = true;
  642. pStatus->bSuccess = bSuccess;
  643. pStatus->strURLToVideo = pURLToVideo;
  644. pStatus->strURLToVideoStats = pURLToVideoStats;
  645. }
  646. }
  647. void CYouTubeSystem::SetUserProfile( const char *pUserProfile )
  648. {
  649. AUTO_LOCK( m_Mutex );
  650. m_strUserProfile = pUserProfile;
  651. CUtlString author;
  652. GetStandardTagValue( "author", m_strUserProfile.Get(), author );
  653. GetStandardTagValue( "name", author.Get(), m_strYouTubeUserName );
  654. }
  655. YouTubeInfoHandle_t CYouTubeSystem::GetInfo( const char *pURLToVideoStats, CYouTubeResponseHandler &responseHandler )
  656. {
  657. AUTO_LOCK( m_Mutex );
  658. CYouTubeRetrieveInfoJob *pJob = new CYouTubeRetrieveInfoJob( this, pURLToVideoStats, responseHandler );
  659. m_pThreadPool->AddJob( pJob );
  660. m_vecRetrieveInfoJobs.AddToTail( pJob );
  661. return (YouTubeInfoHandle_t)pJob;
  662. }
  663. void CYouTubeSystem::CancelGetInfo( YouTubeInfoHandle_t handle )
  664. {
  665. AUTO_LOCK( m_Mutex );
  666. int idx = m_vecRetrieveInfoJobs.Find( (CYouTubeRetrieveInfoJob*)handle );
  667. if ( idx >= 0 && idx < m_vecRetrieveInfoJobs.Count() )
  668. {
  669. ((CYouTubeRetrieveInfoJob*)handle)->Release();
  670. m_vecRetrieveInfoJobs.FastRemove( idx );
  671. }
  672. }
  673. void CYouTubeSystem::SetDeveloperSettings( const char *pDeveloperKey, const char *pDeveloperTag )
  674. {
  675. AUTO_LOCK( m_Mutex );
  676. m_strDeveloperKey = pDeveloperKey;
  677. m_strDeveloperTag = pDeveloperTag;
  678. }
  679. const char *CYouTubeSystem::GetDeveloperKey() const
  680. {
  681. AUTO_LOCK( m_Mutex );
  682. return m_strDeveloperKey.Get();
  683. }
  684. const char *CYouTubeSystem::GetDeveloperTag() const
  685. {
  686. AUTO_LOCK( m_Mutex );
  687. return m_strDeveloperTag.Get();
  688. }
  689. const char *CYouTubeSystem::GetLoginName() const
  690. {
  691. return m_strYouTubeUserName.Get();
  692. }
  693. eYouTubeLoginStatus CYouTubeSystem::GetLoginStatus() const
  694. {
  695. return m_eLoginStatus;
  696. }
  697. bool CYouTubeSystem::GetProfileURL( CUtlString &strProfileURL ) const
  698. {
  699. if ( m_eLoginStatus == kYouTubeLogin_LoggedIn )
  700. {
  701. strProfileURL = CFmtStr1024( "http://www.youtube.com/profile?user=%s", m_strYouTubeUserName.Get() );
  702. return true;
  703. }
  704. return false;
  705. }
  706. void CYouTubeSystem::SetLoginStatus( eYouTubeLoginStatus status )
  707. {
  708. AUTO_LOCK( m_Mutex );
  709. m_eLoginStatus = status;
  710. if ( m_eLoginStatus == kYouTubeLogin_LoggedIn )
  711. {
  712. CYouTubeRetrieveUserProfile *pJob = new CYouTubeRetrieveUserProfile( this );
  713. m_pThreadPool->AddJob( pJob );
  714. pJob->Release();
  715. }
  716. }
  717. void CYouTubeSystem::SetAuthToken( const char *pAuthToken )
  718. {
  719. AUTO_LOCK( m_Mutex );
  720. m_strAuthToken = pAuthToken;
  721. }
  722. const char* CYouTubeSystem::GetAuthToken() const
  723. {
  724. AUTO_LOCK( m_Mutex );
  725. return m_strAuthToken.Get();
  726. }
  727. //=============================================================================
  728. // Public API
  729. void YouTube_SetDeveloperSettings( const char *pDeveloperKey, const char *pDeveloperTag )
  730. {
  731. gYouTube.SetDeveloperSettings( pDeveloperKey, pDeveloperTag );
  732. }
  733. void YouTube_Login( const char *pUserName, const char *pPassword, const char *pSource )
  734. {
  735. if ( gYouTube.GetLoginStatus() == kYouTubeLogin_LoggedIn )
  736. {
  737. return;
  738. }
  739. gYouTube.Login( pUserName, pPassword, pSource );
  740. }
  741. void YouTube_LoginCancel()
  742. {
  743. gYouTube.LoginCancel();
  744. }
  745. const char *YouTube_GetLoginName()
  746. {
  747. return gYouTube.GetLoginName();
  748. }
  749. eYouTubeLoginStatus YouTube_GetLoginStatus()
  750. {
  751. return gYouTube.GetLoginStatus();
  752. }
  753. bool YouTube_GetProfileURL( CUtlString &strProfileURL )
  754. {
  755. return gYouTube.GetProfileURL( strProfileURL );
  756. }
  757. YouTubeUploadHandle_t YouTube_Upload( const char* pFilePath, const char *pMimeType, const char *pTitle, const char *pDescription, const char *pCategory, const char *pKeywords, eYouTubeAccessControl access )
  758. {
  759. return gYouTube.Upload( pFilePath, pMimeType, pTitle, pDescription, pCategory, pKeywords, access );
  760. }
  761. bool YouTube_IsUploadFinished( YouTubeUploadHandle_t handle )
  762. {
  763. return gYouTube.IsUploadFinished( handle );
  764. }
  765. bool YouTube_GetUploadProgress( YouTubeUploadHandle_t handle, double &ultotal, double &ulnow )
  766. {
  767. return gYouTube.GetUploadProgress( handle, ultotal, ulnow );
  768. }
  769. bool YouTube_GetUploadResults( YouTubeUploadHandle_t handle, bool &bSuccess, CUtlString &strURLToVideo, CUtlString &strURLToVideoStats )
  770. {
  771. return gYouTube.GetUploadResults( handle, bSuccess, strURLToVideo, strURLToVideoStats );
  772. }
  773. void YouTube_ClearUploadResults( YouTubeUploadHandle_t handle )
  774. {
  775. gYouTube.ClearUploadResults( handle );
  776. }
  777. void YouTube_CancelUpload( YouTubeUploadHandle_t handle )
  778. {
  779. gYouTube.CancelUpload( handle );
  780. }
  781. YouTubeInfoHandle_t YouTube_GetVideoInfo( const char *pURLToVideoStats, CYouTubeResponseHandler &responseHandler )
  782. {
  783. return gYouTube.GetInfo( pURLToVideoStats, responseHandler );
  784. }
  785. void YouTube_CancelGetVideoInfo( YouTubeInfoHandle_t handle )
  786. {
  787. gYouTube.CancelGetInfo( handle );
  788. }