diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/youtubeapi.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/client/youtubeapi.cpp')
| -rw-r--r-- | game/client/youtubeapi.cpp | 931 |
1 files changed, 931 insertions, 0 deletions
diff --git a/game/client/youtubeapi.cpp b/game/client/youtubeapi.cpp new file mode 100644 index 0000000..c104221 --- /dev/null +++ b/game/client/youtubeapi.cpp @@ -0,0 +1,931 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if defined( WIN32 ) && !defined( _X360 ) +#include "winlite.h" +#include <WinInet.h> +#endif + +#include "youtubeapi.h" + +#include "platform.h" +#include "convar.h" +#include "fmtstr.h" +#include "igamesystem.h" +#include "strtools.h" +#include "cdll_util.h" +#include "utlmap.h" +#include "utlstring.h" +#include "vstdlib/jobthread.h" +#include <steam/steam_api.h> +#include <steam/isteamhttp.h> +#include "cdll_client_int.h" +#include "utlbuffer.h" +#include "filesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//============================================================================= + +static ConVar youtube_http_proxy( "youtube_http_proxy", "", FCVAR_ARCHIVE, "HTTP proxy. Specify if you have have problems uploading to YouTube." ); + +//============================================================================= + +static bool GetStandardTagValue( const char *pTag, const char *pXML, CUtlString &strResult ) +{ + const char *pStart = strstr( pXML, pTag ); + if ( pStart != NULL ) + { + pStart = strstr( pStart, ">" ); + if ( pStart != NULL ) + { + pStart += 1; + const char *pEnd = strstr( pStart, CFmtStr1024( "</%s", pTag ) ); + if ( pEnd != NULL ) + { + strResult.SetDirect( pStart, pEnd - pStart ); + return true; + } + } + } + return false; +} + +//============================================================================= + +class CYouTubeRetrieveInfoJob; + +namespace +{ + class CYouTubeSystem : public CAutoGameSystemPerFrame + { + public: + + CYouTubeSystem(); + ~CYouTubeSystem(); + + // CAutoGameSystem + virtual bool Init(); + virtual void PostInit(); + virtual void Shutdown(); + virtual bool IsPerFrame() { return true; } + virtual void Update( float frametime ); + + void Login( const char *pUserName, const char *pPassword, const char *pSource ); + void LoginCancel(); + YouTubeUploadHandle_t Upload( const char* pFilePath, const char *pMimeType, const char *pTitle, const char *pDescription, const char *pCategory, const char *pKeywords, eYouTubeAccessControl access ); + + bool IsUploadFinished( YouTubeUploadHandle_t handle ); + bool GetUploadProgress( YouTubeUploadHandle_t handle, double &ultotal, double &ulnow ); + bool GetUploadResults( YouTubeUploadHandle_t handle, bool &bSuccess, CUtlString &strURLToVideo, CUtlString &strURLToVideoStats ); + void ClearUploadResults( YouTubeUploadHandle_t handle ); + void CancelUpload( YouTubeUploadHandle_t handle ); + void SetUploadFinished( YouTubeUploadHandle_t handle, bool bSuccess, const char *pURLToVideo, const char *pURLToVideoStats ); + + void SetUserProfile( const char *pUserProfile ); + bool GetProfileURL( CUtlString &strProfileURL ) const; + + YouTubeInfoHandle_t GetInfo( const char *pURLToVideoStats, CYouTubeResponseHandler &responseHandler ); + void CancelGetInfo( YouTubeInfoHandle_t handle ); + + const char *GetDeveloperKey() const; + const char *GetDeveloperTag() const; + void SetDeveloperSettings( const char *pDeveloperKey, const char *pDeveloperTag ); + + const char *GetLoginName() const; + eYouTubeLoginStatus GetLoginStatus() const; + void SetLoginStatus( eYouTubeLoginStatus status ); + + const char* GetAuthToken() const; + void SetAuthToken( const char *pAuthToken ); + + private: + struct uploadstatus_t + { + bool bFinished; + bool bSuccess; + CUtlString strURLToVideo; + CUtlString strURLToVideoStats; + }; + + uploadstatus_t *GetStatus( YouTubeUploadHandle_t handle ); + + eYouTubeLoginStatus m_eLoginStatus; + CUtlString m_strYouTubeUserName; + CUtlString m_strDeveloperKey; + CUtlString m_strDeveloperTag; + CUtlString m_strAuthToken; + CUtlString m_strUserProfile; + CThreadMutex m_Mutex; + IThreadPool* m_pThreadPool; + CUtlMap< YouTubeUploadHandle_t, uploadstatus_t > m_mapUploads; + CUtlVector< CYouTubeRetrieveInfoJob * > m_vecRetrieveInfoJobs; + }; +}; + +static CYouTubeSystem gYouTube; + +static ISteamHTTP *GetISteamHTTP() +{ + if ( steamapicontext != NULL && steamapicontext->SteamHTTP() ) + { + return steamapicontext->SteamHTTP(); + } +#ifndef CLIENT_DLL + if ( steamgameserverapicontext != NULL ) + { + return steamgameserverapicontext->SteamHTTP(); + } +#endif + return NULL; +} + +//============================================================================= + +// Base class for all YouTube jobs +class CYouTubeJob : public CJob +{ +public: + CYouTubeJob( CYouTubeSystem *pSystem ) + { + SetFlags( JF_IO ); + // store local ones so we don't have to go through a mutex + m_strDeveloperKey = pSystem->GetDeveloperKey(); + m_strDeveloperTag = pSystem->GetDeveloperTag(); + } + + virtual ~CYouTubeJob() + { + } + + void CancelUpload() + { + m_bCancelled = true; + } + + bool IsCancelled() const + { + return m_bCancelled; + } + + +protected: + void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam, bool bIOFailure ) + { + m_bHTTPRequestPending = false; + if ( (!m_bAllowRequestFailure && pParam->m_eStatusCode != k_EHTTPStatusCode200OK) || bIOFailure || !pParam->m_bRequestSuccessful ) + { + Warning( "Failed to get youtube url: HTTP status %d fetching %s\n", pParam->m_eStatusCode, m_sURL.String() ); + } + else + { + OnHTTPRequestCompleted( pParam ); + } + } + + virtual void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam ) { Assert( false ); } + + void DoRequest( HTTPRequestHandle hRequest, const char *pchRequestURL ) + { + m_sURL = pchRequestURL; + + SteamAPICall_t hSteamAPICall; + if ( GetISteamHTTP()->SendHTTPRequest( hRequest, &hSteamAPICall ) ) + { + m_HTTPRequestCompleted.Set( hSteamAPICall, this, &CYouTubeJob::OnHTTPRequestCompleted ); + } + + // Wait for it to finish. + while ( m_bHTTPRequestPending && !m_bCancelled ) + { + ThreadSleep( 100 ); + } + + GetISteamHTTP()->ReleaseHTTPRequest( hSteamAPICall ); + } + + + CCallResult<CYouTubeJob, HTTPRequestCompleted_t> m_HTTPRequestCompleted; + + CUtlString m_strDeveloperKey; + CUtlString m_strDeveloperTag; + CUtlString m_sURL; + CUtlString m_strResponse; + bool m_bHTTPRequestPending = true; + bool m_bAllowRequestFailure = false; + bool m_bCancelled = false; +}; + +//============================================================================= + +class CYouTubeRetrieveUserProfile : public CYouTubeJob +{ +public: + CYouTubeRetrieveUserProfile( CYouTubeSystem *pSystem ) + : CYouTubeJob( pSystem ) + { + } + +private: + void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam ) OVERRIDE + { + uint32 unBodySize; + if ( !GetISteamHTTP()->GetHTTPResponseBodySize( pParam->m_hRequest, &unBodySize ) ) + { + Assert( false ); + } + else + { + m_strResponse.SetLength( unBodySize ); + + if ( GetISteamHTTP()->GetHTTPResponseBodyData( pParam->m_hRequest, (uint8*)m_strResponse.String(), unBodySize ) ) + { + gYouTube.SetUserProfile( m_strResponse.Get() ); + } + } + } + + virtual JobStatus_t DoExecute() + { + HTTPRequestHandle hRequest = GetISteamHTTP()->CreateHTTPRequest( k_EHTTPMethodGET, "http://gdata.youtube.com/feeds/api/users/default" ); + GetISteamHTTP()->SetHTTPRequestNetworkActivityTimeout( hRequest, 30 ); + GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "Authorization", CFmtStr1024( "GoogleLogin auth=%s", gYouTube.GetAuthToken() ) ); + + DoRequest( hRequest, "http://gdata.youtube.com/feeds/api/users/default" ); + + return JOB_OK; + } +}; + +//============================================================================= + +class CYouTubeRetrieveInfoJob : public CYouTubeJob +{ +public: + CYouTubeRetrieveInfoJob( CYouTubeSystem *pSystem, const char *pVideoURL, CYouTubeResponseHandler &responseHandler ) + : CYouTubeJob( pSystem ) + , m_strURL( pVideoURL ) + , m_responseHandler( responseHandler ) + { + } + + void NotifyResponseHandler() + { + m_responseHandler.HandleResponse( 200, m_strResponse.Get() ); + } + +private: + void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam ) OVERRIDE + { + uint32 unBodySize; + if ( !GetISteamHTTP()->GetHTTPResponseBodySize( pParam->m_hRequest, &unBodySize ) ) + { + Assert( false ); + } + else + { + m_strResponse.SetLength( unBodySize ); + GetISteamHTTP()->GetHTTPResponseBodyData( pParam->m_hRequest, (uint8*)m_strResponse.String(), unBodySize ); + } + } + + virtual JobStatus_t DoExecute() + { + HTTPRequestHandle hRequest = GetISteamHTTP()->CreateHTTPRequest( k_EHTTPMethodGET, m_strURL.Get() ); + GetISteamHTTP()->SetHTTPRequestNetworkActivityTimeout( hRequest, 30 ); + + DoRequest( hRequest, m_strURL.Get() ); + + return JOB_OK; + } + + // data + CUtlString m_strURL; + CYouTubeResponseHandler &m_responseHandler; +}; + +class CYouTubeLoginJob : public CYouTubeJob +{ +public: + CYouTubeLoginJob( CYouTubeSystem *pSystem, const char *pUserName, const char *pPassword, const char *pSource ) + : CYouTubeJob( pSystem ) + , m_strUserName( pUserName ) + , m_strPassword( pPassword ) + , m_strSource( pSource ) + { + } + +private: + + void SetLoginResults( const char *pLoginResults ) + { + const char *pStart = strstr( pLoginResults, "Auth=" ); + if ( pStart != NULL ) + { + pStart += strlen( "Auth=" ); + const char *pEnd = strstr( pStart, "\r\n" ); + if ( pEnd == NULL ) + { + pEnd = strstr( pStart, "\n" ); + } + CUtlString strAuthToken; + if ( pEnd != NULL ) + { + strAuthToken.SetDirect( pStart, pEnd - pStart ); + } + else + { + strAuthToken.SetDirect( pStart, strlen( pStart ) ); + } + gYouTube.SetAuthToken( strAuthToken.Get() ); + } + } + + void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam ) OVERRIDE + { + eYouTubeLoginStatus loginStatus = kYouTubeLogin_LoggedIn; + + if ( pParam->m_eStatusCode == 403 ) + { + loginStatus = kYouTubeLogin_Forbidden; + } + else if ( pParam->m_eStatusCode != 200 ) + { + loginStatus = kYouTubeLogin_GenericFailure; + } + else + { + uint32 unBodySize; + if ( !GetISteamHTTP()->GetHTTPResponseBodySize( pParam->m_hRequest, &unBodySize ) ) + { + Assert( false ); + } + else + { + m_strResponse.SetLength( unBodySize ); + if ( GetISteamHTTP()->GetHTTPResponseBodyData( pParam->m_hRequest, (uint8*)m_strResponse.String(), unBodySize ) ) + { + SetLoginResults( m_strResponse ); + } + } + } + + gYouTube.SetLoginStatus( loginStatus ); + + } + + virtual JobStatus_t DoExecute() + { + m_bAllowRequestFailure = true; + + HTTPRequestHandle hRequest = GetISteamHTTP()->CreateHTTPRequest( k_EHTTPMethodPOST, "https://www.google.com/accounts/ClientLogin" ); + GetISteamHTTP()->SetHTTPRequestNetworkActivityTimeout( hRequest, 30 ); + + // GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "Content-Type", "application/x-www-form-urlencoded" ); + GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "X-GData-Key", CFmtStr1024( "key=%s", m_strDeveloperKey.Get() ) ); + + char szUserNameEncoded[256]; + char szPasswordEncoded[256]; + char szSourceEncoded[256]; + Q_URLEncode( szUserNameEncoded, sizeof( szUserNameEncoded ), m_strUserName.Get(), m_strUserName.Length() ); + Q_URLEncode( szPasswordEncoded, sizeof( szPasswordEncoded ), m_strPassword.Get(), m_strPassword.Length() ); + Q_URLEncode( szSourceEncoded, sizeof( szSourceEncoded ), m_strSource.Get(), m_strSource.Length() ); + + CFmtStr1024 data( "Email=%s&Passwd=%s&service=youtube&source=%s", szUserNameEncoded, szPasswordEncoded, szSourceEncoded ); + + GetISteamHTTP()->SetHTTPRequestRawPostBody( hRequest, "application/x-www-form-urlencoded", (uint8 *)data.Access(), data.Length() ); + + DoRequest( hRequest, "https://www.google.com/accounts/ClientLogin" ); + + return JOB_OK; + } + + // data + CUtlString m_strUserName; + CUtlString m_strPassword; + CUtlString m_strSource; +}; + +// Job for uploading a file +class CYouTubeUploadJob : public CYouTubeJob +{ +public: + CYouTubeUploadJob( CYouTubeSystem *pSystem, const char* pFilePath, const char *pMimeType, const char *pTitle, const char *pDescription, const char *pCategory, const char *pKeywords, eYouTubeAccessControl access ) + : CYouTubeJob( pSystem ) + , m_strFilePath( pFilePath ) + , m_strMimeType( pMimeType ) + , m_strTitle( pTitle ) + , m_strDesc( pDescription ) + , m_strCategory( pCategory ) + , m_strKeywords( pKeywords ) + , m_eAccess( access ) + { + } + + void GetProgress( double &ultotal, double &ulnow ) + { + ultotal = 0; + ulnow = 0; + } + +private: + + virtual JobStatus_t DoExecute() + { + m_bAllowRequestFailure = true; + + HTTPRequestHandle hRequest = GetISteamHTTP()->CreateHTTPRequest( k_EHTTPMethodPUT, "http://uploads.gdata.youtube.com/feeds/api/users/default/uploads" ); + GetISteamHTTP()->SetHTTPRequestNetworkActivityTimeout( hRequest, 30 ); + + const char *pFileName = Q_UnqualifiedFileName( m_strFilePath.Get() ); + + GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "Authorization", CFmtStr1024( "GoogleLogin auth=%s", gYouTube.GetAuthToken() ) ); + GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "X-GData-Key", CFmtStr1024( "key=%s", m_strDeveloperKey.Get() ) ); + GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "GData-Version", "2" ); + //GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "Content-Type", "multipart/form-data;boundary=-x" ); + GetISteamHTTP()->SetHTTPRequestHeaderValue( hRequest, "Slug", CFmtStr1024( "%s", pFileName ) ); + + const char *pPrivateString = ""; + const char *pAccessControlString = ""; + + switch ( m_eAccess ) + { + case kYouTubeAccessControl_Public: + break; + case kYouTubeAccessControl_Private: + pPrivateString = "<yt:private/>"; + break; + case kYouTubeAccessControl_Unlisted: + pAccessControlString = "<yt:accessControl action=\"list\" permission=\"denied\"/>"; + break; + } + + CFmtStr1024 strAPIRequest( "<?xml version=\"1.0\"?>" + "<entry " + "xmlns=\"http://www.w3.org/2005/Atom\" " + "xmlns:media=\"http://search.yahoo.com/mrss/\" " + "xmlns:yt=\"http://gdata.youtube.com/schemas/2007\">" + "<media:group>" + "<media:title type=\"plain\">%s</media:title>" + "<media:description type=\"plain\">%s</media:description>" + "<media:category scheme=\"http://gdata.youtube.com/schemas/2007/categories.cat\">" + "%s" + "</media:category>" + "%s" + "<media:keywords>%s</media:keywords>" + "<media:category scheme=\"http://gdata.youtube.com/schemas/2007/developertags.cat\">" + "%s" + "</media:category>" + "</media:group>" + "%s" + "</entry>", + m_strTitle.Get(), + m_strDesc.Get(), + m_strCategory.Get(), + pPrivateString, + m_strKeywords.Get(), + m_strDeveloperTag.Get(), + pAccessControlString ); + + CFmtStr1024 fmtstrBody( + "\r\nContent-Type: application/atom+xml; charset=UTF-8\r\n" + "\r\n---x\r\nContent-Disposition: form-data; name=\"apirequest\"\r\n\r\n%s" + "\r\n---x\r\nContent-Disposition: form-data; name=\"video\"\r\nContent-Type: %s\r\nContent-Transfer-Encoding: binary\r\n\r\n", + strAPIRequest.Access(), m_strMimeType.Get() + ); + + CUtlBuffer postDataRaw( 0, 0, 0 ); + + postDataRaw.Put( fmtstrBody.Access(), fmtstrBody.Length() ); + + CUtlBuffer fileData( 0, 0, 0 ); + bool bReadFileOK = g_pFullFileSystem->ReadFile( m_strFilePath, nullptr, fileData ); + + if ( bReadFileOK ) + { + postDataRaw.Put( fileData.Base(), fileData.TellPut() ); + + fileData.Clear(); + + static const char rgchFooter[] = "\r\n---x--\r\n"; + + postDataRaw.Put( rgchFooter, V_strlen( rgchFooter ) ); + + GetISteamHTTP()->SetHTTPRequestRawPostBody( hRequest, "multipart/form-data;boundary=-x", (uint8 *)postDataRaw.Base(), postDataRaw.TellPut() ); + + // BUGBUG: use SendHTTPRequestAndStreamResponse + DoRequest( hRequest, "http://uploads.gdata.youtube.com/feeds/api/users/default/uploads" ); + } + + return JOB_OK; + } + + void OnHTTPRequestCompleted( HTTPRequestCompleted_t *pParam ) OVERRIDE + { + bool bSuccess = false; + + CUtlString strURLToVideoStats; + CUtlString strURLToVideo; + + if ( pParam->m_eStatusCode == 200 ) + { + bSuccess = true; + + uint32 unBodySize; + if ( !GetISteamHTTP()->GetHTTPResponseBodySize( pParam->m_hRequest, &unBodySize ) ) + { + Assert( false ); + } + else + { + m_strResponse.SetLength( unBodySize ); + if ( GetISteamHTTP()->GetHTTPResponseBodyData( pParam->m_hRequest, (uint8*)m_strResponse.String(), unBodySize ) ) + { + // @note Tom Bui: wish I had an xml parser... + { + strURLToVideo = ""; + // "<link rel='alternate' type='text/html' href='http://www.youtube.com/watch?v=7D4pb3irM_0&feature=youtube_gdata' /> "; + const char *kLinkStartTag = "<link rel='alternate' type='text/html' href='"; + const char *kLinkTagEnd = "'/>"; + const char *pStart = strstr( m_strResponse.Get(), kLinkStartTag ); + if ( pStart != NULL ) + { + pStart += strlen( kLinkStartTag ); + const char *pEnd = strstr( pStart, kLinkTagEnd ); + if ( pEnd != NULL ) + { + strURLToVideo.SetDirect( pStart, pEnd - pStart ); + } + } + } + { + strURLToVideoStats = ""; + // "<link rel='self' type='text/html' href='http://www.youtube.com/watch?v=7D4pb3irM_0&feature=youtube_gdata' /> "; + const char *kLinkStartTag = "<link rel='self' type='application/atom+xml' href='"; + const char *kLinkTagEnd = "'/>"; + const char *pStart = strstr( m_strResponse.Get(), kLinkStartTag ); + if ( pStart != NULL ) + { + pStart += strlen( kLinkStartTag ); + const char *pEnd = strstr( pStart, kLinkTagEnd ); + if ( pEnd != NULL ) + { + strURLToVideoStats.SetDirect( pStart, pEnd - pStart ); + // @note Tom Bui: we want at least version 2 + if ( V_strstr( strURLToVideoStats.Get(), "?v=" ) == NULL ) + { + strURLToVideoStats += "?v=2"; + } + } + } + } + } + } + } + + gYouTube.SetUploadFinished( (YouTubeUploadHandle_t)this, bSuccess, strURLToVideo.Get(), strURLToVideoStats.Get() ); + } + + // data + CUtlString m_strFilePath; + CUtlString m_strMimeType; + CUtlString m_strTitle; + CUtlString m_strDesc; + CUtlString m_strCategory; + CUtlString m_strKeywords; + eYouTubeAccessControl m_eAccess; +}; + +//============================================================================= + +CYouTubeSystem::CYouTubeSystem() + : m_eLoginStatus( kYouTubeLogin_NotLoggedIn ) + , m_pThreadPool( NULL ) + , m_mapUploads( DefLessFunc( YouTubeUploadHandle_t ) ) +{ +} + +CYouTubeSystem::~CYouTubeSystem() +{ +} + +bool CYouTubeSystem::Init() +{ + m_pThreadPool = CreateThreadPool(); + m_pThreadPool->Start( ThreadPoolStartParams_t( false, 4 ), "YouTubeSystem" ); + return true; +} + +void CYouTubeSystem::PostInit() +{ +} + +void CYouTubeSystem::Shutdown() +{ + DestroyThreadPool( m_pThreadPool ); + m_pThreadPool = NULL; +} + +void CYouTubeSystem::Update( float frametime ) +{ + AUTO_LOCK( m_Mutex ); + FOR_EACH_VEC( m_vecRetrieveInfoJobs, i ) + { + CYouTubeRetrieveInfoJob *pJob = m_vecRetrieveInfoJobs[i]; + if ( pJob->IsFinished() ) + { + pJob->NotifyResponseHandler(); + // cleanup the job + pJob->Release(); + // and remove + m_vecRetrieveInfoJobs.FastRemove( i ); + } + else + { + ++i; + } + } +} + +void CYouTubeSystem::Login( const char *pUserName, const char *pPassword, const char *pSource ) +{ + m_eLoginStatus = kYouTubeLogin_NotLoggedIn; + CYouTubeLoginJob *pJob = new CYouTubeLoginJob( this, pUserName, pPassword, pSource ); + m_pThreadPool->AddJob( pJob ); + pJob->Release(); +} + +void CYouTubeSystem::LoginCancel() +{ + m_eLoginStatus = kYouTubeLogin_Cancelled; +} + +YouTubeUploadHandle_t CYouTubeSystem::Upload( const char* pFilePath, const char *pMimeType, const char *pTitle, const char *pDescription, const char *pCategory, const char *pKeywords, eYouTubeAccessControl access ) +{ + if ( m_eLoginStatus != kYouTubeLogin_LoggedIn ) + { + return NULL; + } + CYouTubeUploadJob *pJob = new CYouTubeUploadJob( this, pFilePath, pMimeType, pTitle, pDescription, pCategory, pKeywords, access ); + m_pThreadPool->AddJob( pJob ); + uploadstatus_t status = { false, false, "", "" }; + m_mapUploads.Insert( (YouTubeUploadHandle_t)pJob, status ); + return (YouTubeUploadHandle_t)pJob; +} + +CYouTubeSystem::uploadstatus_t *CYouTubeSystem::GetStatus( YouTubeUploadHandle_t handle ) +{ + int idx = m_mapUploads.Find( handle ); + if ( m_mapUploads.IsValidIndex( idx ) ) + { + return &m_mapUploads[idx]; + } + return NULL; +} + +bool CYouTubeSystem::IsUploadFinished( YouTubeUploadHandle_t handle ) +{ + AUTO_LOCK( m_Mutex ); + uploadstatus_t *pStatus = GetStatus( handle ); + if ( pStatus != NULL ) + { + return pStatus->bFinished; + } + return true; +} + +bool CYouTubeSystem::GetUploadProgress( YouTubeUploadHandle_t handle, double &ultotal, double &ulnow ) +{ + AUTO_LOCK( m_Mutex ); + uploadstatus_t *pStatus = GetStatus( handle ); + if ( pStatus != NULL ) + { + CYouTubeUploadJob *pJob = (CYouTubeUploadJob*)handle; + pJob->GetProgress( ultotal, ulnow ); + return true; + } + return false; +} + +bool CYouTubeSystem::GetUploadResults( YouTubeUploadHandle_t handle, bool &bSuccess, CUtlString &strURLToVideo, CUtlString &strURLToVideoStats ) +{ + AUTO_LOCK( m_Mutex ); + uploadstatus_t *pStatus = GetStatus( handle ); + if ( pStatus != NULL ) + { + bSuccess = pStatus->bSuccess; + strURLToVideo = pStatus->strURLToVideo; + strURLToVideoStats = pStatus->strURLToVideoStats; + return true; + } + return false; +} + +void CYouTubeSystem::ClearUploadResults( YouTubeUploadHandle_t handle ) +{ + AUTO_LOCK( m_Mutex ); + if ( m_mapUploads.Remove( handle ) ) + { + CYouTubeUploadJob *pJob = (CYouTubeUploadJob*)handle; + pJob->Release(); + } +} + +void CYouTubeSystem::CancelUpload( YouTubeUploadHandle_t handle ) +{ + AUTO_LOCK( m_Mutex ); + if ( m_mapUploads.Remove( handle ) ) + { + CYouTubeUploadJob *pJob = (CYouTubeUploadJob*)handle; + pJob->CancelUpload(); + pJob->Release(); + } +} + +void CYouTubeSystem::SetUploadFinished( YouTubeUploadHandle_t handle, bool bSuccess, const char *pURLToVideo, const char *pURLToVideoStats ) +{ + AUTO_LOCK( m_Mutex ); + uploadstatus_t *pStatus = GetStatus( handle ); + if ( pStatus ) + { + pStatus->bFinished = true; + pStatus->bSuccess = bSuccess; + pStatus->strURLToVideo = pURLToVideo; + pStatus->strURLToVideoStats = pURLToVideoStats; + } +} + +void CYouTubeSystem::SetUserProfile( const char *pUserProfile ) +{ + AUTO_LOCK( m_Mutex ); + m_strUserProfile = pUserProfile; + CUtlString author; + GetStandardTagValue( "author", m_strUserProfile.Get(), author ); + GetStandardTagValue( "name", author.Get(), m_strYouTubeUserName ); +} + +YouTubeInfoHandle_t CYouTubeSystem::GetInfo( const char *pURLToVideoStats, CYouTubeResponseHandler &responseHandler ) +{ + AUTO_LOCK( m_Mutex ); + CYouTubeRetrieveInfoJob *pJob = new CYouTubeRetrieveInfoJob( this, pURLToVideoStats, responseHandler ); + m_pThreadPool->AddJob( pJob ); + m_vecRetrieveInfoJobs.AddToTail( pJob ); + return (YouTubeInfoHandle_t)pJob; +} + +void CYouTubeSystem::CancelGetInfo( YouTubeInfoHandle_t handle ) +{ + AUTO_LOCK( m_Mutex ); + int idx = m_vecRetrieveInfoJobs.Find( (CYouTubeRetrieveInfoJob*)handle ); + if ( idx >= 0 && idx < m_vecRetrieveInfoJobs.Count() ) + { + ((CYouTubeRetrieveInfoJob*)handle)->Release(); + m_vecRetrieveInfoJobs.FastRemove( idx ); + } +} + +void CYouTubeSystem::SetDeveloperSettings( const char *pDeveloperKey, const char *pDeveloperTag ) +{ + AUTO_LOCK( m_Mutex ); + m_strDeveloperKey = pDeveloperKey; + m_strDeveloperTag = pDeveloperTag; +} + +const char *CYouTubeSystem::GetDeveloperKey() const +{ + AUTO_LOCK( m_Mutex ); + return m_strDeveloperKey.Get(); +} + +const char *CYouTubeSystem::GetDeveloperTag() const +{ + AUTO_LOCK( m_Mutex ); + return m_strDeveloperTag.Get(); +} + +const char *CYouTubeSystem::GetLoginName() const +{ + return m_strYouTubeUserName.Get(); +} + +eYouTubeLoginStatus CYouTubeSystem::GetLoginStatus() const +{ + return m_eLoginStatus; +} + +bool CYouTubeSystem::GetProfileURL( CUtlString &strProfileURL ) const +{ + if ( m_eLoginStatus == kYouTubeLogin_LoggedIn ) + { + strProfileURL = CFmtStr1024( "http://www.youtube.com/profile?user=%s", m_strYouTubeUserName.Get() ); + return true; + } + return false; +} + +void CYouTubeSystem::SetLoginStatus( eYouTubeLoginStatus status ) +{ + AUTO_LOCK( m_Mutex ); + m_eLoginStatus = status; + if ( m_eLoginStatus == kYouTubeLogin_LoggedIn ) + { + CYouTubeRetrieveUserProfile *pJob = new CYouTubeRetrieveUserProfile( this ); + m_pThreadPool->AddJob( pJob ); + pJob->Release(); + } +} + +void CYouTubeSystem::SetAuthToken( const char *pAuthToken ) +{ + AUTO_LOCK( m_Mutex ); + m_strAuthToken = pAuthToken; +} + +const char* CYouTubeSystem::GetAuthToken() const +{ + AUTO_LOCK( m_Mutex ); + return m_strAuthToken.Get(); +} + +//============================================================================= +// Public API + +void YouTube_SetDeveloperSettings( const char *pDeveloperKey, const char *pDeveloperTag ) +{ + gYouTube.SetDeveloperSettings( pDeveloperKey, pDeveloperTag ); +} + +void YouTube_Login( const char *pUserName, const char *pPassword, const char *pSource ) +{ + if ( gYouTube.GetLoginStatus() == kYouTubeLogin_LoggedIn ) + { + return; + } + gYouTube.Login( pUserName, pPassword, pSource ); +} + +void YouTube_LoginCancel() +{ + gYouTube.LoginCancel(); +} + +const char *YouTube_GetLoginName() +{ + return gYouTube.GetLoginName(); +} + +eYouTubeLoginStatus YouTube_GetLoginStatus() +{ + return gYouTube.GetLoginStatus(); +} + +bool YouTube_GetProfileURL( CUtlString &strProfileURL ) +{ + return gYouTube.GetProfileURL( strProfileURL ); +} + +YouTubeUploadHandle_t YouTube_Upload( const char* pFilePath, const char *pMimeType, const char *pTitle, const char *pDescription, const char *pCategory, const char *pKeywords, eYouTubeAccessControl access ) +{ + return gYouTube.Upload( pFilePath, pMimeType, pTitle, pDescription, pCategory, pKeywords, access ); +} + +bool YouTube_IsUploadFinished( YouTubeUploadHandle_t handle ) +{ + return gYouTube.IsUploadFinished( handle ); +} + +bool YouTube_GetUploadProgress( YouTubeUploadHandle_t handle, double &ultotal, double &ulnow ) +{ + return gYouTube.GetUploadProgress( handle, ultotal, ulnow ); +} + +bool YouTube_GetUploadResults( YouTubeUploadHandle_t handle, bool &bSuccess, CUtlString &strURLToVideo, CUtlString &strURLToVideoStats ) +{ + return gYouTube.GetUploadResults( handle, bSuccess, strURLToVideo, strURLToVideoStats ); +} + +void YouTube_ClearUploadResults( YouTubeUploadHandle_t handle ) +{ + gYouTube.ClearUploadResults( handle ); +} + +void YouTube_CancelUpload( YouTubeUploadHandle_t handle ) +{ + gYouTube.CancelUpload( handle ); +} + +YouTubeInfoHandle_t YouTube_GetVideoInfo( const char *pURLToVideoStats, CYouTubeResponseHandler &responseHandler ) +{ + return gYouTube.GetInfo( pURLToVideoStats, responseHandler ); +} + +void YouTube_CancelGetVideoInfo( YouTubeInfoHandle_t handle ) +{ + gYouTube.CancelGetInfo( handle ); +} |