Web Image Downloader For Unreal Engine 4 -- Do not forget to change the include and API key in your own classs, if you simply copy-pasting this.
// (c) 2016 Markakod | |
#include "HitMe.h" | |
#include "WebImageDownloader.h" | |
UWebImageDownloader* UWebImageDownloader::GetWebImageDownloader(FString WebImageName, FString URL, bool& IsValid) | |
{ | |
IsValid = false; | |
UWebImageDownloader *Object = NewObject<UWebImageDownloader>(); | |
if (!Object) { | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::GetWebImageDownloader] Could not be created")); | |
return NULL; | |
} | |
if (!Object->IsValidLowLevel()) { | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::GetWebImageDownloader] Created object is not valid")); | |
return NULL; | |
} | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::GetWebImageDownloader] An instance is created successfully")); | |
Object->OriginalWebImageName = FString(WebImageName); | |
Object->OriginalURL = FString(URL); | |
IsValid = true; | |
return Object; | |
} | |
FString UWebImageDownloader::WebImageFolder() | |
{ | |
FString FileDir = FPaths::GamePersistentDownloadDir() + "/Image/"; | |
FPaths::NormalizeDirectoryName(FileDir); | |
return FString(FPaths::ConvertRelativePathToFull(FileDir)); | |
} | |
bool UWebImageDownloader::CreateWebImageFolder() | |
{ | |
FDirWebImageRecursiveDownloader RFolder = FDirWebImageRecursiveDownloader::CreateLambda([=](FString Folder) | |
{ | |
const int32 MAX_LOOP_ITR = 3000; | |
FPaths::NormalizeDirectoryName(Folder); | |
Folder += "/"; | |
FString Base; | |
FString Left; | |
FString Remaining; | |
Folder.Split(TEXT("/"), &Base, &Remaining); | |
Base += "/"; | |
int32 LoopItr = 0; | |
while (Remaining != "" && LoopItr < MAX_LOOP_ITR) | |
{ | |
Remaining.Split(TEXT("/"), &Left, &Remaining); | |
Base += Left + FString("/"); | |
FPlatformFileManager::Get().GetPlatformFile().CreateDirectory(*Base); | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::CreateWebImageFolder] Creating %s"), *Base); | |
LoopItr++; | |
} | |
}); | |
FString FileDir = WebImageFolder(); | |
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); | |
if (!PlatformFile.DirectoryExists(*FileDir)) { | |
RFolder.Execute(FileDir); | |
if (!PlatformFile.DirectoryExists(*FileDir)) { | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::CreateWebImageFolder] Cannot create folder %s"), *FileDir); | |
return false; | |
} | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::CreateWebImageFolder] Created folder %s"), *FileDir); | |
} | |
return true; | |
} | |
TArray<FString> UWebImageDownloader::DownloadedWebImagesList() | |
{ | |
FString folder = WebImageFolder() + "/*.*"; | |
IFileManager& FileManager = IFileManager::Get(); | |
TArray<FString>files; | |
FileManager.FindFiles(files, *folder, true, false); | |
for (int i = 0; i < files.Num(); i++) { | |
FString str = files[i]; | |
files[i] = str.Replace(TEXT(".jpg"), TEXT(""), ESearchCase::IgnoreCase); | |
} | |
return files; | |
} | |
void UWebImageDownloader::IsWebImageDownloaded(FString WebImageName, bool& isDownloaded) | |
{ | |
if (!CreateWebImageFolder()) | |
{ | |
isDownloaded = false; | |
return; | |
} | |
FString dataFile = WebImageFolder() + "/" + WebImageName + ".jpg"; | |
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); | |
isDownloaded = PlatformFile.FileExists(*dataFile); | |
} | |
void UWebImageDownloader::DeleteWebImageFile(FString WebImageName, bool &isDeleted) | |
{ | |
FString dataFile = WebImageFolder() + "/" + WebImageName + ".jpg"; | |
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); | |
if (!PlatformFile.FileExists(*dataFile)) | |
{ | |
isDeleted = true; | |
return; | |
} | |
isDeleted = PlatformFile.DeleteFile(*dataFile); | |
} | |
void UWebImageDownloader::CheckIfWebImageHasUpdate() | |
{ | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::DoesWebImageHaveUpdate] Checking for update %s"), *OriginalWebImageName); | |
FString dataFile = WebImageFolder() + "/" + OriginalWebImageName + ".jpg"; | |
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); | |
if (!PlatformFile.FileExists(*dataFile)) | |
{ | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::DoesWebImageHaveUpdate] WebImage not downloaded yet %s"), *OriginalWebImageName); | |
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, true); | |
return; | |
} | |
RequestSize = -1; | |
RequestUrl = OriginalURL + "/" + OriginalWebImageName + ".jpg"; | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::DoesWebImageHaveUpdate] Requesting headers for %s from %s"), *OriginalWebImageName, *RequestUrl); | |
FHttpModule* Http = &FHttpModule::Get(); | |
TSharedRef<IHttpRequest> HttpRequest = Http->CreateRequest(); | |
UpdateRequest = HttpRequest; | |
HttpRequest->SetVerb(TEXT("HEAD")); | |
HttpRequest->SetURL(RequestUrl); | |
HttpRequest->OnProcessRequestComplete().BindUObject(this, &UWebImageDownloader::UpdateCheckHttpRequestComplete); | |
if (!HttpRequest->ProcessRequest()) | |
{ | |
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, false); | |
} | |
} | |
void UWebImageDownloader::UpdateCheckHttpRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful) | |
{ | |
UpdateRequest.Reset(); | |
if (!Response.IsValid()) { | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] Could not connect to %s"), *RequestUrl); | |
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, false); | |
return; | |
} | |
if (!bWasSuccessful) { | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] Could not connect to %s"), *RequestUrl); | |
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, false); | |
return; | |
} | |
FString dataFile = WebImageFolder() + "/" + OriginalWebImageName + ".jpg"; | |
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); | |
FFileStatData statData = PlatformFile.GetStatData(*dataFile); | |
bool isSizeDifferent = false; | |
bool isModDateDifferent = false; | |
int64 fileSize = 0; | |
int64 modDate = 0; | |
{ | |
int32 StatusCode = Response->GetResponseCode(); | |
if (StatusCode / 100 != 2) | |
{ | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] %s HTTP response %d, for %s"), *OriginalWebImageName, StatusCode, *RequestUrl); | |
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, false); | |
return; | |
} | |
TArray<FString> headers = Response->GetAllHeaders(); | |
for (FString h : headers) { | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] %s Header: %s"), *OriginalWebImageName, *h); | |
} | |
for (FString h : headers) { | |
if (h.Contains("x-file-size", ESearchCase::IgnoreCase) || h.Contains("Content-Length", ESearchCase::IgnoreCase)) { | |
FString left; | |
FString right; | |
h.Split(":", &left, &right, ESearchCase::IgnoreCase, ESearchDir::FromStart); | |
if (right.Len()) | |
{ | |
fileSize = FCString::Atoi(*right); | |
} | |
} | |
if (h.Contains("x-file-mod", ESearchCase::IgnoreCase)) { | |
FString left; | |
FString right; | |
h.Split(":", &left, &right, ESearchCase::IgnoreCase, ESearchDir::FromStart); | |
if (right.Len()) | |
{ | |
modDate = FCString::Atoi(*right); | |
} | |
} | |
if (h.Contains("Last-Modified", ESearchCase::IgnoreCase)) { | |
FString left; | |
FString right; | |
h.Split(":", &left, &right, ESearchCase::IgnoreCase, ESearchDir::FromStart); | |
if (right.Len()) | |
{ | |
right = right.Trim().TrimTrailing(); | |
FDateTime date; | |
FDateTime::ParseHttpDate(right, date); | |
modDate = date.ToUnixTimestamp(); | |
} | |
} | |
} | |
Request.Reset(); | |
} | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] %s - REMOTE: File size %i Mod date %i"), *OriginalWebImageName, fileSize, modDate); | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] %s - LOCAL: File size %i Mod date %i"), *OriginalWebImageName, statData.FileSize, statData.ModificationTime.ToUnixTimestamp()); | |
isSizeDifferent = fileSize > 0 && statData.FileSize != fileSize; | |
isModDateDifferent = modDate > 0 && modDate > statData.ModificationTime.ToUnixTimestamp(); | |
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, isSizeDifferent || isModDateDifferent); | |
} | |
void UWebImageDownloader::DownloadWebImage() | |
{ | |
CreateWebImageFolder(); | |
RequestSize = -1; | |
RequestUrl = OriginalURL + "/" + OriginalWebImageName + ".jpg"; | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::DownloadWebImage] %s Requesting headers for %s"), *OriginalWebImageName, *RequestUrl); | |
FHttpModule* Http = &FHttpModule::Get(); | |
TSharedRef<IHttpRequest> HttpRequest = Http->CreateRequest(); | |
DownloadRequest = HttpRequest; | |
HttpRequest->SetVerb(TEXT("HEAD")); | |
HttpRequest->SetURL(RequestUrl); | |
HttpRequest->OnProcessRequestComplete().BindUObject(this, &UWebImageDownloader::HttpRequestComplete); | |
if (!HttpRequest->ProcessRequest()) | |
{ | |
OnWebImageDownloadError.Broadcast(OriginalWebImageName); | |
} | |
} | |
void UWebImageDownloader::HttpRequestProgress(FHttpRequestPtr Request, int32 bytesSent, int32 bytesReceived) | |
{ | |
if (RequestSize <= 0) return; | |
float percent = (float)bytesReceived / (float)RequestSize; | |
OnWebImageDownloadProgress.Broadcast(OriginalWebImageName, (int32)(percent * 100)); | |
} | |
void UWebImageDownloader::HttpRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful) | |
{ | |
DownloadRequest.Reset(); | |
if (!Response.IsValid()) { | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpRequestComplete] Could not connect to %s"), *RequestUrl); | |
OnWebImageDownloadError.Broadcast(OriginalWebImageName); | |
return; | |
} | |
if (!bWasSuccessful) { | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpRequestComplete] Could not connect to %s"), *RequestUrl); | |
OnWebImageDownloadError.Broadcast(OriginalWebImageName); | |
return; | |
} | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::HttpRequestComplete] %s Starting download of %s"), *OriginalWebImageName, *RequestUrl); | |
// Finding size of the requested file | |
{ | |
int32 StatusCode = Response->GetResponseCode(); | |
if (StatusCode / 100 != 2) | |
{ | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpRequestComplete] %s HTTP response %d, for %s"), *OriginalWebImageName, StatusCode, *RequestUrl); | |
OnWebImageDownloadError.Broadcast(OriginalWebImageName); | |
return; | |
} | |
TArray<FString> headers = Response->GetAllHeaders(); | |
for (FString h : headers) { | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::HttpRequestComplete] %s Header: %s"), *OriginalWebImageName, *h); | |
} | |
for (FString h : headers) { | |
if (h.Contains("x-file-size", ESearchCase::IgnoreCase) || h.Contains("Content-Length", ESearchCase::IgnoreCase)) { | |
FString left; | |
FString right; | |
h.Split(":", &left, &right, ESearchCase::IgnoreCase, ESearchDir::FromStart); | |
if (right.Len()) | |
{ | |
RequestSize = FCString::Atoi(*right); | |
} | |
break; | |
} | |
} | |
Request.Reset(); | |
} | |
FHttpModule* Http = &FHttpModule::Get(); | |
TSharedRef<IHttpRequest> HttpRequest = Http->CreateRequest(); | |
DownloadRequest = HttpRequest; | |
HttpRequest->SetVerb(TEXT("GET")); | |
HttpRequest->SetURL(RequestUrl); | |
HttpRequest->OnRequestProgress().BindUObject(this, &UWebImageDownloader::HttpRequestProgress); | |
HttpRequest->OnProcessRequestComplete().BindUObject(this, &UWebImageDownloader::HttpDownloadComplete); | |
if (!HttpRequest->ProcessRequest()) | |
{ | |
OnWebImageDownloadError.Broadcast(OriginalWebImageName); | |
} | |
} | |
void UWebImageDownloader::HttpDownloadComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful) | |
{ | |
DownloadRequest.Reset(); | |
if (!Response.IsValid()) { | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpDownloadComplete] Could not connect to %s"), *RequestUrl); | |
OnWebImageDownloadError.Broadcast(OriginalWebImageName); | |
return; | |
} | |
if (!bWasSuccessful) { | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpDownloadComplete] Could not connect to %s"), *RequestUrl); | |
OnWebImageDownloadError.Broadcast(OriginalWebImageName); | |
return; | |
} | |
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::HttpDownloadComplete] Download completed for %s from %s"), *OriginalWebImageName, *RequestUrl); | |
int32 StatusCode = Response->GetResponseCode(); | |
if (StatusCode / 100 != 2) | |
{ | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpDownloadComplete] %s HTTP response %d, for %s"), *OriginalWebImageName, StatusCode, *RequestUrl); | |
OnWebImageDownloadError.Broadcast(OriginalWebImageName); | |
return; | |
} | |
TArray<FString> headers = Response->GetAllHeaders(); | |
for (FString h : headers) { | |
UE_LOG(HITMELOG, Warning, TEXT("UExpoSocket::HttpDownloadComplete] %s Header: %s"), *OriginalWebImageName, *h); | |
} | |
const TArray<uint8>& Content = Response->GetContent(); | |
FString Filename = WebImageFolder() + "/" + OriginalWebImageName + ".jpg"; | |
if (FFileHelper::SaveArrayToFile(Content, *Filename)) | |
{ | |
OnWebImageDownloadCompleted.Broadcast(OriginalWebImageName); | |
} | |
else | |
{ | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpDownloadComplete] %s Could not write %s to disk "), *OriginalWebImageName, *Filename); | |
OnWebImageDownloadError.Broadcast(OriginalWebImageName); | |
} | |
} | |
void UWebImageDownloader::CancelDownload() | |
{ | |
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::CancelDownload] Cancelling request for %s"), *RequestUrl); | |
if (UpdateRequest.IsValid()) { | |
if (UpdateRequest->OnProcessRequestComplete().IsBound()) | |
UpdateRequest->OnProcessRequestComplete().Unbind(); | |
UpdateRequest->CancelRequest(); | |
UpdateRequest.Reset(); | |
} | |
if (DownloadRequest.IsValid()) { | |
if (DownloadRequest->OnProcessRequestComplete().IsBound()) | |
DownloadRequest->OnProcessRequestComplete().Unbind(); | |
DownloadRequest->CancelRequest(); | |
DownloadRequest.Reset(); | |
} | |
} |
#pragma once | |
#include "Object.h" | |
#include "Runtime/Online/HTTP/Public/Http.h" | |
#include "Runtime/Online/HTTP/Public/HttpManager.h" | |
#include "WebImageDownloader.generated.h" | |
DECLARE_DELEGATE_OneParam(FDirWebImageRecursiveDownloader, FString); | |
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWebImageDownloader_OnDownloadComplete, FString, imageName); | |
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWebImageDownloader_OnDownloadError, FString, imageName); | |
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FWebImageDownloader_OnDownloadProgress, FString, imageName, int32, progress); | |
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FWebImageDownloader_OnUpdateCheckCompleted, FString, imageName, bool, hasUpdate); | |
UCLASS(Blueprintable, BlueprintType) | |
class HITME_API UWebImageDownloader : public UObject | |
{ | |
GENERATED_BODY() | |
public: | |
UFUNCTION(BlueprintPure, Category = "WebImage Downloader", Meta = (DisplayName = "Get A Web Image Downloader")) | |
static UWebImageDownloader* GetWebImageDownloader(FString WebImageName, FString URL, bool& IsValid); | |
UFUNCTION(BlueprintPure, Category = "WebImage Downloader", Meta = (DisplayName = "Downloaded Web Images List")) | |
static TArray<FString> DownloadedWebImagesList(); | |
UFUNCTION(BlueprintPure, Category = "WebImage Downloader", Meta = (DisplayName = "Delete Web Image File")) | |
static void DeleteWebImageFile(FString WebImageName, bool &isDeleted); | |
UFUNCTION(BlueprintPure, Category = "WebImage Downloader", Meta = (DisplayName = "Is Web Image Already Downloaded")) | |
static void IsWebImageDownloaded(FString WebImageName, bool &isDownloaded); | |
UPROPERTY(BlueprintAssignable, Category = "WebImage Downloader") | |
FWebImageDownloader_OnDownloadComplete OnWebImageDownloadCompleted; | |
UPROPERTY(BlueprintAssignable, Category = "WebImage Downloader") | |
FWebImageDownloader_OnDownloadError OnWebImageDownloadError; | |
UPROPERTY(BlueprintAssignable, Category = "WebImage Downloader") | |
FWebImageDownloader_OnDownloadProgress OnWebImageDownloadProgress; | |
UPROPERTY(BlueprintAssignable, Category = "WebImage Downloader") | |
FWebImageDownloader_OnUpdateCheckCompleted OnUpdateCheckCompleted; | |
UFUNCTION(BlueprintCallable, Category = "WebImage Downloader", Meta = (DisplayName = "Does Web Image Have Update")) | |
void CheckIfWebImageHasUpdate(); | |
UFUNCTION(BlueprintCallable, Category = "WebImage Downloader", Meta = (DisplayName = "Download Web Image")) | |
void DownloadWebImage(); | |
UFUNCTION(BlueprintCallable, Category = "WebImage Downloader", Meta = (DisplayName = "Cancel Download")) | |
void CancelDownload(); | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "WebImage Downloader", Meta = (DisplayName = "Web Image Name")) | |
FString OriginalWebImageName; | |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "WebImage Downloader", Meta = (DisplayName = "Server URL")) | |
FString OriginalURL; | |
static FString WebImageFolder(); | |
static bool CreateWebImageFolder(); | |
private: | |
void HttpRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful); | |
void HttpDownloadComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful); | |
void HttpRequestProgress(FHttpRequestPtr Request, int32 bytesSent, int32 bytesReceived); | |
void UpdateCheckHttpRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful); | |
int32 RequestSize; | |
FString RequestUrl; | |
TSharedPtr<IHttpRequest> UpdateRequest; | |
TSharedPtr<IHttpRequest> DownloadRequest; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment