Compare commits
2 Commits
20f3709ac9
...
4f021d5a3e
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f021d5a3e | |||
| e33e985031 |
@ -18,6 +18,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="NativeFileDialogSharp" Version="0.5.0" />
|
<PackageReference Include="NativeFileDialogSharp" Version="0.5.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
|
<PackageReference Include="TMDbLib" Version="2.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
11
Src/Config/Attribute/ConfigItemAttribute.cs
Normal file
11
Src/Config/Attribute/ConfigItemAttribute.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace BangumiRenamer.Config;
|
||||||
|
|
||||||
|
public class ConfigItemAttribute : System.Attribute
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
|
||||||
|
public ConfigItemAttribute(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,79 +1,115 @@
|
|||||||
using System.Reflection;
|
namespace BangumiRenamer.Config;
|
||||||
using Newtonsoft.Json;
|
using System.Reflection;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
namespace BangumiRenamer.ConfigManager;
|
|
||||||
|
public class Config(string configPath)
|
||||||
public class ConfigManager(string configPath)
|
{
|
||||||
{
|
private static readonly Lazy<Config> _lazy = new (() =>
|
||||||
private static readonly Dictionary<Type, string> Cache = new();
|
{
|
||||||
private readonly Dictionary<string, object> _configObjects = new();
|
var config = new Config("config.json");
|
||||||
private readonly Dictionary<string, JObject> _configs = new();
|
config.ReLoad();
|
||||||
|
return config;
|
||||||
private static string GetConfigName(Type type)
|
});
|
||||||
{
|
public static Config Default => _lazy.Value;
|
||||||
if (Cache.TryGetValue(type, out var name)) return name;
|
|
||||||
name = type.Name;
|
|
||||||
if(type.GetCustomAttribute(typeof(ConfigItemAttribute)) is ConfigItemAttribute info)
|
private static readonly Dictionary<Type, string> Cache = new();
|
||||||
{
|
private readonly Dictionary<string, object> _configObjects = new();
|
||||||
name = string.IsNullOrEmpty(info.Name) ? type.Name : info.Name;
|
private readonly Dictionary<string, JObject> _configs = new();
|
||||||
}
|
|
||||||
Cache[type] = name;
|
private static string GetConfigItemName(Type type)
|
||||||
return name;
|
{
|
||||||
}
|
if (Cache.TryGetValue(type, out var name)) return name;
|
||||||
|
name = type.Name;
|
||||||
public T Get<T>() where T : class, new()
|
if(type.GetCustomAttribute(typeof(ConfigItemAttribute)) is ConfigItemAttribute info)
|
||||||
{
|
{
|
||||||
var name = GetConfigName(typeof(T));
|
name = string.IsNullOrEmpty(info.Name) ? type.Name : info.Name;
|
||||||
if (_configObjects.TryGetValue(name, out var value))
|
}
|
||||||
{
|
Cache[type] = name;
|
||||||
return (T) value;
|
return name;
|
||||||
}
|
}
|
||||||
T result;
|
|
||||||
if (_configs.TryGetValue(name, out var jObject))
|
public T Get<T>() where T : class, IConfigItem, new()
|
||||||
{
|
{
|
||||||
result = jObject.ToObject<T>();
|
var name = GetConfigItemName(typeof(T));
|
||||||
}
|
if (_configObjects.TryGetValue(name, out var value))
|
||||||
else
|
{
|
||||||
{
|
return (T) value;
|
||||||
result = new T();
|
}
|
||||||
}
|
T result;
|
||||||
_configObjects[name] = result;
|
if (_configs.TryGetValue(name, out var jObject))
|
||||||
return result;
|
{
|
||||||
}
|
result = jObject.ToObject<T>();
|
||||||
|
}
|
||||||
public void Reset<T>()
|
else
|
||||||
{
|
{
|
||||||
var name = GetConfigName(typeof(T));
|
result = new T();
|
||||||
_configs.Remove(name);
|
}
|
||||||
_configObjects.Remove(name);
|
_configObjects[name] = result;
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
public void Clear()
|
|
||||||
{
|
public void Reset<T>() where T : class, IConfigItem, new()
|
||||||
_configs.Clear();
|
{
|
||||||
_configObjects.Clear();
|
var name = GetConfigItemName(typeof(T));
|
||||||
}
|
_configs.Remove(name);
|
||||||
|
_configObjects.Remove(name);
|
||||||
public void Load()
|
}
|
||||||
{
|
|
||||||
_configs.Clear();
|
public void Clear()
|
||||||
_configObjects.Clear();
|
{
|
||||||
if (!File.Exists(configPath)) return;
|
_configs.Clear();
|
||||||
var configJson = File.ReadAllText(configPath);
|
_configObjects.Clear();
|
||||||
var config = JObject.Parse(configJson);
|
}
|
||||||
foreach (var kv in config)
|
|
||||||
{
|
public void ReLoad()
|
||||||
_configs[kv.Key] = kv.Value.ToObject<JObject>();
|
{
|
||||||
}
|
_configs.Clear();
|
||||||
}
|
_configObjects.Clear();
|
||||||
|
if (!File.Exists(configPath)) return;
|
||||||
public void Save()
|
var configJson = File.ReadAllText(configPath);
|
||||||
{
|
var config = JObject.Parse(configJson);
|
||||||
foreach (var config in _configObjects)
|
foreach (var kv in config)
|
||||||
{
|
{
|
||||||
_configs[config.Key] = JObject.FromObject(config.Value);
|
_configs[kv.Key] = kv.Value.ToObject<JObject>();
|
||||||
}
|
}
|
||||||
File.WriteAllText(configPath, JsonConvert.SerializeObject(_configs, Formatting.Indented));
|
}
|
||||||
}
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
foreach (var config in _configObjects)
|
||||||
|
{
|
||||||
|
_configs[config.Key] = JObject.FromObject(config.Value);
|
||||||
|
}
|
||||||
|
File.WriteAllText(configPath, JsonConvert.SerializeObject(_configs, Formatting.Indented));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreateEmptyConfig()
|
||||||
|
{
|
||||||
|
var configItemTypes = AppDomain.CurrentDomain.GetAssemblies()
|
||||||
|
.SelectMany(assembly =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return assembly.GetTypes();
|
||||||
|
}
|
||||||
|
catch (ReflectionTypeLoadException)
|
||||||
|
{
|
||||||
|
return Array.Empty<Type>();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.Where(type => type.IsClass &&
|
||||||
|
!type.IsAbstract &&
|
||||||
|
typeof(IConfigItem).IsAssignableFrom(type))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var configs = new Dictionary<string, JObject>();
|
||||||
|
foreach (var type in configItemTypes)
|
||||||
|
{
|
||||||
|
var name = GetConfigItemName(type);
|
||||||
|
configs[name] = JObject.FromObject(Activator.CreateInstance(type));
|
||||||
|
}
|
||||||
|
File.WriteAllText("config_default.json", JsonConvert.SerializeObject(configs, Formatting.Indented));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
7
Src/Config/ConfigSchema/ProxyConfig.cs
Normal file
7
Src/Config/ConfigSchema/ProxyConfig.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace BangumiRenamer.Config;
|
||||||
|
|
||||||
|
[ConfigItem("Proxy")]
|
||||||
|
public class ProxyConfig : IConfigItem
|
||||||
|
{
|
||||||
|
public string HttpProxy = "";
|
||||||
|
}
|
||||||
7
Src/Config/ConfigSchema/TMDBConfig.cs
Normal file
7
Src/Config/ConfigSchema/TMDBConfig.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace BangumiRenamer.Config;
|
||||||
|
|
||||||
|
[ConfigItem("TMDB")]
|
||||||
|
public class TMDBConfig : IConfigItem
|
||||||
|
{
|
||||||
|
public string ApiKey = "";
|
||||||
|
}
|
||||||
3
Src/Config/IConfigItem.cs
Normal file
3
Src/Config/IConfigItem.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace BangumiRenamer.Config;
|
||||||
|
|
||||||
|
public interface IConfigItem;
|
||||||
@ -1,15 +0,0 @@
|
|||||||
namespace BangumiRenamer.ConfigManager;
|
|
||||||
|
|
||||||
public class ConfigItemAttribute : Attribute
|
|
||||||
{
|
|
||||||
public string Name;
|
|
||||||
|
|
||||||
public ConfigItemAttribute()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConfigItemAttribute(string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
13
Src/Entity/Show.cs
Normal file
13
Src/Entity/Show.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace BangumiRenamer.Data;
|
||||||
|
|
||||||
|
public class Show
|
||||||
|
{
|
||||||
|
public string title;
|
||||||
|
public List<Session> sessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Session
|
||||||
|
{
|
||||||
|
public int id;
|
||||||
|
public List<int> episodes;
|
||||||
|
}
|
||||||
@ -1,16 +1,5 @@
|
|||||||
using BangumiRenamer.Utils;
|
class Program
|
||||||
|
|
||||||
class Program
|
|
||||||
{
|
{
|
||||||
public static void PrintResNames()
|
|
||||||
{
|
|
||||||
var names = ResourceLoader.GetAllResNames();
|
|
||||||
foreach (var name in names)
|
|
||||||
{
|
|
||||||
Console.WriteLine(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Main()
|
static void Main()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
15
Src/Tools/EmbededResourceViewer.cs
Normal file
15
Src/Tools/EmbededResourceViewer.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using BangumiRenamer.Utils;
|
||||||
|
|
||||||
|
namespace BangumiRenamer.Tools;
|
||||||
|
|
||||||
|
public class EmbededResourceViewer
|
||||||
|
{
|
||||||
|
public static void PrintResourceNames()
|
||||||
|
{
|
||||||
|
var names = ResourceLoader.GetAllResNames();
|
||||||
|
foreach (var name in names)
|
||||||
|
{
|
||||||
|
Console.WriteLine(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,7 +13,7 @@ public static class FolderCloner
|
|||||||
|
|
||||||
result = Dialog.FolderPicker();
|
result = Dialog.FolderPicker();
|
||||||
if (!result.IsOk) return;
|
if (!result.IsOk) return;
|
||||||
var dest = Path.Combine(result.Path, Path.GetFileNameWithoutExtension(source));
|
var dest = Path.Combine(result.Path, Path.GetFileNameWithoutExtension(source.Replace("\\\\", "")));
|
||||||
|
|
||||||
var finalDest = dest;
|
var finalDest = dest;
|
||||||
int suffix = 1;
|
int suffix = 1;
|
||||||
|
|||||||
95
Src/Tools/ShowCompletionChecker.cs
Normal file
95
Src/Tools/ShowCompletionChecker.cs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
namespace BangumiRenamer.Tools;
|
||||||
|
|
||||||
|
using Config;
|
||||||
|
using TMDbLib.Client;
|
||||||
|
using Data;
|
||||||
|
using NativeFileDialogSharp;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
public static class ShowCompletionChecker
|
||||||
|
{
|
||||||
|
static List<Show> FindShows(string checkPath)
|
||||||
|
{
|
||||||
|
var shows = new List<Show>();
|
||||||
|
var showPaths = Directory.GetDirectories(checkPath);
|
||||||
|
foreach (var showPath in showPaths)
|
||||||
|
{
|
||||||
|
var sessions = new List<Session>();
|
||||||
|
var sessionPaths = Directory.GetDirectories(showPath);
|
||||||
|
foreach (var sessionPath in sessionPaths)
|
||||||
|
{
|
||||||
|
var episodePaths = Directory.GetFiles(sessionPath);
|
||||||
|
HashSet<int> episodes = new HashSet<int>();
|
||||||
|
foreach (var episodePath in episodePaths)
|
||||||
|
{
|
||||||
|
var matches = Regex.Matches(episodePath, @".*S\d+E(\d+).*");
|
||||||
|
if (matches.Count == 0) continue;
|
||||||
|
var episode = int.Parse(matches[0].Groups[1].Value);
|
||||||
|
episodes.Add(episode);
|
||||||
|
}
|
||||||
|
var session = new Session
|
||||||
|
{
|
||||||
|
id = int.Parse(Path.GetFileName(sessionPath).Replace("Season ", "")),
|
||||||
|
episodes = episodes.ToList()
|
||||||
|
};
|
||||||
|
sessions.Add(session);
|
||||||
|
}
|
||||||
|
shows.Add(new Show
|
||||||
|
{
|
||||||
|
title = Path.GetFileName(showPath),
|
||||||
|
sessions = sessions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return shows;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void Run()
|
||||||
|
{
|
||||||
|
var dir = Dialog.FolderPicker();
|
||||||
|
if (!dir.IsOk) return;
|
||||||
|
var checkPath = dir.Path;
|
||||||
|
|
||||||
|
var shows = FindShows(checkPath);
|
||||||
|
Console.WriteLine($"Total Shows: {shows.Count}");
|
||||||
|
|
||||||
|
var client = new TMDbClient(
|
||||||
|
apiKey: Config.Default.Get<TMDBConfig>().ApiKey ,
|
||||||
|
proxy: new WebProxy(Config.Default.Get<ProxyConfig>().HttpProxy));
|
||||||
|
|
||||||
|
var output = new StringBuilder();
|
||||||
|
foreach (var t in shows)
|
||||||
|
{
|
||||||
|
var match = Regex.Match(t.title, @"(.*) \((\d{4})\)");
|
||||||
|
var title = match.Groups[1].Value;
|
||||||
|
var year = int.Parse(match.Groups[2].Value);
|
||||||
|
var result = client.SearchTvShowAsync(title, firstAirDateYear: year).Result;
|
||||||
|
var info = result.Results.FirstOrDefault();
|
||||||
|
if (info == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"找不到对应的TV:{t.title}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (var session in t.sessions)
|
||||||
|
{
|
||||||
|
var sessionInfo = client.GetTvSeasonAsync(info.Id, session.id).Result;
|
||||||
|
if (sessionInfo == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"季度对不上,可能找错了:{t.title} -> {info.OriginalName}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
foreach (var episode in sessionInfo.Episodes)
|
||||||
|
{
|
||||||
|
if (DateTime.Now.AddDays(-7) < episode.AirDate) continue;
|
||||||
|
if (!session.episodes.Contains(episode.EpisodeNumber))
|
||||||
|
{
|
||||||
|
output.AppendLine($"{title} 的第 {session.id} 季少了第 {episode.EpisodeNumber} 集");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.Write(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user