diff --git a/ArtAPI/ArtAPI.csproj b/ArtAPI/ArtAPI.csproj index 01774f4..a20d0b1 100644 --- a/ArtAPI/ArtAPI.csproj +++ b/ArtAPI/ArtAPI.csproj @@ -12,4 +12,8 @@ + + + + diff --git a/ArtAPI/ArtStationAPI.cs b/ArtAPI/ArtStationAPI.cs index 498e27f..2948520 100644 --- a/ArtAPI/ArtStationAPI.cs +++ b/ArtAPI/ArtStationAPI.cs @@ -20,11 +20,6 @@ public override async Task CheckArtistExistsAsync(string artistName) return response.IsSuccessStatusCode; } - public override async Task GetImagesAsync(string artistUrl) - { - await GetImagesAsync(new Uri(artistUrl)).ConfigureAwait(false); - } - public override async Task GetImagesAsync(Uri artistUrl) { OnDownloadStateChanged(new DownloadStateChangedEventArgs(State.DownloadPreparing)); @@ -32,6 +27,7 @@ public override async Task GetImagesAsync(Uri artistUrl) if (artistname == null) return; CreateSaveDir(artistname); await GetImagesMetadataAsync(string.Format(ApiUrl, artistname)).ConfigureAwait(false); + await DownloadImagesAsync().ConfigureAwait(false); } protected override async Task GetImagesMetadataAsync(string apiUrl) @@ -60,7 +56,6 @@ protected override async Task GetImagesMetadataAsync(string apiUrl) try { await t.ConfigureAwait(false); } catch (Exception e) { OnDownloadStateChanged(new DownloadStateChangedEventArgs(State.DownloadCanceled, e.Message)); return; } - await DownloadImagesAsync().ConfigureAwait(false); } // get all the images from a project diff --git a/ArtAPI/DeviantArtAPI.cs b/ArtAPI/DeviantArtAPI.cs new file mode 100644 index 0000000..7af61f3 --- /dev/null +++ b/ArtAPI/DeviantArtAPI.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; + +namespace ArtAPI +{ + public sealed class DeviantArtAPI : RequestArt + { + private const string + ClientID = "12774", + ClientSecret = "597114f315705b9624c7c1d74ad729e1", + AUTH_URL = "https://www.deviantart.com/oauth2/token", + GALLERY_URL = "https://www.deviantart.com/api/v1/oauth2/gallery/all?mature_content=true&limit=20&username={0}&offset="; + + private const int Offset = 20; + + public bool IsLoggedIn { get; private set; } + + public override Uri CreateUrlFromName(string artistName) + { + return new Uri($"https://www.deviantart.com/{artistName}"); + } + + public override async Task CheckArtistExistsAsync(string artistName) + { + var response = await Client.GetAsync($"https://www.deviantart.com/{artistName}"); + return response.IsSuccessStatusCode; + } + + public override async Task GetImagesAsync(Uri artistUrl) + { + if (!IsLoggedIn) + { + OnDownloadStateChanged(new DownloadStateChangedEventArgs(State.DownloadCanceled, "not logged in")); + return; + } + OnDownloadStateChanged(new DownloadStateChangedEventArgs(State.DownloadPreparing)); + var artistName = artistUrl?.AbsolutePath.Split('/')[1]; + if (artistName == null) return; + CreateSaveDir(artistName); + await GetImagesMetadataAsync(string.Format(GALLERY_URL, artistName)).ConfigureAwait(false); + await DownloadImagesAsync().ConfigureAwait(false); + } + + protected override async Task GetImagesMetadataAsync(string apiUrl) + { + var paginationOffset = 0; + while (true) + { + var rawResponse = await Client.GetStringAsync(apiUrl + paginationOffset).ConfigureAwait(false); + var responseJson = JObject.Parse(rawResponse); + var Gallery = (JContainer)responseJson["results"]; + if (!(Gallery.HasValues)) return; // check if the user has any images in his gallery + foreach (var image in Gallery) + { + if (image["content"] == null) continue; + ImagesToDownload.Add(new ImageModel() + { + Url = image["content"]["src"].ToString(), + Name = image["title"].ToString(), + ID = image["deviationid"].ToString() + } + ); + } + if (responseJson["has_more"].ToString() == "False") return; + paginationOffset += Offset; + } + } + + public override async Task auth(string refreshToken) + { + var data = new Dictionary() + { + {"grant_type", "client_credentials" }, + {"client_id", ClientID}, + {"client_secret", ClientSecret} + }; + using var content = new FormUrlEncodedContent(data); + try + { + var response = await Client.PostAsync(AUTH_URL, content).ConfigureAwait(false); + var jsonResponse = JObject.Parse(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); + if (jsonResponse["status"].ToString() == "error") return false; + Client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jsonResponse["access_token"]}"); + } + catch(HttpRequestException) + { + return false; + } + return IsLoggedIn = true; + } + } +} diff --git a/ArtAPI/PixivAPI.cs b/ArtAPI/PixivAPI.cs index c307723..5941710 100644 --- a/ArtAPI/PixivAPI.cs +++ b/ArtAPI/PixivAPI.cs @@ -56,11 +56,6 @@ private async Task GetArtistName(string artistID) return JObject.Parse(response)["body"]["user_details"]["user_name"].ToString(); } - public override async Task GetImagesAsync(string ArtistUrl) - { - await GetImagesAsync(new Uri(ArtistUrl)).ConfigureAwait(false); - } - public override async Task GetImagesAsync(Uri artistUrl) { OnDownloadStateChanged(new DownloadStateChangedEventArgs(State.DownloadPreparing)); @@ -75,6 +70,7 @@ public override async Task GetImagesAsync(Uri artistUrl) { await GetImagesMetadataAsync(string.Format(APIUrlWithoutLogin, artistID)).ConfigureAwait(false); } + await DownloadImagesAsync().ConfigureAwait(false); } protected override async Task GetImagesMetadataAsync(string apiUrl) @@ -114,7 +110,6 @@ await GetImageURLsWithoutLoginAsync(string.Format(IllustProjectUrl, illust_id)) { OnDownloadStateChanged(new DownloadStateChangedEventArgs(State.DownloadCanceled, e.Message)); } - await DownloadImagesAsync().ConfigureAwait(false); } private async Task GetImageURLsWithoutLoginAsync(string illustProject) diff --git a/Artify/Artify.csproj b/Artify/Artify.csproj index 2563bbc..9b65bec 100644 --- a/Artify/Artify.csproj +++ b/Artify/Artify.csproj @@ -7,6 +7,11 @@ assets/icons/artify.ico + + + + + @@ -17,7 +22,6 @@ - @@ -26,7 +30,8 @@ - + + diff --git a/Artify/Models/ArtifyModel.cs b/Artify/Models/ArtifyModel.cs index 60df505..cfff7e1 100644 --- a/Artify/Models/ArtifyModel.cs +++ b/Artify/Models/ArtifyModel.cs @@ -27,13 +27,15 @@ public class ArtifyModel { {"general", new Regex(@"(https?://)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}(\/?[a-zA-Z0-9]*\/?)*") }, {"artstation", new Regex(@"(https://)?(www\.)?artstation\.com/[0-9a-zA-Z]+/?") }, - {"pixiv", new Regex(@"(https://)?(www\.)?pixiv\.net/[a-z]{0,6}/users/[0-9]+/?") } + {"pixiv", new Regex(@"(https://)?(www\.)?pixiv\.net/[a-z]{0,6}/users/[0-9]+/?") }, + {"deviantart", new Regex(@"(https://)?(www\.)?deviantart\.com/[0-9a-zA-Z]+/?")} }; // container for the classes private readonly Dictionary> ArtPlatform = new Dictionary>() { { "artstation", () => new ArtStationAPI() }, - { "pixiv", () => new PixivAPI() } + { "pixiv", () => new PixivAPI() }, + { "deviantart", () => new DeviantArtAPI()} }; public IRequestArt Platform { diff --git a/Artify/Views/MainView.xaml b/Artify/Views/MainView.xaml index 5ef0f79..359f05b 100644 --- a/Artify/Views/MainView.xaml +++ b/Artify/Views/MainView.xaml @@ -94,11 +94,14 @@ @@ -117,7 +120,10 @@ +