|
@@ -3,7 +3,6 @@ using System.Diagnostics;
|
|
using System.IO;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Linq;
|
|
using System.Net.Mime;
|
|
using System.Net.Mime;
|
|
-using System.Reflection;
|
|
|
|
using System.Text;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Threading.Tasks;
|
|
using TagLib;
|
|
using TagLib;
|
|
@@ -53,6 +52,7 @@ namespace BatchProcess
|
|
private const string OP_CONVERT_FLAC_TO_AAC = "convert_flac_to_aac";
|
|
private const string OP_CONVERT_FLAC_TO_AAC = "convert_flac_to_aac";
|
|
private const string OP_CONVERT_LIB_FLAC_TO_AAC = "convert_lib_flac_to_aac";
|
|
private const string OP_CONVERT_LIB_FLAC_TO_AAC = "convert_lib_flac_to_aac";
|
|
private const string OP_CONVERT_LIB_FLAC_TO_AAC_IN_DIR = "convert_lib_flac_to_aac_in_dir";
|
|
private const string OP_CONVERT_LIB_FLAC_TO_AAC_IN_DIR = "convert_lib_flac_to_aac_in_dir";
|
|
|
|
+ private const string OP_CONVERT_LIB_SUBSET_TO_MP4_IN_DIR = "op_convert_lib_subset_to_mp4_in_dir";
|
|
|
|
|
|
private static void RealMain(string[] args)
|
|
private static void RealMain(string[] args)
|
|
{
|
|
{
|
|
@@ -87,6 +87,9 @@ namespace BatchProcess
|
|
Console.WriteLine($" * {OP_CONVERT_LIB_FLAC_TO_AAC_IN_DIR} <libDir> [q value]");
|
|
Console.WriteLine($" * {OP_CONVERT_LIB_FLAC_TO_AAC_IN_DIR} <libDir> [q value]");
|
|
Console.WriteLine($" Convert to aac and copy tags to output, default q is 1.0");
|
|
Console.WriteLine($" Convert to aac and copy tags to output, default q is 1.0");
|
|
Console.WriteLine($" libDir/Album/Track.flac -> libDir/Album/AAC_Q1.00/Track.m4a");
|
|
Console.WriteLine($" libDir/Album/Track.flac -> libDir/Album/AAC_Q1.00/Track.m4a");
|
|
|
|
+ Console.WriteLine($" * {OP_CONVERT_LIB_SUBSET_TO_MP4_IN_DIR} <libDir> [subset]");
|
|
|
|
+ Console.WriteLine($" Convert to mp4(static cover) and copy tags to output, default subset is AAC_Q1.00");
|
|
|
|
+ Console.WriteLine($" libDir/Album/subset/Track.m4a -> libDir/Album/subset_MP4/Track.mp4");
|
|
Console.WriteLine($"");
|
|
Console.WriteLine($"");
|
|
Console.WriteLine($" + More on demand");
|
|
Console.WriteLine($" + More on demand");
|
|
return;
|
|
return;
|
|
@@ -94,7 +97,7 @@ namespace BatchProcess
|
|
|
|
|
|
var op = args[0];
|
|
var op = args[0];
|
|
|
|
|
|
- Console.WriteLine($"OP:{op}");
|
|
|
|
|
|
+ Console.WriteLine($"OP: {op}");
|
|
|
|
|
|
var argsToOp = args.Skip(1).ToArray();
|
|
var argsToOp = args.Skip(1).ToArray();
|
|
|
|
|
|
@@ -117,11 +120,91 @@ namespace BatchProcess
|
|
case OP_CONVERT_FLAC_TO_AAC: ConvertFlacToAac(argsToOp); break;
|
|
case OP_CONVERT_FLAC_TO_AAC: ConvertFlacToAac(argsToOp); break;
|
|
case OP_CONVERT_LIB_FLAC_TO_AAC: ConvertLibFlacToAac(argsToOp); break;
|
|
case OP_CONVERT_LIB_FLAC_TO_AAC: ConvertLibFlacToAac(argsToOp); break;
|
|
case OP_CONVERT_LIB_FLAC_TO_AAC_IN_DIR: ConvertLibFlacToAacInDir(argsToOp); break;
|
|
case OP_CONVERT_LIB_FLAC_TO_AAC_IN_DIR: ConvertLibFlacToAacInDir(argsToOp); break;
|
|
|
|
+ case OP_CONVERT_LIB_SUBSET_TO_MP4_IN_DIR: ConvertLibSubsetToMp4InDir(argsToOp); break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// impl
|
|
// impl
|
|
|
|
|
|
|
|
+ private static void ConvertLibSubsetToMp4InDir(string[] args)
|
|
|
|
+ {
|
|
|
|
+ if (args.Length < 1) throw new ArgumentException("args least need 1");
|
|
|
|
+ var libDir = args[0]; var subset = args.Length > 1 ? args[1] : "AAC_Q1.00";
|
|
|
|
+
|
|
|
|
+ if (false == Directory.Exists(libDir)) throw new DirectoryNotFoundException($"lib dir `{libDir}' not found.");
|
|
|
|
+
|
|
|
|
+ foreach (var discDir in Directory.GetDirectories(libDir))
|
|
|
|
+ {
|
|
|
|
+ var subsetDir = Path.Combine(discDir, subset); if (false == Directory.Exists(subsetDir)) continue;
|
|
|
|
+
|
|
|
|
+ foreach (var track in Directory.GetFiles(subsetDir))
|
|
|
|
+ {
|
|
|
|
+ var outDir = Path.Combine(discDir, subset + "_MP4");
|
|
|
|
+ var outFile = Path.Combine(outDir, Path.GetFileNameWithoutExtension(track) + ".MP4");
|
|
|
|
+
|
|
|
|
+ if (File.Exists(outFile)) { Console.WriteLine($"SKIP: exist. `{outFile}'"); continue; }
|
|
|
|
+
|
|
|
|
+ byte[] coverBytes;
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ using var tag = TagLib.File.Create(track);
|
|
|
|
+ coverBytes = tag.Tag.Pictures.Where(p => p.Type == PictureType.FrontCover).Select(p => p.Data.ToArray()).FirstOrDefault();
|
|
|
|
+ }
|
|
|
|
+ catch (Exception e) { Console.WriteLine($"ERR: {e.Message} in `{track}'"); continue; }
|
|
|
|
+
|
|
|
|
+ if (coverBytes == null) { Console.WriteLine($"WARN: skip. no cover in `{track}'"); continue; }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ var tmp = Path.GetTempFileName();
|
|
|
|
+ File.WriteAllBytes(tmp, coverBytes);
|
|
|
|
+
|
|
|
|
+ if (Directory.Exists(outDir) == false) { Console.WriteLine($"Create dir `{outDir}'"); Directory.CreateDirectory(outDir); }
|
|
|
|
+
|
|
|
|
+ Console.WriteLine($"PROCESS: `{track}'");
|
|
|
|
+
|
|
|
|
+ var ffMpegArgs = new string[]
|
|
|
|
+ {
|
|
|
|
+ "-n","-hide_banner","-stats","-v","warning",
|
|
|
|
+ "-framerate","60",
|
|
|
|
+ "-loop","1","-i",tmp,
|
|
|
|
+ "-i",track,
|
|
|
|
+ "-map_metadata","-1","-map_chapters","-1",
|
|
|
|
+ "-shortest",
|
|
|
|
+
|
|
|
|
+ "-vf","scale=-1:480",
|
|
|
|
+
|
|
|
|
+ "-c:v","h264","-pix_fmt","yuv420p",
|
|
|
|
+ "-preset","placebo",
|
|
|
|
+ "-crf","28","-bf","1250","-g","1250","-keyint_min","250",
|
|
|
|
+
|
|
|
|
+ "-c:a","copy",
|
|
|
|
+
|
|
|
|
+ outFile
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ var process = new Process
|
|
|
|
+ {
|
|
|
|
+ StartInfo =
|
|
|
|
+ {
|
|
|
|
+ FileName = "ffmpeg",
|
|
|
|
+ CreateNoWindow = false,
|
|
|
|
+ UseShellExecute = false,
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ foreach (var item in ffMpegArgs) process.StartInfo.ArgumentList.Add(item);
|
|
|
|
+ process.Start();
|
|
|
|
+ process.PriorityClass = ProcessPriorityClass.BelowNormal;
|
|
|
|
+ process.WaitForExit();
|
|
|
|
+
|
|
|
|
+ File.Delete(tmp);//delete temp cover file
|
|
|
|
+
|
|
|
|
+ if (process.ExitCode == 0) CopyTag(new[] { track, outFile }, false);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
private static void ConvertLibFlacToAacInDir(string[] args)
|
|
private static void ConvertLibFlacToAacInDir(string[] args)
|
|
{
|
|
{
|
|
if (args.Length < 1) throw new ArgumentException("args least need 1");
|
|
if (args.Length < 1) throw new ArgumentException("args least need 1");
|
|
@@ -137,18 +220,18 @@ namespace BatchProcess
|
|
{
|
|
{
|
|
var outAlbDir = Path.Combine(albDir, $"AAC_Q{q:N2}");
|
|
var outAlbDir = Path.Combine(albDir, $"AAC_Q{q:N2}");
|
|
|
|
|
|
- if (false == Directory.Exists(outAlbDir))
|
|
|
|
- {
|
|
|
|
- Console.WriteLine($"Create dir:{outAlbDir}");
|
|
|
|
- Directory.CreateDirectory(outAlbDir);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
foreach (var flacPath in Directory.GetFiles(albDir, "*.flac"))
|
|
foreach (var flacPath in Directory.GetFiles(albDir, "*.flac"))
|
|
{
|
|
{
|
|
|
|
+ if (false == Directory.Exists(outAlbDir))
|
|
|
|
+ {
|
|
|
|
+ Console.WriteLine($"Create dir:{outAlbDir}");
|
|
|
|
+ Directory.CreateDirectory(outAlbDir);
|
|
|
|
+ }
|
|
|
|
+
|
|
var outM4APath = Path.Combine(outAlbDir, Path.ChangeExtension(Path.GetFileName(flacPath), ".m4a"));
|
|
var outM4APath = Path.Combine(outAlbDir, Path.ChangeExtension(Path.GetFileName(flacPath), ".m4a"));
|
|
Console.WriteLine(
|
|
Console.WriteLine(
|
|
- ConvertFlacToAac(new[] {flacPath, outM4APath, $"{q}"})
|
|
|
|
- ? $"Convert OK. -> {outM4APath}"
|
|
|
|
|
|
+ ConvertFlacToAac(new[] { flacPath, outM4APath, $"{q}" })
|
|
|
|
+ ? $"Convert OK. -> {outM4APath}"
|
|
: $"Exist, Skipped. {outM4APath}"
|
|
: $"Exist, Skipped. {outM4APath}"
|
|
);
|
|
);
|
|
}
|
|
}
|
|
@@ -271,7 +354,7 @@ namespace BatchProcess
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- private static void CopyTag(string[] args)
|
|
|
|
|
|
+ private static void CopyTag(string[] args, bool cover = true)
|
|
{
|
|
{
|
|
if (args.Length < 2) throw new ArgumentException("args need 2");
|
|
if (args.Length < 2) throw new ArgumentException("args need 2");
|
|
var pathIn = args[0];
|
|
var pathIn = args[0];
|
|
@@ -282,13 +365,15 @@ namespace BatchProcess
|
|
if (false == File.Exists(pathOutput)) throw new FileNotFoundException($"targetPath `{pathOutput}' not found.");
|
|
if (false == File.Exists(pathOutput)) throw new FileNotFoundException($"targetPath `{pathOutput}' not found.");
|
|
|
|
|
|
using var src = TagLib.File.Create(pathIn);
|
|
using var src = TagLib.File.Create(pathIn);
|
|
|
|
+
|
|
var dst = TagLib.File.Create(pathOutput);
|
|
var dst = TagLib.File.Create(pathOutput);
|
|
dst.Tag.Clear();
|
|
dst.Tag.Clear();
|
|
dst.Save();
|
|
dst.Save();
|
|
dst.Dispose();
|
|
dst.Dispose();
|
|
dst = TagLib.File.Create(pathOutput);
|
|
dst = TagLib.File.Create(pathOutput);
|
|
|
|
+
|
|
src.Tag.CopyTo(dst.Tag, true);
|
|
src.Tag.CopyTo(dst.Tag, true);
|
|
- dst.Tag.Pictures = src.Tag.Pictures;
|
|
|
|
|
|
+ if (cover) dst.Tag.Pictures = src.Tag.Pictures;
|
|
src.Dispose();
|
|
src.Dispose();
|
|
dst.Save();
|
|
dst.Save();
|
|
dst.Dispose();
|
|
dst.Dispose();
|