/Renamer/Renamer/Form1.cs
C# | 435 lines | 335 code | 61 blank | 39 comment | 74 complexity | 624b8ff307e66ac52ae2370457d86c7d MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Linq;
- using System.Text;
- using System.Windows.Forms;
- using System.IO;
-
- namespace Renamer
- {
- public partial class Form1 : Form
- {
- Video[] _videos;
-
- public Form1()
- {
- InitializeComponent();
- }
-
- /// <summary>
- /// Renames all the files using the new editted values.
- /// </summary>
- private void OnRenameClick(object sender, EventArgs e)
- {
- foreach (Video video in _videos)
- {
- File.Move(video.OriginalPath, video.NewPath);
- }
- }
-
- #region Populate Data
-
- /// <summary>
- /// Opens a directory for processing.
- /// </summary>
- private void OnOpenClick(object sender, EventArgs args)
- {
- OpenFileDialog dialog = new OpenFileDialog();
- DialogResult dialogResult = dialog.ShowDialog();
- if (dialogResult == System.Windows.Forms.DialogResult.OK)
- {
- DirectoryInfo dir = new DirectoryInfo(Path.GetDirectoryName(dialog.FileName));
-
- _videos = FlattenDirectories(dir).SelectMany(d => ProcessFolder(d)).ToArray();
- PopulateDataGrid(_videos);
- }
- }
-
- /// <summary>
- /// Clears and repopulates the data grid with the videos.
- /// </summary>
- private void PopulateDataGrid(IEnumerable<Video> videos)
- {
- dataGrid.Rows.Clear();
- foreach (Video video in videos)
- {
- string season = video.Season == -1 ? string.Empty : video.Season.ToString();
- string episode = video.Episode == -1 ? string.Empty : video.Episode.ToString();
- dataGrid.Rows.Add(video.OriginalName, video.NewName, video.Show, season, episode);
-
- if (video.OriginalName == video.NewName)
- dataGrid.Rows[dataGrid.Rows.Count - 1].DefaultCellStyle.BackColor = Color.LightGray;
- }
- }
-
- /// <summary>
- /// Returns this directory and all descendant directories.
- /// </summary>
- private IEnumerable<DirectoryInfo> FlattenDirectories(DirectoryInfo dir)
- {
- Stack<DirectoryInfo> stack = new Stack<DirectoryInfo>();
- stack.Push(dir);
-
- while (stack.Count != 0)
- {
- DirectoryInfo current = stack.Pop();
- yield return current;
-
- foreach (DirectoryInfo child in current.GetDirectories())
- stack.Push(child);
- }
- }
-
- /// <summary>
- /// Gets the Video files from the given folder.
- /// The Show/Season/Episode values are filled in with guesses.
- /// </summary>
- private ICollection<Video> ProcessFolder(DirectoryInfo dir)
- {
- string[] files = dir.GetFiles().Select(f => f.FullName).ToArray();
- string[] names = files.Select(f => Path.GetFileNameWithoutExtension(f)).ToArray();
-
- string title = GetTitle(names);
- Tuple<int, int>[] episodes = GetEpisodeNumbers(names);
-
- List<Video> videos = new List<Video>();
- for (int i = 0; i < episodes.Length; i++)
- {
- videos.Add(new Video(title, episodes[i].Item1, episodes[i].Item2, files[i]));
- }
-
- return videos;
- }
-
- #endregion Populate Data
-
- #region Title/Episode Detection
-
- /// <summary>
- /// Guesses the title of the show given the raw input strings.
- /// </summary>
- private string GetTitle(string[] input)
- {
- List<string> names = new List<string>();
-
- // Split the name up into contiguous parts.
- // Tokens like (...), {...}, [...], and episode numbers are the delimiters.
- for (int i = 0; i < input.Length; i++)
- {
- names.AddRange(SplitName(input[i]));
- }
-
- // Use the most common value.
- Dictionary<string, int> votes = new Dictionary<string, int>();
- foreach (string name in names)
- {
- int voteCount;
- if (!votes.TryGetValue(name, out voteCount))
- {
- voteCount = 0;
- }
-
- votes[name] = voteCount + 1;
- }
-
- return votes.OrderByDescending(v => v.Value).Select(v => v.Key).FirstOrDefault();
- }
-
- /// <summary>
- /// Split the name up into contiguous parts.
- /// Tokens like (...), {...}, [...], and episode numbers are the delimiters.
- /// Replaces all seperator characters with spaces as well.
- /// </summary>
- private ICollection<string> SplitName(string input)
- {
- List<string> nonScoped = new List<string>();
-
- // Remove scopes: (..), {...}, etc.
- string scopeResult = string.Empty;
- for (int i = 0; i < input.Length; i++)
- {
- char c = input[i];
- if (c == '(')
- {
- nonScoped.Add(scopeResult);
- scopeResult = string.Empty;
- i = input.IndexOf(')', i) + 1;
- }
- else if (c == '{')
- {
- nonScoped.Add(scopeResult);
- scopeResult = string.Empty;
- i = input.IndexOf('}', i) + 1;
- }
- else if (c == '[')
- {
- nonScoped.Add(scopeResult);
- scopeResult = string.Empty;
- i = input.IndexOf(']', i) + 1;
- }
- else
- {
- scopeResult = scopeResult + c;
- }
- }
- nonScoped.Add(scopeResult);
-
- // Remove episodes
- List<string> results = new List<string>();
- foreach (string item in nonScoped)
- {
- string[] split = item.Split(Splitters, StringSplitOptions.RemoveEmptyEntries);
-
- string episodeResult = string.Empty;
- for (int i = 0; i < split.Length; i++)
- {
- if (IsEpisode(split[i]))
- {
- results.Add(episodeResult);
- episodeResult = string.Empty;
- }
- else
- {
- episodeResult += " " + split[i];
- }
- }
-
- results.Add(episodeResult);
- }
-
- return results.Where(s => !string.IsNullOrEmpty(s)).Select(s => s.Trim()).ToArray();
- }
-
- static readonly char[] Splitters = new[] { '.', '-', '_', ' ', '(', ')', '{', '}', '[', ']', ' ' };
-
- /// <summary>
- /// Gets the season and episode number for all of the given strings.
- /// </summary>
- private Tuple<int,int>[] GetEpisodeNumbers(string[] names)
- {
- Tuple<int,int>[] results = new Tuple<int,int>[names.Length];
-
- for (int i = 0; i < names.Length; i++)
- {
- string name = names[i];
- string result = string.Empty;
-
- string[] split = name.Split(Splitters, StringSplitOptions.RemoveEmptyEntries);
-
- int resultSeason = -1;
- int resultEpisode = -1;
- foreach (string piece in split)
- {
- if (TryParseEpisode(piece, out resultEpisode, out resultSeason))
- {
- break;
- }
-
- resultEpisode = -1;
- resultSeason = -1;
- }
-
- results[i] = Tuple.Create(resultSeason, resultEpisode);
- }
-
- return results;
- }
-
- private bool IsEpisode(string input)
- {
- int e, s;
- return TryParseEpisode(input, out e, out s);
- }
-
- /// <summary>
- /// Tries to parse the season and episode from the given string.
- /// </summary>
- private bool TryParseEpisode(string input, out int resultEpisode, out int resultSeason)
- {
- resultEpisode = -1;
- resultSeason = -1;
- int episode;
- int season;
-
- // "01" episode only
- if (int.TryParse(input, out episode) && episode < 1000)
- {
- // "301" Season/Episode in one number
- if (episode > 99)
- {
- resultSeason = episode / 100;
- resultEpisode = episode % 100;
- }
- else
- {
- resultEpisode = episode;
- }
- return true;
- }
-
- // "Ep01" episode only
- string[] episodeSplit = input.Split(new[] { "Episode", "Ep", "E" }, StringSplitOptions.RemoveEmptyEntries);
- if (episodeSplit.Length == 1 && int.TryParse(episodeSplit[0], out episode))
- {
- resultEpisode = episode;
- return true;
- }
-
- // "S3E01" Season/Episode
- string[] seasonSplit = input.Split(new[] { 'S', 's', 'E', 'e', 'X', 'x' }, StringSplitOptions.RemoveEmptyEntries);
- if (seasonSplit.Length == 2 && int.TryParse(seasonSplit[0], out season) && int.TryParse(seasonSplit[1], out episode))
- {
- resultSeason = season;
- resultEpisode = episode;
- return true;
- }
-
- return false;
- }
-
- #endregion Title/Episode Detection
-
- #region Editing
-
- private void UpdateSelectionEditor()
- {
- Video[] selectedVideos = this.SelectedVideos;
-
- if (selectedVideos.Length == 0)
- {
- selectedVideos = _videos;
- }
-
- showBox.Text = string.Empty;
- seasonBox.Text = string.Empty;
- episodeBox.Text = string.Empty;
- seFormatBox.Text = string.Empty;
- eFormatBox.Text = string.Empty;
-
- if (selectedVideos.Length > 0)
- {
- if (selectedVideos.All(v => v.Show == selectedVideos[0].Show))
- {
- showBox.Text = selectedVideos[0].Show;
- }
- else
- showBox.Text = "Various";
-
- if (selectedVideos.All(v => v.Season == selectedVideos[0].Season))
- {
- if (selectedVideos[0].Season != -1)
- seasonBox.Text = selectedVideos[0].Season.ToString();
- }
- else
- seasonBox.Text = "Various";
-
- if (selectedVideos.All(v => v.Episode == selectedVideos[0].Episode))
- {
- if (selectedVideos[0].Episode != -1)
- episodeBox.Text = selectedVideos[0].Episode.ToString();
- }
- else
- episodeBox.Text = "Various";
-
- if (selectedVideos.All(v => v.Format.SeasonEpisode == selectedVideos[0].Format.SeasonEpisode))
- {
- seFormatBox.Text = selectedVideos[0].Format.SeasonEpisode;
- }
- else
- seFormatBox.Text = "Various";
-
- if (selectedVideos.All(v => v.Format.EpisodeOnly == selectedVideos[0].Format.EpisodeOnly))
- {
- eFormatBox.Text = selectedVideos[0].Format.EpisodeOnly;
- }
- else
- eFormatBox.Text = "Various";
- }
- }
-
- private void dataGrid_SelectionChanged(object sender, EventArgs e)
- {
- UpdateSelectionEditor();
- }
-
- private Video[] SelectedVideos
- {
- get
- {
- return SelectedIndexes.Select(i => _videos[i]).ToArray();
- }
- }
-
- private int[] SelectedIndexes
- {
- get
- {
- List<int> indexes = new List<int>();
- for (int i = 0; i < dataGrid.SelectedRows.Count; i++)
- {
- indexes.Add(dataGrid.SelectedRows[i].Index);
- }
-
- return indexes.ToArray();
- }
- }
-
- private void editBtn_Click(object sender, EventArgs e)
- {
- int episode;
- int season;
- if (!int.TryParse(seasonBox.Text, out season))
- {
- if (string.IsNullOrEmpty(seasonBox.Text))
- season = -1;
- else if (seasonBox.Text == "Various")
- season = -2;
- else
- {
- MessageBox.Show("Season must be a number or empty.");
- return;
- }
- }
-
- if (!int.TryParse(episodeBox.Text, out episode))
- {
- if (string.IsNullOrEmpty(episodeBox.Text))
- episode = -1;
- else if (episodeBox.Text == "Various")
- episode = -2;
- else
- {
- MessageBox.Show("Episode must be a number or empty.");
- return;
- }
- }
-
- foreach (Video video in SelectedVideos)
- {
- if (showBox.Text != "Various")
- video.Show = showBox.Text;
- if (season != -2)
- video.Season = season;
- if (episode != -2)
- video.Episode = episode;
- if (seFormatBox.Text != "Various" && !string.IsNullOrEmpty(seFormatBox.Text))
- video.Format.SeasonEpisode = seFormatBox.Text;
- if (eFormatBox.Text != "Various" && !string.IsNullOrEmpty(eFormatBox.Text))
- video.Format.EpisodeOnly = eFormatBox.Text;
- }
-
- int[] indexes = SelectedIndexes;
- PopulateDataGrid(_videos);
- dataGrid.ClearSelection();
- foreach (int i in indexes)
- {
- dataGrid.Rows[i].Selected = true;
- }
- }
-
- #endregion Editing
- }
- }