diff --git a/Pixiview/App.xaml.cs b/Pixiview/App.xaml.cs index 3da910a..d907617 100644 --- a/Pixiview/App.xaml.cs +++ b/Pixiview/App.xaml.cs @@ -1,4 +1,6 @@ -using Pixiview.UI; +using System; +using System.Diagnostics; +using Pixiview.UI; using Pixiview.Utils; using Xamarin.Forms; @@ -54,5 +56,15 @@ namespace Pixiview protected override void OnResume() { } + + public static void DebugPrint(string message) + { + Debug.WriteLine("[{0:HH:mm:ss.ffff}] - {1}", DateTime.Now, message); + } + + public static void DebugError(string category, string message) + { + Debug.Fail(string.Format("[{0:HH:mm:ss.ffff}] - {1} - {2}", DateTime.Now, category, message)); + } } } diff --git a/Pixiview/MainPage.xaml.cs b/Pixiview/MainPage.xaml.cs index c47c903..54c18ed 100644 --- a/Pixiview/MainPage.xaml.cs +++ b/Pixiview/MainPage.xaml.cs @@ -1,6 +1,6 @@ using System; using System.ComponentModel; -using System.Diagnostics; +using System.Threading.Tasks; using Pixiview.UI; using Pixiview.Utils; @@ -11,6 +11,8 @@ namespace Pixiview [DesignTimeVisible(false)] public partial class MainPage : AdaptedPage { + private IllustData illustData; + public MainPage() { InitializeComponent(); @@ -19,7 +21,12 @@ namespace Pixiview public override void OnLoad() { - Debug.WriteLine(Stores.PersonalFolder); + App.DebugPrint($"folder: {Stores.PersonalFolder}"); + Task.Run(async () => + { + illustData = await Stores.LoadIllustData(); + App.DebugPrint(illustData.message); + }); } void NavigationTitle_RightButtonClicked(object sender, EventArgs e) diff --git a/Pixiview/Pixiview.csproj b/Pixiview/Pixiview.csproj index 776110c..d5405d3 100644 --- a/Pixiview/Pixiview.csproj +++ b/Pixiview/Pixiview.csproj @@ -13,6 +13,7 @@ + diff --git a/Pixiview/Utils/IllustData.cs b/Pixiview/Utils/IllustData.cs new file mode 100644 index 0000000..60ddaef --- /dev/null +++ b/Pixiview/Utils/IllustData.cs @@ -0,0 +1,106 @@ +using Newtonsoft.Json; + +namespace Pixiview.Utils +{ + public class IllustData + { + public bool error; + public string message; + public Body body; + + public class Body + { + public Page page; + public Thumbnail thumbnails; + public User[] users; + + public class Page + { + public int[] follow; + public string[] recommend; + public RecommendByTag[] recommendByTags; + public Ranking ranking; + public RecommendUser[] recommendUser; + public EditorRecommend[] editorRecommend; + public string[] newPost; + + public class RecommendByTag + { + public string tag; + public string[] ids; + } + + public class Ranking + { + public RankingItem[] items; + public string date; + + public class RankingItem + { + public string rank; + public string id; + } + } + + public class RecommendUser + { + public int id; + public string[] illustIds; + } + + public class EditorRecommend + { + public string illustId; + public string comment; + } + } + + public class Thumbnail + { + public Illust[] illust; + + public class Illust + { + public string illustId; + public string illustTitle; + public string id; + public string title; + public string url; + public string description; + public string[] tags; + public string userId; + public string userName; + public int width; + public int height; + public string alt; + public IllustUrls urls; + public string seriesId; + public string seriesTitle; + public string profileImageUrl; + + public class IllustUrls + { + [JsonProperty("250x250")] + public string x250; + [JsonProperty("360x360")] + public string x360; + [JsonProperty("540x540")] + public string x540; + } + } + } + + public class User + { + public string userId; + public string name; + public string image; + public string imageBig; + public bool premium; + public bool isFollowed; + public string background; + public int partial; + } + } + } +} diff --git a/Pixiview/Utils/Stores.cs b/Pixiview/Utils/Stores.cs index 140fbc0..74d04d4 100644 --- a/Pixiview/Utils/Stores.cs +++ b/Pixiview/Utils/Stores.cs @@ -1,8 +1,11 @@ using System; +using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; +using System.Text; using System.Threading.Tasks; +using Newtonsoft.Json; namespace Pixiview.Utils { @@ -10,14 +13,137 @@ namespace Pixiview.Utils { public static readonly string PersonalFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal); //public static readonly string CacheFolder = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache); - public const string ImageFolder = "images"; + private const string imageFolder = "img-master"; + private const string userFolder = "user-profile"; + private const string illustFile = "illust.json"; - public static async Task DownloadImage(string url) + public static async Task LoadIllustData() { + var file = Path.Combine(PersonalFolder, illustFile); + string content = null; + if (File.Exists(file)) + { + try + { + content = File.ReadAllText(file); + } + catch (Exception ex) + { + App.DebugError("illust.load", $"failed to read file: {file}, error: {ex.Message}"); + } + } + if (content == null) + { + var response = Download(Configs.UrlIllust, headers: new[] + { + ("cookie", Configs.Cookie), + ("x-user-id", Configs.UserId) + }); + if (response == null) + { + return null; + } + using (response) + { + content = await response.Content.ReadAsStringAsync(); + try + { + File.WriteAllText(file, content, Encoding.UTF8); + } + catch (Exception ex) + { + App.DebugError("illust.save", $"failed to save illust JSON object, error: {ex.Message}"); + } + } + } + try + { + return JsonConvert.DeserializeObject(content); + } + catch (Exception ex) + { + App.DebugError("illust.load", $"failed to parse illust JSON object, error: {ex.Message}"); + return null; + } + } + + public static string LoadIllustImage(string url) + { + return LoadImage(url, imageFolder); + } + + public static string LoadUserProfileImage(string url) + { + return LoadImage(url, userFolder); + } + + public static string LoadImage(string url, string folder) + { + var file = Path.Combine(PersonalFolder, imageFolder, Path.GetFileName(url)); + if (File.Exists(file)) + { + return file; + } + else + { + file = DownloadImage(url, folder).Result; + return file; + } + } + + public static async Task DownloadImage(string url, string folder) + { + try + { + var file = Path.Combine(PersonalFolder, folder, Path.GetFileName(url)); + var response = Download(url); + if (response == null) + { + return null; + } + using (response) + using (var fs = File.OpenWrite(file)) + { + await response.Content.CopyToAsync(fs); + if (response.Headers.Date != null) + { + File.SetLastWriteTimeUtc(file, response.Headers.Date.Value.UtcDateTime); + } + } + return file; + } + catch (Exception ex) + { + App.DebugError("image.download", ex.Message); + return null; + } + } + + private static T TryCount(Func func, int tryCount = 3) + { + int tries = 0; + while (tries < tryCount) + { + try + { + return func(); + } + catch (Exception ex) + { + tries++; + App.DebugError("try.do", $"tries: {tries}, error: {ex.Message}"); + } + } + return default; + } + + private static HttpResponseMessage Download(string url, string referer = null, IEnumerable<(string header, string value)> headers = null) + { + App.DebugPrint($"GET: {url}"); var uri = new Uri(url); var handler = new HttpClientHandler { - Proxy = new WebProxy("10.0.10.100", 8088), + Proxy = Configs.Proxy, UseProxy = true }; var client = new HttpClient(handler) @@ -29,14 +155,38 @@ namespace Pixiview.Utils Version = new Version(2, 0) }) { - request.Headers.Referrer = new Uri("https://www.pixiv.net/"); - var file = Path.Combine(PersonalFolder, ImageFolder, Path.GetFileName(uri.LocalPath)); - using (var response = await client.SendAsync(request)) - using (var fs = File.OpenWrite(file)) + request.Headers.Referrer = referer == null ? Configs.Referer : new Uri(referer); + if (headers != null) { - await response.Content.CopyToAsync(fs); + foreach (var (header, value) in headers) + { + request.Headers.Add(header, value); + } } + return TryCount(() => client.SendAsync(request).Result); } } } + + public static class Configs + { + public static readonly WebProxy Proxy = new WebProxy("10.0.10.100", 8088); + public static readonly Uri Referer = new Uri("https://www.pixiv.net/"); + + public const string UrlIllust = "https://www.pixiv.net/ajax/top/illust?mode=all&lang=zh"; + public const string Cookie = "first_visit_datetime_pc=2019-10-29+22%3A05%3A30; p_ab_id=2; p_ab_id_2=6;" + + " p_ab_d_id=1155161977; a_type=0; b_type=1; d_type=2; module_orders_mypage=%5B%7B%22name%22%3A%22s" + + "ketch_live%22%2C%22visible%22%3Atrue%7D%2C%7B%22name%22%3A%22tag_follow%22%2C%22visible%22%3Atrue" + + "%7D%2C%7B%22name%22%3A%22recommended_illusts%22%2C%22visible%22%3Atrue%7D%2C%7B%22name%22%3A%22ev" + + "eryone_new_illusts%22%2C%22visible%22%3Atrue%7D%2C%7B%22name%22%3A%22following_new_illusts%22%2C%" + + "22visible%22%3Atrue%7D%2C%7B%22name%22%3A%22mypixiv_new_illusts%22%2C%22visible%22%3Atrue%7D%2C%7" + + "B%22name%22%3A%22spotlight%22%2C%22visible%22%3Atrue%7D%2C%7B%22name%22%3A%22fanbox%22%2C%22visib" + + "le%22%3Atrue%7D%2C%7B%22name%22%3A%22featured_tags%22%2C%22visible%22%3Atrue%7D%2C%7B%22name%22%3" + + "A%22contests%22%2C%22visible%22%3Atrue%7D%2C%7B%22name%22%3A%22user_events%22%2C%22visible%22%3At" + + "rue%7D%2C%7B%22name%22%3A%22sensei_courses%22%2C%22visible%22%3Atrue%7D%2C%7B%22name%22%3A%22boot" + + "h_follow_items%22%2C%22visible%22%3Atrue%7D%5D; yuid_b=NgcXQWQ; login_ever=yes; c_type=31; PHPSES" + + "SID=2603358_VHyGPeRaz7LpeoFkRsHvjXIpApCMb56a; __cfduid=d9fa2d4d1ddd30db85ebb519f9855d256158780674" + + "7; privacy_policy_agreement=2"; + public const string UserId = "2603358"; + } }