gelbooru source

This commit is contained in:
2021-08-10 21:46:38 +08:00
parent 8f8cfaca54
commit 24f39a2e27
8 changed files with 104 additions and 30 deletions

View File

@ -15,6 +15,7 @@ namespace Gallery
public static AppTheme CurrentTheme { get; private set; } public static AppTheme CurrentTheme { get; private set; }
public static PlatformCulture CurrentCulture { get; private set; } public static PlatformCulture CurrentCulture { get; private set; }
public static Dictionary<string, System.DateTime> RefreshTimes { get; } = new();
public static List<IGallerySource> GallerySources { get; } = new() public static List<IGallerySource> GallerySources { get; } = new()
{ {
new Yandere.GallerySource(), // https://yande.re new Yandere.GallerySource(), // https://yande.re

View File

@ -12,12 +12,7 @@ namespace Gallery.Resources.UI
{ {
public abstract class GalleryCollectionPage : GalleryScrollableCollectionPage<GalleryItem[]> public abstract class GalleryCollectionPage : GalleryScrollableCollectionPage<GalleryItem[]>
{ {
protected readonly IGallerySource source; public GalleryCollectionPage(IGallerySource source) : base(source) { }
public GalleryCollectionPage(IGallerySource source)
{
this.source = source;
}
} }
public interface IGalleryCollectionPage public interface IGalleryCollectionPage
@ -59,15 +54,46 @@ namespace Gallery.Resources.UI
set => SetValue(IsBottomLoadingProperty, value); set => SetValue(IsBottomLoadingProperty, value);
} }
public IGallerySource Source { get; }
public GalleryCollection GalleryCollection { get; set; } public GalleryCollection GalleryCollection { get; set; }
public DateTime LastUpdated
{
get
{
if (App.RefreshTimes.TryGetValue(Source.Route, out var time))
{
#if DEBUG
Log.Print($"get last updated time for: {Source.Route}, {time}");
#endif
return time;
}
#if DEBUG
Log.Print($"cannot get last updated time for: {Source.Route}");
#endif
return default;
}
set
{
#if DEBUG
Log.Print($"set last updated time for: {Source.Route} to {value}");
#endif
App.RefreshTimes[Source.Route] = value;
}
}
protected virtual ActivityIndicator LoadingIndicator => null; protected virtual ActivityIndicator LoadingIndicator => null;
protected virtual double IndicatorMarginTop => 16; protected virtual double IndicatorMarginTop => 16;
protected bool Expired => lastUpdated == default || (DateTime.Now - lastUpdated).TotalMinutes > EXPIRED_MINUTES; protected bool Expired
{
get
{
var lastUpdated = LastUpdated;
return lastUpdated == default || (DateTime.Now - lastUpdated).TotalMinutes > EXPIRED_MINUTES;
}
}
protected readonly Command<GalleryItem> commandGalleryItemTapped; protected readonly Command<GalleryItem> commandGalleryItemTapped;
protected DateTime lastUpdated;
protected double topOffset; protected double topOffset;
protected string lastError; protected string lastError;
@ -75,8 +101,9 @@ namespace Gallery.Resources.UI
private readonly Stack<ParallelTask> tasks = new(); private readonly Stack<ParallelTask> tasks = new();
private T galleryData; private T galleryData;
public GalleryCollectionPage() public GalleryCollectionPage(IGallerySource source)
{ {
Source = source;
commandGalleryItemTapped = new Command<GalleryItem>(OnGalleryItemTapped); commandGalleryItemTapped = new Command<GalleryItem>(OnGalleryItemTapped);
} }
@ -107,14 +134,14 @@ namespace Gallery.Resources.UI
} }
InvalidateCollection(); InvalidateCollection();
Gallery = null; Gallery = null;
lastUpdated = default; LastUpdated = default;
} }
protected override void OnAppearing() protected override void OnAppearing()
{ {
base.OnAppearing(); base.OnAppearing();
if (lastUpdated == default) if (Expired)
{ {
StartLoading(); StartLoading();
} }
@ -391,9 +418,9 @@ namespace Gallery.Resources.UI
Log.Error("gallery.load", "failed to load gallery data."); Log.Error("gallery.load", "failed to load gallery data.");
return; return;
} }
if (force) if (force || Expired)
{ {
lastUpdated = DateTime.Now; LastUpdated = DateTime.Now;
} }
var data = DoGetGalleryList(galleryData, out int tag).Where(i => i != null); var data = DoGetGalleryList(galleryData, out int tag).Where(i => i != null);
@ -469,6 +496,8 @@ namespace Gallery.Resources.UI
private double lastRefreshY = double.MinValue; private double lastRefreshY = double.MinValue;
private double offset; private double offset;
public GalleryScrollableCollectionPage(IGallerySource source) : base(source) { }
protected bool IsScrollingDown(double y) protected bool IsScrollingDown(double y)
{ {
if (y > lastScrollY) if (y > lastScrollY)

View File

@ -33,7 +33,7 @@ namespace Gallery.Views
protected override async Task<GalleryItem[]> DoloadGalleryData(bool force) protected override async Task<GalleryItem[]> DoloadGalleryData(bool force)
{ {
var result = await source.GetRecentItemsAsync(currentPage); var result = await Source.GetRecentItemsAsync(currentPage);
return result; return result;
} }

View File

@ -55,6 +55,8 @@ namespace Gallery.Util
case nameof(GalleryItem.RawUrl): item.RawUrl = reader.GetString(); break; case nameof(GalleryItem.RawUrl): item.RawUrl = reader.GetString(); break;
case nameof(GalleryItem.Width): item.Width = reader.GetInt32(); break; case nameof(GalleryItem.Width): item.Width = reader.GetInt32(); break;
case nameof(GalleryItem.Height): item.Height = reader.GetInt32(); break; case nameof(GalleryItem.Height): item.Height = reader.GetInt32(); break;
case nameof(GalleryItem.BookmarkId): item.BookmarkId = reader.GetString(); break;
case nameof(GalleryItem.IsRawPage): item.IsRawPage = reader.GetBoolean(); break;
} }
} }
} }
@ -91,6 +93,8 @@ namespace Gallery.Util
writer.WriteString(nameof(GalleryItem.RawUrl), value.RawUrl); writer.WriteString(nameof(GalleryItem.RawUrl), value.RawUrl);
writer.WriteNumber(nameof(GalleryItem.Width), value.Width); writer.WriteNumber(nameof(GalleryItem.Width), value.Width);
writer.WriteNumber(nameof(GalleryItem.Height), value.Height); writer.WriteNumber(nameof(GalleryItem.Height), value.Height);
writer.WriteString(nameof(GalleryItem.BookmarkId), value.BookmarkId);
writer.WriteBoolean(nameof(GalleryItem.IsRawPage), value.IsRawPage);
writer.WriteEndObject(); writer.WriteEndObject();
} }

