feature: parallels to download illusts
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0.524" package="org.tsanie.pixiview" android:versionCode="16">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0.525" package="org.tsanie.pixiview" android:versionCode="18">
|
||||||
<uses-sdk android:minSdkVersion="25" android:targetSdkVersion="28" />
|
<uses-sdk android:minSdkVersion="25" android:targetSdkVersion="28" />
|
||||||
<application android:label="Pixiview" android:icon="@mipmap/icon" android:roundIcon="@mipmap/icon_round"></application>
|
<application android:label="Pixiview" android:icon="@mipmap/icon" android:roundIcon="@mipmap/icon_round"></application>
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
@ -29,8 +29,8 @@
|
|||||||
<string>com.apple.share-services</string>
|
<string>com.apple.share-services</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0.524</string>
|
<string>1.0.525</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>16</string>
|
<string>18</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -79,9 +79,9 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0.524</string>
|
<string>1.0.525</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>16</string>
|
<string>18</string>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>China</string>
|
<string>China</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
@ -717,9 +717,12 @@ namespace Pixiview.Illust
|
|||||||
return true;
|
return true;
|
||||||
}, tagIndex: tag);
|
}, tagIndex: tag);
|
||||||
|
|
||||||
lock (sync)
|
if (task != null)
|
||||||
{
|
{
|
||||||
tasks.Enqueue(task);
|
lock (sync)
|
||||||
|
{
|
||||||
|
tasks.Enqueue(task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,7 +315,7 @@ namespace Pixiview.Illust
|
|||||||
if (illust.ImageUrl != null)
|
if (illust.ImageUrl != null)
|
||||||
{
|
{
|
||||||
var url = Configs.GetThumbnailUrl(illust.ImageUrl);
|
var url = Configs.GetThumbnailUrl(illust.ImageUrl);
|
||||||
var image = Stores.LoadPreviewImage(url, true, force: false);
|
var image = Stores.LoadPreviewImage(url, false);
|
||||||
if (image == null)
|
if (image == null)
|
||||||
{
|
{
|
||||||
image = Stores.LoadThumbnailImage(url, true);
|
image = Stores.LoadThumbnailImage(url, true);
|
||||||
|
@ -400,7 +400,7 @@ namespace Pixiview.Illust
|
|||||||
task.Dispose();
|
task.Dispose();
|
||||||
task = null;
|
task = null;
|
||||||
}
|
}
|
||||||
task = ParallelTask.Start("view.illusts", 0, items.Length, Configs.MaxPageThreads, i =>
|
task = ParallelTask.Start("view.illusts", 0, items.Length, 2, i =>
|
||||||
{
|
{
|
||||||
DoLoadImage(i);
|
DoLoadImage(i);
|
||||||
return true;
|
return true;
|
||||||
@ -439,7 +439,7 @@ namespace Pixiview.Illust
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
item.Loading = true;
|
item.Loading = true;
|
||||||
var image = Stores.LoadPreviewImage(item.PreviewUrl, true, force: force);
|
var image = Stores.LoadPreviewImage(item.PreviewUrl, true, IllustItem.Id, force: force);
|
||||||
if (image != null)
|
if (image != null)
|
||||||
{
|
{
|
||||||
item.Image = image;
|
item.Image = image;
|
||||||
|
@ -107,7 +107,8 @@ namespace Pixiview.Utils
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var task = new ParallelTask(tag, from, toExclusive, maxCount, action, tagIndex, complete);
|
var task = new ParallelTask(tag, from, toExclusive, maxCount, action, tagIndex, complete);
|
||||||
return task.Start();
|
task.Start();
|
||||||
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly object sync = new object();
|
private readonly object sync = new object();
|
||||||
@ -141,10 +142,9 @@ namespace Pixiview.Utils
|
|||||||
this.complete = complete;
|
this.complete = complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParallelTask Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
_ = ThreadPool.QueueUserWorkItem(DoStart);
|
_ = ThreadPool.QueueUserWorkItem(DoStart);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DoStart(object state)
|
private void DoStart(object state)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
@ -6,6 +7,7 @@ using System.Net.Http;
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Pixiview.Utils
|
namespace Pixiview.Utils
|
||||||
@ -204,6 +206,112 @@ namespace Pixiview.Utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Task<string> DownloadImageAsync(string url, string id, string working, string folder)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var directory = Path.Combine(working, folder);
|
||||||
|
if (!Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
var file = Path.Combine(directory, Path.GetFileName(url));
|
||||||
|
var proxy = Configs.Proxy;
|
||||||
|
var referer = new Uri(string.Format(Configs.UrlIllust, id));
|
||||||
|
var handler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
UseCookies = false
|
||||||
|
};
|
||||||
|
if (proxy != null)
|
||||||
|
{
|
||||||
|
handler.Proxy = proxy;
|
||||||
|
handler.UseProxy = true;
|
||||||
|
}
|
||||||
|
var client = new HttpClient(handler)
|
||||||
|
{
|
||||||
|
Timeout = TimeSpan.FromSeconds(30)
|
||||||
|
};
|
||||||
|
long size;
|
||||||
|
DateTimeOffset lastModified;
|
||||||
|
using (var request = new HttpRequestMessage(HttpMethod.Head, url))
|
||||||
|
{
|
||||||
|
var headers = request.Headers;
|
||||||
|
headers.Add("Accept", Configs.AcceptPureImage);
|
||||||
|
headers.Add("Accept-Language", Configs.AcceptLanguage);
|
||||||
|
headers.Referrer = referer;
|
||||||
|
headers.Add("User-Agent", Configs.UserAgent);
|
||||||
|
using (var response = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result)
|
||||||
|
{
|
||||||
|
size = response.Content.Headers.ContentLength.Value;
|
||||||
|
lastModified = response.Content.Headers.LastModified.Value;
|
||||||
|
#if DEBUG
|
||||||
|
App.DebugPrint($"content length: {size:n0} bytes, last modified: {lastModified}");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// segments
|
||||||
|
const int SIZE = 50000;
|
||||||
|
var list = new List<(long from, long to)>();
|
||||||
|
for (var i = 0L; i < size; i += SIZE)
|
||||||
|
{
|
||||||
|
long to;
|
||||||
|
if (i + SIZE >= size)
|
||||||
|
{
|
||||||
|
to = size - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
to = i + SIZE - 1;
|
||||||
|
}
|
||||||
|
list.Add((i, to));
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = new byte[size];
|
||||||
|
var task = new TaskCompletionSource<string>();
|
||||||
|
|
||||||
|
ParallelTask.Start($"download.async.{id}", 0, list.Count, 6, i =>
|
||||||
|
{
|
||||||
|
var (from, to) = list[i];
|
||||||
|
using (var request = new HttpRequestMessage(HttpMethod.Get, url))
|
||||||
|
{
|
||||||
|
var headers = request.Headers;
|
||||||
|
headers.Add("Accept", Configs.AcceptPureImage);
|
||||||
|
headers.Add("Accept-Language", Configs.AcceptLanguage);
|
||||||
|
headers.Add("Accept-Encoding", "identity");
|
||||||
|
headers.IfRange = new RangeConditionHeaderValue(lastModified);
|
||||||
|
headers.Range = new RangeHeaderValue(from, to);
|
||||||
|
headers.Referrer = referer;
|
||||||
|
headers.Add("User-Agent", Configs.UserAgent);
|
||||||
|
using (var response = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result)
|
||||||
|
using (var ms = new MemoryStream(data, (int)from, (int)(to - from + 1)))
|
||||||
|
{
|
||||||
|
response.Content.CopyToAsync(ms).Wait();
|
||||||
|
#if DEBUG
|
||||||
|
App.DebugPrint($"downloaded range: from ({from:n0}) to ({to:n0})");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
complete: () =>
|
||||||
|
{
|
||||||
|
using (var fs = File.OpenWrite(file))
|
||||||
|
{
|
||||||
|
fs.Write(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
task.SetResult(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
return task.Task;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
App.DebugError("image.download.async", ex.Message);
|
||||||
|
return Task.FromResult<string>(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static HttpResponseMessage Download(string url, Action<HttpRequestHeaders> headerAction, HttpContent post = null)
|
private static HttpResponseMessage Download(string url, Action<HttpRequestHeaders> headerAction, HttpContent post = null)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -6,6 +6,7 @@ using System.Net;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Pixiview.Illust;
|
using Pixiview.Illust;
|
||||||
using Xamarin.Essentials;
|
using Xamarin.Essentials;
|
||||||
@ -590,8 +591,12 @@ namespace Pixiview.Utils
|
|||||||
return LoadImage(url, PersonalFolder, imageFolder, true);
|
return LoadImage(url, PersonalFolder, imageFolder, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImageSource LoadPreviewImage(string url, bool downloading, bool force = false)
|
public static ImageSource LoadPreviewImage(string url, bool downloading, string id = null, bool force = false)
|
||||||
{
|
{
|
||||||
|
if (downloading)
|
||||||
|
{
|
||||||
|
return LoadImageAsync(url, id, PersonalFolder, previewFolder, force).Result;
|
||||||
|
}
|
||||||
return LoadImage(url, PersonalFolder, previewFolder, downloading, force);
|
return LoadImage(url, PersonalFolder, previewFolder, downloading, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -656,6 +661,37 @@ namespace Pixiview.Utils
|
|||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Task<ImageSource> LoadImageAsync(string url, string id, string working, string folder, bool force = false)
|
||||||
|
{
|
||||||
|
var file = Path.Combine(working, folder, Path.GetFileName(url));
|
||||||
|
ImageSource image;
|
||||||
|
if (!force && File.Exists(file))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
image = ImageSource.FromFile(file);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
App.DebugError("image.load", $"failed to load image from file: {file}, error: {ex.Message}");
|
||||||
|
image = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
image = null;
|
||||||
|
}
|
||||||
|
if (image == null)
|
||||||
|
{
|
||||||
|
file = HttpUtility.DownloadImageAsync(url, id, working, folder).Result;
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
image = ImageSource.FromFile(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Task.FromResult(image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class IllustFavorite
|
public class IllustFavorite
|
||||||
@ -772,9 +808,9 @@ namespace Pixiview.Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if __IOS__
|
#if __IOS__
|
||||||
public static System.Threading.Tasks.Task<bool> RequestCookieContainer(WebKit.WKHttpCookieStore cookieStore)
|
public static Task<bool> RequestCookieContainer(WebKit.WKHttpCookieStore cookieStore)
|
||||||
{
|
{
|
||||||
var task = new System.Threading.Tasks.TaskCompletionSource<bool>();
|
var task = new TaskCompletionSource<bool>();
|
||||||
cookieStore.GetAllCookies(cookies =>
|
cookieStore.GetAllCookies(cookies =>
|
||||||
{
|
{
|
||||||
var list = new List<string>();
|
var list = new List<string>();
|
||||||
@ -825,6 +861,7 @@ namespace Pixiview.Utils
|
|||||||
|
|
||||||
public const string UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36";
|
public const string UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36";
|
||||||
public const string AcceptImage = "image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5";
|
public const string AcceptImage = "image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5";
|
||||||
|
public const string AcceptPureImage = "image/*,*/*;q=0.8";
|
||||||
public const string AcceptJson = "application/json";
|
public const string AcceptJson = "application/json";
|
||||||
public const string AcceptUrlEncoded = "application/x-www-form-urlencoded";
|
public const string AcceptUrlEncoded = "application/x-www-form-urlencoded";
|
||||||
//public const string AcceptEncoding = "gzip, deflate";
|
//public const string AcceptEncoding = "gzip, deflate";
|
||||||
|
Reference in New Issue
Block a user