diff --git a/Pixiview.iOS/AppDelegate.cs b/Pixiview.iOS/AppDelegate.cs
index 14d3c98..47ab490 100644
--- a/Pixiview.iOS/AppDelegate.cs
+++ b/Pixiview.iOS/AppDelegate.cs
@@ -23,5 +23,11 @@ namespace Pixiview.iOS
return base.FinishedLaunching(app, options);
}
+
+ public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
+ {
+ App.DebugPrint($"url: {url}.");
+ return App.OpenUrl(url.AbsoluteString);
+ }
}
}
diff --git a/Pixiview.iOS/Info.plist b/Pixiview.iOS/Info.plist
index 1d65878..3861c37 100644
--- a/Pixiview.iOS/Info.plist
+++ b/Pixiview.iOS/Info.plist
@@ -50,5 +50,20 @@
UIFileSharingEnabled
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Viewer
+ CFBundleURLSchemes
+
+ pixiview
+
+ CFBundleURLName
+ org.tsanie.pixiview
+ CFBundleURLIconFile
+ Assets.xcassets/AppIcon.appiconset/Icon58
+
+
diff --git a/Pixiview/App.cs b/Pixiview/App.cs
index e3fea30..c414be8 100644
--- a/Pixiview/App.cs
+++ b/Pixiview/App.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Text.RegularExpressions;
+using Pixiview.Illust;
using Pixiview.Resources;
using Pixiview.UI.Theme;
using Pixiview.Utils;
@@ -96,5 +98,28 @@ namespace Pixiview
{
Debug.Fail(string.Format("[{0:HH:mm:ss.ffff}] - {1} - {2}", DateTime.Now, category, message));
}
+
+ public static bool OpenUrl(string url)
+ {
+ var current = Current.MainPage;
+ if (current != null)
+ {
+ var m = Regex.Match(url, "/artworks/([0-9]+)", RegexOptions.IgnoreCase);
+ if (m.Success)
+ {
+ var illust = new IllustItem { Id = m.Groups[1].Value };
+ var page = new ViewIllustPage(illust, true);
+ MainThread.BeginInvokeOnMainThread(() => current.Navigation.PushAsync(page));
+ }
+ else
+ {
+ MainThread.BeginInvokeOnMainThread(() => current.DisplayAlert(
+ url,
+ ResourceHelper.InvalidUrl,
+ ResourceHelper.Ok));
+ }
+ }
+ return true;
+ }
}
}
diff --git a/Pixiview/Illust/FavoritesPage.xaml.cs b/Pixiview/Illust/FavoritesPage.xaml.cs
index 7bd5c05..8e62a95 100644
--- a/Pixiview/Illust/FavoritesPage.xaml.cs
+++ b/Pixiview/Illust/FavoritesPage.xaml.cs
@@ -15,6 +15,10 @@ namespace Pixiview.Illust
protected override bool IsFavoriteVisible => false;
+ public override void OnUnload()
+ {
+ }
+
protected override void OnAppearing()
{
//base.OnAppearing();
diff --git a/Pixiview/Illust/IllustCollectionPage.cs b/Pixiview/Illust/IllustCollectionPage.cs
index 09453ed..43ba8f5 100644
--- a/Pixiview/Illust/IllustCollectionPage.cs
+++ b/Pixiview/Illust/IllustCollectionPage.cs
@@ -13,10 +13,7 @@ using Xamarin.Forms;
namespace Pixiview.Illust
{
- public abstract class FavoriteIllustCollectionPage : IllustCollectionPage
- {
- public override void OnUnload() { }
- }
+ public abstract class FavoriteIllustCollectionPage : IllustCollectionPage { }
public abstract class IllustDataCollectionPage : IllustCollectionPage { }
public abstract class IllustUserDataCollectionPage : IllustCollectionPage { }
@@ -138,7 +135,7 @@ namespace Pixiview.Illust
protected abstract IEnumerable DoGetIllustList(T data, ICommand command);
protected virtual void OnIllustImageTapped(IllustItem illust)
{
- var page = new ViewIllustPage(illust, this);
+ var page = new ViewIllustPage(illust, IsFavoriteVisible);
Navigation.PushAsync(page);
}
@@ -452,6 +449,8 @@ namespace Pixiview.Illust
[JsonObject(MemberSerialization.OptIn)]
public class IllustItem : BindableObject
{
+ public static readonly BindableProperty TitleProperty = BindableProperty.Create(
+ nameof(Title), typeof(string), typeof(IllustItem));
public static readonly BindableProperty ImageProperty = BindableProperty.Create(
nameof(Image), typeof(ImageSource), typeof(IllustItem));
public static readonly BindableProperty ProfileImageProperty = BindableProperty.Create(
@@ -461,6 +460,12 @@ namespace Pixiview.Illust
public static readonly BindableProperty IsFavoriteProperty = BindableProperty.Create(
nameof(IsFavorite), typeof(bool), typeof(IllustItem));
+ [JsonProperty]
+ public string Title
+ {
+ get => (string)GetValue(TitleProperty);
+ set => SetValue(TitleProperty, value);
+ }
public ImageSource Image
{
get => (ImageSource)GetValue(ImageProperty);
@@ -488,8 +493,6 @@ namespace Pixiview.Illust
[JsonProperty]
public string ImageUrl { get; set; }
[JsonProperty]
- public string Title { get; set; }
- [JsonProperty]
public bool IsRestrict { get; set; }
[JsonProperty]
public string ProfileUrl { get; set; }
diff --git a/Pixiview/Illust/RankingPage.xaml.cs b/Pixiview/Illust/RankingPage.xaml.cs
index cc2b849..b0b65b9 100644
--- a/Pixiview/Illust/RankingPage.xaml.cs
+++ b/Pixiview/Illust/RankingPage.xaml.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Windows.Input;
using Pixiview.UI;
using Pixiview.Utils;
+using Xamarin.Essentials;
using Xamarin.Forms;
namespace Pixiview.Illust
@@ -69,7 +70,7 @@ namespace Pixiview.Illust
{
date = date.Substring(0, 4) + "-" + date.Substring(4, 2) + "-" + date.Substring(6, 2);
}
- Device.BeginInvokeOnMainThread(() => Title = date);
+ MainThread.BeginInvokeOnMainThread(() => Title = date);
}
return data;
}
diff --git a/Pixiview/Illust/ViewIllustPage.xaml.cs b/Pixiview/Illust/ViewIllustPage.xaml.cs
index ee75910..7cba37a 100644
--- a/Pixiview/Illust/ViewIllustPage.xaml.cs
+++ b/Pixiview/Illust/ViewIllustPage.xaml.cs
@@ -55,15 +55,15 @@ namespace Pixiview.Illust
public int CurrentPage { get; private set; }
- private readonly IIllustCollectionPage collectionPage;
+ private readonly bool saveFavorites;
private readonly ICommand longPressed;
private readonly ImageSource fontIconLove;
private readonly ImageSource fontIconNotLove;
- public ViewIllustPage(IllustItem illust, IIllustCollectionPage page)
+ public ViewIllustPage(IllustItem illust, bool save)
{
IllustItem = illust;
- collectionPage = page;
+ saveFavorites = save;
longPressed = new Command(Illust_LongPressed);
BindingContext = this;
@@ -97,7 +97,7 @@ namespace Pixiview.Illust
{
base.OnDisappearing();
- if (collectionPage is IllustDataCollectionPage)
+ if (saveFavorites)
{
Stores.SaveFavoritesIllusts();
}
@@ -161,7 +161,7 @@ namespace Pixiview.Illust
LongPressed = longPressed
};
}
- items = tmp;
+ Illusts = items = tmp;
}
for (var i = 0; i < items.Length; i++)
@@ -170,6 +170,20 @@ namespace Pixiview.Illust
var p = pages.body[i];
item.PreviewUrl = p.urls.regular;
item.OriginalUrl = p.urls.original;
+
+ if (i == 0 && illustItem.ImageUrl == null)
+ {
+ // maybe open from a link
+ var preload = Stores.LoadIllustPreloadData(illustItem.Id);
+ if (preload != null && preload.illust.TryGetValue(illustItem.Id, out var illust))
+ {
+ illust.CopyToItem(illustItem);
+ if (preload.user.TryGetValue(illust.userId, out var user))
+ {
+ illustItem.ProfileUrl = user.image;
+ }
+ }
+ }
}
DoLoadImage(0, true);
@@ -329,7 +343,7 @@ namespace Pixiview.Illust
var image = Stores.LoadIllustImage(item.OriginalUrl);
if (image != null)
{
- Device.BeginInvokeOnMainThread(async () =>
+ MainThread.BeginInvokeOnMainThread(async () =>
{
var service = DependencyService.Get();
var result = await service.SaveImageToGalleryAsync(image);
diff --git a/Pixiview/Resources/Languages/zh-CN.xml b/Pixiview/Resources/Languages/zh-CN.xml
index 5bf800d..a45cc3f 100644
--- a/Pixiview/Resources/Languages/zh-CN.xml
+++ b/Pixiview/Resources/Languages/zh-CN.xml
@@ -20,4 +20,5 @@
浏览用户
成功保存图片到照片库。
原图已保存,是否继续?
+ 无法识别该 URL。
\ No newline at end of file
diff --git a/Pixiview/Resources/ResourceHelper.cs b/Pixiview/Resources/ResourceHelper.cs
index 28b0b1f..d4936d6 100644
--- a/Pixiview/Resources/ResourceHelper.cs
+++ b/Pixiview/Resources/ResourceHelper.cs
@@ -22,6 +22,7 @@ namespace Pixiview.Resources
public static string UserDetail => GetResource(nameof(UserDetail));
public static string SaveSuccess => GetResource(nameof(SaveSuccess));
public static string AlreadySavedQuestion => GetResource(nameof(AlreadySavedQuestion));
+ public static string InvalidUrl => GetResource(nameof(InvalidUrl));
static readonly Dictionary dict = new Dictionary();
diff --git a/Pixiview/Utils/IllustData.cs b/Pixiview/Utils/IllustData.cs
index 0be7284..e3537d1 100644
--- a/Pixiview/Utils/IllustData.cs
+++ b/Pixiview/Utils/IllustData.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using Newtonsoft.Json;
using Pixiview.Illust;
@@ -47,8 +48,8 @@ namespace Pixiview.Utils
return new IllustItem
{
Id = illustId,
- ImageUrl = urls?.x360 ?? url,
Title = illustTitle,
+ ImageUrl = urls?.x360 ?? url,
IsRestrict = xRestrict == 1,
ProfileUrl = profileImageUrl,
UserId = userId,
@@ -60,6 +61,18 @@ namespace Pixiview.Utils
}
}
+ 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;
+ }
+
public class IllustData : IllustResponse { }
public class IllustBody
{
@@ -112,20 +125,92 @@ namespace Pixiview.Utils
{
public Illust[] illust;
}
+ }
- public class User
+ public class IllustPreloadBody
+ {
+ public Dictionary illust;
+ public Dictionary user;
+
+ public class Illust
{
+ public string illustId;
+ public string illustTitle;
+ public string illustComment;
+ public string id;
+ public string title;
+ public string description;
+ public int illustType;
+ public DateTime createDate;
+ public DateTime uploadDate;
+ public int xRestrict;
+ public IllustUrls urls;
+ public IllustTag tags;
+ public string alt;
public string userId;
- public string name;
- public string image;
- public string imageBig;
- public bool premium;
- public bool isFollowed;
- public string background;
- public int partial;
+ public string userName;
+ public string userAccount;
+ //public Dictionary userIllusts;
+ public int width;
+ public int height;
+ public int pageCount;
+ public int bookmarkCount;
+ public int likeCount;
+ public int commentCount;
+ public int responseCount;
+ public int viewCount;
+ public bool isOriginal;
+
+ public IllustItem CopyToItem(IllustItem item)
+ {
+ item.Title = illustTitle;
+ item.ImageUrl = urls?.regular;
+ item.IsRestrict = xRestrict == 1;
+ item.UserId = userId;
+ item.UserName = userName;
+ item.Width = width;
+ item.Height = height;
+ item.PageCount = pageCount;
+ return item;
+ }
+
+ [JsonIgnore]
+ public string Url => urls.regular;
+
+ public class IllustUrls
+ {
+ public string mini;
+ public string thumb;
+ public string small;
+ public string regular;
+ public string original;
+ }
+
+ public class IllustTag
+ {
+ public string authorId;
+ public bool isLocked;
+ public IllustTagItem[] tags;
+ public bool writable;
+
+ public class IllustTagItem
+ {
+ public string tag;
+ public bool locked;
+ public bool deletable;
+ public string userId;
+ public IllustTranslate translation;
+ public string userName;
+ }
+ }
}
}
+ public class IllustTranslate
+ {
+ public string en;
+ }
+
public class IllustPageData : IllustResponse { }
public class IllustPageBody
{
diff --git a/Pixiview/Utils/Stores.cs b/Pixiview/Utils/Stores.cs
index abdb0f5..24ffeac 100644
--- a/Pixiview/Utils/Stores.cs
+++ b/Pixiview/Utils/Stores.cs
@@ -18,15 +18,16 @@ namespace Pixiview.Utils
public static readonly string PersonalFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
public static readonly string CacheFolder = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache);
- private const string pagesFolder = "pages";
private const string imageFolder = "img-original";
private const string previewFolder = "img-master";
- private const string thumbFolder = "img-thumb";
- private const string userFolder = "user-profile";
-
private const string illustFile = "illust.json";
private const string favoriteFile = "favorites.json";
+ private const string pagesFolder = "pages";
+ private const string preloadsFolder = "preloads";
+ private const string thumbFolder = "img-thumb";
+ private const string userFolder = "user-profile";
+
private static readonly object sync = new object();
public static bool NetworkAvailable
@@ -93,7 +94,7 @@ namespace Pixiview.Utils
}
}
- private static T LoadObject(string file, string url, string referer = null, bool force = false)
+ private static T LoadObject(string file, string url, string referer, bool force = false, Func action = null)
{
string content = null;
if (!force && file != null && File.Exists(file))
@@ -111,7 +112,10 @@ namespace Pixiview.Utils
{
var response = Download(url, headers =>
{
- headers.Referrer = referer == null ? Configs.Referer : new Uri(referer);
+ if (referer != null)
+ {
+ headers.Referrer = new Uri(referer);
+ }
headers.Add("user-agent", Configs.UserAgent);
headers.Add("accept", Configs.AcceptJson);
headers.Add("cookie", Configs.Cookie);
@@ -123,7 +127,20 @@ namespace Pixiview.Utils
}
using (response)
{
- content = response.Content.ReadAsStringAsync().Result;
+ try
+ {
+ content = response.Content.ReadAsStringAsync().Result;
+ if (action != null)
+ {
+ content = action(content);
+ }
+ }
+ catch (Exception ex)
+ {
+ App.DebugError("load.strea", $"failed to read stream, error: {ex.Message}");
+ return default;
+ }
+
if (file != null)
{
try
@@ -217,18 +234,52 @@ namespace Pixiview.Utils
var result = LoadObject(
file,
Configs.UrlIllustList,
+ Configs.Referer,
force: force);
+ if (result.error)
+ {
+ App.DebugPrint($"error when load illust data: {result.message} ({force})");
+ }
+ return result;
+ }
+
+ public static IllustPreloadBody LoadIllustPreloadData(string id, bool force = false)
+ {
+ var file = Path.Combine(CacheFolder, preloadsFolder, $"{id}.json");
+ var result = LoadObject(
+ file,
+ string.Format(Configs.UrlIllust, id),
+ null,
+ force: force,
+ action: content =>
+ {
+ var index = content.IndexOf(Configs.SuffixPreload);
+ if (index > 0)
+ {
+ index += Configs.SuffixPreloadLength;
+ var end = content.IndexOf('\'', index);
+ if (end > index)
+ {
+ content = content.Substring(index, end - index);
+ }
+ }
+ return content;
+ });
return result;
}
public static IllustPageData LoadIllustPageData(string id, bool force = false)
{
- var file = Path.Combine(PersonalFolder, pagesFolder, $"{id}.json");
+ var file = Path.Combine(CacheFolder, pagesFolder, $"{id}.json");
var result = LoadObject(
file,
string.Format(Configs.UrlIllustPage, id),
string.Format(Configs.UrlIllust, id),
force: force);
+ if (result.error)
+ {
+ App.DebugPrint($"error when load page data: {result.message} ({force})");
+ }
return result;
}
@@ -239,7 +290,12 @@ namespace Pixiview.Utils
string.Format(Configs.UrlIllustUserAll, userId),
string.Format(Configs.UrlIllustUser, userId),
force: force);
+ if (list.error)
+ {
+ App.DebugPrint($"error when load user data: {list.message} ({force})");
+ }
+ // TODO
var ids = string.Join("&ids%5B%5D=", list.body.illusts.Keys.Take(20));
var result = LoadObject(
@@ -247,6 +303,10 @@ namespace Pixiview.Utils
string.Format(Configs.UrlIllustUserArtworks, userId, ids, 1),
string.Format(Configs.UrlIllustUser, userId),
force: force);
+ if (result.error)
+ {
+ App.DebugPrint($"error when load user illust data: {result.message} ({force})");
+ }
return result;
}
@@ -330,7 +390,7 @@ namespace Pixiview.Utils
App.DebugPrint($"download, url: {url}");
var response = Download(url, headers =>
{
- headers.Referrer = Configs.Referer;
+ headers.Referrer = new Uri(Configs.Referer);
headers.Add("user-agent", Configs.UserAgent);
headers.Add("accept", Configs.AcceptImage);
});
@@ -409,11 +469,13 @@ namespace Pixiview.Utils
public static class Configs
{
public static readonly WebProxy Proxy = new WebProxy("router.tsanie.us", 8088);
- public static readonly Uri Referer = new Uri("https://www.pixiv.net/");
public const int MaxThreads = 3;
+ public const string Referer = "https://www.pixiv.net/";
public const string UrlIllustList = "https://www.pixiv.net/ajax/top/illust?mode=all&lang=zh";
public const string UrlIllust = "https://www.pixiv.net/artworks/{0}";
+ public const string SuffixPreload = " id=\"meta-preload-data\" content='";
+ public const int SuffixPreloadLength = 33; // SuffixPreload.Length
public const string UrlIllustUserAll = "https://www.pixiv.net/ajax/user/{0}/profile/all?lang=zh";
public const string UrlIllustUserArtworks = "https://www.pixiv.net/ajax/user/{0}/profile/illusts?ids%5B%5D={1}&work_category=illustManga&is_first_page={2}&lang=zh";
public const string UrlIllustUser = "https://www.pixiv.net/users/{0}/artworks";