feature: open with URL
This commit is contained in:
parent
33fe1c8cc1
commit
dffe0bb3a4
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,5 +50,20 @@
|
||||
<true/>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>pixiview</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>org.tsanie.pixiview</string>
|
||||
<key>CFBundleURLIconFile</key>
|
||||
<string>Assets.xcassets/AppIcon.appiconset/Icon58</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,10 @@ namespace Pixiview.Illust
|
||||
|
||||
protected override bool IsFavoriteVisible => false;
|
||||
|
||||
public override void OnUnload()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnAppearing()
|
||||
{
|
||||
//base.OnAppearing();
|
||||
|
@ -13,10 +13,7 @@ using Xamarin.Forms;
|
||||
|
||||
namespace Pixiview.Illust
|
||||
{
|
||||
public abstract class FavoriteIllustCollectionPage : IllustCollectionPage<IllustItem[]>
|
||||
{
|
||||
public override void OnUnload() { }
|
||||
}
|
||||
public abstract class FavoriteIllustCollectionPage : IllustCollectionPage<IllustItem[]> { }
|
||||
public abstract class IllustDataCollectionPage : IllustCollectionPage<IllustData> { }
|
||||
public abstract class IllustUserDataCollectionPage : IllustCollectionPage<IllustUserData> { }
|
||||
|
||||
@ -138,7 +135,7 @@ namespace Pixiview.Illust
|
||||
protected abstract IEnumerable<IllustItem> 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; }
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<IllustDetailItem>(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<IFileStore>();
|
||||
var result = await service.SaveImageToGalleryAsync(image);
|
||||
|
@ -20,4 +20,5 @@
|
||||
<UserDetail>浏览用户</UserDetail>
|
||||
<SaveSuccess>成功保存图片到照片库。</SaveSuccess>
|
||||
<AlreadySavedQuestion>原图已保存,是否继续?</AlreadySavedQuestion>
|
||||
<InvalidUrl>无法识别该 URL。</InvalidUrl>
|
||||
</root>
|
@ -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<string, LanguageResource> dict = new Dictionary<string, LanguageResource>();
|
||||
|
||||
|
@ -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<IllustBody> { }
|
||||
public class IllustBody
|
||||
{
|
||||
@ -112,20 +125,92 @@ namespace Pixiview.Utils
|
||||
{
|
||||
public Illust[] illust;
|
||||
}
|
||||
}
|
||||
|
||||
public class User
|
||||
public class IllustPreloadBody
|
||||
{
|
||||
public Dictionary<string, Illust> illust;
|
||||
public Dictionary<string, User> 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<string, Illust> 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<IllustPageBody[]> { }
|
||||
public class IllustPageBody
|
||||
{
|
||||
|
@ -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<T>(string file, string url, string referer = null, bool force = false)
|
||||
private static T LoadObject<T>(string file, string url, string referer, bool force = false, Func<string, string> 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<IllustData>(
|
||||
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<IllustPreloadBody>(
|
||||
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<IllustPageData>(
|
||||
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<IllustUserData>(
|
||||
@ -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";
|
||||
|
Loading…
x
Reference in New Issue
Block a user