diff --git a/Pixiview.Android/Pixiview.Android.csproj b/Pixiview.Android/Pixiview.Android.csproj
index 47aaf0d..f4b971c 100644
--- a/Pixiview.Android/Pixiview.Android.csproj
+++ b/Pixiview.Android/Pixiview.Android.csproj
@@ -81,6 +81,7 @@
+
diff --git a/Pixiview.Android/Renderers/OptionPickerRenderer.cs b/Pixiview.Android/Renderers/OptionPickerRenderer.cs
new file mode 100644
index 0000000..ed987bf
--- /dev/null
+++ b/Pixiview.Android/Renderers/OptionPickerRenderer.cs
@@ -0,0 +1,29 @@
+using Android.Content;
+using Android.Graphics.Drawables;
+using Pixiview.Droid.Renderers;
+using Pixiview.UI;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android;
+
+[assembly: ExportRenderer(typeof(OptionPicker), typeof(OptionPickerRenderer))]
+namespace Pixiview.Droid.Renderers
+{
+ public class OptionPickerRenderer : PickerRenderer
+ {
+ public OptionPickerRenderer(Context context) : base(context)
+ {
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs e)
+ {
+ base.OnElementChanged(e);
+
+ if (e.NewElement != null)
+ {
+ var drawable = new ColorDrawable(e.NewElement.BackgroundColor.ToAndroid());
+ Control.Gravity = Android.Views.GravityFlags.Right;
+ Control.SetBackground(drawable);
+ }
+ }
+ }
+}
diff --git a/Pixiview.iOS/Pixiview.iOS.csproj b/Pixiview.iOS/Pixiview.iOS.csproj
index 894b5e9..0de050d 100644
--- a/Pixiview.iOS/Pixiview.iOS.csproj
+++ b/Pixiview.iOS/Pixiview.iOS.csproj
@@ -84,6 +84,7 @@
+
diff --git a/Pixiview.iOS/Renderers/OptionPickerRenderer.cs b/Pixiview.iOS/Renderers/OptionPickerRenderer.cs
new file mode 100644
index 0000000..8c316a7
--- /dev/null
+++ b/Pixiview.iOS/Renderers/OptionPickerRenderer.cs
@@ -0,0 +1,22 @@
+using Pixiview.iOS.Renderers;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.iOS;
+
+[assembly: ExportRenderer(typeof(Picker), typeof(OptionPickerRenderer))]
+namespace Pixiview.iOS.Renderers
+{
+ public class OptionPickerRenderer : PickerRenderer
+ {
+ protected override void OnElementChanged(ElementChangedEventArgs e)
+ {
+ base.OnElementChanged(e);
+
+ var control = Control;
+ if (control != null)
+ {
+ control.TextAlignment = UIKit.UITextAlignment.Right;
+ control.BorderStyle = UIKit.UITextBorderStyle.None;
+ }
+ }
+ }
+}
diff --git a/Pixiview/App.cs b/Pixiview/App.cs
index 037dd68..ea67e0c 100644
--- a/Pixiview/App.cs
+++ b/Pixiview/App.cs
@@ -3,7 +3,6 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
-using System.Threading.Tasks;
using Pixiview.Illust;
using Pixiview.Resources;
using Pixiview.UI.Theme;
@@ -35,10 +34,8 @@ namespace Pixiview
Configs.SetCookie(Preferences.Get(Configs.CookieKey, null));
Configs.SetUserId(Preferences.Get(Configs.UserIdKey, null));
- // login info
- Task.Run(() => AppShell.Current.DoLoginInformation());
-
Configs.IsOnR18 = Preferences.Get(Configs.IsOnR18Key, false);
+ Configs.SyncFavType = (SyncType)Preferences.Get(Configs.SyncFavTypeKey, 0);
var isProxied = Preferences.Get(Configs.IsProxiedKey, false);
if (isProxied)
{
diff --git a/Pixiview/AppShell.xaml.cs b/Pixiview/AppShell.xaml.cs
index c19c26b..e1da9c3 100644
--- a/Pixiview/AppShell.xaml.cs
+++ b/Pixiview/AppShell.xaml.cs
@@ -50,6 +50,8 @@ namespace Pixiview
public event EventHandler NavigationBarHeightChanged;
public event EventHandler StatusBarHeightChanged;
+ private bool firstLoading = true;
+
public AppShell()
{
BindingContext = this;
@@ -58,6 +60,16 @@ namespace Pixiview
App.DebugPrint($"folder: {Stores.PersonalFolder}");
}
+ protected override void OnNavigated(ShellNavigatedEventArgs args)
+ {
+ if (firstLoading)
+ {
+ firstLoading = false;
+ // login info
+ Task.Run(() => DoLoginInformation(true));
+ }
+ }
+
public void SetNavigationBarHeight(double height)
{
NavigationBarOffset = new Thickness(0, height, 0, 0);
@@ -153,10 +165,14 @@ namespace Pixiview
Preferences.Set(Configs.ProfileIdKey, userId);
Preferences.Set(Configs.ProfileImageKey, img);
}
- UserProfileName = name;
- UserProfileId = $"@{userId}";
+ UserProfileName = name ?? ResourceHelper.Guest;
+ UserProfileId = string.IsNullOrEmpty(userId)
+ ? string.Empty
+ : $"@{userId}";
- UserProfileImage = Stores.LoadUserProfileImage(img);
+ UserProfileImage = img == null
+ ? StyleDefinition.ProfileNone
+ : Stores.LoadUserProfileImage(img);
}
}
diff --git a/Pixiview/Illust/IllustCollectionPage.cs b/Pixiview/Illust/IllustCollectionPage.cs
index 61ca47e..ce6887b 100644
--- a/Pixiview/Illust/IllustCollectionPage.cs
+++ b/Pixiview/Illust/IllustCollectionPage.cs
@@ -837,6 +837,8 @@ namespace Pixiview.Illust
[JsonProperty]
public string Id { get; set; }
[JsonProperty]
+ public string BookmarkId { get; set; }
+ [JsonProperty]
public DateTime FavoriteDateUtc { get; set; }
[JsonProperty]
public string ImageUrl { get; set; }
diff --git a/Pixiview/Illust/ViewIllustPage.xaml.cs b/Pixiview/Illust/ViewIllustPage.xaml.cs
index 8b4bb80..2220c28 100644
--- a/Pixiview/Illust/ViewIllustPage.xaml.cs
+++ b/Pixiview/Illust/ViewIllustPage.xaml.cs
@@ -133,6 +133,7 @@ namespace Pixiview.Illust
private readonly object sync = new object();
private int downloaded = 0;
private int pageCount;
+ private bool isPreloading;
public ViewIllustPage(IllustItem illust, bool save)
{
@@ -383,28 +384,7 @@ namespace Pixiview.Illust
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);
- MainThread.BeginInvokeOnMainThread(() =>
- {
- var count = illustItem.PageCount;
- pageCount = count;
- Title = illustItem.Title;
- IsAnimateSliderVisible = illustItem.IsAnimeVisible;
- if (count > 1)
- {
- IsPageVisible = true;
- ProgressVisible = true;
- PagePositionText = $"1/{count}";
- }
- });
- if (preload.user.TryGetValue(illust.userId, out var user))
- {
- illustItem.ProfileUrl = user.image;
- }
- }
+ DoForcePreload(false);
}
}
@@ -434,13 +414,7 @@ namespace Pixiview.Illust
private void DoLoadImage(int index, bool force = false)
{
var items = Illusts;
- if (index == 0 && force)
- {
- // error, refresh all
- Task.Run(() => DoLoadImages(true));
- return;
- }
- if (index < 0 || index >= items.Length)
+ if (index < 0 || (!force && index >= items.Length))
{
App.DebugPrint($"invalid index: {index}");
return;
@@ -525,12 +499,13 @@ namespace Pixiview.Illust
}
}
- private void Favorite_Clicked(object sender, EventArgs e)
+ private async void Favorite_Clicked(object sender, EventArgs e)
{
var favorites = Stores.Favorites;
var illust = IllustItem;
var index = favorites.FindIndex(i => i.Id == illust.Id);
- if (index < 0)
+ bool add = index < 0;
+ if (add)
{
illust.IsFavorite = true;
illust.FavoriteDateUtc = DateTime.UtcNow;
@@ -543,6 +518,40 @@ namespace Pixiview.Illust
favorites.RemoveAt(index);
FavoriteIcon = fontIconNotLove;
}
+
+ if (Configs.SyncFavType == SyncType.None)
+ {
+ return;
+ }
+ if (Configs.SyncFavType == SyncType.Prompt)
+ {
+ var ok = await DisplayAlert(
+ ResourceHelper.Title,
+ ResourceHelper.ConfirmSyncFavorite,
+ ResourceHelper.Yes,
+ ResourceHelper.No);
+ if (!ok)
+ {
+ return;
+ }
+ }
+
+ if (add)
+ {
+ var id = await Task.Run(() => Stores.AddBookmark(illust.Id));
+ if (id != null)
+ {
+ illust.BookmarkId = id;
+ }
+ }
+ else
+ {
+ var bookmarkId = illust.BookmarkId;
+ if (!string.IsNullOrEmpty(bookmarkId))
+ {
+ _ = Task.Run(() => Stores.DeleteBookmark(bookmarkId));
+ }
+ }
}
private void Image_Tapped(object sender, EventArgs e)
@@ -582,9 +591,47 @@ namespace Pixiview.Illust
CurrentAnimeFrame = e.FrameIndex;
}
+ private void DoForcePreload(bool force)
+ {
+ isPreloading = true;
+ var illustItem = IllustItem;
+ // force to reload
+ var preload = Stores.LoadIllustPreloadData(illustItem.Id, force);
+ if (preload != null && preload.illust.TryGetValue(illustItem.Id, out var illust))
+ {
+ illust.CopyToItem(illustItem);
+ MainThread.BeginInvokeOnMainThread(() =>
+ {
+ var count = illustItem.PageCount;
+ pageCount = count;
+ Title = illustItem.Title;
+ IsAnimateSliderVisible = illustItem.IsAnimeVisible;
+ if (count > 1)
+ {
+ IsPageVisible = true;
+ ProgressVisible = true;
+ PagePositionText = $"1/{count}";
+ }
+ });
+ if (preload.user.TryGetValue(illust.userId, out var user))
+ {
+ illustItem.ProfileUrl = user.image;
+ }
+ }
+ isPreloading = false;
+ }
+
private void Refresh_Clicked(object sender, EventArgs e)
{
- Task.Run(() => DoLoadImage(CurrentPage, true));
+ if (isPreloading)
+ {
+ return;
+ }
+ Task.Run(() =>
+ {
+ DoForcePreload(true);
+ DoLoadImage(CurrentPage, true);
+ });
}
private async void More_Clicked(object sender, EventArgs e)
diff --git a/Pixiview/OptionPage.xaml b/Pixiview/OptionPage.xaml
index 9d86cc4..26ddf88 100644
--- a/Pixiview/OptionPage.xaml
+++ b/Pixiview/OptionPage.xaml
@@ -15,6 +15,8 @@
+
(bool)GetValue(IsOnR18Property);
set => SetValue(IsOnR18Property, value);
}
+ public int SyncFavType
+ {
+ get => (int)GetValue(SyncFavTypeProperty);
+ set => SetValue(SyncFavTypeProperty, value);
+ }
public bool IsProxied
{
get => (bool)GetValue(IsProxiedProperty);
@@ -49,6 +57,14 @@ namespace Pixiview
{
BindingContext = this;
InitializeComponent();
+
+ optionFavSync.Items = new[]
+ {
+ ResourceHelper.SyncNo,
+ ResourceHelper.SyncPrompt,
+ ResourceHelper.SyncAuto,
+ };
+ SyncFavType = 0;
}
protected override void OnAppearing()
@@ -56,6 +72,7 @@ namespace Pixiview
base.OnAppearing();
IsOnR18 = Configs.IsOnR18;
+ SyncFavType = (int)Configs.SyncFavType;
var proxy = Configs.Proxy;
if (proxy != null)
{
@@ -78,6 +95,7 @@ namespace Pixiview
base.OnDisappearing();
var r18 = IsOnR18;
+ var syncType = SyncFavType;
var proxied = IsProxied;
if (Configs.IsOnR18 != r18)
@@ -87,6 +105,13 @@ namespace Pixiview
App.DebugPrint($"r-18 filter: {r18}");
}
+ if ((int)Configs.SyncFavType != syncType)
+ {
+ Preferences.Set(Configs.SyncFavTypeKey, syncType);
+ Configs.SyncFavType = (SyncType)syncType;
+ App.DebugPrint($"favorite sync type changed to {Configs.SyncFavType}");
+ }
+
var proxy = Configs.Proxy;
var h = Host?.Trim();
_ = int.TryParse(Port, out int pt);
diff --git a/Pixiview/Resources/Languages/zh-CN.xml b/Pixiview/Resources/Languages/zh-CN.xml
index 11b8187..6241aba 100644
--- a/Pixiview/Resources/Languages/zh-CN.xml
+++ b/Pixiview/Resources/Languages/zh-CN.xml
@@ -29,6 +29,10 @@
{0} 最受欢迎
一般
R-18
+ 收藏同步类型
+ 不同步
+ 提示同步
+ 自动同步
已关注
推荐
按用户
@@ -53,4 +57,5 @@
视频已保存,是否继续?
视频已导出到照片库。
无法获取返回结果。
+ 要同步收藏吗?
\ No newline at end of file
diff --git a/Pixiview/Resources/ResourceHelper.cs b/Pixiview/Resources/ResourceHelper.cs
index a6fff42..cb26e8e 100644
--- a/Pixiview/Resources/ResourceHelper.cs
+++ b/Pixiview/Resources/ResourceHelper.cs
@@ -17,6 +17,9 @@ namespace Pixiview.Resources
public static string Yes => GetResource(nameof(Yes));
public static string No => GetResource(nameof(No));
public static string R18 => GetResource(nameof(R18));
+ public static string SyncNo => GetResource(nameof(SyncNo));
+ public static string SyncPrompt => GetResource(nameof(SyncPrompt));
+ public static string SyncAuto => GetResource(nameof(SyncAuto));
public static string Operation => GetResource(nameof(Operation));
public static string SaveOriginal => GetResource(nameof(SaveOriginal));
public static string Share => GetResource(nameof(Share));
@@ -34,6 +37,7 @@ namespace Pixiview.Resources
public static string AlreadySavedVideo => GetResource(nameof(AlreadySavedVideo));
public static string ExportSuccess => GetResource(nameof(ExportSuccess));
public static string FailedResponse => GetResource(nameof(FailedResponse));
+ public static string ConfirmSyncFavorite => GetResource(nameof(ConfirmSyncFavorite));
static readonly Dictionary dict = new Dictionary();
diff --git a/Pixiview/UI/OptionCell.cs b/Pixiview/UI/OptionCell.cs
index d408333..6691d54 100644
--- a/Pixiview/UI/OptionCell.cs
+++ b/Pixiview/UI/OptionCell.cs
@@ -1,10 +1,12 @@
-using Pixiview.UI.Theme;
+using System.Collections;
+using Pixiview.UI.Theme;
using Pixiview.Utils;
using Xamarin.Forms;
namespace Pixiview.UI
{
public class OptionEntry : Entry { }
+ public class OptionPicker : Picker { }
public abstract class OptionCell : ViewCell
{
@@ -27,8 +29,8 @@ namespace Pixiview.UI
Padding = new Thickness(20, 0),
ColumnDefinitions =
{
- new ColumnDefinition { Width = new GridLength(.2, GridUnitType.Star) },
- new ColumnDefinition { Width = new GridLength(.8, GridUnitType.Star) }
+ new ColumnDefinition { Width = new GridLength(.3, GridUnitType.Star) },
+ new ColumnDefinition { Width = new GridLength(.7, GridUnitType.Star) }
},
Children =
{
@@ -65,6 +67,35 @@ namespace Pixiview.UI
}.Binding(Switch.IsToggledProperty, nameof(IsToggled), BindingMode.TwoWay);
}
+ public class OptionDropCell : OptionCell
+ {
+ public static readonly BindableProperty ItemsProperty = BindableProperty.Create(
+ nameof(Items), typeof(IList), typeof(OptionDropCell));
+ public static readonly BindableProperty SelectedIndexProperty = BindableProperty.Create(
+ nameof(SelectedIndex), typeof(int), typeof(OptionDropCell));
+
+ public IList Items
+ {
+ get => (IList)GetValue(ItemsProperty);
+ set => SetValue(ItemsProperty, value);
+ }
+ public int SelectedIndex
+ {
+ get => (int)GetValue(SelectedIndexProperty);
+ set => SetValue(SelectedIndexProperty, value);
+ }
+
+ protected override View Content => new OptionPicker
+ {
+ HorizontalOptions = LayoutOptions.Fill,
+ VerticalOptions = LayoutOptions.Center
+ }
+ .Binding(Picker.ItemsSourceProperty, nameof(Items))
+ .Binding(Picker.SelectedIndexProperty, nameof(SelectedIndex), BindingMode.TwoWay)
+ .DynamicResource(Picker.TextColorProperty, ThemeBase.TextColor)
+ .DynamicResource(VisualElement.BackgroundColorProperty, ThemeBase.OptionTintColor);
+ }
+
public class OptionEntryCell : OptionCell
{
public static readonly BindableProperty TextProperty = BindableProperty.Create(
diff --git a/Pixiview/Utils/HttpUtility.cs b/Pixiview/Utils/HttpUtility.cs
index a9fd6a3..7a181cb 100644
--- a/Pixiview/Utils/HttpUtility.cs
+++ b/Pixiview/Utils/HttpUtility.cs
@@ -13,12 +13,14 @@ namespace Pixiview.Utils
{
public static T LoadObject(string file, string url, string referer, out string error,
bool force = false,
+ bool nojson = false,
+ HttpContent post = null,
Action header = null,
Func namehandler = null,
Func action = null)
{
string content = null;
- if (!force && file != null && File.Exists(file))
+ if (post == null && !force && file != null && File.Exists(file))
{
try
{
@@ -31,6 +33,11 @@ namespace Pixiview.Utils
}
if (content == null)
{
+ bool noToken = string.IsNullOrEmpty(Configs.CsrfToken);
+ if (noToken)
+ {
+ post = null;
+ }
var response = Download(url, headers =>
{
if (referer != null)
@@ -44,6 +51,11 @@ namespace Pixiview.Utils
{
headers.Add("Cookie", cookie);
}
+ if (post != null && !noToken)
+ {
+ headers.Add("Origin", Configs.Referer);
+ headers.Add("X-Csrf-Token", Configs.CsrfToken);
+ }
if (header == null)
{
var userId = Configs.UserId;
@@ -56,12 +68,18 @@ namespace Pixiview.Utils
{
header(headers);
}
- });
+ }, post);
if (response == null)
{
error = "response is null";
return default;
}
+ if (!response.IsSuccessStatusCode)
+ {
+ App.DebugPrint($"http failed with code: {response.StatusCode}");
+ error = response.StatusCode.ToString();
+ return default;
+ }
using (response)
{
try
@@ -124,7 +142,14 @@ namespace Pixiview.Utils
try
{
error = null;
- return JsonConvert.DeserializeObject(content);
+ if (nojson)
+ {
+ return JsonConvert.DeserializeObject("{}");
+ }
+ else
+ {
+ return JsonConvert.DeserializeObject(content);
+ }
}
catch (Exception ex)
{
@@ -172,7 +197,7 @@ namespace Pixiview.Utils
}
}
- private static HttpResponseMessage Download(string url, Action headerAction)
+ private static HttpResponseMessage Download(string url, Action headerAction, HttpContent post = null)
{
App.DebugPrint($"GET: {url}");
var uri = new Uri(url);
@@ -194,7 +219,7 @@ namespace Pixiview.Utils
};
return TryCount(() =>
{
- using (var request = new HttpRequestMessage(HttpMethod.Get, uri.PathAndQuery)
+ using (var request = new HttpRequestMessage(post == null ? HttpMethod.Get : HttpMethod.Post, uri.PathAndQuery)
{
Version = new Version(2, 0)
})
@@ -207,6 +232,10 @@ namespace Pixiview.Utils
}
headers.Add("Accept-Language", Configs.AcceptLanguage);
//headers.Add("Accept-Encoding", Configs.AcceptEncoding);
+ if (post != null)
+ {
+ request.Content = post;
+ }
return client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result;
}
});
diff --git a/Pixiview/Utils/IllustData.cs b/Pixiview/Utils/IllustData.cs
index 500a8f0..6334658 100644
--- a/Pixiview/Utils/IllustData.cs
+++ b/Pixiview/Utils/IllustData.cs
@@ -14,6 +14,12 @@ namespace Pixiview.Utils
public T body;
}
+ public class BookmarkResultData
+ {
+ public string last_bookmark_id;
+ public string stacc_status_id;
+ }
+
public class Illust
{
public string illustId;
@@ -30,6 +36,7 @@ namespace Pixiview.Utils
public int width;
public int height;
public int pageCount;
+ public IllustBookmark bookmarkData;
public string alt;
public IllustUrls urls;
public string seriesId;
@@ -46,11 +53,19 @@ namespace Pixiview.Utils
public string x540;
}
+ public class IllustBookmark
+ {
+ public string id;
+ [JsonProperty("private")]
+ public bool isPrivate;
+ }
+
public IllustItem ConvertToItem(ImageSource image = null)
{
return new IllustItem
{
Id = illustId,
+ BookmarkId = bookmarkData?.id,
Title = illustTitle,
RankTitle = illustTitle,
IllustType = (IllustType)illustType,
@@ -167,9 +182,11 @@ namespace Pixiview.Utils
public int responseCount;
public int viewCount;
public bool isOriginal;
+ public IllustBookmark bookmarkData;
public IllustItem CopyToItem(IllustItem item)
{
+ item.BookmarkId = bookmarkData?.id;
item.Title = illustTitle;
item.RankTitle = illustTitle;
item.IllustType = (IllustType)illustType;
@@ -194,6 +211,13 @@ namespace Pixiview.Utils
[JsonIgnore]
public string Url => urls.regular;
+ public class IllustBookmark
+ {
+ public string id;
+ [JsonProperty("private")]
+ public bool isPrivate;
+ }
+
public class IllustUrls
{
public string mini;
diff --git a/Pixiview/Utils/IllustLegacy.cs b/Pixiview/Utils/IllustLegacy.cs
index 1d8033c..88f2ced 100644
--- a/Pixiview/Utils/IllustLegacy.cs
+++ b/Pixiview/Utils/IllustLegacy.cs
@@ -41,6 +41,8 @@ namespace Pixiview.Utils
public string attr;
public bool is_bookmarked;
public bool bookmarkable;
+ public string bookmark_id;
+ public string bookmark_illust_restrict;
public class ContentType
{
@@ -94,6 +96,7 @@ namespace Pixiview.Utils
return new IllustItem
{
Id = illust_id.ToString(),
+ BookmarkId = bookmark_id,
Title = title,
RankTitle = $"#{rank} {title}",
IllustType = (IllustType)type,
diff --git a/Pixiview/Utils/Stores.cs b/Pixiview/Utils/Stores.cs
index 6a0123d..3303879 100644
--- a/Pixiview/Utils/Stores.cs
+++ b/Pixiview/Utils/Stores.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
+using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using Pixiview.Illust;
@@ -310,9 +311,75 @@ namespace Pixiview.Utils
{
App.DebugPrint($"error when load global data, is null");
}
+ else
+ {
+ App.DebugPrint($"current csrf token: {result.token}");
+ Configs.CsrfToken = result.token;
+ }
return result;
}
+ public static string AddBookmark(string id)
+ {
+ if (string.IsNullOrEmpty(Configs.CsrfToken))
+ {
+ return null;
+ }
+ var content = new StringContent(
+ "{\"illust_id\":\"" + id + "\",\"restrict\":0,\"comment\":\"\",\"tags\":[]}",
+ Encoding.UTF8,
+ Configs.AcceptJson);
+ var result = HttpUtility.LoadObject>(
+ null,
+ Configs.BookmarkAdd,
+ Configs.Referer,
+ out string error,
+ force: true,
+ post: content);
+ if (error != null)
+ {
+ App.DebugPrint($"failed to add bookmark, error: {error}");
+ }
+ else if (result == null || result.error)
+ {
+ App.DebugPrint($"failed to add bookmark, message: {result.message}");
+ }
+ App.DebugPrint($"successs, bookmark id: {result.body.last_bookmark_id}, status: {result.body.stacc_status_id}");
+ return result.body.last_bookmark_id;
+ }
+
+ public static bool DeleteBookmark(string id)
+ {
+ if (string.IsNullOrEmpty(Configs.CsrfToken))
+ {
+ return false;
+ }
+ var content = new StringContent(
+ "mode=delete_illust_bookmark&bookmark_id=" + id,
+ Encoding.UTF8,
+ Configs.AcceptUrlEncoded);
+ var result = HttpUtility.LoadObject