mirror of
https://github.com/Pixeval/Pixeval.git
synced 2025-01-08 11:47:34 +08:00
refactor project
This commit is contained in:
parent
f72390867f
commit
b0b5b522a8
1354
Pixeval/Annotations.cs
Normal file
1354
Pixeval/Annotations.cs
Normal file
File diff suppressed because it is too large
Load Diff
318
Pixeval/App.xaml
Normal file
318
Pixeval/App.xaml
Normal file
@ -0,0 +1,318 @@
|
||||
<!--
|
||||
Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
Copyright (C) 2019-2020 Dylech30th
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.-->
|
||||
|
||||
<Application x:Class="Pixeval.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime"
|
||||
xmlns:valueConverters="clr-namespace:Pixeval.Objects.ValueConverters"
|
||||
StartupUri="UI/SignIn.xaml">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary
|
||||
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
|
||||
<ResourceDictionary
|
||||
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
|
||||
<ResourceDictionary
|
||||
Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
|
||||
<ResourceDictionary
|
||||
Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
|
||||
<ResourceDictionary>
|
||||
<!-- ReSharper disable Xaml.RedundantResource -->
|
||||
<SolidColorBrush x:Key="PrimaryHueMidBrush" Color="#007CEE" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<Style x:Key="MaterialDesignToolButtonWithGrayWaveEffect"
|
||||
BasedOn="{StaticResource MaterialDesignToolButton}"
|
||||
TargetType="Button">
|
||||
<Style.Resources>
|
||||
<SolidColorBrush x:Key="PrimaryHueMidBrush" Color="Gray" />
|
||||
</Style.Resources>
|
||||
</Style>
|
||||
<system:Double x:Key="Two">
|
||||
2
|
||||
</system:Double>
|
||||
<CubicEase x:Key="CubicEase" EasingMode="EaseOut" />
|
||||
<PowerEase x:Key="QuinticEase"
|
||||
EasingMode="EaseInOut"
|
||||
Power="1" />
|
||||
<valueConverters:EnumToStringConverter x:Key="EnumToStringConverter" />
|
||||
<valueConverters:VisibleIfTrueConverter x:Key="VisibleIfTrueConverter" />
|
||||
<valueConverters:VisibleIfFalseConverter x:Key="VisibleIfFalseConverter" />
|
||||
<valueConverters:DoublePlusConverter x:Key="DoublePlusConverter" />
|
||||
<valueConverters:IllustSubscriptConverter x:Key="IllustSubscriptConverter" />
|
||||
<valueConverters:DateTimeOffsetConverter x:Key="DateTimeOffsetConverter" />
|
||||
<valueConverters:DoubleDivisionConverter x:Key="DoubleDivisionConverter" />
|
||||
<valueConverters:BoolToCachingPolicyConverter x:Key="BoolToCachingPolicyConverter" />
|
||||
<valueConverters:IllustrationMatchConditionMaskConverter x:Key="IllustrationMatchConditionMaskConverter" />
|
||||
<valueConverters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||
<valueConverters:TrendsStatConverter x:Key="TrendsStatConverter" />
|
||||
<valueConverters:DateTimeConverter x:Key="DateTimeConverter" />
|
||||
<valueConverters:MultiCultureConverter x:Key="MultiCultureConverter" />
|
||||
<valueConverters:TagMatchEnumToModelConverter x:Key="TagMatchEnumToModelConverter" />
|
||||
<Style x:Key="RoundedCornerProgressBar" TargetType="{x:Type ProgressBar}">
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryHueDarkBrush}" />
|
||||
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryHueLightBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="Height" Value="4" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ProgressBar}">
|
||||
<ControlTemplate.Resources>
|
||||
<Storyboard x:Key="OnLoaded">
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="TemplateRoot"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
|
||||
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="TemplateRoot"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
|
||||
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
|
||||
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="TemplateRoot"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
|
||||
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
|
||||
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<Storyboard x:Key="OnLoadedNoAnimation">
|
||||
<DoubleAnimation Storyboard.TargetName="TemplateRoot"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
To="1"
|
||||
Duration="0" />
|
||||
<DoubleAnimation Storyboard.TargetName="TemplateRoot"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
|
||||
To="1"
|
||||
Duration="0" />
|
||||
<DoubleAnimation Storyboard.TargetName="TemplateRoot"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
|
||||
To="1"
|
||||
Duration="0" />
|
||||
</Storyboard>
|
||||
</ControlTemplate.Resources>
|
||||
<Grid x:Name="TemplateRoot"
|
||||
Opacity="0"
|
||||
RenderTransformOrigin="0,0.5">
|
||||
<Grid.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="0" ScaleY="0" />
|
||||
<SkewTransform />
|
||||
<RotateTransform />
|
||||
<TranslateTransform />
|
||||
</TransformGroup>
|
||||
</Grid.RenderTransform>
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="3" />
|
||||
<Rectangle x:Name="PART_Track" />
|
||||
<Grid x:Name="PART_Indicator"
|
||||
HorizontalAlignment="Left"
|
||||
ClipToBounds="true">
|
||||
<Rectangle x:Name="Indicator"
|
||||
Fill="{TemplateBinding Foreground}"
|
||||
RadiusX="3"
|
||||
RadiusY="3" />
|
||||
<Rectangle x:Name="Animation"
|
||||
Fill="{TemplateBinding Foreground}"
|
||||
RadiusX="3"
|
||||
RadiusY="3"
|
||||
RenderTransformOrigin="0.5,0.5">
|
||||
<Rectangle.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform />
|
||||
<SkewTransform />
|
||||
<RotateTransform />
|
||||
<TranslateTransform />
|
||||
</TransformGroup>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
</Grid>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Determinate" />
|
||||
<VisualState x:Name="Indeterminate">
|
||||
<Storyboard RepeatBehavior="Forever">
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Animation"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
|
||||
<EasingDoubleKeyFrame KeyTime="0" Value="0.25" />
|
||||
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.25" />
|
||||
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="0.25" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<PointAnimationUsingKeyFrames Storyboard.TargetName="Animation"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)">
|
||||
<EasingPointKeyFrame KeyTime="0" Value="-0.5,0.5" />
|
||||
<EasingPointKeyFrame KeyTime="0:0:1" Value="0.5,0.5" />
|
||||
<EasingPointKeyFrame KeyTime="0:0:2" Value="1.5,0.5" />
|
||||
</PointAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="materialDesign:TransitionAssist.DisableTransitions" Value="True">
|
||||
<Trigger.EnterActions>
|
||||
<BeginStoryboard Name="BeginStoryboardOnLoadedNoAnimation"
|
||||
Storyboard="{StaticResource OnLoadedNoAnimation}" />
|
||||
</Trigger.EnterActions>
|
||||
<Trigger.ExitActions>
|
||||
<RemoveStoryboard BeginStoryboardName="BeginStoryboardOnLoadedNoAnimation" />
|
||||
</Trigger.ExitActions>
|
||||
</Trigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsVisible" Value="True" />
|
||||
<Condition Property="materialDesign:TransitionAssist.DisableTransitions"
|
||||
Value="False" />
|
||||
</MultiTrigger.Conditions>
|
||||
<MultiTrigger.EnterActions>
|
||||
<BeginStoryboard Name="BeginStoryboardOnLoaded"
|
||||
Storyboard="{StaticResource OnLoaded}" />
|
||||
</MultiTrigger.EnterActions>
|
||||
<MultiTrigger.ExitActions>
|
||||
<RemoveStoryboard BeginStoryboardName="BeginStoryboardOnLoaded" />
|
||||
</MultiTrigger.ExitActions>
|
||||
</MultiTrigger>
|
||||
<Trigger Property="Orientation" Value="Vertical">
|
||||
<Setter Property="LayoutTransform">
|
||||
<Setter.Value>
|
||||
<RotateTransform Angle="-90" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
<Trigger Property="IsIndeterminate" Value="true">
|
||||
<Setter TargetName="Indicator" Property="Visibility" Value="Collapsed" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="ScrollThumbs" TargetType="{x:Type Thumb}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Thumb}">
|
||||
<Grid x:Name="Grid">
|
||||
<Rectangle Width="Auto"
|
||||
Height="Auto"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Fill="Transparent" />
|
||||
<Border x:Name="Rectangle1"
|
||||
Width="Auto"
|
||||
Height="Auto"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="5" />
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="Tag" Value="Horizontal">
|
||||
<Setter TargetName="Rectangle1" Property="Width" Value="Auto" />
|
||||
<Setter TargetName="Rectangle1" Property="Height" Value="7" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}">
|
||||
<Setter Property="Stylus.IsFlicksEnabled" Value="false" />
|
||||
<Setter Property="Foreground" Value="#8C8C8C" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Width" Value="8" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ScrollBar}">
|
||||
<Grid x:Name="GridRoot"
|
||||
Width="8"
|
||||
Background="{TemplateBinding Background}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="0.00001*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Track x:Name="PART_Track"
|
||||
Grid.Row="0"
|
||||
Focusable="false"
|
||||
IsDirectionReversed="true">
|
||||
<Track.Thumb>
|
||||
<Thumb x:Name="Thumb"
|
||||
Background="{TemplateBinding Foreground}"
|
||||
Style="{DynamicResource ScrollThumbs}" />
|
||||
</Track.Thumb>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton x:Name="PageUp"
|
||||
Command="ScrollBar.PageDownCommand"
|
||||
Focusable="false"
|
||||
Opacity="0" />
|
||||
</Track.IncreaseRepeatButton>
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton x:Name="PageDown"
|
||||
Command="ScrollBar.PageUpCommand"
|
||||
Focusable="false"
|
||||
Opacity="0" />
|
||||
</Track.DecreaseRepeatButton>
|
||||
</Track>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger SourceName="Thumb" Property="IsMouseOver" Value="true">
|
||||
<Setter TargetName="Thumb" Property="Background"
|
||||
Value="{DynamicResource ButtonSelectBrush}" />
|
||||
</Trigger>
|
||||
<Trigger SourceName="Thumb" Property="IsDragging" Value="true">
|
||||
<Setter TargetName="Thumb" Property="Background"
|
||||
Value="{DynamicResource DarkBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter TargetName="Thumb" Property="Visibility" Value="Collapsed" />
|
||||
</Trigger>
|
||||
<Trigger Property="Orientation" Value="Horizontal">
|
||||
<Setter TargetName="GridRoot" Property="LayoutTransform">
|
||||
<Setter.Value>
|
||||
<RotateTransform Angle="-90" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter TargetName="PART_Track" Property="LayoutTransform">
|
||||
<Setter.Value>
|
||||
<RotateTransform Angle="-90" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Width" Value="Auto" />
|
||||
<Setter Property="Height" Value="8" />
|
||||
<Setter TargetName="Thumb" Property="Tag" Value="Horizontal" />
|
||||
<Setter TargetName="PageDown" Property="Command" Value="ScrollBar.PageLeftCommand" />
|
||||
<Setter TargetName="PageUp" Property="Command" Value="ScrollBar.PageRightCommand" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="ReleaseImageStyle" TargetType="Image">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsVisible" Value="False">
|
||||
<Setter Property="Source" Value="{x:Null}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
128
Pixeval/App.xaml.cs
Normal file
128
Pixeval/App.xaml.cs
Normal file
@ -0,0 +1,128 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Pixeval.Core;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Pixeval.Persisting;
|
||||
#if RELEASE
|
||||
using System.Net;
|
||||
using Pixeval.Objects.Exceptions.Logger;
|
||||
|
||||
#endif
|
||||
|
||||
namespace Pixeval
|
||||
{
|
||||
public partial class App
|
||||
{
|
||||
private static readonly Mutex UniqueMutex = new Mutex(true, "Pixeval Mutex");
|
||||
|
||||
public App()
|
||||
{
|
||||
if (Dispatcher != null)
|
||||
{
|
||||
Dispatcher.UnhandledException += (sender, args) => DispatcherOnUnhandledException(args.Exception);
|
||||
}
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, args) => DispatcherOnUnhandledException((Exception) args.ExceptionObject);
|
||||
TaskScheduler.UnobservedTaskException += (sender, args) => DispatcherOnUnhandledException(args.Exception);
|
||||
}
|
||||
|
||||
private static void DispatcherOnUnhandledException(Exception e)
|
||||
{
|
||||
#if RELEASE
|
||||
if (e is WebException || e is TaskCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ExceptionDumper.WriteException(e);
|
||||
#elif DEBUG
|
||||
throw e;
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override async void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
InitializeFolders();
|
||||
CheckMultipleProcess();
|
||||
await RestoreSettings();
|
||||
await CheckUpdate();
|
||||
base.OnStartup(e);
|
||||
}
|
||||
|
||||
private static void InitializeFolders()
|
||||
{
|
||||
Directory.CreateDirectory(AppContext.ProjectFolder);
|
||||
Directory.CreateDirectory(AppContext.SettingsFolder);
|
||||
Directory.CreateDirectory(AppContext.ExceptionReportFolder);
|
||||
}
|
||||
|
||||
private static void CheckMultipleProcess()
|
||||
{
|
||||
if (!UniqueMutex.WaitOne(0, false))
|
||||
{
|
||||
MessageBox.Show(AkaI18N.MultiplePixevalInstanceDetected, AkaI18N.MultiplePixevalInstanceDetectedTitle, MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Environment.Exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task CheckUpdate()
|
||||
{
|
||||
if (await AppContext.UpdateAvailable() && MessageBox.Show(AkaI18N.PixevalUpdateAvailable, AkaI18N.PixevalUpdateAvailableTitle, MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
|
||||
{
|
||||
Process.Start(@"updater\Pixeval.Updater.exe");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task RestoreSettings()
|
||||
{
|
||||
await Settings.Restore();
|
||||
BrowsingHistoryAccessor.GlobalLifeTimeScope = new BrowsingHistoryAccessor(200, AppContext.BrowseHistoryDatabase);
|
||||
}
|
||||
|
||||
protected override async void OnExit(ExitEventArgs e)
|
||||
{
|
||||
await Settings.Global.Store();
|
||||
if (Session.Current != null && !Session.Current.AccessToken.IsNullOrEmpty())
|
||||
{
|
||||
await Session.Current.Store();
|
||||
}
|
||||
if (File.Exists(AppContext.BrowseHistoryDatabase))
|
||||
{
|
||||
BrowsingHistoryAccessor.GlobalLifeTimeScope.SetWritable();
|
||||
BrowsingHistoryAccessor.GlobalLifeTimeScope.Rewrite();
|
||||
BrowsingHistoryAccessor.GlobalLifeTimeScope.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
BrowsingHistoryAccessor.GlobalLifeTimeScope.EmergencyRewrite();
|
||||
}
|
||||
|
||||
base.OnExit(e);
|
||||
}
|
||||
}
|
||||
}
|
68
Pixeval/AppContext.cs
Normal file
68
Pixeval/AppContext.cs
Normal file
@ -0,0 +1,68 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Core;
|
||||
using Pixeval.Data.ViewModel;
|
||||
|
||||
namespace Pixeval
|
||||
{
|
||||
public static class AppContext
|
||||
{
|
||||
public const string AppIdentifier = "Pixeval";
|
||||
|
||||
public const string CurrentVersion = "3.0.1";
|
||||
|
||||
public const string ConfigurationFileName = "pixeval_conf.json";
|
||||
|
||||
public static readonly string ProjectFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), AppIdentifier.ToLower());
|
||||
|
||||
public static readonly string ConfFolder = ProjectFolder;
|
||||
|
||||
public static readonly string SettingsFolder = ProjectFolder;
|
||||
|
||||
public static readonly string ExceptionReportFolder = Path.Combine(ProjectFolder, "crash-reports");
|
||||
|
||||
public static readonly string BrowseHistoryDatabase = Path.Combine(ProjectFolder, "history.db");
|
||||
|
||||
public static string PermanentlyFolder = Path.Combine(ProjectFolder, "permanent");
|
||||
|
||||
public static readonly ObservableCollection<TrendingTag> TrendingTags = new ObservableCollection<TrendingTag>();
|
||||
|
||||
public static readonly IQualifier<Illustration, IllustrationQualification> DefaultQualifier = new IllustrationQualifier();
|
||||
|
||||
public static readonly I18NOption[] AvailableCultures = { I18NOption.UsEnglish, I18NOption.ChineseSimplified };
|
||||
|
||||
public static int ProxyPort { get; set; }
|
||||
|
||||
public static int PacPort { get; set; }
|
||||
|
||||
public static async Task<bool> UpdateAvailable()
|
||||
{
|
||||
const string Url = "http://47.95.218.243/Pixeval/version.txt";
|
||||
var httpClient = new HttpClient();
|
||||
return await httpClient.GetStringAsync(Url) != CurrentVersion;
|
||||
}
|
||||
}
|
||||
}
|
67
Pixeval/Core/AbstractPixivAsyncEnumerable.cs
Normal file
67
Pixeval/Core/AbstractPixivAsyncEnumerable.cs
Normal file
@ -0,0 +1,67 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract implementation of <see cref="IPixivAsyncEnumerable{T}" />, provides the default implementation of cancel a
|
||||
/// running <see cref="IPixivAsyncEnumerable{T}" /> instance
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class AbstractPixivAsyncEnumerable<T> : IPixivAsyncEnumerable<T>
|
||||
{
|
||||
protected bool IsCancelled { get; private set; }
|
||||
|
||||
public abstract int RequestedPages { get; protected set; }
|
||||
|
||||
public abstract IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);
|
||||
|
||||
public virtual bool VerifyRationality(T item, IList<T> collection)
|
||||
{
|
||||
return item != null && !collection.Contains(item);
|
||||
}
|
||||
|
||||
public virtual void InsertionPolicy(T item, IList<T> collection)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
IsCancelled = true;
|
||||
}
|
||||
|
||||
public bool IsCancellationRequested()
|
||||
{
|
||||
return IsCancelled;
|
||||
}
|
||||
|
||||
public void ReportRequestedPages()
|
||||
{
|
||||
RequestedPages++;
|
||||
}
|
||||
}
|
||||
}
|
50
Pixeval/Core/AbstractPixivAsyncEnumerator.cs
Normal file
50
Pixeval/Core/AbstractPixivAsyncEnumerator.cs
Normal file
@ -0,0 +1,50 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide a set of functions that support iterate an <see cref="IPixivAsyncEnumerable{T}" />
|
||||
/// </summary>
|
||||
/// <typeparam name="T">the correspond data type</typeparam>
|
||||
public abstract class AbstractPixivAsyncEnumerator<T> : IAsyncEnumerator<T>
|
||||
{
|
||||
protected IPixivAsyncEnumerable<T> Enumerable;
|
||||
|
||||
protected AbstractPixivAsyncEnumerator(IPixivAsyncEnumerable<T> enumerable)
|
||||
{
|
||||
Enumerable = enumerable;
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public abstract ValueTask<bool> MoveNextAsync();
|
||||
|
||||
public abstract T Current { get; }
|
||||
|
||||
protected abstract void UpdateEnumerator();
|
||||
}
|
||||
}
|
143
Pixeval/Core/BrowsingHistoryAccessor.cs
Normal file
143
Pixeval/Core/BrowsingHistoryAccessor.cs
Normal file
@ -0,0 +1,143 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using SQLite;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages the global browsing history which lives inside application
|
||||
/// the underlying implementation is sqlite database
|
||||
/// </summary>
|
||||
public class BrowsingHistoryAccessor : ITimelineService, IDisposable
|
||||
{
|
||||
public static BrowsingHistoryAccessor GlobalLifeTimeScope;
|
||||
|
||||
// current browsing histories
|
||||
private readonly ObservableCollection<BrowsingHistory> delegation;
|
||||
private readonly string path;
|
||||
private readonly SQLiteConnection sqLiteConnection;
|
||||
private readonly int stackLimit;
|
||||
private bool writable;
|
||||
|
||||
public BrowsingHistoryAccessor(int stackLimit, string path)
|
||||
{
|
||||
this.stackLimit = stackLimit;
|
||||
this.path = path;
|
||||
sqLiteConnection = new SQLiteConnection(path, SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite);
|
||||
sqLiteConnection.CreateTable<BrowsingHistory>();
|
||||
delegation = new ObservableCollection<BrowsingHistory>(sqLiteConnection.Table<BrowsingHistory>());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
sqLiteConnection?.Dispose();
|
||||
}
|
||||
|
||||
public bool VerifyRationality(BrowsingHistory browsingHistory)
|
||||
{
|
||||
// if current browsing history list has elements
|
||||
if (delegation.Any())
|
||||
{
|
||||
var prev = delegation[0];
|
||||
// check if the last one in the browsing history list is the same as the one to be insert, return false if so
|
||||
if (prev.Type == browsingHistory.Type && prev.BrowseObjectId == browsingHistory.BrowseObjectId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Insert(BrowsingHistory browsingHistory)
|
||||
{
|
||||
// we can simply consider the browsing histories as a double-ended queue with limited capacity, we will pop the oldest one
|
||||
// and insert a new one if the Deque is full
|
||||
if (delegation.Count >= stackLimit)
|
||||
{
|
||||
delegation.Remove(delegation.Last());
|
||||
}
|
||||
|
||||
delegation.Insert(0, browsingHistory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the database file is not present, we will urgently create one and
|
||||
/// write all the browsing histories that we have into it
|
||||
/// </summary>
|
||||
public void EmergencyRewrite()
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
using var sql = new SQLiteConnection(path);
|
||||
sql.CreateTable<BrowsingHistory>();
|
||||
sql.InsertAll(Get());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns currently maintained browsing histories
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<BrowsingHistory> Get()
|
||||
{
|
||||
return delegation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rewrite the local database, you muse call <see cref="SetWritable" />
|
||||
/// before call this method
|
||||
/// </summary>
|
||||
public void Rewrite()
|
||||
{
|
||||
if (!writable)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
sqLiteConnection.DropTable<BrowsingHistory>();
|
||||
sqLiteConnection.CreateTable<BrowsingHistory>();
|
||||
sqLiteConnection.InsertAll(delegation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete the local database
|
||||
/// </summary>
|
||||
public void DropDb()
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetWritable()
|
||||
{
|
||||
writable = true;
|
||||
}
|
||||
}
|
||||
}
|
51
Pixeval/Core/CreateNewFolderForUserDownloadPathProvider.cs
Normal file
51
Pixeval/Core/CreateNewFolderForUserDownloadPathProvider.cs
Normal file
@ -0,0 +1,51 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Pixeval.Persisting;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class CreateNewFolderForUserDownloadPathProvider : IDownloadPathProvider
|
||||
{
|
||||
public CreateNewFolderForUserDownloadPathProvider(string userName)
|
||||
{
|
||||
UserName = userName;
|
||||
}
|
||||
|
||||
public string UserName { get; set; }
|
||||
|
||||
public string GetSpotlightPath(string title, DownloadOption option = null)
|
||||
{
|
||||
return option?.RootDirectory ?? Path.Combine(Settings.Global.DownloadLocation, "Spotlight", Strings.FormatPath(title));
|
||||
}
|
||||
|
||||
public string GetIllustrationPath(DownloadOption option = null)
|
||||
{
|
||||
return option?.RootDirectory ?? Path.Combine(Settings.Global.DownloadLocation, UserName);
|
||||
}
|
||||
|
||||
public string GetMangaPath(string id, DownloadOption option = null)
|
||||
{
|
||||
return option?.RootDirectory ?? Path.Combine(Settings.Global.DownloadLocation, UserName, id);
|
||||
}
|
||||
}
|
||||
}
|
44
Pixeval/Core/DefaultDownloadPathProvider.cs
Normal file
44
Pixeval/Core/DefaultDownloadPathProvider.cs
Normal file
@ -0,0 +1,44 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Pixeval.Persisting;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class DefaultDownloadPathProvider : IDownloadPathProvider
|
||||
{
|
||||
public string GetSpotlightPath(string title, DownloadOption option = null)
|
||||
{
|
||||
return option?.RootDirectory ?? Path.Combine(Settings.Global.DownloadLocation, "Spotlight", Strings.FormatPath(title));
|
||||
}
|
||||
|
||||
public string GetIllustrationPath(DownloadOption option = null)
|
||||
{
|
||||
return option?.RootDirectory ?? Settings.Global.DownloadLocation;
|
||||
}
|
||||
|
||||
public string GetMangaPath(string id, DownloadOption option = null)
|
||||
{
|
||||
return option?.RootDirectory ?? Path.Combine(Settings.Global.DownloadLocation, id);
|
||||
}
|
||||
}
|
||||
}
|
44
Pixeval/Core/DefaultIllustrationFileNameFormatter.cs
Normal file
44
Pixeval/Core/DefaultIllustrationFileNameFormatter.cs
Normal file
@ -0,0 +1,44 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class DefaultIllustrationFileNameFormatter : IIllustrationFileNameFormatter
|
||||
{
|
||||
public string Format(Illustration illustration)
|
||||
{
|
||||
return $"[{Strings.FormatPath(illustration.UserName)}]{illustration.Id}{Path.GetExtension(illustration.Origin.IsNullOrEmpty() ? illustration.Large : illustration.Origin)}";
|
||||
}
|
||||
|
||||
public string FormatManga(Illustration illustration, int idx)
|
||||
{
|
||||
return $"[{Strings.FormatPath(illustration.UserName)}]{illustration.Id}_p{idx}{Path.GetExtension(illustration.Origin.IsNullOrEmpty() ? illustration.Large : illustration.Origin)}";
|
||||
}
|
||||
|
||||
public string FormatGif(Illustration illustration)
|
||||
{
|
||||
return $"[{Strings.FormatPath(illustration.UserName)}]{illustration.Id}.gif";
|
||||
}
|
||||
}
|
||||
}
|
47
Pixeval/Core/EnumeratingSchedule.cs
Normal file
47
Pixeval/Core/EnumeratingSchedule.cs
Normal file
@ -0,0 +1,47 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class EnumeratingSchedule
|
||||
{
|
||||
private static object _currentItr;
|
||||
|
||||
public static void StartNewInstance<T>(IPixivAsyncEnumerable<T> itr)
|
||||
{
|
||||
CancelCurrent();
|
||||
_currentItr = itr;
|
||||
}
|
||||
|
||||
public static IPixivAsyncEnumerable<T> GetCurrentEnumerator<T>()
|
||||
{
|
||||
return _currentItr as IPixivAsyncEnumerable<T>;
|
||||
}
|
||||
|
||||
public static void CancelCurrent()
|
||||
{
|
||||
var iterator = _currentItr as ICancellable;
|
||||
iterator?.Cancel();
|
||||
GC.Collect();
|
||||
}
|
||||
}
|
||||
}
|
166
Pixeval/Core/GalleryAsyncEnumerable.cs
Normal file
166
Pixeval/Core/GalleryAsyncEnumerable.cs
Normal file
@ -0,0 +1,166 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Pixeval.Persisting;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public abstract class AbstractGalleryAsyncEnumerable : AbstractPixivAsyncEnumerable<Illustration>
|
||||
{
|
||||
protected abstract string Uid { get; }
|
||||
|
||||
protected abstract RestrictPolicy RestrictPolicy { get; }
|
||||
|
||||
public override int RequestedPages { get; protected set; }
|
||||
|
||||
public override bool VerifyRationality(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
return item != null && collection.All(t => t.Id != item.Id) && PixivHelper.VerifyIllust(Settings.Global.ExcludeTag, Settings.Global.IncludeTag, Settings.Global.MinBookmark, item);
|
||||
}
|
||||
|
||||
public override IAsyncEnumerator<Illustration> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new GalleryAsyncEnumerator(Uid, this, RestrictPolicy);
|
||||
}
|
||||
|
||||
public static AbstractGalleryAsyncEnumerable Of(string uid, RestrictPolicy restrictPolicy)
|
||||
{
|
||||
return restrictPolicy switch
|
||||
{
|
||||
RestrictPolicy.Public => new PublicGalleryAsyncEnumerable(uid),
|
||||
RestrictPolicy.Private => new PrivateGalleryAsyncEnumerable(uid),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(restrictPolicy), restrictPolicy, null)
|
||||
};
|
||||
}
|
||||
|
||||
private class GalleryAsyncEnumerator : AbstractPixivAsyncEnumerator<Illustration>
|
||||
{
|
||||
private readonly RestrictPolicy restrictPolicy;
|
||||
private readonly string uid;
|
||||
private GalleryResponse entity;
|
||||
|
||||
private IEnumerator<Illustration> illustrationsEnumerator;
|
||||
|
||||
public GalleryAsyncEnumerator(string uid, IPixivAsyncEnumerable<Illustration> outerInstance, RestrictPolicy restrictPolicy) : base(outerInstance)
|
||||
{
|
||||
this.uid = uid;
|
||||
this.restrictPolicy = restrictPolicy;
|
||||
}
|
||||
|
||||
public override Illustration Current => illustrationsEnumerator.Current;
|
||||
|
||||
protected override void UpdateEnumerator()
|
||||
{
|
||||
illustrationsEnumerator = entity.Illusts.NonNull().Select(_ => _.Parse()).GetEnumerator();
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
if (await TryGetResponse(restrictPolicy switch
|
||||
{
|
||||
RestrictPolicy.Public => $"/v1/user/bookmarks/illust?user_id={uid}&restrict=public&filter=for_ios",
|
||||
RestrictPolicy.Private => $"/v1/user/bookmarks/illust?user_id={uid}&restrict=private&filter=for_ios",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
}) is (true, var model))
|
||||
{
|
||||
entity = model;
|
||||
UpdateEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
|
||||
Enumerable.ReportRequestedPages();
|
||||
}
|
||||
|
||||
if (illustrationsEnumerator.MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entity.NextUrl.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await TryGetResponse(entity.NextUrl) is (true, var response))
|
||||
{
|
||||
entity = response;
|
||||
UpdateEnumerator();
|
||||
Enumerable.ReportRequestedPages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponse<GalleryResponse>> TryGetResponse(string url)
|
||||
{
|
||||
var result = (await HttpClientFactory.AppApiHttpClient().GetStringAsync(url)).FromJson<GalleryResponse>();
|
||||
|
||||
if (result is { } response && !response.Illusts.IsNullOrEmpty())
|
||||
{
|
||||
return HttpResponse<GalleryResponse>.Wrap(true, response);
|
||||
}
|
||||
return HttpResponse<GalleryResponse>.Wrap(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PublicGalleryAsyncEnumerable : AbstractGalleryAsyncEnumerable
|
||||
{
|
||||
public PublicGalleryAsyncEnumerable(string uid)
|
||||
{
|
||||
Uid = uid;
|
||||
}
|
||||
|
||||
protected override string Uid { get; }
|
||||
|
||||
protected override RestrictPolicy RestrictPolicy { get; } = RestrictPolicy.Public;
|
||||
}
|
||||
|
||||
public class PrivateGalleryAsyncEnumerable : AbstractGalleryAsyncEnumerable
|
||||
{
|
||||
public PrivateGalleryAsyncEnumerable(string uid)
|
||||
{
|
||||
Uid = uid;
|
||||
}
|
||||
|
||||
protected override string Uid { get; }
|
||||
|
||||
protected override RestrictPolicy RestrictPolicy { get; } = RestrictPolicy.Private;
|
||||
}
|
||||
}
|
29
Pixeval/Core/ICancellable.cs
Normal file
29
Pixeval/Core/ICancellable.cs
Normal file
@ -0,0 +1,29 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public interface ICancellable
|
||||
{
|
||||
void Cancel();
|
||||
|
||||
bool IsCancellationRequested();
|
||||
}
|
||||
}
|
49
Pixeval/Core/IDownloadPathProvider.cs
Normal file
49
Pixeval/Core/IDownloadPathProvider.cs
Normal file
@ -0,0 +1,49 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Pixeval.Data.ViewModel;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public interface IIllustrationFileNameFormatter
|
||||
{
|
||||
string Format(Illustration illustration);
|
||||
|
||||
string FormatManga(Illustration illustration, int idx);
|
||||
|
||||
string FormatGif(Illustration illustration);
|
||||
}
|
||||
|
||||
public interface IDownloadPathProvider
|
||||
{
|
||||
string GetSpotlightPath(string title, DownloadOption option = null);
|
||||
|
||||
string GetIllustrationPath(DownloadOption option = null);
|
||||
|
||||
string GetMangaPath(string id, DownloadOption option = null);
|
||||
}
|
||||
|
||||
public class DownloadOption
|
||||
{
|
||||
public string RootDirectory { get; set; }
|
||||
|
||||
public bool CreateNewWhenFromUser { get; set; }
|
||||
}
|
||||
}
|
35
Pixeval/Core/IPixivAsyncEnumerable.cs
Normal file
35
Pixeval/Core/IPixivAsyncEnumerable.cs
Normal file
@ -0,0 +1,35 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public interface IPixivAsyncEnumerable<T> : IAsyncEnumerable<T>, ICancellable
|
||||
{
|
||||
int RequestedPages { get; }
|
||||
|
||||
void ReportRequestedPages();
|
||||
|
||||
void InsertionPolicy(T item, IList<T> collection);
|
||||
|
||||
bool VerifyRationality(T item, IList<T> collection);
|
||||
}
|
||||
}
|
27
Pixeval/Core/IQualifier.cs
Normal file
27
Pixeval/Core/IQualifier.cs
Normal file
@ -0,0 +1,27 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public interface IQualifier<in T, in P>
|
||||
{
|
||||
public bool Qualified(T condition, P pattern);
|
||||
}
|
||||
}
|
43
Pixeval/Core/ITimelineService.cs
Normal file
43
Pixeval/Core/ITimelineService.cs
Normal file
@ -0,0 +1,43 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Pixeval.Data.ViewModel;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a set of functions that support a Browsing Timeline
|
||||
/// </summary>
|
||||
public interface ITimelineService
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if the <see cref="BrowsingHistory" /> has the rationality to be insert to timeline
|
||||
/// </summary>
|
||||
/// <param name="browsingHistory"></param>
|
||||
/// <returns></returns>
|
||||
bool VerifyRationality(BrowsingHistory browsingHistory);
|
||||
|
||||
/// <summary>
|
||||
/// Insert a <see cref="BrowsingHistory" /> to timeline
|
||||
/// </summary>
|
||||
/// <param name="browsingHistory"></param>
|
||||
void Insert(BrowsingHistory browsingHistory);
|
||||
}
|
||||
}
|
56
Pixeval/Core/IllustrationQualification.cs
Normal file
56
Pixeval/Core/IllustrationQualification.cs
Normal file
@ -0,0 +1,56 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class IllustrationQualification
|
||||
{
|
||||
public IllustrationQualification(ConditionType type, string condition)
|
||||
{
|
||||
Type = type;
|
||||
Condition = condition;
|
||||
}
|
||||
|
||||
public ConditionType Type { get; set; }
|
||||
|
||||
public string Condition { get; set; }
|
||||
|
||||
public static IllustrationQualification Parse(string input)
|
||||
{
|
||||
var isResolution = Regex.IsMatch(input, "\\d+x\\d+");
|
||||
return new IllustrationQualification(input switch
|
||||
{
|
||||
_ when input.IsNumber() => ConditionType.Id,
|
||||
_ when input.StartsWith("!") => ConditionType.ExcludeTag,
|
||||
_ when !input.IsNullOrEmpty() => ConditionType.Tag,
|
||||
_ when isResolution => ConditionType.Resolution,
|
||||
_ => ConditionType.None
|
||||
}, input);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ConditionType
|
||||
{
|
||||
Id, Tag, ExcludeTag, Resolution, None
|
||||
}
|
||||
}
|
61
Pixeval/Core/IllustrationQualifier.cs
Normal file
61
Pixeval/Core/IllustrationQualifier.cs
Normal file
@ -0,0 +1,61 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class IllustrationQualifier : IQualifier<Illustration, IllustrationQualification>
|
||||
{
|
||||
public bool Qualified(Illustration condition, IllustrationQualification pattern)
|
||||
{
|
||||
if (pattern.Type == ConditionType.Resolution)
|
||||
{
|
||||
const string Reg = "(?<width>\\d+)x(?<height>\\d+)";
|
||||
if (Regex.IsMatch(pattern.Condition, Reg))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var illustrationMatch = Regex.Match(condition.Resolution, Reg);
|
||||
var conditionMatch = Regex.Match(pattern.Condition, Reg);
|
||||
if (conditionMatch.Groups["width"].Value.IsNumber() && conditionMatch.Groups["height"].Value.IsNumber())
|
||||
{
|
||||
var illustrationWidth = int.Parse(illustrationMatch.Groups["width"].Value);
|
||||
var illustrationHeight = int.Parse(illustrationMatch.Groups["height"].Value);
|
||||
var desireWidth = int.Parse(conditionMatch.Groups["width"].Value);
|
||||
var desireHeight = int.Parse(conditionMatch.Groups["height"].Value);
|
||||
return desireWidth < illustrationWidth || desireHeight < illustrationHeight;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return pattern switch
|
||||
{
|
||||
{ Type: ConditionType.Id } => !condition.Id.Contains(pattern.Condition),
|
||||
{ Type: ConditionType.Tag } => !condition.Title.Contains(pattern.Condition) && !(condition.Tags != null && condition.Tags.Any(tag => tag?.Name != null && tag.Name.ToLower().Contains(pattern.Condition.ToLower()) || tag?.TranslatedName != null && tag.TranslatedName.ToLower().Contains(pattern.Condition.ToLower()))),
|
||||
{ Type: ConditionType.ExcludeTag } => condition.Tags != null && condition.Tags.Any(tag => tag?.Name != null && tag.Name.ToLower().Contains(pattern.Condition[1..].ToLower()) || tag?.TranslatedName != null && tag.TranslatedName.ToLower().Contains(pattern.Condition[1..].ToLower())),
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
111
Pixeval/Core/Managers.cs
Normal file
111
Pixeval/Core/Managers.cs
Normal file
@ -0,0 +1,111 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Pixeval.Data.ViewModel;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class DownloadManager
|
||||
{
|
||||
public static readonly ObservableCollection<DownloadableIllustration> Downloading = new ObservableCollection<DownloadableIllustration>();
|
||||
|
||||
public static readonly ObservableCollection<DownloadableIllustration> Downloaded = new ObservableCollection<DownloadableIllustration>();
|
||||
|
||||
public static void EnqueueDownloadItem(Illustration illustration, DownloadOption option = null)
|
||||
{
|
||||
if (Downloading.Any(i => illustration.Id == i.DownloadContent.Id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
option ??= new DownloadOption();
|
||||
|
||||
static DownloadableIllustration CreateDownloadableIllustration(Illustration downloadContent, bool isFromMange, DownloadOption option, int index = -1)
|
||||
{
|
||||
var filePathProvider = option.CreateNewWhenFromUser ? new CreateNewFolderForUserDownloadPathProvider(downloadContent.UserName) : (IDownloadPathProvider) new DefaultDownloadPathProvider();
|
||||
var fileNameFormatter = new DefaultIllustrationFileNameFormatter();
|
||||
var model = new DownloadableIllustration(downloadContent, fileNameFormatter, filePathProvider, isFromMange, index) { Option = option };
|
||||
model.DownloadState.ValueChanged += (sender, args) => Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
switch (args.NewValue)
|
||||
{
|
||||
case DownloadStateEnum.Finished:
|
||||
model.Freeze();
|
||||
Downloading.Remove(model);
|
||||
if (Downloaded.All(i => model.DownloadContent.GetDownloadUrl() != i.DownloadContent.GetDownloadUrl()))
|
||||
{
|
||||
Downloaded.Add(model);
|
||||
}
|
||||
break;
|
||||
case DownloadStateEnum.Downloading:
|
||||
Downloaded.Remove(model);
|
||||
Downloading.Add(model);
|
||||
break;
|
||||
case var stat when stat == DownloadStateEnum.Canceled || stat == DownloadStateEnum.Queue || stat == DownloadStateEnum.Exceptional:
|
||||
if (stat == DownloadStateEnum.Canceled)
|
||||
{
|
||||
Downloading.Remove(model);
|
||||
}
|
||||
break;
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
});
|
||||
return model;
|
||||
}
|
||||
|
||||
if (illustration.IsManga)
|
||||
{
|
||||
for (var j = 0; j < illustration.MangaMetadata.Length; j++)
|
||||
{
|
||||
var cpy = j;
|
||||
Task.Run(() => CreateDownloadableIllustration(illustration.MangaMetadata[cpy], true, option, cpy).Download());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.Run(() => CreateDownloadableIllustration(illustration, false, option).Download());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SearchingHistoryManager
|
||||
{
|
||||
private static readonly ObservableCollection<string> SearchingHistory = new ObservableCollection<string>();
|
||||
|
||||
public static void EnqueueSearchHistory(string keyword)
|
||||
{
|
||||
if (SearchingHistory.Count == 4)
|
||||
{
|
||||
SearchingHistory.RemoveAt(SearchingHistory.Count - 1);
|
||||
}
|
||||
SearchingHistory.Insert(0, keyword);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetSearchingHistory()
|
||||
{
|
||||
return SearchingHistory;
|
||||
}
|
||||
}
|
||||
}
|
45
Pixeval/Core/PixivClient.cs
Normal file
45
Pixeval/Core/PixivClient.cs
Normal file
@ -0,0 +1,45 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public sealed class PixivClient
|
||||
{
|
||||
private static volatile PixivClient _instance;
|
||||
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
public static PixivClient Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
_instance ??= new PixivClient();
|
||||
}
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
99
Pixeval/Core/PixivClientExtension.cs
Normal file
99
Pixeval/Core/PixivClientExtension.cs
Normal file
@ -0,0 +1,99 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Html.Parser;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Request;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public static class PixivClientExtension
|
||||
{
|
||||
public static async void PostFavoriteAsync(this PixivClient _, Illustration illustration, RestrictPolicy restrictPolicy)
|
||||
{
|
||||
illustration.IsLiked = true;
|
||||
await HttpClientFactory.AppApiService().AddBookmark(new AddBookmarkRequest { Id = illustration.Id, Restrict = restrictPolicy == RestrictPolicy.Public ? "public" : "private" });
|
||||
}
|
||||
|
||||
public static async void RemoveFavoriteAsync(this PixivClient _, Illustration illustration)
|
||||
{
|
||||
illustration.IsLiked = false;
|
||||
await HttpClientFactory.AppApiService().DeleteBookmark(new DeleteBookmarkRequest { IllustId = illustration.Id });
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<string>> GetArticleWorks(this PixivClient _, string spotlightId)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
var html = await httpClient.GetStringAsync($"https://www.pixivision.net/en/a/{spotlightId}");
|
||||
|
||||
var doc = await new HtmlParser().ParseDocumentAsync(html);
|
||||
|
||||
return doc.QuerySelectorAll(".am__body .am__work").Select(element => element.Children[1].Children[0].GetAttribute("href")).Select(url => Regex.Match(url, "https://www.pixiv.net/artworks/(?<Id>\\d+)").Groups["Id"].Value);
|
||||
}
|
||||
|
||||
public static async Task FollowArtist(this PixivClient _, User user, RestrictPolicy policy)
|
||||
{
|
||||
user.IsFollowed = true;
|
||||
await HttpClientFactory.AppApiService().FollowArtist(new FollowArtistRequest { Id = user.Id, Restrict = policy == RestrictPolicy.Private ? "private" : "public" });
|
||||
}
|
||||
|
||||
public static async Task UnFollowArtist(this PixivClient _, User user)
|
||||
{
|
||||
user.IsFollowed = false;
|
||||
await HttpClientFactory.AppApiService().UnFollowArtist(new UnFollowArtistRequest { UserId = user.Id });
|
||||
}
|
||||
|
||||
public static async Task<List<TrendingTag>> GetTrendingTags(this PixivClient _)
|
||||
{
|
||||
var result = await HttpClientFactory.AppApiService().GetTrendingTags();
|
||||
var list = new List<TrendingTag>();
|
||||
if (result is { } res)
|
||||
{
|
||||
list.AddRange(res.TrendTags.Select(tag => new TrendingTag { Tag = tag.TagStr, TranslatedName = tag.TranslatedName, Thumbnail = tag.Illust.ImageUrls.SquareMedium }));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
[Obsolete("reserved for Web API")]
|
||||
public static async ValueTask<bool> ToggleWebApiR18State(this PixivClient _, bool isR18On)
|
||||
{
|
||||
try
|
||||
{
|
||||
var html = await HttpClientFactory.WebApiHttpClient().GetStringAsync("https://www.pixiv.net/setting_user.php");
|
||||
var doc = await new HtmlParser().ParseDocumentAsync(html);
|
||||
|
||||
var tt = doc.QuerySelectorAll(".settingContent form input")[1].GetAttribute("value");
|
||||
await HttpClientFactory.WebApiService().ToggleR18State(new ToggleR18StateRequest { R18 = isR18On ? "show" : "hide", R18G = isR18On ? "2" : "1", Tt = tt });
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
152
Pixeval/Core/PixivHelper.cs
Normal file
152
Pixeval/Core/PixivHelper.cs
Normal file
@ -0,0 +1,152 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Pixeval.Objects.Exceptions.Logger;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class PixivHelper
|
||||
{
|
||||
public static async Task<Illustration> IllustrationInfo(string id)
|
||||
{
|
||||
SingleWorkResponse.Illust response;
|
||||
try
|
||||
{
|
||||
response = (await HttpClientFactory.AppApiService().GetSingle(id)).IllustInfo;
|
||||
}
|
||||
catch (ApiException e)
|
||||
{
|
||||
ExceptionDumper.WriteException(e);
|
||||
return null;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var illust = new Illustration
|
||||
{
|
||||
Bookmark = (int) response.TotalBookmarks,
|
||||
Id = response.Id.ToString(),
|
||||
IsLiked = response.IsBookmarked,
|
||||
IsManga = response.PageCount != 1,
|
||||
IsUgoira = response.Type == "ugoira",
|
||||
Origin = response.ImageUrls.Original ?? response.MetaSinglePage.OriginalImageUrl,
|
||||
Large = response.ImageUrls.Large,
|
||||
Tags = response.Tags.Select(t => new Tag { Name = t.Name, TranslatedName = t.TranslatedName }),
|
||||
Thumbnail = response.ImageUrls.Medium,
|
||||
Title = response.Title,
|
||||
UserName = response.User.Name,
|
||||
UserId = response.User.Id.ToString(),
|
||||
ViewCount = (int) response.TotalView,
|
||||
Comments = (int) response.TotalComments,
|
||||
Resolution = $"{response.Width}x{response.Height}",
|
||||
PublishDate = response.CreateDate
|
||||
};
|
||||
|
||||
if (illust.IsManga && response.MetaPages != null)
|
||||
{
|
||||
illust.MangaMetadata = response.MetaPages.Select(p =>
|
||||
{
|
||||
var page = (Illustration) illust.Clone();
|
||||
page.Thumbnail = p.ImageUrls.Medium;
|
||||
page.Origin = p.ImageUrls.Original;
|
||||
page.Large = p.ImageUrls.Large;
|
||||
return page;
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
return illust;
|
||||
}
|
||||
|
||||
public static async void Enumerate<T>(IPixivAsyncEnumerable<T> pixivIterator, IList<T> container, int limit = -1)
|
||||
{
|
||||
EnumeratingSchedule.StartNewInstance(pixivIterator);
|
||||
var enumerator = EnumeratingSchedule.GetCurrentEnumerator<T>();
|
||||
|
||||
await foreach (var illust in enumerator)
|
||||
{
|
||||
if (enumerator.IsCancellationRequested() || limit != -1 && pixivIterator.RequestedPages > limit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (pixivIterator.VerifyRationality(illust, container))
|
||||
{
|
||||
pixivIterator.InsertionPolicy(illust, container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RecordTimeline(ITimelineService service, BrowsingHistory browsingHistory)
|
||||
{
|
||||
if (service.VerifyRationality(browsingHistory))
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(DispatcherPriority.Loaded, (Action) (() => service.Insert(browsingHistory)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void RecordTimelineInternal(BrowsingHistory browsingHistory)
|
||||
{
|
||||
RecordTimeline(BrowsingHistoryAccessor.GlobalLifeTimeScope, browsingHistory);
|
||||
if (CheckWindowsVersion())
|
||||
{
|
||||
RecordTimeline(WindowsUserActivityManager.GlobalLifeTimeScope, browsingHistory);
|
||||
}
|
||||
|
||||
static bool CheckWindowsVersion()
|
||||
{
|
||||
return Environment.OSVersion.Version >= new Version(10, 0, 17134); /* Windows 10 April 2018 Update */
|
||||
}
|
||||
}
|
||||
|
||||
public static bool VerifyIllust(ISet<string> excludeTag, ISet<string> includeTag, int minBookmark, Illustration illustration)
|
||||
{
|
||||
if (illustration == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool excludeMatch = true, includeMatch = true;
|
||||
if (!excludeTag.IsNullOrEmpty())
|
||||
{
|
||||
excludeMatch = excludeTag.All(x => x.IsNullOrEmpty() || illustration.Tags.All(i => !i.Name.EqualsIgnoreCase(x)));
|
||||
}
|
||||
|
||||
if (!includeTag.IsNullOrEmpty())
|
||||
{
|
||||
includeMatch = includeTag.All(x => x.IsNullOrEmpty() || illustration.Tags.Any(i => i.Name.EqualsIgnoreCase(x)));
|
||||
}
|
||||
|
||||
var minBookmarkMatch = illustration.Bookmark > minBookmark;
|
||||
return excludeMatch && includeMatch && minBookmarkMatch;
|
||||
}
|
||||
}
|
||||
}
|
104
Pixeval/Core/PixivIO.cs
Normal file
104
Pixeval/Core/PixivIO.cs
Normal file
@ -0,0 +1,104 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static class PixivIO
|
||||
{
|
||||
public static async Task<byte[]> GetBytes(string url)
|
||||
{
|
||||
var client = HttpClientFactory.PixivImage();
|
||||
|
||||
byte[] res;
|
||||
try
|
||||
{
|
||||
res = await client.GetByteArrayAsync(url);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static async Task<BitmapImage> FromUrl(string url)
|
||||
{
|
||||
return await FromByteArray(await GetBytes(url));
|
||||
}
|
||||
|
||||
public static async Task<BitmapImage> FromByteArray(byte[] bArr)
|
||||
{
|
||||
if (bArr == null || bArr.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
await using var memoryStream = new MemoryStream(bArr);
|
||||
return InternalIO.CreateBitmapImageFromStream(memoryStream);
|
||||
}
|
||||
|
||||
public static async Task<string> GetResizedBase64UriOfImageFromUrl(string url, string type = null)
|
||||
{
|
||||
return $"data:image/{type ?? url[(url.LastIndexOf('.') + 1)..]};base64,{Convert.ToBase64String(await GetBytes(url))}";
|
||||
}
|
||||
|
||||
public static async Task<MemoryStream> Download(string url, IProgress<double> progress, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var response = await HttpClientFactory.GetResponseHeader(HttpClientFactory.PixivImage().Apply(_ => _.Timeout = TimeSpan.FromSeconds(30)), url);
|
||||
|
||||
var contentLength = response.Content.Headers.ContentLength;
|
||||
if (!contentLength.HasValue)
|
||||
{
|
||||
return new MemoryStream(await GetBytes(url));
|
||||
}
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
long bytesRead, totalRead = 0L;
|
||||
var byteBuffer = ArrayPool<byte>.Shared.Rent(4096);
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
await using var contentStream = await response.Content.ReadAsStreamAsync();
|
||||
while ((bytesRead = await contentStream.ReadAsync(byteBuffer, 0, byteBuffer.Length, cancellationToken)) != 0)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
totalRead += bytesRead;
|
||||
await memoryStream.WriteAsync(byteBuffer, 0, (int) bytesRead, cancellationToken);
|
||||
progress.Report(totalRead / (double) contentLength);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ArrayPool<byte>.Shared.Return(byteBuffer, true);
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
}
|
||||
}
|
186
Pixeval/Core/QueryAsyncEnumerable.cs
Normal file
186
Pixeval/Core/QueryAsyncEnumerable.cs
Normal file
@ -0,0 +1,186 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Pixeval.Persisting;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public abstract class AbstractQueryAsyncEnumerable : AbstractPixivAsyncEnumerable<Illustration>
|
||||
{
|
||||
protected readonly bool IsPremium;
|
||||
private readonly SearchTagMatchOption matchOption;
|
||||
private readonly int start;
|
||||
private readonly string tag;
|
||||
|
||||
protected AbstractQueryAsyncEnumerable(string tag, SearchTagMatchOption matchOption, bool isPremium, int start = 1)
|
||||
{
|
||||
this.start = start < 1 ? 1 : start;
|
||||
this.tag = tag;
|
||||
this.matchOption = matchOption;
|
||||
IsPremium = isPremium;
|
||||
}
|
||||
|
||||
public override int RequestedPages { get; protected set; }
|
||||
|
||||
public abstract override void InsertionPolicy(Illustration item, IList<Illustration> collection);
|
||||
|
||||
public override bool VerifyRationality(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
return item != null && collection.All(t => t.Id != item.Id) && PixivHelper.VerifyIllust(Settings.Global.ExcludeTag, Settings.Global.IncludeTag, Settings.Global.MinBookmark, item);
|
||||
}
|
||||
|
||||
public override IAsyncEnumerator<Illustration> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new QueryAsyncEnumerator(this, tag, matchOption, start, IsPremium);
|
||||
}
|
||||
|
||||
private class QueryAsyncEnumerator : AbstractPixivAsyncEnumerator<Illustration>
|
||||
{
|
||||
private readonly int current;
|
||||
private readonly bool isPremium;
|
||||
private readonly string keyword;
|
||||
private readonly SearchTagMatchOption matchOption;
|
||||
|
||||
private QueryWorksResponse entity;
|
||||
|
||||
private IEnumerator<Illustration> illustrationsEnumerator;
|
||||
|
||||
public QueryAsyncEnumerator(IPixivAsyncEnumerable<Illustration> enumerable, string keyword, SearchTagMatchOption matchOption, int current, bool isPremium) : base(enumerable)
|
||||
{
|
||||
this.keyword = keyword;
|
||||
this.matchOption = matchOption;
|
||||
this.current = current;
|
||||
this.isPremium = isPremium;
|
||||
}
|
||||
|
||||
public override Illustration Current => illustrationsEnumerator.Current;
|
||||
|
||||
protected override void UpdateEnumerator()
|
||||
{
|
||||
illustrationsEnumerator = entity.Illusts.NonNull().Select(_ => _.Parse()).GetEnumerator();
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
if (await TryGetResponse($"/v1/search/illust?search_target={matchOption.GetEnumAttribute<EnumAlias>().AliasAs}&sort={(isPremium ? "date_desc" : "popular_desc")}&word={keyword}&filter=for_android&offset={(current - 1) * 30}") is (true, var model))
|
||||
{
|
||||
entity = model;
|
||||
UpdateEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
|
||||
Enumerable.ReportRequestedPages();
|
||||
}
|
||||
|
||||
if (illustrationsEnumerator.MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (int.Parse(entity.NextUrl[(entity.NextUrl.LastIndexOf('=') + 1)..]) >= 5000)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await TryGetResponse(entity.NextUrl) is (true, var res))
|
||||
{
|
||||
entity = res;
|
||||
UpdateEnumerator();
|
||||
Enumerable.ReportRequestedPages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponse<QueryWorksResponse>> TryGetResponse(string url)
|
||||
{
|
||||
var res = (await HttpClientFactory.AppApiHttpClient().GetStringAsync(url)).FromJson<QueryWorksResponse>();
|
||||
if (res is { } response && !response.Illusts.IsNullOrEmpty())
|
||||
{
|
||||
return HttpResponse<QueryWorksResponse>.Wrap(true, response);
|
||||
}
|
||||
|
||||
return HttpResponse<QueryWorksResponse>.Wrap(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PopularityQueryAsyncEnumerable : AbstractQueryAsyncEnumerable
|
||||
{
|
||||
public PopularityQueryAsyncEnumerable(string tag, SearchTagMatchOption matchOption, bool isPremium, int start = 1) : base(tag, matchOption, isPremium, start)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InsertionPolicy(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
if (IsPremium)
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
collection.AddSorted(item, IllustrationPopularityComparator.Instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PublishDateQueryAsyncEnumerable : AbstractQueryAsyncEnumerable
|
||||
{
|
||||
public PublishDateQueryAsyncEnumerable(string tag, SearchTagMatchOption matchOption, bool isPremium, int start = 1) : base(tag, matchOption, isPremium, start)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InsertionPolicy(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
if (IsPremium)
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
collection.AddSorted(item, IllustrationPublishDateComparator.Instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
136
Pixeval/Core/RankOption.cs
Normal file
136
Pixeval/Core/RankOption.cs
Normal file
@ -0,0 +1,136 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class ForR18Only : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
public enum RankOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 日榜
|
||||
/// </summary>
|
||||
[EnumAlias("day")]
|
||||
[EnumLocalizedName("RankOptionDay")]
|
||||
Day,
|
||||
|
||||
/// <summary>
|
||||
/// 周榜
|
||||
/// </summary>
|
||||
[EnumAlias("week")]
|
||||
[EnumLocalizedName("RankOptionWeek")]
|
||||
Week,
|
||||
|
||||
/// <summary>
|
||||
/// 月榜
|
||||
/// </summary>
|
||||
[EnumAlias("month")]
|
||||
[EnumLocalizedName("RankOptionMonth")]
|
||||
Month,
|
||||
|
||||
/// <summary>
|
||||
/// 男性向日榜
|
||||
/// </summary>
|
||||
[EnumAlias("day_male")]
|
||||
[EnumLocalizedName("RankOptionDayMale")]
|
||||
DayMale,
|
||||
|
||||
/// <summary>
|
||||
/// 女性向日榜
|
||||
/// </summary>
|
||||
[EnumAlias("day_female")]
|
||||
[EnumLocalizedName("RankOptionDayFemale")]
|
||||
DayFemale,
|
||||
|
||||
/// <summary>
|
||||
/// 多图日榜
|
||||
/// </summary>
|
||||
[EnumAlias("day_manga")]
|
||||
[EnumLocalizedName("RankOptionDayManga")]
|
||||
DayManga,
|
||||
|
||||
/// <summary>
|
||||
/// 多图周榜
|
||||
/// </summary>
|
||||
[EnumAlias("week_manga")]
|
||||
[EnumLocalizedName("RankOptionWeekManga")]
|
||||
WeekManga,
|
||||
|
||||
/// <summary>
|
||||
/// 原创
|
||||
/// </summary>
|
||||
[EnumAlias("week_original")]
|
||||
[EnumLocalizedName("RankOptionWeekOriginal")]
|
||||
WeekOriginal,
|
||||
|
||||
/// <summary>
|
||||
/// 新人
|
||||
/// </summary>
|
||||
[EnumAlias("week_rookie")]
|
||||
[EnumLocalizedName("RankOptionWeekRookie")]
|
||||
WeekRookie,
|
||||
|
||||
/// <summary>
|
||||
/// R18日榜
|
||||
/// </summary>
|
||||
[ForR18Only]
|
||||
[EnumAlias("day_r18")]
|
||||
[EnumLocalizedName("RankOptionDayR18")]
|
||||
DayR18,
|
||||
|
||||
/// <summary>
|
||||
/// 男性向R18日榜
|
||||
/// </summary>
|
||||
[ForR18Only]
|
||||
[EnumAlias("day_male_r18")]
|
||||
[EnumLocalizedName("RankOptionDayMaleR18")]
|
||||
DayMaleR18,
|
||||
|
||||
/// <summary>
|
||||
/// 女性向R18日榜
|
||||
/// </summary>
|
||||
[ForR18Only]
|
||||
[EnumAlias("day_female_r18")]
|
||||
[EnumLocalizedName("RankOptionDayFemaleR18")]
|
||||
DayFemaleR18,
|
||||
|
||||
/// <summary>
|
||||
/// R18周榜
|
||||
/// </summary>
|
||||
[ForR18Only]
|
||||
[EnumAlias("week_r18")]
|
||||
[EnumLocalizedName("RankOptionWeekR18")]
|
||||
WeekR18,
|
||||
|
||||
/// <summary>
|
||||
/// R18G周榜
|
||||
/// </summary>
|
||||
[ForR18Only]
|
||||
[EnumAlias("week_r18g")]
|
||||
[EnumLocalizedName("RankOptionWeekR18G")]
|
||||
WeekR18G
|
||||
}
|
||||
}
|
137
Pixeval/Core/RankingAsyncEnumerable.cs
Normal file
137
Pixeval/Core/RankingAsyncEnumerable.cs
Normal file
@ -0,0 +1,137 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Pixeval.Persisting;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class RankingAsyncEnumerable : AbstractPixivAsyncEnumerable<Illustration>
|
||||
{
|
||||
private readonly DateTime dateTime;
|
||||
private readonly RankOption rankOption;
|
||||
|
||||
public RankingAsyncEnumerable(RankOption rankOption, DateTime dateTime)
|
||||
{
|
||||
this.rankOption = rankOption;
|
||||
this.dateTime = dateTime;
|
||||
}
|
||||
|
||||
public override int RequestedPages { get; protected set; }
|
||||
|
||||
public override bool VerifyRationality(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
return item != null && collection.All(t => t.Id != item.Id) && PixivHelper.VerifyIllust(Settings.Global.ExcludeTag, Settings.Global.IncludeTag, Settings.Global.MinBookmark, item);
|
||||
}
|
||||
|
||||
public override void InsertionPolicy(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
|
||||
public override IAsyncEnumerator<Illustration> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new RankingAsyncEnumerator(this, rankOption, dateTime);
|
||||
}
|
||||
|
||||
private class RankingAsyncEnumerator : AbstractPixivAsyncEnumerator<Illustration>
|
||||
{
|
||||
private readonly string dateTimeParameter;
|
||||
private readonly string rankOptionParameter;
|
||||
private RankingResponse entity;
|
||||
|
||||
private IEnumerator<Illustration> illustrationEnumerator;
|
||||
|
||||
public RankingAsyncEnumerator(IPixivAsyncEnumerable<Illustration> enumerable, RankOption rankOption, DateTime dateTime) : base(enumerable)
|
||||
{
|
||||
rankOptionParameter = rankOption.GetEnumAttribute<EnumAlias>().AliasAs;
|
||||
dateTimeParameter = dateTime.ToString("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
public override Illustration Current => illustrationEnumerator.Current;
|
||||
|
||||
protected override void UpdateEnumerator()
|
||||
{
|
||||
illustrationEnumerator = entity.Illusts.NonNull().Select(_ => _.Parse()).GetEnumerator();
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
if (await TryGetResponse($"/v1/illust/ranking?filter=for_android&mode={rankOptionParameter}&date={dateTimeParameter}") is (true, var result))
|
||||
{
|
||||
entity = result;
|
||||
UpdateEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
|
||||
Enumerable.ReportRequestedPages();
|
||||
}
|
||||
|
||||
if (illustrationEnumerator.MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entity.NextUrl.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await TryGetResponse(entity.NextUrl) is (true, var model))
|
||||
{
|
||||
entity = model;
|
||||
UpdateEnumerator();
|
||||
Enumerable.ReportRequestedPages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponse<RankingResponse>> TryGetResponse(string url)
|
||||
{
|
||||
var result = (await HttpClientFactory.AppApiHttpClient().GetStringAsync(url)).FromJson<RankingResponse>();
|
||||
|
||||
if (result is { } response && !response.Illusts.IsNullOrEmpty())
|
||||
{
|
||||
return HttpResponse<RankingResponse>.Wrap(true, response);
|
||||
}
|
||||
return HttpResponse<RankingResponse>.Wrap(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
139
Pixeval/Core/RecommendAsyncEnumerable.cs
Normal file
139
Pixeval/Core/RecommendAsyncEnumerable.cs
Normal file
@ -0,0 +1,139 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Pixeval.Persisting;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public abstract class AbstractRecommendAsyncEnumerable : AbstractPixivAsyncEnumerable<Illustration>
|
||||
{
|
||||
public override int RequestedPages { get; protected set; }
|
||||
|
||||
public abstract override void InsertionPolicy(Illustration item, IList<Illustration> collection);
|
||||
|
||||
public override bool VerifyRationality(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
return item != null && collection.All(t => t.Id != item.Id) && PixivHelper.VerifyIllust(Settings.Global.ExcludeTag, Settings.Global.IncludeTag, Settings.Global.MinBookmark, item);
|
||||
}
|
||||
|
||||
public override IAsyncEnumerator<Illustration> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new RecommendAsyncEnumerator(this);
|
||||
}
|
||||
|
||||
private class RecommendAsyncEnumerator : AbstractPixivAsyncEnumerator<Illustration>
|
||||
{
|
||||
private RecommendResponse entity;
|
||||
|
||||
private IEnumerator<Illustration> illustrationEnumerator;
|
||||
|
||||
public RecommendAsyncEnumerator(IPixivAsyncEnumerable<Illustration> enumerable) : base(enumerable)
|
||||
{
|
||||
}
|
||||
|
||||
public override Illustration Current => illustrationEnumerator.Current;
|
||||
|
||||
protected override void UpdateEnumerator()
|
||||
{
|
||||
illustrationEnumerator = entity.Illusts.NonNull().Select(_ => _.Parse()).GetEnumerator();
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
if (await TryGetResponse("/v1/illust/recommended") is (true, var model))
|
||||
{
|
||||
entity = model;
|
||||
UpdateEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
|
||||
Enumerable.ReportRequestedPages();
|
||||
}
|
||||
|
||||
if (illustrationEnumerator.MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entity.NextUrl.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await TryGetResponse(entity.NextUrl) is (true, var res))
|
||||
{
|
||||
entity = res;
|
||||
UpdateEnumerator();
|
||||
Enumerable.ReportRequestedPages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponse<RecommendResponse>> TryGetResponse(string url)
|
||||
{
|
||||
var res = (await HttpClientFactory.AppApiHttpClient().GetStringAsync(url)).FromJson<RecommendResponse>();
|
||||
if (res is { } response && !response.Illusts.IsNullOrEmpty())
|
||||
{
|
||||
return HttpResponse<RecommendResponse>.Wrap(true, response);
|
||||
}
|
||||
|
||||
return HttpResponse<RecommendResponse>.Wrap(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PopularityRecommendAsyncEnumerable : AbstractRecommendAsyncEnumerable
|
||||
{
|
||||
public override void InsertionPolicy(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
collection.AddSorted(item, IllustrationPopularityComparator.Instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PlainRecommendAsyncEnumerable : AbstractRecommendAsyncEnumerable
|
||||
{
|
||||
public override void InsertionPolicy(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
71
Pixeval/Core/RecommendIllustratorDeferrer.cs
Normal file
71
Pixeval/Core/RecommendIllustratorDeferrer.cs
Normal file
@ -0,0 +1,71 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Request;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class RecommendIllustratorDeferrer
|
||||
{
|
||||
public static readonly RecommendIllustratorDeferrer Instance = new RecommendIllustratorDeferrer();
|
||||
|
||||
private readonly List<User> currentIllustrators = new List<User>();
|
||||
|
||||
private int index;
|
||||
|
||||
private int requestTimes;
|
||||
|
||||
public async Task<IEnumerable<User>> Acquire(int count)
|
||||
{
|
||||
if (30 % count != 0)
|
||||
{
|
||||
throw new ArgumentException("count must be divisible by 30");
|
||||
}
|
||||
|
||||
if (currentIllustrators.Count < index + count)
|
||||
{
|
||||
if (requestTimes >= 9)
|
||||
{
|
||||
index = 0;
|
||||
requestTimes = 0;
|
||||
currentIllustrators.Clear();
|
||||
}
|
||||
|
||||
await Request();
|
||||
}
|
||||
|
||||
var illustrators = currentIllustrators.Skip(index).Take(count);
|
||||
index += count;
|
||||
return illustrators;
|
||||
}
|
||||
|
||||
private async Task Request()
|
||||
{
|
||||
var newIllustrators = await HttpClientFactory.AppApiService().GetRecommendIllustrators(new RecommendIllustratorRequest { Offset = requestTimes++ * 30 });
|
||||
currentIllustrators.AddRange(newIllustrators.UserPreviews.Select(i => i.Parse()));
|
||||
}
|
||||
}
|
||||
}
|
27
Pixeval/Core/RestrictPolicy.cs
Normal file
27
Pixeval/Core/RestrictPolicy.cs
Normal file
@ -0,0 +1,27 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public enum RestrictPolicy
|
||||
{
|
||||
Public, Private
|
||||
}
|
||||
}
|
48
Pixeval/Core/SearchTagMatchOption.cs
Normal file
48
Pixeval/Core/SearchTagMatchOption.cs
Normal file
@ -0,0 +1,48 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public enum SearchTagMatchOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 部分一致
|
||||
/// </summary>
|
||||
[EnumAlias("partial_match_for_tags")]
|
||||
[EnumLocalizedName("TagMatchingPartialMatch")]
|
||||
PartialMatchForTags,
|
||||
|
||||
/// <summary>
|
||||
/// 完全一致
|
||||
/// </summary>
|
||||
[EnumAlias("exact_match_for_tags")]
|
||||
[EnumLocalizedName("TagMatchingExactMatch")]
|
||||
ExactMatchForTags,
|
||||
|
||||
/// <summary>
|
||||
/// 标题和说明文
|
||||
/// </summary>
|
||||
[EnumAlias("title_and_caption")]
|
||||
[EnumLocalizedName("TagMatchingTitleAndCaption")]
|
||||
TitleAndCaption
|
||||
}
|
||||
}
|
121
Pixeval/Core/SpotlightQueryAsyncEnumerable.cs
Normal file
121
Pixeval/Core/SpotlightQueryAsyncEnumerable.cs
Normal file
@ -0,0 +1,121 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class SpotlightQueryAsyncEnumerable : AbstractPixivAsyncEnumerable<SpotlightArticle>
|
||||
{
|
||||
private readonly int start;
|
||||
|
||||
public SpotlightQueryAsyncEnumerable(int start)
|
||||
{
|
||||
this.start = start < 1 ? 1 : start;
|
||||
}
|
||||
|
||||
public override int RequestedPages { get; protected set; }
|
||||
|
||||
public override IAsyncEnumerator<SpotlightArticle> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new SpotlightArticleAsyncEnumerator(this, start);
|
||||
}
|
||||
|
||||
private class SpotlightArticleAsyncEnumerator : AbstractPixivAsyncEnumerator<SpotlightArticle>
|
||||
{
|
||||
private int current;
|
||||
|
||||
private SpotlightResponse entity;
|
||||
|
||||
private IEnumerator<SpotlightArticle> spotlightArticleEnumerator;
|
||||
|
||||
public SpotlightArticleAsyncEnumerator(IPixivAsyncEnumerable<SpotlightArticle> enumerable, int current) : base(enumerable)
|
||||
{
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
public override SpotlightArticle Current => spotlightArticleEnumerator.Current;
|
||||
|
||||
protected override void UpdateEnumerator()
|
||||
{
|
||||
spotlightArticleEnumerator = entity.SpotlightArticles.NonNull().GetEnumerator();
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
if (await TryGetResponse() is (true, var model))
|
||||
{
|
||||
entity = model;
|
||||
UpdateEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
|
||||
Enumerable.ReportRequestedPages();
|
||||
}
|
||||
|
||||
if (spotlightArticleEnumerator.MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entity.NextUrl.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await TryGetResponse() is (true, var res))
|
||||
{
|
||||
entity = res;
|
||||
UpdateEnumerator();
|
||||
Enumerable.ReportRequestedPages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<HttpResponse<SpotlightResponse>> TryGetResponse()
|
||||
{
|
||||
var res = await HttpClientFactory.AppApiService().GetSpotlights(current++ * 10);
|
||||
|
||||
if (res is { } response && !response.SpotlightArticles.IsNullOrEmpty())
|
||||
{
|
||||
return HttpResponse<SpotlightResponse>.Wrap(true, response);
|
||||
}
|
||||
|
||||
return HttpResponse<SpotlightResponse>.Wrap(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
253
Pixeval/Core/TrendsAsyncEnumerable.cs
Normal file
253
Pixeval/Core/TrendsAsyncEnumerable.cs
Normal file
@ -0,0 +1,253 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is piece of shit
|
||||
/// </summary>
|
||||
public class TrendsAsyncEnumerable : AbstractPixivAsyncEnumerable<Trends>
|
||||
{
|
||||
public override int RequestedPages { get; protected set; }
|
||||
|
||||
public override IAsyncEnumerator<Trends> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new TrendsAsyncEnumerator(this);
|
||||
}
|
||||
|
||||
private class TrendsAsyncEnumerator : AbstractPixivAsyncEnumerator<Trends>
|
||||
{
|
||||
private TrendsRequestContext requestContext;
|
||||
private IEnumerator<Trends> trendsEnumerable;
|
||||
private string tt;
|
||||
|
||||
public TrendsAsyncEnumerator(IPixivAsyncEnumerable<Trends> enumerable) : base(enumerable)
|
||||
{
|
||||
}
|
||||
|
||||
public override Trends Current => trendsEnumerable.Current;
|
||||
|
||||
public override async ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (requestContext == null)
|
||||
{
|
||||
if (await GetResponse(BuildRequestUrl()) is (true, var result))
|
||||
{
|
||||
tt = Regex.Match(result, "tt: \"(?<tt>.*)\"").Groups["tt"].Value;
|
||||
trendsEnumerable = (await ParsePreloadJsonFromHtml(result)).NonNull().GetEnumerator();
|
||||
requestContext = ExtractRequestParametersFromHtml(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
|
||||
Enumerable.ReportRequestedPages();
|
||||
}
|
||||
|
||||
if (trendsEnumerable.MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (requestContext.IsLastPage)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await GetResponse(BuildRequestUrl()) is (true, var json))
|
||||
{
|
||||
trendsEnumerable = (await ParseRawJson(json)).NonNull().GetEnumerator();
|
||||
requestContext = ExtractRequestParametersFromRawJson(json);
|
||||
Enumerable.ReportRequestedPages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string BuildRequestUrl()
|
||||
{
|
||||
return requestContext == null ? "/stacc?mode=unify" : $"/stacc/my/home/all/activity/{requestContext.Sid}/.json?mode={requestContext.Mode}&unify_token={requestContext.UnifyToken}&tt={tt}";
|
||||
}
|
||||
|
||||
private static TrendsRequestContext ExtractRequestParametersFromHtml(string html)
|
||||
{
|
||||
var json = JObject.Parse(ExtractPreloadJsonSnippet(html));
|
||||
return new TrendsRequestContext
|
||||
{
|
||||
Mode = json["param"]?["mode"]?.Value<string>(),
|
||||
UnifyToken = json["param"]?["unify_token"]?.Value<string>(),
|
||||
Sid = json["next_max_sid"]?.Value<long>().ToString(),
|
||||
IsLastPage = json["is_last_page"]?.Value<int>() == 1
|
||||
};
|
||||
}
|
||||
|
||||
private static TrendsRequestContext ExtractRequestParametersFromRawJson(string json)
|
||||
{
|
||||
var obj = JObject.Parse(json);
|
||||
return new TrendsRequestContext
|
||||
{
|
||||
Mode = obj["stacc"]?["param"]?["mode"]?.Value<string>(),
|
||||
UnifyToken = obj["stacc"]?["param"]?["unify_token"]?.Value<string>(),
|
||||
Sid = obj["stacc"]?["next_max_sid"]?.Value<long>().ToString(),
|
||||
IsLastPage = obj["stacc"]?["is_last_page"]?.Value<int>() == 1
|
||||
};
|
||||
}
|
||||
|
||||
private static Task<IEnumerable<Trends>> ParsePreloadJsonFromHtml(string html)
|
||||
{
|
||||
return ParsePreloadJson(ExtractPreloadJsonSnippet(html));
|
||||
}
|
||||
|
||||
private static string ExtractPreloadJsonSnippet(string html)
|
||||
{
|
||||
var match = Regex.Match(html, "pixiv\\.stacc\\.env\\.preload\\.stacc \\= (?<json>.*);");
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
return match.Groups["json"].Value;
|
||||
}
|
||||
|
||||
private static Task<IEnumerable<Trends>> ParseRawJson(string json)
|
||||
{
|
||||
var stacc = JObject.Parse(json)["stacc"]?.ToString();
|
||||
return ParsePreloadJson(stacc);
|
||||
}
|
||||
|
||||
private static async Task<IEnumerable<Trends>> ParsePreloadJson(string json)
|
||||
{
|
||||
var tasks = new List<Task<Trends>>();
|
||||
var stacc = JObject.Parse(json);
|
||||
var status = stacc["status"];
|
||||
var timeline = stacc["timeline"];
|
||||
var user = stacc["user"];
|
||||
var illust = stacc["illust"];
|
||||
foreach (var timelineChild in timeline!)
|
||||
{
|
||||
var task = Task.Run(() =>
|
||||
{
|
||||
var timelineProp = timelineChild.First;
|
||||
var statusObj = status?.FirstOrDefault(sChild => sChild.First?["id"]?.Value<string>() == timelineProp?["id"]?.Value<string>());
|
||||
if (statusObj?.First == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var statusObjProp = statusObj.First;
|
||||
var trendsObj = new Trends
|
||||
{
|
||||
PostDate = DateTime.Parse(statusObjProp?["post_date"]?.Value<string>()!, CultureInfo.CurrentCulture),
|
||||
PostUserId = statusObjProp["post_user"]?["id"]?.Value<string>(),
|
||||
TrendObjectId = statusObjProp["type"]?.Value<string>() switch
|
||||
{
|
||||
var type when type == "add_illust" || type == "add_bookmark" => statusObjProp["ref_illust"]?["id"]?.Value<string>(),
|
||||
"add_favorite" => statusObjProp["ref_user"]?["id"]?.Value<string>(),
|
||||
_ => null
|
||||
}
|
||||
};
|
||||
var matchingPostUser = user?.FirstOrDefault(uChild => uChild.First?["id"]?.Value<string>() == trendsObj.PostUserId);
|
||||
if (matchingPostUser != null)
|
||||
{
|
||||
trendsObj.PostUserThumbnail = matchingPostUser.First?["profile_image"]?.First?.First?["url"]?["m"]?.Value<string>();
|
||||
trendsObj.PostUserName = matchingPostUser.First?["name"]?.Value<string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
trendsObj.Type = statusObjProp["type"]?.Value<string>() switch
|
||||
{
|
||||
"add_illust" => TrendType.AddIllust,
|
||||
"add_bookmark" => TrendType.AddBookmark,
|
||||
"add_favorite" => TrendType.AddFavorite,
|
||||
_ => (TrendType) (-1)
|
||||
};
|
||||
trendsObj.TrendObjectThumbnail = trendsObj.Type switch
|
||||
{
|
||||
var type when type == TrendType.AddBookmark || type == TrendType.AddIllust => illust?.FirstOrDefault(iChild => iChild.First?["id"]?.Value<string>() == trendsObj.TrendObjectId)?.First?["url"]?["m"]?.Value<string>(),
|
||||
TrendType.AddFavorite => user.FirstOrDefault(uChild => uChild.First?["id"]?.Value<string>() == trendsObj.TrendObjectId)?.First?["profile_image"]?.First?.First?["url"]?["s"]?.Value<string>(),
|
||||
(TrendType) (-1) => null,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
if (trendsObj.Type != TrendType.AddFavorite)
|
||||
{
|
||||
var illustration = illust.FirstOrDefault(iChild => iChild.First?["id"]?.Value<string>() == trendsObj.TrendObjectId);
|
||||
if (illustration != null)
|
||||
{
|
||||
trendsObj.ByName = user.FirstOrDefault(uChild => uChild.First?["id"]?.Value<string>() == illustration.First?["post_user"]?["id"]?.Value<string>())?.First["name"].Value<string>();
|
||||
trendsObj.TrendObjName = illustration.First["title"].Value<string>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trendsObj.TrendObjName = user.FirstOrDefault(uChild => uChild.First?["id"]?.Value<string>() == trendsObj.TrendObjectId)?.First["name"].Value<string>();
|
||||
trendsObj.IsReferToUser = true;
|
||||
}
|
||||
|
||||
return trendsObj;
|
||||
});
|
||||
tasks.Add(task);
|
||||
}
|
||||
|
||||
return await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
protected override void UpdateEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static async Task<HttpResponse<string>> GetResponse(string url)
|
||||
{
|
||||
var result = await HttpClientFactory.WebApiHttpClient().GetStringAsync(url);
|
||||
return !result.IsNullOrEmpty() ? HttpResponse<string>.Wrap(true, result) : HttpResponse<string>.Wrap(false);
|
||||
}
|
||||
}
|
||||
|
||||
private class TrendsRequestContext
|
||||
{
|
||||
public string UnifyToken { get; set; }
|
||||
|
||||
public string Sid { get; set; }
|
||||
|
||||
public string Mode { get; set; }
|
||||
|
||||
public bool IsLastPage { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
136
Pixeval/Core/UploadAsyncEnumerable.cs
Normal file
136
Pixeval/Core/UploadAsyncEnumerable.cs
Normal file
@ -0,0 +1,136 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Pixeval.Persisting;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class UploadAsyncEnumerable : AbstractPixivAsyncEnumerable<Illustration>
|
||||
{
|
||||
private readonly string uid;
|
||||
|
||||
public UploadAsyncEnumerable(string uid)
|
||||
{
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
public override int RequestedPages { get; protected set; }
|
||||
|
||||
public override void InsertionPolicy(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
collection.AddSorted(item, IllustrationPublishDateComparator.Instance);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool VerifyRationality(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
return item != null && collection.All(t => t.Id != item.Id) && PixivHelper.VerifyIllust(Settings.Global.ExcludeTag, Settings.Global.IncludeTag, Settings.Global.MinBookmark, item);
|
||||
}
|
||||
|
||||
public override IAsyncEnumerator<Illustration> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new UploadAsyncEnumerator(this, uid);
|
||||
}
|
||||
|
||||
private class UploadAsyncEnumerator : AbstractPixivAsyncEnumerator<Illustration>
|
||||
{
|
||||
private readonly string uid;
|
||||
|
||||
private UploadResponse entity;
|
||||
|
||||
private IEnumerator<Illustration> illustrationEnumerator;
|
||||
|
||||
public UploadAsyncEnumerator(IPixivAsyncEnumerable<Illustration> enumerable, string uid) : base(enumerable)
|
||||
{
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
public override Illustration Current => illustrationEnumerator.Current;
|
||||
|
||||
protected override void UpdateEnumerator()
|
||||
{
|
||||
illustrationEnumerator = entity.Illusts.NonNull().Select(_ => _.Parse()).GetEnumerator();
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
if (await TryGetResponse($"/v1/user/illusts?user_id={uid}&filter=for_android&type=illust") is (true, var model))
|
||||
{
|
||||
entity = model;
|
||||
UpdateEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
|
||||
Enumerable.ReportRequestedPages();
|
||||
}
|
||||
|
||||
if (illustrationEnumerator.MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entity.NextUrl.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await TryGetResponse(entity.NextUrl) is (true, var res))
|
||||
{
|
||||
entity = res;
|
||||
UpdateEnumerator();
|
||||
Enumerable.ReportRequestedPages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponse<UploadResponse>> TryGetResponse(string url)
|
||||
{
|
||||
var res = (await HttpClientFactory.AppApiHttpClient().GetStringAsync(url)).FromJson<UploadResponse>();
|
||||
if (res is { } response && !response.Illusts.IsNullOrEmpty())
|
||||
{
|
||||
return HttpResponse<UploadResponse>.Wrap(true, response);
|
||||
}
|
||||
|
||||
return HttpResponse<UploadResponse>.Wrap(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
166
Pixeval/Core/UserFollowingAsyncEnumerable.cs
Normal file
166
Pixeval/Core/UserFollowingAsyncEnumerable.cs
Normal file
@ -0,0 +1,166 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public abstract class AbstractUserFollowingAsyncEnumerable : AbstractPixivAsyncEnumerable<User>
|
||||
{
|
||||
protected abstract string Uid { get; }
|
||||
|
||||
protected abstract RestrictPolicy RestrictPolicy { get; }
|
||||
|
||||
public override int RequestedPages { get; protected set; }
|
||||
|
||||
public override IAsyncEnumerator<User> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new UserFollowingAsyncEnumerator(this, Uid, RestrictPolicy);
|
||||
}
|
||||
|
||||
public static AbstractUserFollowingAsyncEnumerable Of(string uid, RestrictPolicy restrictPolicy)
|
||||
{
|
||||
return restrictPolicy switch
|
||||
{
|
||||
RestrictPolicy.Public => new PublicUserFollowingAsyncEnumerable(uid),
|
||||
RestrictPolicy.Private => new PrivateUserFollowingAsyncEnumerable(uid),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(restrictPolicy), restrictPolicy, null)
|
||||
};
|
||||
}
|
||||
|
||||
private class UserFollowingAsyncEnumerator : AbstractPixivAsyncEnumerator<User>
|
||||
{
|
||||
private readonly RestrictPolicy restrictPolicy;
|
||||
private readonly string userId;
|
||||
|
||||
private FollowingResponse entity;
|
||||
|
||||
private IEnumerator<User> followerEnumerator;
|
||||
|
||||
public UserFollowingAsyncEnumerator(IPixivAsyncEnumerable<User> enumerable, string userId, RestrictPolicy restrictPolicy) : base(enumerable)
|
||||
{
|
||||
this.userId = userId;
|
||||
this.restrictPolicy = restrictPolicy;
|
||||
}
|
||||
|
||||
public override User Current => followerEnumerator.Current;
|
||||
|
||||
protected override void UpdateEnumerator()
|
||||
{
|
||||
followerEnumerator = entity.UserPreviews.NonNull().Select(u => new User
|
||||
{
|
||||
Thumbnails = u.Illusts.NonNull().Select(_ => _.ImageUrls.SquareMedium).ToArray(),
|
||||
Id = u.User.Id.ToString(),
|
||||
Name = u.User.Name,
|
||||
Avatar = u.User.ProfileImageUrls.Medium
|
||||
}).GetEnumerator();
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
if (await TryGetResponse(restrictPolicy switch
|
||||
{
|
||||
RestrictPolicy.Public => $"/v1/user/following?user_id={userId}&restrict=public",
|
||||
RestrictPolicy.Private => $"/v1/user/following?user_id={userId}&restrict=private",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
}) is (true, var model))
|
||||
{
|
||||
entity = model;
|
||||
UpdateEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
|
||||
Enumerable.ReportRequestedPages();
|
||||
}
|
||||
|
||||
if (followerEnumerator.MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entity.NextUrl.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await TryGetResponse(entity.NextUrl) is (true, var res))
|
||||
{
|
||||
entity = res;
|
||||
UpdateEnumerator();
|
||||
Enumerable.ReportRequestedPages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponse<FollowingResponse>> TryGetResponse(string url)
|
||||
{
|
||||
var res = (await HttpClientFactory.AppApiHttpClient().GetStringAsync(url)).FromJson<FollowingResponse>();
|
||||
if (res is { } response && !response.UserPreviews.IsNullOrEmpty())
|
||||
{
|
||||
return HttpResponse<FollowingResponse>.Wrap(true, response);
|
||||
}
|
||||
|
||||
return HttpResponse<FollowingResponse>.Wrap(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PublicUserFollowingAsyncEnumerable : AbstractUserFollowingAsyncEnumerable
|
||||
{
|
||||
public PublicUserFollowingAsyncEnumerable(string uid)
|
||||
{
|
||||
Uid = uid;
|
||||
}
|
||||
|
||||
protected override string Uid { get; }
|
||||
|
||||
protected override RestrictPolicy RestrictPolicy { get; } = RestrictPolicy.Public;
|
||||
}
|
||||
|
||||
public class PrivateUserFollowingAsyncEnumerable : AbstractUserFollowingAsyncEnumerable
|
||||
{
|
||||
public PrivateUserFollowingAsyncEnumerable(string uid)
|
||||
{
|
||||
Uid = uid;
|
||||
}
|
||||
|
||||
protected override string Uid { get; }
|
||||
|
||||
protected override RestrictPolicy RestrictPolicy { get; } = RestrictPolicy.Private;
|
||||
}
|
||||
}
|
126
Pixeval/Core/UserPreviewAsyncEnumerable.cs
Normal file
126
Pixeval/Core/UserPreviewAsyncEnumerable.cs
Normal file
@ -0,0 +1,126 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class UserPreviewAsyncEnumerable : AbstractPixivAsyncEnumerable<User>
|
||||
{
|
||||
private readonly string keyword;
|
||||
|
||||
public UserPreviewAsyncEnumerable(string keyword)
|
||||
{
|
||||
this.keyword = keyword;
|
||||
}
|
||||
|
||||
public override int RequestedPages { get; protected set; }
|
||||
|
||||
public override IAsyncEnumerator<User> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new UserPreviewAsyncEnumerator(this, keyword);
|
||||
}
|
||||
|
||||
private class UserPreviewAsyncEnumerator : AbstractPixivAsyncEnumerator<User>
|
||||
{
|
||||
private readonly string keyword;
|
||||
private UserNavResponse entity;
|
||||
|
||||
private IEnumerator<User> userPreviewEnumerator;
|
||||
|
||||
public UserPreviewAsyncEnumerator(IPixivAsyncEnumerable<User> enumerable, string keyword) : base(enumerable)
|
||||
{
|
||||
this.keyword = keyword;
|
||||
}
|
||||
|
||||
public override User Current => userPreviewEnumerator.Current;
|
||||
|
||||
protected override void UpdateEnumerator()
|
||||
{
|
||||
userPreviewEnumerator = entity.UserPreviews.NonNull().Select(u => new User
|
||||
{
|
||||
Avatar = u.User.ProfileImageUrls.Medium,
|
||||
Thumbnails = u.Illusts.NonNull().Select(_ => _.ImageUrl.SquareMedium).ToArray(),
|
||||
Id = u.User.Id.ToString(),
|
||||
Name = u.User.Name
|
||||
}).GetEnumerator();
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
if (await TryGetResponse($"https://app-api.pixiv.net/v1/search/user?filter=for_android&word={keyword}") is (true, var model))
|
||||
{
|
||||
entity = model;
|
||||
UpdateEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
|
||||
Enumerable.ReportRequestedPages();
|
||||
}
|
||||
|
||||
if (userPreviewEnumerator.MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entity.NextUrl.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await TryGetResponse(entity.NextUrl) is (true, var res))
|
||||
{
|
||||
entity = res;
|
||||
UpdateEnumerator();
|
||||
Enumerable.ReportRequestedPages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponse<UserNavResponse>> TryGetResponse(string url)
|
||||
{
|
||||
var res = (await HttpClientFactory.AppApiHttpClient().GetStringAsync(url)).FromJson<UserNavResponse>();
|
||||
if (res is { } response && !response.UserPreviews.IsNullOrEmpty())
|
||||
{
|
||||
return HttpResponse<UserNavResponse>.Wrap(true, response);
|
||||
}
|
||||
|
||||
return HttpResponse<UserNavResponse>.Wrap(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
118
Pixeval/Core/UserUpdateAsyncEnumerable.cs
Normal file
118
Pixeval/Core/UserUpdateAsyncEnumerable.cs
Normal file
@ -0,0 +1,118 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Data.Web;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Pixeval.Persisting;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
public class UserUpdateAsyncEnumerable : AbstractPixivAsyncEnumerable<Illustration>
|
||||
{
|
||||
public override int RequestedPages { get; protected set; }
|
||||
|
||||
public override IAsyncEnumerator<Illustration> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new UserUpdateAsyncEnumerator(this);
|
||||
}
|
||||
|
||||
public override bool VerifyRationality(Illustration item, IList<Illustration> collection)
|
||||
{
|
||||
return item != null && collection.All(t => t.Id != item.Id) && PixivHelper.VerifyIllust(Settings.Global.ExcludeTag, Settings.Global.IncludeTag, Settings.Global.MinBookmark, item);
|
||||
}
|
||||
|
||||
private class UserUpdateAsyncEnumerator : AbstractPixivAsyncEnumerator<Illustration>
|
||||
{
|
||||
private UserUpdateResponse entity;
|
||||
|
||||
private IEnumerator<Illustration> illustrationEnumerator;
|
||||
|
||||
public UserUpdateAsyncEnumerator(IPixivAsyncEnumerable<Illustration> enumerable) : base(enumerable)
|
||||
{
|
||||
}
|
||||
|
||||
public override Illustration Current => illustrationEnumerator.Current;
|
||||
|
||||
protected override void UpdateEnumerator()
|
||||
{
|
||||
illustrationEnumerator = entity.Illusts.NonNull().Select(_ => _.Parse()).GetEnumerator();
|
||||
}
|
||||
|
||||
public override async ValueTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
if (await TryGetResponse("https://app-api.pixiv.net/v2/illust/follow?restrict=public") is (true, var model))
|
||||
{
|
||||
entity = model;
|
||||
UpdateEnumerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new QueryNotRespondingException();
|
||||
}
|
||||
|
||||
Enumerable.ReportRequestedPages();
|
||||
}
|
||||
|
||||
if (illustrationEnumerator.MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entity.NextUrl.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (await TryGetResponse(entity.NextUrl) is (true, var res))
|
||||
{
|
||||
entity = res;
|
||||
UpdateEnumerator();
|
||||
Enumerable.ReportRequestedPages();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponse<UserUpdateResponse>> TryGetResponse(string url)
|
||||
{
|
||||
var res = (await HttpClientFactory.AppApiHttpClient().GetStringAsync(url)).FromJson<UserUpdateResponse>();
|
||||
if (res is { } response && !response.Illusts.IsNullOrEmpty())
|
||||
{
|
||||
return HttpResponse<UserUpdateResponse>.Wrap(true, response);
|
||||
}
|
||||
|
||||
return HttpResponse<UserUpdateResponse>.Wrap(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
137
Pixeval/Core/WindowsUserActivityManager.cs
Normal file
137
Pixeval/Core/WindowsUserActivityManager.cs
Normal file
@ -0,0 +1,137 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.UserActivities;
|
||||
using Windows.UI.Shell;
|
||||
using AdaptiveCards;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Objects.Generic;
|
||||
|
||||
namespace Pixeval.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a set of functions to create a Windows 10 Timeline Activity,
|
||||
/// for more information and underlying implementation, see
|
||||
/// <a href="https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/modernize-wpf-tutorial-4" />
|
||||
/// </summary>
|
||||
public class WindowsUserActivityManager : ITimelineService
|
||||
{
|
||||
public static readonly WindowsUserActivityManager GlobalLifeTimeScope = new WindowsUserActivityManager();
|
||||
private readonly Uri iconUri = new Uri("http://qa23pqcql.bkt.clouddn.com/pxlogo.ico");
|
||||
private UserActivitySession userActivitySession;
|
||||
|
||||
public bool VerifyRationality(BrowsingHistory browsingHistory)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public async void Insert(BrowsingHistory browsingHistory)
|
||||
{
|
||||
var userActivityChannel = UserActivityChannel.GetDefault();
|
||||
var model = await GetPixevalTimelineModel(browsingHistory);
|
||||
var userActivity = await userActivityChannel.GetOrCreateUserActivityAsync($"Pixeval-{model.Id}-{DateTime.Now:s}");
|
||||
userActivity.VisualElements.DisplayText = model.Title;
|
||||
userActivity.VisualElements.Content = AdaptiveCardBuilder.CreateAdaptiveCardFromJson(BuildAdaptiveCard(model));
|
||||
userActivity.VisualElements.Attribution = new UserActivityAttribution(iconUri);
|
||||
userActivity.VisualElements.AttributionDisplayText = "Pixeval";
|
||||
userActivity.ActivationUri = new Uri(browsingHistory.Type switch
|
||||
{
|
||||
"illust" => $"pixeval://www.pixiv.net/artworks/{model.Id}",
|
||||
"user" => $"pixeval://www.pixiv.net/users/{model.Id}",
|
||||
"spotlight" => $"pixeval://www.pixivision.net/en/a/{model.Id}",
|
||||
_ => throw new ArgumentException(nameof(browsingHistory.Type))
|
||||
});
|
||||
await userActivity.SaveAsync();
|
||||
userActivitySession?.Dispose();
|
||||
userActivitySession = userActivity.CreateSession();
|
||||
}
|
||||
|
||||
private static async Task<PixevalTimelineModel> GetPixevalTimelineModel(BrowsingHistory history)
|
||||
{
|
||||
var p = new PixevalTimelineModel { Background = await PixivIO.GetResizedBase64UriOfImageFromUrl(history.BrowseObjectThumbnail), Id = history.BrowseObjectId, Title = history.BrowseObjectState };
|
||||
switch (history.Type)
|
||||
{
|
||||
case "illust":
|
||||
p.Author = history.IllustratorName;
|
||||
return p;
|
||||
case "user":
|
||||
case "spotlight": return p;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(history.Type));
|
||||
}
|
||||
|
||||
private static string BuildAdaptiveCard(PixevalTimelineModel pixevalTimelineModel)
|
||||
{
|
||||
var card = new StringifyBackgroundAdaptiveCard("1.0") { StringifyUrl = pixevalTimelineModel.Background };
|
||||
card.Body.Add(new AdaptiveTextBlock
|
||||
{
|
||||
Text = pixevalTimelineModel.Title,
|
||||
Weight = AdaptiveTextWeight.Bolder,
|
||||
Wrap = true,
|
||||
Size = AdaptiveTextSize.Large,
|
||||
MaxLines = 3
|
||||
});
|
||||
if (!pixevalTimelineModel.Author.IsNullOrEmpty())
|
||||
{
|
||||
card.Body.Add(new AdaptiveTextBlock
|
||||
{
|
||||
Text = pixevalTimelineModel.Author,
|
||||
Weight = AdaptiveTextWeight.Bolder,
|
||||
Wrap = true,
|
||||
Size = AdaptiveTextSize.Small,
|
||||
MaxLines = 3,
|
||||
Spacing = AdaptiveSpacing.Small
|
||||
});
|
||||
}
|
||||
|
||||
return card.ToJson();
|
||||
}
|
||||
|
||||
private class PixevalTimelineModel
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string Author { get; set; }
|
||||
|
||||
public string Background { get; set; }
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/55663963/adaptive-cards-serving-images-in-bytes
|
||||
private class StringifyBackgroundAdaptiveCard : AdaptiveCard
|
||||
{
|
||||
public StringifyBackgroundAdaptiveCard(AdaptiveSchemaVersion schemaVersion) : base(schemaVersion)
|
||||
{
|
||||
}
|
||||
|
||||
public StringifyBackgroundAdaptiveCard(string schemaVersion) : base(schemaVersion)
|
||||
{
|
||||
}
|
||||
|
||||
[JsonProperty("backgroundImage")]
|
||||
public string StringifyUrl { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
27
Pixeval/Data/IParser.cs
Normal file
27
Pixeval/Data/IParser.cs
Normal file
@ -0,0 +1,27 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Pixeval.Data
|
||||
{
|
||||
public interface IParser<out T>
|
||||
{
|
||||
T Parse();
|
||||
}
|
||||
}
|
32
Pixeval/Data/ViewModel/AutoCompletion.cs
Normal file
32
Pixeval/Data/ViewModel/AutoCompletion.cs
Normal file
@ -0,0 +1,32 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class AutoCompletion
|
||||
{
|
||||
public string Tag { get; set; }
|
||||
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
}
|
58
Pixeval/Data/ViewModel/BrowsingHistory.cs
Normal file
58
Pixeval/Data/ViewModel/BrowsingHistory.cs
Normal file
@ -0,0 +1,58 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using PropertyChanged;
|
||||
using SQLite;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class BrowsingHistory
|
||||
{
|
||||
[PrimaryKey]
|
||||
[AutoIncrement]
|
||||
public int Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提供当前<see cref="BrowsingHistory"/>的<see cref="string"/>视图,默认的值是名称/标题
|
||||
/// </summary>
|
||||
public string BrowseObjectState { get; set; }
|
||||
|
||||
public string BrowseObjectThumbnail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="IsReferToIllust"/>有效仅当此属性有效
|
||||
/// </summary>
|
||||
public string IllustratorName { get; set; }
|
||||
|
||||
public bool IsReferToUser { get; set; }
|
||||
|
||||
public bool IsReferToIllust { get; set; }
|
||||
|
||||
public bool IsReferToSpotlight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提供当前<see cref="BrowsingHistory"/>的id的<see cref="string"/>视图,默认的值是作品ID/用户ID/特辑ID
|
||||
/// </summary>
|
||||
public string BrowseObjectId { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
}
|
||||
}
|
33
Pixeval/Data/ViewModel/ConditionString.cs
Normal file
33
Pixeval/Data/ViewModel/ConditionString.cs
Normal file
@ -0,0 +1,33 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class ConditionString
|
||||
{
|
||||
[DoNotNotify]
|
||||
public static ConditionString Shared = new ConditionString();
|
||||
|
||||
public string Condition { get; set; }
|
||||
}
|
||||
}
|
227
Pixeval/Data/ViewModel/DownloadableIllustration.cs
Normal file
227
Pixeval/Data/ViewModel/DownloadableIllustration.cs
Normal file
@ -0,0 +1,227 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Core;
|
||||
using Pixeval.Data.Web.Delegation;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class DownloadableIllustration
|
||||
{
|
||||
[DoNotNotify]
|
||||
private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
private bool modifiable = true;
|
||||
|
||||
private bool retried;
|
||||
|
||||
public DownloadableIllustration(Illustration downloadContent, IIllustrationFileNameFormatter fileNameFormatter, IDownloadPathProvider downloadPathProvider, bool isFromManga, int mangaIndex = -1)
|
||||
{
|
||||
DownloadContent = downloadContent;
|
||||
FileNameFormatter = fileNameFormatter;
|
||||
DownloadPathProvider = downloadPathProvider;
|
||||
IsFromManga = isFromManga;
|
||||
MangaIndex = mangaIndex;
|
||||
}
|
||||
|
||||
public Illustration DownloadContent { get; set; }
|
||||
|
||||
public IIllustrationFileNameFormatter FileNameFormatter { get; set; }
|
||||
|
||||
public IDownloadPathProvider DownloadPathProvider { get; set; }
|
||||
|
||||
public bool IsFromManga { get; set; }
|
||||
|
||||
public int MangaIndex { get; set; }
|
||||
|
||||
public bool DownloadFailed { get; set; }
|
||||
|
||||
public double Progress { get; set; }
|
||||
|
||||
public string ReasonPhase { get; set; }
|
||||
|
||||
public Observable<DownloadStateEnum> DownloadState { get; set; } = new Observable<DownloadStateEnum>(DownloadStateEnum.Queue);
|
||||
|
||||
public DownloadOption Option { get; set; }
|
||||
|
||||
public string GetPath()
|
||||
{
|
||||
if (DownloadContent.IsUgoira)
|
||||
{
|
||||
return Path.Combine(Directory.CreateDirectory(DownloadPathProvider.GetIllustrationPath(Option)).FullName, FileNameFormatter.FormatGif(DownloadContent));
|
||||
}
|
||||
if (DownloadContent.FromSpotlight)
|
||||
{
|
||||
return IsFromManga ? Path.Combine(Directory.CreateDirectory(DownloadPathProvider.GetSpotlightPath(DownloadContent.SpotlightTitle, Option)).FullName, DownloadContent.Id, FileNameFormatter.FormatManga(DownloadContent, MangaIndex)) : Path.Combine(Directory.CreateDirectory(DownloadPathProvider.GetSpotlightPath(DownloadContent.SpotlightTitle, Option)).FullName, FileNameFormatter.Format(DownloadContent));
|
||||
}
|
||||
return IsFromManga ? Path.Combine(Directory.CreateDirectory(DownloadPathProvider.GetMangaPath(DownloadContent.Id, Option)).FullName, FileNameFormatter.FormatManga(DownloadContent, MangaIndex)) : Path.Combine(Directory.CreateDirectory(DownloadPathProvider.GetIllustrationPath(Option)).FullName, FileNameFormatter.Format(DownloadContent));
|
||||
}
|
||||
|
||||
|
||||
public void Freeze()
|
||||
{
|
||||
modifiable = false;
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
if (modifiable)
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
Progress = 0;
|
||||
ReasonPhase = null;
|
||||
DownloadFailed = false;
|
||||
DownloadState.Value = DownloadStateEnum.Canceled;
|
||||
}
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
{
|
||||
if (modifiable)
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
Progress = 0;
|
||||
ReasonPhase = null;
|
||||
DownloadFailed = false;
|
||||
Download();
|
||||
}
|
||||
}
|
||||
|
||||
public async void Download()
|
||||
{
|
||||
if (!modifiable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadState.Value = DownloadStateEnum.Downloading;
|
||||
var downloadPath = GetPath();
|
||||
if (DownloadContent.IsUgoira)
|
||||
{
|
||||
DownloadGif();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await using var memory = await PixivIO.Download(DownloadContent.GetDownloadUrl(), new Progress<double>(d => Progress = d), cancellationTokenSource.Token);
|
||||
if (cancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await using var fileStream = new FileStream(downloadPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
|
||||
memory.WriteTo(fileStream);
|
||||
DownloadState.Value = DownloadStateEnum.Finished;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (downloadPath != null && File.Exists(downloadPath))
|
||||
{
|
||||
File.Delete(downloadPath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!retried)
|
||||
{
|
||||
Restart();
|
||||
retried = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleError(e, downloadPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void DownloadGif()
|
||||
{
|
||||
var downloadPath = GetPath();
|
||||
try
|
||||
{
|
||||
var metadata = await HttpClientFactory.AppApiService().GetUgoiraMetadata(DownloadContent.Id);
|
||||
var ugoiraUrl = metadata.UgoiraMetadataInfo.ZipUrls.Medium;
|
||||
ugoiraUrl = !ugoiraUrl.EndsWith("ugoira1920x1080.zip") ? Regex.Replace(ugoiraUrl, "ugoira(\\d+)x(\\d+).zip", "ugoira1920x1080.zip") : ugoiraUrl;
|
||||
var delay = metadata.UgoiraMetadataInfo.Frames.Select(f => f.Delay / 10).ToArray();
|
||||
if (cancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await using var memory = await PixivIO.Download(ugoiraUrl, new Progress<double>(d => Progress = d), cancellationTokenSource.Token);
|
||||
await using var gifStream = (MemoryStream) InternalIO.MergeGifStream(InternalIO.ReadGifZipEntries(memory), delay);
|
||||
if (cancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await using var fileStream = new FileStream(downloadPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
|
||||
gifStream.WriteTo(fileStream);
|
||||
DownloadState.Value = DownloadStateEnum.Finished;
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
if (downloadPath != null && File.Exists(downloadPath))
|
||||
{
|
||||
File.Delete(downloadPath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!retried)
|
||||
{
|
||||
Restart();
|
||||
retried = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleError(e, downloadPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleError(Exception e, string path)
|
||||
{
|
||||
DownloadState.Value = DownloadStateEnum.Exceptional;
|
||||
DownloadFailed = true;
|
||||
ReasonPhase = e.Message;
|
||||
if (path != null && File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DownloadStateEnum
|
||||
{
|
||||
Queue, Downloading, Exceptional, Finished, Canceled
|
||||
}
|
||||
}
|
46
Pixeval/Data/ViewModel/I18nOption.cs
Normal file
46
Pixeval/Data/ViewModel/I18nOption.cs
Normal file
@ -0,0 +1,46 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class I18NOption
|
||||
{
|
||||
public static readonly I18NOption UsEnglish = new I18NOption("English(US)", "en-us");
|
||||
|
||||
public static readonly I18NOption ChineseSimplified = new I18NOption("简体中文(中国)", "zh-cn");
|
||||
|
||||
public I18NOption(string localizedName, string name)
|
||||
{
|
||||
LocalizedName = localizedName;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public I18NOption()
|
||||
{
|
||||
}
|
||||
|
||||
public string LocalizedName { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
119
Pixeval/Data/ViewModel/Illustration.cs
Normal file
119
Pixeval/Data/ViewModel/Illustration.cs
Normal file
@ -0,0 +1,119 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class Illustration : ICloneable
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public bool IsUgoira { get; set; }
|
||||
|
||||
public bool IsR18 => Tags?.Any(x => Regex.IsMatch(x?.Name ?? string.Empty, "[Rr][-]?18[Gg]?") || Regex.IsMatch(x?.TranslatedName ?? string.Empty, "[Rr][-]?18[Gg]?")) ?? false;
|
||||
|
||||
public string Origin { get; set; }
|
||||
|
||||
public string Large { get; set; }
|
||||
|
||||
public string Thumbnail { get; set; }
|
||||
|
||||
public int Bookmark { get; set; }
|
||||
|
||||
public bool IsLiked { get; set; }
|
||||
|
||||
public bool IsManga { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string UserName { get; set; }
|
||||
|
||||
public string UserId { get; set; }
|
||||
|
||||
public IEnumerable<Tag> Tags { get; set; }
|
||||
|
||||
public Illustration[] MangaMetadata { get; set; }
|
||||
|
||||
public DateTimeOffset PublishDate { get; set; }
|
||||
|
||||
public int ViewCount { get; set; }
|
||||
|
||||
public string Resolution { get; set; }
|
||||
|
||||
public int Comments { get; set; }
|
||||
|
||||
public bool FromSpotlight { get; set; }
|
||||
|
||||
public string SpotlightTitle { get; set; }
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return MemberwiseClone();
|
||||
}
|
||||
|
||||
public string GetDownloadUrl()
|
||||
{
|
||||
return Origin.IsNullOrEmpty() ? Large : Origin;
|
||||
}
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
|
||||
public class IllustrationPopularityComparator : IComparer<Illustration>
|
||||
{
|
||||
public static readonly IllustrationPopularityComparator Instance = new IllustrationPopularityComparator();
|
||||
|
||||
public int Compare(Illustration x, Illustration y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return x.Bookmark < y.Bookmark ? 1 : x.Bookmark == y.Bookmark ? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
public class IllustrationPublishDateComparator : IComparer<Illustration>
|
||||
{
|
||||
public static readonly IllustrationPublishDateComparator Instance = new IllustrationPublishDateComparator();
|
||||
|
||||
public int Compare(Illustration x, Illustration y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return x.PublishDate < y.PublishDate ? 1 : x.PublishDate == y.PublishDate ? 0 : -1;
|
||||
}
|
||||
}
|
||||
}
|
60
Pixeval/Data/ViewModel/RankOptionModel.cs
Normal file
60
Pixeval/Data/ViewModel/RankOptionModel.cs
Normal file
@ -0,0 +1,60 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Pixeval.Core;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class RankOptionModel
|
||||
{
|
||||
[DoNotNotify]
|
||||
public static readonly RankOptionModel[] RegularRankOptions = Enum.GetValues(typeof(RankOption)).Cast<RankOption>().Select(rank => new RankOptionModel(rank)).ToArray().Apply(models => models[0].IsSelected = true);
|
||||
|
||||
[DoNotNotify]
|
||||
public static readonly DateTime MaxRankDateTime = DateTime.Today - TimeSpan.FromDays(2);
|
||||
|
||||
[DoNotNotify]
|
||||
public static readonly DateTime InvalidRankDateTimeStart = DateTime.Today - TimeSpan.FromDays(1);
|
||||
|
||||
public RankOptionModel(RankOption option)
|
||||
{
|
||||
Corresponding = option;
|
||||
Name = AkaI18N.GetResource(option.GetEnumAttribute<EnumLocalizedName>().Name);
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public bool IsSelected { get; set; }
|
||||
|
||||
public RankOption Corresponding { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
50
Pixeval/Data/ViewModel/SearchTagMatchOptionModel.cs
Normal file
50
Pixeval/Data/ViewModel/SearchTagMatchOptionModel.cs
Normal file
@ -0,0 +1,50 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Pixeval.Core;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class SearchTagMatchOptionModel
|
||||
{
|
||||
public static readonly SearchTagMatchOptionModel PartialMatchModel = new SearchTagMatchOptionModel(SearchTagMatchOption.PartialMatchForTags);
|
||||
|
||||
public static readonly SearchTagMatchOptionModel ExactMatchModel = new SearchTagMatchOptionModel(SearchTagMatchOption.ExactMatchForTags);
|
||||
|
||||
public static readonly SearchTagMatchOptionModel TitleAndCaptionModel = new SearchTagMatchOptionModel(SearchTagMatchOption.TitleAndCaption);
|
||||
|
||||
public static readonly IEnumerable<SearchTagMatchOptionModel> AllPossibleMatchOptions = new[] { PartialMatchModel, ExactMatchModel, TitleAndCaptionModel };
|
||||
|
||||
public SearchTagMatchOptionModel(SearchTagMatchOption corresponding)
|
||||
{
|
||||
Description = AkaI18N.GetResource(corresponding.GetEnumAttribute<EnumLocalizedName>().Name);
|
||||
Corresponding = corresponding;
|
||||
}
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public SearchTagMatchOption Corresponding { get; set; }
|
||||
}
|
||||
}
|
72
Pixeval/Data/ViewModel/SpotlightArticle.cs
Normal file
72
Pixeval/Data/ViewModel/SpotlightArticle.cs
Normal file
@ -0,0 +1,72 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Core;
|
||||
using Pixeval.Objects.Generic;
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class SpotlightArticle
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("pure_title")]
|
||||
public string PureTitle { get; set; }
|
||||
|
||||
[JsonProperty("thumbnail")]
|
||||
public string Thumbnail { get; set; }
|
||||
|
||||
[JsonProperty("article_url")]
|
||||
public string ArticleUrl { get; set; }
|
||||
|
||||
[JsonProperty("publish_date")]
|
||||
public DateTimeOffset PublishDate { get; set; }
|
||||
|
||||
[JsonProperty("category")]
|
||||
public string Category { get; set; }
|
||||
|
||||
[JsonProperty("subcategory_label")]
|
||||
public string SubcategoryLabel { get; set; }
|
||||
|
||||
public async void Download()
|
||||
{
|
||||
var result = await Tasks<string, Illustration>.Of(await PixivClient.Instance.GetArticleWorks(Id.ToString())).Mapping(async i =>
|
||||
{
|
||||
var res = await PixivHelper.IllustrationInfo(i);
|
||||
res.SpotlightTitle = Title;
|
||||
res.FromSpotlight = true;
|
||||
return res;
|
||||
}).Construct().WhenAll();
|
||||
|
||||
foreach (var illustration in result)
|
||||
{
|
||||
DownloadManager.EnqueueDownloadItem(illustration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
Pixeval/Data/ViewModel/TrendingTag.cs
Normal file
34
Pixeval/Data/ViewModel/TrendingTag.cs
Normal file
@ -0,0 +1,34 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class TrendingTag
|
||||
{
|
||||
public string Tag { get; set; }
|
||||
|
||||
public string TranslatedName { get; set; }
|
||||
|
||||
public string Thumbnail { get; set; }
|
||||
}
|
||||
}
|
67
Pixeval/Data/ViewModel/Trends.cs
Normal file
67
Pixeval/Data/ViewModel/Trends.cs
Normal file
@ -0,0 +1,67 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class Trends
|
||||
{
|
||||
public string PostUserId { get; set; }
|
||||
|
||||
public string PostUserName { get; set; }
|
||||
|
||||
public string TrendObjectId { get; set; }
|
||||
|
||||
public DateTime PostDate { get; set; }
|
||||
|
||||
public TrendType Type { get; set; }
|
||||
|
||||
public string ByName { get; set; }
|
||||
|
||||
public bool IsReferToUser { get; set; }
|
||||
|
||||
public string TrendObjName { get; set; }
|
||||
|
||||
public string TrendObjectThumbnail { get; set; }
|
||||
|
||||
public string PostUserThumbnail { get; set; }
|
||||
}
|
||||
|
||||
public enum TrendType
|
||||
{
|
||||
/// <summary>
|
||||
/// Bookmark
|
||||
/// </summary>
|
||||
AddBookmark,
|
||||
|
||||
/// <summary>
|
||||
/// New illust
|
||||
/// </summary>
|
||||
AddIllust,
|
||||
|
||||
/// <summary>
|
||||
/// New follow
|
||||
/// </summary>
|
||||
AddFavorite
|
||||
}
|
||||
}
|
46
Pixeval/Data/ViewModel/User.cs
Normal file
46
Pixeval/Data/ViewModel/User.cs
Normal file
@ -0,0 +1,46 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using PropertyChanged;
|
||||
|
||||
namespace Pixeval.Data.ViewModel
|
||||
{
|
||||
[AddINotifyPropertyChangedInterface]
|
||||
public class User
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Id { get; set; }
|
||||
|
||||
public bool IsFollowed { get; set; }
|
||||
|
||||
public string Avatar { get; set; }
|
||||
|
||||
public string Introduction { get; set; }
|
||||
|
||||
public string Background { get; set; }
|
||||
|
||||
public int Follows { get; set; }
|
||||
|
||||
public bool IsPremium { get; set; }
|
||||
|
||||
public string[] Thumbnails { get; set; } = new string[3];
|
||||
}
|
||||
}
|
95
Pixeval/Data/Web/Delegation/DnsResolvedHttpClientHandler.cs
Normal file
95
Pixeval/Data/Web/Delegation/DnsResolvedHttpClientHandler.cs
Normal file
@ -0,0 +1,95 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Persisting;
|
||||
|
||||
namespace Pixeval.Data.Web.Delegation
|
||||
{
|
||||
public abstract class DnsResolvedHttpClientHandler : HttpClientHandler
|
||||
{
|
||||
private readonly bool directConnect;
|
||||
private readonly IHttpRequestHandler requestHandler;
|
||||
|
||||
static DnsResolvedHttpClientHandler()
|
||||
{
|
||||
System.AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
|
||||
}
|
||||
|
||||
protected DnsResolvedHttpClientHandler(IHttpRequestHandler requestHandler = null, bool directConnect = true)
|
||||
{
|
||||
this.requestHandler = requestHandler;
|
||||
this.directConnect = directConnect;
|
||||
ServerCertificateCustomValidationCallback = DangerousAcceptAnyServerCertificateValidator;
|
||||
}
|
||||
|
||||
protected abstract DnsResolver DnsResolver { get; set; }
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
requestHandler?.Handle(request);
|
||||
|
||||
if (directConnect)
|
||||
{
|
||||
var host = request.RequestUri.DnsSafeHost;
|
||||
|
||||
var isSslSession = request.RequestUri.ToString().StartsWith("https://");
|
||||
|
||||
request.RequestUri = new Uri($"{(isSslSession ? "https://" : "http://")}{DnsResolver.Lookup()[0]}{request.RequestUri.PathAndQuery}");
|
||||
request.Headers.Host = host;
|
||||
}
|
||||
|
||||
HttpResponseMessage result;
|
||||
try
|
||||
{
|
||||
result = await base.SendAsync(request, cancellationToken);
|
||||
}
|
||||
catch (HttpRequestException e)
|
||||
{
|
||||
if (e.InnerException != null && e.InnerException.Message.ToLower().Contains("winhttp"))
|
||||
{
|
||||
return new HttpResponseMessage(HttpStatusCode.OK);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
if (result.StatusCode == HttpStatusCode.BadRequest && (await result.Content.ReadAsStringAsync()).Contains("OAuth"))
|
||||
{
|
||||
using var semaphore = new SemaphoreSlim(1);
|
||||
await semaphore.WaitAsync(cancellationToken);
|
||||
await Authentication.AppApiAuthenticate(Session.Current.Account, Session.Current.Password);
|
||||
var token = request.Headers.Authorization;
|
||||
if (token != null)
|
||||
{
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue(token.Scheme, Session.Current.AccessToken);
|
||||
}
|
||||
|
||||
return await base.SendAsync(request, cancellationToken);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
138
Pixeval/Data/Web/Delegation/DnsResolver.cs
Normal file
138
Pixeval/Data/Web/Delegation/DnsResolver.cs
Normal file
@ -0,0 +1,138 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Authentication;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.Web.Protocol;
|
||||
using Pixeval.Data.Web.Request;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Delegation
|
||||
{
|
||||
public abstract class DnsResolver
|
||||
{
|
||||
public static readonly ThreadLocal<Dictionary<string, List<IPAddress>>> DnsCache = new ThreadLocal<Dictionary<string, List<IPAddress>>>(() => new Dictionary<string, List<IPAddress>>());
|
||||
|
||||
protected async Task<DnsResolveResponse> GetDnsJson(string hostname)
|
||||
{
|
||||
return await RestService.For<IResolveDnsProtocol>(new HttpClient(new HttpClientHandler { SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls }) { BaseAddress = new Uri(ProtocolBase.DnsServer), Timeout = TimeSpan.FromSeconds(5) }).ResolveDns(new DnsResolveRequest
|
||||
{
|
||||
Ct = "application/dns-json",
|
||||
Cd = "false",
|
||||
Do = "false",
|
||||
Name = hostname,
|
||||
Type = "A"
|
||||
});
|
||||
}
|
||||
|
||||
/*public async Task<IReadOnlyList<IPAddress>> Lookup(string hostname)
|
||||
{
|
||||
const string OAuthUrl = "oauth.secure.pixiv.net";
|
||||
if (hostname == OAuthUrl)
|
||||
{
|
||||
CacheDns(hostname, UseDefaultDns());
|
||||
return DnsCache.Value[hostname];
|
||||
}
|
||||
|
||||
if (DnsCache.Value.ContainsKey(hostname)) return DnsCache.Value[hostname].ToImmutableList();
|
||||
|
||||
var ipList = new HashSet<IPAddress>(new IpAddressEqualityComparer());
|
||||
if (_dnsQueryFailed)
|
||||
{
|
||||
CacheDns(hostname, UseDefaultDns());
|
||||
return DnsCache.Value[hostname];
|
||||
}
|
||||
|
||||
DnsResolveResponse response;
|
||||
try
|
||||
{
|
||||
response = await GetDnsJson(hostname);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_dnsQueryFailed = true;
|
||||
CacheDns(hostname, UseDefaultDns());
|
||||
return DnsCache.Value[hostname];
|
||||
}
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
var answer = response.Answers;
|
||||
if (!answer.IsNullOrEmpty())
|
||||
{
|
||||
foreach (var queriedIp in answer)
|
||||
if (IPAddress.TryParse(queriedIp.Data, out var address))
|
||||
ipList.Add(address);
|
||||
}
|
||||
else
|
||||
{
|
||||
ipList.AddRange(await Dns.GetHostAddressesAsync(hostname));
|
||||
if (ipList.IsNullOrEmpty()) ipList.AddRange(UseDefaultDns());
|
||||
}
|
||||
|
||||
CacheDns(hostname, ipList);
|
||||
return ipList.ToImmutableList();
|
||||
}
|
||||
|
||||
ipList.AddRange(UseDefaultDns());
|
||||
CacheDns(hostname, ipList);
|
||||
return ipList.ToImmutableList();
|
||||
}*/
|
||||
|
||||
public IReadOnlyList<IPAddress> Lookup()
|
||||
{
|
||||
return UseDefaultDns().ToImmutableList();
|
||||
}
|
||||
|
||||
// private static void CacheDns(string hostname, IEnumerable<IPAddress> ipList)
|
||||
// {
|
||||
// if (DnsCache.Value.ContainsKey(hostname))
|
||||
// DnsCache.Value[hostname].AddRange(ipList);
|
||||
// else
|
||||
// DnsCache.Value[hostname] = new List<IPAddress>(ipList);
|
||||
// }
|
||||
|
||||
protected abstract IEnumerable<IPAddress> UseDefaultDns();
|
||||
|
||||
private class IpAddressEqualityComparer : IEqualityComparer<IPAddress>
|
||||
{
|
||||
public bool Equals(IPAddress x, IPAddress y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return x.ToString() == y.ToString();
|
||||
}
|
||||
|
||||
public int GetHashCode(IPAddress obj)
|
||||
{
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
72
Pixeval/Data/Web/Delegation/HttpClientFactory.cs
Normal file
72
Pixeval/Data/Web/Delegation/HttpClientFactory.cs
Normal file
@ -0,0 +1,72 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.Web.Protocol;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Persisting;
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Delegation
|
||||
{
|
||||
public class HttpClientFactory
|
||||
{
|
||||
public static HttpClient AppApiHttpClient()
|
||||
{
|
||||
return PixivApi(ProtocolBase.AppApiBaseUrl, Settings.Global.DirectConnect).Apply(h => h.DefaultRequestHeaders.Add("Authorization", "Bearer"));
|
||||
}
|
||||
|
||||
public static HttpClient WebApiHttpClient()
|
||||
{
|
||||
return PixivApi(ProtocolBase.WebApiBaseUrl, Settings.Global.DirectConnect);
|
||||
}
|
||||
|
||||
public static IAppApiProtocol AppApiService()
|
||||
{
|
||||
return RestService.For<IAppApiProtocol>(PixivApi(ProtocolBase.AppApiBaseUrl, Settings.Global.DirectConnect));
|
||||
}
|
||||
|
||||
public static IWebApiProtocol WebApiService()
|
||||
{
|
||||
return RestService.For<IWebApiProtocol>(PixivApi(ProtocolBase.WebApiBaseUrl, Settings.Global.DirectConnect));
|
||||
}
|
||||
|
||||
public static HttpClient PixivApi(string baseAddress, bool directConnect)
|
||||
{
|
||||
return new HttpClient(PixivApiHttpClientHandler.Instance(directConnect)) { BaseAddress = new Uri(baseAddress) };
|
||||
}
|
||||
|
||||
public static HttpClient PixivImage()
|
||||
{
|
||||
return new HttpClient(PixivImageHttpClientHandler.Instance).Apply(client =>
|
||||
{
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("Referer", "http://www.pixiv.net");
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "PixivIOSApp/5.8.7");
|
||||
});
|
||||
}
|
||||
|
||||
public static Task<HttpResponseMessage> GetResponseHeader(HttpClient client, string uri)
|
||||
{
|
||||
return client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
|
||||
}
|
||||
}
|
||||
}
|
29
Pixeval/Data/Web/Delegation/IHttpRequestHandler.cs
Normal file
29
Pixeval/Data/Web/Delegation/IHttpRequestHandler.cs
Normal file
@ -0,0 +1,29 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Pixeval.Data.Web.Delegation
|
||||
{
|
||||
public interface IHttpRequestHandler
|
||||
{
|
||||
void Handle(HttpRequestMessage httpRequestMessage);
|
||||
}
|
||||
}
|
37
Pixeval/Data/Web/Delegation/PixivApiDnsResolver.cs
Normal file
37
Pixeval/Data/Web/Delegation/PixivApiDnsResolver.cs
Normal file
@ -0,0 +1,37 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
namespace Pixeval.Data.Web.Delegation
|
||||
{
|
||||
public class PixivApiDnsResolver : DnsResolver
|
||||
{
|
||||
public static readonly DnsResolver Instance = new PixivApiDnsResolver();
|
||||
|
||||
protected override IEnumerable<IPAddress> UseDefaultDns()
|
||||
{
|
||||
yield return IPAddress.Parse("210.140.131.219");
|
||||
yield return IPAddress.Parse("210.140.131.223");
|
||||
yield return IPAddress.Parse("210.140.131.226");
|
||||
}
|
||||
}
|
||||
}
|
38
Pixeval/Data/Web/Delegation/PixivApiHttpClientHandler.cs
Normal file
38
Pixeval/Data/Web/Delegation/PixivApiHttpClientHandler.cs
Normal file
@ -0,0 +1,38 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Pixeval.Data.Web.Delegation
|
||||
{
|
||||
public class PixivApiHttpClientHandler : DnsResolvedHttpClientHandler
|
||||
{
|
||||
private PixivApiHttpClientHandler(bool directConnect) : base(PixivHttpRequestHandler.Instance, directConnect)
|
||||
{
|
||||
}
|
||||
|
||||
protected override DnsResolver DnsResolver { get; set; } = PixivApiDnsResolver.Instance;
|
||||
|
||||
public static HttpMessageHandler Instance(bool directConnect)
|
||||
{
|
||||
return new PixivApiHttpClientHandler(directConnect);
|
||||
}
|
||||
}
|
||||
}
|
72
Pixeval/Data/Web/Delegation/PixivHttpRequestHandler.cs
Normal file
72
Pixeval/Data/Web/Delegation/PixivHttpRequestHandler.cs
Normal file
@ -0,0 +1,72 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.I18n;
|
||||
using Pixeval.Objects.Primitive;
|
||||
using Pixeval.Persisting;
|
||||
|
||||
namespace Pixeval.Data.Web.Delegation
|
||||
{
|
||||
public class PixivHttpRequestHandler : IHttpRequestHandler
|
||||
{
|
||||
public static readonly PixivHttpRequestHandler Instance = new PixivHttpRequestHandler();
|
||||
|
||||
protected PixivHttpRequestHandler()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Handle(HttpRequestMessage httpRequestMessage)
|
||||
{
|
||||
switch (httpRequestMessage.RequestUri.DnsSafeHost)
|
||||
{
|
||||
case "app-api.pixiv.net":
|
||||
var token = httpRequestMessage.Headers.Authorization;
|
||||
if (token != null)
|
||||
{
|
||||
if (Session.Current.AccessToken.IsNullOrEmpty())
|
||||
{
|
||||
throw new TokenNotFoundException($"{nameof(Session.Current.AccessToken)} is empty, this exception should never be thrown, if you see this message, please send issue on github or contact me (decem0730@gmail.com)");
|
||||
}
|
||||
|
||||
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(token.Scheme, Session.Current.AccessToken);
|
||||
}
|
||||
|
||||
break;
|
||||
case var x when x == "pixiv.net" || x == "www.pixiv.net":
|
||||
httpRequestMessage.Headers.TryAddWithoutValidation("Cookie", Settings.Global.Cookie);
|
||||
break;
|
||||
}
|
||||
|
||||
if (httpRequestMessage.RequestUri.DnsSafeHost == "i.pximg.net" && !Settings.Global.MirrorServer.IsNullOrEmpty())
|
||||
{
|
||||
httpRequestMessage.RequestUri = new Uri(httpRequestMessage.RequestUri.ToString().Replace("i.pximg.net", Settings.Global.MirrorServer));
|
||||
}
|
||||
|
||||
if (!httpRequestMessage.Headers.Contains("Accept-Language"))
|
||||
{
|
||||
httpRequestMessage.Headers.TryAddWithoutValidation("Accept-Language", AkaI18N.GetCultureAcceptLanguage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
Pixeval/Data/Web/Delegation/PixivImageHttpClientHandler.cs
Normal file
35
Pixeval/Data/Web/Delegation/PixivImageHttpClientHandler.cs
Normal file
@ -0,0 +1,35 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Pixeval.Data.Web.Delegation
|
||||
{
|
||||
public class PixivImageHttpClientHandler : DnsResolvedHttpClientHandler
|
||||
{
|
||||
public static readonly HttpMessageHandler Instance = new PixivImageHttpClientHandler();
|
||||
|
||||
private PixivImageHttpClientHandler() : base(PixivHttpRequestHandler.Instance, false)
|
||||
{
|
||||
}
|
||||
|
||||
protected override DnsResolver DnsResolver { get; set; } = null;
|
||||
}
|
||||
}
|
47
Pixeval/Data/Web/HttpResponse.cs
Normal file
47
Pixeval/Data/Web/HttpResponse.cs
Normal file
@ -0,0 +1,47 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace Pixeval.Data.Web
|
||||
{
|
||||
public class HttpResponse<T> : Tuple<bool, T>
|
||||
{
|
||||
private HttpResponse(bool status, T response) : base(status, response)
|
||||
{
|
||||
}
|
||||
|
||||
public static HttpResponse<T> Wrap(bool status)
|
||||
{
|
||||
return new HttpResponse<T>(status, default);
|
||||
}
|
||||
|
||||
public static HttpResponse<T> Wrap(bool status, T response)
|
||||
{
|
||||
return new HttpResponse<T>(status, response);
|
||||
}
|
||||
|
||||
public void Deconstruct(out bool status, out T response)
|
||||
{
|
||||
status = Item1;
|
||||
response = Item2;
|
||||
}
|
||||
}
|
||||
}
|
64
Pixeval/Data/Web/Protocol/IAppApiProtocol.cs
Normal file
64
Pixeval/Data/Web/Protocol/IAppApiProtocol.cs
Normal file
@ -0,0 +1,64 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.Web.Request;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Protocol
|
||||
{
|
||||
[Headers("Authorization: Bearer")]
|
||||
public interface IAppApiProtocol
|
||||
{
|
||||
[Post("/v1/illust/bookmark/delete")]
|
||||
Task DeleteBookmark([Body(BodySerializationMethod.UrlEncoded)] DeleteBookmarkRequest deleteBookmarkRequest);
|
||||
|
||||
[Get("/v1/user/detail")]
|
||||
Task<UserInformationResponse> GetUserInformation(UserInformationRequest userInformationRequest);
|
||||
|
||||
[Get("/v1/spotlight/articles?category=all")]
|
||||
Task<SpotlightResponse> GetSpotlights(int offset);
|
||||
|
||||
[Post("/v1/user/follow/add")]
|
||||
Task FollowArtist([Body(BodySerializationMethod.UrlEncoded)] FollowArtistRequest followArtistRequest);
|
||||
|
||||
[Post("/v1/user/follow/delete")]
|
||||
Task UnFollowArtist([Body(BodySerializationMethod.UrlEncoded)] UnFollowArtistRequest unFollowArtistRequest);
|
||||
|
||||
[Get("/v1/ugoira/metadata")]
|
||||
Task<UgoiraMetadataResponse> GetUgoiraMetadata([AliasAs("illust_id")] string id);
|
||||
|
||||
[Post("/v2/illust/bookmark/add")]
|
||||
Task AddBookmark([Body(BodySerializationMethod.UrlEncoded)] AddBookmarkRequest addBookmarkRequest);
|
||||
|
||||
[Get("/v2/search/autocomplete")]
|
||||
Task<AutoCompletionResponse> GetAutoCompletion(AutoCompletionRequest autoCompletionRequest);
|
||||
|
||||
[Get("/v1/illust/detail")]
|
||||
Task<SingleWorkResponse> GetSingle([AliasAs("illust_id")] string id);
|
||||
|
||||
[Get("/v1/user/recommended?filter=for_android")]
|
||||
Task<RecommendIllustratorResponse> GetRecommendIllustrators(RecommendIllustratorRequest recommendIllustratorRequest);
|
||||
|
||||
[Get("/v1/trending-tags/illust?filter=for_android")]
|
||||
Task<TrendingTagResponse> GetTrendingTags();
|
||||
}
|
||||
}
|
33
Pixeval/Data/Web/Protocol/IResolveDnsProtocol.cs
Normal file
33
Pixeval/Data/Web/Protocol/IResolveDnsProtocol.cs
Normal file
@ -0,0 +1,33 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.Web.Request;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Protocol
|
||||
{
|
||||
public interface IResolveDnsProtocol
|
||||
{
|
||||
[Get("/dns-query")]
|
||||
Task<DnsResolveResponse> ResolveDns(DnsResolveRequest dnsResolverRequest);
|
||||
}
|
||||
}
|
34
Pixeval/Data/Web/Protocol/ISauceNAOProtocol.cs
Normal file
34
Pixeval/Data/Web/Protocol/ISauceNAOProtocol.cs
Normal file
@ -0,0 +1,34 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Protocol
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public interface ISauceNAOProtocol
|
||||
{
|
||||
[Multipart]
|
||||
[Post("/search.php")]
|
||||
Task<HttpResponseMessage> GetSauce([AliasAs("file")] StreamPart stream);
|
||||
}
|
||||
}
|
37
Pixeval/Data/Web/Protocol/ITokenProtocol.cs
Normal file
37
Pixeval/Data/Web/Protocol/ITokenProtocol.cs
Normal file
@ -0,0 +1,37 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.Web.Request;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Protocol
|
||||
{
|
||||
[Headers("User-Agent: PixivAndroidApp/5.0.64 (Android 6.0)", "Content-Type: application/x-www-form-urlencoded")]
|
||||
public interface ITokenProtocol
|
||||
{
|
||||
[Post("/auth/token")]
|
||||
Task<TokenResponse> GetTokenByPassword([Body(BodySerializationMethod.UrlEncoded)] PasswordTokenRequest body, [Header("X-Client-Time")] string clientTime, [Header("X-Client-Hash")] string clientHash);
|
||||
|
||||
[Post("/auth/token")]
|
||||
Task<TokenResponse> RefreshToken([Body(BodySerializationMethod.UrlEncoded)] RefreshTokenRequest body);
|
||||
}
|
||||
}
|
41
Pixeval/Data/Web/Protocol/IWebApiProtocol.cs
Normal file
41
Pixeval/Data/Web/Protocol/IWebApiProtocol.cs
Normal file
@ -0,0 +1,41 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Pixeval.Data.Web.Request;
|
||||
using Pixeval.Data.Web.Response;
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Protocol
|
||||
{
|
||||
[Headers("User-Agent: PixivAndroidApp/5.0.64 (Android 6.0)", "Content-Type: application/x-www-form-urlencoded")]
|
||||
public interface IWebApiProtocol
|
||||
{
|
||||
[Post("/setting_user.php")]
|
||||
Task<HttpResponseMessage> ToggleR18State([Body(BodySerializationMethod.UrlEncoded)] ToggleR18StateRequest toggleR18StateRequest);
|
||||
|
||||
[Get("/ajax/showcase/article")]
|
||||
Task<SpotlightArticleResponse> GetSpotlightArticles([AliasAs("article_id")] string articleId);
|
||||
|
||||
[Get("/touch/ajax/user/details")]
|
||||
Task<WebApiUserDetailResponse> GetWebApiUserDetail(string id);
|
||||
}
|
||||
}
|
37
Pixeval/Data/Web/ProtocolBase.cs
Normal file
37
Pixeval/Data/Web/ProtocolBase.cs
Normal file
@ -0,0 +1,37 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Pixeval.Data.Web
|
||||
{
|
||||
public class ProtocolBase
|
||||
{
|
||||
public const string PublicApiBaseUrl = "https://public-api.secure.pixiv.net/v1";
|
||||
|
||||
public const string AppApiBaseUrl = "https://app-api.pixiv.net";
|
||||
|
||||
public const string DnsServer = "https://1.0.0.1";
|
||||
|
||||
public const string SauceNaoUrl = "https://saucenao.com/";
|
||||
|
||||
public const string OAuthBaseUrl = "https://oauth.secure.pixiv.net";
|
||||
|
||||
public const string WebApiBaseUrl = "https://www.pixiv.net";
|
||||
}
|
||||
}
|
33
Pixeval/Data/Web/Request/AddBookmarkRequest.cs
Normal file
33
Pixeval/Data/Web/Request/AddBookmarkRequest.cs
Normal file
@ -0,0 +1,33 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class AddBookmarkRequest
|
||||
{
|
||||
[AliasAs("restrict")]
|
||||
public string Restrict { get; set; } = "public";
|
||||
|
||||
[AliasAs("illust_id")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
33
Pixeval/Data/Web/Request/AutoCompletionRequest.cs
Normal file
33
Pixeval/Data/Web/Request/AutoCompletionRequest.cs
Normal file
@ -0,0 +1,33 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class AutoCompletionRequest
|
||||
{
|
||||
[AliasAs("merge_plain_keyword_results=true")]
|
||||
public bool MergePlainKeywordResult { get; set; } = true;
|
||||
|
||||
[AliasAs("word")]
|
||||
public string Word { get; set; }
|
||||
}
|
||||
}
|
30
Pixeval/Data/Web/Request/DeleteBookmarkRequest.cs
Normal file
30
Pixeval/Data/Web/Request/DeleteBookmarkRequest.cs
Normal file
@ -0,0 +1,30 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class DeleteBookmarkRequest
|
||||
{
|
||||
[AliasAs("illust_id")]
|
||||
public string IllustId { get; set; }
|
||||
}
|
||||
}
|
42
Pixeval/Data/Web/Request/DnsResolveRequest.cs
Normal file
42
Pixeval/Data/Web/Request/DnsResolveRequest.cs
Normal file
@ -0,0 +1,42 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class DnsResolveRequest
|
||||
{
|
||||
[AliasAs("ct")]
|
||||
public string Ct { get; set; }
|
||||
|
||||
[AliasAs("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[AliasAs("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[AliasAs("do")]
|
||||
public string Do { get; set; }
|
||||
|
||||
[AliasAs("cd")]
|
||||
public string Cd { get; set; }
|
||||
}
|
||||
}
|
33
Pixeval/Data/Web/Request/FollowArtistRequest.cs
Normal file
33
Pixeval/Data/Web/Request/FollowArtistRequest.cs
Normal file
@ -0,0 +1,33 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class FollowArtistRequest
|
||||
{
|
||||
[AliasAs("user_id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[AliasAs("restrict")]
|
||||
public string Restrict { get; set; } = "public";
|
||||
}
|
||||
}
|
45
Pixeval/Data/Web/Request/PasswordTokenRequest.cs
Normal file
45
Pixeval/Data/Web/Request/PasswordTokenRequest.cs
Normal file
@ -0,0 +1,45 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class PasswordTokenRequest
|
||||
{
|
||||
[AliasAs("username")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[AliasAs("password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[AliasAs("grant_type")]
|
||||
public string GrantType => "password";
|
||||
|
||||
[AliasAs("client_id")]
|
||||
public string ClientId => "MOBrBDS8blbauoSck0ZfDbtuzpyT";
|
||||
|
||||
[AliasAs("client_secret")]
|
||||
public string ClientSecret => "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj";
|
||||
|
||||
[AliasAs("get_secure_url")]
|
||||
public string GetSecureUrl => "1";
|
||||
}
|
||||
}
|
33
Pixeval/Data/Web/Request/RecommendIllustratorRequest.cs
Normal file
33
Pixeval/Data/Web/Request/RecommendIllustratorRequest.cs
Normal file
@ -0,0 +1,33 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class RecommendIllustratorRequest
|
||||
{
|
||||
[AliasAs("filter")]
|
||||
public string Filter { get; } = "for_android";
|
||||
|
||||
[AliasAs("offset")]
|
||||
public int Offset { get; set; } = 0;
|
||||
}
|
||||
}
|
42
Pixeval/Data/Web/Request/RefreshTokenRequest.cs
Normal file
42
Pixeval/Data/Web/Request/RefreshTokenRequest.cs
Normal file
@ -0,0 +1,42 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class RefreshTokenRequest
|
||||
{
|
||||
[AliasAs("refresh_token")]
|
||||
public string RefreshToken { get; set; }
|
||||
|
||||
[AliasAs("grant_type")]
|
||||
public string GrantType => "refresh_token";
|
||||
|
||||
[AliasAs("client_id")]
|
||||
public string ClientId => "MOBrBDS8blbauoSck0ZfDbtuzpyT";
|
||||
|
||||
[AliasAs("client_secret")]
|
||||
public string ClientSecret => "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj";
|
||||
|
||||
[AliasAs("get_secure_url")]
|
||||
public string GetSecureUrl => "1";
|
||||
}
|
||||
}
|
45
Pixeval/Data/Web/Request/ToggleR18StateRequest.cs
Normal file
45
Pixeval/Data/Web/Request/ToggleR18StateRequest.cs
Normal file
@ -0,0 +1,45 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class ToggleR18StateRequest
|
||||
{
|
||||
[AliasAs("mode")]
|
||||
public string Mode { get; } = "mod";
|
||||
|
||||
[AliasAs("user_language")]
|
||||
public string UserLang { get; } = "zh";
|
||||
|
||||
[AliasAs("r18")]
|
||||
public string R18 { get; set; }
|
||||
|
||||
[AliasAs("r18g")]
|
||||
public string R18G { get; set; }
|
||||
|
||||
[AliasAs("submit")]
|
||||
public string Submit { get; } = "保存";
|
||||
|
||||
[AliasAs("tt")]
|
||||
public string Tt { get; set; }
|
||||
}
|
||||
}
|
30
Pixeval/Data/Web/Request/UnFollowArtistRequest.cs
Normal file
30
Pixeval/Data/Web/Request/UnFollowArtistRequest.cs
Normal file
@ -0,0 +1,30 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class UnFollowArtistRequest
|
||||
{
|
||||
[AliasAs("user_id")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
}
|
33
Pixeval/Data/Web/Request/UserInformationRequest.cs
Normal file
33
Pixeval/Data/Web/Request/UserInformationRequest.cs
Normal file
@ -0,0 +1,33 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Refit;
|
||||
|
||||
namespace Pixeval.Data.Web.Request
|
||||
{
|
||||
public class UserInformationRequest
|
||||
{
|
||||
[AliasAs("user_id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[AliasAs("filter")]
|
||||
public string Filter { get; set; } = "for_android";
|
||||
}
|
||||
}
|
40
Pixeval/Data/Web/Response/AutoCompletionResponse.cs
Normal file
40
Pixeval/Data/Web/Response/AutoCompletionResponse.cs
Normal file
@ -0,0 +1,40 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class AutoCompletionResponse
|
||||
{
|
||||
[JsonProperty("tags")]
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
76
Pixeval/Data/Web/Response/DnsResolveResponse.cs
Normal file
76
Pixeval/Data/Web/Response/DnsResolveResponse.cs
Normal file
@ -0,0 +1,76 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class DnsResolveResponse
|
||||
{
|
||||
[JsonProperty("Status")]
|
||||
public long Status { get; set; }
|
||||
|
||||
[JsonProperty("TC")]
|
||||
public bool Tc { get; set; }
|
||||
|
||||
[JsonProperty("RD")]
|
||||
public bool Rd { get; set; }
|
||||
|
||||
[JsonProperty("RA")]
|
||||
public bool Ra { get; set; }
|
||||
|
||||
[JsonProperty("AD")]
|
||||
public bool Ad { get; set; }
|
||||
|
||||
[JsonProperty("CD")]
|
||||
public bool Cd { get; set; }
|
||||
|
||||
[JsonProperty("Question")]
|
||||
public List<Question> Questions { get; set; }
|
||||
|
||||
[JsonProperty("Answer")]
|
||||
public List<Answer> Answers { get; set; }
|
||||
|
||||
public class Answer
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public long Type { get; set; }
|
||||
|
||||
[JsonProperty("TTL")]
|
||||
public long Ttl { get; set; }
|
||||
|
||||
[JsonProperty("data")]
|
||||
public string Data { get; set; }
|
||||
}
|
||||
|
||||
public class Question
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public long Type { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
263
Pixeval/Data/Web/Response/FollowingResponse.cs
Normal file
263
Pixeval/Data/Web/Response/FollowingResponse.cs
Normal file
@ -0,0 +1,263 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class FollowingResponse
|
||||
{
|
||||
[JsonProperty("user_previews")]
|
||||
public List<UserPreview> UserPreviews { get; set; }
|
||||
|
||||
[JsonProperty("next_url")]
|
||||
public string NextUrl { get; set; }
|
||||
|
||||
public class UserPreview
|
||||
{
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("illusts")]
|
||||
public List<Illust> Illusts { get; set; }
|
||||
|
||||
[JsonProperty("novels")]
|
||||
public List<Novel> Novels { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
}
|
||||
|
||||
public class Illust
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<IllustTag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public List<string> Tools { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public long Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public long Height { get; set; }
|
||||
|
||||
[JsonProperty("sanity_level")]
|
||||
public long SanityLevel { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("series")]
|
||||
public Series Series { get; set; }
|
||||
|
||||
[JsonProperty("meta_single_page")]
|
||||
public MetaSinglePage MetaSinglePage { get; set; }
|
||||
|
||||
[JsonProperty("meta_pages")]
|
||||
public List<MetaPage> MetaPages { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public Uri Original { get; set; }
|
||||
}
|
||||
|
||||
public class MetaPage
|
||||
{
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
}
|
||||
|
||||
public class MetaSinglePage
|
||||
{
|
||||
[JsonProperty("original_image_url", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public Uri OriginalImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Series
|
||||
{
|
||||
[JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public long? Id { get; set; }
|
||||
|
||||
[JsonProperty("title", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Title { get; set; }
|
||||
}
|
||||
|
||||
public class IllustTag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
|
||||
public class Novel
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("is_original")]
|
||||
public bool IsOriginal { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<NovelTag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("text_length")]
|
||||
public long TextLength { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("series")]
|
||||
public Series Series { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("total_comments")]
|
||||
public long TotalComments { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
|
||||
[JsonProperty("is_mypixiv_only")]
|
||||
public bool IsMypixivOnly { get; set; }
|
||||
|
||||
[JsonProperty("is_x_restricted")]
|
||||
public bool IsXRestricted { get; set; }
|
||||
}
|
||||
|
||||
public class NovelTag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("added_by_uploaded_user")]
|
||||
public bool AddedByUploadedUser { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
207
Pixeval/Data/Web/Response/GalleryResponse.cs
Normal file
207
Pixeval/Data/Web/Response/GalleryResponse.cs
Normal file
@ -0,0 +1,207 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class GalleryResponse
|
||||
{
|
||||
[JsonProperty("illusts")]
|
||||
public List<Illust> Illusts { get; set; }
|
||||
|
||||
[JsonProperty("next_url")]
|
||||
public string NextUrl { get; set; }
|
||||
|
||||
public class Illust : IParser<Illustration>
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public List<string> Tools { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public long Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public long Height { get; set; }
|
||||
|
||||
[JsonProperty("sanity_level")]
|
||||
public long SanityLevel { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("meta_single_page")]
|
||||
public MetaSinglePage MetaSinglePage { get; set; }
|
||||
|
||||
[JsonProperty("meta_pages")]
|
||||
public List<MetaPage> MetaPages { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
|
||||
public Illustration Parse()
|
||||
{
|
||||
return new Illustration
|
||||
{
|
||||
Bookmark = (int) TotalBookmarks,
|
||||
Id = Id.ToString(),
|
||||
IsLiked = IsBookmarked,
|
||||
IsManga = PageCount != 1,
|
||||
IsUgoira = Type == "ugoira",
|
||||
Origin = MetaSinglePage.OriginalImageUrl,
|
||||
Large = ImageUrls.Large,
|
||||
Tags = Tags.Select(t => new ViewModel.Tag { Name = t.Name, TranslatedName = t.TranslatedName }),
|
||||
Thumbnail = ImageUrls.Medium.IsNullOrEmpty() ? ImageUrls.SquareMedium : ImageUrls.Medium,
|
||||
Title = Title,
|
||||
UserId = User.Id.ToString(),
|
||||
UserName = User.Name,
|
||||
Resolution = $"{Width}x{Height}",
|
||||
ViewCount = (int) TotalView,
|
||||
PublishDate = CreateDate
|
||||
}.Apply(i =>
|
||||
{
|
||||
if (i.IsManga)
|
||||
{
|
||||
i.MangaMetadata = MetaPages.Select(p =>
|
||||
{
|
||||
var page = (Illustration) i.Clone();
|
||||
page.Thumbnail = p.ImageUrls.Medium;
|
||||
page.Origin = p.ImageUrls.Original;
|
||||
page.Large = p.ImageUrls.Large;
|
||||
return page;
|
||||
}).ToArray();
|
||||
foreach (var illustration in i.MangaMetadata)
|
||||
{
|
||||
illustration.MangaMetadata = i.MangaMetadata;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class MetaPage
|
||||
{
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
}
|
||||
|
||||
public class MetaSinglePage
|
||||
{
|
||||
[JsonProperty("original_image_url", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OriginalImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
206
Pixeval/Data/Web/Response/QueryWorksResponse.cs
Normal file
206
Pixeval/Data/Web/Response/QueryWorksResponse.cs
Normal file
@ -0,0 +1,206 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Objects.Generic;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class QueryWorksResponse
|
||||
{
|
||||
[JsonProperty("illusts")]
|
||||
public List<Illust> Illusts { get; set; }
|
||||
|
||||
[JsonProperty("next_url")]
|
||||
public string NextUrl { get; set; }
|
||||
|
||||
public class Illust : IParser<Illustration>
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public List<string> Tools { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public long Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public long Height { get; set; }
|
||||
|
||||
[JsonProperty("sanity_level")]
|
||||
public long SanityLevel { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("meta_single_page")]
|
||||
public MetaSinglePage MetaSinglePage { get; set; }
|
||||
|
||||
[JsonProperty("meta_pages")]
|
||||
public List<MetaPage> MetaPages { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
|
||||
public Illustration Parse()
|
||||
{
|
||||
return new Illustration
|
||||
{
|
||||
Bookmark = (int) TotalBookmarks,
|
||||
Id = Id.ToString(),
|
||||
IsLiked = IsBookmarked,
|
||||
IsUgoira = Type == "ugoira",
|
||||
IsManga = !MetaPages.IsNullOrEmpty(),
|
||||
Origin = MetaSinglePage.OriginalImageUrl ?? ImageUrls.Large,
|
||||
Large = ImageUrls.Large,
|
||||
Tags = Tags.Select(t => new ViewModel.Tag { Name = t.Name, TranslatedName = t.TranslatedName }),
|
||||
Thumbnail = ImageUrls.Medium ?? ImageUrls.SquareMedium,
|
||||
Title = Title,
|
||||
UserId = User.Id.ToString(),
|
||||
UserName = User.Name,
|
||||
Resolution = $"{Width}x{Height}",
|
||||
ViewCount = (int) TotalView,
|
||||
PublishDate = CreateDate
|
||||
}.Apply(i =>
|
||||
{
|
||||
if (i.IsManga)
|
||||
{
|
||||
i.MangaMetadata = MetaPages.Select(p =>
|
||||
{
|
||||
var page = (Illustration) i.Clone();
|
||||
page.Thumbnail = p.ImageUrls.Medium ?? p.ImageUrls.SquareMedium;
|
||||
page.Origin = p.ImageUrls.Original;
|
||||
page.Large = p.ImageUrls.Large;
|
||||
return page;
|
||||
}).ToArray();
|
||||
foreach (var illustration in i.MangaMetadata)
|
||||
{
|
||||
illustration.MangaMetadata = i.MangaMetadata;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class MetaPage
|
||||
{
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
}
|
||||
|
||||
public class MetaSinglePage
|
||||
{
|
||||
[JsonProperty("original_image_url", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OriginalImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
207
Pixeval/Data/Web/Response/RankingResponse.cs
Normal file
207
Pixeval/Data/Web/Response/RankingResponse.cs
Normal file
@ -0,0 +1,207 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class RankingResponse
|
||||
{
|
||||
[JsonProperty("illusts")]
|
||||
public List<Illust> Illusts { get; set; }
|
||||
|
||||
[JsonProperty("next_url")]
|
||||
public string NextUrl { get; set; }
|
||||
|
||||
public class Illust : IParser<Illustration>
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public List<string> Tools { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public long Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public long Height { get; set; }
|
||||
|
||||
[JsonProperty("sanity_level")]
|
||||
public long SanityLevel { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("meta_single_page")]
|
||||
public MetaSinglePage MetaSinglePage { get; set; }
|
||||
|
||||
[JsonProperty("meta_pages")]
|
||||
public List<MetaPage> MetaPages { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
|
||||
public Illustration Parse()
|
||||
{
|
||||
return new Illustration
|
||||
{
|
||||
Bookmark = (int) TotalBookmarks,
|
||||
Id = Id.ToString(),
|
||||
IsLiked = IsBookmarked,
|
||||
IsManga = PageCount != 1,
|
||||
IsUgoira = Type == "ugoira",
|
||||
Origin = MetaSinglePage.OriginalImageUrl,
|
||||
Large = ImageUrls.Large,
|
||||
Tags = Tags.Select(t => new ViewModel.Tag { Name = t.Name, TranslatedName = t.TranslatedName }),
|
||||
Thumbnail = ImageUrls.Medium.IsNullOrEmpty() ? ImageUrls.SquareMedium : ImageUrls.Medium,
|
||||
Title = Title,
|
||||
UserId = User.Id.ToString(),
|
||||
UserName = User.Name,
|
||||
Resolution = $"{Width}x{Height}",
|
||||
ViewCount = (int) TotalView,
|
||||
PublishDate = CreateDate
|
||||
}.Apply(i =>
|
||||
{
|
||||
if (i.IsManga)
|
||||
{
|
||||
i.MangaMetadata = MetaPages.Select(p =>
|
||||
{
|
||||
var page = (Illustration) i.Clone();
|
||||
page.Thumbnail = p.ImageUrls.Medium;
|
||||
page.Origin = p.ImageUrls.Original;
|
||||
page.Large = p.ImageUrls.Large;
|
||||
return page;
|
||||
}).ToArray();
|
||||
foreach (var illustration in i.MangaMetadata)
|
||||
{
|
||||
illustration.MangaMetadata = i.MangaMetadata;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class MetaPage
|
||||
{
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
}
|
||||
|
||||
public class MetaSinglePage
|
||||
{
|
||||
[JsonProperty("original_image_url", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OriginalImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
185
Pixeval/Data/Web/Response/RecommendIllustratorResponse.cs
Normal file
185
Pixeval/Data/Web/Response/RecommendIllustratorResponse.cs
Normal file
@ -0,0 +1,185 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class RecommendIllustratorResponse
|
||||
{
|
||||
[JsonProperty("user_previews")]
|
||||
public UserPreview[] UserPreviews { get; set; }
|
||||
|
||||
[JsonProperty("next_url")]
|
||||
public string NextUrl { get; set; }
|
||||
|
||||
public class UserPreview : IParser<ViewModel.User>
|
||||
{
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("illusts")]
|
||||
public Illust[] Illusts { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
|
||||
public ViewModel.User Parse()
|
||||
{
|
||||
return new ViewModel.User
|
||||
{
|
||||
Avatar = Regex.Replace(User.ProfileImageUrls.Medium, "_170\\.", "_50."),
|
||||
Id = User.Id.ToString(),
|
||||
Name = User.Name,
|
||||
Thumbnails = Illusts.Select(i => i.ImageUrls.SquareMedium).ToArray()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class Illust
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public Tag[] Tags { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public string[] Tools { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public long Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public long Height { get; set; }
|
||||
|
||||
[JsonProperty("sanity_level")]
|
||||
public long SanityLevel { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("meta_single_page")]
|
||||
public MetaSinglePage MetaSinglePage { get; set; }
|
||||
|
||||
[JsonProperty("meta_pages")]
|
||||
public MetaPage[] MetaPages { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class MetaPage
|
||||
{
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
}
|
||||
|
||||
public class MetaSinglePage
|
||||
{
|
||||
[JsonProperty("original_image_url", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OriginalImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
210
Pixeval/Data/Web/Response/RecommendResponse.cs
Normal file
210
Pixeval/Data/Web/Response/RecommendResponse.cs
Normal file
@ -0,0 +1,210 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class RecommendResponse
|
||||
{
|
||||
[JsonProperty("illusts")]
|
||||
public List<Illust> Illusts { get; set; }
|
||||
|
||||
[JsonProperty("contest_exists")]
|
||||
public bool ContestExists { get; set; }
|
||||
|
||||
[JsonProperty("next_url")]
|
||||
public string NextUrl { get; set; }
|
||||
|
||||
public class Illust : IParser<Illustration>
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public List<string> Tools { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public long Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public long Height { get; set; }
|
||||
|
||||
[JsonProperty("sanity_level")]
|
||||
public long SanityLevel { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("meta_single_page")]
|
||||
public MetaSinglePage MetaSinglePage { get; set; }
|
||||
|
||||
[JsonProperty("meta_pages")]
|
||||
public List<MetaPage> MetaPages { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
|
||||
public Illustration Parse()
|
||||
{
|
||||
return new Illustration
|
||||
{
|
||||
Bookmark = (int) TotalBookmarks,
|
||||
Id = Id.ToString(),
|
||||
IsLiked = IsBookmarked,
|
||||
IsManga = PageCount != 1,
|
||||
IsUgoira = Type == "ugoira",
|
||||
Origin = MetaSinglePage.OriginalImageUrl.IsNullOrEmpty() ? MetaPages[0].ImageUrls.Original : MetaSinglePage.OriginalImageUrl,
|
||||
Large = ImageUrls.Large,
|
||||
Tags = Tags.Select(t => new ViewModel.Tag { Name = t.Name, TranslatedName = t.TranslatedName }),
|
||||
Thumbnail = ImageUrls.Medium,
|
||||
Title = Title,
|
||||
UserId = User.Id.ToString(),
|
||||
UserName = User.Name,
|
||||
Resolution = $"{Width}x{Height}",
|
||||
ViewCount = (int) TotalView,
|
||||
PublishDate = CreateDate
|
||||
}.Apply(i =>
|
||||
{
|
||||
if (i.IsManga)
|
||||
{
|
||||
i.MangaMetadata = MetaPages.Select(p =>
|
||||
{
|
||||
var page = (Illustration) i.Clone();
|
||||
page.Thumbnail = p.ImageUrls.Medium;
|
||||
page.Origin = p.ImageUrls.Original;
|
||||
page.Large = p.ImageUrls.Large;
|
||||
return page;
|
||||
}).ToArray();
|
||||
foreach (var illustration in i.MangaMetadata)
|
||||
{
|
||||
illustration.MangaMetadata = i.MangaMetadata;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class MetaPage
|
||||
{
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
}
|
||||
|
||||
public class MetaSinglePage
|
||||
{
|
||||
[JsonProperty("original_image_url", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OriginalImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
164
Pixeval/Data/Web/Response/SingleWorkResponse.cs
Normal file
164
Pixeval/Data/Web/Response/SingleWorkResponse.cs
Normal file
@ -0,0 +1,164 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class SingleWorkResponse
|
||||
{
|
||||
[JsonProperty("illust")]
|
||||
public Illust IllustInfo { get; set; }
|
||||
|
||||
public class Illust
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public List<string> Tools { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public long Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public long Height { get; set; }
|
||||
|
||||
[JsonProperty("sanity_level")]
|
||||
public long SanityLevel { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("meta_single_page")]
|
||||
public MetaSinglePage MetaSinglePage { get; set; }
|
||||
|
||||
[JsonProperty("meta_pages")]
|
||||
public List<MetaPage> MetaPages { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
|
||||
[JsonProperty("total_comments")]
|
||||
public long TotalComments { get; set; }
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class MetaPage
|
||||
{
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
}
|
||||
|
||||
public class MetaSinglePage
|
||||
{
|
||||
[JsonProperty("original_image_url")]
|
||||
public string OriginalImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
49
Pixeval/Data/Web/Response/SpotlightArticleResponse.cs
Normal file
49
Pixeval/Data/Web/Response/SpotlightArticleResponse.cs
Normal file
@ -0,0 +1,49 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class SpotlightArticleResponse
|
||||
{
|
||||
[JsonProperty("body")]
|
||||
public List<Body> BodyList { get; set; }
|
||||
|
||||
public class Body
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("illusts")]
|
||||
public List<Illust> Illusts { get; set; }
|
||||
}
|
||||
|
||||
public class Illust
|
||||
{
|
||||
[JsonProperty("illust_id")]
|
||||
public long IllustId { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
35
Pixeval/Data/Web/Response/SpotlightResponse.cs
Normal file
35
Pixeval/Data/Web/Response/SpotlightResponse.cs
Normal file
@ -0,0 +1,35 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Data.ViewModel;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class SpotlightResponse
|
||||
{
|
||||
[JsonProperty("spotlight_articles")]
|
||||
public List<SpotlightArticle> SpotlightArticles { get; set; }
|
||||
|
||||
[JsonProperty("next_url")]
|
||||
public string NextUrl { get; set; }
|
||||
}
|
||||
}
|
136
Pixeval/Data/Web/Response/TokenResponse.cs
Normal file
136
Pixeval/Data/Web/Response/TokenResponse.cs
Normal file
@ -0,0 +1,136 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Objects.Exceptions;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class TokenResponse
|
||||
{
|
||||
[JsonProperty("response")]
|
||||
public Response ToResponse { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.ToJson();
|
||||
}
|
||||
|
||||
public class Response
|
||||
{
|
||||
[JsonProperty("access_token")]
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
[JsonProperty("expires_in")]
|
||||
public long ExpiresIn { get; set; }
|
||||
|
||||
[JsonProperty("token_type")]
|
||||
public string TokenType { get; set; }
|
||||
|
||||
[JsonProperty("scope")]
|
||||
public string Scope { get; set; }
|
||||
|
||||
[JsonProperty("refresh_token")]
|
||||
public string RefreshToken { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("device_token")]
|
||||
public string DeviceToken { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("id")]
|
||||
[JsonConverter(typeof(ParseStringConverter))]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("mail_address")]
|
||||
public string MailAddress { get; set; }
|
||||
|
||||
[JsonProperty("is_premium")]
|
||||
public bool IsPremium { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("is_mail_authorized")]
|
||||
public bool IsMailAuthorized { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("px_16x16")]
|
||||
public string Px16X16 { get; set; }
|
||||
|
||||
[JsonProperty("px_50x50")]
|
||||
public string Px50X50 { get; set; }
|
||||
|
||||
[JsonProperty("px_170x170")]
|
||||
public string Px170X170 { get; set; }
|
||||
}
|
||||
|
||||
private class ParseStringConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type t)
|
||||
{
|
||||
return t == typeof(long) || t == typeof(long?);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var value = serializer.Deserialize<string>(reader);
|
||||
if (long.TryParse(value, out var l))
|
||||
{
|
||||
return l;
|
||||
}
|
||||
throw new TypeMismatchException("Cannot unmarshal type long");
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
|
||||
{
|
||||
if (untypedValue == null)
|
||||
{
|
||||
serializer.Serialize(writer, null);
|
||||
return;
|
||||
}
|
||||
|
||||
var value = (long) untypedValue;
|
||||
serializer.Serialize(writer, value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
173
Pixeval/Data/Web/Response/TrendingTagResponse.cs
Normal file
173
Pixeval/Data/Web/Response/TrendingTagResponse.cs
Normal file
@ -0,0 +1,173 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class TrendingTagResponse
|
||||
{
|
||||
[JsonProperty("trend_tags")]
|
||||
public List<TrendTag> TrendTags { get; set; }
|
||||
|
||||
public class TrendTag
|
||||
{
|
||||
[JsonProperty("tag")]
|
||||
public string TagStr { get; set; }
|
||||
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
|
||||
[JsonProperty("illust")]
|
||||
public Illust Illust { get; set; }
|
||||
}
|
||||
|
||||
public class Illust
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public List<string> Tools { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public long Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public long Height { get; set; }
|
||||
|
||||
[JsonProperty("sanity_level")]
|
||||
public long SanityLevel { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("meta_single_page")]
|
||||
public MetaSinglePage MetaSinglePage { get; set; }
|
||||
|
||||
[JsonProperty("meta_pages")]
|
||||
public List<MetaPage> MetaPages { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class MetaPage
|
||||
{
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
}
|
||||
|
||||
public class MetaSinglePage
|
||||
{
|
||||
[JsonProperty("original_image_url", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OriginalImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
55
Pixeval/Data/Web/Response/UgoiraMetadataResponse.cs
Normal file
55
Pixeval/Data/Web/Response/UgoiraMetadataResponse.cs
Normal file
@ -0,0 +1,55 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class UgoiraMetadataResponse
|
||||
{
|
||||
[JsonProperty("ugoira_metadata")]
|
||||
public UgoiraMetadata UgoiraMetadataInfo { get; set; }
|
||||
|
||||
public class UgoiraMetadata
|
||||
{
|
||||
[JsonProperty("zip_urls")]
|
||||
public ZipUrls ZipUrls { get; set; }
|
||||
|
||||
[JsonProperty("frames")]
|
||||
public List<Frame> Frames { get; set; }
|
||||
}
|
||||
|
||||
public class Frame
|
||||
{
|
||||
[JsonProperty("file")]
|
||||
public string File { get; set; }
|
||||
|
||||
[JsonProperty("delay")]
|
||||
public long Delay { get; set; }
|
||||
}
|
||||
|
||||
public class ZipUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
209
Pixeval/Data/Web/Response/UploadResponse.cs
Normal file
209
Pixeval/Data/Web/Response/UploadResponse.cs
Normal file
@ -0,0 +1,209 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Objects.Generic;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class UploadResponse
|
||||
{
|
||||
[JsonProperty("illusts")]
|
||||
public List<Illust> Illusts { get; set; }
|
||||
|
||||
[JsonProperty("next_url")]
|
||||
public string NextUrl { get; set; }
|
||||
|
||||
public class Illust : IParser<Illustration>
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public List<string> Tools { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public long Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public long Height { get; set; }
|
||||
|
||||
[JsonProperty("sanity_level")]
|
||||
public long SanityLevel { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("meta_single_page")]
|
||||
public MetaSinglePage MetaSinglePage { get; set; }
|
||||
|
||||
[JsonProperty("meta_pages")]
|
||||
public List<MetaPage> MetaPages { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
|
||||
[JsonProperty("total_comments")]
|
||||
public long TotalComments { get; set; }
|
||||
|
||||
public Illustration Parse()
|
||||
{
|
||||
return new Illustration
|
||||
{
|
||||
Bookmark = (int) TotalBookmarks,
|
||||
Id = Id.ToString(),
|
||||
IsLiked = IsBookmarked,
|
||||
IsUgoira = Type == "ugoira",
|
||||
IsManga = !MetaPages.IsNullOrEmpty(),
|
||||
Origin = MetaSinglePage.OriginalImageUrl ?? ImageUrls.Large,
|
||||
Large = ImageUrls.Large,
|
||||
Tags = Tags.Select(t => new ViewModel.Tag { Name = t.Name, TranslatedName = t.TranslatedName }),
|
||||
Thumbnail = ImageUrls.Medium ?? ImageUrls.SquareMedium,
|
||||
Title = Title,
|
||||
UserId = User.Id.ToString(),
|
||||
UserName = User.Name,
|
||||
Resolution = $"{Width}x{Height}",
|
||||
ViewCount = (int) TotalView,
|
||||
PublishDate = CreateDate
|
||||
}.Apply(i =>
|
||||
{
|
||||
if (i.IsManga)
|
||||
{
|
||||
i.MangaMetadata = MetaPages.Select(p =>
|
||||
{
|
||||
var page = (Illustration) i.Clone();
|
||||
page.Thumbnail = p.ImageUrls.Medium ?? p.ImageUrls.SquareMedium;
|
||||
page.Origin = p.ImageUrls.Original;
|
||||
page.Large = p.ImageUrls.Large;
|
||||
return page;
|
||||
}).ToArray();
|
||||
foreach (var illustration in i.MangaMetadata)
|
||||
{
|
||||
illustration.MangaMetadata = i.MangaMetadata;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class MetaPage
|
||||
{
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
}
|
||||
|
||||
public class MetaSinglePage
|
||||
{
|
||||
[JsonProperty("original_image_url", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OriginalImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
198
Pixeval/Data/Web/Response/UserInformationResponse.cs
Normal file
198
Pixeval/Data/Web/Response/UserInformationResponse.cs
Normal file
@ -0,0 +1,198 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class UserInformationResponse
|
||||
{
|
||||
[JsonProperty("user")]
|
||||
public User UserEntity { get; set; }
|
||||
|
||||
[JsonProperty("profile")]
|
||||
public Profile UserProfile { get; set; }
|
||||
|
||||
[JsonProperty("profile_publicity")]
|
||||
public ProfilePublicity UserProfilePublicity { get; set; }
|
||||
|
||||
[JsonProperty("workspace")]
|
||||
public Workspace UserWorkspace { get; set; }
|
||||
|
||||
public class Profile
|
||||
{
|
||||
[JsonProperty("webpage")]
|
||||
public string Webpage { get; set; }
|
||||
|
||||
[JsonProperty("gender")]
|
||||
public string Gender { get; set; }
|
||||
|
||||
[JsonProperty("birth")]
|
||||
public string Birth { get; set; }
|
||||
|
||||
[JsonProperty("birth_day")]
|
||||
public string BirthDay { get; set; }
|
||||
|
||||
[JsonProperty("birth_year")]
|
||||
public long BirthYear { get; set; }
|
||||
|
||||
[JsonProperty("region")]
|
||||
public string Region { get; set; }
|
||||
|
||||
[JsonProperty("address_id")]
|
||||
public long AddressId { get; set; }
|
||||
|
||||
[JsonProperty("country_code")]
|
||||
public string CountryCode { get; set; }
|
||||
|
||||
[JsonProperty("job")]
|
||||
public string Job { get; set; }
|
||||
|
||||
[JsonProperty("job_id")]
|
||||
public long JobId { get; set; }
|
||||
|
||||
[JsonProperty("total_follow_users")]
|
||||
public long TotalFollowUsers { get; set; }
|
||||
|
||||
[JsonProperty("total_mypixiv_users")]
|
||||
public long TotalMypixivUsers { get; set; }
|
||||
|
||||
[JsonProperty("total_illusts")]
|
||||
public long TotalIllusts { get; set; }
|
||||
|
||||
[JsonProperty("total_manga")]
|
||||
public long TotalManga { get; set; }
|
||||
|
||||
[JsonProperty("total_novels")]
|
||||
public long TotalNovels { get; set; }
|
||||
|
||||
[JsonProperty("total_illust_bookmarks_public")]
|
||||
public long TotalIllustBookmarksPublic { get; set; }
|
||||
|
||||
[JsonProperty("total_illust_series")]
|
||||
public long TotalIllustSeries { get; set; }
|
||||
|
||||
[JsonProperty("total_novel_series")]
|
||||
public long TotalNovelSeries { get; set; }
|
||||
|
||||
[JsonProperty("background_image_url")]
|
||||
public string BackgroundImageUrl { get; set; }
|
||||
|
||||
[JsonProperty("twitter_account")]
|
||||
public string TwitterAccount { get; set; }
|
||||
|
||||
[JsonProperty("twitter_url")]
|
||||
public string TwitterUrl { get; set; }
|
||||
|
||||
[JsonProperty("is_premium")]
|
||||
public bool IsPremium { get; set; }
|
||||
|
||||
[JsonProperty("is_using_custom_profile_image")]
|
||||
public bool IsUsingCustomProfileImage { get; set; }
|
||||
}
|
||||
|
||||
public class ProfilePublicity
|
||||
{
|
||||
[JsonProperty("gender")]
|
||||
public string Gender { get; set; }
|
||||
|
||||
[JsonProperty("region")]
|
||||
public string Region { get; set; }
|
||||
|
||||
[JsonProperty("birth_day")]
|
||||
public string BirthDay { get; set; }
|
||||
|
||||
[JsonProperty("birth_year")]
|
||||
public string BirthYear { get; set; }
|
||||
|
||||
[JsonProperty("job")]
|
||||
public string Job { get; set; }
|
||||
|
||||
[JsonProperty("pawoo")]
|
||||
public bool Pawoo { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("comment")]
|
||||
public string Comment { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
|
||||
public class Workspace
|
||||
{
|
||||
[JsonProperty("pc")]
|
||||
public string Pc { get; set; }
|
||||
|
||||
[JsonProperty("monitor")]
|
||||
public string Monitor { get; set; }
|
||||
|
||||
[JsonProperty("tool")]
|
||||
public string Tool { get; set; }
|
||||
|
||||
[JsonProperty("scanner")]
|
||||
public string Scanner { get; set; }
|
||||
|
||||
[JsonProperty("tablet")]
|
||||
public string Tablet { get; set; }
|
||||
|
||||
[JsonProperty("mouse")]
|
||||
public string Mouse { get; set; }
|
||||
|
||||
[JsonProperty("printer")]
|
||||
public string Printer { get; set; }
|
||||
|
||||
[JsonProperty("desktop")]
|
||||
public string Desktop { get; set; }
|
||||
|
||||
[JsonProperty("music")]
|
||||
public string Music { get; set; }
|
||||
|
||||
[JsonProperty("desk")]
|
||||
public string Desk { get; set; }
|
||||
|
||||
[JsonProperty("chair")]
|
||||
public string Chair { get; set; }
|
||||
|
||||
[JsonProperty("comment")]
|
||||
public string Comment { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
106
Pixeval/Data/Web/Response/UserNavResponse.cs
Normal file
106
Pixeval/Data/Web/Response/UserNavResponse.cs
Normal file
@ -0,0 +1,106 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class UserNavResponse
|
||||
{
|
||||
[JsonProperty("user_previews")]
|
||||
public List<UserPreview> UserPreviews { get; set; }
|
||||
|
||||
[JsonProperty("next_url")]
|
||||
public string NextUrl { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.ToJson();
|
||||
}
|
||||
|
||||
public class UserPreview
|
||||
{
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("illusts")]
|
||||
public List<Illust> Illusts { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
}
|
||||
|
||||
public class Illust
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrl { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public string[] Tools { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
207
Pixeval/Data/Web/Response/UserUpdateResponse.cs
Normal file
207
Pixeval/Data/Web/Response/UserUpdateResponse.cs
Normal file
@ -0,0 +1,207 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Pixeval.Data.ViewModel;
|
||||
using Pixeval.Objects.Generic;
|
||||
using Pixeval.Objects.Primitive;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class UserUpdateResponse
|
||||
{
|
||||
[JsonProperty("illusts")]
|
||||
public List<Illust> Illusts { get; set; }
|
||||
|
||||
[JsonProperty("next_url")]
|
||||
public string NextUrl { get; set; }
|
||||
|
||||
public class Illust : IParser<Illustration>
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
|
||||
[JsonProperty("restrict")]
|
||||
public long Restrict { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("tags")]
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
[JsonProperty("tools")]
|
||||
public List<string> Tools { get; set; }
|
||||
|
||||
[JsonProperty("create_date")]
|
||||
public DateTimeOffset CreateDate { get; set; }
|
||||
|
||||
[JsonProperty("page_count")]
|
||||
public long PageCount { get; set; }
|
||||
|
||||
[JsonProperty("width")]
|
||||
public long Width { get; set; }
|
||||
|
||||
[JsonProperty("height")]
|
||||
public long Height { get; set; }
|
||||
|
||||
[JsonProperty("sanity_level")]
|
||||
public long SanityLevel { get; set; }
|
||||
|
||||
[JsonProperty("x_restrict")]
|
||||
public long XRestrict { get; set; }
|
||||
|
||||
[JsonProperty("meta_single_page")]
|
||||
public MetaSinglePage MetaSinglePage { get; set; }
|
||||
|
||||
[JsonProperty("meta_pages")]
|
||||
public List<MetaPage> MetaPages { get; set; }
|
||||
|
||||
[JsonProperty("total_view")]
|
||||
public long TotalView { get; set; }
|
||||
|
||||
[JsonProperty("total_bookmarks")]
|
||||
public long TotalBookmarks { get; set; }
|
||||
|
||||
[JsonProperty("is_bookmarked")]
|
||||
public bool IsBookmarked { get; set; }
|
||||
|
||||
[JsonProperty("visible")]
|
||||
public bool Visible { get; set; }
|
||||
|
||||
[JsonProperty("is_muted")]
|
||||
public bool IsMuted { get; set; }
|
||||
|
||||
public Illustration Parse()
|
||||
{
|
||||
return new Illustration
|
||||
{
|
||||
Bookmark = (int) TotalBookmarks,
|
||||
Id = Id.ToString(),
|
||||
IsLiked = IsBookmarked,
|
||||
IsManga = PageCount != 1,
|
||||
IsUgoira = Type == "ugoira",
|
||||
Origin = MetaSinglePage.OriginalImageUrl.IsNullOrEmpty() ? ImageUrls.Large : MetaSinglePage.OriginalImageUrl,
|
||||
Large = ImageUrls.Large,
|
||||
Tags = Tags.Select(t => new ViewModel.Tag { Name = t.Name, TranslatedName = t.TranslatedName }),
|
||||
Thumbnail = ImageUrls.Medium,
|
||||
UserId = User.Id.ToString(),
|
||||
UserName = User.Name,
|
||||
Title = Title,
|
||||
Resolution = $"{Width}x{Height}",
|
||||
ViewCount = (int) TotalView,
|
||||
PublishDate = CreateDate
|
||||
}.Apply(i =>
|
||||
{
|
||||
if (i.IsManga)
|
||||
{
|
||||
i.MangaMetadata = MetaPages.Select(p =>
|
||||
{
|
||||
var page = (Illustration) i.Clone();
|
||||
page.Thumbnail = p.ImageUrls.Medium;
|
||||
page.Origin = p.ImageUrls.Original;
|
||||
page.Large = p.ImageUrls.Large;
|
||||
return page;
|
||||
}).ToArray();
|
||||
foreach (var illustration in i.MangaMetadata)
|
||||
{
|
||||
illustration.MangaMetadata = i.MangaMetadata;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageUrls
|
||||
{
|
||||
[JsonProperty("square_medium")]
|
||||
public string SquareMedium { get; set; }
|
||||
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
|
||||
[JsonProperty("large")]
|
||||
public string Large { get; set; }
|
||||
|
||||
[JsonProperty("original", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Original { get; set; }
|
||||
}
|
||||
|
||||
public class MetaPage
|
||||
{
|
||||
[JsonProperty("image_urls")]
|
||||
public ImageUrls ImageUrls { get; set; }
|
||||
}
|
||||
|
||||
public class MetaSinglePage
|
||||
{
|
||||
[JsonProperty("original_image_url", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string OriginalImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("translated_name")]
|
||||
public string TranslatedName { get; set; }
|
||||
}
|
||||
|
||||
public class User
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("account")]
|
||||
public string Account { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_urls")]
|
||||
public ProfileImageUrls ProfileImageUrls { get; set; }
|
||||
|
||||
[JsonProperty("is_followed")]
|
||||
public bool IsFollowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileImageUrls
|
||||
{
|
||||
[JsonProperty("medium")]
|
||||
public string Medium { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
54
Pixeval/Data/Web/Response/WebApiUserDetailResponse.cs
Normal file
54
Pixeval/Data/Web/Response/WebApiUserDetailResponse.cs
Normal file
@ -0,0 +1,54 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Pixeval.Data.Web.Response
|
||||
{
|
||||
public class WebApiUserDetailResponse
|
||||
{
|
||||
[JsonProperty("body")]
|
||||
public Body ResponseBody { get; set; }
|
||||
|
||||
public class Body
|
||||
{
|
||||
[JsonProperty("user_details")]
|
||||
public UserDetails UserDetails { get; set; }
|
||||
}
|
||||
|
||||
public class UserDetails
|
||||
{
|
||||
[JsonProperty("cover_image")]
|
||||
public CoverImage CoverImage { get; set; }
|
||||
}
|
||||
|
||||
public class CoverImage
|
||||
{
|
||||
[JsonProperty("profile_cover_image")]
|
||||
public ProfileCoverImage ProfileCoverImage { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileCoverImage
|
||||
{
|
||||
[JsonProperty("720x360")]
|
||||
public string The720X360 { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
3
Pixeval/FodyWeavers.xml
Normal file
3
Pixeval/FodyWeavers.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<PropertyChanged />
|
||||
</Weavers>
|
64
Pixeval/FodyWeavers.xsd
Normal file
64
Pixeval/FodyWeavers.xsd
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
|
||||
<xs:element name="Weavers">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="PropertyChanged" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="InjectOnPropertyNameChanged" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if the On_PropertyName_Changed feature is enabled.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="EventInvokerNames" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="CheckForEquality" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="CheckForEqualityUsingBaseEquals" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if equality checks should use the Equals method resolved from the base class.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UseStaticEqualsFromBase" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if equality checks should use the static Equals method resolved from the base class.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SuppressWarnings" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to turn off build warnings from this weaver.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SuppressOnPropertyNameChangedWarning" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to turn off build warnings about mismatched On_PropertyName_Changed methods.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="GenerateXsd" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
27
Pixeval/Objects/Caching/CachingPolicy.cs
Normal file
27
Pixeval/Objects/Caching/CachingPolicy.cs
Normal file
@ -0,0 +1,27 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Pixeval.Objects.Caching
|
||||
{
|
||||
public enum CachingPolicy
|
||||
{
|
||||
Memory, File
|
||||
}
|
||||
}
|
117
Pixeval/Objects/Caching/FileCache.cs
Normal file
117
Pixeval/Objects/Caching/FileCache.cs
Normal file
@ -0,0 +1,117 @@
|
||||
#region Copyright (C) 2019-2020 Dylech30th. All rights reserved.
|
||||
|
||||
// Pixeval - A Strong, Fast and Flexible Pixiv Client
|
||||
// Copyright (C) 2019-2020 Dylech30th
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pixeval.Objects.Caching
|
||||
{
|
||||
public class FileCache<T, THash> : IWeakCacheProvider<T, THash>, IEnumerable<KeyValuePair<THash, string>> where T : class
|
||||
{
|
||||
private readonly Func<T, Stream> cachingPolicy;
|
||||
private readonly ConcurrentDictionary<THash, string> fileMapping = new ConcurrentDictionary<THash, string>();
|
||||
private readonly string initDirectory;
|
||||
private readonly Func<Stream, T> restorePolicy;
|
||||
|
||||
public FileCache(string initDirectory, Func<T, Stream> cachingPolicy, Func<Stream, T> restorePolicy)
|
||||
{
|
||||
this.cachingPolicy = cachingPolicy;
|
||||
this.restorePolicy = restorePolicy;
|
||||
this.initDirectory = initDirectory;
|
||||
|
||||
Directory.CreateDirectory(initDirectory);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<THash, string>> GetEnumerator()
|
||||
{
|
||||
return fileMapping.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Attach(ref T key, THash associateWith)
|
||||
{
|
||||
if (associateWith == null || key == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var path = Path.Combine(initDirectory, IWeakCacheProvider<T, THash>.HashKey(associateWith) + ".tmp");
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
var s = cachingPolicy(key);
|
||||
key = null;
|
||||
Task.Run(() =>
|
||||
{
|
||||
fileMapping.TryAdd(associateWith, path);
|
||||
WriteFile(path, s);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Detach(THash associateWith)
|
||||
{
|
||||
using var sem = new SemaphoreSlim(1);
|
||||
var path = Path.Combine(initDirectory, IWeakCacheProvider<T, THash>.HashKey(associateWith) + ".");
|
||||
if (File.Exists(path))
|
||||
{
|
||||
fileMapping.TryRemove(associateWith, out _);
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool, T)> TryGet([NotNull] THash key)
|
||||
{
|
||||
if (fileMapping.TryGetValue(key, out var file) && File.Exists(file))
|
||||
{
|
||||
await using var fileStream = File.OpenRead(file);
|
||||
fileStream.Position = 0L;
|
||||
await using Stream memoStream = new MemoryStream();
|
||||
await fileStream.CopyToAsync(memoStream);
|
||||
return (true, restorePolicy(memoStream));
|
||||
}
|
||||
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
using var sem = new SemaphoreSlim(1);
|
||||
foreach (var file in Directory.GetFiles(initDirectory))
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
|
||||
private static async void WriteFile(string path, Stream src)
|
||||
{
|
||||
await using var fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
|
||||
src.Position = 0L;
|
||||
await src.CopyToAsync(fileStream);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user