public async ValueTask <MuzlanResponse <IList <SitemapRecord> > > GetVideos(CancellationToken token = default) { var pageUri = new Uri($"{_baseUri.DnsSafeHost}/sitemap/videos"); var pagination = new MuzlanPagination(pageUri, _client, _parser); var items = new List <SitemapRecord>(); try { await foreach (var page in pagination.FollowForward(token).ConfigureAwait(false)) { await foreach (var item in EnumerateSitemapItems(page, token).ConfigureAwait(false)) { items.Add(item); } } return(MuzlanResponse <IList <SitemapRecord> > .FromResult(items, pagination.PageUri)); } catch (Exception ex) { if (pagination.PageNumber == -1) { return(MuzlanResponse <IList <SitemapRecord> > .FromException(ex, pagination.PageUri)); } return(MuzlanResponse <IList <SitemapRecord> > .FromPartialResult(items, pagination.PageUri, pagination.PageNumber)); } }
public async ValueTask <MuzlanResponse <IList <AlbumRecord> > > FindAlbums(string artist, CancellationToken token = default) { var pageUri = new Uri($"https://{_baseUri.DnsSafeHost}/artist/{Uri.EscapeDataString(artist)}/all-albums"); try { var content = await _client.TryGetStringAsync(pageUri, token).ConfigureAwait(false); using var document = await _parser.ParseDocumentAsync(content, token).ConfigureAwait(false); var albums = new List <AlbumRecord>(); foreach (var item in document.QuerySelectorAll <IHtmlDivElement>("div.page-content div.row div.item")) { var mediaImage = item.QuerySelector <IHtmlImageElement>("div.item-media a.item-media-content img"); var mediaTitle = item.QuerySelector <IHtmlAnchorElement>("div.item-info div.item-title a"); var imageUri = new Uri($"https://{_baseUri.DnsSafeHost}{mediaImage.Dataset["original"]}"); var albumName = mediaTitle.Text.Trim(); var albumUri = new Uri($"https://{_baseUri.DnsSafeHost}{mediaTitle.PathName}"); var album = new AlbumRecord(artist, albumName, albumUri, imageUri); albums.Add(album); } return(MuzlanResponse <IList <AlbumRecord> > .FromResult(albums, pageUri)); } catch (Exception ex) { return(MuzlanResponse <IList <AlbumRecord> > .FromException(ex, pageUri)); } }
public async ValueTask <MuzlanResponse <IList <SearchQueryRecord> > > ListRecentSearches(CancellationToken token = default) { var pageUri = new Uri($"https://{_baseUri.DnsSafeHost}/last-queries"); try { var content = await _client.TryGetStringAsync(pageUri, token).ConfigureAwait(false); using var document = await _parser.ParseDocumentAsync(content, token).ConfigureAwait(false); var searches = new List <SearchQueryRecord>(); foreach (var searchElement in document.QuerySelectorAll <IHtmlAnchorElement>("div.page-content div.item-meta a.btn")) { var name = searchElement.Text.Trim(); var searchUri = new Uri($"https://{_baseUri.DnsSafeHost}{searchElement.PathName}"); var search = new SearchQueryRecord(name, searchUri); searches.Add(search); } return(MuzlanResponse <IList <SearchQueryRecord> > .FromResult(searches, pageUri)); } catch (Exception ex) { return(MuzlanResponse <IList <SearchQueryRecord> > .FromException(ex, pageUri)); } }
public async ValueTask <MuzlanResponse <IList <ArtistRecord> > > ListPopularArtists(CancellationToken token = default) { var pageUri = _baseUri; try { var content = await _client.TryGetStringAsync(pageUri, token).ConfigureAwait(false); using var document = await _parser.ParseDocumentAsync(content, token).ConfigureAwait(false); var artists = new List <ArtistRecord>(); foreach (var artistElement in document.QuerySelectorAll <IHtmlDivElement>("div.page-content div.row-col div div.padding div.row div div.item")) { var anchor = artistElement.QuerySelector <IHtmlAnchorElement>("div.item-info div.item-title.text-ellipsis a"); var image = artistElement.QuerySelector <IHtmlImageElement>("div.item-media a.item-media-content img.lazy.img-responsive"); var name = anchor.Text.Trim(); var artistUri = new Uri($"https://{_baseUri.DnsSafeHost}/artist/{Uri.EscapeDataString(name)}"); var searchUri = new Uri($"https://{_baseUri.DnsSafeHost}{anchor.PathName}"); var imageUri = new Uri($"https://{_baseUri.DnsSafeHost}{image.Dataset["original"]}"); var artist = new ArtistRecord(name, artistUri, searchUri, imageUri); artists.Add(artist); } return(MuzlanResponse <IList <ArtistRecord> > .FromResult(artists, pageUri)); } catch (Exception ex) { return(MuzlanResponse <IList <ArtistRecord> > .FromException(ex, pageUri)); } }
public async ValueTask <MuzlanResponse <IList <SearchArtistRecord> > > FindArtists( string query, CancellationToken token = default) { var pageUri = new Uri($"https://{_baseUri.DnsSafeHost}/search/{Uri.EscapeDataString(query)}"); try { var content = await _client.TryGetStringAsync( pageUri, token).ConfigureAwait(false); using var document = await _parser.ParseDocumentAsync(content, token).ConfigureAwait(false); var artists = new List <SearchArtistRecord>(); foreach (var artistElement in document.QuerySelectorAll <IHtmlDivElement>("div.page-content div.row-col div.row.item-list:not(#search-result-items)")) { var imageElement = artistElement.QuerySelector <IHtmlAnchorElement>("div.item-media a.item-media-content"); var titleElement = artistElement.QuerySelector <IHtmlAnchorElement>("div.item-info div.item-title.text-ellipsis a"); var descriptionElement = artistElement.QuerySelector <IHtmlDivElement>("div.item-info div.item-except"); var artistName = titleElement.Text.Trim(); var artistUri = new Uri($"https://{_baseUri.DnsSafeHost}/artist/{Uri.EscapeDataString(query)}"); var artistSearchUri = new Uri($"https://{_baseUri.DnsSafeHost}/search/{Uri.EscapeDataString(query)}"); var match = _bgImageRegex.Match(imageElement.OuterHtml); var artistImageUri = new Uri($"https://{_baseUri.DnsSafeHost}{match.Groups[1].Value}"); var description = string.IsNullOrEmpty(descriptionElement.TextContent) ? string.Empty : descriptionElement.TextContent.Trim(); var tags = new List <TagRecord>(); foreach (var tagElement in artistElement.QuerySelectorAll <IHtmlAnchorElement>("div.item-info div.item-meta a.btn")) { var tagName = tagElement.Text.Trim(); var tagUri = new Uri($"https://{_baseUri.DnsSafeHost}{tagElement.PathName}"); tags.Add(new TagRecord(tagName, tagUri)); } var artist = new ArtistRecord(artistName, artistUri, artistSearchUri, artistImageUri); artists.Add(new SearchArtistRecord(artist, tags, description)); } return(MuzlanResponse <IList <SearchArtistRecord> > .FromResult(artists, pageUri)); } catch (Exception ex) { return(MuzlanResponse <IList <SearchArtistRecord> > .FromException(ex, pageUri)); } }
public async ValueTask <MuzlanResponse <IList <TrackRecord> > > FindTracks( Uri pageUri, int?limitItems = null, int?limitPages = null, CancellationToken cancellationToken = default) { var pagination = new MuzlanPagination(pageUri, _client, _parser); var tracks = new List <TrackRecord>(); try { bool reachedLimit = false; int itemCount = 0; await foreach (var pageContent in pagination.FollowForward(cancellationToken).ConfigureAwait(false)) { reachedLimit = limitPages > 0 && pagination.PageCount >= limitPages; await foreach (var track in EnumerateTracks(pageContent, cancellationToken).ConfigureAwait(false)) { tracks.Add(track); itemCount++; reachedLimit = limitItems > 0 && itemCount >= limitItems; } if (reachedLimit) { break; } } return(MuzlanResponse <IList <TrackRecord> > .FromResult(tracks, pagination.PageUri)); } catch (Exception ex) { if (pagination.PageNumber == -1) { return(MuzlanResponse <IList <TrackRecord> > .FromException(ex, pagination.PageUri, pagination.PageNumber)); } return(MuzlanResponse <IList <TrackRecord> > .FromPartialResult(tracks, pagination.PageUri, pagination.PageNumber)); } }
public async ValueTask <MuzlanResponse <AuthRecord> > Authenticate(CancellationToken token = default) { ServerOnline = null; CsrfToken = null; MediaToken = null; var pageUri = _firstServerUri; try { var online = await CheckServerResponse(pageUri, token).ConfigureAwait(false); if (!online) { pageUri = _secondServerUri; online = await CheckServerResponse(pageUri, token).ConfigureAwait(false); if (!online) { ServerOnline = false; throw new HttpRequestException("Authentication servers seem to be unavailable.", null, HttpStatusCode.NoContent); } } ServerOnline = true; pageUri = _baseUri; CsrfToken = await GetCsrfToken(pageUri, token).ConfigureAwait(false); pageUri = _mediaTokenUri; MediaToken = await GetMediaToken(pageUri, CsrfToken, token).ConfigureAwait(false); return(MuzlanResponse <AuthRecord> .FromResult(new AuthRecord(CsrfToken, MediaToken), pageUri)); } catch (Exception ex) { return(MuzlanResponse <AuthRecord> .FromException(ex, pageUri)); } }
public async ValueTask <MuzlanResponse <IList <TrackRecord> > > GetTracks(string artist, string album, CancellationToken token = default) { var pageUri = new Uri($"https://{_baseUri.DnsSafeHost}/artist/{Uri.EscapeDataString(artist)}/album/{Uri.EscapeDataString(album)}"); try { var content = await _client.TryGetStringAsync(pageUri, token).ConfigureAwait(false); using var document = await _parser.ParseDocumentAsync(content, token).ConfigureAwait(false); var tracks = new List <TrackRecord>(); foreach (var item in document.QuerySelectorAll <IHtmlDivElement>("div.page-content div.row-col div.row.item-list div.item.track")) { var trackItem = item.QuerySelector <IHtmlAnchorElement>("div.item-info div.item-title a"); var authorItem = item.QuerySelector <IHtmlAnchorElement>("div.item-info div.item-author a"); var trackName = trackItem.Text.Trim(); var trackUri = new Uri($"https://{_baseUri.DnsSafeHost}{trackItem.PathName}"); var trackDownload = new Uri($"https://{_baseUri.DnsSafeHost}{item.Dataset["src"]}"); var artistName = authorItem.Text.Trim(); var track = new TrackRecord(trackName, artistName, trackUri, trackDownload); tracks.Add(track); } return(MuzlanResponse <IList <TrackRecord> > .FromResult(tracks, pageUri)); } catch (Exception ex) { return(MuzlanResponse <IList <TrackRecord> > .FromException(ex, pageUri)); } }
public async ValueTask <MuzlanResponse <DownloadRecord> > DownloadTrack(TrackRecord track, AuthRecord auth, CancellationToken cancellationToken = default) { var sourceUri = new Uri(track.DownloadUri, $"?key={auth.MediaToken}"); var fileExtension = NormalizeFileExtension(Path.GetExtension(sourceUri.LocalPath)); var fileName = track.Name; try { using var response = await _client.GetAsync(sourceUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); var contentLength = response.Content.Headers.GetValues("Content-Length").First(); var fileSize = int.Parse(contentLength); var fileOffset = 0; var bytesRead = 0; var fileData = new byte[fileSize]; await OnDownloadProgressChanged(fileOffset, fileSize).ConfigureAwait(false); using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); bool hasCompletedEvent = false; do { if (fileOffset >= fileSize) { break; } bytesRead = await stream.ReadAsync( ConvertToMemory(fileData, fileOffset, 8192), cancellationToken).ConfigureAwait(false); fileOffset += bytesRead; if (fileOffset == fileSize) { hasCompletedEvent = true; } await OnDownloadProgressChanged(fileOffset, fileSize).ConfigureAwait(false); } while (bytesRead > 0); if (!hasCompletedEvent) { await OnDownloadProgressChanged(fileSize, fileSize).ConfigureAwait(false); } var file = new DownloadRecord(fileName + fileExtension, fileData, sourceUri); return(MuzlanResponse <DownloadRecord> .FromResult(file, sourceUri)); } catch (Exception ex) { return(MuzlanResponse <DownloadRecord> .FromException(ex, sourceUri)); } }