Fix temp file reuse/cleanup. Add retain aax option.
This commit is contained in:
parent
8af60b56b6
commit
05f25a88c6
@ -10,7 +10,7 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
protected AaxFile AaxFile;
|
protected AaxFile AaxFile;
|
||||||
|
|
||||||
protected AaxcDownloadConvertBase(string outFileName, string cacheDirectory, DownloadLicense dlLic)
|
protected AaxcDownloadConvertBase(string outFileName, string cacheDirectory, DownloadOptions dlLic)
|
||||||
: base(outFileName, cacheDirectory, dlLic) { }
|
: base(outFileName, cacheDirectory, dlLic) { }
|
||||||
|
|
||||||
/// <summary>Setting cover art by this method will insert the art into the audiobook metadata</summary>
|
/// <summary>Setting cover art by this method will insert the art into the audiobook metadata</summary>
|
||||||
@ -46,7 +46,7 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
OnDecryptProgressUpdate(zeroProgress);
|
OnDecryptProgressUpdate(zeroProgress);
|
||||||
|
|
||||||
AaxFile.SetDecryptionKey(DownloadLicense.AudibleKey, DownloadLicense.AudibleIV);
|
AaxFile.SetDecryptionKey(DownloadOptions.AudibleKey, DownloadOptions.AudibleIV);
|
||||||
return zeroProgress;
|
return zeroProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ namespace AaxDecrypter
|
|||||||
if (double.IsNormal(estTimeRemaining))
|
if (double.IsNormal(estTimeRemaining))
|
||||||
OnDecryptTimeRemaining(TimeSpan.FromSeconds(estTimeRemaining));
|
OnDecryptTimeRemaining(TimeSpan.FromSeconds(estTimeRemaining));
|
||||||
|
|
||||||
var progressPercent = e.ProcessPosition.TotalSeconds / duration.TotalSeconds;
|
var progressPercent = (e.ProcessPosition / e.TotalDuration);
|
||||||
|
|
||||||
OnDecryptProgressUpdate(
|
OnDecryptProgressUpdate(
|
||||||
new DownloadProgress
|
new DownloadProgress
|
||||||
|
|||||||
@ -18,13 +18,13 @@ namespace AaxDecrypter
|
|||||||
private static TimeSpan minChapterLength { get; } = TimeSpan.FromSeconds(3);
|
private static TimeSpan minChapterLength { get; } = TimeSpan.FromSeconds(3);
|
||||||
private List<string> multiPartFilePaths { get; } = new List<string>();
|
private List<string> multiPartFilePaths { get; } = new List<string>();
|
||||||
|
|
||||||
public AaxcDownloadMultiConverter(string outFileName, string cacheDirectory, DownloadLicense dlLic,
|
public AaxcDownloadMultiConverter(string outFileName, string cacheDirectory, DownloadOptions dlLic,
|
||||||
Func<MultiConvertFileProperties, string> multipartFileNameCallback = null)
|
Func<MultiConvertFileProperties, string> multipartFileNameCallback = null)
|
||||||
: base(outFileName, cacheDirectory, dlLic)
|
: base(outFileName, cacheDirectory, dlLic)
|
||||||
{
|
{
|
||||||
Steps = new StepSequence
|
Steps = new StepSequence
|
||||||
{
|
{
|
||||||
Name = "Download and Convert Aaxc To " + DownloadLicense.OutputFormat,
|
Name = "Download and Convert Aaxc To " + DownloadOptions.OutputFormat,
|
||||||
|
|
||||||
["Step 1: Get Aaxc Metadata"] = Step_GetMetadata,
|
["Step 1: Get Aaxc Metadata"] = Step_GetMetadata,
|
||||||
["Step 2: Download Decrypted Audiobook"] = Step_DownloadAudiobookAsMultipleFilesPerChapter,
|
["Step 2: Download Decrypted Audiobook"] = Step_DownloadAudiobookAsMultipleFilesPerChapter,
|
||||||
@ -61,10 +61,10 @@ That naming may not be desirable for everyone, but it's an easy change to instea
|
|||||||
{
|
{
|
||||||
var zeroProgress = Step_DownloadAudiobook_Start();
|
var zeroProgress = Step_DownloadAudiobook_Start();
|
||||||
|
|
||||||
var chapters = DownloadLicense.ChapterInfo.Chapters.ToList();
|
var chapters = DownloadOptions.ChapterInfo.Chapters.ToList();
|
||||||
|
|
||||||
// Ensure split files are at least minChapterLength in duration.
|
// Ensure split files are at least minChapterLength in duration.
|
||||||
var splitChapters = new ChapterInfo(DownloadLicense.ChapterInfo.StartOffset);
|
var splitChapters = new ChapterInfo(DownloadOptions.ChapterInfo.StartOffset);
|
||||||
|
|
||||||
var runningTotal = TimeSpan.Zero;
|
var runningTotal = TimeSpan.Zero;
|
||||||
string title = "";
|
string title = "";
|
||||||
@ -89,7 +89,7 @@ That naming may not be desirable for everyone, but it's an easy change to instea
|
|||||||
ConversionResult result;
|
ConversionResult result;
|
||||||
|
|
||||||
AaxFile.ConversionProgressUpdate += AaxFile_ConversionProgressUpdate;
|
AaxFile.ConversionProgressUpdate += AaxFile_ConversionProgressUpdate;
|
||||||
if (DownloadLicense.OutputFormat == OutputFormat.M4b)
|
if (DownloadOptions.OutputFormat == OutputFormat.M4b)
|
||||||
result = ConvertToMultiMp4a(splitChapters);
|
result = ConvertToMultiMp4a(splitChapters);
|
||||||
else
|
else
|
||||||
result = ConvertToMultiMp3(splitChapters);
|
result = ConvertToMultiMp3(splitChapters);
|
||||||
@ -97,13 +97,7 @@ That naming may not be desirable for everyone, but it's an easy change to instea
|
|||||||
|
|
||||||
Step_DownloadAudiobook_End(zeroProgress);
|
Step_DownloadAudiobook_End(zeroProgress);
|
||||||
|
|
||||||
var success = result == ConversionResult.NoErrorsDetected;
|
return result == ConversionResult.NoErrorsDetected;
|
||||||
|
|
||||||
if (success)
|
|
||||||
foreach (var path in multiPartFilePaths)
|
|
||||||
OnFileCreated(path);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConversionResult ConvertToMultiMp4a(ChapterInfo splitChapters)
|
private ConversionResult ConvertToMultiMp4a(ChapterInfo splitChapters)
|
||||||
@ -111,7 +105,7 @@ That naming may not be desirable for everyone, but it's an easy change to instea
|
|||||||
var chapterCount = 0;
|
var chapterCount = 0;
|
||||||
return AaxFile.ConvertToMultiMp4a(splitChapters, newSplitCallback =>
|
return AaxFile.ConvertToMultiMp4a(splitChapters, newSplitCallback =>
|
||||||
createOutputFileStream(++chapterCount, splitChapters, newSplitCallback),
|
createOutputFileStream(++chapterCount, splitChapters, newSplitCallback),
|
||||||
DownloadLicense.TrimOutputToChapterLength);
|
DownloadOptions.TrimOutputToChapterLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConversionResult ConvertToMultiMp3(ChapterInfo splitChapters)
|
private ConversionResult ConvertToMultiMp3(ChapterInfo splitChapters)
|
||||||
@ -121,7 +115,7 @@ That naming may not be desirable for everyone, but it's an easy change to instea
|
|||||||
{
|
{
|
||||||
createOutputFileStream(++chapterCount, splitChapters, newSplitCallback);
|
createOutputFileStream(++chapterCount, splitChapters, newSplitCallback);
|
||||||
((NAudio.Lame.LameConfig)newSplitCallback.UserState).ID3.Track = chapterCount.ToString();
|
((NAudio.Lame.LameConfig)newSplitCallback.UserState).ID3.Track = chapterCount.ToString();
|
||||||
}, null, DownloadLicense.TrimOutputToChapterLength);
|
}, null, DownloadOptions.TrimOutputToChapterLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createOutputFileStream(int currentChapter, ChapterInfo splitChapters, NewSplitCallback newSplitCallback)
|
private void createOutputFileStream(int currentChapter, ChapterInfo splitChapters, NewSplitCallback newSplitCallback)
|
||||||
@ -140,6 +134,8 @@ That naming may not be desirable for everyone, but it's an easy change to instea
|
|||||||
FileUtility.SaferDelete(fileName);
|
FileUtility.SaferDelete(fileName);
|
||||||
|
|
||||||
newSplitCallback.OutputFile = File.Open(fileName, FileMode.OpenOrCreate);
|
newSplitCallback.OutputFile = File.Open(fileName, FileMode.OpenOrCreate);
|
||||||
|
|
||||||
|
OnFileCreated(fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,12 +11,12 @@ namespace AaxDecrypter
|
|||||||
{
|
{
|
||||||
protected override StepSequence Steps { get; }
|
protected override StepSequence Steps { get; }
|
||||||
|
|
||||||
public AaxcDownloadSingleConverter(string outFileName, string cacheDirectory, DownloadLicense dlLic)
|
public AaxcDownloadSingleConverter(string outFileName, string cacheDirectory, DownloadOptions dlLic)
|
||||||
: base(outFileName, cacheDirectory, dlLic)
|
: base(outFileName, cacheDirectory, dlLic)
|
||||||
{
|
{
|
||||||
Steps = new StepSequence
|
Steps = new StepSequence
|
||||||
{
|
{
|
||||||
Name = "Download and Convert Aaxc To " + DownloadLicense.OutputFormat,
|
Name = "Download and Convert Aaxc To " + DownloadOptions.OutputFormat,
|
||||||
|
|
||||||
["Step 1: Get Aaxc Metadata"] = Step_GetMetadata,
|
["Step 1: Get Aaxc Metadata"] = Step_GetMetadata,
|
||||||
["Step 2: Download Decrypted Audiobook"] = Step_DownloadAudiobookAsSingleFile,
|
["Step 2: Download Decrypted Audiobook"] = Step_DownloadAudiobookAsSingleFile,
|
||||||
@ -32,15 +32,16 @@ namespace AaxDecrypter
|
|||||||
FileUtility.SaferDelete(OutputFileName);
|
FileUtility.SaferDelete(OutputFileName);
|
||||||
|
|
||||||
var outputFile = File.Open(OutputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
|
var outputFile = File.Open(OutputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
|
||||||
|
OnFileCreated(OutputFileName);
|
||||||
|
|
||||||
AaxFile.ConversionProgressUpdate += AaxFile_ConversionProgressUpdate;
|
AaxFile.ConversionProgressUpdate += AaxFile_ConversionProgressUpdate;
|
||||||
var decryptionResult
|
var decryptionResult
|
||||||
= DownloadLicense.OutputFormat == OutputFormat.M4b
|
= DownloadOptions.OutputFormat == OutputFormat.M4b
|
||||||
? AaxFile.ConvertToMp4a(outputFile, DownloadLicense.ChapterInfo, DownloadLicense.TrimOutputToChapterLength)
|
? AaxFile.ConvertToMp4a(outputFile, DownloadOptions.ChapterInfo, DownloadOptions.TrimOutputToChapterLength)
|
||||||
: AaxFile.ConvertToMp3(outputFile, null, DownloadLicense.ChapterInfo, DownloadLicense.TrimOutputToChapterLength);
|
: AaxFile.ConvertToMp3(outputFile, null, DownloadOptions.ChapterInfo, DownloadOptions.TrimOutputToChapterLength);
|
||||||
AaxFile.ConversionProgressUpdate -= AaxFile_ConversionProgressUpdate;
|
AaxFile.ConversionProgressUpdate -= AaxFile_ConversionProgressUpdate;
|
||||||
|
|
||||||
DownloadLicense.ChapterInfo = AaxFile.Chapters;
|
DownloadOptions.ChapterInfo = AaxFile.Chapters;
|
||||||
|
|
||||||
Step_DownloadAudiobook_End(zeroProgress);
|
Step_DownloadAudiobook_End(zeroProgress);
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using Dinah.Core.Net.Http;
|
using Dinah.Core.Net.Http;
|
||||||
@ -20,8 +21,9 @@ namespace AaxDecrypter
|
|||||||
public event EventHandler<string> FileCreated;
|
public event EventHandler<string> FileCreated;
|
||||||
|
|
||||||
protected bool IsCanceled { get; set; }
|
protected bool IsCanceled { get; set; }
|
||||||
|
|
||||||
protected string OutputFileName { get; private set; }
|
protected string OutputFileName { get; private set; }
|
||||||
protected DownloadLicense DownloadLicense { get; }
|
protected DownloadOptions DownloadOptions { get; }
|
||||||
protected NetworkFileStream InputFileStream => (nfsPersister ??= OpenNetworkFileStream()).NetworkFileStream;
|
protected NetworkFileStream InputFileStream => (nfsPersister ??= OpenNetworkFileStream()).NetworkFileStream;
|
||||||
|
|
||||||
// Don't give the property a 'set'. This should have to be an obvious choice; not accidental
|
// Don't give the property a 'set'. This should have to be an obvious choice; not accidental
|
||||||
@ -31,9 +33,9 @@ namespace AaxDecrypter
|
|||||||
private NetworkFileStreamPersister nfsPersister;
|
private NetworkFileStreamPersister nfsPersister;
|
||||||
|
|
||||||
private string jsonDownloadState { get; }
|
private string jsonDownloadState { get; }
|
||||||
private string tempFile => Path.ChangeExtension(jsonDownloadState, ".tmp");
|
public string TempFilePath { get; }
|
||||||
|
|
||||||
protected AudiobookDownloadBase(string outFileName, string cacheDirectory, DownloadLicense dlLic)
|
protected AudiobookDownloadBase(string outFileName, string cacheDirectory, DownloadOptions dlLic)
|
||||||
{
|
{
|
||||||
OutputFileName = ArgumentValidator.EnsureNotNullOrWhiteSpace(outFileName, nameof(outFileName));
|
OutputFileName = ArgumentValidator.EnsureNotNullOrWhiteSpace(outFileName, nameof(outFileName));
|
||||||
|
|
||||||
@ -43,9 +45,11 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
if (!Directory.Exists(cacheDirectory))
|
if (!Directory.Exists(cacheDirectory))
|
||||||
throw new DirectoryNotFoundException($"Directory does not exist: {nameof(cacheDirectory)}");
|
throw new DirectoryNotFoundException($"Directory does not exist: {nameof(cacheDirectory)}");
|
||||||
jsonDownloadState = Path.Combine(cacheDirectory, Path.ChangeExtension(OutputFileName, ".json"));
|
|
||||||
|
|
||||||
DownloadLicense = ArgumentValidator.EnsureNotNull(dlLic, nameof(dlLic));
|
jsonDownloadState = Path.Combine(cacheDirectory, Path.GetFileName(Path.ChangeExtension(OutputFileName, ".json")));
|
||||||
|
TempFilePath = Path.ChangeExtension(jsonDownloadState, ".tmp");
|
||||||
|
|
||||||
|
DownloadOptions = ArgumentValidator.EnsureNotNull(dlLic, nameof(dlLic));
|
||||||
|
|
||||||
// delete file after validation is complete
|
// delete file after validation is complete
|
||||||
FileUtility.SaferDelete(OutputFileName);
|
FileUtility.SaferDelete(OutputFileName);
|
||||||
@ -99,7 +103,7 @@ namespace AaxDecrypter
|
|||||||
{
|
{
|
||||||
var path = Path.ChangeExtension(OutputFileName, ".cue");
|
var path = Path.ChangeExtension(OutputFileName, ".cue");
|
||||||
path = FileUtility.GetValidFilename(path);
|
path = FileUtility.GetValidFilename(path);
|
||||||
File.WriteAllText(path, Cue.CreateContents(Path.GetFileName(OutputFileName), DownloadLicense.ChapterInfo));
|
File.WriteAllText(path, Cue.CreateContents(Path.GetFileName(OutputFileName), DownloadOptions.ChapterInfo));
|
||||||
OnFileCreated(path);
|
OnFileCreated(path);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -111,9 +115,27 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
protected bool Step_Cleanup()
|
protected bool Step_Cleanup()
|
||||||
{
|
{
|
||||||
FileUtility.SaferDelete(jsonDownloadState);
|
bool success = !IsCanceled;
|
||||||
FileUtility.SaferDelete(tempFile);
|
if (success)
|
||||||
return !IsCanceled;
|
{
|
||||||
|
FileUtility.SaferDelete(jsonDownloadState);
|
||||||
|
|
||||||
|
if (DownloadOptions.RetainEncryptedFile)
|
||||||
|
{
|
||||||
|
string aaxPath = Path.ChangeExtension(TempFilePath, ".aax");
|
||||||
|
FileUtility.SaferMove(TempFilePath, aaxPath);
|
||||||
|
OnFileCreated(aaxPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
FileUtility.SaferDelete(TempFilePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FileUtility.SaferDelete(OutputFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NetworkFileStreamPersister OpenNetworkFileStream()
|
private NetworkFileStreamPersister OpenNetworkFileStream()
|
||||||
@ -126,13 +148,13 @@ namespace AaxDecrypter
|
|||||||
var nfsp = new NetworkFileStreamPersister(jsonDownloadState);
|
var nfsp = new NetworkFileStreamPersister(jsonDownloadState);
|
||||||
// If More than ~1 hour has elapsed since getting the download url, it will expire.
|
// If More than ~1 hour has elapsed since getting the download url, it will expire.
|
||||||
// The new url will be to the same file.
|
// The new url will be to the same file.
|
||||||
nfsp.NetworkFileStream.SetUriForSameFile(new Uri(DownloadLicense.DownloadUrl));
|
nfsp.NetworkFileStream.SetUriForSameFile(new Uri(DownloadOptions.DownloadUrl));
|
||||||
return nfsp;
|
return nfsp;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
FileUtility.SaferDelete(jsonDownloadState);
|
FileUtility.SaferDelete(jsonDownloadState);
|
||||||
FileUtility.SaferDelete(tempFile);
|
FileUtility.SaferDelete(TempFilePath);
|
||||||
return NewNetworkFilePersister();
|
return NewNetworkFilePersister();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,10 +163,10 @@ namespace AaxDecrypter
|
|||||||
{
|
{
|
||||||
var headers = new System.Net.WebHeaderCollection
|
var headers = new System.Net.WebHeaderCollection
|
||||||
{
|
{
|
||||||
{ "User-Agent", DownloadLicense.UserAgent }
|
{ "User-Agent", DownloadOptions.UserAgent }
|
||||||
};
|
};
|
||||||
|
|
||||||
var networkFileStream = new NetworkFileStream(tempFile, new Uri(DownloadLicense.DownloadUrl), 0, headers);
|
var networkFileStream = new NetworkFileStream(TempFilePath, new Uri(DownloadOptions.DownloadUrl), 0, headers);
|
||||||
return new NetworkFileStreamPersister(networkFileStream, jsonDownloadState);
|
return new NetworkFileStreamPersister(networkFileStream, jsonDownloadState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ using Dinah.Core;
|
|||||||
|
|
||||||
namespace AaxDecrypter
|
namespace AaxDecrypter
|
||||||
{
|
{
|
||||||
public class DownloadLicense
|
public class DownloadOptions
|
||||||
{
|
{
|
||||||
public string DownloadUrl { get; }
|
public string DownloadUrl { get; }
|
||||||
public string UserAgent { get; }
|
public string UserAgent { get; }
|
||||||
@ -11,9 +11,10 @@ namespace AaxDecrypter
|
|||||||
public string AudibleIV { get; init; }
|
public string AudibleIV { get; init; }
|
||||||
public OutputFormat OutputFormat { get; init; }
|
public OutputFormat OutputFormat { get; init; }
|
||||||
public bool TrimOutputToChapterLength { get; init; }
|
public bool TrimOutputToChapterLength { get; init; }
|
||||||
|
public bool RetainEncryptedFile { get; init; }
|
||||||
public ChapterInfo ChapterInfo { get; set; }
|
public ChapterInfo ChapterInfo { get; set; }
|
||||||
|
|
||||||
public DownloadLicense(string downloadUrl, string userAgent)
|
public DownloadOptions(string downloadUrl, string userAgent)
|
||||||
{
|
{
|
||||||
DownloadUrl = ArgumentValidator.EnsureNotNullOrEmpty(downloadUrl, nameof(downloadUrl));
|
DownloadUrl = ArgumentValidator.EnsureNotNullOrEmpty(downloadUrl, nameof(downloadUrl));
|
||||||
UserAgent = ArgumentValidator.EnsureNotNullOrEmpty(userAgent, nameof(userAgent));
|
UserAgent = ArgumentValidator.EnsureNotNullOrEmpty(userAgent, nameof(userAgent));
|
||||||
@ -10,7 +10,7 @@ namespace AaxDecrypter
|
|||||||
{
|
{
|
||||||
protected override StepSequence Steps { get; }
|
protected override StepSequence Steps { get; }
|
||||||
|
|
||||||
public UnencryptedAudiobookDownloader(string outFileName, string cacheDirectory, DownloadLicense dlLic)
|
public UnencryptedAudiobookDownloader(string outFileName, string cacheDirectory, DownloadOptions dlLic)
|
||||||
: base(outFileName, cacheDirectory, dlLic)
|
: base(outFileName, cacheDirectory, dlLic)
|
||||||
{
|
{
|
||||||
Steps = new StepSequence
|
Steps = new StepSequence
|
||||||
|
|||||||
@ -83,6 +83,9 @@ namespace AppScaffolding
|
|||||||
|
|
||||||
if (!config.Exists(nameof(config.StripAudibleBrandAudio)))
|
if (!config.Exists(nameof(config.StripAudibleBrandAudio)))
|
||||||
config.StripAudibleBrandAudio = false;
|
config.StripAudibleBrandAudio = false;
|
||||||
|
|
||||||
|
if (!config.Exists(nameof(config.RetainAaxFile)))
|
||||||
|
config.RetainAaxFile = false;
|
||||||
|
|
||||||
if (!config.Exists(nameof(config.FolderTemplate)))
|
if (!config.Exists(nameof(config.FolderTemplate)))
|
||||||
config.FolderTemplate = Templates.Folder.DefaultTemplate;
|
config.FolderTemplate = Templates.Folder.DefaultTemplate;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ namespace FileLiberator
|
|||||||
/// File name: final file name.
|
/// File name: final file name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string GetInProgressFilename(this AudioFileStorage _, LibraryBook libraryBook, string extension)
|
public static string GetInProgressFilename(this AudioFileStorage _, LibraryBook libraryBook, string extension)
|
||||||
=> Templates.File.GetFilename(libraryBook.ToDto(), AudibleFileStorage.DecryptInProgressDirectory, extension);
|
=> Templates.File.GetFilename(libraryBook.ToDto(), AudibleFileStorage.DecryptInProgressDirectory, extension, returnFirstExisting: true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// PDF: audio file does not exist
|
/// PDF: audio file does not exist
|
||||||
|
|||||||
@ -61,7 +61,12 @@ namespace FileLiberator
|
|||||||
|
|
||||||
// decrypt failed
|
// decrypt failed
|
||||||
if (!success)
|
if (!success)
|
||||||
|
{
|
||||||
|
foreach (var tmpFile in entries)
|
||||||
|
FileUtility.SaferDelete(tmpFile.Path);
|
||||||
|
|
||||||
return new StatusHandler { "Decrypt failed" };
|
return new StatusHandler { "Decrypt failed" };
|
||||||
|
}
|
||||||
|
|
||||||
// moves new files from temp dir to final dest
|
// moves new files from temp dir to final dest
|
||||||
var movedAudioFile = moveFilesToBooksDir(libraryBook, entries);
|
var movedAudioFile = moveFilesToBooksDir(libraryBook, entries);
|
||||||
@ -92,7 +97,7 @@ namespace FileLiberator
|
|||||||
|
|
||||||
var api = await libraryBook.GetApiAsync();
|
var api = await libraryBook.GetApiAsync();
|
||||||
var contentLic = await api.GetDownloadLicenseAsync(libraryBook.Book.AudibleProductId);
|
var contentLic = await api.GetDownloadLicenseAsync(libraryBook.Book.AudibleProductId);
|
||||||
var audiobookDlLic = BuildDownloadLicense(config, contentLic);
|
var audiobookDlLic = BuildDownloadOptions(config, contentLic);
|
||||||
|
|
||||||
var outFileName = AudibleFileStorage.Audio.GetInProgressFilename(libraryBook, audiobookDlLic.OutputFormat.ToString().ToLower());
|
var outFileName = AudibleFileStorage.Audio.GetInProgressFilename(libraryBook, audiobookDlLic.OutputFormat.ToString().ToLower());
|
||||||
var cacheDir = AudibleFileStorage.DownloadsInProgressDirectory;
|
var cacheDir = AudibleFileStorage.DownloadsInProgressDirectory;
|
||||||
@ -132,28 +137,28 @@ namespace FileLiberator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DownloadLicense BuildDownloadLicense(Configuration config, AudibleApi.Common.ContentLicense contentLic)
|
private static DownloadOptions BuildDownloadOptions(Configuration config, AudibleApi.Common.ContentLicense contentLic)
|
||||||
{
|
{
|
||||||
//I assume if ContentFormat == "MPEG" that the delivered file is an unencrypted mp3.
|
//I assume if ContentFormat == "MPEG" that the delivered file is an unencrypted mp3.
|
||||||
//I also assume that if DrmType != Adrm, the file will be an mp3.
|
//I also assume that if DrmType != Adrm, the file will be an mp3.
|
||||||
//These assumptions may be wrong, and only time and bug reports will tell.
|
//These assumptions may be wrong, and only time and bug reports will tell.
|
||||||
var outputFormat =
|
|
||||||
contentLic?.ContentMetadata?.ContentReference?.ContentFormat == "MPEG" ||
|
bool encrypted = contentLic.DrmType == AudibleApi.Common.DrmType.Adrm;
|
||||||
(config.AllowLibationFixup && config.DecryptToLossy) ?
|
|
||||||
|
var outputFormat = !encrypted || (config.AllowLibationFixup && config.DecryptToLossy) ?
|
||||||
OutputFormat.Mp3 : OutputFormat.M4b;
|
OutputFormat.Mp3 : OutputFormat.M4b;
|
||||||
|
|
||||||
var audiobookDlLic = new DownloadLicense
|
var audiobookDlLic = new DownloadOptions
|
||||||
(
|
(
|
||||||
contentLic?.ContentMetadata?.ContentUrl?.OfflineUrl,
|
contentLic?.ContentMetadata?.ContentUrl?.OfflineUrl,
|
||||||
Resources.USER_AGENT
|
Resources.USER_AGENT
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
AudibleKey = contentLic?.Voucher?.Key,
|
AudibleKey = contentLic?.Voucher?.Key,
|
||||||
AudibleIV = contentLic?.Voucher?.Iv,
|
AudibleIV = contentLic?.Voucher?.Iv,
|
||||||
OutputFormat = outputFormat,
|
OutputFormat = outputFormat,
|
||||||
TrimOutputToChapterLength = config.StripAudibleBrandAudio
|
TrimOutputToChapterLength = config.StripAudibleBrandAudio,
|
||||||
|
RetainEncryptedFile = config.RetainAaxFile && encrypted
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.AllowLibationFixup || outputFormat == OutputFormat.Mp3)
|
if (config.AllowLibationFixup || outputFormat == OutputFormat.Mp3)
|
||||||
|
|||||||
@ -29,14 +29,14 @@ namespace FileManager
|
|||||||
public string IllegalCharacterReplacements { get; set; }
|
public string IllegalCharacterReplacements { get; set; }
|
||||||
|
|
||||||
/// <summary>Generate a valid path for this file or directory</summary>
|
/// <summary>Generate a valid path for this file or directory</summary>
|
||||||
public string GetFilePath()
|
public string GetFilePath(bool returnFirstExisting = false)
|
||||||
{
|
{
|
||||||
var filename = Template;
|
var filename = Template;
|
||||||
|
|
||||||
foreach (var r in ParameterReplacements)
|
foreach (var r in ParameterReplacements)
|
||||||
filename = filename.Replace($"<{formatKey(r.Key)}>", formatValue(r.Value));
|
filename = filename.Replace($"<{formatKey(r.Key)}>", formatValue(r.Value));
|
||||||
|
|
||||||
return FileUtility.GetValidFilename(filename, IllegalCharacterReplacements);
|
return FileUtility.GetValidFilename(filename, IllegalCharacterReplacements, returnFirstExisting);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string formatKey(string key)
|
private static string formatKey(string key)
|
||||||
|
|||||||
@ -48,7 +48,7 @@ namespace FileManager
|
|||||||
/// <br/>- ensure uniqueness
|
/// <br/>- ensure uniqueness
|
||||||
/// <br/>- enforce max file length
|
/// <br/>- enforce max file length
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string GetValidFilename(string path, string illegalCharacterReplacements = "")
|
public static string GetValidFilename(string path, string illegalCharacterReplacements = "", bool returnFirstExisting = false)
|
||||||
{
|
{
|
||||||
ArgumentValidator.EnsureNotNull(path, nameof(path));
|
ArgumentValidator.EnsureNotNull(path, nameof(path));
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ namespace FileManager
|
|||||||
fullfilename = removeInvalidWhitespace(fullfilename);
|
fullfilename = removeInvalidWhitespace(fullfilename);
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
while (File.Exists(fullfilename))
|
while (File.Exists(fullfilename) && !returnFirstExisting)
|
||||||
{
|
{
|
||||||
var increm = $" ({++i})";
|
var increm = $" ({++i})";
|
||||||
fullfilename = fileStem.Truncate(MAX_FILENAME_LENGTH - increm.Length - extension.Length) + increm + extension;
|
fullfilename = fileStem.Truncate(MAX_FILENAME_LENGTH - increm.Length - extension.Length) + increm + extension;
|
||||||
|
|||||||
@ -116,6 +116,13 @@ namespace LibationFileManager
|
|||||||
get => persistentDictionary.GetNonString<bool>(nameof(SplitFilesByChapter));
|
get => persistentDictionary.GetNonString<bool>(nameof(SplitFilesByChapter));
|
||||||
set => persistentDictionary.SetNonString(nameof(SplitFilesByChapter), value);
|
set => persistentDictionary.SetNonString(nameof(SplitFilesByChapter), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Description("Retain the Aax file after successfully decrypting")]
|
||||||
|
public bool RetainAaxFile
|
||||||
|
{
|
||||||
|
get => persistentDictionary.GetNonString<bool>(nameof(RetainAaxFile));
|
||||||
|
set => persistentDictionary.SetNonString(nameof(RetainAaxFile), value);
|
||||||
|
}
|
||||||
|
|
||||||
public enum BadBookAction
|
public enum BadBookAction
|
||||||
{
|
{
|
||||||
|
|||||||
@ -230,9 +230,9 @@ namespace LibationFileManager
|
|||||||
|
|
||||||
#region to file name
|
#region to file name
|
||||||
/// <summary>USES LIVE CONFIGURATION VALUES</summary>
|
/// <summary>USES LIVE CONFIGURATION VALUES</summary>
|
||||||
public string GetFilename(LibraryBookDto libraryBookDto, string dirFullPath, string extension)
|
public string GetFilename(LibraryBookDto libraryBookDto, string dirFullPath, string extension, bool returnFirstExisting = false)
|
||||||
=> getFileNamingTemplate(libraryBookDto, Configuration.Instance.FileTemplate, dirFullPath, extension)
|
=> getFileNamingTemplate(libraryBookDto, Configuration.Instance.FileTemplate, dirFullPath, extension)
|
||||||
.GetFilePath();
|
.GetFilePath(returnFirstExisting);
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user