Modified ffmpeg arguments and added argument checks.
This commit is contained in:
parent
e32a39085f
commit
b53aabe0e3
@ -46,9 +46,8 @@ namespace AaxDecrypter
|
|||||||
private TagLib.Mpeg4.File aaxcTagLib { get; set; }
|
private TagLib.Mpeg4.File aaxcTagLib { get; set; }
|
||||||
private StepSequence steps { get; }
|
private StepSequence steps { get; }
|
||||||
private DownloadLicense downloadLicense { get; set; }
|
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);
|
var converter = new AaxcDownloadConverter(outDirectory, dlLic, chapters);
|
||||||
await converter.prelimProcessing();
|
await converter.prelimProcessing();
|
||||||
@ -59,7 +58,6 @@ namespace AaxDecrypter
|
|||||||
{
|
{
|
||||||
ArgumentValidator.EnsureNotNullOrWhiteSpace(outDirectory, nameof(outDirectory));
|
ArgumentValidator.EnsureNotNullOrWhiteSpace(outDirectory, nameof(outDirectory));
|
||||||
ArgumentValidator.EnsureNotNull(dlLic, nameof(dlLic));
|
ArgumentValidator.EnsureNotNull(dlLic, nameof(dlLic));
|
||||||
ArgumentValidator.EnsureNotNull(chapters, nameof(chapters));
|
|
||||||
|
|
||||||
if (!Directory.Exists(outDirectory))
|
if (!Directory.Exists(outDirectory))
|
||||||
throw new ArgumentNullException(nameof(outDirectory), "Directory does not exist");
|
throw new ArgumentNullException(nameof(outDirectory), "Directory does not exist");
|
||||||
@ -134,27 +132,35 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
public bool Step2_DownloadAndCombine()
|
public bool Step2_DownloadAndCombine()
|
||||||
{
|
{
|
||||||
var ffmetaHeader = $";FFMETADATA1\n";
|
|
||||||
|
|
||||||
File.WriteAllText(metadataPath, ffmetaHeader + chapters.ToFFMeta());
|
|
||||||
|
|
||||||
var aaxcProcesser = new FFMpegAaxcProcesser(DecryptSupportLibraries.ffmpegPath);
|
var aaxcProcesser = new FFMpegAaxcProcesser(DecryptSupportLibraries.ffmpegPath);
|
||||||
|
|
||||||
aaxcProcesser.ProgressUpdate += AaxcProcesser_ProgressUpdate;
|
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(
|
aaxcProcesser.ProcessBook(
|
||||||
downloadLicense.DownloadUrl,
|
downloadLicense.DownloadUrl,
|
||||||
downloadLicense.UserAgent,
|
downloadLicense.UserAgent,
|
||||||
downloadLicense.AudibleKey,
|
downloadLicense.AudibleKey,
|
||||||
downloadLicense.AudibleIV,
|
downloadLicense.AudibleIV,
|
||||||
metadataPath,
|
outputFileName,
|
||||||
outputFileName)
|
metadataPath)
|
||||||
.GetAwaiter()
|
.GetAwaiter()
|
||||||
.GetResult();
|
.GetResult();
|
||||||
|
|
||||||
|
if (chapters != null)
|
||||||
|
FileExt.SafeDelete(metadataPath);
|
||||||
|
|
||||||
DecryptProgressUpdate?.Invoke(this, 0);
|
DecryptProgressUpdate?.Invoke(this, 0);
|
||||||
|
|
||||||
FileExt.SafeDelete(metadataPath);
|
|
||||||
return aaxcProcesser.Succeeded;
|
return aaxcProcesser.Succeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,6 +171,10 @@ namespace AaxDecrypter
|
|||||||
DecryptProgressUpdate?.Invoke(this, (int)progressPercent);
|
DecryptProgressUpdate?.Invoke(this, (int)progressPercent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copy all aacx metadata to m4b file.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public bool Step3_RestoreMetadata()
|
public bool Step3_RestoreMetadata()
|
||||||
{
|
{
|
||||||
var outFile = new TagLib.Mpeg4.File(outputFileName, TagLib.ReadStyle.Average);
|
var outFile = new TagLib.Mpeg4.File(outputFileName, TagLib.ReadStyle.Average);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using Dinah.Core;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@ -11,11 +12,16 @@ namespace AaxDecrypter
|
|||||||
public int Count => _chapterList.Count;
|
public int Count => _chapterList.Count;
|
||||||
public void AddChapter(Chapter chapter)
|
public void AddChapter(Chapter chapter)
|
||||||
{
|
{
|
||||||
|
ArgumentValidator.EnsureNotNull(chapter, nameof(chapter));
|
||||||
_chapterList.Add(chapter);
|
_chapterList.Add(chapter);
|
||||||
}
|
}
|
||||||
public string ToFFMeta()
|
public string ToFFMeta(bool includeFFMetaHeader)
|
||||||
{
|
{
|
||||||
var ffmetaChapters = new StringBuilder();
|
var ffmetaChapters = new StringBuilder();
|
||||||
|
|
||||||
|
if (includeFFMetaHeader)
|
||||||
|
ffmetaChapters.AppendLine(";FFMETADATA1\n");
|
||||||
|
|
||||||
foreach (var c in Chapters)
|
foreach (var c in Chapters)
|
||||||
{
|
{
|
||||||
ffmetaChapters.AppendLine(c.ToFFMeta());
|
ffmetaChapters.AppendLine(c.ToFFMeta());
|
||||||
@ -30,6 +36,10 @@ namespace AaxDecrypter
|
|||||||
public long EndOffsetMs { get; }
|
public long EndOffsetMs { get; }
|
||||||
public Chapter(string title, long startOffsetMs, long lengthMs)
|
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;
|
Title = title;
|
||||||
StartOffsetMs = startOffsetMs;
|
StartOffsetMs = startOffsetMs;
|
||||||
EndOffsetMs = StartOffsetMs + lengthMs;
|
EndOffsetMs = StartOffsetMs + lengthMs;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using Dinah.Core;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -15,6 +16,11 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
public DownloadLicense(string downloadUrl, string audibleKey, string audibleIV, string userAgent)
|
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;
|
DownloadUrl = downloadUrl;
|
||||||
AudibleKey = audibleKey;
|
AudibleKey = audibleKey;
|
||||||
AudibleIV = audibleIV;
|
AudibleIV = audibleIV;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -15,17 +16,20 @@ namespace AaxDecrypter
|
|||||||
public string FFMpegPath { get; }
|
public string FFMpegPath { get; }
|
||||||
public bool IsRunning { get; private set; }
|
public bool IsRunning { get; private set; }
|
||||||
public bool Succeeded { 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);
|
private static Regex processedTimeRegex = new Regex("time=(\\d{2}):(\\d{2}):(\\d{2}).\\d{2}", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
public FFMpegAaxcProcesser(string ffmpegPath)
|
public FFMpegAaxcProcesser(string ffmpegPath)
|
||||||
{
|
{
|
||||||
FFMpegPath = 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
|
//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
|
var StartInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = FFMpegPath,
|
FileName = FFMpegPath,
|
||||||
@ -34,71 +38,47 @@ namespace AaxDecrypter
|
|||||||
WindowStyle = ProcessWindowStyle.Hidden,
|
WindowStyle = ProcessWindowStyle.Hidden,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
WorkingDirectory = Path.GetDirectoryName(FFMpegPath),
|
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);
|
if (metadataPath != null)
|
||||||
|
{
|
||||||
|
StartInfo.ArgumentList.Add("-ignore_chapters"); //prevents ffmpeg from copying chapter info from aaxc to output file
|
||||||
|
StartInfo.ArgumentList.Add("true");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ProcessBook(string aaxcUrl, string userAgent, string audibleKey, string audibleIV, string metadataPath, string outputFile)
|
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);
|
||||||
|
|
||||||
//This process gets the aaxc from the url and streams the decrypted
|
if (metadataPath != null)
|
||||||
//m4b to the output file. Preserves album art, but replaces metadata.
|
|
||||||
var StartInfo = new ProcessStartInfo
|
|
||||||
{
|
{
|
||||||
FileName = FFMpegPath,
|
StartInfo.ArgumentList.Add("-f");
|
||||||
RedirectStandardError = true,
|
StartInfo.ArgumentList.Add("ffmetadata");
|
||||||
CreateNoWindow = true,
|
StartInfo.ArgumentList.Add("-i");
|
||||||
WindowStyle = ProcessWindowStyle.Hidden,
|
StartInfo.ArgumentList.Add(metadataPath);
|
||||||
UseShellExecute = false,
|
StartInfo.ArgumentList.Add("-map_metadata");
|
||||||
WorkingDirectory = Path.GetDirectoryName(FFMpegPath),
|
StartInfo.ArgumentList.Add("1");
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessBool(ProcessStartInfo startInfo)
|
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 ProcessBook(ProcessStartInfo startInfo)
|
||||||
{
|
{
|
||||||
var downloader = new Process
|
var downloader = new Process
|
||||||
{
|
{
|
||||||
@ -124,6 +104,8 @@ namespace AaxDecrypter
|
|||||||
if (string.IsNullOrEmpty(e.Data))
|
if (string.IsNullOrEmpty(e.Data))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ffmpegError.AppendLine(e.Data);
|
||||||
|
|
||||||
if (processedTimeRegex.IsMatch(e.Data))
|
if (processedTimeRegex.IsMatch(e.Data))
|
||||||
{
|
{
|
||||||
//get timestamp of of last processed audio stream position
|
//get timestamp of of last processed audio stream position
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user