feature: open with URL

This commit is contained in:
Tsanie Lily 2020-05-09 17:39:01 +08:00
parent 33fe1c8cc1
commit dffe0bb3a4
11 changed files with 251 additions and 34 deletions

View File

@ -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);
}
}
}

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -15,6 +15,10 @@ namespace Pixiview.Illust
protected override bool IsFavoriteVisible => false;
public override void OnUnload()
{
}
protected override void OnAppearing()
{
//base.OnAppearing();

View File

@ -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; }

View File

@ -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;
}

View File

@ -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);

View File

@ -20,4 +20,5 @@
<UserDetail>浏览用户</UserDetail>
<SaveSuccess>成功保存图片到照片库。</SaveSuccess>
<AlreadySavedQuestion>原图已保存,是否继续?</AlreadySavedQuestion>
<InvalidUrl>无法识别该 URL。</InvalidUrl>
</root>

View File

@ -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>();

View File

@ -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
{

View File

@ -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";