XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFENewsApplication

【WinUI】新闻软件

公开
关注 0 Fork 0 Star 0
UTF-8
using HtmlAgilityPack;
using Microsoft.UI.Text;
using Microsoft.UI.Xaml.Documents;
using System.Net;
using System.Text.Json;
using XFEExtension.NetCore.StringExtension;
using XFENewsApplication.Models;

namespace XFENewsApplication.Utilities.Helper;

public static class ArticleDisplayHelper
{
    public static List<ArticlePart> ConvertCCTVToArticlePart(string newsDocument)
    {
        var htmlDocument = new HtmlDocument();
        htmlDocument.LoadHtml(newsDocument);
        var articleParts = new List<ArticlePart>
        {
            new TextArticlePart
            {
                FontSize = 40,
                FontWeight = FontWeights.Bold,
                Content = (htmlDocument.DocumentNode.SelectSingleNode("/html/body/div[@id = 'page_body']/div/div/div[@class = 'title_area']/h1") ?? htmlDocument.DocumentNode.SelectSingleNode("//div[@class = 'page_wrap']/div/div[@class = 'title_area']/h1")).InnerText.Replace("\t", string.Empty).Replace(" ", string.Empty)
            }
        };
        AnalysisMSNDocument(articleParts, articleParts[0].Content, [], (htmlDocument.DocumentNode.SelectSingleNode("/html/body/div[@id = 'page_body']/div/div/div[@class = 'content_area']") ?? htmlDocument.DocumentNode.SelectSingleNode("//div[@class = 'page_wrap']/div/div[@class = 'text_area']")).ChildNodes, htmlDocument.DocumentNode);
        return articleParts;
    }

    public static List<ArticlePart> ConvertMSNNewsToArticlePart(string newsDocument)
    {
        var articleParts = new List<ArticlePart>();
        var imageDictionary = new Dictionary<string, string>();
        var document = JsonDocument.Parse(newsDocument);
        var title = document.RootElement.GetProperty("title").ToString();
        articleParts.Add(new TextArticlePart
        {
            FontSize = 40,
            FontWeight = FontWeights.Bold,
            Content = title
        });
        if (document.RootElement.TryGetProperty("provider", out var provider))
        {
            var providerName = provider.GetProperty("name").ToString();
            articleParts.Add(new AuthorArticlePart
            {
                Content = provider.GetProperty("logo").GetProperty("url").ToString(),
                PublishDateTime = GetRelativeTimeDescription(document.RootElement.GetProperty("publishedDateTime").ToString()),
                ReadTime = document.RootElement.TryGetProperty("readTimeMin", out var readTime) && readTime.GetInt32() > 0 ? readTime.ToString() : string.Empty,
                ProviderName = providerName,
                AuthorName = document.RootElement.TryGetProperty("authors", out var authors) && authors.EnumerateArray().Any() ? string.Join(", ", authors.EnumerateArray().Select(x => x.GetProperty("name").ToString())) : providerName
            });
        }
        if (document.RootElement.TryGetProperty("slides", out var slides) && slides.EnumerateArray().Any())
        {
            var flipImages = new List<FlipImage>();
            foreach (var slide in slides.EnumerateArray())
            {
                var imageProperty = slide.GetProperty("image");
                flipImages.Add(new()
                {
                    ImageUrl = imageProperty.GetProperty("url").ToString(),
                    Description = imageProperty.TryGetProperty("caption", out var description) ? description.ToString() : string.Empty,
                    Attribution = imageProperty.TryGetProperty("attribution", out var attribution) ? attribution.ToString() : string.Empty,
                    Title = slide.TryGetProperty("title", out var titleProperty) ? titleProperty.ToString() : string.Empty
                });
            }
            articleParts.Add(new FlipImageArticlePart
            {
                Images = flipImages
            });
        }
        foreach (var imageNode in document.RootElement.GetProperty("imageResources").EnumerateArray())
            imageDictionary.Add(imageNode.GetProperty("cmsId").ToString(), imageNode.GetProperty("url").ToString());
        var htmlDocument = new HtmlDocument();
        htmlDocument.LoadHtml(document.RootElement.GetProperty("body").ToString());
        AnalysisMSNDocument(articleParts, title, imageDictionary, htmlDocument.DocumentNode.ChildNodes, htmlDocument.DocumentNode);
        return articleParts;
    }

    private static CustomTextArticlePart CheckLastArticlePart(List<ArticlePart> articleParts, HtmlNode parentNode, Inline inline)
    {
        if (articleParts.LastOrDefault() is not CustomTextArticlePart customTextArticlePart)
        {
            customTextArticlePart = new CustomTextArticlePart
            {
                Content = parentNode.GetHashCode().ToString()
            };
            articleParts.Add(customTextArticlePart);
        }
        if (customTextArticlePart.Content != parentNode.GetHashCode().ToString())
        {
            customTextArticlePart.Content = parentNode.GetHashCode().ToString();
            customTextArticlePart.CustomTextBlock.Inlines.Add(new LineBreak());
            customTextArticlePart.CustomTextBlock.Inlines.Add(new LineBreak());
        }
        customTextArticlePart.CustomTextBlock.Inlines.Add(inline);
        return customTextArticlePart;
    }

