Files
EpisodeRenamer/Program.cs
2025-09-23 09:54:08 +07:00

233 lines
8.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace EpisodeRenamer
{
class EpisodeRenamer
{
private class PatternConfig
{
public bool Enabled { get; set; }
public string Regex { get; set; }
public int? Start { get; set; }
public int? End { get; set; }
public bool IgnoreCase { get; set; }
}
private class Config
{
public List<PatternConfig> Patterns { get; set; }
public List<string> Extensions { get; set; }
}
private static List<Pattern> patterns;
private static HashSet<string> extensions;
private class Pattern
{
public Regex Regex { get; }
public int? Start { get; }
public int? End { get; }
public Pattern(Regex regex, int? start, int? end)
{
Regex = regex;
Start = start;
End = end;
}
}
static async Task Main(string[] args)
{
// Создаем экземпляр слушателя
using (var hotkeyListener = new HotkeyListener())
{
// Подписываемся на события
hotkeyListener.OnHotkeyPressed += (combination) =>
{
switch (combination)
{
case "ControlAltR":
LoadConfiguration(true);
break;
case "ControlC":
Console.WriteLine("\nВыход из программы.");
Environment.Exit(0);
break;
default:
break;
}
};
hotkeyListener.OnError += (ex) => Console.WriteLine($"Ошибка: {ex.Message}");
hotkeyListener.RegisterCombination("ControlC", new[] { 0x11, 0x43 });
// Запускаем прослушивание
await hotkeyListener.StartListeningAsync();
// Основной цикл программы
await RunMainProgramLoop();
// Останавливаем слушатель (автоматически вызывается в Dispose)
await hotkeyListener.StopListeningAsync();
}
}
static async Task RunMainProgramLoop()
{
Console.Title = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyTitleAttribute>().Title;
try
{
LoadConfiguration();
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка загрузки конфигурации: {ex.Message}");
Console.WriteLine("Программа будет завершена.");
Console.ReadLine();
return;
}
//Console.CancelKeyPress += (sender, e) =>
//{
// Console.WriteLine("\nВыход из программы.");
// Environment.Exit(0);
//};
Console.WriteLine("Чтобы оставить текущую директорию нажмите 'Enter'");
Console.WriteLine("Чтобы перезагрузить конфигурацию нажмите 'Ctrl + Alt + R'");
Console.WriteLine("Чтобы выйти нажмите 'Ctrl + C'");
while (true)
{
try
{
Console.Write("\nВведите путь до папки с эпизодами: ");
string input = Console.ReadLine() ?? string.Empty;
input = input.Trim();
string folder = string.IsNullOrEmpty(input)
? Directory.GetCurrentDirectory()
: Path.GetFullPath(input);
if (Directory.Exists(folder))
{
ProcessFolder(folder);
}
else
{
Console.WriteLine("Указанная папка не существует.");
}
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка: {ex.Message}");
}
}
}
private static void LoadConfiguration(bool reloadConfiguration = false)
{
if (reloadConfiguration)
{
extensions.Clear();
patterns.Clear();
Console.WriteLine("\nЗапрошена перезагрузка конфигурации.");
}
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.json");
if (!File.Exists(configPath))
{
throw new FileNotFoundException("Конфигурационный файл config.json не найден");
}
string json = File.ReadAllText(configPath);
Config config = JsonConvert.DeserializeObject<Config>(json);
// Загружаем расширения файлов
extensions = new HashSet<string>(config.Extensions, StringComparer.OrdinalIgnoreCase);
// Загружаем паттерны
patterns = new List<Pattern>();
foreach (PatternConfig patternConfig in config.Patterns)
{
if (!patternConfig.Enabled)
continue;
RegexOptions options = patternConfig.IgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;
Regex regex = new Regex(patternConfig.Regex, options);
patterns.Add(new Pattern(regex, patternConfig.Start, patternConfig.End));
}
Console.WriteLine("Конфигурация успешно загружена.");
Console.WriteLine($"Загружено паттернов: {patterns.Count}; расширений: {extensions.Count}.");
}
private static void ProcessFolder(string folder)
{
foreach (string filePath in Directory.GetFiles(folder))
{
string fileName = Path.GetFileName(filePath);
string extension = Path.GetExtension(fileName);
if (extensions.Contains(extension))
{
RenameFile(filePath, fileName, folder);
}
}
}
private static void RenameFile(string filePath, string fileName, string folder)
{
string nameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
foreach (var pattern in patterns)
{
Match match = pattern.Regex.Match(nameWithoutExt);
if (!match.Success)
continue;
string found = match.Value;
int startIndex = AdjustIndex(pattern.Start, found.Length);
int endIndex = AdjustIndex(pattern.End, found.Length);
if (startIndex < 0 || endIndex < 0 || startIndex >= endIndex)
continue;
string numberStr = found.Substring(
startIndex,
endIndex - startIndex
);
if (int.TryParse(numberStr, out int episode))
{
string newName = $"{episode:D2}{Path.GetExtension(fileName)}";
string newPath = Path.Combine(folder, newName);
if (!File.Exists(newPath))
{
File.Move(filePath, newPath);
Console.WriteLine($"\"{fileName}\" успешно переименован в \"{newName}\".");
return;
}
Console.WriteLine($"Ошибка: файл \"{newName}\" уже существует.");
}
}
}
private static int AdjustIndex(int? index, int length)
{
if (!index.HasValue)
return length;
if (index.Value < 0)
return length + index.Value;
return index.Value;
}
}
}