using System.Text.Json.Nodes; using System.Web; using FreeSql.DataAnnotations; using MegghysAPI.Attributes; using static MegghysAPI.Modules.PixivFavoriteDownloader.Pixiv; namespace MegghysAPI.Modules { public static class PixivFavoriteDownloader { [AutoInit(Async = true)] public static void Init() { Favorites = DB.SQL.Select().ToList(); Favorites.ForEach(f => { f.S3URL = f.URL.Select(u => new PixivURLInfo() { Origin = $"http://eternalland.top:9000/{Config.Instance.MinIOBucket}{FileManager.FavoritePath}{f.Id}_{f.URL.IndexOf(u)}.{u.Extension}", Large = $"http://194.104.147.128:880/{u.Large?.Replace("i.pixiv.re", "i.pximg.net")}?referer=https://www.pixiv.net/", Medium = $"http://194.104.147.128:880/{u.Medium?.Replace("i.pixiv.re", "i.pximg.net")}?referer=https://www.pixiv.net/", Small = $"http://194.104.147.128:880/{u.Small?.Replace("i.pixiv.re", "i.pximg.net")}?referer=https://www.pixiv.net/", }).ToList(); }); Logs.Success($"Pixiv 收藏图片总数: {Favorites.Count}"); } public static readonly string PIXIV_FAVORITE_URL = Datas.HIBI_URL + "api/pixiv/favorite?id=19045447"; public const string PixivFavoritePath = "/files/favorite/"; public static List Favorites = []; [AutoTimer(Time = 5 * 60, CallOnRegister = true)] public static void UpdateMyFavorite() { Logs.Info("正在更新收藏图片"); var url = PIXIV_FAVORITE_URL; var num = 0; while (num < 5) { try { var result = Utils.RequestString(url); var json = JsonNode.Parse(result); if (json is null) return; json["illusts"]?.AsArray().ForEach(i => { if (!Favorites.Any(f => f.Id == (long)i["id"])) { var img = new PixivImgInfo(i, PixivImgType.Favorite); Favorites.Add(img); DB.SQL.InsertOrUpdate() .SetSource(img) .ExecuteAffrows(); Logs.Success($"[{Favorites.Count}] 发现新增收藏: {Favorites.Last().Title}, 类型: {Favorites.Last().Restrict}"); } }); var next = (string)json["next_url"]; if (next is null) break; var list = next.Split("max_bookmark_id=", StringSplitOptions.RemoveEmptyEntries); if (list.Length != 0) url = PIXIV_FAVORITE_URL + $"&max_bookmark_id={list[1]}"; else break; } catch (Exception ex) { Logs.Error(ex); num++; } } Logs.Success($"收藏图片更新完成. 当前共 {Favorites.Count} 个"); } static bool uploading = false; [AutoTimer(Time = 60 * 5, CallOnRegister = true)] public static async Task DownloadFavoriteToBucket() { if (uploading) { Logs.Info($"正在下载收藏, 忽略"); return; } uploading = true; var files = await FileManager.ListFilesAsync(FileManager.FavoritePath, true); if (files is null) return; Logs.Info($"FTP 总收藏数: {files.Length}"); int num = 0; for (int i = 0; i < Favorites.Count; i++) { var s = Favorites[i]; try { num = 0; foreach (var u in s?.URL) { var url = u.Origin.Replace("i.pixiv.re", "i.pximg.net"); url = $"http://194.104.147.128:880/{url}?referer=https://www.pixiv.net/"; var fileName = $"{s.Id}_{num}.{u.Extension}"; if (!files.Any(f => f.Name == fileName)) { var data = await Utils.DownloadBytesAsync(url); if (data.code == System.Net.HttpStatusCode.OK) { using var stream = new MemoryStream(data.data); if (await FileManager.UploadStreamAsync(stream, FileManager.FavoritePath + fileName)) Logs.Success($"已上传收藏图片 {s.Title}({s.Id})[{num + 1}-{s.URL.Count}]:{Favorites.IndexOf(s)} 至储存空间 [{(double)data.data.Length / 1024 / 1024:0.00} Mb]."); else Logs.Warn($"{s.Title} 上传失败"); } num++; } } } catch (Exception ex) { Logs.Error(ex); } } uploading = false; } public enum PixivImgType { None, Setu, Favorite } public partial class Pixiv { public class PixivImgInfo { public PixivImgInfo() { Type = PixivImgType.None; } public PixivImgInfo(PixivImgType t) { Type = t; } public PixivImgInfo(JsonNode node, PixivImgType t) { Type = t; ArgumentNullException.ThrowIfNull(node); var tag = new List(); node["tags"].AsArray().ForEach(t => tag.Add(new((string)t["name"], (string)t["translated_name"]))); Id = (long)node["id"]; Author = new() { UID = ((long)node["user"]["id"]).ToString(), Name = (string)node["user"]["name"], Account = (string)node["user"]["account"], HeadURL = (string)node["user"]["profile_image_urls"]["medium"] }; Title = (string)node["title"]; Restrict = (PixivRestrictInfo)(int)node["x_restrict"]; Description = (string)node["caption"]; Tags = tag; var url = new List(); if ((int)node["page_count"] == 1) url.Add(new() { Origin = ((string)node["meta_single_page"]["original_image_url"]).Replace("i.pximg.net", "i.pixiv.cat") }); else node["meta_pages"].AsArray().ForEach(p => { var imgs = p["image_urls"]; url.Add(new() { Origin = ((string)imgs["original"] ?? "") .Replace("i.pximg.net", "i.pixiv.re"), Large = ((string)imgs["large"] ?? "") .Replace("i.pximg.net", "i.pixiv.re"), Medium = ((string)imgs["medium"] ?? "") .Replace("i.pximg.net", "i.pixiv.re"), Small = ((string)imgs["square_medium"] ?? "") .Replace("i.pximg.net", "i.pixiv.re") }); }); URL = url; Width = (int)node["width"]; Height = (int)node["height"]; UploadDate = DateTime.TryParse((string)node["create_date"], out var date) ? date.Ticks : 0; ViewCount = (long)node["total_view"]; FavoriteCount = (long)node["total_bookmarks"]; } public long Id { get; set; } public PixivImgType Type { get; set; } public string Title { get; set; } [JsonMap] public PixivRestrictInfo Restrict { get; set; } [Column(DbType = "text")] public string Description { get; set; } [JsonMap] public PixivAuthorInfo Author { get; set; } public bool R18 => Restrict != PixivRestrictInfo.Normal; [JsonMap] public List Tags { get; set; } = []; [JsonMap] public List URL { get; set; } = []; [JsonMap] public List S3URL { get; set; } = []; public int Width { get; set; } public int Height { get; set; } public long UploadDate { set; get; } public long ViewCount { get; set; } public long FavoriteCount { get; set; } } public enum PixivRestrictInfo { Normal, R18, R18G } public record PixivAuthorInfo { public string Name { get; set; } public string UID { get; set; } public string Account { get; set; } public string HeadURL { get; set; } } public record PixivURLInfo { public override string ToString() { return Origin; } public string Extension => Path.GetExtension(HttpUtility.UrlDecode(new Uri(Origin).Segments.Last()))?.Replace(".", ""); public string Name => HttpUtility.UrlDecode(new Uri(Origin).Segments.Last()) is { } url ? $"{url}" : ""; public string Origin { get; set; } public string Large { get; set; } public string Medium { get; set; } public string Small { get; set; } } public record PixivTagInfo { public override string ToString() => $"{Name} {(TranslateName is null ? "" : $"<{TranslateName}>")}"; public PixivTagInfo(string name, string translateName) { Name = name; TranslateName = translateName; } public bool Contains(string tag) { return Name.ToLower().Contains(tag.ToLower()) || (TranslateName != null && TranslateName.ToLower().Contains(tag.ToLower())); } public string Name { get; set; } public string TranslateName { get; set; } } } } }