gelbooru source
This commit is contained in:
		| @@ -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 | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
| @@ -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; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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(); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -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> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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() | ||||||
|   | |||||||
| @@ -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() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user