C#:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
namespace Oxide.Plugins
{
[Info("Imgur API", "MJSU", "1.0.2")]
[Description("Allows plugins to upload images to imgur")]
internal class ImgurApi : CovalencePlugin
{
#region Class Fields
private PluginConfig _pluginConfig; //Plugin Config
private const string ClientIdUrl = "https://api.imgur.com/oauth2/addclient";
private const string UploadImageUrl = "https://api.imgur.com/3/upload";
private const string DeleteImageUrl = "https://api.imgur.com/3/image/{0}";
private const string CreateAlbumUrl = "https://api.imgur.com/3/album";
private const string DeleteAlbumUrl = "https://api.imgur.com/3/album/{0}";
private const string AlbumLink = "https://imgur.com/a/{0}";
private GameObject _go;
private ImgurBehavior _behavior;
#endregion
#region Setup & Loading
protected override void LoadDefaultConfig()
{
PrintWarning("Loading Default Config");
}
protected override void LoadConfig()
{
base.LoadConfig();
Config.Settings.DefaultValueHandling = DefaultValueHandling.Populate;
_pluginConfig = AdditionalConfig(Config.ReadObject<PluginConfig>());
Config.WriteObject(_pluginConfig);
}
private PluginConfig AdditionalConfig(PluginConfig config)
{
return config;
}
private void OnServerInitialized()
{
_go = new GameObject();
_behavior = _go.AddComponent<ImgurBehavior>();
}
private void Unload()
{
_behavior.StopAllCoroutines();
GameObject.Destroy(_go);
}
#endregion
#region API
private void UploadImage(byte[] image, Action<Hash<string, object>> callback, string title = null, string description = null)
{
if (_pluginConfig.ClientId == ClientIdUrl)
{
PrintError($"Please set your Imgur Client Id in the config!");
return;
}
_behavior.StartCoroutine(HandleUploadImage(image, response =>
{
callback(response.ToHash());
}, title, description));
}
private void DeleteSingleImage(string deleteHash, Action<Hash<string, object>> callback)
{
if (_pluginConfig.ClientId == ClientIdUrl)
{
PrintError($"Please set your Imgur Client Id in the config!");
return;
}
_behavior.StartCoroutine(HandleDeleteSingleImage(deleteHash, callback));
}
private void UploadAlbum(List<Hash<string, object>> images, Action<Hash<string, Hash<string, object>>> callback, string title = null, string description = null)
{
if (_pluginConfig.ClientId == ClientIdUrl)
{
PrintError($"Please set your Imgur Client Id in the config!");
return;
}
_behavior.StartCoroutine(HandleUploadAlbum(images, callback, title, description));
}
private void DeleteAlbum(string deleteHash, Action<Hash<string, object>> callback)
{
if (_pluginConfig.ClientId == ClientIdUrl)
{
PrintError($"Please set your Imgur Client Id in the config!");
return;
}
_behavior.StartCoroutine(HandleDeleteAlbum(deleteHash, callback));
}
#endregion
#region Handlers
private IEnumerator HandleUploadImage(byte[] image, Action<ApiResponse<UploadResponse>> callback, string title, string description)
{
List<IMultipartFormSection> data = new List<IMultipartFormSection>
{
new MultipartFormDataSection("image", Convert.ToBase64String(image)),
new MultipartFormDataSection("type", "base64")
};
if (!string.IsNullOrEmpty(title))
{
data.Add(new MultipartFormDataSection("title", title));
}
if (!string.IsNullOrEmpty(description))
{
data.Add(new MultipartFormDataSection("description", description));
}
yield return HandleImgurRequest(UploadImageUrl, data, callback);
}
private IEnumerator HandleDeleteSingleImage(string deleteHash, Action<Hash<string, object>> callback)
{
yield return HandleImgurRequest<bool>(string.Format(DeleteImageUrl, deleteHash), new List<IMultipartFormSection>(), response =>
{
callback(response.ToHash());
});
}
private IEnumerator HandleUploadAlbum(List<Hash<string, object>> images, Action<Hash<string, Hash<string, object>>> callback, string title = null, string description = null)
{
List<ApiResponse<UploadResponse>> albumImages = new List<ApiResponse<UploadResponse>>();
foreach (Hash<string, object> uploadData in images)
{
byte[] image = uploadData["Image"] as byte[];
string imageTitle = uploadData["Title"] as string;
string imageDescription = uploadData["Description"] as string;
yield return HandleUploadImage(image, img =>
{
albumImages.Add(img);
}, imageTitle, imageDescription);
yield return new WaitForSeconds(1);
}
List<IMultipartFormSection> data = albumImages.Where(a => a.Success).Select(response => new MultipartFormDataSection("deletehashes[]", response.Data.DeleteHash)).Cast<IMultipartFormSection>().ToList();
if (!string.IsNullOrEmpty(title))
{
data.Add(new MultipartFormDataSection("title", title));
}
if (!string.IsNullOrEmpty(description))
{
data.Add(new MultipartFormDataSection("description", description));
}
data.Add(new MultipartFormDataSection("type", "base64"));
yield return HandleImgurRequest<AlbumResponse>(CreateAlbumUrl, data, response =>
{
Hash<string, Hash<string, object>> album = new Hash<string, Hash<string, object>>
{
["Album"] = response.ToHash()
};
for (int index = 0; index < albumImages.Count; index++)
{
ApiResponse<UploadResponse> image = albumImages[index];
album[$"Image{index}"] = image.ToHash();
}
callback(album);
});
}
private IEnumerator HandleDeleteAlbum(string deleteHash, Action<Hash<string, object>> callback)
{
yield return HandleImgurRequest<bool>(string.Format(DeleteAlbumUrl, deleteHash), new List<IMultipartFormSection>(), response =>
{
callback(response.ToHash());
});
}
#endregion
#region Send Methods
private IEnumerator HandleImgurRequest<T>(string url, List<IMultipartFormSection> data, Action<ApiResponse<T>> action)
{
UnityWebRequest www = UnityWebRequest.Post(url, data);
www.SetRequestHeader("Authorization", $"Client-ID {_pluginConfig.ClientId}");
yield return www.SendWebRequest();
ApiResponse<T> response;
if (www.isNetworkError || www.isHttpError)
{
response = new ApiResponse<T>
{
Success = false,
Status = (int) www.responseCode,
Errors = new[] {new ErrorMessage {Detail = www.error}}
};
}
else
{
response = JsonConvert.DeserializeObject<ApiResponse<T>>(www.downloadHandler.text);
}
action(response);
}
#endregion
#region Behavior
private class ImgurBehavior : MonoBehaviour
{
}
#endregion
#region Classes
private class PluginConfig
{
[DefaultValue(ClientIdUrl)]
[JsonProperty(PropertyName = "Imgur Client ID")]
public string ClientId { get; set; }
}
private class ApiResponse<T>
{
[JsonProperty(PropertyName = "status")]
public int Status { get; set; }
[JsonProperty(PropertyName = "success")]
public bool Success { get; set; }
[JsonProperty(PropertyName = "data")]
public T Data { get; set; }
[JsonProperty(PropertyName = "errors")]
public ErrorMessage[] Errors { get; set; }
public Hash<string, object> ToHash()
{
object data;
BaseDataResponse response = Data as BaseDataResponse;
if (response != null)
{
data = response.ToHash();
}
else
{
data = Data;
}
return new Hash<string, object>
{
[nameof(Status)] = Status,
[nameof(Success)] = Success,
[nameof(Data)] = data,
[nameof(Errors)] = Errors?.Select(e => e.ToHash()).ToList()
};
}
}
private class ErrorMessage
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "code")]
public string Code { get; set; }
[JsonProperty(PropertyName = "status")]
public string Status { get; set; }
[JsonProperty(PropertyName = "detail")]
public string Detail { get; set; }
public Hash<string, object> ToHash()
{
return new Hash<string, object>
{
[nameof(Id)] = Id,
[nameof(Code)] = Code,
[nameof(Status)] = Status,
[nameof(Detail)] = Detail
};
}
}
private abstract class BaseDataResponse
{
public abstract Hash<string, object> ToHash();
}
private class UploadResponse : BaseDataResponse
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "deletehash")]
public string DeleteHash { get; set; }
[JsonProperty(PropertyName = "link")]
public string Link { get; set; }
public override Hash<string, object> ToHash()
{
return new Hash<string, object>
{
[nameof(Id)] = Id,
[nameof(DeleteHash)] = DeleteHash,
[nameof(Link)] = Link
};
}
}
private class AlbumResponse : BaseDataResponse
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "deletehash")]
public string DeleteHash { get; set; }
public string Link => string.Format(AlbumLink, Id);
public override Hash<string, object> ToHash()
{
return new Hash<string, object>
{
[nameof(Id)] = Id,
[nameof(DeleteHash)] = DeleteHash,
[nameof(Link)] = Link
};
}
}
#endregion
}
}