Skip to content

Commit

Permalink
- Added search by name to PixivAPI
Browse files Browse the repository at this point in the history
(Now you can download illustrations by entering the name, ID or URL), search by name works only if you're logged in
  • Loading branch information
sentouki committed Jul 28, 2020
1 parent f626106 commit c75f5e3
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 41 deletions.
6 changes: 3 additions & 3 deletions ArtAPI/ArtStationAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ public sealed class ArtStationAPI : RequestArt
private const string ApiUrl = @"https://artstation.com/users/{0}/projects?page=";
private const string AssetsUrl = @"https://www.artstation.com/projects/{0}.json";

public override Uri CreateUrlFromName(string artistName)
public override Task<Uri> CreateUrlFromName(string artistName)
{
return new Uri(string.Format($@"https://www.artstation.com/{artistName}"));
return Task.FromResult(new Uri(string.Format($@"https://www.artstation.com/{artistName}")));
}
public override async Task<bool> CheckArtistExistsAsync(string artistName)
{
var response = await Client.GetAsync(CreateUrlFromName(artistName));
var response = await Client.GetAsync(await CreateUrlFromName(artistName));
return response.IsSuccessStatusCode;
}

Expand Down
4 changes: 2 additions & 2 deletions ArtAPI/DeviantArtAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ private const string

public bool IsLoggedIn { get; private set; }

public override Uri CreateUrlFromName(string artistName)
public override Task<Uri> CreateUrlFromName(string artistName)
{
return new Uri($"https://www.deviantart.com/{artistName}");
return Task.FromResult(new Uri($"https://www.deviantart.com/{artistName}"));
}

