Added TagLib through package manager and improved tag retreival.
This commit is contained in:
parent
78f278121b
commit
e958944466
@ -4,6 +4,10 @@
|
|||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="TagLibSharp" Version="2.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="taglib-sharp">
|
<Reference Include="taglib-sharp">
|
||||||
<HintPath>lib\taglib-sharp.dll</HintPath>
|
<HintPath>lib\taglib-sharp.dll</HintPath>
|
||||||
@ -42,9 +46,6 @@
|
|||||||
<None Update="DecryptLib\swscale-5.dll">
|
<None Update="DecryptLib\swscale-5.dll">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="DecryptLib\taglib-sharp.dll">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -41,12 +41,12 @@ namespace AaxDecrypter
|
|||||||
public string outDir { get; private set; }
|
public string outDir { get; private set; }
|
||||||
public string outputFileName { get; private set; }
|
public string outputFileName { get; private set; }
|
||||||
public ChapterInfo chapters { get; private set; }
|
public ChapterInfo chapters { get; private set; }
|
||||||
public string Title => aaxcTagLib.Tag.Title?.Replace(" (Unabridged)", "") ?? "[unknown]";
|
public string Title => aaxcTagLib.TitleSansUnabridged ?? "[unknown]";
|
||||||
public string Author => aaxcTagLib.Tag.FirstPerformer ?? "[unknown]";
|
public string Author => aaxcTagLib.FirstAuthor ?? "[unknown]";
|
||||||
public string Narrator => aaxcTagLib.GetTag(TagLib.TagTypes.Apple).Narrator ?? "[unknown]";
|
public string Narrator => aaxcTagLib.Narrator ?? "[unknown]";
|
||||||
public byte[] CoverArt => aaxcTagLib.Tag.Pictures.Length > 0 ? aaxcTagLib.Tag.Pictures[0].Data.Data : default;
|
public byte[] CoverArt => aaxcTagLib.Tag.Pictures.Length > 0 ? aaxcTagLib.Tag.Pictures[0].Data.Data : default;
|
||||||
|
|
||||||
private TagLib.Mpeg4.File aaxcTagLib { get; set; }
|
private AaxcTagLibFile aaxcTagLib { get; set; }
|
||||||
private StepSequence steps { get; }
|
private StepSequence steps { get; }
|
||||||
private DownloadLicense downloadLicense { get; set; }
|
private DownloadLicense downloadLicense { get; set; }
|
||||||
private FFMpegAaxcProcesser aaxcProcesser;
|
private FFMpegAaxcProcesser aaxcProcesser;
|
||||||
@ -90,7 +90,7 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
var networkFile = await NetworkFileAbstraction.CreateAsync(client, new Uri(downloadLicense.DownloadUrl));
|
var networkFile = await NetworkFileAbstraction.CreateAsync(client, new Uri(downloadLicense.DownloadUrl));
|
||||||
|
|
||||||
aaxcTagLib = await Task.Run(() => TagLib.File.Create(networkFile, "audio/mp4", TagLib.ReadStyle.Average) as TagLib.Mpeg4.File);
|
aaxcTagLib = await Task.Run(() => new AaxcTagLibFile(networkFile));
|
||||||
|
|
||||||
var defaultFilename = Path.Combine(
|
var defaultFilename = Path.Combine(
|
||||||
outDir,
|
outDir,
|
||||||
@ -239,21 +239,8 @@ namespace AaxDecrypter
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Step3_RestoreMetadata()
|
public bool Step3_RestoreMetadata()
|
||||||
{
|
{
|
||||||
var outFile = new TagLib.Mpeg4.File(outputFileName, TagLib.ReadStyle.Average);
|
var outFile = new AaxcTagLibFile(outputFileName);
|
||||||
|
outFile.CopyTagsFrom(aaxcTagLib);
|
||||||
var destTags = outFile.GetTag(TagLib.TagTypes.Apple) as TagLib.Mpeg4.AppleTag;
|
|
||||||
destTags.Clear();
|
|
||||||
|
|
||||||
var sourceTag = aaxcTagLib.GetTag(TagLib.TagTypes.Apple) as TagLib.Mpeg4.AppleTag;
|
|
||||||
|
|
||||||
//copy all metadata fields in the source file, even those that TagLib doesn't
|
|
||||||
//recognize, to the output file.
|
|
||||||
//NOTE: Chapters aren't stored in MPEG-4 metadata. They are encoded as a Timed
|
|
||||||
//Text Stream (MPEG-4 Part 17), so taglib doesn't read or write them.
|
|
||||||
foreach (var stag in sourceTag)
|
|
||||||
{
|
|
||||||
destTags.SetData(stag.BoxType, stag.Children.Cast<TagLib.Mpeg4.AppleDataBox>().ToArray());
|
|
||||||
}
|
|
||||||
outFile.Save();
|
outFile.Save();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Binary file not shown.
@ -3,32 +3,31 @@ namespace AaxDecrypter
|
|||||||
{
|
{
|
||||||
public static class NFO
|
public static class NFO
|
||||||
{
|
{
|
||||||
public static string CreateContents(string ripper, TagLib.File aaxcTagLib, ChapterInfo chapters)
|
public static string CreateContents(string ripper, AaxcTagLibFile aaxcTagLib, ChapterInfo chapters)
|
||||||
{
|
{
|
||||||
var tag = aaxcTagLib.GetTag(TagLib.TagTypes.Apple);
|
var tag = aaxcTagLib.AppleTags;
|
||||||
|
|
||||||
string narator = string.IsNullOrWhiteSpace(aaxcTagLib.Tag.FirstComposer) ? tag.Narrator : aaxcTagLib.Tag.FirstComposer;
|
|
||||||
|
|
||||||
var _hours = (int)aaxcTagLib.Properties.Duration.TotalHours;
|
var _hours = (int)aaxcTagLib.Properties.Duration.TotalHours;
|
||||||
var myDuration
|
var myDuration
|
||||||
= (_hours > 0 ? _hours + " hours, " : "")
|
= (_hours > 0 ? _hours + " hours, " : string.Empty)
|
||||||
+ aaxcTagLib.Properties.Duration.Minutes + " minutes, "
|
+ aaxcTagLib.Properties.Duration.Minutes + " minutes, "
|
||||||
+ aaxcTagLib.Properties.Duration.Seconds + " seconds";
|
+ aaxcTagLib.Properties.Duration.Seconds + " seconds";
|
||||||
|
|
||||||
var header
|
var header
|
||||||
= "General Information\r\n"
|
= "General Information\r\n"
|
||||||
+ "===================\r\n"
|
+ "===================\r\n"
|
||||||
+ $" Title: {aaxcTagLib.Tag.Title.Replace(" (Unabridged)", "")}\r\n"
|
+ $" Title: {aaxcTagLib.TitleSansUnabridged ?? "[unknown]"}\r\n"
|
||||||
+ $" Author: {aaxcTagLib.Tag.FirstPerformer ?? "[unknown]"}\r\n"
|
+ $" Author: {aaxcTagLib.FirstAuthor ?? "[unknown]"}\r\n"
|
||||||
+ $" Read By: {aaxcTagLib.GetTag(TagLib.TagTypes.Apple).Narrator??"[unknown]"}\r\n"
|
+ $" Read By: {aaxcTagLib.Narrator ?? "[unknown]"}\r\n"
|
||||||
+ $" Copyright: {aaxcTagLib.Tag.Year}\r\n"
|
+ $" Release Date: {aaxcTagLib.ReleaseDate ?? "[unknown]"}\r\n"
|
||||||
+ $" Audiobook Copyright: {aaxcTagLib.Tag.Year}\r\n";
|
+ $" Book Copyright: {aaxcTagLib.BookCopyright ?? "[unknown]"}\r\n"
|
||||||
if (!string.IsNullOrEmpty(aaxcTagLib.Tag.FirstGenre))
|
+ $" Recording Copyright: {aaxcTagLib.RecordingCopyright ?? "[unknown]"}\r\n";
|
||||||
header += $" Genre: {aaxcTagLib.Tag.FirstGenre}\r\n";
|
if (!string.IsNullOrEmpty(tag.FirstGenre))
|
||||||
|
header += $" Genre: {aaxcTagLib.AppleTags.FirstGenre}\r\n";
|
||||||
|
|
||||||
var s
|
var s
|
||||||
= header
|
= header
|
||||||
+ $" Publisher: {tag.Publisher ?? ""}\r\n"
|
+ $" Publisher: {aaxcTagLib.Publisher ?? string.Empty}\r\n"
|
||||||
+ $" Duration: {myDuration}\r\n"
|
+ $" Duration: {myDuration}\r\n"
|
||||||
+ $" Chapters: {chapters.Count}\r\n"
|
+ $" Chapters: {chapters.Count}\r\n"
|
||||||
+ "\r\n"
|
+ "\r\n"
|
||||||
@ -38,20 +37,20 @@ namespace AaxDecrypter
|
|||||||
+ " Source Format: Audible AAX\r\n"
|
+ " Source Format: Audible AAX\r\n"
|
||||||
+ $" Source Sample Rate: {aaxcTagLib.Properties.AudioSampleRate} Hz\r\n"
|
+ $" Source Sample Rate: {aaxcTagLib.Properties.AudioSampleRate} Hz\r\n"
|
||||||
+ $" Source Channels: {aaxcTagLib.Properties.AudioChannels}\r\n"
|
+ $" Source Channels: {aaxcTagLib.Properties.AudioChannels}\r\n"
|
||||||
+ $" Source Bitrate: {aaxcTagLib.Properties.AudioBitrate} kbits\r\n"
|
+ $" Source Bitrate: {aaxcTagLib.Properties.AudioBitrate} Kbps\r\n"
|
||||||
+ "\r\n"
|
+ "\r\n"
|
||||||
+ " Lossless Encode: Yes\r\n"
|
+ " Lossless Encode: Yes\r\n"
|
||||||
+ " Encoded Codec: AAC / M4B\r\n"
|
+ " Encoded Codec: AAC / M4B\r\n"
|
||||||
+ $" Encoded Sample Rate: {aaxcTagLib.Properties.AudioSampleRate} Hz\r\n"
|
+ $" Encoded Sample Rate: {aaxcTagLib.Properties.AudioSampleRate} Hz\r\n"
|
||||||
+ $" Encoded Channels: {aaxcTagLib.Properties.AudioChannels}\r\n"
|
+ $" Encoded Channels: {aaxcTagLib.Properties.AudioChannels}\r\n"
|
||||||
+ $" Encoded Bitrate: {aaxcTagLib.Properties.AudioBitrate} kbits\r\n"
|
+ $" Encoded Bitrate: {aaxcTagLib.Properties.AudioBitrate} Kbps\r\n"
|
||||||
+ "\r\n"
|
+ "\r\n"
|
||||||
+ $" Ripper: {ripper}\r\n"
|
+ $" Ripper: {ripper}\r\n"
|
||||||
+ "\r\n"
|
+ "\r\n"
|
||||||
+ "\r\n"
|
+ "\r\n"
|
||||||
+ "Book Description\r\n"
|
+ "Book Description\r\n"
|
||||||
+ "================\r\n"
|
+ "================\r\n"
|
||||||
+ (!string.IsNullOrWhiteSpace(tag.LongDescription) ? tag.LongDescription : tag.Description);
|
+ (!string.IsNullOrWhiteSpace(aaxcTagLib.LongDescription) ? aaxcTagLib.LongDescription : aaxcTagLib.Tag.Comment);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
149
AaxDecrypter/TagLibMpeg4Ex.cs
Normal file
149
AaxDecrypter/TagLibMpeg4Ex.cs
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TagLib;
|
||||||
|
using TagLib.Mpeg4;
|
||||||
|
|
||||||
|
namespace AaxDecrypter
|
||||||
|
{
|
||||||
|
public class AaxcTagLibFile : TagLib.Mpeg4.File
|
||||||
|
{
|
||||||
|
public AppleTag AppleTags => GetTag(TagTypes.Apple) as AppleTag;
|
||||||
|
|
||||||
|
private static ReadOnlyByteVector naratorType = new ReadOnlyByteVector(0xa9, (byte)'n', (byte)'r', (byte)'t');
|
||||||
|
private static ReadOnlyByteVector descriptionType = new ReadOnlyByteVector(0xa9, (byte)'d', (byte)'e', (byte)'s');
|
||||||
|
private static ReadOnlyByteVector publisherType = new ReadOnlyByteVector(0xa9, (byte)'p', (byte)'u', (byte)'b');
|
||||||
|
public string Narrator { get; }
|
||||||
|
public string LongDescription { get; }
|
||||||
|
public string ReleaseDate { get; }
|
||||||
|
public string Publisher { get; }
|
||||||
|
//TagLib uses @ART, which is the Artist tag
|
||||||
|
public string[] Authors => AppleTags.Performers;
|
||||||
|
public string FirstAuthor { get; }
|
||||||
|
public string TitleSansUnabridged { get; }
|
||||||
|
public string BookCopyright { get; }
|
||||||
|
public string RecordingCopyright { get; }
|
||||||
|
|
||||||
|
private string[] _copyright;
|
||||||
|
public AaxcTagLibFile(IFileAbstraction abstraction)
|
||||||
|
: base(abstraction, ReadStyle.Average)
|
||||||
|
{
|
||||||
|
_copyright = AppleTags.Copyright?.Replace("©", string.Empty).Replace("(P)", string.Empty)?.Split(';');
|
||||||
|
|
||||||
|
BookCopyright = _copyright is not null && _copyright.Length > 0 ? _copyright[0] : default;
|
||||||
|
|
||||||
|
RecordingCopyright = _copyright is not null && _copyright.Length > 1 ? _copyright[1] : default;
|
||||||
|
|
||||||
|
TitleSansUnabridged = AppleTags.Title?.Replace(" (Unabridged)", "");
|
||||||
|
|
||||||
|
FirstAuthor = Authors?.Length > 0 ? unicodeToAscii(Authors[0]) : default;
|
||||||
|
|
||||||
|
string[] text = AppleTags.GetText(publisherType);
|
||||||
|
Publisher = text.Length == 0 ? null : text[0];
|
||||||
|
|
||||||
|
text = AppleTags.GetText("rldt");
|
||||||
|
ReleaseDate = text.Length == 0 ? null : text[0];
|
||||||
|
|
||||||
|
text = AppleTags.GetText(descriptionType);
|
||||||
|
LongDescription = text.Length == 0 ? null : unicodeToAscii(text[0]);
|
||||||
|
|
||||||
|
text = AppleTags.GetText(naratorType);
|
||||||
|
Narrator = text.Length == 0 ? null : unicodeToAscii(text[0]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AaxcTagLibFile(string path) : this(new LocalFileAbstraction(path))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void CopyTagsFrom(AaxcTagLibFile sourceFile)
|
||||||
|
{
|
||||||
|
AppleTags.Clear();
|
||||||
|
|
||||||
|
//copy all metadata fields in the source file, even those that TagLib doesn't
|
||||||
|
//recognize, to the output file.
|
||||||
|
//NOTE: Chapters aren't stored in MPEG-4 metadata. They are encoded as a Timed
|
||||||
|
//Text Stream (MPEG-4 Part 17), so taglib doesn't read or write them.
|
||||||
|
foreach (var stag in sourceFile.AppleTags)
|
||||||
|
{
|
||||||
|
AppleTags.SetData(stag.BoxType, stag.Children.Cast<AppleDataBox>().ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to convert unicode characters to an approximately equal ASCII character.
|
||||||
|
/// </summary>
|
||||||
|
private string unicodeToAscii(string unicodeStr)
|
||||||
|
{
|
||||||
|
//Accents
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[éèëêð]", "e");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ÉÈËÊ]", "E");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[àâä]", "a");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ÀÁÂÃÄÅ]", "A");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[àáâãäå]", "a");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ÙÚÛÜ]", "U");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ùúûüµ]", "u");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[òóôõöø]", "o");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ÒÓÔÕÖØ]", "O");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ìíîï]", "i");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ÌÍÎÏ]", "I");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[š]", "s");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Š]", "S");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ñ]", "n");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ñ]", "N");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ç]", "c");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ç]", "C");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ÿ]", "y");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ÿ]", "Y");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ž]", "z");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ž]", "Z");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ð]", "D");
|
||||||
|
|
||||||
|
//Ligatures
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[œ]", "oe");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Œ]", "Oe");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ꜳ]", "aa");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ꜳ]", "AA");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[æ]", "ae");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Æ]", "AE");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ꜵ]", "ao");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ꜵ]", "AO");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ꜷ]", "au");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ꜷ]", "AU");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[«»ꜹꜻ]", "av");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[«»ꜸꜺ]", "AV");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[🙰]", "et");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ff]", "ff");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ffi]", "ffi");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ffl]", "ffl");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[fi]", "fi");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[fl]", "fl");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ƕ]", "hv");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ƕ]", "Hv");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[℔]", "lb");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ꝏ]", "oo");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ꝏ]", "OO");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[st]", "st");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ꜩ]", "tz");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[Ꜩ]", "TZ");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ᵫ]", "ue");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[ꭣ]", "uo");
|
||||||
|
|
||||||
|
//Punctuation
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[«»\u2018\u2019\u201A\u201B\u2032\u2035]", "\'");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[«»\u201C\u201D\u201E\u201F\u2033\u2036]", "\"");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[\u2026]", "...");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[\u1680]", "-");
|
||||||
|
|
||||||
|
//Spaces
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[«»\u00A0\u2000\u2002\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u200F\u205F\u3000]", " ");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[«»\u2001\u2003]", " ");
|
||||||
|
unicodeStr = Regex.Replace(unicodeStr, "[«»\u180E\u200B\uFEFF]", "");
|
||||||
|
|
||||||
|
return unicodeStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user