Modified ffmpeg arguments and added argument checks.

This commit is contained in:
Michael Bucari-Tovo 2021-06-27 18:24:44 -06:00
parent e32a39085f
commit b53aabe0e3
4 changed files with 84 additions and 76 deletions

View File

@ -46,9 +46,8 @@ namespace AaxDecrypter
private TagLib.Mpeg4.File aaxcTagLib { get; set; }
private StepSequence steps { get; }
private DownloadLicense downloadLicense { get; set; }
private string metadataPath => Path.Combine(outDir, Path.GetFileName(outputFileName) + ".ffmeta");
public static async Task<AaxcDownloadConverter> CreateAsync(string outDirectory, DownloadLicense dlLic, ChapterInfo chapters)
public static async Task<AaxcDownloadConverter> CreateAsync(string outDirectory, DownloadLicense dlLic, ChapterInfo chapters = null)
{
var converter = new AaxcDownloadConverter(outDirectory, dlLic, chapters);
await converter.prelimProcessing();
@ -59,7 +58,6 @@ namespace AaxDecrypter
{
ArgumentValidator.EnsureNotNullOrWhiteSpace(outDirectory, nameof(outDirectory));
ArgumentValidator.EnsureNotNull(dlLic, nameof(dlLic));
ArgumentValidator.EnsureNotNull(chapters, nameof(chapters));
if (!Directory.Exists(outDirectory))
throw new ArgumentNullException(nameof(outDirectory), "Directory does not exist");
@ -134,27 +132,35 @@ namespace AaxDecrypter
public bool Step2_DownloadAndCombine()
{
var ffmetaHeader = $";FFMETADATA1\n";
File.WriteAllText(metadataPath, ffmetaHeader + chapters.ToFFMeta());
var aaxcProcesser = new FFMpegAaxcProcesser(DecryptSupportLibraries.ffmpegPath);
aaxcProcesser.ProgressUpdate += AaxcProcesser_ProgressUpdate;
string metadataPath = null;
if (chapters != null)
{
//Only write chaopters to the metadata file. All other aaxc metadata will be
//wiped out but is restored in Step 3.
metadataPath = Path.Combine(outDir, Path.GetFileName(outputFileName) + ".ffmeta");
File.WriteAllText(metadataPath, chapters.ToFFMeta(true));
}
aaxcProcesser.ProcessBook(
downloadLicense.DownloadUrl,
downloadLicense.UserAgent,
downloadLicense.AudibleKey,
downloadLicense.AudibleIV,
metadataPath,
outputFileName)
outputFileName,
metadataPath)
.GetAwaiter()
.GetResult();
if (chapters != null)
FileExt.SafeDelete(metadataPath);
DecryptProgressUpdate?.Invoke(this, 0);
FileExt.SafeDelete(metadataPath);
return aaxcProcesser.Succeeded;
}
@ -165,6 +171,10 @@ namespace AaxDecrypter
DecryptProgressUpdate?.Invoke(this, (int)progressPercent);
}
/// <summary>
/// Copy all aacx metadata to m4b file.
/// </summary>
/// <returns></returns>
public bool Step3_RestoreMetadata()
{
var outFile = new TagLib.Mpeg4.File(outputFileName, TagLib.ReadStyle.Average);

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using Dinah.Core;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -11,11 +12,16 @@ namespace AaxDecrypter
public int Count => _chapterList.Count;
public void AddChapter(Chapter chapter)
{
ArgumentValidator.EnsureNotNull(chapter, nameof(chapter));
_chapterList.Add(chapter);
}
public string ToFFMeta()
public string ToFFMeta(bool includeFFMetaHeader)
{
var ffmetaChapters = new StringBuilder();
if (includeFFMetaHeader)
ffmetaChapters.AppendLine(";FFMETADATA1\n");
foreach (var c in Chapters)
{
ffmetaChapters.AppendLine(c.ToFFMeta());
@ -30,6 +36,10 @@ namespace AaxDecrypter
public long EndOffsetMs { get; }
public Chapter(string title, long startOffsetMs, long lengthMs)
{
ArgumentValidator.EnsureNotNullOrEmpty(title, nameof(title));
ArgumentValidator.EnsureGreaterThan(startOffsetMs, nameof(startOffsetMs), -1);
ArgumentValidator.EnsureGreaterThan(lengthMs, nameof(lengthMs), 0);
Title = title;
StartOffsetMs = startOffsetMs;
EndOffsetMs = StartOffsetMs + lengthMs;

View File

@ -1,4 +1,5 @@
using System;
using Dinah.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -15,6 +16,11 @@ namespace AaxDecrypter
public DownloadLicense(string downloadUrl, string audibleKey, string audibleIV, string userAgent)
{
ArgumentValidator.EnsureNotNullOrEmpty(downloadUrl, nameof(downloadUrl));
ArgumentValidator.EnsureNotNullOrEmpty(audibleKey, nameof(audibleKey));
ArgumentValidator.EnsureNotNullOrEmpty(audibleIV, nameof(audibleIV));
ArgumentValidator.EnsureNotNullOrEmpty(userAgent, nameof(userAgent));
DownloadUrl = downloadUrl;
AudibleKey = audibleKey;
AudibleIV = audibleIV;

View File

@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@ -15,17 +16,20 @@ namespace AaxDecrypter
public string FFMpegPath { get; }
public bool IsRunning { get; private set; }
public bool Succeeded { get; private set; }
public string FFMpegStandardError => ffmpegError.ToString();
private StringBuilder ffmpegError = new StringBuilder();
private static Regex processedTimeRegex = new Regex("time=(\\d{2}):(\\d{2}):(\\d{2}).\\d{2}", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public FFMpegAaxcProcesser(string ffmpegPath)
{
FFMpegPath = ffmpegPath;
}
public async Task ProcessBook(string aaxcUrl, string userAgent, string audibleKey, string audibleIV, string outputFile)
public async Task ProcessBook(string aaxcUrl, string userAgent, string audibleKey, string audibleIV, string outputFile, string metadataPath = null)
{
//This process gets the aaxc from the url and streams the decrypted
//m4b to the output file. Preserves album art, and ignores metadata.
//m4b to the output file.
var StartInfo = new ProcessStartInfo
{
FileName = FFMpegPath,
@ -34,71 +38,47 @@ namespace AaxDecrypter
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
WorkingDirectory = Path.GetDirectoryName(FFMpegPath),
ArgumentList =
{
"-audible_key",
audibleKey,
"-audible_iv",
audibleIV,
"-user_agent",
userAgent,
"-i",
aaxcUrl,
"-c", //audio codec
"copy", //copy stream
"-f", //force output format: adts
"mp4",
outputFile, //pipe output to standard output
"-y"
}
};
await ProcessBool(StartInfo);
}
public async Task ProcessBook(string aaxcUrl, string userAgent, string audibleKey, string audibleIV, string metadataPath, string outputFile)
{
//This process gets the aaxc from the url and streams the decrypted
//m4b to the output file. Preserves album art, but replaces metadata.
var StartInfo = new ProcessStartInfo
if (metadataPath != null)
{
FileName = FFMpegPath,
RedirectStandardError = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
WorkingDirectory = Path.GetDirectoryName(FFMpegPath),
ArgumentList =
{
"-ignore_chapters", //prevents ffmpeg from copying chapter info from aaxc to output file
"true",
"-audible_key",
audibleKey,
"-audible_iv",
audibleIV,
"-user_agent",
userAgent,
"-i",
aaxcUrl,
"-f",
"ffmetadata",
"-i",
metadataPath,
"-map_metadata",
"1",
"-c", //audio codec
"copy", //copy stream
"-f", //force output format: adts
"mp4",
outputFile, //pipe output to standard output
"-y"
}
};
await ProcessBool(StartInfo);
StartInfo.ArgumentList.Add("-ignore_chapters"); //prevents ffmpeg from copying chapter info from aaxc to output file
StartInfo.ArgumentList.Add("true");
}
StartInfo.ArgumentList.Add("-audible_key");
StartInfo.ArgumentList.Add(audibleKey);
StartInfo.ArgumentList.Add("-audible_iv");
StartInfo.ArgumentList.Add(audibleIV);
StartInfo.ArgumentList.Add("-user_agent");
StartInfo.ArgumentList.Add(userAgent);
StartInfo.ArgumentList.Add("-i");
StartInfo.ArgumentList.Add(aaxcUrl);
if (metadataPath != null)
{
StartInfo.ArgumentList.Add("-f");
StartInfo.ArgumentList.Add("ffmetadata");
StartInfo.ArgumentList.Add("-i");
StartInfo.ArgumentList.Add(metadataPath);
StartInfo.ArgumentList.Add("-map_metadata");
StartInfo.ArgumentList.Add("1");
}
StartInfo.ArgumentList.Add("-c"); //copy all codecs to output
StartInfo.ArgumentList.Add("copy");
StartInfo.ArgumentList.Add("-f"); //force output format: mp4
StartInfo.ArgumentList.Add("mp4");
StartInfo.ArgumentList.Add("-movflags"); //don't add nero format chapter flags
StartInfo.ArgumentList.Add("disable_chpl+faststart");
StartInfo.ArgumentList.Add(outputFile);
StartInfo.ArgumentList.Add("-y"); //overwrite existing file
await ProcessBook(StartInfo);
}
private async Task ProcessBool(ProcessStartInfo startInfo)
private async Task ProcessBook(ProcessStartInfo startInfo)
{
var downloader = new Process
{
@ -124,6 +104,8 @@ namespace AaxDecrypter
if (string.IsNullOrEmpty(e.Data))
return;
ffmpegError.AppendLine(e.Data);
if (processedTimeRegex.IsMatch(e.Data))
{
//get timestamp of of last processed audio stream position