public IEnumerable <WebSearchResult> Search(string text) { string sql = "SELECT id, title, actors, year, genres, alternate_titles " + "FROM movie_info " + "WHERE title LIKE @search OR alternate_titles LIKE @search OR actors LIKE @search"; return(ReadList <WebSearchResult>(sql, delegate(SQLiteDataReader reader) { var result = new WebSearchResult() { Type = WebMediaType.Movie, Id = reader.ReadIntAsString(0), Title = reader.ReadString(1), Details = new WebDictionary <string>() { { "Year", reader.ReadIntAsString(3) }, { "Genres", String.Join(", ", reader.ReadPipeList(4)) }, } }; // simple score int score = result.Title.Contains(text, false) ? (int)Math.Round(40 + (decimal)text.Length / result.Title.Length * 40) : 0; var validAlternate = reader.ReadPipeList(5).Where(x => x.Contains(text, false)); score = Math.Max(score, validAlternate.Count() > 0 ? validAlternate.Max(x => 40 + (int)Math.Round((decimal)text.Length / x.Length * 30)) : 0); // actors var valid = reader.ReadPipeList(2).Where(x => x.Contains(text, false)); score = Math.Max(score, valid.Count() > 0 ? valid.Max(x => 40 + (int)Math.Round((decimal)text.Length / x.Length * 30)) : 0); // set result.Score = score; return result; }, new SQLiteParameter("@search", "%" + text + "%"))); }
public SearchResultsViewModel(WebSearchResult res, string url) { Score = res.Score; URL = url; Type = (SearchResultType)res.Type; Title = GetTitle(res); }
private string CreateLink(WebSearchResult result) { switch (result.Type) { case WebMediaType.Movie: return(Url.Action("Details", "MovieLibrary", new { movie = result.Id })); case WebMediaType.MusicAlbum: return(Url.Action("Album", "MusicLibrary", new { album = result.Id })); case WebMediaType.MusicArtist: return(Url.Action("Albums", "MusicLibrary", new { artist = result.Id })); case WebMediaType.MusicTrack: return(Url.Action("Album", "MusicLibrary", new { album = result.Details["AlbumId"], track = result.Id })); case WebMediaType.TVEpisode: return(Url.Action("Details", "TVShowsLibrary", new { episode = result.Id })); case WebMediaType.TVSeason: return(Url.Action("Episodes", "TVShowsLibrary", new { season = result.Id })); case WebMediaType.TVShow: return(Url.Action("Seasons", "TVShowsLibrary", new { show = result.Id })); default: return(null); } }
public async Task <IActionResult> Search(string query) { var searchResults = new WebSearchResult { Query = query.Trim(), }; await Task.Run(() => { var results = EngineOptions.SearchEngine.Search(query); foreach (var result in results) { var urlFile = EngineOptions.UrlFileStore.GetUrlFile(result.UrlFileId); var searchResultItem = new SearchResultItem { Title = urlFile.Title, Url = urlFile.Url, PublishDate = DateTime.FromBinary((long)urlFile.PublishDate), Score = result.Score.Value, ProScore = result.ProScore.Value, ScoreDebugInfo = result.Score.ToString(), ProScoreDebugInfo = result.ProScore.ToString(), }; if (result.WordPositions == null) { searchResultItem.Details = urlFile.TextContent .Substring(0, Math.Min(50, urlFile.TextContent.Length)).Replace("\r", "").Replace("\n", " "); } else { var orderPos = result.WordPositions.OrderBy(o => o.Position); var minWordPos = orderPos.First(); var minPos = Math.Max((int)minWordPos.Position - 50, 0); var maxPos = orderPos.Last(); var content = urlFile.TextContent; searchResultItem.Details = content.Substring((int)minPos, Math.Min((int)maxPos.Position - minPos + maxPos.Word.Length + 50, content.Length - minPos)) .Replace("\r", "").Replace("\n", " "); } searchResults.Items.Add(searchResultItem); } }); return(View("Index", searchResults)); }
private static IEnumerable <WebSearchResult> ParseResults(string data) { /* * <div class="prew-film"> * <div style="padding: 0px 0px 0px 30px;"> * <div class="prew-film-content"> * <div class="box4"><a href="http://dcshara.ru/uzhasy/14831118-pod-kupolom-under-the-dome-1-sezon.html" class="tip-bottom item" ><img width="155" height="228" src="http://dcshara.ru/uploads/posts/2013-06/1372606952_1372224699_kupol.jpg" alt="Под куполом - Under the Dome (1 сезон)" /> * <span class="tt opacity"><h2>Под куполом - Under the Dome (1 сезон)</h2></span></a></div> * </div> * <div class="prew-film-title"> * <div style="clear:both; height:10px;"></div> * <div align="center" class="date" style="height:30px; overflow:hidden;"><a href="http://dcshara.ru/uzhasy/">ужасы</a>, <a href="http://dcshara.ru/fantastika/">фантастика</a>, <a href="http://dcshara.ru/serial/">сериал</a></div> * <div class="bt2"><a href="http://dcshara.ru/uzhasy/14831118-pod-kupolom-under-the-dome-1-sezon.html">СКАЧАТЬ</a></div> * <div><a href="#" title=""><img width="70" height="18" src="/templates/Cinema/images/smt.jpg" alt="" /></a></div> * </div> * </div> * </div> */ int startIndex = 0; while ((startIndex = data.IndexOf("class=\"box4\"", startIndex)) != -1) { // class="box4"><a href="http://dcshara.ru/uzhasy/14831118-pod-kupolom-under-the-dome-1-sezon.html" class="tip-bottom item" ><img width="155" height="228" src="http://dcshara.ru/uploads/posts/2013-06/1372606952_1372224699_kupol.jpg" alt="Под куполом - Under the Dome (1 сезон)" WebSearchResult res = new WebSearchResult(); var linkStartInd = data.IndexOf("http://", startIndex); var linkEndInd = data.IndexOf("\" class", linkStartInd); res.ReleaseUrl = data.Substring(linkStartInd, linkEndInd - linkStartInd); var posterStartInd = data.IndexOf("http://", linkEndInd); var posterEndInd = data.IndexOf("\" alt=", posterStartInd); res.PosterUrl = data.Substring(posterStartInd, posterEndInd - posterStartInd); var nameStartInd = data.IndexOf("alt=\"", posterEndInd) + 5; var nameEndInd = data.IndexOf("\" />", nameStartInd); res.Name = data.Substring(nameStartInd, nameEndInd - nameStartInd); yield return(res); startIndex++; } }
private string GetTitle(WebSearchResult result) { switch (result.Type) { case WebMediaType.MusicAlbum: return(String.Format(FormStrings.SearchResultAlbum, result.Title, result.Details["Artist"])); case WebMediaType.MusicTrack: return(String.Format(FormStrings.SearchResultTrack, result.Title, result.Details["Artist"])); case WebMediaType.TVEpisode: return(String.Format("{0} ({1} {2}x{3})", result.Title, result.Details["ShowName"], result.Details["SeasonNumber"], result.Details["EpisodeNumber"])); default: return(result.Title); } }
public GridRow(WebSearchResult webSearchResult, int count) : this() { HeaderCell.Value = $"{count + 1}"; Cells.Add(new DataGridViewTextBoxCell()); Cells[0].Style.BackColor = webSearchResult.IsVIPad ? Color.DarkOrange : Color.White; DataGridViewTextBoxCell dateCell = new DataGridViewTextBoxCell() { Value = webSearchResult.Date.ToString(CultureInfo.CurrentUICulture) }; Cells.Add(dateCell); dateCell.Style.BackColor = webSearchResult.IsHighlighted ? Color.Lavender : Color.White; if (webSearchResult.ImageBinary == null && webSearchResult.ImageBase64 != null) { webSearchResult.ImageBinary = ImageUtil.Base64StringToImage(webSearchResult.ImageBase64); } Cells.Add(new DataGridViewImageCell() { Value = (Image)webSearchResult.ImageBinary }); DataGridViewLinkCell linkCell = new DataGridViewLinkCell { Value = webSearchResult.Title.Text, Tag = webSearchResult.Title.Url }; Cells.Add(linkCell); Cells.Add(new DataGridViewTextBoxCell() { Value = $"{webSearchResult.Price:C}" }); Cells.Add(new DataGridViewTextBoxCell() { Value = webSearchResult.Category }); Cells.Add(new DataGridViewTextBoxCell() { Value = webSearchResult.Address }); }
public IEnumerable <WebSearchResult> Search(string text) { using (DatabaseConnection connection = OpenConnection()) { IEnumerable <WebSearchResult> results; SQLiteParameter param = new SQLiteParameter("@search", "%" + text + "%"); // search for shows string showSql = "SELECT ID, Pretty_Name FROM online_series WHERE Pretty_Name LIKE @search"; IEnumerable <WebSearchResult> shows = ReadList <WebSearchResult>(showSql, delegate(SQLiteDataReader reader) { string title = reader.ReadString(1); return(new WebSearchResult() { Type = WebMediaType.TVShow, Id = reader.ReadIntAsString(0), Title = title, Score = 40 + (int)Math.Round((decimal)text.Length / title.Length * 40), }); }, param); results = shows; string actorShowSql = "SELECT ID, Pretty_Name, Actors FROM online_series WHERE Actors LIKE @search"; IEnumerable <WebSearchResult> actorShows = ReadList <WebSearchResult>(actorShowSql, delegate(SQLiteDataReader reader) { var valid = reader.ReadPipeList(2).Where(x => x.IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0); // contains is case sensitive if (valid.Count() == 0) { return(null); } return(new WebSearchResult() { Type = WebMediaType.TVShow, Id = reader.ReadIntAsString(0), Title = reader.ReadString(1), Score = valid.Max(x => 40 + (int)Math.Round((decimal)text.Length / x.Length * 30)) }); }, param); results = results.Concat(actorShows); #region Episodes // initialize List <SQLiteParameter> parameters = new List <SQLiteParameter>() { param }; // search for episodes Regex episodeRegex = new Regex(@"^(.*) ([0-9]{1,3})x([0-9]{1,3})$"); Match episodeResult = episodeRegex.Match(text); string episodeRegexWhere = "0"; if (episodeResult.Success) { episodeRegexWhere = "((os.Pretty_Name LIKE @show OR ls.Parsed_Name LIKE @show) AND e.SeasonIndex = @season AND e.EpisodeIndex = @episode)"; parameters.Add(new SQLiteParameter("@show", "%" + episodeResult.Groups[1].Value.Trim() + "%")); parameters.Add(new SQLiteParameter("@season", episodeResult.Groups[2].Value)); parameters.Add(new SQLiteParameter("@episode", episodeResult.Groups[3].Value)); } // execute string episodeSql = "SELECT e.EpisodeID, e.EpisodeName, e.EpisodeIndex, e.SeasonIndex, e.SeriesID, e.GuestStars, os.Pretty_Name, MIN(ls.Parsed_Name) AS Parsed_Name " + "FROM online_episodes e " + "INNER JOIN online_series os ON os.ID = e.SeriesID " + "INNER JOIN local_series ls ON ls.ID = e.SeriesID " + "WHERE e.EpisodeName LIKE @search OR e.GuestStars LIKE @search OR " + episodeRegexWhere + " " + "GROUP BY e.EpisodeID, e.EpisodeName, e.EpisodeIndex, e.SeasonIndex, e.SeriesID, e.GuestStars, os.Pretty_Name "; IEnumerable <WebSearchResult> episodes = ReadList <WebSearchResult>(episodeSql, delegate(SQLiteDataReader reader) { // read the data string title = reader.ReadString(1); string showTitle = reader.ReadString(6); WebSearchResult result = new WebSearchResult() { Type = WebMediaType.TVEpisode, Id = reader.ReadIntAsString(0), Title = title, Details = new WebDictionary <string>() { { "EpisodeNumber", reader.ReadIntAsString(2) }, { "SeasonNumber", reader.ReadIntAsString(3) }, { "ShowId", reader.ReadIntAsString(4) }, { "ShowName", !String.IsNullOrEmpty(showTitle) ? showTitle : reader.ReadString(7) } } }; // title int score = title.Contains(text, false) ? 40 + (int)Math.Round((decimal)text.Length / title.Length * 40) : 0; // guest stars var valid = reader.ReadPipeList(5).Where(x => x.Contains(text, false)); // .Contains() is case sensitive score = Math.Max(score, valid.Count() > 0 ? valid.Max(x => 20 + (int)Math.Round((decimal)text.Length / x.Length * 40)) : 0); // regex match if (episodeResult.Success && (result.Details["ShowName"].Contains(episodeResult.Groups[1].Value.Trim(), false) && result.Details["SeasonNumber"] == episodeResult.Groups[2].Value && result.Details["EpisodeNumber"] == episodeResult.Groups[3].Value)) { score = 100; } // set score and return result.Score = score; return(result); }, parameters.ToArray()); // when there are multiple matches with 100%, set them all to 95% as we apparantly aren't sure if (episodes.Count(x => x.Score == 100) > 1) { episodes = episodes.Select(x => { if (x.Score == 100) { x.Score = 95; } return(x); }); } results = results.Concat(episodes); #endregion // fancy season search: <showname> s<season> Regex seasonRegex = new Regex(@"^(.*) s([0-9]{1,3})$"); Match seasonResult = seasonRegex.Match(text); if (seasonResult.Success) { string sql = "SELECT DISTINCT s.ID, s.SeasonIndex, s.SeriesID, o.Pretty_Name, MIN(l.Parsed_Name) AS Parsed_Name " + "FROM season s " + "INNER JOIN online_series o ON s.SeriesID = o.ID " + "INNER JOIN local_series l ON s.SeriesID = l.ID " + "WHERE s.HasLocalFiles = 1 AND (o.Pretty_Name = @show OR l.Parsed_Name = @show) AND s.SeasonIndex = @season " + "GROUP BY s.ID, s.SeasonIndex, s.SeriesID, o.Pretty_Name "; results = ReadList <WebSearchResult>(sql, delegate(SQLiteDataReader reader) { string showTitle = !String.IsNullOrEmpty(reader.ReadString(3)) ? reader.ReadString(3) : reader.ReadString(4); return(new WebSearchResult() { Type = WebMediaType.TVSeason, Id = reader.ReadString(0), Title = showTitle + " (season " + reader.ReadInt32(1) + ")", Score = 100, Details = new WebDictionary <string>() { { "SeasonNumber", reader.ReadIntAsString(1) }, { "ShowId", reader.ReadIntAsString(2) }, { "ShowName", showTitle } } }); }, new SQLiteParameter("@show", seasonResult.Groups[1].Value.Trim()), new SQLiteParameter("@season", seasonResult.Groups[2].Value)) .Concat(results); } // return return(results); } }
public IEnumerable <WebSearchResult> Search(string text) { using (DatabaseConnection connection = OpenConnection()) { SQLiteParameter param = new SQLiteParameter("@search", "%" + text + "%"); string artistSql = "SELECT DISTINCT strArtist, strAlbumArtist, strAlbum FROM tracks WHERE strArtist LIKE @search"; IEnumerable <WebSearchResult> artists = ReadList <IEnumerable <WebSearchResult> >(artistSql, delegate(SQLiteDataReader reader) { IEnumerable <string> albumArtists = reader.ReadPipeList(1); return(reader.ReadPipeList(0) .Where(name => name.Contains(text)) .Select(name => new WebSearchResult() { Type = WebMediaType.MusicArtist, Id = name, Title = name, Score = (int)Math.Round(40 + (decimal)text.Length / name.Length * 40) }) .Concat(new[] { new WebSearchResult() { Type = WebMediaType.MusicAlbum, Id = (string)AlbumIdReader(reader, 2), Title = reader.ReadString(2), Score = (int)Math.Round(20 + (decimal)text.Length / reader.ReadString(0).Length * 40), Details = new WebDictionary <string>() { { "Artist", albumArtists.First() }, { "ArtistId", albumArtists.First() } } } })); }, param).SelectMany(x => x); string songSql = "SELECT DISTINCT idTrack, strTitle, strAlbumArtist, strAlbum, iDuration, iYear FROM tracks WHERE strTitle LIKE @search"; IEnumerable <WebSearchResult> songs = ReadList <WebSearchResult>(songSql, delegate(SQLiteDataReader reader) { IEnumerable <string> allArtists = reader.ReadPipeList(2); string title = reader.ReadString(1); string artist = allArtists.Count() == 0 ? String.Empty : allArtists.First(); return(new WebSearchResult() { Type = WebMediaType.MusicTrack, Id = reader.ReadIntAsString(0), Title = title, Score = (int)Math.Round(40 + (decimal)text.Length / title.Length * 40), Details = new WebDictionary <string>() { { "Artist", artist }, { "ArtistId", artist }, { "Album", reader.ReadString(3) }, { "AlbumId", (string)AlbumIdReader(reader, 3) }, { "Duration", reader.ReadIntAsString(4) }, { "Year", reader.ReadIntAsString(5) } } }); }, param); string albumsSql = "SELECT DISTINCT t.strAlbumArtist, t.strAlbum, " + "CASE WHEN i.iYear ISNULL THEN MIN(t.iYear) ELSE i.iYear END AS year " + "FROM tracks t " + "LEFT JOIN albuminfo i ON t.strAlbum = i.strAlbum AND t.strArtist LIKE '%' || i.strArtist || '%' " + "WHERE t.strAlbum LIKE @search " + "GROUP BY t.strAlbumArtist, t.strAlbum "; IEnumerable <WebSearchResult> albums = ReadList <IEnumerable <WebSearchResult> >(albumsSql, delegate(SQLiteDataReader reader) { string title = reader.ReadString(1); IEnumerable <string> artistList = reader.ReadPipeList(0); var albumResult = new WebSearchResult() { Type = WebMediaType.MusicAlbum, Id = (string)AlbumIdReader(reader, 1), Title = title, Score = (int)Math.Round(40 + (decimal)text.Length / title.Length * 40), Details = new WebDictionary <string>() { { "Artist", artistList.First().Trim() }, { "ArtistId", artistList.First().Trim() }, { "Year", reader.ReadIntAsString(2) } } }; string allArtists = String.Join("", artistList); return(artistList .Select(name => new WebSearchResult() { Type = WebMediaType.MusicArtist, Id = name, Title = name, Score = (int)Math.Round((decimal)name.Length / allArtists.Length * 30) }).Concat(new[] { albumResult })); }, param).SelectMany(x => x); return(artists.Concat(songs).Concat(albums)); } }
public List <WebSearchResult> GetResults(Filter filter) { List <WebSearchResult> results = new List <WebSearchResult>(); HtmlNode node = new HtmlToHtmlNode(_content.Value); if (node == null) { Log.Error("Can't parse content. Invalid HtmlNode."); return(results); } // <div class="snippet-date-info" data-marker="item-date" data-shape="default" data-tooltip="27 августа 14:12" flow="down"> // 2 дня назад // </div> HtmlNodeCollection dates = node.SelectNodes("//div[@data-marker='item-date']"); if (dates == null) { Log.Error("Can't parse dates. Unexpected html structure."); return(results); } DateTime prevDate = DateTime.Today; foreach (HtmlNode dateNode in dates) { // <div class="description item_table-description"> // <div class="snippet-title-row">... HtmlNode entryNode = dateNode.ParentNode.ParentNode.ParentNode; HtmlNode titleANode = entryNode.SelectSingleNode(".//div[contains(@class,'snippet-title-row')]/h3/a"); WebLink titleValue = GetTitleValue(titleANode); string title = new LowerText(titleValue.Text); bool @break = false; foreach (string contains in filter.TitleContains) { if (!title.Contains(contains)) { @break = true; break; } } if (@break) { continue; } foreach (string contains in filter.TitleDoesNotContain) { if (title.Contains(contains)) { @break = true; break; } } if (@break) { continue; } DateTime?dateValue = AvitoParser.GetDateValue(dateNode.InnerText, prevDate, DateTime.Now); if (dateValue == null || dateValue < filter.DatesAfter) { continue; } // <div class="snippet-price-row"><span itemprop="offers" itemtype="http://schema.org/Offer" itemscope="" class="snippet-price " data-shape="default" data-marker="item-price"><meta itemprop="priceCurrency" content="RUB"><meta itemprop="price" content="6490"><meta itemprop="availability" content="https://schema.org/LimitedAvailability"> // 6 490 ₽ HtmlNode priceNode = entryNode.SelectSingleNode(".//span[@data-marker='item-price']"); int? priceValue = AvitoParser.GetPriceValue(priceNode?.InnerText); if (priceValue != null) { if (priceValue < filter.MinPrice || priceValue > filter.MaxPrice) { continue; } } bool isVIPad = priceNode.ParentNode.ParentNode.GetAttributeValue("class", "") == "options" && priceNode.ParentNode.ParentNode.GetAttributeValue("itemprop", "") == "offers"; // <div class="data"> // <p>Часы и украшения</p> HtmlNode categoryNode = entryNode.SelectSingleNode(".//div[@class='data']/p"); // <span class="item-address-georeferences-item__content">Комендантский проспект</span> HtmlNode addressNode = entryNode.SelectSingleNode(".//span[@class='item-address-georeferences-item__content']"); // <div class="item-photo" data-marker="item-photo"> HtmlNode imgNode = entryNode.ParentNode.ParentNode.SelectSingleNode(".//div[@data-marker='item-photo']"); imgNode = imgNode?.SelectSingleNode(".//img"); if (isVIPad) { if (imgNode == null) { imgNode = entryNode.ParentNode.ParentNode.SelectSingleNode(".//div[@class='img-container']"); imgNode = imgNode?.SelectSingleNode(".//img"); } } WebSearchResult result = new WebSearchResult(); result.Title = titleValue; result.IsVIPad = isVIPad; result.Date = dateValue.Value; prevDate = result.Date.Date; result.Category = AvitoParser.GetCategoryValue(categoryNode?.InnerText); result.Address = AvitoParser.GetAddressValue(addressNode?.InnerText); result.ImageUrl = GetImageUrl(imgNode); result.Price = priceValue; results.Add(result); } return(results); }