BangumiRenamer/ShowsManager.cs
2025-05-13 01:31:17 +08:00

226 lines
7.0 KiB
C#

using System.Net;
using Newtonsoft.Json;
using TMDbLib.Client;
namespace ConsoleApp1;
public class ShowSession
{
public string session;
public List<EpisodeInfo> extras = new List<EpisodeInfo>();
public List<EpisodeInfo> episodes = new List<EpisodeInfo>();
}
public class Show
{
public string rawTitle;
public string title;
public string year;
public string tmdbId;
public List<ShowSession> sessions = new List<ShowSession>();
}
public class ShowsManager
{
private List<Show> _shows = new List<Show>();
private TMDbClient _client;
public ShowsManager()
{
_client = new TMDbClient("991107af25913562cfa06622a52873e1", proxy: new WebProxy("http://127.0.0.1:7897"));
}
private static Show FindOrCreateShow(List<Show> shows, string rawTitle)
{
foreach (var show in shows)
{
if (show.rawTitle == rawTitle)
{
return show;
}
}
var result = new Show();
result.rawTitle = rawTitle;
shows.Add(result);
return result;
}
private static ShowSession FindOrCreateShowSession(List<ShowSession> sessions, string sessionNumber)
{
foreach (var session in sessions)
{
if (session.session == sessionNumber)
{
return session;
}
}
var result = new ShowSession();
result.session = sessionNumber;
sessions.Add(result);
return result;
}
private static string LCP(string str1, string str2)
{
if (string.IsNullOrEmpty(str1) || string.IsNullOrEmpty(str2))
{
return string.Empty;
}
int minLength = Math.Min(str1.Length, str2.Length);
int i = 0;
while (i < minLength && str1[i] == str2[i])
{
i++;
}
return str1.Substring(0, i);
}
public static string CalcBasePathOfSessionExtras(ShowSession session)
{
if(session.extras.Count == 0) return string.Empty;
var result = session.extras[0].path;
foreach (var extra in session.extras)
{
result = LCP(result, extra.path);
}
return result;
}
public void AppendEpisodeFromFile(string path)
{
var resultsJson = File.ReadAllText(path);
var results = JsonConvert.DeserializeObject<List<EpisodeInfo>>(resultsJson);
foreach (var episode in results)
{
AppendEpisode(episode);
}
}
public void AppendEpisode(EpisodeInfo episode)
{
var show = FindOrCreateShow(_shows, episode.name);
var session = FindOrCreateShowSession(show.sessions, episode.session);
if (episode.type == "others")
{
session.extras.Add(episode);
}
else
{
session.episodes.Add(episode);
}
}
public async Task QueryTMDB(Dictionary<string, string> mapping)
{
int current = 0;
foreach (var show in _shows)
{
current++;
Console.WriteLine($"{current}/{_shows.Count}");
var title = show.rawTitle;
if(mapping.TryGetValue(title, out var value)) title = value;
var result = await _client.SearchTvShowAsync(title, language:"zh-CN");
if (result == null || result.Results.Count == 0) continue;
var tv = result.Results[0];
show.title = tv.Name;
show.year = tv.FirstAirDate.Value.Year.ToString();
show.tmdbId = tv.Id.ToString();
}
}
public void Dump(string path)
{
var result = JsonConvert.SerializeObject(_shows, Formatting.Indented);
File.WriteAllText(path, result);
}
public void Load(string path)
{
var json = File.ReadAllText(path);
_shows = JsonConvert.DeserializeObject<List<Show>>(json);
}
private string AddZero(string s)
{
if(s.Length == 1) return $"0{s}";
return s;
}
private string AddNumberToFileName(string path, int n)
{
return Path.Combine(Path.GetDirectoryName(path)??"",
Path.GetFileNameWithoutExtension(path) + $"({n})" + Path.GetExtension(path));
}
public void MoveFiles(string basePath, string targetBasePath)
{
HashSet<string> files = new HashSet<string>();
Queue<(string, string)> moves = new Queue<(string, string)>();
foreach (var show in _shows)
{
foreach (var session in show.sessions)
{
foreach (var episode in session.episodes)
{
var oldPath = Path.Combine(basePath, episode.path);
var newSubPath = $"{show.title} ({show.year})/Season {session.session}/{show.title} ({show.year}) S{AddZero(episode.session)}E{AddZero(episode.episode)} [{episode.group}]";
if (episode.type == "subtitle" && !string.IsNullOrEmpty(episode.language))
{
newSubPath += $".{episode.language}";
}
newSubPath += Path.GetExtension(episode.path);
var newPath = Path.Combine(targetBasePath, newSubPath);
var testPath = newPath;
int n = 0;
while (files.Contains(testPath))
{
testPath = AddNumberToFileName(newPath, ++n);
}
newPath = testPath;
files.Add(newPath);
moves.Enqueue((oldPath, newPath));
Console.WriteLine($"{oldPath} -> {newPath}");
}
var extraPath = CalcBasePathOfSessionExtras(session);
foreach (var episode in session.extras)
{
var oldPath = Path.Combine(basePath, episode.path);
var newSubPath = $"{show.title} ({show.year})/Season {session.session}/extras";
var subPath = episode.path.Substring(extraPath.Length);
var newPath = Path.Combine(targetBasePath, newSubPath, subPath);
var testPath = newPath;
int n = 0;
while (files.Contains(testPath))
{
testPath = AddNumberToFileName(newPath, ++n);
}
newPath = testPath;
files.Add(newPath);
moves.Enqueue((oldPath, newPath));
Console.WriteLine($"{oldPath} -> {newPath}");
}
}
}
while (moves.Count > 0)
{
var move = moves.Dequeue();
if (!File.Exists(move.Item1)) continue;
Directory.CreateDirectory(Path.GetDirectoryName(move.Item2));
File.Move(move.Item1, move.Item2);
Console.WriteLine($"{move.Item1} -> {move.Item2}");
}
}
}