public override async Task<bool> CheckArtistExistsAsync(string artistName)
Expand Down
4 changes: 2 additions & 2 deletions ArtAPI/IRequestArt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public interface IRequestArt
/// </summary>
/// <param name="artistName">user name of an artist</param>
/// <returns>URL with which an API request can be created</returns>
Uri CreateUrlFromName(string artistName);
Task<Uri> CreateUrlFromName(string artistName);
void CancelDownload();
Task<bool> CheckArtistExistsAsync(string artistName);
Task<bool> auth(string refreshToken);
Expand Down Expand Up @@ -255,7 +255,7 @@ public virtual async Task GetImagesAsync(string artistUrl)
await GetImagesAsync(new Uri(artistUrl)).ConfigureAwait(false);
}
public abstract Task GetImagesAsync(Uri artistUrl);
public abstract Uri CreateUrlFromName(string artistName);
public abstract Task<Uri> CreateUrlFromName(string artistName);
public abstract Task<bool> CheckArtistExistsAsync(string artistName);
protected abstract Task GetImagesMetadataAsync(string apiUrl);
public virtual Task<bool> auth(string refreshToken) => Task.FromResult(true);
Expand Down
69 changes: 48 additions & 21 deletions ArtAPI/PixivAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,58 @@ namespace ArtAPI
{
public sealed class PixivAPI : RequestArt
{
const string AUTH_URL = @"https://oauth.secure.pixiv.net/auth/token";
const string LOGIN_SECRET = "28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c";
private const string APIUrlWithLogin = @"https://app-api.pixiv.net/v1/user/illusts?user_id={0}";
private const string APIUrlWithoutLogin = @"https://www.pixiv.net/touch/ajax/illust/user_illusts?user_id={0}"; // &offset= einbauen

/// <summary>
/// one project can contain multiple illustrations
/// </summary>
private const string IllustProjectUrl = @"https://www.pixiv.net/touch/ajax/illust/details?illust_id={0}";

private const string ArtistDetails = @"https://www.pixiv.net/touch/ajax/user/details?id={0}";
private const string
AUTH_URL = @"https://oauth.secure.pixiv.net/auth/token",
LOGIN_SECRET = "28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c",
APIUrlWithLogin = @"https://app-api.pixiv.net/v1/user/illusts?user_id={0}",
APIUrlWithoutLogin = @"https://www.pixiv.net/touch/ajax/illust/user_illusts?user_id={0}",
UserSearchUrl = @"https://app-api.pixiv.net/v1/search/user?word={0}",
IllustProjectUrl = @"https://www.pixiv.net/touch/ajax/illust/details?illust_id={0}", // one project can contain multiple illustrations
ArtistDetails = @"https://www.pixiv.net/touch/ajax/user/details?id={0}";

private string _artistName;
public bool IsLoggedIn { get; private set; }

public string RefreshToken { get; private set; }

public PixivAPI()
{
Client.DefaultRequestHeaders.Referrer = new Uri("https://www.pixiv.net");
}

public override Uri CreateUrlFromName(string username)
public override async Task<Uri> CreateUrlFromName(string artistName)
{
if (int.TryParse(username, out _))
{
return CreateUrlFromID(username);
}
// NOTE: implement search for artist
return null;
// input may be an ID or a name, so we check first if it's an ID
if (int.TryParse(artistName, out _))
return CreateUrlFromID(artistName);
_artistName = artistName; // this will be needed later to create a directory, so we don't need to look up the name twice
return CreateUrlFromID(await GetArtistID(artistName));
}

public Uri CreateUrlFromID(string userid)
{
return new Uri($@"https://www.pixiv.net/en/users/{userid}");
}

public override async Task<bool> CheckArtistExistsAsync(string artistID)
public override async Task<bool> CheckArtistExistsAsync(string artist)
{
var response = await Client.GetAsync(string.Format(ArtistDetails, artistID))
if (!int.TryParse(artist, out _))
{
artist = await GetArtistID(artist);
}
var response = await Client.GetAsync(string.Format(ArtistDetails, artist))
.ConfigureAwait(false);
return response.IsSuccessStatusCode;
}
private async Task<string> GetArtistID(string artistName)
{
if (!IsLoggedIn) return null;
var response = await Client.GetStringAsync(string.Format(UserSearchUrl, artistName)).ConfigureAwait(false);
var searchResults = JObject.Parse(response);
if (!searchResults["user_previews"].HasValues) return null;
var artistID = searchResults["user_previews"][0]["user"]["id"].ToString();
return artistID;
}
private async Task<string> GetArtistName(string artistID)
{
var response = await Client.GetStringAsync(string.Format(ArtistDetails, artistID)).ConfigureAwait(false);
Expand All @@ -61,7 +72,13 @@ public override async Task GetImagesAsync(Uri artistUrl)
OnDownloadStateChanged(new DownloadStateChangedEventArgs(State.DownloadPreparing));
var artistID = artistUrl?.AbsolutePath.Split('/')[3];
if (artistID == null) return;
CreateSaveDir(await GetArtistName(artistID).ConfigureAwait(false));
if (_artistName is {})
{
CreateSaveDir(_artistName);
_artistName = null;
}
else
CreateSaveDir(await GetArtistName(artistID).ConfigureAwait(false));
if (IsLoggedIn)
{
await GetImagesMetadataAsync(string.Format(APIUrlWithLogin, artistID)).ConfigureAwait(false);
Expand Down Expand Up @@ -197,6 +214,11 @@ public override async Task<bool> auth(string refreshToken)
{"grant_type", "refresh_token" },
{"refresh_token", refreshToken },
};
if (Client.DefaultRequestHeaders.Contains("X-Client-Time"))
{
Client.DefaultRequestHeaders.Remove("X-Client-Time");
Client.DefaultRequestHeaders.Remove("X-Client-Hash");
}
Client.DefaultRequestHeaders.Add("X-Client-Time", clientTime);
Client.DefaultRequestHeaders.Add("X-Client-Hash", General.CreateMD5(clientTime + LOGIN_SECRET));
using var content = new FormUrlEncodedContent(data);
Expand Down Expand Up @@ -234,6 +256,11 @@ public override async Task<string> login(string username, string password)
{"username", username },
{"password", password }
};
if (Client.DefaultRequestHeaders.Contains("X-Client-Time"))
{
Client.DefaultRequestHeaders.Remove("X-Client-Time");
Client.DefaultRequestHeaders.Remove("X-Client-Hash");
}
Client.DefaultRequestHeaders.Add("X-Client-Time", clientTime);
Client.DefaultRequestHeaders.Add("X-Client-Hash", General.CreateMD5(clientTime + LOGIN_SECRET));
using var content = new FormUrlEncodedContent(data);
Expand Down
4 changes: 2 additions & 2 deletions Artify/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,12 @@

<!--#region input field Style -->
<Style x:Key="InputFieldStyle" TargetType="{x:Type TextBox}">
<EventSetter Event="TextChanged" Handler="InputField_OnTextChanged"/>
<Setter Property="Background" Value="#111111"/>
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="23"/>
<Setter Property="Height" Value="35"/>
<Setter Property="Margin" Value="5,0"/>
<Setter Property="ap:AttachedProperties.IsEmpty" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
Expand Down Expand Up @@ -414,7 +414,7 @@
<Border Name="input_border" Background="{TemplateBinding Background}" BorderBrush="#252525" BorderThickness="1" CornerRadius="3" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" VerticalContentAlignment="Center" Margin="1,1,0,0"/>
</Border>
<Border Name="input_border2" Background="Transparent" BorderBrush="#aaffa500" BorderThickness="1" CornerRadius="3" SnapsToDevicePixels="True" Opacity="0"/>
<Border Name="input_border2" Background="Transparent" BorderBrush="#aaffa500" BorderThickness="1" CornerRadius="3" SnapsToDevicePixels="True" Opacity="0" IsHitTestVisible="False"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
Expand Down
8 changes: 8 additions & 0 deletions Artify/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using Artify.Views.misc;

namespace Artify
{
Expand All @@ -12,5 +14,11 @@ private void Animation_OnCompleted(object sender, EventArgs e)
(sender as Storyboard)?.Remove();
GC.Collect();
}

private void InputField_OnTextChanged(object sender, TextChangedEventArgs e)
{
var inputfield = sender as TextBox;
AttachedProperties.SetIsEmpty(inputfield, string.IsNullOrEmpty(inputfield.Text));
}
}
}
6 changes: 5 additions & 1 deletion Artify/Models/ArtifyModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ public void UpdateSettings()
{
if (Platform == null) return;
settings.last_used_savepath = Platform.SavePath;
if (string.IsNullOrWhiteSpace(settings.pixiv_refresh_token))
{
settings.pixiv_refresh_token = null;
}
var fi = new FileInfo(SettingsFilePath) { Attributes = FileAttributes.Normal };
using (var sw = new StreamWriter(SettingsFilePath))
{
Expand Down Expand Up @@ -153,7 +157,7 @@ public void SelectPlatform(string platformName)
public async Task<bool> Auth()
{
if (_selectedPlatform != "pixiv") return await Platform.auth(null);
if (settings.pixiv_refresh_token is { } token)
if (settings.pixiv_refresh_token is { } token && !string.IsNullOrWhiteSpace(token))
{
return await Platform.auth(token);
}
Expand Down
2 changes: 1 addition & 1 deletion Artify/ViewModels/ArtifyViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ private async void RunDownload()
await artifyModel.Platform.GetImagesAsync(UserInput);
break;
case InputType.ArtistNameOrID:
await artifyModel.Platform.GetImagesAsync(artifyModel.Platform.CreateUrlFromName(UserInput));
await artifyModel.Platform.GetImagesAsync(await artifyModel.Platform.CreateUrlFromName(UserInput));
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion Artify/Views/MainView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox x:Name="UserInputField" Grid.RowSpan="2" MaxWidth="470" GotFocus="UserInputField_GotFocus"
Text="{Binding UserInput}" Tag="{Binding IsInputValid, Mode=TwoWay}" TextChanged="UserInputField_OnTextChanged">
Text="{Binding UserInput}" Tag="{Binding IsInputValid, Mode=TwoWay}">
<!-- #region DataTriggers -->
<TextBox.Style>
<Style BasedOn="{StaticResource InputFieldStyle}" TargetType="{x:Type TextBox}">
Expand Down
7 changes: 0 additions & 7 deletions Artify/Views/MainView.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;
using ArtAPI;
using Artify.ViewModels.misc;
using Artify.Views;
using Artify.Views.misc;

namespace Artify
{
Expand Down Expand Up @@ -123,11 +121,6 @@ private void UserInputField_GotFocus(object sender, RoutedEventArgs e)
UserInputField.Tag = true;
InputValidationLabel.Content = "";
}
private void UserInputField_OnTextChanged(object sender, TextChangedEventArgs e)
{
var inputfield = sender as TextBox;
AttachedProperties.SetIsEmpty(inputfield, string.IsNullOrEmpty(inputfield.Text));
}
private void HideSelectionMenuAnimation_Completed(object sender, EventArgs e)
{
SelectionMenu.Visibility = Visibility.Hidden;
Expand Down
2 changes: 1 addition & 1 deletion Artify/Views/misc/AttachedProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public static class AttachedProperties
typeof(AttachedProperties));
public static readonly DependencyProperty IsEmptyProperty = DependencyProperty.RegisterAttached("IsEmpty",
typeof(bool),
typeof(AttachedProperties), new PropertyMetadata(false));
typeof(AttachedProperties), new PropertyMetadata(true));

public static string GetPlaceholder(UIElement element)
=> element?.GetValue(PlaceholderProperty) as string;
Expand Down

0 comments on commit c75f5e3

Please sign in to comment.