177 lines
5.8 KiB
C#
177 lines
5.8 KiB
C#
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<AnimeLibrary> LoadLibrary(string filePath)
|
|
{
|
|
var animeRows = await ReadExcelFile(filePath);
|
|
return MakeLibrary(animeRows);
|
|
}
|
|
|
|
private async Task<List<AnimeRow>> 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<AnimeRow>();
|
|
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<AnimeRow> animeRows)
|
|
{
|
|
var animeTitles = new Dictionary<string, AnimeTitle>(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<AnimeSeriesCountItem> ParseFormula(string? formula)
|
|
{
|
|
var result = new List<AnimeSeriesCountItem>();
|
|
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;
|
|
}
|
|
} |