Глобальное обновление #1
@@ -1,79 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pf2eDataScrapper.App;
|
||||
|
||||
/// <summary>
|
||||
/// Общий аттрибут обработчика.
|
||||
/// </summary>
|
||||
/// <param name="name">Название обработчика.</param>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ProcessorAttribute(string name) : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Название обработчика.
|
||||
/// </summary>
|
||||
public string Name { get; init; } = name;
|
||||
|
||||
/// <summary>
|
||||
/// Описание обработчика.
|
||||
/// </summary>
|
||||
public string Description { get; init; } = name;
|
||||
|
||||
/// <summary>
|
||||
/// Группа обработчиков, к которому относится обработчик.
|
||||
/// </summary>
|
||||
public ProcessorGroupEnum Group { get; init; } = ProcessorGroupEnum.General;
|
||||
|
||||
/// <summary>
|
||||
/// Процессор включён по умолчанию.
|
||||
/// </summary>
|
||||
public bool Active { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Разрешить выполнять процессов в параллельном режиме
|
||||
/// </summary>
|
||||
public bool Parallel { get; init; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Обработчик набора элементов
|
||||
/// </summary>
|
||||
public virtual bool Collection { get; } = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Аттрибут обработчика набор элементов.
|
||||
/// </summary>
|
||||
/// <param name="name">Название обработчика.</param>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ProcessorCollectionAttribute(string name) : ProcessorAttribute(name)
|
||||
{
|
||||
/// <summary>
|
||||
/// Название типов, который обрабатывает этот оброботчик.
|
||||
/// <c>null</c> - обработать все типы.
|
||||
/// </summary>
|
||||
public required string? InnerType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Тип используемого компендиума.
|
||||
/// </summary>
|
||||
public required ProcessorCompendiumEnum CompendiumType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Обработчик набора элементов.
|
||||
/// </summary>
|
||||
public override bool Collection { get; } = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Аттрибут зависимостей обработчика.
|
||||
/// </summary>
|
||||
/// <param name="dependencies">Коллекция названий обработчиков, которые должны быть выполнены до этого оброботчика.</param>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ProcessorDependenciesAttribute(string[] dependencies) : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Коллекция названий обработчиков, которые должны быть выполнены до этого оброботчика.
|
||||
/// </summary>
|
||||
public ICollection<string> Dependencies { get; } = dependencies;
|
||||
}
|
||||
@@ -1,261 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
|
||||
namespace Pf2eDataScrapper.App;
|
||||
|
||||
/// <summary>
|
||||
/// Класс с коллекцией обработчиков.
|
||||
/// </summary>
|
||||
internal class ProcessorCollection
|
||||
{
|
||||
/// <summary>
|
||||
/// Коллекция всех доступных обработчиков.
|
||||
/// </summary>
|
||||
public ICollection<ProcessorCollectionItem> AllItems { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Коллекция обработчиков, которые будут обрабатываться.
|
||||
/// Для изменения необходимо использовать <see cref="FilterProcessors"/>.
|
||||
/// </summary>
|
||||
public List<ProcessorCollectionItem> Items { get; private set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Обеспечение доступа к элементам обработчиков.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public ProcessorCollectionItem this[string name] => AllItems.First(item => item.Name == name);
|
||||
|
||||
/// <summary>
|
||||
/// Конструктор класса <see cref="ProcessorCollection"/>.
|
||||
/// </summary>
|
||||
public ProcessorCollection()
|
||||
{
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
foreach (Type type in assembly.GetTypes())
|
||||
{
|
||||
if (type.GetCustomAttributes(typeof(ProcessorAttribute), true).Length <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AllItems.Add(CreateItem(type));
|
||||
}
|
||||
|
||||
CheckDependencies();
|
||||
FilterProcessors([]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создание элемента коллекции обработчиков.
|
||||
/// </summary>
|
||||
/// <param name="type">Тип обработчика.</param>
|
||||
/// <returns></returns>
|
||||
private ProcessorCollectionItem CreateItem(Type type)
|
||||
{
|
||||
if (!type.IsAssignableTo(typeof(IProcessor)))
|
||||
{
|
||||
throw new(
|
||||
$"'ProcessorAttribute' attribute should only be applied to children of 'IProcessor' class. '{type.FullName}' is not."
|
||||
);
|
||||
}
|
||||
|
||||
ProcessorAttribute processorAttribute = type.GetCustomAttribute<ProcessorAttribute>()!;
|
||||
ProcessorDependenciesAttribute? dependenciesAttribute =
|
||||
type.GetCustomAttribute<ProcessorDependenciesAttribute>();
|
||||
|
||||
bool isCollection = processorAttribute.Collection;
|
||||
|
||||
string? innerType = null;
|
||||
ProcessorCompendiumEnum? compendium = null;
|
||||
|
||||
if (processorAttribute.GetType() == typeof(ProcessorCollectionAttribute))
|
||||
{
|
||||
ProcessorCollectionAttribute processorCollectionAttribute =
|
||||
(ProcessorCollectionAttribute)processorAttribute;
|
||||
|
||||
innerType = processorCollectionAttribute.InnerType;
|
||||
compendium = processorCollectionAttribute.CompendiumType;
|
||||
}
|
||||
|
||||
return new()
|
||||
{
|
||||
Name = processorAttribute.Name,
|
||||
Type = type,
|
||||
Description = processorAttribute.Description,
|
||||
Group = processorAttribute.Group,
|
||||
Dependencies = dependenciesAttribute?.Dependencies ?? [],
|
||||
IsCollection = isCollection,
|
||||
InnerType = innerType,
|
||||
Compendium = compendium,
|
||||
Active = processorAttribute.Active,
|
||||
Parallel = processorAttribute.Parallel,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверка, что все зависимости всех обработчиков могут быть удовлетворены.
|
||||
/// </summary>
|
||||
private void CheckDependencies()
|
||||
{
|
||||
foreach (ProcessorCollectionItem item in Items)
|
||||
{
|
||||
foreach (string dependency in item.Dependencies)
|
||||
{
|
||||
if (Items.All(i => i.Name != dependency))
|
||||
{
|
||||
throw new($"Dependency '{dependency}' for processor '{item.Name}' not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сортировать обработчики в соответсвии со всеми зависимостями.
|
||||
/// </summary>
|
||||
public void SortItems()
|
||||
{
|
||||
Items.ForEach(item => item.Priority = -1);
|
||||
|
||||
Dictionary<string, int> priorities = [];
|
||||
|
||||
while (priorities.Count < Items.Count)
|
||||
{
|
||||
foreach (ProcessorCollectionItem item in Items)
|
||||
{
|
||||
if (item.Priority >= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IEnumerable<int> dependencyPriorities = item.Dependencies.Select(d =>
|
||||
priorities.GetValueOrDefault(d, -1)
|
||||
);
|
||||
|
||||
if (dependencyPriorities.Any(p => p == -1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.Priority = Math.Max(
|
||||
dependencyPriorities.Any() ? dependencyPriorities.Max() + 1 : 1,
|
||||
(int)item.Group * 100
|
||||
);
|
||||
priorities.Add(item.Name, item.Priority);
|
||||
}
|
||||
}
|
||||
|
||||
Items.Sort((a, b) => a.Priority - b.Priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ограничить список используемых обработчиков по названию.
|
||||
/// Автоматически включает все обработчики, от которых зависят указанные в аргументе обработчики.
|
||||
/// </summary>
|
||||
/// <param name="processorNames">Коллекция названиий требуемых обработчиков.</param>
|
||||
public void FilterProcessors(ICollection<string> processorNames)
|
||||
{
|
||||
if (processorNames.Count == 0)
|
||||
{
|
||||
Items = [.. AllItems];
|
||||
SortItems();
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<string, bool> nameFlags = processorNames.ToDictionary(name => name, _ => false);
|
||||
|
||||
while (nameFlags.Values.Any(v => !v))
|
||||
{
|
||||
foreach (
|
||||
KeyValuePair<string, bool> pair in nameFlags.Where(pair => !pair.Value).ToList()
|
||||
)
|
||||
{
|
||||
ProcessorCollectionItem item = AllItems.First(item => item.Name == pair.Key);
|
||||
|
||||
foreach (string dependency in item.Dependencies)
|
||||
{
|
||||
nameFlags.TryAdd(dependency, false);
|
||||
}
|
||||
|
||||
nameFlags[pair.Key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
Items = AllItems.Where(item => nameFlags.ContainsKey(item.Name)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить список типов, которые обрабатываются в компендиуме.
|
||||
/// </summary>
|
||||
/// <param name="compendium">Тип компендиума.</param>
|
||||
/// <returns>Набор типов.</returns>
|
||||
public ICollection<string> GetTypesOfCompendium(ProcessorCompendiumEnum compendium) =>
|
||||
Items.Select(item => item.InnerType).OfType<string>().ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Элемент коллекции обработчиков.
|
||||
/// </summary>
|
||||
internal class ProcessorCollectionItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Название обработчика.
|
||||
/// </summary>
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Тип класса обработчика.
|
||||
/// </summary>
|
||||
public required Type Type { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Описание обработчика.
|
||||
/// </summary>
|
||||
public string Description { get; init; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Группа обработчика.
|
||||
/// </summary>
|
||||
public required ProcessorGroupEnum Group { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Коллекция названий обработчиков, после которых должен выполняться обработчик.
|
||||
/// </summary>
|
||||
public ICollection<string> Dependencies { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Процессор включён по умолчанию.
|
||||
/// </summary>
|
||||
public bool Active { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Приоритет выполнения обработчика.
|
||||
/// </summary>
|
||||
public int Priority { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Флаг, указывающий, обрабатывает ли обработчик коллекцию элементов.
|
||||
/// Внутренний тип элементов указывается в <see cref="InnerType"/>.
|
||||
/// </summary>
|
||||
public required bool IsCollection { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Флаг, указывающий внутренний тип коллекции обрабатываемых элементов.
|
||||
/// </summary>
|
||||
public string? InnerType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Название типов, который обрабатывает этот оброботчик.
|
||||
/// <c>null</c> - обработать все типы.
|
||||
/// </summary>
|
||||
public ProcessorCompendiumEnum? Compendium { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Разрешить выполнять процессов в параллельном режиме
|
||||
/// </summary>
|
||||
public bool Parallel { get; init; } = true;
|
||||
}
|
||||
@@ -91,6 +91,7 @@ public class EntityView
|
||||
.Include(c => c.ClassTrainings)
|
||||
.ThenInclude(t => t.Training)
|
||||
.Include(c => c.ClassProgressions)
|
||||
.Include(c => c.SubclassGroups)
|
||||
),
|
||||
new Getter<Feat>(
|
||||
EntityType.Feat,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2eDataScrapper.Helpers;
|
||||
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.WPF;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eDataScrapper.WPF.EntityViewer;
|
||||
using Pf2eDataScrapper.WPF.ProgressForm;
|
||||
using Pf2eDataScrapper.WPF.StartForm;
|
||||
@@ -102,7 +101,7 @@ internal sealed class ImportApplication : Application
|
||||
_entityForm = ActivatorUtilities.CreateInstance<EntityForm>(ServiceProvider);
|
||||
_entityForm.WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||
_entityForm.Closing += Wpf_HandleFormClosing;
|
||||
//_entityForm.ApplicationStateChange += ApplicationStateChange;
|
||||
_entityForm.ApplicationStateChange += ApplicationStateChange;
|
||||
_entityForm.Show();
|
||||
|
||||
CurrentWpfForm = _entityForm;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eModel.Model.Base.Targets;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
@@ -16,108 +19,64 @@ internal class AonprdBuilderGlobals
|
||||
/// <summary>
|
||||
/// Словарь идентификаторов источников.
|
||||
/// </summary>
|
||||
public Dictionary<string, int> SourceIds { get; set; } = [];
|
||||
public Dictionary<string, int> SourceIds { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Словарь идентификаторов признаков.
|
||||
/// </summary>
|
||||
public Dictionary<string, int> TraitIds { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Конструктор класса <see cref="AonprdBuilderGlobals"/>.
|
||||
/// </summary>
|
||||
public AonprdBuilderGlobals() { }
|
||||
|
||||
/// <summary>
|
||||
/// Получить суффикс для ссылки.
|
||||
/// </summary>
|
||||
/// <param name="id">Идентификатор Aounprd.</param>
|
||||
/// <returns>Суффикс для ссылки или пустая строка.</returns>
|
||||
public string GetSlugSuffix(string id)
|
||||
{
|
||||
return SlugSuffixes.TryGetValue(id, out var slug) ? $"-{slug}" : string.Empty;
|
||||
}
|
||||
public Dictionary<string, int> TraitIds { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Словарей суффиксов для сущностей
|
||||
/// </summary>
|
||||
public Dictionary<string, string> SlugSuffixes { get; } =
|
||||
new()
|
||||
{
|
||||
["feat-5997"] = "legacy",
|
||||
["feat-5730"] = "dragonblood",
|
||||
["feat-6469"] = "general",
|
||||
["feat-4344"] = "archetype",
|
||||
["feat-3549"] = "vampire",
|
||||
["feat-7380"] = "mythic",
|
||||
["feat-5737"] = "dragonblood",
|
||||
["feat-6284"] = "bounty-hunter",
|
||||
["feat-2664"] = "archetype",
|
||||
["feat-6883"] = "kitsune",
|
||||
["feat-6209"] = "investigator",
|
||||
["feat-6477"] = "undead-slayer",
|
||||
["feat-7637"] = "dandy",
|
||||
["feat-7004"] = "yaoguai",
|
||||
["feat-4380"] = "stonebound",
|
||||
};
|
||||
public Dictionary<string, string> SlugSuffixes { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Словарь допольнительных проверок связей.
|
||||
/// Ключ - устаревшая сущность, значение - обновлённая.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> LegacyRemasterExtra { get; } =
|
||||
new()
|
||||
{
|
||||
["archetype-83"] = "archetype-129",
|
||||
["archetype-86"] = "archetype-198",
|
||||
["feat-5997"] = "feat-7108",
|
||||
["feat-4088"] = "feat-5491",
|
||||
["feat-1177"] = "feat-4553",
|
||||
["feat-2986"] = "feat-4340",
|
||||
["feat-1753"] = "feat-6031",
|
||||
["feat-2729"] = "feat-4077",
|
||||
["feat-480"] = "feat-4850",
|
||||
["feat-2989"] = "feat-4343",
|
||||
["feat-2987"] = "feat-4341",
|
||||
["feat-2990"] = "feat-4346",
|
||||
["feat-936"] = "feat-2269",
|
||||
["feat-2992"] = "feat-4350",
|
||||
["feat-2991"] = "feat-4349",
|
||||
["feat-2742"] = "feat-4078",
|
||||
["feat-1169"] = "feat-5055",
|
||||
["feat-2743"] = "feat-4079",
|
||||
["feat-963"] = "feat-4519",
|
||||
["feat-1171"] = "feat-4858",
|
||||
["feat-1167"] = "feat-5880",
|
||||
["feat-455"] = "feat-6007",
|
||||
["feat-2993"] = "feat-4352",
|
||||
["language-91"] = "language-180",
|
||||
["ritual-31"] = "ritual-191",
|
||||
["spell-571"] = "spell-1975",
|
||||
["spell-1052"] = "spell-1309",
|
||||
["spell-1053"] = "spell-1306",
|
||||
["spell-843"] = "spell-2376",
|
||||
["spell-578"] = "spell-1566",
|
||||
["spell-551"] = "spell-2003",
|
||||
["spell-553"] = "spell-2012",
|
||||
["spell-646"] = "spell-1394",
|
||||
["spell-1054"] = "spell-1305",
|
||||
["spell-559"] = "spell-2417",
|
||||
["spell-1055"] = "spell-1311",
|
||||
["spell-1056"] = "spell-1310",
|
||||
["spell-841"] = "spell-1107",
|
||||
["spell-1057"] = "spell-1307",
|
||||
["spell-560"] = "spell-2418",
|
||||
["spell-1058"] = "spell-1304",
|
||||
["spell-641"] = "spell-1413",
|
||||
["spell-1059"] = "spell-1308",
|
||||
};
|
||||
public Dictionary<string, string> LegacyRemasterExtra { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Словарь сущностей, которые нужно слить с другой/другими.
|
||||
/// Ключ - пропускаемая сущность. Значение - целевая сущность.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> MergeSources { get; } = new() { ["spell-654"] = "spell-819" };
|
||||
public Dictionary<string, string> MergeSources { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Конструктор класса <see cref="AonprdBuilderGlobals"/>.
|
||||
/// </summary>
|
||||
public AonprdBuilderGlobals()
|
||||
{
|
||||
using StreamReader fileReader = new("Resources\\ImportAdaptation.json");
|
||||
|
||||
JObject? json = JObject
|
||||
.Parse(fileReader.ReadToEnd())
|
||||
.SelectToken("Aonprd")
|
||||
?.ToObject<JObject>();
|
||||
|
||||
if (json is not null)
|
||||
{
|
||||
SlugSuffixes = JsonToDictionary(json, "SlugSuffixes");
|
||||
LegacyRemasterExtra = JsonToDictionary(json, "LegacyRemasterExtra");
|
||||
MergeSources = JsonToDictionary(json, "MergeSources");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить суффикс для ссылки.
|
||||
/// </summary>
|
||||
/// <param name="id">Идентификатор Aonprd.</param>
|
||||
/// <returns>Суффикс для ссылки или пустая строка.</returns>
|
||||
public string GetSlugSuffix(string id)
|
||||
{
|
||||
return SlugSuffixes.TryGetValue(id, out string? slug) ? $"-{slug}" : string.Empty;
|
||||
}
|
||||
|
||||
private Dictionary<string, string> JsonToDictionary(JObject json, string tokenPath)
|
||||
{
|
||||
return json.SelectToken(tokenPath)?.ToObject<Dictionary<string, string>>() ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+15
-1
@@ -2,10 +2,11 @@
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model;
|
||||
using Pf2eModel.Model.Base;
|
||||
@@ -60,6 +61,8 @@ internal abstract class AbstractEntityProcessor(
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
Check();
|
||||
|
||||
AddEntity();
|
||||
AddSource();
|
||||
AddExternal();
|
||||
@@ -73,6 +76,17 @@ internal abstract class AbstractEntityProcessor(
|
||||
Context.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверки необходимости импорта сущности.
|
||||
/// </summary>
|
||||
public virtual void Check()
|
||||
{
|
||||
if (Globals.MergeSources.ContainsKey(Input.GetRequired<string>("id")))
|
||||
{
|
||||
throw new SkipItemException(Input.GetRequired<string>("name"), "помечено на слияние.");
|
||||
}
|
||||
}
|
||||
|
||||
#region "Генерация описания"
|
||||
|
||||
/// <summary>
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
using System.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Base;
|
||||
using Pf2eModel.Model.Common.I18n;
|
||||
|
||||
+4
-3
@@ -1,6 +1,7 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Base.Targets;
|
||||
|
||||
@@ -12,7 +13,7 @@ namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.Processors.Common;
|
||||
Group = ProcessorGroupEnum.AonprdPreparation
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:repository"])]
|
||||
internal class ExternalProcessor(AonprdBuilderGlobals globals) : AbstractProcessor
|
||||
internal class ExternalProcessor(AonprdBuilderGlobals globals) : AbstractSimpleProcessor
|
||||
{
|
||||
public Pf2eDbContext Context { get; } = new();
|
||||
public AonprdBuilderGlobals Globals { get; } = globals;
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Common;
|
||||
using Pf2eModel.Model.Common.I18n;
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Base.Source;
|
||||
using Pf2eModel.Model.Enum;
|
||||
|
||||
+6
-13
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Base;
|
||||
using Pf2eModel.Model.Base.Targets;
|
||||
@@ -21,7 +21,7 @@ namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.Processors.Finalizat
|
||||
)]
|
||||
internal class LegacyRemasterProcessors(ProcessorInput input) : AbstractInputProcessor(input)
|
||||
{
|
||||
private Pf2eDbContext Context { get; set; } = new();
|
||||
private Pf2eDbContext Context { get; } = new();
|
||||
|
||||
public override void Process()
|
||||
{
|
||||
@@ -32,27 +32,20 @@ internal class LegacyRemasterProcessors(ProcessorInput input) : AbstractInputPro
|
||||
int entityId = entity.EntityId;
|
||||
Entity legacyEntity =
|
||||
Context.Entities.FirstOrDefault(e => e.Id == entityId)
|
||||
?? throw new Exception($"Неизвестная сущность с ID {entityId}");
|
||||
?? throw new($"Неизвестная сущность с ID {entityId}");
|
||||
|
||||
foreach (int remasterId in GetEntityIds("remaster_id"))
|
||||
{
|
||||
Context.LegacyRemasters.Add(new() { LegacyId = entityId, RemasterId = remasterId });
|
||||
Entity remasterEntity =
|
||||
Context.Entities.AsNoTracking().FirstOrDefault(e => e.Id == remasterId)
|
||||
?? throw new Exception($"Неизвестная сущность с ID {remasterId}");
|
||||
?? throw new($"Неизвестная сущность с ID {remasterId}");
|
||||
|
||||
if (legacyEntity.Slug == remasterEntity.Slug)
|
||||
{
|
||||
legacyEntity.Slug += "-legacy";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
foreach (int legacyId in GetEntityIds("legacy_id"))
|
||||
{
|
||||
Context.LegacyRemasters.Add(new() { LegacyId = legacyId, RemasterId = entityId });
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
protected List<int> GetEntityIds(string path)
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eDataScrapper.Processors.Factory;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Base;
|
||||
using Pf2eModel.Model.Base.Targets;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.Processors.Finalization;
|
||||
|
||||
[ProcessorFactory(
|
||||
"aonprd:fix-legacy-remaster",
|
||||
ProcessorType = typeof(MissingLegacyRemasterProcessor),
|
||||
Description = "Дополнение связяй устаревших и обновлённых сущностей",
|
||||
Group = ProcessorGroupEnum.AonprdFinalization,
|
||||
Parallel = true
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:legacy-remaster"])]
|
||||
internal class MissingLegacyRemasterProcessorFactory(
|
||||
IServiceProvider serviceProvider,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractProcessorFactory
|
||||
{
|
||||
public IServiceProvider ServiceProvider { get; } = serviceProvider;
|
||||
public AonprdBuilderGlobals Globals { get; } = globals;
|
||||
|
||||
public override int Count() => Globals.LegacyRemasterExtra.Count;
|
||||
|
||||
public override IEnumerable<Tuple<string, IProcessor>> GetEnumerator()
|
||||
{
|
||||
foreach ((string key, string value) in Globals.LegacyRemasterExtra)
|
||||
{
|
||||
yield return new(
|
||||
$"{key} -> {value}",
|
||||
ActivatorUtilities.CreateInstance<MissingLegacyRemasterProcessor>(
|
||||
ServiceProvider,
|
||||
key,
|
||||
value
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class MissingLegacyRemasterProcessor(string legacyId, string remasterId) : IProcessor
|
||||
{
|
||||
public Pf2eDbContext Context { get; } = new();
|
||||
public string LegacyId { get; } = legacyId;
|
||||
public string RemasterId { get; } = remasterId;
|
||||
|
||||
private Entity GetEntity(string aonprdId)
|
||||
{
|
||||
EntityExternal entity =
|
||||
Context.EntityExternals.AsNoTracking().FirstOrDefault(x => x.ExternalId == aonprdId)
|
||||
?? throw new SilentSkipItemException();
|
||||
|
||||
int entityId = entity.EntityId;
|
||||
|
||||
return Context.Entities.FirstOrDefault(e => e.Id == entityId)
|
||||
?? throw new($"Неизвестная сущность с ID {entityId}");
|
||||
}
|
||||
|
||||
public void Process()
|
||||
{
|
||||
Entity legacyEntity = GetEntity(LegacyId);
|
||||
Entity remasterEntity = GetEntity(RemasterId);
|
||||
|
||||
Context.LegacyRemasters.Add(
|
||||
new() { LegacyId = legacyEntity.Id, RemasterId = remasterEntity.Id }
|
||||
);
|
||||
|
||||
if (legacyEntity.Slug == remasterEntity.Slug)
|
||||
{
|
||||
legacyEntity.Slug += "-legacy";
|
||||
}
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
Context.SaveChanges();
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Compendium;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.Processors.Preparation;
|
||||
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.Processors.Preparation;
|
||||
|
||||
|
||||
+1
-1
@@ -2,9 +2,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Compendium;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.SchemaBuilder;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.Processors.Preparation;
|
||||
|
||||
+3
-3
@@ -1,9 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Base;
|
||||
using Pf2eModel.Model.Common;
|
||||
@@ -19,8 +20,7 @@ namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.Processors.Subclasse
|
||||
InnerType = "apparition",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Apparitions",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses,
|
||||
Active = false
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(
|
||||
["aonprd:trait", "aonprd:source", "aonprd:class", "aonprd:spell", "aonprd:skill"]
|
||||
|
||||
+6
-3
@@ -1,7 +1,8 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eModel.Model.Enum;
|
||||
using StringHelper = Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
@@ -42,8 +43,10 @@ internal class ActionProcessor(
|
||||
Object.Extra = GenerateJsonString("school");
|
||||
}
|
||||
|
||||
public void Check()
|
||||
public override void Check()
|
||||
{
|
||||
base.Check();
|
||||
|
||||
if (Input.GetRequired<string>("markdown").StartsWith("**Activate"))
|
||||
{
|
||||
throw new SkipItemException(Input.GetRequired<string>("name"), "activating action");
|
||||
|
||||
+2
-1
@@ -2,10 +2,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eModel.Model.Enum;
|
||||
using Pf2eModel.Model.Structure;
|
||||
using StringHelper = Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eModel.Model.Enum;
|
||||
using Pf2eModel.Model.Structure;
|
||||
using StringHelper = Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eModel.Model.Enum;
|
||||
using Pf2eModel.Model.Structure;
|
||||
using Pf2eModel.Model.Structure.BackgroundRelation;
|
||||
|
||||
+2
-1
@@ -3,10 +3,11 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Common;
|
||||
using Pf2eModel.Model.Common.I18n;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Enum;
|
||||
using Pf2eModel.Model.Structure;
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eModel.Model.Enum;
|
||||
using Pf2eModel.Model.Structure;
|
||||
using StringHelper = Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
+1
-1
@@ -3,10 +3,10 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Common.I18n;
|
||||
using Pf2eModel.Model.Enum;
|
||||
|
||||
+1
-1
@@ -1,9 +1,9 @@
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eModel.Model.Base.Source;
|
||||
using Pf2eModel.Model.Base.Targets;
|
||||
using Pf2eModel.Model.Common.I18n;
|
||||
|
||||
+2
-2
@@ -7,9 +7,9 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eModel;
|
||||
using Rule = Pf2eModel.Model.Structure.Rule;
|
||||
|
||||
|
||||
+4
-3
@@ -4,9 +4,9 @@ using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using AngleSharp;
|
||||
using AngleSharp.Dom;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Base.Source;
|
||||
|
||||
@@ -120,7 +120,8 @@ internal partial class RulesTocProcessor(Pf2eDbContext context) : IProcessor
|
||||
IDocument document = null!;
|
||||
bool completed = false;
|
||||
|
||||
while (!completed){
|
||||
while (!completed)
|
||||
{
|
||||
try
|
||||
{
|
||||
document = context.OpenAsync(Url).Result;
|
||||
|
||||
+1
-1
@@ -1,10 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eModel.Model.Common.I18n;
|
||||
using Pf2eModel.Model.Enum;
|
||||
using Pf2eModel.Model.Structure;
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eModel.Model.Common.I18n;
|
||||
using Pf2eModel.Model.Enum;
|
||||
using Pf2eModel.Model.Structure;
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Enum;
|
||||
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model.Enum;
|
||||
using Pf2eModel.Model.Structure;
|
||||
|
||||
+1
@@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eModel;
|
||||
using Pf2eModel.Model;
|
||||
using Pf2eModel.Model.Base;
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Processors.Preparation;
|
||||
|
||||
|
||||
+2
-2
@@ -2,10 +2,10 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Processors.Preparation;
|
||||
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Processors.Preparation;
|
||||
|
||||
|
||||
+1
-1
@@ -2,9 +2,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.SchemaBuilder;
|
||||
|
||||
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Processors.Preparation;
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
<None Update=".env">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Resources\ImportAdaptation.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="schema.pgsql">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Абстрактный аттрибут обработчика.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
internal class AbstractProcessorAttribute(string name) : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Название обработчика.
|
||||
/// </summary>
|
||||
public string Name { get; } = name;
|
||||
|
||||
/// <summary>
|
||||
/// Описание обработчика.
|
||||
/// </summary>
|
||||
public string Description { get; init; } = name;
|
||||
|
||||
/// <summary>
|
||||
/// Группа обработчиков, к которому относится обработчик.
|
||||
/// </summary>
|
||||
public ProcessorGroupEnum Group { get; init; } = ProcessorGroupEnum.General;
|
||||
|
||||
/// <summary>
|
||||
/// Процессор включён по умолчанию.
|
||||
/// </summary>
|
||||
public bool Active { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Разрешить выполнять процессов в параллельном режиме
|
||||
/// </summary>
|
||||
public bool Parallel { get; init; } = false;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Общий аттрибут обработчика.
|
||||
/// </summary>
|
||||
/// <param name="name">Название обработчика.</param>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
internal class ProcessorAttribute(string name) : AbstractProcessorAttribute(name) { }
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Аттрибут обработчика набор элементов.
|
||||
/// </summary>
|
||||
/// <param name="name">Название обработчика.</param>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
internal class ProcessorCollectionAttribute(string name) : AbstractProcessorAttribute(name)
|
||||
{
|
||||
/// <summary>
|
||||
/// Название типов, который обрабатывает этот оброботчик.
|
||||
/// <c>null</c> - обработать все типы.
|
||||
/// </summary>
|
||||
public required string? InnerType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Тип используемого компендиума.
|
||||
/// </summary>
|
||||
public required ProcessorCompendiumEnum CompendiumType { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Аттрибут зависимостей обработчика.
|
||||
/// </summary>
|
||||
/// <param name="dependencies">Коллекция названий обработчиков, которые должны быть выполнены до этого оброботчика.</param>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ProcessorDependenciesAttribute(string[] dependencies) : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Коллекция названий обработчиков, которые должны быть выполнены до этого оброботчика.
|
||||
/// </summary>
|
||||
public ICollection<string> Dependencies { get; } = dependencies;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.Attributes;
|
||||
|
||||
internal class ProcessorFactoryAttribute(string name) : AbstractProcessorAttribute(name)
|
||||
{
|
||||
/// <summary>
|
||||
/// Тип обрабатывающего процессора
|
||||
/// </summary>
|
||||
public required Type ProcessorType { get; init; }
|
||||
}
|
||||
+8
-1
@@ -1,7 +1,7 @@
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Pf2eDataScrapper.App;
|
||||
namespace Pf2eDataScrapper.Processors.Attributes;
|
||||
|
||||
public enum ProcessorGroupEnum
|
||||
{
|
||||
@@ -33,6 +33,13 @@ public enum ProcessorCompendiumEnum
|
||||
FoundryEn,
|
||||
}
|
||||
|
||||
public enum ProcessorFactoryTypeEnum
|
||||
{
|
||||
Simple,
|
||||
Compendium,
|
||||
Iterator,
|
||||
}
|
||||
|
||||
public static class ProcessorGroupEnumExtension
|
||||
{
|
||||
public static string GetDescription(this ProcessorGroupEnum group)
|
||||
@@ -0,0 +1,296 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using LinqToDB;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eDataScrapper.Processors.Factory;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.Collection;
|
||||
|
||||
/// <summary>
|
||||
/// Класс с коллекцией обработчиков.
|
||||
/// </summary>
|
||||
internal class ProcessorCollection
|
||||
{
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Коллекция всех доступных обработчиков.
|
||||
/// </summary>
|
||||
public ICollection<ProcessorRecord> AllItems { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Коллекция обработчиков, которые будут обрабатываться.
|
||||
/// Для изменения необходимо использовать <see cref="FilterProcessors"/>.
|
||||
/// </summary>
|
||||
public List<ProcessorRecord> Items { get; private set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Обеспечение доступа к элементам обработчиков.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public ProcessorRecord this[string name] => AllItems.First(item => item.Name == name);
|
||||
|
||||
/// <summary>
|
||||
/// Конструктор класса <see cref="ProcessorCollection"/>.
|
||||
/// </summary>
|
||||
public ProcessorCollection(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
foreach (Type type in assembly.GetTypes())
|
||||
{
|
||||
ProcessType(type, type.GetCustomAttribute<AbstractProcessorAttribute>());
|
||||
}
|
||||
|
||||
CheckDependencies();
|
||||
FilterProcessors([]);
|
||||
}
|
||||
|
||||
private void ProcessType(Type type, AbstractProcessorAttribute? attribute)
|
||||
{
|
||||
switch (attribute)
|
||||
{
|
||||
case null:
|
||||
break;
|
||||
|
||||
case ProcessorAttribute processorAttribute:
|
||||
ProcessType(type, processorAttribute);
|
||||
break;
|
||||
|
||||
case ProcessorCollectionAttribute processorCollectionAttribute:
|
||||
ProcessType(type, processorCollectionAttribute);
|
||||
break;
|
||||
|
||||
case ProcessorFactoryAttribute processorFactoryAttribute:
|
||||
ProcessType(type, processorFactoryAttribute);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new(
|
||||
$"Неизвестная реализация класса {typeof(AbstractProcessorAttribute)} - {attribute.GetType()}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessType(Type type, ProcessorAttribute? attribute)
|
||||
{
|
||||
if (attribute is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!type.IsAssignableTo(typeof(IProcessor)))
|
||||
{
|
||||
throw new(
|
||||
$"Процессор {type}, которому установлен аттрибут {attribute.GetType()}, не представляет интерфейс {typeof(IProcessor)}"
|
||||
);
|
||||
}
|
||||
|
||||
ProcessorDependenciesAttribute? dependenciesAttribute =
|
||||
type.GetCustomAttribute<ProcessorDependenciesAttribute>();
|
||||
|
||||
ProcessorRecord item = new()
|
||||
{
|
||||
Name = attribute.Name,
|
||||
Type = type,
|
||||
Description = attribute.Description,
|
||||
Group = attribute.Group,
|
||||
Dependencies = dependenciesAttribute?.Dependencies ?? [],
|
||||
Active = attribute.Active,
|
||||
Parallel = attribute.Parallel,
|
||||
};
|
||||
|
||||
item.Factory = ActivatorUtilities.CreateInstance<SimpleProcessorFactory>(
|
||||
ServiceProvider,
|
||||
item
|
||||
);
|
||||
|
||||
AllItems.Add(item);
|
||||
}
|
||||
|
||||
private void ProcessType(Type type, ProcessorCollectionAttribute? attribute)
|
||||
{
|
||||
if (attribute is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!type.IsAssignableTo(typeof(AbstractInputProcessor)))
|
||||
{
|
||||
throw new(
|
||||
$"Процессор {type}, которому установлен аттрибут {attribute.GetType()}, не реализует класс {typeof(AbstractInputProcessor)}."
|
||||
);
|
||||
}
|
||||
|
||||
ProcessorDependenciesAttribute? dependenciesAttribute =
|
||||
type.GetCustomAttribute<ProcessorDependenciesAttribute>();
|
||||
|
||||
ProcessorRecord item = new()
|
||||
{
|
||||
Name = attribute.Name,
|
||||
Type = type,
|
||||
Description = attribute.Description,
|
||||
Group = attribute.Group,
|
||||
Dependencies = dependenciesAttribute?.Dependencies ?? [],
|
||||
Active = attribute.Active,
|
||||
Parallel = attribute.Parallel,
|
||||
};
|
||||
|
||||
CompendiumProcessorFactory factory =
|
||||
ActivatorUtilities.CreateInstance<CompendiumProcessorFactory>(ServiceProvider, item);
|
||||
|
||||
factory.CompendiumType = attribute.CompendiumType;
|
||||
factory.InnerType = attribute.InnerType;
|
||||
|
||||
item.Factory = factory;
|
||||
|
||||
AllItems.Add(item);
|
||||
}
|
||||
|
||||
private void ProcessType(Type type, ProcessorFactoryAttribute? attribute)
|
||||
{
|
||||
if (attribute is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!type.IsAssignableTo(typeof(AbstractProcessorFactory)))
|
||||
{
|
||||
throw new(
|
||||
$"Процессор {type}, которому установлен аттрибут {attribute.GetType()}, не реализует класс {typeof(AbstractProcessorFactory)}."
|
||||
);
|
||||
}
|
||||
|
||||
ProcessorDependenciesAttribute? dependenciesAttribute =
|
||||
type.GetCustomAttribute<ProcessorDependenciesAttribute>();
|
||||
|
||||
ProcessorRecord item = new()
|
||||
{
|
||||
Name = attribute.Name,
|
||||
Type = attribute.ProcessorType,
|
||||
Description = attribute.Description,
|
||||
Group = attribute.Group,
|
||||
Dependencies = dependenciesAttribute?.Dependencies ?? [],
|
||||
Active = attribute.Active,
|
||||
Parallel = attribute.Parallel,
|
||||
Factory = (AbstractProcessorFactory)
|
||||
ActivatorUtilities.CreateInstance(ServiceProvider, type),
|
||||
};
|
||||
|
||||
AllItems.Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверка, что все зависимости всех обработчиков могут быть удовлетворены.
|
||||
/// </summary>
|
||||
private void CheckDependencies()
|
||||
{
|
||||
foreach (ProcessorRecord item in Items)
|
||||
{
|
||||
foreach (string dependency in item.Dependencies)
|
||||
{
|
||||
if (Items.All(i => i.Name != dependency))
|
||||
{
|
||||
throw new($"Dependency '{dependency}' for processor '{item.Name}' not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сортировать обработчики в соответсвии со всеми зависимостями.
|
||||
/// </summary>
|
||||
public void SortItems()
|
||||
{
|
||||
Items.ForEach(item => item.Priority = -1);
|
||||
|
||||
Dictionary<string, int> priorities = [];
|
||||
|
||||
while (priorities.Count < Items.Count)
|
||||
{
|
||||
foreach (ProcessorRecord item in Items)
|
||||
{
|
||||
if (item.Priority >= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IEnumerable<int> dependencyPriorities = item.Dependencies.Select(d =>
|
||||
priorities.GetValueOrDefault(d, -1)
|
||||
);
|
||||
|
||||
if (dependencyPriorities.Any(p => p == -1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item.Priority = Math.Max(
|
||||
dependencyPriorities.Any() ? dependencyPriorities.Max() + 1 : 1,
|
||||
(int)item.Group * 100
|
||||
);
|
||||
priorities.Add(item.Name, item.Priority);
|
||||
}
|
||||
}
|
||||
|
||||
Items.Sort((a, b) => a.Priority - b.Priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ограничить список используемых обработчиков по названию.
|
||||
/// Автоматически включает все обработчики, от которых зависят указанные в аргументе обработчики.
|
||||
/// </summary>
|
||||
/// <param name="processorNames">Коллекция названиий требуемых обработчиков.</param>
|
||||
public void FilterProcessors(ICollection<string> processorNames)
|
||||
{
|
||||
if (processorNames.Count == 0)
|
||||
{
|
||||
Items = [.. AllItems];
|
||||
SortItems();
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<string, bool> nameFlags = processorNames.ToDictionary(name => name, _ => false);
|
||||
|
||||
while (nameFlags.Values.Any(v => !v))
|
||||
{
|
||||
foreach (
|
||||
KeyValuePair<string, bool> pair in nameFlags.Where(pair => !pair.Value).ToList()
|
||||
)
|
||||
{
|
||||
ProcessorRecord item = AllItems.First(item => item.Name == pair.Key);
|
||||
|
||||
foreach (string dependency in item.Dependencies)
|
||||
{
|
||||
nameFlags.TryAdd(dependency, false);
|
||||
}
|
||||
|
||||
nameFlags[pair.Key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
Items = AllItems.Where(item => nameFlags.ContainsKey(item.Name)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить список типов, которые обрабатываются в компендиуме.
|
||||
/// </summary>
|
||||
/// <param name="compendium">Тип компендиума.</param>
|
||||
/// <returns>Набор типов.</returns>
|
||||
public ICollection<string> GetTypesOfCompendium(ProcessorCompendiumEnum compendium) =>
|
||||
Items
|
||||
.Where(item =>
|
||||
item.Factory.GetType().IsAssignableTo(typeof(CompendiumProcessorFactory))
|
||||
)
|
||||
.Where(item =>
|
||||
(item.Factory as CompendiumProcessorFactory)!.CompendiumType == compendium
|
||||
)
|
||||
.Select(item => (item.Factory as CompendiumProcessorFactory)!.InnerType)
|
||||
.OfType<string>()
|
||||
.ToList();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Factory;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.Collection;
|
||||
|
||||
/// <summary>
|
||||
/// Элемент коллекции обработчиков.
|
||||
/// </summary>
|
||||
internal class ProcessorRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// Название обработчика.
|
||||
/// </summary>
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Тип класса обработчика.
|
||||
/// </summary>
|
||||
public required Type Type { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Описание обработчика.
|
||||
/// </summary>
|
||||
public string Description { get; init; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Фабрика обработчиков.
|
||||
/// </summary>
|
||||
public AbstractProcessorFactory Factory { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Группа обработчика.
|
||||
/// </summary>
|
||||
public required ProcessorGroupEnum Group { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Коллекция названий обработчиков, после которых должен выполняться обработчик.
|
||||
/// </summary>
|
||||
public ICollection<string> Dependencies { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Процессор включён по умолчанию.
|
||||
/// </summary>
|
||||
public bool Active { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Приоритет выполнения обработчика.
|
||||
/// </summary>
|
||||
public int Priority { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Разрешить выполнять процессов в параллельном режиме
|
||||
/// </summary>
|
||||
public bool Parallel { get; init; } = true;
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors;
|
||||
namespace Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
/// <summary>
|
||||
/// Абстрактный класс-обработчик данных, полученных из Архивов Нефиса.
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors;
|
||||
namespace Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
/// <summary>
|
||||
/// Абстрактный класс-обработчик данных, полученных из Архивов Нефиса.
|
||||
@@ -8,7 +8,7 @@ namespace Pf2eDataScrapper.Processors;
|
||||
/// для которых указан атрибут <see cref="ProcessorAttribute"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="ProcessorAttribute"/>
|
||||
internal abstract class AbstractProcessor : IProcessor
|
||||
internal abstract class AbstractSimpleProcessor : IProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Основной метод обработки данных.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Pf2eDataScrapper.Processors;
|
||||
namespace Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
public interface IProcessor
|
||||
{
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.Factory;
|
||||
|
||||
/// <summary>
|
||||
/// Абстрактная фабрика создания процессоров.
|
||||
/// </summary>
|
||||
internal abstract class AbstractProcessorFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Подготовить фабрику к работе.
|
||||
/// </summary>
|
||||
public virtual void Prepare() { }
|
||||
|
||||
/// <summary>
|
||||
/// Количество элеметов для итерирования.
|
||||
/// </summary>
|
||||
/// <returns>Количество элеметов</returns>
|
||||
public abstract int Count();
|
||||
|
||||
/// <summary>
|
||||
/// Итератор процессоров.
|
||||
/// </summary>
|
||||
/// <returns>Пара значений: [0] - описание элемента процессор, [1] - процессор.</returns>
|
||||
public abstract IEnumerable<Tuple<string, IProcessor>> GetEnumerator();
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.Importers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Compendium;
|
||||
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.Factory;
|
||||
|
||||
internal class CompendiumProcessorFactory(ProcessorRecord item, IServiceProvider serviceProvider)
|
||||
: AbstractProcessorFactory
|
||||
{
|
||||
public ProcessorRecord Item { get; } = item;
|
||||
public IServiceProvider ServiceProvider { get; } = serviceProvider;
|
||||
|
||||
public ProcessorCompendiumEnum? CompendiumType { get; set; } = null;
|
||||
public string? InnerType { get; set; } = null;
|
||||
|
||||
public AbstractCompendium Compendium { get; private set; } = null!;
|
||||
public ICollection<string> Types { get; private set; } = [];
|
||||
|
||||
public override void Prepare()
|
||||
{
|
||||
if (CompendiumType is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(CompendiumType));
|
||||
}
|
||||
|
||||
base.Prepare();
|
||||
|
||||
ProcessorCollection collection =
|
||||
ServiceProvider.GetService<ProcessorCollection>() ?? throw new();
|
||||
|
||||
Compendium =
|
||||
CompendiumType switch
|
||||
{
|
||||
ProcessorCompendiumEnum.Aonprd => ServiceProvider.GetService<AonprdCompendium>(),
|
||||
ProcessorCompendiumEnum.FoundryEn =>
|
||||
ServiceProvider.GetService<FoundryEnCompendium>(),
|
||||
_ => (AbstractCompendium?)null,
|
||||
} ?? throw new($"Не могу выбрать импортёр для группы {Item.Group}");
|
||||
|
||||
Types = InnerType is null
|
||||
? collection.GetTypesOfCompendium(CompendiumType ?? throw new())
|
||||
: [InnerType];
|
||||
}
|
||||
|
||||
public override int Count() => Compendium.Count(Types);
|
||||
|
||||
public override IEnumerable<Tuple<string, IProcessor>> GetEnumerator()
|
||||
{
|
||||
foreach ((AbstractCompendiumItem compendiumItem, JObject json) in Compendium.Iterate(Types))
|
||||
{
|
||||
ProcessorInput processorInput = ActivatorUtilities.CreateInstance<ProcessorInput>(
|
||||
ServiceProvider,
|
||||
compendiumItem.Id,
|
||||
json
|
||||
);
|
||||
|
||||
yield return new(
|
||||
compendiumItem.Id,
|
||||
(IProcessor)
|
||||
ActivatorUtilities.CreateInstance(ServiceProvider, Item.Type, processorInput)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.Factory;
|
||||
|
||||
internal class SimpleProcessorFactory(ProcessorRecord item, IServiceProvider serviceProvider)
|
||||
: AbstractProcessorFactory
|
||||
{
|
||||
public ProcessorRecord Item { get; } = item;
|
||||
public IServiceProvider ServiceProvider { get; } = serviceProvider;
|
||||
|
||||
public override int Count() => 1;
|
||||
|
||||
public override IEnumerable<Tuple<string, IProcessor>> GetEnumerator()
|
||||
{
|
||||
yield return new(
|
||||
Item.Description,
|
||||
(IProcessor)ActivatorUtilities.CreateInstance(ServiceProvider, Item.Type)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eModel;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors.General;
|
||||
|
||||
@@ -2,30 +2,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers;
|
||||
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Compendium;
|
||||
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
using Pf2eDataScrapper.Processors.Factory;
|
||||
|
||||
namespace Pf2eDataScrapper.Processors;
|
||||
|
||||
internal sealed class ProcessorExecutor(
|
||||
IServiceProvider serviceProvider,
|
||||
ProcessorCollection collection,
|
||||
ProcessProgress progress,
|
||||
AonprdCompendium aonprdCompendium,
|
||||
FoundryEnCompendium foundryEnCompendium,
|
||||
ApplicationSettings settings
|
||||
)
|
||||
{
|
||||
public IServiceProvider ServiceProvider { get; } = serviceProvider;
|
||||
public ProcessorCollection Collection { get; } = collection;
|
||||
public ProcessProgress Progress { get; } = progress;
|
||||
public AonprdCompendium AonprdCompendium { get; } = aonprdCompendium;
|
||||
public FoundryEnCompendium FoundryEnCompendium { get; } = foundryEnCompendium;
|
||||
public ApplicationSettings Settings { get; } = settings;
|
||||
|
||||
public void Start()
|
||||
@@ -39,23 +30,25 @@ internal sealed class ProcessorExecutor(
|
||||
|
||||
private int _currentIndex;
|
||||
|
||||
private AbstractProcessorFactory CurrentFactory { get; set; } = null!;
|
||||
|
||||
private void StartItem()
|
||||
{
|
||||
ProcessorCollectionItem item = Collection.Items[_currentIndex];
|
||||
ProcessorRecord item = Collection.Items[_currentIndex];
|
||||
|
||||
Progress.Processors.Start(item.Description);
|
||||
Progress.Progress(Progress.Processors.ToString());
|
||||
|
||||
BackgroundWorker worker = new();
|
||||
|
||||
CurrentFactory = item.Factory;
|
||||
CurrentFactory.Prepare();
|
||||
|
||||
worker.DoWork += (_, _) =>
|
||||
{
|
||||
Parallel.ForEach(
|
||||
IterateProcessors(item),
|
||||
new ParallelOptions()
|
||||
{
|
||||
MaxDegreeOfParallelism = item.Parallel ? Settings.MaxThreads : 1,
|
||||
},
|
||||
IterateProcessors(),
|
||||
new() { MaxDegreeOfParallelism = item.Parallel ? Settings.MaxThreads : 1 },
|
||||
RunProcessor
|
||||
);
|
||||
};
|
||||
@@ -94,53 +87,18 @@ internal sealed class ProcessorExecutor(
|
||||
else
|
||||
{
|
||||
Progress.Processors.Complete();
|
||||
Progress.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IProcessor> IterateProcessors(ProcessorCollectionItem item)
|
||||
private IEnumerable<IProcessor> IterateProcessors()
|
||||
{
|
||||
if (!item.IsCollection)
|
||||
Progress.Local.Reset(CurrentFactory.Count());
|
||||
|
||||
foreach ((string title, IProcessor processor) in CurrentFactory.GetEnumerator())
|
||||
{
|
||||
Progress.Local.Reset(1);
|
||||
Progress.Local.Start(item.Description);
|
||||
yield return (IProcessor)ActivatorUtilities.CreateInstance(ServiceProvider, item.Type);
|
||||
Progress.Local.Complete();
|
||||
yield break;
|
||||
}
|
||||
Progress.Local.Start(title);
|
||||
|
||||
if (item.Group == ProcessorGroupEnum.General)
|
||||
{
|
||||
throw new(
|
||||
$"Обработчик {item.Description} помечен как общий (поле Group == General) и коллекционный (поле InnerType), что запрещено."
|
||||
);
|
||||
}
|
||||
|
||||
AbstractCompendium compendium = item.Compendium switch
|
||||
{
|
||||
ProcessorCompendiumEnum.Aonprd => AonprdCompendium,
|
||||
ProcessorCompendiumEnum.FoundryEn => FoundryEnCompendium,
|
||||
_ => throw new($"Не могу выбрать импортёр для группы {item.Group}"),
|
||||
};
|
||||
|
||||
ICollection<string> types = item.InnerType is null
|
||||
? Collection.GetTypesOfCompendium(item.Compendium ?? throw new("impossible"))
|
||||
: [item.InnerType];
|
||||
|
||||
Progress.Local.Reset(compendium.Count(types));
|
||||
|
||||
foreach ((AbstractCompendiumItem compendiumItem, JObject json) in compendium.Iterate(types))
|
||||
{
|
||||
Progress.Local.Start(compendiumItem.Id);
|
||||
|
||||
ProcessorInput processorInput = ActivatorUtilities.CreateInstance<ProcessorInput>(
|
||||
ServiceProvider,
|
||||
compendiumItem.Id,
|
||||
json
|
||||
);
|
||||
|
||||
yield return (IProcessor)
|
||||
ActivatorUtilities.CreateInstance(ServiceProvider, item.Type, processorInput);
|
||||
yield return processor;
|
||||
|
||||
Progress.Local.End();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"Aonprd": {
|
||||
"SlugSuffixes": {
|
||||
"feat-455": "initial",
|
||||
"spell-843": "initial",
|
||||
"feat-2664": "archetype",
|
||||
"feat-3247": "game-hunter",
|
||||
"feat-3477": "undead-slayer",
|
||||
"feat-3549": "vampire",
|
||||
"feat-4344": "archetype",
|
||||
"feat-4380": "stonebound",
|
||||
"feat-5730": "dragonblood",
|
||||
"feat-5737": "dragonblood",
|
||||
"feat-5997": "legacy",
|
||||
"feat-6209": "investigator",
|
||||
"feat-6469": "general",
|
||||
"feat-6477": "undead-slayer",
|
||||
"feat-6883": "kitsune",
|
||||
"feat-7004": "yaoguai",
|
||||
"feat-7380": "mythic",
|
||||
"feat-7637": "dandy"
|
||||
},
|
||||
"LegacyRemasterExtra": {
|
||||
"action-14": "action-2273",
|
||||
"action-15": "action-2275",
|
||||
"action-558": "action-2277",
|
||||
|
||||
"archetype-83": "archetype-129",
|
||||
"archetype-86": "archetype-198",
|
||||
|
||||
"feat-455": "feat-6007",
|
||||
"feat-480": "feat-4850",
|
||||
"feat-936": "feat-2269",
|
||||
"feat-1177": "feat-4553",
|
||||
"feat-1753": "feat-6031",
|
||||
"feat-2117": "feat-7577",
|
||||
"feat-2729": "feat-4077",
|
||||
"feat-2742": "feat-4078",
|
||||
"feat-2743": "feat-4079",
|
||||
"feat-2986": "feat-4340",
|
||||
"feat-2987": "feat-4341",
|
||||
"feat-2989": "feat-4343",
|
||||
"feat-2990": "feat-4346",
|
||||
"feat-2991": "feat-4349",
|
||||
"feat-2992": "feat-4350",
|
||||
"feat-2993": "feat-4352",
|
||||
"feat-4088": "feat-5491",
|
||||
"feat-5997": "feat-7108",
|
||||
|
||||
"language-91": "language-180",
|
||||
|
||||
"ritual-31": "ritual-191",
|
||||
|
||||
"spell-641": "spell-1413",
|
||||
"spell-646": "spell-1394",
|
||||
"spell-841": "spell-1107",
|
||||
"spell-843": "spell-2376",
|
||||
"spell-1052": "spell-1309",
|
||||
"spell-1053": "spell-1306",
|
||||
"spell-1054": "spell-1305",
|
||||
"spell-1055": "spell-1311",
|
||||
"spell-1056": "spell-1310",
|
||||
"spell-1057": "spell-1307",
|
||||
"spell-1058": "spell-1304",
|
||||
"spell-1059": "spell-1308"
|
||||
},
|
||||
"MergeSources": {
|
||||
"feat-963": "feat-4519",
|
||||
"feat-1167": "feat-5880",
|
||||
"feat-1169": "feat-5055",
|
||||
"feat-1171": "feat-4858",
|
||||
|
||||
"spell-551": "spell-2003",
|
||||
"spell-553": "spell-2012",
|
||||
"spell-559": "spell-2417",
|
||||
"spell-560": "spell-2418",
|
||||
"spell-571": "spell-1975",
|
||||
"spell-578": "spell-1566",
|
||||
"spell-654": "spell-819"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
using Pf2eDataScrapper.Importers;
|
||||
using Pf2eDataScrapper.Processors;
|
||||
using Pf2eDataScrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2eDataScrapper.SchemaBuilder;
|
||||
|
||||
|
||||
@@ -1,42 +1,15 @@
|
||||
using System.Windows;
|
||||
using Pf2eDataScrapper.WPF.EntityViewer.ViewModel;
|
||||
|
||||
namespace Pf2eDataScrapper.WPF.EntityViewer.Component;
|
||||
namespace Pf2eDataScrapper.WPF.EntityViewer.Component;
|
||||
|
||||
/// <summary>
|
||||
/// Логика взаимодействия для DbEntityListControl.xaml
|
||||
/// </summary>
|
||||
internal partial class EntityListControl : System.Windows.Controls.UserControl
|
||||
{
|
||||
private EntityListViewModel? _viewModel;
|
||||
|
||||
public EntityListControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
//https://www.youtube.com/watch?v=54ZmhbpjBmg
|
||||
|
||||
private void FirstButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// DataContext?.FirstPage();
|
||||
}
|
||||
|
||||
private void PreviousButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//ViewModel?.PreviousPage();
|
||||
}
|
||||
|
||||
private void NextButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//ViewModel?.NextPage();
|
||||
}
|
||||
|
||||
private void LastButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//ViewModel?.LastPage();
|
||||
}
|
||||
|
||||
private void TextBox_PreviewTextInput(
|
||||
object sender,
|
||||
System.Windows.Input.TextCompositionEventArgs e
|
||||
|
||||
@@ -29,6 +29,8 @@ internal partial class EntityForm : Window
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
(Application.Current as ImportApplication)!.CurrentStage = ApplicationStage.InitialSettings;
|
||||
ApplicationStateChange?.Invoke(this, ApplicationStage.InitialSettings);
|
||||
}
|
||||
|
||||
public event ImportApplication.ApplicationStateChangeDelegate? ApplicationStateChange;
|
||||
}
|
||||
|
||||
@@ -124,10 +124,6 @@ internal class StructureRow : INotifyPropertyChanged
|
||||
Field.PropertyChanged += Field_PropertyChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
private void Field_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(Field));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Drawing;
|
||||
using System.Windows;
|
||||
using LinqToDB.Tools;
|
||||
using Pf2eDataScrapper.Helpers;
|
||||
|
||||
namespace Pf2eDataScrapper.WPF.ProgressForm;
|
||||
@@ -26,7 +27,6 @@ internal partial class ProgressForm : Window
|
||||
Progress.ProgressComplete += Progress_ProgressComplete;
|
||||
}
|
||||
|
||||
|
||||
private void Progress_ProgressUpdate(ProcessProgress sender)
|
||||
{
|
||||
if (!Dispatcher.CheckAccess())
|
||||
@@ -58,9 +58,10 @@ internal partial class ProgressForm : Window
|
||||
|
||||
MessageListView.ScrollIntoView(item);
|
||||
}
|
||||
|
||||
private void Progress_ProgressComplete(ProcessProgress sender)
|
||||
{
|
||||
(Application.Current as ImportApplication)!.CurrentStage = ApplicationStage.Viewer;
|
||||
ApplicationStateChange?.Invoke(this, ApplicationStage.Viewer);
|
||||
}
|
||||
|
||||
public event ImportApplication.ApplicationStateChangeDelegate? ApplicationStateChange;
|
||||
|
||||
@@ -3,7 +3,8 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Processors.Attributes;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
using CheckBox = System.Windows.Controls.CheckBox;
|
||||
|
||||
namespace Pf2eDataScrapper.WPF.StartForm.Components;
|
||||
@@ -61,11 +62,7 @@ internal partial class ProcessorCollectionControl : System.Windows.Controls.User
|
||||
Style = (Style)Resources["ElementPanelStyle"]!,
|
||||
};
|
||||
|
||||
foreach (
|
||||
ProcessorCollectionItem item in Collection.AllItems.Where(item =>
|
||||
item.Group == group
|
||||
)
|
||||
)
|
||||
foreach (ProcessorRecord item in Collection.AllItems.Where(item => item.Group == group))
|
||||
{
|
||||
ItemCheckBoxes[item.Name] = new()
|
||||
{
|
||||
@@ -96,7 +93,7 @@ internal partial class ProcessorCollectionControl : System.Windows.Controls.User
|
||||
|
||||
foreach ((string key, CheckBox? checkBox) in ItemCheckBoxes)
|
||||
{
|
||||
ProcessorCollectionItem item = Collection[key];
|
||||
ProcessorRecord item = Collection[key];
|
||||
bool isChecked = checkBox.IsChecked ?? false;
|
||||
|
||||
if (GroupLastStats.TryGetValue(item.Group, out bool? state))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Windows;
|
||||
using Pf2eDataScrapper.App;
|
||||
using Pf2eDataScrapper.Processors.Collection;
|
||||
|
||||
namespace Pf2eDataScrapper.WPF.StartForm;
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ using Pf2eModel.Model.Enum;
|
||||
namespace Pf2eModel.Migrations
|
||||
{
|
||||
[DbContext(typeof(Pf2eDbContext))]
|
||||
[Migration("20250521102908_1")]
|
||||
[Migration("20250521155437_1")]
|
||||
partial class _1
|
||||
{
|
||||
/// <inheritdoc />
|
||||
Reference in New Issue
Block a user