2020-08-17 01:06:06 +02:00
|
|
|
|
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) {
|
2021-02-21 01:23:01 +01:00
|
|
|
|
if (args.Length != 3 || args[0] != "albums" && args[0] != "playlists") {
|
2020-08-17 01:06:06 +02:00
|
|
|
|
Console.WriteLine("Usage: autotag <albums/playlists> <inputfolder> <outputfolder>");
|
|
|
|
|
Environment.Exit(1);
|
|
|
|
|
}
|
2021-02-21 01:13:45 +01:00
|
|
|
|
|
2020-08-17 01:06:06 +02:00
|
|
|
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
|
|
|
|
|
|
|
|
|
var type = args[0] == "albums" ? FolderType.Albums : FolderType.Playlists;
|
2021-02-21 01:13:45 +01:00
|
|
|
|
|
|
|
|
|
var inputDir = new Folder(args[1], type);
|
2020-08-17 01:06:06 +02:00
|
|
|
|
var outputDir = args[2];
|
|
|
|
|
|
|
|
|
|
switch (inputDir.Type) {
|
|
|
|
|
case FolderType.Albums: {
|
2021-02-21 01:13:45 +01:00
|
|
|
|
foreach (var track in Directory.EnumerateFiles(inputDir.Path, "*.*", SearchOption.AllDirectories)
|
|
|
|
|
.Where(IsAllowed)) {
|
|
|
|
|
Console.WriteLine("<- " + track);
|
|
|
|
|
var tagFile = TagFile.Create(track);
|
2020-08-17 01:06:06 +02:00
|
|
|
|
if (tagFile.Tag.AlbumArtists.Length == 0)
|
|
|
|
|
tagFile.Tag.AlbumArtists = new[] {tagFile.Tag.Performers[0]};
|
2021-02-21 01:13:45 +01:00
|
|
|
|
var outputFileDirectory = Path.Combine(outputDir, CleanFileName(tagFile.Tag.AlbumArtists[0]),
|
|
|
|
|
CleanFileName(tagFile.Tag.Album));
|
2020-08-17 01:06:06 +02:00
|
|
|
|
Directory.CreateDirectory(outputFileDirectory);
|
2021-02-21 01:13:45 +01:00
|
|
|
|
var outputFilePath = Path.Combine(outputDir, CleanFileName(tagFile.Tag.AlbumArtists[0]),
|
|
|
|
|
CleanFileName(tagFile.Tag.Album),
|
2020-08-17 01:06:06 +02:00
|
|
|
|
CleanFileName($"{tagFile.Tag.Track}. {tagFile.Tag.Performers[0]} - {tagFile.Tag.Title}{Path.GetExtension(track)}"));
|
|
|
|
|
if (tagFile.Tag.Disc != 0 && tagFile.Tag.Disc != 1) {
|
2021-02-21 01:13:45 +01:00
|
|
|
|
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)}"));
|
2020-08-17 01:06:06 +02:00
|
|
|
|
}
|
2021-02-21 01:13:45 +01:00
|
|
|
|
|
2020-08-17 01:06:06 +02:00
|
|
|
|
File.Copy(track, outputFilePath, true);
|
|
|
|
|
var newTagFile = TagFile.Create(outputFilePath);
|
|
|
|
|
newTagFile.Tag.Comment = null;
|
2021-02-21 01:13:45 +01:00
|
|
|
|
newTagFile.Tag.Genres = null;
|
2020-08-17 01:06:06 +02:00
|
|
|
|
newTagFile.Save();
|
|
|
|
|
Console.WriteLine("-> " + outputFilePath);
|
|
|
|
|
Console.WriteLine();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case FolderType.Playlists: {
|
|
|
|
|
foreach (var playlist in Directory.GetDirectories(inputDir.Path)) {
|
2021-02-21 01:13:45 +01:00
|
|
|
|
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);
|
|
|
|
|
|
2020-08-17 01:06:06 +02:00
|
|
|
|
foreach (var track in tracks) {
|
|
|
|
|
Console.WriteLine("<- " + track);
|
2021-02-21 01:13:45 +01:00
|
|
|
|
var tagFile = TagFile.Create(track);
|
|
|
|
|
var outputFileDirectory =
|
|
|
|
|
Path.Combine(outputDir, "Various Artists", CleanFileName(playlistName));
|
2020-08-17 01:06:06 +02:00
|
|
|
|
Directory.CreateDirectory(outputFileDirectory);
|
2021-02-21 01:13:45 +01:00
|
|
|
|
|
2020-08-17 01:06:06 +02:00
|
|
|
|
var outputFilePath = Path.Combine(outputDir, "Various Artists", CleanFileName(playlistName),
|
2021-02-21 01:23:01 +01:00
|
|
|
|
CleanFileName(tagFile.Tag.Performers.Length == 0
|
2021-02-21 01:13:45 +01:00
|
|
|
|
? $"{i}. {tagFile.Tag.Title}{Path.GetExtension(track)}"
|
2021-02-21 01:23:01 +01:00
|
|
|
|
: $"{i}. {tagFile.Tag.Performers[0]} - {tagFile.Tag.Title}{Path.GetExtension(track)}"));
|
2020-08-17 01:06:06 +02:00
|
|
|
|
File.Copy(track, outputFilePath, true);
|
|
|
|
|
var newTagFile = TagFile.Create(outputFilePath);
|
2021-02-21 01:13:45 +01:00
|
|
|
|
newTagFile.Tag.Comment = null;
|
|
|
|
|
newTagFile.Tag.Genres = null;
|
|
|
|
|
newTagFile.Tag.Album = playlistName;
|
|
|
|
|
newTagFile.Tag.Track = i++;
|
|
|
|
|
newTagFile.Tag.TrackCount = (uint) trackCount;
|
2020-08-17 01:06:06 +02:00
|
|
|
|
newTagFile.Tag.AlbumArtists = new[] {"Various Artists"};
|
2021-02-21 01:13:45 +01:00
|
|
|
|
|
2021-02-21 01:23:01 +01:00
|
|
|
|
if (newTagFile.Tag.Performers.Length == 0)
|
|
|
|
|
newTagFile.Tag.Performers = new[] {"Various Artists"};
|
|
|
|
|
|
2020-08-17 01:06:06 +02:00
|
|
|
|
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<string> AllowedFileTypes = new List<string> {".flac", ".opus", ".mp3", ".m4a"};
|
|
|
|
|
|
|
|
|
|
internal static bool IsAllowed(string filename) => AllowedFileTypes.Any(filename.EndsWith);
|
|
|
|
|
|
|
|
|
|
internal static string CleanFileName(string fileName) {
|
2021-02-21 01:13:45 +01:00
|
|
|
|
return Path.GetInvalidFileNameChars()
|
|
|
|
|
.Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty))
|
|
|
|
|
.Replace(":", " -")
|
|
|
|
|
.Replace("\\", " ");
|
|
|
|
|
|
2020-08-17 01:06:06 +02:00
|
|
|
|
//var tempBytes = Encoding.GetEncoding("ISO-8859-8").GetBytes(str);
|
|
|
|
|
//return Encoding.UTF8.GetString(tempBytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|