/// <summary> /// Конструктор. /// </summary> /// <param name="parent">Родитель.</param> /// <param name="data">Данные.</param> public PostTags(IPostViewModel parent, PostTree data) { this.Parent = parent; var tagExt = data?.Extensions?.OfType<PostTreeTagsExtension>()?.FirstOrDefault(); if (tagExt?.Tags != null) { foreach (var t in tagExt.Tags) { Tags.Add(t); } HasTags = Tags.Count > 0; } }
/// <summary> /// Конструктор. /// </summary> /// <param name="parent">Родительская модель.</param> /// <param name="postData">Данные поста.</param> public PostMediaViewModel(IPostViewModel parent, PostTree postData) : base(parent) { var media = postData?.Media; if (media != null) { foreach (var model in media.Select(CreateModel).Where(model => model != null)) { Files.Add(model); } } PrimaryFile = Files.FirstOrDefault(); }
/// <summary> /// Конструктор. /// </summary> /// <param name="parent">Родительская модель.</param> /// <param name="post">Пост.</param> public PostTextViewModel(IPostViewModel parent, PostTree post) : base(parent) { this.UniqueId = Guid.NewGuid(); this.post = post; if (post?.Quotes != null) { var linkHash = ServiceLocator.Current.GetServiceOrThrow<ILinkHashService>(); var linkTransform = ServiceLocator.Current.GetServiceOrThrow<ILinkTransformService>(); var q = post.Quotes .Distinct(linkHash.GetComparer()) .OrderBy(a => a, linkTransform.GetLinkComparer()) .ToArray(); foreach (var a in q) { HasQuotes = true; Quotes.Add(new QuoteViewModel() { Parent = parent, Name = linkTransform.GetBackLinkDisplayString(a), Link = a }); } } }
/// <summary> /// Создать модель представления поста. /// </summary> /// <param name="post">Пост.</param> /// <returns>Модель представления поста.</returns> protected override IPostViewModel CreatePostViewModel(PostTree post) { // Для этого тип коллекции не поддерживается прямое обновление. throw new System.NotImplementedException(); }
/// <summary> /// Перевести в простой текст. /// </summary> /// <param name="tree">Дерево поста.</param> /// <returns>Текст.</returns> public static IList<string> ToPlainText(PostTree tree) { return tree.ToPlainText(); }
/// <summary> /// Разобрать HTML в посте. /// </summary> /// <param name="data">Данные.</param> /// <param name="link">Ссылка.</param> /// <param name="isPreview">Предварительный просмотр треда.</param> /// <returns>Результат разбора.</returns> private PostTree Parse(BoardPost2 data, ThreadLink link, bool isPreview) { var ipIdRegex = Services.GetServiceOrThrow<IRegexCacheService>().CreateRegex(IpIdRegexText); var ipIdRegex2 = Services.GetServiceOrThrow<IRegexCacheService>().CreateRegex(IpIdRegexText2); var colorRegex = Services.GetServiceOrThrow<IRegexCacheService>().CreateRegex(ColorRegexText); PostFlags flags = 0; if (data.Banned != "0" && !string.IsNullOrWhiteSpace(data.Banned)) { flags |= PostFlags.Banned; } if (data.Closed != "0" && !string.IsNullOrWhiteSpace(data.Closed)) { flags |= PostFlags.Closed; } if (data.Sticky != "0" && !string.IsNullOrWhiteSpace(data.Sticky)) { flags |= PostFlags.Sticky; } if (isPreview) { flags |= PostFlags.ThreadPreview; } if (data.Op != "0" && !string.IsNullOrWhiteSpace(data.Op)) { flags |= PostFlags.Op; } if ("mailto:sage".Equals((data.Email ?? "").Trim(), StringComparison.OrdinalIgnoreCase)) { flags |= PostFlags.Sage; } if (data.Edited != "0" && !string.IsNullOrWhiteSpace(data.Edited)) { flags |= PostFlags.IsEdited; } string admName = null; if (data.Tripcode != null) { if (data.Tripcode.StartsWith("!!%") && data.Tripcode.EndsWith("%!!")) { if ("!!%mod%!!".Equals(data.Tripcode)) { admName = "## Mod ##"; } else if ("!!%adm%!!".Equals(data.Tripcode)) { admName = "## Abu ##"; } else if ("!!%Inquisitor%!!".Equals(data.Tripcode)) { admName = "## Applejack ##"; } else if ("!!%coder%!!".Equals(data.Tripcode)) { admName = "## Кодер ##"; } else admName = data.Tripcode.Replace("!!%", "## ").Replace("%!!", " ##"); flags |= PostFlags.AdminTrip; } } var number = data.Number.TryParseWithDefault(); var postNodes = Services.GetServiceOrThrow<IMakabaHtmlPostParseService>().GetPostNodes(data.Comment ?? ""); var name = admName != null && string.IsNullOrWhiteSpace(data.Name) ? admName : WebUtility.HtmlDecode(data.Name ?? string.Empty).Replace(" ", " "); var result = new PostTree() { Link = new PostLink() { Engine = CoreConstants.Engine.Makaba, Board = link.Board, Thread = link.Thread, Post = number }, ParentLink = new ThreadLink() { Engine = CoreConstants.Engine.Makaba, Board = link.Board, Thread = link.Thread }, Subject = WebUtility.HtmlDecode(data.Subject ?? string.Empty), BoardSpecificDate = data.Date, Date = Services.GetServiceOrThrow<IDateService>().FromUnixTime(data.Timestamp.TryParseWithDefault()), Flags = flags, Quotes = new List<BoardLinkBase>(), Comment = new PostNodes() { Nodes = postNodes.ToList() }, Hash = data.Md5, Extensions = new List<PostTreeExtension>(), Email = data.Email, Media = new List<PostMediaBase>(), }; result.GeneratePostStamp(); if (string.IsNullOrWhiteSpace(result.Subject) && number == link.Thread) { try { var lines = ToPlainText(result); if (lines.Count > 0) { var s = lines.Where(l => !string.IsNullOrWhiteSpace(l)).FirstOrDefault(); if (s != null) { if (s.Length >= 50) { s = s.Substring(0, 50 - 3) + "..."; } result.Subject = s; } } } catch { } } string nameColor = null; PostColor color = null; var match = ipIdRegex.Match(name); var match2 = ipIdRegex2.Match(name); if (match.Success) { name = match.Groups["id"].Captures[0].Value; } else if (match2.Success) { name = match2.Groups["id"].Captures[0].Value; nameColor = match2.Groups["style"].Captures[0].Value; var cmatch = colorRegex.Match(nameColor); if (cmatch.Success) { try { var r = byte.Parse(cmatch.Groups["r"].Captures[0].Value, CultureInfo.InvariantCulture.NumberFormat); var g = byte.Parse(cmatch.Groups["g"].Captures[0].Value, CultureInfo.InvariantCulture.NumberFormat); var b = byte.Parse(cmatch.Groups["b"].Captures[0].Value, CultureInfo.InvariantCulture.NumberFormat); color = new PostColor() { R = r, G = g, B = b }; } catch (Exception) { color = null; } } } else if (name.StartsWith("Аноним ID:", StringComparison.OrdinalIgnoreCase)) { name = name.Remove(0, "Аноним ID:".Length).Trim(); } if (!string.IsNullOrEmpty(name) || !string.IsNullOrWhiteSpace(data.Tripcode)) { result.Extensions.Add(new PostTreePosterExtension() { Name = HtmlToText(name ?? ""), /* Windows.Data.Html.HtmlUtilities.ConvertToText работает очень медленно, потому что вызывает EDGE через COM, не годится для массовых обработок*/ //Name = Windows.Data.Html.HtmlUtilities.ConvertToText(name ?? ""), Tripcode = data.Tripcode, NameColorStr = nameColor, NameColor = color }); } var flagAndIcon = ParseFlagAndIcon(data.Icon); if (flagAndIcon.Icon != null) { result.Extensions.Add(flagAndIcon.Icon); } if (flagAndIcon.Country != null) { result.Extensions.Add(flagAndIcon.Country); } if (!string.IsNullOrWhiteSpace(data.Tags)) { result.Extensions.Add(new PostTreeTagsExtension() { TagString = data.Tags, Tags = new List<string>() { data.Tags } }); } if (data.Files != null) { foreach (var f in data.Files) { BoardLinkBase mediaLink, tnLink; if (IsBoardLink(f.Path, link.Board)) { mediaLink = new BoardMediaLink() { Engine = CoreConstants.Engine.Makaba, Board = link.Board, RelativeUri = RemoveBoardFromLink(f.Path), KnownMediaType = f.Type == MakabaMediaTypes.Webm ? KnownMediaType.Webm : KnownMediaType.Default }; tnLink = new BoardMediaLink() { Engine = CoreConstants.Engine.Makaba, Board = link.Board, RelativeUri = RemoveBoardFromLink(f.Thumbnail), KnownMediaType = KnownMediaType.Default }; } else { mediaLink = new MediaLink() { Engine = CoreConstants.Engine.Makaba, RelativeUri = f.Path, IsAbsolute = false, }; tnLink = new MediaLink() { Engine = CoreConstants.Engine.Makaba, RelativeUri = f.Thumbnail, IsAbsolute = false }; } var media = new PostImageWithThumbnail() { Link = mediaLink, ParentLink = result.Link, Size = f.Size * 1024, Height = f.Heigth, Width = f.Width, Name = f.Name, Thumbnail = new PostImage() { Link = tnLink, ParentLink = mediaLink, Height = f.TnHeight, Width = f.TnWidth, Size = null, Name = f.Name } }; result.Media.Add(media); } } return result; }
/// <summary> /// Получить короткую информацию о треде. /// </summary> /// <param name="firstPost">ОП-пост.</param> /// <returns>Короткая информация.</returns> public ShortThreadInfo GetShortInfo(PostTree firstPost) { if (firstPost == null) { return null; } PostImageWithThumbnail firstMedia = null; if (firstPost.Media != null) { firstMedia = firstPost.Media.OfType<PostImageWithThumbnail>().Where(l => l.Thumbnail != null && l.Thumbnail.Link != null).FirstOrDefault(); } return new ShortThreadInfo() { Title = firstPost.Subject, SmallImage = firstMedia != null ? new ThreadPictureInfo() { Link = firstMedia.Thumbnail.Link, Height = firstMedia.Thumbnail.Height, Width = firstMedia.Thumbnail.Width } : null }; }
/// <summary> /// Конструктор. /// </summary> /// <param name="postData">Данные поста.</param> /// <param name="parent">Родительская модель.</param> /// <param name="omitPosts">Пропущено постов.</param> public PostViewModel(PostTree postData, IPostCollectionViewModel parent, int omitPosts) : base(postData, parent) { this.omitPosts = omitPosts; }
/// <summary> /// Конструктор. /// </summary> /// <param name="postData">Данные поста.</param> /// <param name="parent">Родительская модель.</param> public PostViewModel(PostTree postData, IPostCollectionViewModel parent) : base(postData, parent) { }
/// <summary> /// Конструктор. /// </summary> /// <param name="postData">Данные поста.</param> /// <param name="parent">Родительская модель.</param> protected PostViewModelBase(PostTree postData, IPostCollectionViewModel parent) { PostData = postData; Parent = parent; }
/// <summary> /// Конструктор. /// </summary> /// <param name="postData">Данные.</param> /// <param name="parent">Родитель.</param> public PostNameViewModel(PostTree postData, IPostViewModel parent) { this.postData = postData; Parent = parent; TripCode = ""; Name = ""; AppHelpers.DispatchAction(SetData, false, 0); }