    private static void AnalysisMSNDocument(List<ArticlePart> articleParts, string title, Dictionary<string, string> imageDictionary, HtmlNodeCollection htmlNodes, HtmlNode parentNode)
    {
        foreach (var node in htmlNodes)
        {
            switch (node.Name)
            {
                case "img":
                    articleParts.Add(new ImageArticlePart
                    {
                        Content = imageDictionary.Count > 0 ? imageDictionary[node.GetAttributeValue("data-document-id", string.Empty).Replace("\"", string.Empty)] : $"https:{node.GetAttributeValue("src", string.Empty)}",
                        From = title
                    });
                    break;
                //case "video":
                //    articleParts.Add(new )
                case "#text":
                    switch (parentNode.Name)
                    {
                        case "p":
                            CheckLastArticlePart(articleParts, parentNode, new Run
                            {
                                Text = WebUtility.HtmlDecode(node.InnerText)
                            });
                            break;
                        case "span":
                            CheckLastArticlePart(articleParts, parentNode.ParentNode, new Run
                            {
                                Text = WebUtility.HtmlDecode(node.InnerText)
                            });
                            break;
                        case "strong":
                            var bold = new Bold();
                            bold.Inlines.Add(new Run
                            {
                                Text = WebUtility.HtmlDecode(node.InnerText)
                            });
                            CheckLastArticlePart(articleParts, parentNode.ParentNode, bold);
                            break;
                        case "b":
                            bold = new Bold();
                            bold.Inlines.Add(new Run
                            {
                                Text = WebUtility.HtmlDecode(node.InnerText)
                            });
                            CheckLastArticlePart(articleParts, parentNode.ParentNode, bold);
                            break;
                        case "em":
                            var italic = new Italic();
                            italic.Inlines.Add(new Run
                            {
                                Text = WebUtility.HtmlDecode(node.InnerText)
                            });
                            CheckLastArticlePart(articleParts, parentNode.ParentNode, italic);
                            break;
                        case "blockquote":
                            if (node.InnerText.IsNullOrWhiteSpace())
                                continue;
                            articleParts.Add(new QuoteArticlePart
                            {
                                Content = WebUtility.HtmlDecode(node.InnerText),
                                FontSize = 36,
                                FontWeight = FontWeights.SemiBold
                            });
                            break;
                        case "h1":
                            articleParts.Add(new TitleArticlePart
                            {
                                Content = WebUtility.HtmlDecode(node.InnerText),
                                FontSize = 68,
                                FontWeight = FontWeights.SemiBold
                            });
                            break;
                        case "h2":
                            articleParts.Add(new TitleArticlePart
                            {
                                Content = WebUtility.HtmlDecode(node.InnerText),
                                FontSize = 48,
                                FontWeight = FontWeights.SemiBold
                            });
                            break;
                        case "h3":
                            articleParts.Add(new TitleArticlePart
                            {
                                Content = WebUtility.HtmlDecode(node.InnerText),
                                FontSize = 36,
                                FontWeight = FontWeights.SemiBold
                            });
                            break;
                        case "h4":
                            articleParts.Add(new TitleArticlePart
                            {
                                Content = WebUtility.HtmlDecode(node.InnerText),
                                FontSize = 28,
                                FontWeight = FontWeights.SemiBold
                            });
                            break;
                        case "h5":
                            articleParts.Add(new TitleArticlePart
                            {
                                Content = WebUtility.HtmlDecode(node.InnerText),
                                FontSize = 20,
                                FontWeight = FontWeights.SemiBold
                            });
                            break;
                        case "h6":
                            articleParts.Add(new TitleArticlePart
                            {
                                Content = WebUtility.HtmlDecode(node.InnerText),
                                FontSize = 16,
                                FontWeight = FontWeights.SemiBold
                            });
                            break;
                        default:
                            break;
                    }
                    break;
                default:
                    if (node.HasChildNodes)
                        AnalysisMSNDocument(articleParts, title, imageDictionary, node.ChildNodes, node);
                    break;
            }
        }
    }

    public static string GetRelativeTimeDescription(DateTime time)
    {
        var now = DateTime.Now;
        var span = now - time;

        if (span.TotalSeconds < 60)
        {
            return "现在";
        }
        else if (span.TotalMinutes < 60)
        {
            int minutes = (int)span.TotalMinutes;
            return $"{minutes} 分钟前";
        }
        else if (span.TotalHours < 24)
        {
            int hours = (int)span.TotalHours;
            return $"{hours} 小时前";
        }
        else if (span.TotalDays < 7)
        {
            int days = (int)span.TotalDays;
            return $"{days} 天前";
        }
        else
        {
            return time.ToString("yyyy年MM月dd日 HH:mm");
        }
    }

    public static string GetRelativeTimeDescription(string time)
    {
        if (DateTime.TryParse(time, out var dateTime))
        {
            return GetRelativeTimeDescription(dateTime);
        }
        return "暂无时间";
    }
}