using System.Net; using Newtonsoft.Json; using TMDbLib.Client; namespace ConsoleApp1; public class ShowSession { public string session; public List extras = new List(); public List episodes = new List(); } public class Show { public string rawTitle; public string title; public string year; public string tmdbId; public List sessions = new List(); } public class ShowsManager { private List _shows = new List(); private TMDbClient _client; public ShowsManager() { _client = new TMDbClient("991107af25913562cfa06622a52873e1", proxy: new WebProxy("http://127.0.0.1:7897")); } private static Show FindOrCreateShow(List 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 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>(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 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>(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 files = new HashSet(); 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}"); } } }