using System.Globalization; using System.Text.RegularExpressions; using ExcelTableImporter.Models.ExcelModels; using ExcelTableImporter.Models.ExcelModels.ExcelModels; using NPOI.SS.UserModel; namespace ExcelTableImporter; public class LibrayLoader { public async Task LoadLibrary(string filePath) { var animeRows = await ReadExcelFile(filePath); return MakeLibrary(animeRows); } private async Task> ReadExcelFile(string filePath) { await using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); IWorkbook workbook = WorkbookFactory.Create(stream); var sheet = workbook.GetSheetAt(0); var animeRows = new List(); for (var i = 1; i <= sheet.LastRowNum; i++) { var row = sheet.GetRow(i); var isEmpty = row.GetCell(0) is null && row.GetCell(1) is null && row.GetCell(2) is null && row.GetCell(3) is null && row.GetCell(4) is null && row.GetCell(8) is null && row.GetCell(9) is null; if (isEmpty) continue; var c1 = row.GetCell(0)?.ToString(); // russian name var c2 = row.GetCell(1)?.ToString(); // original name var c3 = TryShort(row.GetCell(2)); // release year var c4 = ReadSerialsCount(row.GetCell(3)); // formula cell var c5 = ReadSerialsCount(row.GetCell(4)); // series viewed var c6 = row.GetCell(6)?.ToString(); // is completed var c7 = TryShort(row.GetCell(8)); // rating var c8 = row.GetCell(9)?.ToString(); // comment // var str = $"{c1} | {c2} [{c3}] - {c4} - : — {c5} — [{c6}] [{c7}]; {c8}"; animeRows.Add(new AnimeRow { NameRussian = c1, NameOriginal = c2, ReleaseYear = c3, AnimeSeriesCountItems = ParseFormula(c4), AnimeSeriesViewsCountItems = ParseFormula(c5), IsCompleted = c6 == "Да", RatingValue = c7, Comment = c8, }); // Console.WriteLine(str); } return animeRows; } private AnimeLibrary MakeLibrary(List animeRows) { var animeTitles = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var row in animeRows) { if (!animeTitles.TryGetValue(row.NameOriginal, out var title)) { title = new AnimeTitle { NameRussian = row.NameRussian, NameOriginal = row.NameOriginal, ReleaseYear = row.ReleaseYear, RatingValue = row.RatingValue, Comment = row.Comment }; animeTitles[row.NameOriginal] = title; } var part = new AnimePart { ReleaseYear = row.ReleaseYear, Type = DetectPartType(row.NameRussian, row.NameOriginal), SeasonNumber = DetectSeasonNumber(row.NameRussian) }; foreach (var item in row.AnimeSeriesCountItems) { part.EpisodeGroups.Add(new AnimeEpisodeGroup { Order = item.Order, Count = item.Count, Viewed = row.AnimeSeriesViewsCountItems .FirstOrDefault(v => v.Order == item.Order)?.Count ?? 0 }); } title.Parts.Add(part); } return new AnimeLibrary { Titles = animeTitles.Values.ToList() }; } static short? TryShort(ICell? cell) { if (cell == null) return null; if (cell.CellType == CellType.Numeric) return Convert.ToInt16(cell.NumericCellValue); if (short.TryParse(cell.ToString(), out var v)) return v; return null; } static string? ReadSerialsCount(ICell? cell) { if (cell == null) return null; return cell.CellType switch { CellType.Numeric => cell.NumericCellValue.ToString(CultureInfo.InvariantCulture), CellType.Formula => cell.CellFormula, _ => null }; } static List ParseFormula(string? formula) { var result = new List(); if (string.IsNullOrWhiteSpace(formula)) return result; formula = formula.TrimStart('='); var parts = formula.Split('+', StringSplitOptions.RemoveEmptyEntries); var order = 1; foreach (var p in parts) { if (int.TryParse(p, out var count)) { result.Add(new AnimeSeriesCountItem { Order = order++, Count = count }); } } return result; } static AnimePartType DetectPartType(string nameRu, string nameOrig) { var name = (nameRu + " " + nameOrig).ToLowerInvariant(); if (name.Contains("фильм") || name.Contains("movie") || name.Contains("gekijouban")) return AnimePartType.Movie; if (name.Contains("ova")) return AnimePartType.Ova; if (name.Contains("special") || name.Contains("спешл")) return AnimePartType.Special; return AnimePartType.Season; } static int? DetectSeasonNumber(string nameRu) { var match = Regex.Match(nameRu, @"сезон\s*(\d+)", RegexOptions.IgnoreCase); if (match.Success && int.TryParse(match.Groups[1].Value, out var num)) return num; return null; } }