/// <summary> /// Пытается добавить текст автора в очередь закачки. /// Если уже есть в кеше, то не добавляет, а возвращает из кеша. /// </summary> /// <param name="author">Автор</param> /// <param name="text">Текст</param> /// <returns>Элемент очереди, либо из кеша</returns> public static DownloadTextItem Add(Author author, AuthorText text) { foreach (DownloadTextItem downloadTextItem in DownloadTextItems) { if (downloadTextItem.GetHashCode() == (new DownloadTextItem(author, text)).GetHashCode()) return downloadTextItem; } DownloadTextItem item = new DownloadTextItem(author, text) {Logger = _logger}; if (item.Text == null) DownloadTextItems.Add(item); ChangeVisibility(); return item; }
private static bool ProcessArrivedBook(TransportBookInfo book, bool isMyInfo) { if (book == null || string.IsNullOrWhiteSpace(book.AuthorLink)) { return(true); } if (Authors == null) { return(true); } var author = Authors.FindAuthor(book.AuthorLink); if (author == null) { return(true); } var alreadyStared = author.IsNew; if (author.IsIgnored || author.IsDeleted) { return(true); } var authorText = author.Texts.FirstOrDefault(t => t.Link == book.Link); // Link у нас - относительный путь, поэтому не преобразовываем bool isNew = false; bool isUpdated = false; var convertedTime = new DateTime(book.UpdateDate, DateTimeKind.Utc).ToLocalTime(); if (isMyInfo) { if (authorText == null) { return(true); } // просто маркируем свои штампы серверным, не меняя локальные даты проверок authorText.ServerStamp = book.UpdateDate; author.ServerStamp = book.UpdateDate; } else { if (authorText == null) { authorText = new AuthorText(); isNew = true; } if (authorText.ServerStamp > book.UpdateDate) { return(true); } if (!isNew) { book.Size = book.Size < 0 ? 0 : book.Size; // кооректируем, иногда бывает -1 isUpdated = ((authorText.Name != book.Name || authorText.Size != book.Size || (_setting.SkipBookDescription ? false : authorText.Description != book.Description))); } if (!isNew && !isUpdated) { authorText.ServerStamp = book.UpdateDate;// скорректируем локальное значение. поставим серверное return(true); } _messageBrokerTrayInfoCollectorTimer.Stop(); authorText.Description = book.Description; authorText.Genres = book.Genres; authorText.Link = book.Link; authorText.Name = book.Name; authorText.SectionName = book.SectionName; if (!authorText.IsNew) { authorText.SizeOld = authorText.Size; } authorText.Size = book.Size; authorText.UpdateDate = convertedTime; authorText.ServerStamp = book.UpdateDate; // ставим штамп сервера authorText.IsNew = true; if (isNew) { author.Texts.Add(authorText); } author.LastCheckDate = authorText.UpdateDate; try { if (author.NextCheckDate < author.LastCheckDate) { var elasticScheduler = new ElasticScheduler(_logger, _setting); elasticScheduler.MakePlan(author); elasticScheduler.SaveStatistics(); } author.UpdateDate = authorText.UpdateDate; author.ServerStamp = book.UpdateDate; // ставим штамп сервера author.IsNew = true; _logger.Add(string.Format("StatServer> Уведомление: обновился {0} ({1})", author.Name, authorText.Name), true, false); if (!_messageBrokerTrayInfo.Contains(author.Name) && !alreadyStared) { _messageBrokerTrayInfo = string.IsNullOrWhiteSpace(_messageBrokerTrayInfo) ? author.Name : _messageBrokerTrayInfo + "; " + author.Name; } _messageBrokerTrayInfoCollectorTimer.Start(); } catch (Exception ex) { _logger.Add(string.Format("Ошибка формирования плана проверок автора {0} - {1}", author.Name, ex)); } } return(false); }
/// <summary> /// Обновляет список произведений автора /// </summary> /// <param name="page">Страница автора со списком произведений</param> /// <param name="context">Контекст синхронизации для обновления GUI</param> /// <returns>true - автор обновился</returns> public bool UpdateAuthorInfo(string page, SynchronizationContext context) { lock (_lockObj) { bool retValue = false; Author authorTemp = new Author { UpdateDate = UpdateDate }; // проанализируем данные на страничке. если раньше их не загружали, то в любом случае не показываем, что есть обновления, просто заполняем данные MatchCollection matches = Regex.Matches(page, "<DL><DT><li>(?:<font.*?>.*?</font>)?\\s*(<b>(?<Authors>.*?)\\s*</b>\\s*)?<A HREF=(?<LinkToText>.*?)><b>\\s*(?<NameOfText>.*?)\\s*</b></A>.*?<b>(?<SizeOfText>\\d+)k</b>.*?<small>(?:Оценка:<b>(?<DescriptionOfRating>(?<rating>\\d+(?:\\.\\d+)?).*?)</b>.*?)?\\s*\"(?<Section>.*?)\"\\s*(?<Genres>.*?)?\\s*(?:<A HREF=\"(?<LinkToComments>.*?)\">Комментарии:\\s*(?<CommentsDescription>(?<CommentCount>\\d+).*?)</A>\\s*)?</small>.*?(?:<br><DD>(?<Description>.*?))?</DL>"); if (matches.Count > 0) { int cnt = 0; foreach (Match m in matches) { var item = new AuthorText { Description = NormalizeHTML(m.Groups["Description"].Value).Trim(), Genres = NormalizeHTML(m.Groups["Genres"].Value), Link = m.Groups["LinkToText"].Value, Name = NormalizeHTML(m.Groups["NameOfText"].Value), Order = cnt, SectionName = NormalizeHTML(m.Groups["Section"].Value).Replace("@", ""), Size = int.Parse(m.Groups["SizeOfText"].Value) }; authorTemp.Texts.Add(item); cnt++; } } if (Texts.Count > 0) // если раньше загружали автора, то проводим сравнение { foreach (AuthorText txt in authorTemp.Texts) { bool bFound = false; int OldSize = 0; // стрый размер текста foreach (AuthorText t in Texts) { if (txt.Link == t.Link) { txt.Cached = t.Cached; OldSize = t.Size;// запоминаем старый размер, чтобы запомнить его в новом тексте } if (txt.Description == t.Description && txt.Name == t.Name && txt.Size == t.Size) { bFound = true; // переносим значение isNew в новый массив, чтобы не потерять непрочитанные новые тексты txt.IsNew = t.IsNew; txt.UpdateDate = t.UpdateDate; break; } } if (!bFound) { retValue = true; authorTemp.IsNew = true; txt.IsNew = true; txt.UpdateDate = DateTime.Now; txt.SizeOld = OldSize; // да, автор обновился authorTemp.UpdateDate = DateTime.Now; } } // доп проверка по количеству произведений if (authorTemp.Texts.Count != Texts.Count) { retValue = true; authorTemp.UpdateDate = DateTime.Now; } } context.Post(SyncRun, new RunContent {Renewed = this, New = authorTemp}); return retValue; } // lock }
/// <summary> /// Обновляет список произведений автора /// </summary> /// <param name="page">Страница автора со списком произведений</param> /// <param name="context">Контекст синхронизации для обновления GUI</param> /// <returns>true - автор обновился</returns> public bool UpdateAuthorInfo(string page, SynchronizationContext context) { lock (_lockObj) { bool retValue = false; Author authorTemp = new Author { UpdateDate = UpdateDate }; // проанализируем данные на страничке. если раньше их не загружали, то в любом случае не показываем, что есть обновления, просто заполняем данные MatchCollection matches = Regex.Matches(page, "<DL><DT><li>(?:<font.*?>.*?</font>)?\\s*(<b>(?<Authors>.*?)\\s*</b>\\s*)?<A HREF=(?<LinkToText>.*?)><b>\\s*(?<NameOfText>.*?)\\s*</b></A>.*?<b>(?<SizeOfText>\\d+)k</b>.*?<small>(?:Оценка:<b>(?<DescriptionOfRating>(?<rating>\\d+(?:\\.\\d+)?).*?)</b>.*?)?\\s*\"(?<Section>.*?)\"\\s*(?<Genres>.*?)?\\s*(?:<A HREF=\"(?<LinkToComments>.*?)\">Комментарии:\\s*(?<CommentsDescription>(?<CommentCount>\\d+).*?)</A>\\s*)?</small>.*?(?:<br><DD>(?<Description>.*?))?</DL>"); if (matches.Count > 0) { int cnt = 0; foreach (Match m in matches) { var item = new AuthorText { Description = NormalizeHTML(m.Groups["Description"].Value).Trim(), Genres = NormalizeHTML(m.Groups["Genres"].Value), Link = m.Groups["LinkToText"].Value, Name = NormalizeHTML(m.Groups["NameOfText"].Value), Order = cnt, SectionName = NormalizeHTML(m.Groups["Section"].Value).Replace("@", ""), Size = int.Parse(m.Groups["SizeOfText"].Value) }; authorTemp.Texts.Add(item); cnt++; } } if (Texts.Count > 0) // если раньше загружали автора, то проводим сравнение { foreach (AuthorText txt in authorTemp.Texts) { bool bFound = false; int OldSize = 0; // стрый размер текста foreach (AuthorText t in Texts) { if (txt.Link == t.Link) { txt.Cached = t.Cached; OldSize = t.Size;// запоминаем старый размер, чтобы запомнить его в новом тексте } if (txt.Description == t.Description && txt.Name == t.Name && txt.Size == t.Size) { bFound = true; // переносим значение isNew в новый массив, чтобы не потерять непрочитанные новые тексты txt.IsNew = t.IsNew; txt.UpdateDate = t.UpdateDate; break; } } if (!bFound) { retValue = true; authorTemp.IsNew = true; txt.IsNew = true; txt.UpdateDate = DateTime.Now; txt.SizeOld = OldSize; // да, автор обновился authorTemp.UpdateDate = DateTime.Now; } } // доп проверка по количеству произведений if (authorTemp.Texts.Count != Texts.Count) { retValue = true; authorTemp.UpdateDate = DateTime.Now; } } context.Post(SyncRun, new RunContent { Renewed = this, New = authorTemp }); return(retValue); } // lock }
/// <summary> /// Конструктор (при нахождении файла в кеше устанавливается свойство Text /// </summary> /// <param name="author">Автор</param> /// <param name="text">Текст</param> public DownloadTextItem(Author author, AuthorText text) { _author = author; AuthorText = text; string fileName = GetCachedFileName(); if (File.Exists(fileName)) Text = File.ReadAllText(fileName, Encoding.GetEncoding(1251)); BytesReceived = 0; }
public static AuthorList Load() { var result = new AuthorList(); #region Чтение из БД using (var con = new SqlCeConnection("Data Source=" + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Author.sdf"))) { con.Open(); using (var com = new SqlCeCommand("Select [Id],[Name],[Url],[DateLine],[isIgnored], [Category] from [Author]", con)) { var dr = com.ExecuteReader(); while (dr.Read()) { result.Add(new Author { Id = dr.GetInt32(0), Name = dr.GetString(1), URL = dr.GetString(2), UpdateDate = dr.GetDateTime(3), IsIgnored = dr.GetBoolean(4), Category = dr.GetString(5) }); } var aTexts = AuthorText.Read(); foreach (var aText in aTexts) { var a = result.Find(aText.IdAuthor); if (a != null) { a.Texts.Add(aText); } } foreach (var a in result) { a.PropertyChanged += AuthorPropertyChanged; } } } result.ListChanged += AuthorListChanged; #endregion if (result.Count > 0) { return(result); } #region Если есть данные в старом файле БД (пусть будет версии 0 с БД), то перегоняем оттуда if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Author.sdf_0"))) { using (var con = new SqlCeConnection("Data Source=" + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Author.sdf_0"))) { con.Open(); using ( var com = new SqlCeCommand("Select [Id],[Name],[Url],[DateLine],[isIgnored] from [Author]", con) ) { var dr = com.ExecuteReader(); while (dr.Read()) { Author a = new Author { Id = dr.GetInt32(0), Name = dr.GetString(1), URL = dr.GetString(2), UpdateDate = dr.GetDateTime(3), IsIgnored = dr.GetBoolean(4) }; result.Add(a); a.Texts = new BindingList <AuthorText>(); using ( var _com = new SqlCeCommand( "Select [Id],[Name],[Url],[SectionName],[DateLine],[Genres],[Description],[Size],[LastSize],[IsNew],[IdAuthor] From [AuthorText] Where IdAuthor=" + a.Id.ToString(), con)) { var _dr = _com.ExecuteReader(); while (_dr.Read()) { var aText = new AuthorText(); aText.Read(_dr); aText.Id = 0;// перегенерим айдишку, чтобы произошло добавление в новую БД a.Texts.Add(aText); aText.Save(); } } } } foreach (var a in result) { a.Id = 0;// перегенерим айдишку, чтобы произошло добавление в новую БД a.Save(); a.PropertyChanged += AuthorPropertyChanged; } } return(result); } #endregion #region Чтение из XML try { using (var st = new StreamReader(InfoUpdater.AuthorsFileName)) result = (AuthorList)(new XmlSerializer(typeof(AuthorList))).Deserialize(st); } catch { result = new AuthorList(); result.Retreive(); } result.ListChanged += new ListChangedEventHandler(AuthorListChanged); foreach (var a in result) { a.Save(); a.PropertyChanged += AuthorPropertyChanged; } #endregion return(result); }