public async Task Export(WeissSchwarzDeck deck, IExportInfo info) { Log.Information("Serializing: {name}", deck.Name); using (var db = _database()) { Log.Information("Replacing all foils with non-foils..."); foreach (var card in deck.Ratios.Keys) { if (card.IsFoil) { deck.ReplaceCard(card, await db.FindNonFoil(card)); } } } Log.Information("Creating deck.cod..."); var cckDeck = new CockatriceDeck(); cckDeck.DeckName = deck.Name; cckDeck.Comments = deck.Remarks; cckDeck.Ratios = new CockatriceDeckRatio(); cckDeck.Ratios.Ratios = deck.Ratios.Select(Translate).ToList(); var resultDeck = Path.CreateDirectory(info.Destination).Combine($"{deck.Name?.AsFileNameFriendly() ?? "deck"}.cod"); resultDeck.Open(s => _serializer.Serialize(s, cckDeck), System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite ); Log.Information($"Saved: {resultDeck.FullPath}"); }
public async Task <WeissSchwarzDeck> Inspect(WeissSchwarzDeck deck, InspectionOptions options) { Log.Debug("Starting..."); var keyCards = deck.Ratios.Keys.Where(c => ((!c.Images?.Any()) ?? false) && String.IsNullOrWhiteSpace(c.CachedImagePath)); var inspectedDeck = deck.Clone(); foreach (var card in keyCards) { Log.Information("{serial} has no image URL nor a cached image. This deck cannot be exported without an image. Do you want to supply an image instead? [Y/N] (Default is N)", card.Serial); if (ConsoleUtils.Prompted(options.IsNonInteractive, false)) { if (inspectedDeck.ReplaceCard(card, await AddImageFromConsole(card, options))) { Log.Information("Checking for other missing images (if any)..."); } else { return(WeissSchwarzDeck.Empty); } } else { Log.Information("Selected No; inspection failed."); return(WeissSchwarzDeck.Empty); } } Log.Debug("Finished inspection."); return(inspectedDeck); }
public async Task <WeissSchwarzDeck> Inspect(WeissSchwarzDeck deck, InspectionOptions options) { Log.Information("Starting..."); var imageFolder = Path.Get(_imageCachePath); try { foreach (var card in deck.Ratios.Keys) { try { var serialImage = imageFolder .Files($"{card.Serial.Replace('-', '_').AsFileNameFriendly()}.*", true) .WhereExtensionIs(".png", ".jpeg", ".jpg", "jfif") .First(); var relativeFileName = _imageCachePath + serialImage.FileName; serialImage = await InspectImage(serialImage, relativeFileName); if (serialImage != null) { Log.Information($"Using cached image: {serialImage}"); card.CachedImagePath = serialImage.FullPath; } } catch (InvalidOperationException) { // Do nothing. } } } catch (System.IO.DirectoryNotFoundException) { // Do nothing. } return(deck); }
public async Task <WeissSchwarzDeck> Inspect(WeissSchwarzDeck deck, InspectionOptions options) { var allEmptyTranslations = deck.Ratios.Keys.Where(card => String.IsNullOrWhiteSpace(card.Name.EN)) .Select(card => card.ReleaseID) .Distinct(); if (allEmptyTranslations.Any()) { Log.Warning("The following sets (based on Release ID) do not have proper English translations: {allEmptyTranslations}", allEmptyTranslations.ToList()); Log.Warning("This may result in a deck generator with only Japanese text."); Log.Warning("Do you wish to continue? [Y/N] (Default is N)"); if (ConsoleUtils.Prompted(options.IsNonInteractive, options.NoWarning)) { return(deck); } else { Log.Information("Operation cancelled."); Log.Information("If you need to add card data from other sources, use this command: {command}", "wstools parse link_url"); Log.Information("For more information, please see: {url}", new Uri("https://github.com/ronelm2000/wsmtools")); return(WeissSchwarzDeck.Empty); } } else { await Task.CompletedTask; //placebo way to stop warning about async/await return(deck); } }
public async Task <WeissSchwarzDeck> Parse(string sourceUrlOrFile) { var filePath = Path.Get(sourceUrlOrFile); SimpleDeck deckJSON = null; deckJSON = JsonSerializer.Deserialize <SimpleDeck>(filePath.ReadBytes()); WeissSchwarzDeck deck = new WeissSchwarzDeck(); deck.Name = deckJSON.Name; deck.Remarks = deckJSON.Remarks; using (var db = _database()) { await db.Database.MigrateAsync(); foreach (var serial in deckJSON.Ratios.Keys) { var card = await db.WeissSchwarzCards.FindAsync(serial); if (card == null) { Log.Error("This card is missing in your local card db: {serial}", serial); Log.Error("You must obtain information about this card first using the command {cmd}", "./wstools parse"); return(WeissSchwarzDeck.Empty); } else { deck.Ratios[card] = deckJSON.Ratios[serial]; } } } return(deck); }
public WeissSchwarzDeck Clone() { var res = new WeissSchwarzDeck(); res.Ratios = this.Ratios.ToDictionary(kyd => kyd.Key, kyd => kyd.Value); res.Name = this.Name; res.Remarks = this.Remarks; return(res); }
internal void ReportParsedDeckData(WeissSchwarzDeck newDeck) { report = report with { Percentage = 10, ReportMessage = new MultiLanguageString { EN = $"Found Deck [{newDeck.Name}] [{newDeck.Remarks}]" } }; progress.Report(report); }
public async Task <WeissSchwarzDeck> Inspect(WeissSchwarzDeck deck, InspectionOptions options) { var allEmptyTranslations = deck.Ratios.Keys.Where(card => String.IsNullOrWhiteSpace(card.Name.EN)) .Select(card => card.ReleaseID) .Distinct(); var setsWithTranslations = deck.Ratios.Keys.Where(card => !String.IsNullOrWhiteSpace(card.Name.EN)) .Select(card => card.ReleaseID) .Distinct() .ToList(); var allNonTranslatedCards = deck.Ratios.Keys.Where(card => String.IsNullOrWhiteSpace(card.Name.EN)) //.Select(card => card.Serial) .Distinct() .ToList(); if (allEmptyTranslations.Any()) { if (setsWithTranslations.Any(rid => allEmptyTranslations.Contains(rid))) { Log.Warning("The following cards have missing translations: {allNonTranslatedCards}", allNonTranslatedCards.Select(card => card.Serial).ToList()); Log.Warning("These are very likely untranslated PRs, please go back and manually export PRs using any of the ff. where applicable and retry:\n" + "\t./wstools export https://www.heartofthecards.com/translations/schwarz_promos.html\n" + "\t./wstools export https://www.heartofthecards.com/translations/weiss_promos.html"); Log.Warning("Note that to avoid too much bandwidth, images are not exported this way. You will need to put an image manually on the Images sub-folder. The process to improve this process is still in progress."); return(WeissSchwarzDeck.Empty); } else { Log.Warning("The following sets (based on Release ID) do not have proper English translations: {allEmptyTranslations}", allEmptyTranslations.ToList()); Log.Warning("Cards with missing EN Translations: {allNonTranslatedCards}", allNonTranslatedCards.Select(card => card.Serial).ToList()); Log.Warning("This may result in a deck generator with only Japanese text."); Log.Warning("Do you wish to continue? [Y/N] (Default is N)"); if (ConsoleUtils.Prompted(options.IsNonInteractive, options.NoWarning)) { return(deck); } else { Log.Information("Operation cancelled."); Log.Information("If you need to add card data from other sources, use this command: {command}", "wstools parse link_url"); Log.Information("For more information, please see: {url}", new Uri("https://github.com/ronelm2000/wsmtools")); return(WeissSchwarzDeck.Empty); } } } else { await Task.CompletedTask; //placebo way to stop warning about async/await return(deck); } }
private async Task <WeissSchwarzDeck> Parse(Uri uri) { var encoreDecksDeckAPIURL = "https://www.encoredecks.com/api/deck"; var localPath = uri.LocalPath; var deckID = localPath.Substring(localPath.LastIndexOf('/') + 1); Log.Information("Deck ID: {deckID}", deckID); dynamic deckJSON = await GetDeckJSON(encoreDecksDeckAPIURL, deckID); WeissSchwarzDeck res = new WeissSchwarzDeck(); res.Name = deckJSON.name; using (var db = _database()) { await db.Database.MigrateAsync(); foreach (dynamic card in deckJSON.cards) { string serial = WeissSchwarzCard.GetSerial(card.set.ToString(), card.side.ToString(), card.lang.ToString(), card.release.ToString(), card.sid.ToString()); WeissSchwarzCard wscard = await db.WeissSchwarzCards.FindAsync(serial); if (wscard == null) { string setID = card.series; await _parse($"https://www.encoredecks.com/api/series/{setID}/cards"); wscard = await db.WeissSchwarzCards.FindAsync(serial); } if (res.Ratios.TryGetValue(wscard, out int quantity)) { res.Ratios[wscard]++; } else { res.Ratios[wscard] = 1; } //Log.Information("Parsed: {@wscard}", wscard); } } var simpleRatios = res.AsSimpleDictionary(); Log.Information("Deck Parsed: {@simpleRatios}", simpleRatios); Log.Information("Cards in Deck: {@count}", simpleRatios.Values.Sum()); return(res); }
public async Task <WeissSchwarzDeck> Parse(string sourceUrlOrFile) { Log.Information("Parsing: {source}", sourceUrlOrFile); var file = Fluent.IO.Path.Get(sourceUrlOrFile); var serializer = new XmlSerializer(typeof(CockatriceDeck)); using (var stream = file.GetStream()) { var cockatriceDeck = serializer.Deserialize(stream) as CockatriceDeck; var result = new WeissSchwarzDeck(); result.Name = cockatriceDeck.DeckName; result.Remarks = cockatriceDeck.Comments; result.Ratios = cockatriceDeck.Ratios.Ratios.Select(Translate).ToDictionary(p => p.card, p => p.amount); return(await Task.FromResult(result)); } }
public async Task <WeissSchwarzDeck> Inspect(WeissSchwarzDeck deck, InspectionOptions options) { var englishEditionCards = deck.Ratios.Keys.Where(card => card.EnglishSetType == EnglishSetType.EnglishEdition); if (HeededWarningOnEnglishEditionSets(englishEditionCards, options)) { return(WeissSchwarzDeck.Empty); } var japaneseImportCards = deck.Ratios.Keys.Where(card => card.EnglishSetType == EnglishSetType.JapaneseImport); if (HeededWarningOnJapaneseImports(japaneseImportCards, options)) { return(WeissSchwarzDeck.Empty); } return(await Task.FromResult(deck)); }
private async Task <WeissSchwarzDeck> ParseFromCSV(string sourceCSV) { WeissSchwarzDeck res = new WeissSchwarzDeck(); using (var db = _database()) foreach (var row in ParseCSV(sourceCSV, b => b.SetDelimiters(","))) { if (row[0] == "Code") { continue; } var card = await db.WeissSchwarzCards.FindAsync(row[0]); var quantity = row[1].AsParsed <int>(int.TryParse).GetValueOrDefault(0); res.Ratios.Add(card, quantity); } res.Remarks = (res.Remarks ?? "") + $"\nParsed: {this.GetType().Name}"; res.Remarks = res.Remarks.Trim(); return(res); }
public async Task Export(WeissSchwarzDeck deck, IExportInfo info) { Log.Information("Exporting as Deck JSON."); var jsonFilename = Path.CreateDirectory(info.Destination).Combine($"deck_{deck.Name.AsFileNameFriendly()}.json"); var simplifiedDeck = new { Name = deck.Name, Remarks = deck.Remarks, Ratios = deck.AsSimpleDictionary() }; jsonFilename.Open( async s => await JsonSerializer.SerializeAsync(s, simplifiedDeck, options: _defaultOptions), System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.ReadWrite ); Log.Information($"Done: {jsonFilename.FullPath}"); if (!String.IsNullOrWhiteSpace(info.OutCommand)) { await ExecuteCommandAsync(info.OutCommand, jsonFilename); } }
public static DeckParserProgressReport ObtainedParseDeckData(this DeckParserProgressReport report, WeissSchwarzDeck deck) { return(report with { Percentage = 10, ReportMessage = new Card.API.Entities.Impls.MultiLanguageString { EN = $"Obtained data for [{deck.Name}]" } }); }
public static DeckParserProgressReport SuccessfullyParsedDeck(this DeckParserProgressReport report, WeissSchwarzDeck deck) { return(report with { Percentage = 100, ReportMessage = new Card.API.Entities.Impls.MultiLanguageString { EN = $"Successfully Parsed [{deck.Name}]" } }); }
public async Task <WeissSchwarzDeck> Parse(string sourceUrlOrFile) { var document = await sourceUrlOrFile.WithHTMLHeaders().GetHTMLAsync(); //var deckView = document.QuerySelector(".deckview"); //var cardControllers = deckView.QuerySelectorAll(".card-controller-inner"); var deckID = urlMatcher.Match(sourceUrlOrFile).Groups[2]; Log.Information("Parsing ID: {deckID}", deckID); var response = await $"{deckLogApiUrlPrefix}{deckID}" // .WithReferrer(sourceUrlOrFile) // .PostJsonAsync(null); var json = JsonConvert.DeserializeObject <dynamic>(await response.Content.ReadAsStringAsync()); //var json = JsonConverter.CreateDefault().Deserialize<dynamic>(new JsonReader(await response.Content.ReadAsStreamAsync())); var newDeck = new WeissSchwarzDeck(); var missingSerials = new List <string>(); newDeck.Name = json.title.ToString(); newDeck.Remarks = json.memo.ToString(); using (var db = _database()) { List <dynamic> items = new List <dynamic>(); items.AddRange(json.list); items.AddRange(json.sub_list); foreach (var cardJSON in items) { string serial = cardJSON.card_number.ToString(); serial = serial.Replace('+', '+'); if (serial == null) { Log.Warning("serial is null for some reason!"); } var card = await db.WeissSchwarzCards.FindAsync(serial); int quantity = cardJSON.num; if (card != null) { Log.Debug("Adding: {card} [{quantity}]", card?.Serial, quantity); if (newDeck.Ratios.TryGetValue(card, out int oldVal)) { newDeck.Ratios[card] = oldVal + quantity; } else { var url = awsWeissSchwarzSitePrefix + cardJSON.img; Log.Debug("Adding URL into Images: {url}", url); card.Images.Add(new Uri(url)); newDeck.Ratios.Add(card, quantity); } } else { missingSerials.Add(serial); //throw new DeckParsingException($"MISSING_SERIAL_{serial}"); Log.Warning("Serial has been effectively skipped because it's not found on the local db: [{serial}]", serial); } } } if (missingSerials.Count > 0) { throw new DeckParsingException($"The following serials are missing from the DB:\n{missingSerials.ConcatAsString("\n")}"); } else { Log.Debug($"Result Deck: {JsonConvert.SerializeObject(newDeck.AsSimpleDictionary())}"); return(newDeck); } }
internal void ReportSuccessfulParsedDeckData(WeissSchwarzDeck newDeck) { report = report.SuccessfullyParsedDeck(newDeck); progress.Report(report); }