Last active
January 25, 2023 21:15
-
-
Save emrahgunduz/5c3a8bbc2ef846a43ba68ac96a47c485 to your computer and use it in GitHub Desktop.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// (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(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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