using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using static AutoTag.cli.Helpers; using TagFile = TagLib.File; namespace AutoTag.cli { internal static class AutoTag { private static void Main(string[] args) { if (args.Length != 3 || (args[0] != "albums" && args[0] != "playlists")) { Console.WriteLine("Usage: autotag "); Environment.Exit(1); } Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); var type = args[0] == "albums" ? FolderType.Albums : FolderType.Playlists; var inputDir = new Folder(args[1], type); var outputDir = args[2]; switch (inputDir.Type) { case FolderType.Albums: { foreach (var track in Directory.EnumerateFiles(inputDir.Path, "*.*", SearchOption.AllDirectories).Where(IsAllowed)) { Console.WriteLine("<- " + track); var tagFile = TagFile.Create(track); if (tagFile.Tag.AlbumArtists.Length == 0) tagFile.Tag.AlbumArtists = new[] {tagFile.Tag.Performers[0]}; var outputFileDirectory = Path.Combine(outputDir, CleanFileName(tagFile.Tag.AlbumArtists[0]), CleanFileName(tagFile.Tag.Album)); Directory.CreateDirectory(outputFileDirectory); var outputFilePath = Path.Combine(outputDir, CleanFileName(tagFile.Tag.AlbumArtists[0]), CleanFileName(tagFile.Tag.Album), CleanFileName($"{tagFile.Tag.Track}. {tagFile.Tag.Performers[0]} - {tagFile.Tag.Title}{Path.GetExtension(track)}")); if (tagFile.Tag.Disc != 0 && tagFile.Tag.Disc != 1) { outputFilePath = Path.Combine(outputDir, CleanFileName(tagFile.Tag.AlbumArtists[0]), CleanFileName(tagFile.Tag.Album), CleanFileName($"Disc{tagFile.Tag.Disc} - {tagFile.Tag.Track}. {tagFile.Tag.Performers[0]} - {tagFile.Tag.Title}{Path.GetExtension(track)}")); } File.Copy(track, outputFilePath, true); var newTagFile = TagFile.Create(outputFilePath); newTagFile.Tag.Comment = null; newTagFile.Tag.Genres = null; newTagFile.Save(); Console.WriteLine("-> " + outputFilePath); Console.WriteLine(); } break; } case FolderType.Playlists: { foreach (var playlist in Directory.GetDirectories(inputDir.Path)) { var tracks = Directory.EnumerateFiles(playlist, "*.*", SearchOption.AllDirectories).Where(IsAllowed).OrderBy(s => s, new AlphanumComparator()); uint i = 1; var trackCount = tracks.Count(); var playlistName = Path.GetFileName(playlist); foreach (var track in tracks) { Console.WriteLine("<- " + track); var tagFile = TagFile.Create(track); var outputFileDirectory = Path.Combine(outputDir, "Various Artists", CleanFileName(playlistName)); Directory.CreateDirectory(outputFileDirectory); var outputFilePath = Path.Combine(outputDir, "Various Artists", CleanFileName(playlistName), CleanFileName((tagFile.Tag.Performers.Length == 0 ? $"{i}. {tagFile.Tag.Title}{Path.GetExtension(track)}" : $"{i}. {tagFile.Tag.Performers[0]} - {tagFile.Tag.Title}{Path.GetExtension(track)}"))); File.Copy(track, outputFilePath, true); var newTagFile = TagFile.Create(outputFilePath); newTagFile.Tag.Comment = null; newTagFile.Tag.Genres = null; newTagFile.Tag.Album = playlistName; newTagFile.Tag.Track = i++; newTagFile.Tag.TrackCount = (uint) trackCount; newTagFile.Tag.AlbumArtists = new[] {"Various Artists"}; newTagFile.Save(); Console.WriteLine("-> " + outputFilePath); Console.WriteLine(); } } break; } default: throw new ArgumentOutOfRangeException(); } } } internal class Folder { public readonly string Path; public readonly FolderType Type; public Folder(string path, FolderType type) { Path = path; Type = type; } } internal enum FolderType { Albums, Playlists } internal static class Helpers { private static readonly List AllowedFileTypes = new List {".flac", ".opus", ".mp3", ".m4a"}; internal static bool IsAllowed(string filename) => AllowedFileTypes.Any(filename.EndsWith); internal static string CleanFileName(string fileName) { return Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty)) .Replace(":", " -"); //var tempBytes = Encoding.GetEncoding("ISO-8859-8").GetBytes(str); //return Encoding.UTF8.GetString(tempBytes); } } }