View File

@ -2,7 +2,6 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\Ref\Tsanie.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\Ref\Tsanie.snk</AssemblyOriginatorKeyFile>
</PropertyGroup> </PropertyGroup>

View File

@ -19,31 +19,26 @@ namespace Gallery.Util.Model
public static readonly BindableProperty IsFavoriteProperty = BindableProperty.Create(nameof(IsFavorite), typeof(bool), typeof(GalleryItem)); public static readonly BindableProperty IsFavoriteProperty = BindableProperty.Create(nameof(IsFavorite), typeof(bool), typeof(GalleryItem));
public static readonly BindableProperty BookmarkIdProperty = BindableProperty.Create(nameof(BookmarkId), typeof(string), typeof(GalleryItem)); public static readonly BindableProperty BookmarkIdProperty = BindableProperty.Create(nameof(BookmarkId), typeof(string), typeof(GalleryItem));
[JsonIgnore]
public string TagDescription public string TagDescription
{ {
get => (string)GetValue(TagDescriptionProperty); get => (string)GetValue(TagDescriptionProperty);
set => SetValue(TagDescriptionProperty, value); set => SetValue(TagDescriptionProperty, value);
} }
[JsonIgnore]
public ImageSource PreviewImage public ImageSource PreviewImage
{ {
get => (ImageSource)GetValue(PreviewImageProperty); get => (ImageSource)GetValue(PreviewImageProperty);
set => SetValue(PreviewImageProperty, value); set => SetValue(PreviewImageProperty, value);
} }
[JsonIgnore]
public GridLength ImageHeight public GridLength ImageHeight
{ {
get => (GridLength)GetValue(ImageHeightProperty); get => (GridLength)GetValue(ImageHeightProperty);
set => SetValue(ImageHeightProperty, value); set => SetValue(ImageHeightProperty, value);
} }
[JsonIgnore]
public bool IsFavorite public bool IsFavorite
{ {
get => (bool)GetValue(IsFavoriteProperty); get => (bool)GetValue(IsFavoriteProperty);
set => SetValue(IsFavoriteProperty, value); set => SetValue(IsFavoriteProperty, value);
} }
[JsonIgnore]
public string BookmarkId public string BookmarkId
{ {
get => (string)GetValue(BookmarkIdProperty); get => (string)GetValue(BookmarkIdProperty);
@ -75,6 +70,7 @@ namespace Gallery.Util.Model
public string Source { get; set; } public string Source { get; set; }
public string PreviewUrl { get; set; } public string PreviewUrl { get; set; }
public string RawUrl { get; set; } public string RawUrl { get; set; }
public bool IsRawPage { get; set; }
private int width; private int width;
private int height; private int height;

View File

@ -18,7 +18,7 @@ namespace Gallery.Danbooru
public async Task<GalleryItem[]> GetRecentItemsAsync(int page) public async Task<GalleryItem[]> GetRecentItemsAsync(int page)
{ {
var url = $"https://danbooru.donmai.us/posts?page={page}"; var url = $"https://danbooru.donmai.us/posts?page={page}";
var (result, error) = await NetHelper.RequestObject<GalleryItem[]>(url, contentHandler: ContentHandler); var (result, error) = await NetHelper.RequestObject(url, @return: content => ResolveGalleryItems(content));
if (result == null || !string.IsNullOrEmpty(error)) if (result == null || !string.IsNullOrEmpty(error))
{ {
@ -29,18 +29,30 @@ namespace Gallery.Danbooru
return result; return result;
} }
private string ContentHandler(string content) private GalleryItem[] ResolveGalleryItems(string content)
{ {
var regex = new Regex(@"<article id=""post_\d+"".+?data-id=""(\d+)"".+?data-tags=""([^""]+?)"".+?data-width=""(\d+?)"" data-height=""(\d+?)"".+?data-source=""([^""]+?)"" data-uploader-id=""(\d+?)"" data-normalized-source=""([^""]+?)"".+?data-file-url=""([^""]+?)"".+?data-preview-file-url=""([^""]+?)""", RegexOptions.Multiline); var regex = new Regex(
@"<article id=""post_\d+"".+?data-id=""(\d+)"".+?data-tags=""([^""]+?)"".+?" +
@"data-width=""(\d+?)"" data-height=""(\d+?)"".+?data-source=""([^""]+?)"".+?" +
@"data-uploader-id=""(\d+?)"".+?data-normalized-source=""([^""]+?)"".+?" +
@"data-file-url=""([^""]+?)"".+?data-large-file-url=""([^""]+?)""", RegexOptions.Multiline);
var matches = regex.Matches(content); var matches = regex.Matches(content);
var array = new string[matches.Count]; var items = new GalleryItem[matches.Count];
for (var i = 0; i < array.Length; i++) for (var i = 0; i < items.Length; i++)
{ {
var g = matches[i].Groups; var g = matches[i].Groups;
var tags = g[2].Value.Replace(" ", "\",\""); items[i] = new GalleryItem(int.Parse(g[1].Value))
array[i] = $"{{\"Id\":{g[1].Value},\"Tags\":[\"{tags}\"],\"Width\":{g[3].Value},\"Height\":{g[4].Value},\"Source\":\"{g[7].Value}\",\"UserId\":\"{g[6].Value}\",\"RawUrl\":\"{g[8].Value}\",\"PreviewUrl\":\"{g[9].Value}\"}}"; {
Tags = g[2].Value.Split(' '),
Width = int.Parse(g[3].Value),
Height = int.Parse(g[4].Value),
UserId = g[6].Value,
Source = g[7].Value,
RawUrl = g[8].Value,
PreviewUrl = g[9].Value
};
} }
return $"[{string.Join(',', array)}]"; return items;
} }
public void SetCookie() public void SetCookie()

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Gallery.Util;
using Gallery.Util.Interface; using Gallery.Util.Interface;
using Gallery.Util.Model; using Gallery.Util.Model;
using Xamarin.Forms; using Xamarin.Forms;
@ -13,9 +15,40 @@ namespace Gallery.Gelbooru
public string FlyoutIconKey => "Gelbooru"; public string FlyoutIconKey => "Gelbooru";
public string HomePage => "https://gelbooru.com"; public string HomePage => "https://gelbooru.com";
public Task<GalleryItem[]> GetRecentItemsAsync(int page) public async Task<GalleryItem[]> GetRecentItemsAsync(int page)
{ {
throw new NotImplementedException(); var offset = (page - 1) * 42;
var url = $"https://gelbooru.com/index.php?page=post&s=list&tags=all&pid={offset}";
var (result, error) = await NetHelper.RequestObject(url, @return: content => ResolveGalleryItems(content));
if (result == null || !string.IsNullOrEmpty(error))
{
Log.Error("gelbooru.content.load", $"failed to load content array, error: {error}");
return null;
}
return result;
}
private GalleryItem[] ResolveGalleryItems(string content)
{
var regex = new Regex(
@"<article(.|\n)+?<a id=""p(\d+?)"" href=""([^""]+?)"">(.|\n)+?<img src=""([^""]+?)"" title=""([^""]+?)""",
RegexOptions.Multiline);
var matches = regex.Matches(content);
var items = new GalleryItem[matches.Count];
for (var i = 0; i < items.Length; i++)
{
var g = matches[i].Groups;
items[i] = new GalleryItem(int.Parse(g[2].Value))
{
RawUrl = g[3].Value,
PreviewUrl = g[5].Value,
Tags = g[6].Value.Split(' '),
IsRawPage = true
};
}
return items;
} }
public void SetCookie() public void SetCookie()