/// <summary> /// Downloads a score zip file to the destination directory /// </summary> /// <param name="listing">Search result listing</param> /// <param name="directory">Directory to unzip to</param> /// <returns>The created file or an error message</returns> public async Task <Result <string, string> > DownloadZip(LibrarySearchListing listing, string directory) { try { WebClient client = new WebClient(); var data = await client.DownloadDataTaskAsync(new Uri(listing.DownloadLink)); string filename; if (!string.IsNullOrEmpty(client.ResponseHeaders["Content-Disposition"])) { filename = client.ResponseHeaders["Content-Disposition"] .Substring(client.ResponseHeaders["Content-Disposition"] .IndexOf("filename=", StringComparison.Ordinal) + 9) .Replace("\"", ""); } else { filename = $"PPDownload-{DateTime.Now:s}.zip"; } var filePath = Path.Join(directory, filename); File.WriteAllBytes(filePath, data); return(Result.Success <string, string>(filePath)); } catch (Exception e) { return(Result.Failure <string, string>(e.Message)); } }
public async Task InstallScore(LibrarySearchListing listing) { var installResult = await _downloader.DownloadUnzipWithVideoDefault(listing); if (installResult.IsFailure) { return; //todo:return information } var directory = installResult.Value; await _tracker.AddInstalledScore(listing, directory); }
internal async Task AddInstalledScore(LibrarySearchListing listing, string installPath) { var score = new InstalledScore() { ScoreID = listing.ScoreID, ScoreName = listing.Title, TargetVideoURL = listing.VideoLink, DirectoryPath = installPath }; ScoreList.Add(score); await SaveInstalledScoreList(); }
public async void News39SearchTest() { LibraryScraper lib = new LibraryScraper(); var searchScores = await lib.SearchScores("news"); LibrarySearchListing news39 = searchScores.First(); LibrarySearchListing expected = new LibrarySearchListing() { Author = "Sakura-san (桜-さん)", BPM = 132, Description = "I've been working on this song for two weeks, so I really hope you will enjoy it :)", DownloadLink = "https://projectdxxx.me/score-library/download/id/13c2aaad8377b9890b7b4fb03fbaa4d0", Downloads = 384, Easy = null, Evaluation = 4.14m, Evaluators = 37, Extreme = 21.08m, Hard = null, Length = "3:41", Normal = null, Title = "News 39 ver桜-さん", Uploaded = new DateTime(2018, 7, 17, 1, 5, 42), VideoLink = "https://www.youtube.com/watch?v=l69v6SVoE9k", ScoreID = "13c2aaad8377b9890b7b4fb03fbaa4d0" }; Assert.Equal(expected.Author, news39.Author); Assert.Equal(expected.BPM, news39.BPM); Assert.Equal(expected.Description, news39.Description); Assert.Equal(expected.DownloadLink, news39.DownloadLink); Assert.True(news39.Downloads > 380); Assert.Equal(expected.Easy, news39.Easy); Assert.Equal(expected.Evaluation, news39.Evaluation); Assert.Equal(expected.Evaluators, news39.Evaluators); Assert.Equal(expected.Extreme, news39.Extreme); Assert.Equal(expected.Hard, news39.Hard); Assert.Equal(expected.Length, news39.Length); Assert.Equal(expected.Normal, news39.Normal); Assert.Equal(expected.Title, news39.Title); Assert.Equal(expected.Uploaded, news39.Uploaded); Assert.Equal(expected.VideoLink, news39.VideoLink); Assert.Equal(expected.ScoreID, news39.ScoreID); }
/// <summary> /// Downloads a score zip to memory, unzips it to the destination folder, and downloads the target video for the score /// </summary> /// <param name="listing">Search result listing</param> /// <param name="directory">Directory to unzip to</param> /// <returns>The created directory or an error message</returns> public async Task <Result <string, string> > DownloadUnzipWithVideo(LibrarySearchListing listing, string directory) { try { var unzipResult = await DownloadAndUnzip(listing, directory); if (unzipResult.IsFailure) { return(unzipResult); } var directoryPath = unzipResult.Value; var youtube = YouTube.Default; var video = youtube.GetVideo(listing.VideoLink); var videoPath = Path.Join(directoryPath, video.FullName); File.WriteAllBytes(videoPath, video.GetBytes()); return(Result.Success <string, string>(directoryPath)); } catch (Exception e) { return(Result.Failure <string, string>(e.Message)); } }
/// <summary> /// Downloads the score zip to memory, then unzips into the destination directory /// </summary> /// <param name="listing">Search result listing</param> /// <param name="directory">Directory to unzip to</param> /// <returns>The created directory or the error message</returns> public async Task <Result <string, string> > DownloadAndUnzip(LibrarySearchListing listing, string directory) { try { WebClient client = new WebClient(); var data = await client.DownloadDataTaskAsync(new Uri(listing.DownloadLink)); using var stream = new MemoryStream(data); using var archive = new ZipArchive(stream, ZipArchiveMode.Read); var newDirectoryName = archive.Entries.FirstOrDefault()?.FullName.Split('/')[0]; if (string.IsNullOrEmpty(newDirectoryName)) { return(Result.Failure <string, string>("Could not resolve new directory name, aborting.")); } archive.ExtractToDirectory(directory, true); return(Result.Success <string, string>(Path.Join(directory, newDirectoryName))); } catch (Exception e) { return(Result.Failure <string, string>(e.Message)); } }
private Result <LibrarySearchListing, string> ParseSearchListing(IElement root) { var title = root.QuerySelector("div.panel-heading > h3 > div > a")?.InnerHtml.CleanInnerHtml() ?? ""; if (string.IsNullOrEmpty(title)) { return(Result.Failure <LibrarySearchListing, string>("Could not retrieve title.")); } var id = root.QuerySelector("div.panel-heading > h3 > div > a")?.Attributes["href"].Value.Split('/') .LastOrDefault() ?? ""; if (string.IsNullOrEmpty(id)) { return(Result.Failure <LibrarySearchListing, string>("Could not retrieve ID.")); } var author = root.QuerySelector("div.panel-heading > div.pull-right > a")?.Text()?.CleanInnerHtml(); if (string.IsNullOrEmpty(author)) { return(Result.Failure <LibrarySearchListing, string>("Could not retrieve author.")); } var description = root.QuerySelector("div.panel-body > div.clearfix")?.InnerHtml.CleanInnerHtml() ?? ""; if (string.IsNullOrEmpty(description)) { return(Result.Failure <LibrarySearchListing, string>("Could not retrieve description.")); } var uploadedStr = root.QuerySelector("div.panel-body > div.pull-right > span")?.InnerHtml.Replace("投稿", "") .Replace("Uploaded", "").CleanInnerHtml() ?? ""; if (string.IsNullOrEmpty(uploadedStr)) { return(Result.Failure <LibrarySearchListing, string>("Could not retrieve upload date.")); } var vidLink = root.QuerySelector("div.panel-body > div.pull-right > input")?.Attributes?["value"]?.Value ?? ""; if (string.IsNullOrEmpty(vidLink)) { return(Result.Failure <LibrarySearchListing, string>("Could not retrieve youtube link.")); } var downloadLink = root.QuerySelector("div.panel-body > div.pull-right > a:nth-child(3)") ?.Attributes?["href"]?.Value ?? ""; if (string.IsNullOrEmpty(downloadLink)) { return(Result.Failure <LibrarySearchListing, string>("Could not retrieve download link.")); } downloadLink = "https://projectdxxx.me" + downloadLink; var difficultyTable = root.QuerySelector("table > tbody > tr:nth-of-type(2)"); var easyStr = difficultyTable?.QuerySelector("td:nth-of-type(1)")?.InnerHtml.CleanInnerHtml() .Replace("pt", "") ?? ""; var normalStr = difficultyTable?.QuerySelector("td:nth-of-type(2)")?.InnerHtml.CleanInnerHtml() .Replace("pt", "") ?? ""; var hardStr = difficultyTable?.QuerySelector("td:nth-of-type(3)")?.InnerHtml.CleanInnerHtml() .Replace("pt", "") ?? ""; var extremeStr = difficultyTable?.QuerySelector("td:nth-of-type(4)")?.InnerHtml.CleanInnerHtml() .Replace("pt", "") ?? ""; var downloadsStr = difficultyTable?.QuerySelector("td:nth-of-type(5)")?.InnerHtml.CleanInnerHtml() ?? ""; var bpmStr = difficultyTable?.QuerySelector("td:nth-of-type(6)")?.InnerHtml.CleanInnerHtml() ?? ""; var evalStr = difficultyTable?.QuerySelector("td:nth-of-type(7)")?.InnerHtml.CleanInnerHtml() ?? ""; var length = difficultyTable?.QuerySelector("td:nth-of-type(8)")?.InnerHtml.CleanInnerHtml() ?? ""; var evalScoreStr = Regex.Match(evalStr, @"([0-9].[0-9]+)\(\<span").Groups[1].Captures.FirstOrDefault() ?.Value; var evalCountStr = Regex.Match(evalStr, @"span\>([0-9]+)\)").Groups[1].Captures.FirstOrDefault()?.Value; var easy = easyStr.ParseDecimalNullable(); var normal = normalStr.ParseDecimalNullable(); var hard = hardStr.ParseDecimalNullable(); var extreme = extremeStr.ParseDecimalNullable(); var downloads = downloadsStr.ParseIntNullable(); var bpm = bpmStr.ParseIntNullable(); var evalScore = evalScoreStr.ParseDecimalNullable(); var evalCount = evalCountStr.ParseIntNullable(); var uploadDate = DateTime.Parse(uploadedStr); var result = new LibrarySearchListing() { Author = author, BPM = bpm, Description = description, DownloadLink = downloadLink, Downloads = downloads, Easy = easy, Normal = normal, Hard = hard, Extreme = extreme, Evaluation = evalScore, Evaluators = evalCount, Length = length, Title = title, Uploaded = uploadDate, VideoLink = vidLink, ScoreID = id }; return(Result.Success <LibrarySearchListing, string>(result)); }
internal async Task UninstallScore(LibrarySearchListing listing) { ScoreList.RemoveAll(x => x.ScoreID == listing.ScoreID); await SaveInstalledScoreList(); }
internal bool IsInstalled(LibrarySearchListing listing) => ScoreList.Any(x => x.ScoreID == listing.ScoreID);
public LibrarySearchResultViewModel(LibrarySearchListing listing, PpdManager manager) { _listing = listing; _manager = manager; DownloadSong = ReactiveCommand.Create(() => { _manager.InstallScore(_listing); }); }
public async Task DownloadSong(LibrarySearchListing listing) { await _downloader.DownloadUnzipWithVideoDefault(listing); }
public async Task UninstallScore(LibrarySearchListing listing) => await _tracker.UninstallScore(listing);