public void TryGrabAndParsePage_Song() { OneSongHeader expected_song_header = new OneSongHeader( 1, "Graeme Revell - Vaako Conspiracy", "Vaako Conspiracy", "Graeme Revell", "The Chronicles Of Riddick - OST / Хроники Риддика - Саундтрек [Score]", "OST", "03:19", "5,31 Мб", "223 Кб/с", "mp3", "Fluffy", new Uri("http://fp42.myzuka.ru/Download.aspx?lid=727400&mid=5258695&date=20140130224847&sum=0afff71bffd5ff030dad549c1973575f&name=&ic=False&cr=False&ex=.jpg&il=False"), new Uri("http://myzuka.ru/Song/164181/Graeme-Revell-Vaako-Conspiracy"), true ); ACommonData result1 = Core.TryGrabAndParsePage( new Uri("http://myzuka.ru/Song/164181/Graeme-Revell-Vaako-Conspiracy"), "Mozilla/5.0 (Windows; I; Windows NT 5.1; ru; rv:1.9.2.13) Gecko/20100101 Firefox/4.0", true, false, CancellationToken.None); Assert.NotNull(result1); Assert.IsInstanceOf(typeof(ParsedSong), result1); ParsedSong conv_result1 = (ParsedSong)result1; Assert.IsTrue(conv_result1.Header.Equals(expected_song_header)); Assert.IsTrue(conv_result1.AlbumLink == new Uri("http://myzuka.ru/Album/12059/Graeme-Revell-The-Chronicles-Of-Riddick-Ost-Хроники-Риддика-Саундтрек-Score-2004")); }
/// <summary> /// Извлекает и возвращает всю информацию по одной песне из страницы песни /// </summary> /// <param name="HTMLPage"></param> /// <returns></returns> internal static OneSongHeader ParseOneSongHeader(HtmlDocument HTMLPage) { String caption = CoreInternal.TryGrabCaption(HTMLPage); HtmlNode body_node = HTMLPage.DocumentNode.SelectSingleNode( "//div[@class='centerblock gr']/div[starts-with(@class, 'in2')]/div/table[@style and @class]/tr/td[2][@class='infoSong']"); if (body_node == null) {throw new InvalidOperationException("Невозможно извлечь блок HTML-кода с метаинформацией по песне");} String body = body_node.InnerHtml; Int32 pos_input; String genre = StringTools.SubstringHelpers.GetInnerStringBetweenTokens (body, "Жанр:", "Исполнитель", 0, StringComparison.OrdinalIgnoreCase, out pos_input); if (genre.Contains("Нет данных", StringComparison.OrdinalIgnoreCase) == true) { genre = "Нет данных"; } else { genre = StringTools.SubstringHelpers.GetInnerStringBetweenTokens (genre, ">", "</a>", 0, StringComparison.OrdinalIgnoreCase, out pos_input); genre = HttpUtility.HtmlDecode(genre); } String artist = StringTools.SubstringHelpers.GetInnerStringBetweenTokens (body, "Исполнитель:", "<br>", pos_input, StringComparison.OrdinalIgnoreCase, out pos_input).Trim(); artist = CoreInternal.ExtractFromHTML(artist); String album = StringTools.SubstringHelpers.GetInnerStringBetweenTokens (body, "Альбом:", "<br>", pos_input, StringComparison.OrdinalIgnoreCase, out pos_input).Trim(); album = CoreInternal.ExtractFromHTML(album); String duration = StringTools.SubstringHelpers.GetInnerStringBetweenTokens (body, "Длительность:", "<br>", pos_input, StringComparison.OrdinalIgnoreCase, out pos_input).Trim(); duration = CoreInternal.ExtractFromHTML(duration); String size = StringTools.SubstringHelpers.GetInnerStringBetweenTokens (body, "Размер:", "<br>", pos_input, StringComparison.OrdinalIgnoreCase, out pos_input).Trim(); size = CoreInternal.ExtractFromHTML(size); String format = StringTools.SubstringHelpers.GetInnerStringBetweenTokens (body, "<i class=\"format\">", "</i>", pos_input, StringComparison.OrdinalIgnoreCase, out pos_input).Trim(); String bitrate = StringTools.SubstringHelpers.GetInnerStringBetweenTokens (body, "<i class=\"bitrate\">", "</i>", pos_input, StringComparison.OrdinalIgnoreCase, out pos_input).Trim(); HtmlNode uploader_node = body_node.ChildNodes.FindFirst("div"); String uploader = uploader_node.InnerText.TrimStart("Загрузил:", StringComparison.OrdinalIgnoreCase, false).Trim(); HtmlNode name_node = HTMLPage.DocumentNode.SelectSingleNode("//div[@id]/table[@width='100%']/tr[starts-with(@id,'trSong_')]/td[2]/div"); if(name_node==null) {throw new InvalidOperationException("Невозможно извлечь из страницы песни блок HTML-кода с названием песни");} Boolean is_available = !name_node.InnerText.Contains("Файл утерян", StringComparison.InvariantCultureIgnoreCase); String name = HttpUtility.HtmlDecode(name_node.ChildNodes.Single( nd => nd.Name == "span" && nd.Attributes.Count > 0 && nd.Attributes.Contains("itemprop") && nd.Attributes["itemprop"].Value == "name" ).InnerText.CleanString().Trim()); HtmlNode link_node = body_node.SelectSingleNode ("//div[@class='centerblock gr']/div[starts-with(@class, 'in2')]/div/table[@style and @class]/tr/td[2][@class='infoSong']/meta[@itemprop='url' and @content]"); if(link_node==null) {throw new InvalidOperationException("Невозможно извлечь из страницы песни блок HTML-кода с URL на данную страницу");} String raw_link_URI = link_node.GetAttributeValue("content", ""); String err_mes; Uri link_URI = CoreInternal.TryFixReturnURI(raw_link_URI, out err_mes); if (link_URI == null) { throw new InvalidOperationException("Невозможно извлечь URI текущей страницы песни: " + err_mes); } OneSongHeader song = new OneSongHeader( 1, caption, name, artist, album, genre, duration, size, bitrate, format, uploader, CoreInternal.TryGrabImageUri(HTMLPage), link_URI, is_available); return song; }
internal static KeyValuePair<OneSongHeader, Exception> DownloadAndSaveOneSong (OneSongHeader Song, String UserAgent, Boolean GenerateNewFilenames, String FilenameTemplate, String FolderPath, Int32 IterationNumber) { // 1. запрос по УРЛ и перевести результат в ХТМЛдокумент String err_mess; HtmlAgilityPack.HtmlDocument HTML_doc = CoreInternal.TryGrabPage(Song.SongPageURI, UserAgent, out err_mess); if (HTML_doc == null) { return new KeyValuePair<OneSongHeader, Exception>(Song, new InvalidOperationException( String.Format("Невозможно скачать HTML-документ по ссылке '{0}' на итерации {1}: {2}", Song.SongPageURI.ToString(), IterationNumber, err_mess))); } // 2. извлечь УРЛ на скачивание самой песни Uri download_link; try { download_link = CoreInternal.ExtractDownloadSongURI(HTML_doc); } catch (Exception ex) { return new KeyValuePair<OneSongHeader, Exception>(Song, new InvalidOperationException( "Невозможно извлечь ссылку на скачивание песни из HTML-документа на итерации " + IterationNumber, ex)); } // 3. скачать саму песню и всунуть её в контейнер DownloadedFile DownloadedFile song_file = CoreInternal.TryDownloadFile (download_link, Song.SongPageURI, UserAgent, out err_mess); if (song_file == null) { return new KeyValuePair<OneSongHeader, Exception>(Song, new InvalidOperationException(String.Format( "Невозможно скачать файл песни '{0}.{1}' (альбом {2}) из страницы '{3}' по ссылке '{4}' на итерации {5}: {6}", Song.Number, Song.Name, Song.Album, Song.SongPageURI.ToString(), download_link.ToString(), IterationNumber, err_mess))); } //4. определиться с названием сохраняемого файла String new_filename = null; if (GenerateNewFilenames == true) { new_filename = Song.GenerateSongFilename(song_file.Filename, FilenameTemplate); FilePathTools.TryCleanFilename(new_filename, out new_filename); } if (new_filename == null) { new_filename = song_file.Filename; } new_filename = Path.Combine(FolderPath, new_filename); //5. начать сохранение try { using (FileStream fs = new FileStream(new_filename, FileMode.Create, FileAccess.Write, FileShare.None)) { song_file.FileBody.Position = 0; song_file.FileBody.CopyTo(fs, 1024*8); } return new KeyValuePair<OneSongHeader, Exception>(Song, null); } catch (Exception ex) { return new KeyValuePair<OneSongHeader, Exception>(Song, new InvalidOperationException(String.Format( "Невозможно сохранить файл песни '{0}.{1}' (альбом {2}) на диск с полным именем файла '{3}' на итерации {4}", Song.Number, Song.Name, Song.Album, new_filename, IterationNumber), ex)); } finally { song_file.Dispose(); song_file = null; } }