From 5815a0471298c00453ec024e11e10c633b62e533 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Fri, 24 Jun 2022 23:09:20 -0600 Subject: [PATCH 01/14] Add bitrate to Book --- Source/DataLayer/Configurations/BookConfig.cs | 2 + Source/DataLayer/EfClasses/AudioFormat.cs | 62 +++ Source/DataLayer/EfClasses/Book.cs | 5 + .../20220624214932_AddAudioFormat.Designer.cs | 397 ++++++++++++++++++ .../20220624214932_AddAudioFormat.cs | 26 ++ .../LibationContextModelSnapshot.cs | 5 +- Source/DtoImporterService/BookImporter.cs | 3 + .../Dialogs/BookDetailsDialog.cs | 1 + 8 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 Source/DataLayer/EfClasses/AudioFormat.cs create mode 100644 Source/DataLayer/Migrations/20220624214932_AddAudioFormat.Designer.cs create mode 100644 Source/DataLayer/Migrations/20220624214932_AddAudioFormat.cs diff --git a/Source/DataLayer/Configurations/BookConfig.cs b/Source/DataLayer/Configurations/BookConfig.cs index 88a92a46..17054ea7 100644 --- a/Source/DataLayer/Configurations/BookConfig.cs +++ b/Source/DataLayer/Configurations/BookConfig.cs @@ -12,11 +12,13 @@ namespace DataLayer.Configurations entity.OwnsOne(b => b.Rating); + entity.Property(nameof(Book._audioFormat)); // // CRUCIAL: ignore unmapped collections, even get-only // entity.Ignore(nameof(Book.Authors)); entity.Ignore(nameof(Book.Narrators)); + entity.Ignore(nameof(Book.AudioFormat)); //// these don't seem to matter //entity.Ignore(nameof(Book.AuthorNames)); //entity.Ignore(nameof(Book.NarratorNames)); diff --git a/Source/DataLayer/EfClasses/AudioFormat.cs b/Source/DataLayer/EfClasses/AudioFormat.cs new file mode 100644 index 00000000..2d2f9d19 --- /dev/null +++ b/Source/DataLayer/EfClasses/AudioFormat.cs @@ -0,0 +1,62 @@ +using System; + +namespace DataLayer +{ + internal enum AudioFormatEnum : long + { + //Defining the enum this way ensures that when comparing: + //LC_128_44100_stereo > LC_64_44100_stereo > LC_64_22050_stereo > LC_64_22050_stereo + //This matches how audible interprets these codecs when specifying quality using AudibleApi.DownloadQuality + //I've never seen mono formats. + Unknown = 0, + LC_32_22050_stereo = (32L << 18) | (22050 << 2) | 2, + LC_64_22050_stereo = (64L << 18) | (22050 << 2) | 2, + LC_64_44100_stereo = (64L << 18) | (44100 << 2) | 2, + LC_128_44100_stereo = (128L << 18) | (44100 << 2) | 2, + } + + public class AudioFormat : IComparable, IComparable + { + + internal int AudioFormatID { get; private set; } + public int Bitrate { get; private init; } + public int SampleRate { get; private init; } + public int Channels { get; private init; } + public bool IsValid => Bitrate != 0 && SampleRate != 0 && Channels != 0; + + public static AudioFormat FromString(string formatStr) + { + if (Enum.TryParse(formatStr, ignoreCase: true, out AudioFormatEnum enumVal)) + return FromEnum(enumVal); + return FromEnum(AudioFormatEnum.Unknown); + } + + internal static AudioFormat FromEnum(AudioFormatEnum enumVal) + { + var val = (long)enumVal; + + return new() + { + Bitrate = (int)(val >> 18), + SampleRate = (int)(val >> 2) & ushort.MaxValue, + Channels = (int)(val & 3) + }; + } + internal AudioFormatEnum ToEnum() + { + var val = (AudioFormatEnum)(((long)Bitrate << 18) | ((long)SampleRate << 2) | (long)Channels); + + return Enum.IsDefined(val) ? + val : AudioFormatEnum.Unknown; + } + + public override string ToString() + => IsValid ? + $"{Bitrate} Kbps, {SampleRate / 1000d:F1} kHz, {(Channels == 2 ? "Stereo" : Channels)}" : + "Unknown"; + + public int CompareTo(AudioFormat other) => ToEnum().CompareTo(other.ToEnum()); + + public int CompareTo(object obj) => CompareTo(obj as AudioFormat); + } +} diff --git a/Source/DataLayer/EfClasses/Book.cs b/Source/DataLayer/EfClasses/Book.cs index ef072484..22007e13 100644 --- a/Source/DataLayer/EfClasses/Book.cs +++ b/Source/DataLayer/EfClasses/Book.cs @@ -25,6 +25,7 @@ namespace DataLayer Parent = 4, } + public class Book { // implementation detail. set by db only. only used by data layer @@ -38,6 +39,10 @@ namespace DataLayer public ContentType ContentType { get; private set; } public string Locale { get; private set; } + internal AudioFormatEnum _audioFormat; + + public AudioFormat AudioFormat { get => AudioFormat.FromEnum(_audioFormat); set => _audioFormat = value.ToEnum(); } + // mutable public string PictureId { get; set; } public string PictureLarge { get; set; } diff --git a/Source/DataLayer/Migrations/20220624214932_AddAudioFormat.Designer.cs b/Source/DataLayer/Migrations/20220624214932_AddAudioFormat.Designer.cs new file mode 100644 index 00000000..fce7a0ce --- /dev/null +++ b/Source/DataLayer/Migrations/20220624214932_AddAudioFormat.Designer.cs @@ -0,0 +1,397 @@ +// +using System; +using DataLayer; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace DataLayer.Migrations +{ + [DbContext(typeof(LibationContext))] + [Migration("20220624214932_AddAudioFormat")] + partial class AddAudioFormat + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.6"); + + modelBuilder.Entity("DataLayer.Book", b => + { + b.Property("BookId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AudibleProductId") + .HasColumnType("TEXT"); + + b.Property("CategoryId") + .HasColumnType("INTEGER"); + + b.Property("ContentType") + .HasColumnType("INTEGER"); + + b.Property("DatePublished") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("IsAbridged") + .HasColumnType("INTEGER"); + + b.Property("LengthInMinutes") + .HasColumnType("INTEGER"); + + b.Property("Locale") + .HasColumnType("TEXT"); + + b.Property("PictureId") + .HasColumnType("TEXT"); + + b.Property("PictureLarge") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("_audioFormat") + .HasColumnType("INTEGER"); + + b.HasKey("BookId"); + + b.HasIndex("AudibleProductId"); + + b.HasIndex("CategoryId"); + + b.ToTable("Books"); + }); + + modelBuilder.Entity("DataLayer.BookContributor", b => + { + b.Property("BookId") + .HasColumnType("INTEGER"); + + b.Property("ContributorId") + .HasColumnType("INTEGER"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.HasKey("BookId", "ContributorId", "Role"); + + b.HasIndex("BookId"); + + b.HasIndex("ContributorId"); + + b.ToTable("BookContributor"); + }); + + modelBuilder.Entity("DataLayer.Category", b => + { + b.Property("CategoryId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AudibleCategoryId") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("ParentCategoryCategoryId") + .HasColumnType("INTEGER"); + + b.HasKey("CategoryId"); + + b.HasIndex("AudibleCategoryId"); + + b.HasIndex("ParentCategoryCategoryId"); + + b.ToTable("Categories"); + + b.HasData( + new + { + CategoryId = -1, + AudibleCategoryId = "", + Name = "" + }); + }); + + modelBuilder.Entity("DataLayer.Contributor", b => + { + b.Property("ContributorId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AudibleContributorId") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("ContributorId"); + + b.HasIndex("Name"); + + b.ToTable("Contributors"); + + b.HasData( + new + { + ContributorId = -1, + Name = "" + }); + }); + + modelBuilder.Entity("DataLayer.LibraryBook", b => + { + b.Property("BookId") + .HasColumnType("INTEGER"); + + b.Property("Account") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.HasKey("BookId"); + + b.ToTable("LibraryBooks"); + }); + + modelBuilder.Entity("DataLayer.Series", b => + { + b.Property("SeriesId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AudibleSeriesId") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("SeriesId"); + + b.HasIndex("AudibleSeriesId"); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("DataLayer.SeriesBook", b => + { + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("BookId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("TEXT"); + + b.HasKey("SeriesId", "BookId"); + + b.HasIndex("BookId"); + + b.HasIndex("SeriesId"); + + b.ToTable("SeriesBook"); + }); + + modelBuilder.Entity("DataLayer.Book", b => + { + b.HasOne("DataLayer.Category", "Category") + .WithMany() + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("DataLayer.Rating", "Rating", b1 => + { + b1.Property("BookId") + .HasColumnType("INTEGER"); + + b1.Property("OverallRating") + .HasColumnType("REAL"); + + b1.Property("PerformanceRating") + .HasColumnType("REAL"); + + b1.Property("StoryRating") + .HasColumnType("REAL"); + + b1.HasKey("BookId"); + + b1.ToTable("Books"); + + b1.WithOwner() + .HasForeignKey("BookId"); + }); + + b.OwnsMany("DataLayer.Supplement", "Supplements", b1 => + { + b1.Property("SupplementId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b1.Property("BookId") + .HasColumnType("INTEGER"); + + b1.Property("Url") + .HasColumnType("TEXT"); + + b1.HasKey("SupplementId"); + + b1.HasIndex("BookId"); + + b1.ToTable("Supplement"); + + b1.WithOwner("Book") + .HasForeignKey("BookId"); + + b1.Navigation("Book"); + }); + + b.OwnsOne("DataLayer.UserDefinedItem", "UserDefinedItem", b1 => + { + b1.Property("BookId") + .HasColumnType("INTEGER"); + + b1.Property("BookStatus") + .HasColumnType("INTEGER"); + + b1.Property("PdfStatus") + .HasColumnType("INTEGER"); + + b1.Property("Tags") + .HasColumnType("TEXT"); + + b1.HasKey("BookId"); + + b1.ToTable("UserDefinedItem", (string)null); + + b1.WithOwner("Book") + .HasForeignKey("BookId"); + + b1.OwnsOne("DataLayer.Rating", "Rating", b2 => + { + b2.Property("UserDefinedItemBookId") + .HasColumnType("INTEGER"); + + b2.Property("OverallRating") + .HasColumnType("REAL"); + + b2.Property("PerformanceRating") + .HasColumnType("REAL"); + + b2.Property("StoryRating") + .HasColumnType("REAL"); + + b2.HasKey("UserDefinedItemBookId"); + + b2.ToTable("UserDefinedItem"); + + b2.WithOwner() + .HasForeignKey("UserDefinedItemBookId"); + }); + + b1.Navigation("Book"); + + b1.Navigation("Rating"); + }); + + b.Navigation("Category"); + + b.Navigation("Rating"); + + b.Navigation("Supplements"); + + b.Navigation("UserDefinedItem"); + }); + + modelBuilder.Entity("DataLayer.BookContributor", b => + { + b.HasOne("DataLayer.Book", "Book") + .WithMany("ContributorsLink") + .HasForeignKey("BookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("DataLayer.Contributor", "Contributor") + .WithMany("BooksLink") + .HasForeignKey("ContributorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Book"); + + b.Navigation("Contributor"); + }); + + modelBuilder.Entity("DataLayer.Category", b => + { + b.HasOne("DataLayer.Category", "ParentCategory") + .WithMany() + .HasForeignKey("ParentCategoryCategoryId"); + + b.Navigation("ParentCategory"); + }); + + modelBuilder.Entity("DataLayer.LibraryBook", b => + { + b.HasOne("DataLayer.Book", "Book") + .WithOne() + .HasForeignKey("DataLayer.LibraryBook", "BookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Book"); + }); + + modelBuilder.Entity("DataLayer.SeriesBook", b => + { + b.HasOne("DataLayer.Book", "Book") + .WithMany("SeriesLink") + .HasForeignKey("BookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("DataLayer.Series", "Series") + .WithMany("BooksLink") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Book"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("DataLayer.Book", b => + { + b.Navigation("ContributorsLink"); + + b.Navigation("SeriesLink"); + }); + + modelBuilder.Entity("DataLayer.Contributor", b => + { + b.Navigation("BooksLink"); + }); + + modelBuilder.Entity("DataLayer.Series", b => + { + b.Navigation("BooksLink"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Source/DataLayer/Migrations/20220624214932_AddAudioFormat.cs b/Source/DataLayer/Migrations/20220624214932_AddAudioFormat.cs new file mode 100644 index 00000000..38c7880a --- /dev/null +++ b/Source/DataLayer/Migrations/20220624214932_AddAudioFormat.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DataLayer.Migrations +{ + public partial class AddAudioFormat : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "_audioFormat", + table: "Books", + type: "INTEGER", + nullable: false, + defaultValue: 0L); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "_audioFormat", + table: "Books"); + } + } +} diff --git a/Source/DataLayer/Migrations/LibationContextModelSnapshot.cs b/Source/DataLayer/Migrations/LibationContextModelSnapshot.cs index c198e3c0..5579839c 100644 --- a/Source/DataLayer/Migrations/LibationContextModelSnapshot.cs +++ b/Source/DataLayer/Migrations/LibationContextModelSnapshot.cs @@ -15,7 +15,7 @@ namespace DataLayer.Migrations protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "6.0.4"); + modelBuilder.HasAnnotation("ProductVersion", "6.0.6"); modelBuilder.Entity("DataLayer.Book", b => { @@ -56,6 +56,9 @@ namespace DataLayer.Migrations b.Property("Title") .HasColumnType("TEXT"); + b.Property("_audioFormat") + .HasColumnType("INTEGER"); + b.HasKey("BookId"); b.HasIndex("AudibleProductId"); diff --git a/Source/DtoImporterService/BookImporter.cs b/Source/DtoImporterService/BookImporter.cs index 67d18f4e..3e05db63 100644 --- a/Source/DtoImporterService/BookImporter.cs +++ b/Source/DtoImporterService/BookImporter.cs @@ -162,6 +162,9 @@ namespace DtoImporterService { var item = importItem.DtoItem; + var codec = item.AvailableCodecs?.Max(f => AudioFormat.FromString(f.EnhancedCodec)) ?? new AudioFormat(); + book.AudioFormat = codec; + // set/update book-specific info which may have changed if (item.PictureId is not null) book.PictureId = item.PictureId; diff --git a/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs b/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs index fdbc7ac7..838b72b7 100644 --- a/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs +++ b/Source/LibationWinForms/Dialogs/BookDetailsDialog.cs @@ -49,6 +49,7 @@ Title: {Book.Title} Author(s): {Book.AuthorNames()} Narrator(s): {Book.NarratorNames()} Length: {(Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min")} +Audio Bitrate: {Book.AudioFormat} Category: {string.Join(" > ", Book.CategoriesNames())} Purchase Date: {_libraryBook.DateAdded.ToString("d")} ".Trim(); From 1b20bb06ada64956e6585e7227380555978cbdc8 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Fri, 24 Jun 2022 23:23:08 -0600 Subject: [PATCH 02/14] Add some filename length headroom in case of diplicate files and " (n)" suffix. --- Source/FileManager/FileNamingTemplate.cs | 16 ++++++++++----- Source/FileManager/ReplacementCharacters.cs | 22 +++++++++++---------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Source/FileManager/FileNamingTemplate.cs b/Source/FileManager/FileNamingTemplate.cs index c00232a9..4d79c5af 100644 --- a/Source/FileManager/FileNamingTemplate.cs +++ b/Source/FileManager/FileNamingTemplate.cs @@ -35,18 +35,24 @@ namespace FileManager } else { - file = replaceFileName(file, paramReplacements); - fileName = Path.GetDirectoryName(fileName); pathParts.Add(file); + fileName = Path.GetDirectoryName(fileName); } } pathParts.Reverse(); + var fileNamePart = pathParts[^1]; + pathParts.Remove(fileNamePart); - return FileUtility.GetValidFilename(Path.Join(pathParts.ToArray()), replacements, returnFirstExisting); + LongPath directory = Path.Join(pathParts.Select(p => replaceFileName(p, paramReplacements, LongPath.MaxFilenameLength)).ToArray()); + + //If file already exists, GetValidFilename will append " (n)" to the filename. + //This could cause the filename length to exceed MaxFilenameLength, so reduce + //allowable filename length by 5 chars, allowing for up to 99 duplicates. + return FileUtility.GetValidFilename(Path.Join(directory, replaceFileName(fileNamePart, paramReplacements, LongPath.MaxFilenameLength - 5)), replacements, returnFirstExisting); } - private string replaceFileName(string filename, Dictionary paramReplacements) + private string replaceFileName(string filename, Dictionary paramReplacements, int maxFilenameLength) { List filenameParts = new(); //Build the filename in parts, replacing replacement parameters with @@ -82,7 +88,7 @@ namespace FileManager //Remove 1 character from the end of the longest filename part until //the total filename is less than max filename length - while (filenameParts.Sum(p => p.Length) > LongPath.MaxFilenameLength) + while (filenameParts.Sum(p => p.Length) > maxFilenameLength) { int maxLength = filenameParts.Max(p => p.Length); var maxEntry = filenameParts.First(p => p.Length == maxLength); diff --git a/Source/FileManager/ReplacementCharacters.cs b/Source/FileManager/ReplacementCharacters.cs index b81d3865..53fd9517 100644 --- a/Source/FileManager/ReplacementCharacters.cs +++ b/Source/FileManager/ReplacementCharacters.cs @@ -136,19 +136,21 @@ namespace FileManager { if (toReplace == Replacement.QUOTE_MARK) { - if (preceding == default || - (preceding != default - && !char.IsLetter(preceding) - && !char.IsNumber(preceding) - && (char.IsLetter(succeding) || char.IsNumber(succeding)) + if ( + preceding == default || + ( + !char.IsLetter(preceding) && + !char.IsNumber(preceding) && + (char.IsLetter(succeding) || char.IsNumber(succeding)) ) ) return OpenQuote; - else if (succeding == default || - (succeding != default - && !char.IsLetter(succeding) - && !char.IsNumber(succeding) - && (char.IsLetter(preceding) || char.IsNumber(preceding)) + else if ( + succeding == default || + ( + !char.IsLetter(succeding) && + !char.IsNumber(succeding) && + (char.IsLetter(preceding) || char.IsNumber(preceding)) ) ) return CloseQuote; From d58092968ad3edd05a43fea936256d8eb8a19ef5 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Fri, 24 Jun 2022 23:26:52 -0600 Subject: [PATCH 03/14] Add option to merge Opening/End Credits with following/preceding chapters --- Source/FileLiberator/DownloadDecryptBook.cs | 21 +- Source/LibationFileManager/Configuration.cs | 7 + .../Dialogs/SettingsDialog.AudioSettings.cs | 3 + .../Dialogs/SettingsDialog.Designer.cs | 22 +- .../DownloadDecryptBookTests.cs | 350 ++++++++++++------ 5 files changed, 280 insertions(+), 123 deletions(-) diff --git a/Source/FileLiberator/DownloadDecryptBook.cs b/Source/FileLiberator/DownloadDecryptBook.cs index a426cff2..855a0322 100644 --- a/Source/FileLiberator/DownloadDecryptBook.cs +++ b/Source/FileLiberator/DownloadDecryptBook.cs @@ -166,6 +166,9 @@ namespace FileLiberator }; var chapters = flattenChapters(contentLic.ContentMetadata.ChapterInfo.Chapters).OrderBy(c => c.StartOffsetMs).ToList(); + + if (config.MergeOpeningAndEndCredits) + combineCredits(chapters); if (config.AllowLibationFixup || outputFormat == OutputFormat.Mp3) { @@ -192,7 +195,7 @@ namespace FileLiberator return dlOptions; } - public static List flattenChapters(IEnumerable chapters, string titleConcat = ": ") + public static List flattenChapters(IList chapters, string titleConcat = ": ") { List chaps = new(); @@ -217,6 +220,22 @@ namespace FileLiberator return chaps; } + public static void combineCredits(IList chapters) + { + if (chapters.Count > 1 && chapters[0].Title == "Opening Credits") + { + chapters[1].StartOffsetMs = chapters[0].StartOffsetMs; + chapters[1].StartOffsetSec = chapters[0].StartOffsetSec; + chapters[1].LengthMs += chapters[0].LengthMs; + chapters.RemoveAt(0); + } + if (chapters.Count > 1 && chapters[^1].Title == "End Credits") + { + chapters[^2].LengthMs += chapters[^1].LengthMs; + chapters.Remove(chapters[^1]); + } + } + private static void downloadValidation(LibraryBook libraryBook) { string errorString(string field) diff --git a/Source/LibationFileManager/Configuration.cs b/Source/LibationFileManager/Configuration.cs index d545df22..23403699 100644 --- a/Source/LibationFileManager/Configuration.cs +++ b/Source/LibationFileManager/Configuration.cs @@ -117,6 +117,13 @@ namespace LibationFileManager set => persistentDictionary.SetNonString(nameof(SplitFilesByChapter), value); } + [Description("Merge Opening/End Credits into the following/preceding chapters")] + public bool MergeOpeningAndEndCredits + { + get => persistentDictionary.GetNonString(nameof(MergeOpeningAndEndCredits)); + set => persistentDictionary.SetNonString(nameof(MergeOpeningAndEndCredits), value); + } + [Description("Strip \"(Unabridged)\" from audiobook metadata tags")] public bool StripUnabridged { diff --git a/Source/LibationWinForms/Dialogs/SettingsDialog.AudioSettings.cs b/Source/LibationWinForms/Dialogs/SettingsDialog.AudioSettings.cs index 72f9a151..d7b53a2e 100644 --- a/Source/LibationWinForms/Dialogs/SettingsDialog.AudioSettings.cs +++ b/Source/LibationWinForms/Dialogs/SettingsDialog.AudioSettings.cs @@ -13,6 +13,7 @@ namespace LibationWinForms.Dialogs this.downloadCoverArtCbox.Text = desc(nameof(config.DownloadCoverArt)); this.retainAaxFileCbox.Text = desc(nameof(config.RetainAaxFile)); this.splitFilesByChapterCbox.Text = desc(nameof(config.SplitFilesByChapter)); + this.mergeOpeningEndCreditsCbox.Text = desc(nameof(config.MergeOpeningAndEndCredits)); this.stripAudibleBrandingCbox.Text = desc(nameof(config.StripAudibleBrandAudio)); this.stripUnabridgedCbox.Text = desc(nameof(config.StripUnabridged)); @@ -21,6 +22,7 @@ namespace LibationWinForms.Dialogs downloadCoverArtCbox.Checked = config.DownloadCoverArt; retainAaxFileCbox.Checked = config.RetainAaxFile; splitFilesByChapterCbox.Checked = config.SplitFilesByChapter; + mergeOpeningEndCreditsCbox.Checked = config.MergeOpeningAndEndCredits; stripUnabridgedCbox.Checked = config.StripUnabridged; stripAudibleBrandingCbox.Checked = config.StripAudibleBrandAudio; convertLosslessRb.Checked = !config.DecryptToLossy; @@ -50,6 +52,7 @@ namespace LibationWinForms.Dialogs config.DownloadCoverArt = downloadCoverArtCbox.Checked; config.RetainAaxFile = retainAaxFileCbox.Checked; config.SplitFilesByChapter = splitFilesByChapterCbox.Checked; + config.MergeOpeningAndEndCredits = mergeOpeningEndCreditsCbox.Checked; config.StripUnabridged = stripUnabridgedCbox.Checked; config.StripAudibleBrandAudio = stripAudibleBrandingCbox.Checked; config.DecryptToLossy = convertLossyRb.Checked; diff --git a/Source/LibationWinForms/Dialogs/SettingsDialog.Designer.cs b/Source/LibationWinForms/Dialogs/SettingsDialog.Designer.cs index d117e4fe..19166a4f 100644 --- a/Source/LibationWinForms/Dialogs/SettingsDialog.Designer.cs +++ b/Source/LibationWinForms/Dialogs/SettingsDialog.Designer.cs @@ -108,6 +108,7 @@ this.retainAaxFileCbox = new System.Windows.Forms.CheckBox(); this.downloadCoverArtCbox = new System.Windows.Forms.CheckBox(); this.createCueSheetCbox = new System.Windows.Forms.CheckBox(); + this.mergeOpeningEndCreditsCbox = new System.Windows.Forms.CheckBox(); this.badBookGb.SuspendLayout(); this.tabControl.SuspendLayout(); this.tab1ImportantSettings.SuspendLayout(); @@ -251,7 +252,7 @@ // stripAudibleBrandingCbox // this.stripAudibleBrandingCbox.AutoSize = true; - this.stripAudibleBrandingCbox.Location = new System.Drawing.Point(19, 168); + this.stripAudibleBrandingCbox.Location = new System.Drawing.Point(19, 193); this.stripAudibleBrandingCbox.Name = "stripAudibleBrandingCbox"; this.stripAudibleBrandingCbox.Size = new System.Drawing.Size(143, 34); this.stripAudibleBrandingCbox.TabIndex = 13; @@ -285,7 +286,7 @@ // convertLossyRb // this.convertLossyRb.AutoSize = true; - this.convertLossyRb.Location = new System.Drawing.Point(19, 232); + this.convertLossyRb.Location = new System.Drawing.Point(19, 257); this.convertLossyRb.Name = "convertLossyRb"; this.convertLossyRb.Size = new System.Drawing.Size(329, 19); this.convertLossyRb.TabIndex = 12; @@ -297,7 +298,7 @@ // this.convertLosslessRb.AutoSize = true; this.convertLosslessRb.Checked = true; - this.convertLosslessRb.Location = new System.Drawing.Point(19, 207); + this.convertLosslessRb.Location = new System.Drawing.Point(19, 232); this.convertLosslessRb.Name = "convertLosslessRb"; this.convertLosslessRb.Size = new System.Drawing.Size(335, 19); this.convertLosslessRb.TabIndex = 11; @@ -608,6 +609,7 @@ this.tab4AudioFileOptions.Controls.Add(this.stripAudibleBrandingCbox); this.tab4AudioFileOptions.Controls.Add(this.convertLosslessRb); this.tab4AudioFileOptions.Controls.Add(this.stripUnabridgedCbox); + this.tab4AudioFileOptions.Controls.Add(this.mergeOpeningEndCreditsCbox); this.tab4AudioFileOptions.Controls.Add(this.splitFilesByChapterCbox); this.tab4AudioFileOptions.Controls.Add(this.retainAaxFileCbox); this.tab4AudioFileOptions.Controls.Add(this.downloadCoverArtCbox); @@ -980,7 +982,7 @@ // stripUnabridgedCbox // this.stripUnabridgedCbox.AutoSize = true; - this.stripUnabridgedCbox.Location = new System.Drawing.Point(19, 143); + this.stripUnabridgedCbox.Location = new System.Drawing.Point(19, 168); this.stripUnabridgedCbox.Name = "stripUnabridgedCbox"; this.stripUnabridgedCbox.Size = new System.Drawing.Size(147, 19); this.stripUnabridgedCbox.TabIndex = 13; @@ -1024,6 +1026,17 @@ this.createCueSheetCbox.UseVisualStyleBackColor = true; this.createCueSheetCbox.CheckedChanged += new System.EventHandler(this.allowLibationFixupCbox_CheckedChanged); // + // mergeBeginningEndCreditsCbox + // + this.mergeOpeningEndCreditsCbox.AutoSize = true; + this.mergeOpeningEndCreditsCbox.Location = new System.Drawing.Point(19, 143); + this.mergeOpeningEndCreditsCbox.Name = "mergeOpeningEndCreditsCbox"; + this.mergeOpeningEndCreditsCbox.Size = new System.Drawing.Size(206, 19); + this.mergeOpeningEndCreditsCbox.TabIndex = 13; + this.mergeOpeningEndCreditsCbox.Text = "[MergeOpeningEndCredits desc]"; + this.mergeOpeningEndCreditsCbox.UseVisualStyleBackColor = true; + this.mergeOpeningEndCreditsCbox.CheckedChanged += new System.EventHandler(this.splitFilesByChapterCbox_CheckedChanged); + // // SettingsDialog // this.AcceptButton = this.saveBtn; @@ -1155,5 +1168,6 @@ private System.Windows.Forms.Button chapterTitleTemplateBtn; private System.Windows.Forms.TextBox chapterTitleTemplateTb; private System.Windows.Forms.Button editCharreplacementBtn; + private System.Windows.Forms.CheckBox mergeOpeningEndCreditsCbox; } } \ No newline at end of file diff --git a/Source/_Tests/FileLiberator.Tests/DownloadDecryptBookTests.cs b/Source/_Tests/FileLiberator.Tests/DownloadDecryptBookTests.cs index a30e585f..c2df3666 100644 --- a/Source/_Tests/FileLiberator.Tests/DownloadDecryptBookTests.cs +++ b/Source/_Tests/FileLiberator.Tests/DownloadDecryptBookTests.cs @@ -14,8 +14,142 @@ namespace FileLiberator.Tests [TestClass] public class DownloadDecryptBookTests { + private static Chapter[] HierarchicalChapters => new Chapter[] + { + new () + { + Title = "Opening Credits", + StartOffsetMs = 0, + StartOffsetSec = 0, + LengthMs = 10000, + }, + new () + { + Title = "Book 1", + StartOffsetMs = 10000, + StartOffsetSec = 10, + LengthMs = 2000, + Chapters = new Chapter[] + { + new () + { + Title = "Part 1", + StartOffsetMs = 12000, + StartOffsetSec = 12, + LengthMs = 2000, + Chapters = new Chapter[] + { + new () + { + Title = "Chapter 1", + StartOffsetMs = 14000, + StartOffsetSec = 14, + LengthMs = 86000, + }, + new() + { + Title = "Chapter 2", + StartOffsetMs = 100000, + StartOffsetSec = 100, + LengthMs = 100000, + }, + } + }, + new() + { + Title = "Part 2", + StartOffsetMs = 200000, + StartOffsetSec = 200, + LengthMs = 2000, + Chapters = new Chapter[] + { + new() + { + Title = "Chapter 3", + StartOffsetMs = 202000, + StartOffsetSec = 202, + LengthMs = 98000, + }, + new() + { + Title = "Chapter 4", + StartOffsetMs = 300000, + StartOffsetSec = 300, + LengthMs = 100000, + }, + } + } + } + }, + new() + { + Title = "Book 2", + StartOffsetMs = 400000, + StartOffsetSec = 400, + LengthMs = 2000, + Chapters = new Chapter[] + { + new() + { + Title = "Part 3", + StartOffsetMs = 402000, + StartOffsetSec = 402, + LengthMs = 2000, + Chapters = new Chapter[] + { + new() + { + Title = "Chapter 5", + StartOffsetMs = 404000, + StartOffsetSec = 404, + LengthMs = 96000, + }, + new() + { + Title = "Chapter 6", + StartOffsetMs = 500000, + StartOffsetSec = 500, + LengthMs = 100000, + }, + } + }, + new() + { + Title = "Part 4", + StartOffsetMs = 600000, + StartOffsetSec = 600, + LengthMs = 2000, + Chapters = new Chapter[] + { + new() + { + Title = "Chapter 7", + StartOffsetMs = 602000, + StartOffsetSec = 602, + LengthMs = 98000, + }, + new() + { + Title = "Chapter 8", + StartOffsetMs = 700000, + StartOffsetSec = 700, + LengthMs = 100000, + }, + } + } + } + }, + new() + { + Title = "End Credits", + StartOffsetMs = 800000, + StartOffsetSec = 800, + LengthMs = 10000, + }, + }; + [TestMethod] - public void HierarchicalChapters_Flatten() + public void Chapters_CombineCredits() { var expected = new Chapter[] { @@ -73,129 +207,109 @@ namespace FileLiberator.Tests Title = "Book 2: Part 4: Chapter 8", StartOffsetMs = 700000, StartOffsetSec = 700, - LengthMs = 100000, + LengthMs = 110000, } }; - var hierarchicalChapters = new Chapter[] - { - new() - { - Title = "Book 1", - StartOffsetMs = 0, - StartOffsetSec = 0, - LengthMs = 2000, - Chapters = new Chapter[] - { - new() - { Title = "Part 1", - StartOffsetMs = 2000, - StartOffsetSec = 2, - LengthMs = 2000, - Chapters = new Chapter[] - { - new() - { Title = "Chapter 1", - StartOffsetMs = 4000, - StartOffsetSec = 4, - LengthMs = 96000, - }, - new() - { Title = "Chapter 2", - StartOffsetMs = 100000, - StartOffsetSec = 100, - LengthMs = 100000, - }, - } - }, - new() - { Title = "Part 2", - StartOffsetMs = 200000, - StartOffsetSec = 200, - LengthMs = 2000, - Chapters = new Chapter[] - { - new() - { Title = "Chapter 3", - StartOffsetMs = 202000, - StartOffsetSec = 202, - LengthMs = 98000, - }, - new() - { Title = "Chapter 4", - StartOffsetMs = 300000, - StartOffsetSec = 300, - LengthMs = 100000, - }, - } - } - } - }, - new() - { - Title = "Book 2", - StartOffsetMs = 400000, - StartOffsetSec = 400, - LengthMs = 2000, - Chapters = new Chapter[] - { - new() - { Title = "Part 3", - StartOffsetMs = 402000, - StartOffsetSec = 402, - LengthMs = 2000, - Chapters = new Chapter[] - { - new() - { Title = "Chapter 5", - StartOffsetMs = 404000, - StartOffsetSec = 404, - LengthMs = 96000, - }, - new() - { Title = "Chapter 6", - StartOffsetMs = 500000, - StartOffsetSec = 500, - LengthMs = 100000, - }, - } - }, - new() - { Title = "Part 4", - StartOffsetMs = 600000, - StartOffsetSec = 600, - LengthMs = 2000, - Chapters = new Chapter[] - { - new() - { Title = "Chapter 7", - StartOffsetMs = 602000, - StartOffsetSec = 602, - LengthMs = 98000, - }, - new() - { Title = "Chapter 8", - StartOffsetMs = 700000, - StartOffsetSec = 700, - LengthMs = 100000, - }, - } - } - } - } - }; + var flatChapters = DownloadDecryptBook.flattenChapters(HierarchicalChapters); + DownloadDecryptBook.combineCredits(flatChapters); + checkChapters(flatChapters, expected); + } - var flatChapters = DownloadDecryptBook.flattenChapters(hierarchicalChapters); - flatChapters.Count.Should().Be(expected.Length); - - for (int i = 0; i < flatChapters.Count; i++) + [TestMethod] + public void HierarchicalChapters_Flatten() + { + var expected = new Chapter[] { - flatChapters[i].Title.Should().Be(expected[i].Title); - flatChapters[i].StartOffsetMs.Should().Be(expected[i].StartOffsetMs); - flatChapters[i].StartOffsetSec.Should().Be(expected[i].StartOffsetSec); - flatChapters[i].LengthMs.Should().Be(expected[i].LengthMs); - flatChapters[i].Chapters.Should().BeNull(); + new() + { + Title = "Opening Credits", + StartOffsetMs = 0, + StartOffsetSec = 0, + LengthMs = 10000, + }, + new() + { + Title = "Book 1: Part 1: Chapter 1", + StartOffsetMs = 10000, + StartOffsetSec = 10, + LengthMs = 90000, + }, + new() + { + Title = "Book 1: Part 1: Chapter 2", + StartOffsetMs = 100000, + StartOffsetSec = 100, + LengthMs = 100000, + }, + new() + { + Title = "Book 1: Part 2: Chapter 3", + StartOffsetMs = 200000, + StartOffsetSec = 200, + LengthMs = 100000, + }, + new() + { + Title = "Book 1: Part 2: Chapter 4", + StartOffsetMs = 300000, + StartOffsetSec = 300, + LengthMs = 100000, + }, + new() + { + Title = "Book 2: Part 3: Chapter 5", + StartOffsetMs = 400000, + StartOffsetSec = 400, + LengthMs = 100000, + }, + new() + { + Title = "Book 2: Part 3: Chapter 6", + StartOffsetMs = 500000, + StartOffsetSec = 500, + LengthMs = 100000, + }, + new() + { + Title = "Book 2: Part 4: Chapter 7", + StartOffsetMs = 600000, + StartOffsetSec = 600, + LengthMs = 100000, + }, + new() + { + Title = "Book 2: Part 4: Chapter 8", + StartOffsetMs = 700000, + StartOffsetSec = 700, + LengthMs = 100000, + }, + new() + { + Title = "End Credits", + StartOffsetMs = 800000, + StartOffsetSec = 800, + LengthMs = 10000, + } + }; + + var flatChapters = DownloadDecryptBook.flattenChapters(HierarchicalChapters); + + checkChapters(flatChapters, expected); + } + + private static void checkChapters(IList value, IList expected) + { + value.Count.Should().Be(expected.Count); + + for (int i = 0; i < value.Count; i++) + { + value[i].Title.Should().Be(expected[i].Title); + value[i].StartOffsetMs.Should().Be(expected[i].StartOffsetMs); + value[i].StartOffsetSec.Should().Be(expected[i].StartOffsetSec); + value[i].LengthMs.Should().Be(expected[i].LengthMs); + value[i].Chapters.Should().BeNull(); } } } From 071b1a54d5e3afc4b5d8007d4808fbb729f6c72e Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 25 Jun 2022 05:11:21 -0600 Subject: [PATCH 04/14] Publish Embedded --- .gitignore | 2 +- Source/AaxDecrypter/AaxDecrypter.csproj | 12 +++++++++++- Source/AppScaffolding/AppScaffolding.csproj | 8 ++++++++ Source/AppScaffolding/UNSAFE_MigrationHelper.cs | 2 +- .../ApplicationServices.csproj | 10 +++++++++- Source/AudibleUtilities/ApiExtended.cs | 12 +----------- Source/AudibleUtilities/AudibleApiValidators.cs | 12 ++++++++++++ Source/AudibleUtilities/AudibleUtilities.csproj | 16 ++++++++++++++-- Source/DataLayer/DataLayer.csproj | 14 ++++++++++---- .../DtoImporterService/DtoImporterService.csproj | 8 ++++++++ Source/FileLiberator/FileLiberator.csproj | 9 +++++++++ Source/FileManager/FileManager.csproj | 10 +++++++++- Source/Hangover/Hangover.csproj | 8 +++++--- .../PublishProfiles/FolderProfile.pubxml | 16 ++++++++++++++++ Source/LibationCli/LibationCli.csproj | 9 +++++---- .../PublishProfiles/FolderProfile.pubxml | 16 ++++++++++++++++ Source/LibationFileManager/Configuration.cs | 2 +- .../LibationFileManager.csproj | 8 ++++++++ .../LibationSearchEngine.csproj | 9 +++++++++ Source/LibationWinForms/LibationWinForms.csproj | 12 +++++++++++- .../PublishProfiles/FolderProfile.pubxml | 16 ++++++++++++++++ 21 files changed, 180 insertions(+), 31 deletions(-) create mode 100644 Source/Hangover/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 Source/LibationCli/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 Source/LibationWinForms/Properties/PublishProfiles/FolderProfile.pubxml diff --git a/.gitignore b/.gitignore index 787caf71..7ab9c6b2 100644 --- a/.gitignore +++ b/.gitignore @@ -184,7 +184,7 @@ publish/ *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted -*.pubxml +#*.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to diff --git a/Source/AaxDecrypter/AaxDecrypter.csproj b/Source/AaxDecrypter/AaxDecrypter.csproj index 90fdc76d..bb56f3ef 100644 --- a/Source/AaxDecrypter/AaxDecrypter.csproj +++ b/Source/AaxDecrypter/AaxDecrypter.csproj @@ -2,13 +2,23 @@ net6.0-windows + true - + + embedded + + + + embedded + + + + diff --git a/Source/AppScaffolding/AppScaffolding.csproj b/Source/AppScaffolding/AppScaffolding.csproj index 9408bbec..49071deb 100644 --- a/Source/AppScaffolding/AppScaffolding.csproj +++ b/Source/AppScaffolding/AppScaffolding.csproj @@ -19,4 +19,12 @@ + + embedded + + + + embedded + + diff --git a/Source/AppScaffolding/UNSAFE_MigrationHelper.cs b/Source/AppScaffolding/UNSAFE_MigrationHelper.cs index 61af7aac..fbfe6bb2 100644 --- a/Source/AppScaffolding/UNSAFE_MigrationHelper.cs +++ b/Source/AppScaffolding/UNSAFE_MigrationHelper.cs @@ -25,7 +25,7 @@ namespace AppScaffolding : value; #region appsettings.json - private static string APPSETTINGS_JSON { get; } = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "appsettings.json"); + private static string APPSETTINGS_JSON { get; } = Path.Combine(Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName), "appsettings.json"); public static bool APPSETTINGS_Json_Exists => File.Exists(APPSETTINGS_JSON); diff --git a/Source/ApplicationServices/ApplicationServices.csproj b/Source/ApplicationServices/ApplicationServices.csproj index b2c3abea..cb4528e5 100644 --- a/Source/ApplicationServices/ApplicationServices.csproj +++ b/Source/ApplicationServices/ApplicationServices.csproj @@ -1,4 +1,4 @@ - + net6.0-windows @@ -14,4 +14,12 @@ + + embedded + + + + embedded + + diff --git a/Source/AudibleUtilities/ApiExtended.cs b/Source/AudibleUtilities/ApiExtended.cs index 28fbd14f..732890ff 100644 --- a/Source/AudibleUtilities/ApiExtended.cs +++ b/Source/AudibleUtilities/ApiExtended.cs @@ -155,7 +155,7 @@ namespace AudibleUtilities //System.IO.File.WriteAllText(library_json, AudibleApi.Common.Converter.ToJson(items)); #endif var validators = new List(); - validators.AddRange(getValidators()); + validators.AddRange(Validators.GetValidators()); foreach (var v in validators) { var exceptions = v.Validate(items); @@ -329,15 +329,5 @@ namespace AudibleUtilities return results; } #endregion - - private static List getValidators() - { - var type = typeof(IValidator); - var types = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(s => s.GetTypes()) - .Where(p => type.IsAssignableFrom(p) && !p.IsInterface); - - return types.Select(t => Activator.CreateInstance(t) as IValidator).ToList(); - } } } diff --git a/Source/AudibleUtilities/AudibleApiValidators.cs b/Source/AudibleUtilities/AudibleApiValidators.cs index cae6e812..acb2ca5d 100644 --- a/Source/AudibleUtilities/AudibleApiValidators.cs +++ b/Source/AudibleUtilities/AudibleApiValidators.cs @@ -5,6 +5,18 @@ using AudibleApi.Common; namespace AudibleUtilities { + public static class Validators + { + public static IValidator[] GetValidators() + => new IValidator[] + { + new LibraryValidator(), + new BookValidator(), + new CategoryValidator(), + new ContributorValidator(), + new SeriesValidator(), + }; + } public interface IValidator { IEnumerable Validate(IEnumerable items); diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj index b5dcffd2..92a875f4 100644 --- a/Source/AudibleUtilities/AudibleUtilities.csproj +++ b/Source/AudibleUtilities/AudibleUtilities.csproj @@ -5,10 +5,22 @@ - + + + - + + + embedded + + + + embedded + + + + diff --git a/Source/DataLayer/DataLayer.csproj b/Source/DataLayer/DataLayer.csproj index 1690e74f..87bd7c77 100644 --- a/Source/DataLayer/DataLayer.csproj +++ b/Source/DataLayer/DataLayer.csproj @@ -6,9 +6,7 @@ true - Library - @@ -23,8 +21,16 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + embedded + + + + embedded + + + diff --git a/Source/DtoImporterService/DtoImporterService.csproj b/Source/DtoImporterService/DtoImporterService.csproj index a9b17110..d784be6f 100644 --- a/Source/DtoImporterService/DtoImporterService.csproj +++ b/Source/DtoImporterService/DtoImporterService.csproj @@ -4,6 +4,14 @@ net6.0-windows + + embedded + + + + embedded + + diff --git a/Source/FileLiberator/FileLiberator.csproj b/Source/FileLiberator/FileLiberator.csproj index 460308d6..65b461a1 100644 --- a/Source/FileLiberator/FileLiberator.csproj +++ b/Source/FileLiberator/FileLiberator.csproj @@ -11,4 +11,13 @@ + + embedded + + + + embedded + + + diff --git a/Source/FileManager/FileManager.csproj b/Source/FileManager/FileManager.csproj index 16363aa5..28f22c83 100644 --- a/Source/FileManager/FileManager.csproj +++ b/Source/FileManager/FileManager.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -9,4 +9,12 @@ + + embedded + + + + embedded + + diff --git a/Source/Hangover/Hangover.csproj b/Source/Hangover/Hangover.csproj index 7c90124e..5c2c104a 100644 --- a/Source/Hangover/Hangover.csproj +++ b/Source/Hangover/Hangover.csproj @@ -24,11 +24,13 @@ edit debug and release output paths --> - ..\LibationWinForms\bin\Debug + ..\bin\Debug + embedded - ..\LibationWinForms\bin\Release + ..\bin\Release + embedded @@ -37,7 +39,7 @@ - + Form1.cs diff --git a/Source/Hangover/Properties/PublishProfiles/FolderProfile.pubxml b/Source/Hangover/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 00000000..3ed14ad3 --- /dev/null +++ b/Source/Hangover/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,16 @@ + + + + + Release + Any CPU + ..\bin\publish\ + FileSystem + net6.0-windows + win-x64 + false + false + + \ No newline at end of file diff --git a/Source/LibationCli/LibationCli.csproj b/Source/LibationCli/LibationCli.csproj index 84f16e9b..e3b1fa09 100644 --- a/Source/LibationCli/LibationCli.csproj +++ b/Source/LibationCli/LibationCli.csproj @@ -4,12 +4,11 @@ Exe net6.0-windows - - true true win-x64 false false + True - ..\LibationWinForms\bin\Debug + ..\bin\Debug + embedded - ..\LibationWinForms\bin\Release + ..\bin\Release + embedded diff --git a/Source/LibationCli/Properties/PublishProfiles/FolderProfile.pubxml b/Source/LibationCli/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 00000000..3ed14ad3 --- /dev/null +++ b/Source/LibationCli/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,16 @@ + + + + + Release + Any CPU + ..\bin\publish\ + FileSystem + net6.0-windows + win-x64 + false + false + + \ No newline at end of file diff --git a/Source/LibationFileManager/Configuration.cs b/Source/LibationFileManager/Configuration.cs index 23403699..f7000e07 100644 --- a/Source/LibationFileManager/Configuration.cs +++ b/Source/LibationFileManager/Configuration.cs @@ -444,7 +444,7 @@ namespace LibationFileManager #endregion #region LibationFiles - private static string APPSETTINGS_JSON { get; } = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "appsettings.json"); + private static string APPSETTINGS_JSON { get; } = Path.Combine(Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName), "appsettings.json"); private const string LIBATION_FILES_KEY = "LibationFiles"; [Description("Location for storage of program-created files")] diff --git a/Source/LibationFileManager/LibationFileManager.csproj b/Source/LibationFileManager/LibationFileManager.csproj index 4648a9ee..04ae43f2 100644 --- a/Source/LibationFileManager/LibationFileManager.csproj +++ b/Source/LibationFileManager/LibationFileManager.csproj @@ -14,4 +14,12 @@ + + embedded + + + + embedded + + diff --git a/Source/LibationSearchEngine/LibationSearchEngine.csproj b/Source/LibationSearchEngine/LibationSearchEngine.csproj index 9fc7e889..5e811683 100644 --- a/Source/LibationSearchEngine/LibationSearchEngine.csproj +++ b/Source/LibationSearchEngine/LibationSearchEngine.csproj @@ -15,5 +15,14 @@ + + + embedded + + + + embedded + + diff --git a/Source/LibationWinForms/LibationWinForms.csproj b/Source/LibationWinForms/LibationWinForms.csproj index b21cadd3..b15b714c 100644 --- a/Source/LibationWinForms/LibationWinForms.csproj +++ b/Source/LibationWinForms/LibationWinForms.csproj @@ -7,7 +7,7 @@ true libation.ico Libation - + true win-x64 false @@ -27,6 +27,16 @@ en;es + + ..\bin\Debug + embedded + + + + ..\bin\Release + embedded + + diff --git a/Source/LibationWinForms/Properties/PublishProfiles/FolderProfile.pubxml b/Source/LibationWinForms/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 00000000..3ed14ad3 --- /dev/null +++ b/Source/LibationWinForms/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,16 @@ + + + + + Release + Any CPU + ..\bin\publish\ + FileSystem + net6.0-windows + win-x64 + false + false + + \ No newline at end of file From d48a74912a1abb3574276f34ea09c09f21f53523 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 25 Jun 2022 16:48:23 -0600 Subject: [PATCH 05/14] Use abstract static member, add publish script --- Source/.config/dotnet-tools.json | 12 +++++++ Source/AppScaffolding/.msbump | 4 --- Source/AppScaffolding/AppScaffolding.csproj | 32 ++++++++----------- .../ApplicationServices.csproj | 1 + Source/AudibleUtilities/ApiExtended.cs | 17 +++++----- .../AudibleUtilities/AudibleApiValidators.cs | 27 ++++++---------- .../AudibleUtilities/AudibleUtilities.csproj | 5 ++- Source/DtoImporterService/BookImporter.cs | 4 +-- Source/DtoImporterService/CategoryImporter.cs | 4 +-- .../DtoImporterService/ContributorImporter.cs | 4 +-- .../DtoImporterService.csproj | 1 + Source/DtoImporterService/ImporterBase.cs | 20 +++--------- .../DtoImporterService/LibraryBookImporter.cs | 4 +-- Source/DtoImporterService/SeriesImporter.cs | 4 +-- Source/FileLiberator/FileLiberator.csproj | 1 + Source/Hangover/Hangover.csproj | 2 +- Source/LibationCli/LibationCli.csproj | 1 + .../LibationWinForms/LibationWinForms.csproj | 1 + .../PublishProfiles/FolderProfile.pubxml | 2 +- Source/publish.bat | 4 +++ 20 files changed, 66 insertions(+), 84 deletions(-) create mode 100644 Source/.config/dotnet-tools.json delete mode 100644 Source/AppScaffolding/.msbump create mode 100644 Source/publish.bat diff --git a/Source/.config/dotnet-tools.json b/Source/.config/dotnet-tools.json new file mode 100644 index 00000000..921204ae --- /dev/null +++ b/Source/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "frogvall.dotnetbumpversion": { + "version": "3.0.1", + "commands": [ + "bump-version" + ] + } + } +} \ No newline at end of file diff --git a/Source/AppScaffolding/.msbump b/Source/AppScaffolding/.msbump deleted file mode 100644 index e9c0b591..00000000 --- a/Source/AppScaffolding/.msbump +++ /dev/null @@ -1,4 +0,0 @@ -{ - "//": "https://github.com/BalassaMarton/MSBump", - BumpRevision: true -} diff --git a/Source/AppScaffolding/AppScaffolding.csproj b/Source/AppScaffolding/AppScaffolding.csproj index 59092d01..497bd40a 100644 --- a/Source/AppScaffolding/AppScaffolding.csproj +++ b/Source/AppScaffolding/AppScaffolding.csproj @@ -1,30 +1,24 @@ - + - net6.0-windows - 8.1.4.1 + True + 8.1.4.16 - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - embedded - - - - embedded - - - + + embedded + + + embedded + + + + + \ No newline at end of file diff --git a/Source/ApplicationServices/ApplicationServices.csproj b/Source/ApplicationServices/ApplicationServices.csproj index cb4528e5..87a0fb18 100644 --- a/Source/ApplicationServices/ApplicationServices.csproj +++ b/Source/ApplicationServices/ApplicationServices.csproj @@ -2,6 +2,7 @@ net6.0-windows + True diff --git a/Source/AudibleUtilities/ApiExtended.cs b/Source/AudibleUtilities/ApiExtended.cs index 732890ff..9a8c0254 100644 --- a/Source/AudibleUtilities/ApiExtended.cs +++ b/Source/AudibleUtilities/ApiExtended.cs @@ -154,15 +154,16 @@ namespace AudibleUtilities #if DEBUG //System.IO.File.WriteAllText(library_json, AudibleApi.Common.Converter.ToJson(items)); #endif - var validators = new List(); - validators.AddRange(Validators.GetValidators()); - foreach (var v in validators) - { - var exceptions = v.Validate(items); - if (exceptions is not null && exceptions.Any()) - throw new AggregateException(exceptions); - } + var exceptions = new List(); + exceptions.AddRange(IValidator.Validate(items)); + exceptions.AddRange(IValidator.Validate(items)); + exceptions.AddRange(IValidator.Validate(items)); + exceptions.AddRange(IValidator.Validate(items)); + exceptions.AddRange(IValidator.Validate(items)); + + if (exceptions.Any()) + throw new AggregateException(exceptions); return items; } diff --git a/Source/AudibleUtilities/AudibleApiValidators.cs b/Source/AudibleUtilities/AudibleApiValidators.cs index acb2ca5d..c0b4af43 100644 --- a/Source/AudibleUtilities/AudibleApiValidators.cs +++ b/Source/AudibleUtilities/AudibleApiValidators.cs @@ -5,25 +5,16 @@ using AudibleApi.Common; namespace AudibleUtilities { - public static class Validators - { - public static IValidator[] GetValidators() - => new IValidator[] - { - new LibraryValidator(), - new BookValidator(), - new CategoryValidator(), - new ContributorValidator(), - new SeriesValidator(), - }; - } public interface IValidator { - IEnumerable Validate(IEnumerable items); + public static abstract IEnumerable Validate(IEnumerable items); + public static IEnumerable Validate(IEnumerable items) + where T : IValidator + => T.Validate(items); } public class LibraryValidator : IValidator { - public IEnumerable Validate(IEnumerable items) + public static IEnumerable Validate(IEnumerable items) { var exceptions = new List(); @@ -37,7 +28,7 @@ namespace AudibleUtilities } public class BookValidator : IValidator { - public IEnumerable Validate(IEnumerable items) + public static IEnumerable Validate(IEnumerable items) { var exceptions = new List(); @@ -55,7 +46,7 @@ namespace AudibleUtilities } public class CategoryValidator : IValidator { - public IEnumerable Validate(IEnumerable items) + public static IEnumerable Validate(IEnumerable items) { var exceptions = new List(); @@ -70,7 +61,7 @@ namespace AudibleUtilities } public class ContributorValidator : IValidator { - public IEnumerable Validate(IEnumerable items) + public static IEnumerable Validate(IEnumerable items) { var exceptions = new List(); @@ -84,7 +75,7 @@ namespace AudibleUtilities } public class SeriesValidator : IValidator { - public IEnumerable Validate(IEnumerable items) + public static IEnumerable Validate(IEnumerable items) { var exceptions = new List(); diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj index 92a875f4..191fbd40 100644 --- a/Source/AudibleUtilities/AudibleUtilities.csproj +++ b/Source/AudibleUtilities/AudibleUtilities.csproj @@ -2,12 +2,11 @@ net6.0-windows + True - - - + diff --git a/Source/DtoImporterService/BookImporter.cs b/Source/DtoImporterService/BookImporter.cs index 3e05db63..ed5d7cde 100644 --- a/Source/DtoImporterService/BookImporter.cs +++ b/Source/DtoImporterService/BookImporter.cs @@ -8,10 +8,8 @@ using Dinah.Core.Collections.Generic; namespace DtoImporterService { - public class BookImporter : ItemsImporterBase + public class BookImporter : ImporterBase { - protected override IValidator Validator => new BookValidator(); - public Dictionary Cache { get; private set; } = new(); private ContributorImporter contributorImporter { get; } diff --git a/Source/DtoImporterService/CategoryImporter.cs b/Source/DtoImporterService/CategoryImporter.cs index 5a3434c6..99dda82f 100644 --- a/Source/DtoImporterService/CategoryImporter.cs +++ b/Source/DtoImporterService/CategoryImporter.cs @@ -8,10 +8,8 @@ using Dinah.Core.Collections.Generic; namespace DtoImporterService { - public class CategoryImporter : ItemsImporterBase + public class CategoryImporter : ImporterBase { - protected override IValidator Validator => new CategoryValidator(); - public Dictionary Cache { get; private set; } = new(); public CategoryImporter(LibationContext context) : base(context) { } diff --git a/Source/DtoImporterService/ContributorImporter.cs b/Source/DtoImporterService/ContributorImporter.cs index dd3e273f..f7fa41c5 100644 --- a/Source/DtoImporterService/ContributorImporter.cs +++ b/Source/DtoImporterService/ContributorImporter.cs @@ -8,10 +8,8 @@ using Dinah.Core.Collections.Generic; namespace DtoImporterService { - public class ContributorImporter : ItemsImporterBase + public class ContributorImporter : ImporterBase { - protected override IValidator Validator => new ContributorValidator(); - public Dictionary Cache { get; private set; } = new(); public ContributorImporter(LibationContext context) : base(context) { } diff --git a/Source/DtoImporterService/DtoImporterService.csproj b/Source/DtoImporterService/DtoImporterService.csproj index d784be6f..749d1a5b 100644 --- a/Source/DtoImporterService/DtoImporterService.csproj +++ b/Source/DtoImporterService/DtoImporterService.csproj @@ -2,6 +2,7 @@ net6.0-windows + True diff --git a/Source/DtoImporterService/ImporterBase.cs b/Source/DtoImporterService/ImporterBase.cs index 278659c7..bb5142c0 100644 --- a/Source/DtoImporterService/ImporterBase.cs +++ b/Source/DtoImporterService/ImporterBase.cs @@ -7,7 +7,7 @@ using Dinah.Core; namespace DtoImporterService { - public abstract class ImporterBase + public abstract class ImporterBase where TValidate : IValidator { protected LibationContext DbContext { get; } @@ -18,13 +18,13 @@ namespace DtoImporterService } /// LONG RUNNING. call with await Task.Run - public int Import(T param) => Run(DoImport, param); + public int Import(IEnumerable param) => Run(DoImport, param); - public TResult Run(Func func, T param) + public TResult Run(Func, TResult> func, IEnumerable param) { try { - var exceptions = Validate(param); + var exceptions = TValidate.Validate(param.Select(i => i.DtoItem)); if (exceptions is not null && exceptions.Any()) throw new AggregateException($"Importer validation failed", exceptions); } @@ -46,16 +46,6 @@ namespace DtoImporterService } } - protected abstract int DoImport(T elements); - public abstract IEnumerable Validate(T param); - } - - public abstract class ItemsImporterBase : ImporterBase> - { - protected ItemsImporterBase(LibationContext context) : base(context) { } - - protected abstract IValidator Validator { get; } - public sealed override IEnumerable Validate(IEnumerable importItems) - => Validator.Validate(importItems.Select(i => i.DtoItem)); + protected abstract int DoImport(IEnumerable elements); } } diff --git a/Source/DtoImporterService/LibraryBookImporter.cs b/Source/DtoImporterService/LibraryBookImporter.cs index 634d8494..9590393b 100644 --- a/Source/DtoImporterService/LibraryBookImporter.cs +++ b/Source/DtoImporterService/LibraryBookImporter.cs @@ -7,10 +7,8 @@ using Dinah.Core.Collections.Generic; namespace DtoImporterService { - public class LibraryBookImporter : ItemsImporterBase + public class LibraryBookImporter : ImporterBase { - protected override IValidator Validator => new LibraryValidator(); - private BookImporter bookImporter { get; } public LibraryBookImporter(LibationContext context) : base(context) diff --git a/Source/DtoImporterService/SeriesImporter.cs b/Source/DtoImporterService/SeriesImporter.cs index 67f5d487..e4541d01 100644 --- a/Source/DtoImporterService/SeriesImporter.cs +++ b/Source/DtoImporterService/SeriesImporter.cs @@ -8,10 +8,8 @@ using Dinah.Core.Collections.Generic; namespace DtoImporterService { - public class SeriesImporter : ItemsImporterBase + public class SeriesImporter : ImporterBase { - protected override IValidator Validator => new SeriesValidator(); - public Dictionary Cache { get; private set; } = new(); public SeriesImporter(LibationContext context) : base(context) { } diff --git a/Source/FileLiberator/FileLiberator.csproj b/Source/FileLiberator/FileLiberator.csproj index 65b461a1..5d8093fa 100644 --- a/Source/FileLiberator/FileLiberator.csproj +++ b/Source/FileLiberator/FileLiberator.csproj @@ -2,6 +2,7 @@ net6.0-windows + True diff --git a/Source/Hangover/Hangover.csproj b/Source/Hangover/Hangover.csproj index 5c2c104a..b421f3e5 100644 --- a/Source/Hangover/Hangover.csproj +++ b/Source/Hangover/Hangover.csproj @@ -6,7 +6,7 @@ true hangover.ico enable - + True true win-x64 false diff --git a/Source/LibationCli/LibationCli.csproj b/Source/LibationCli/LibationCli.csproj index e3b1fa09..b1edb68b 100644 --- a/Source/LibationCli/LibationCli.csproj +++ b/Source/LibationCli/LibationCli.csproj @@ -5,6 +5,7 @@ Exe net6.0-windows true + True win-x64 false false diff --git a/Source/LibationWinForms/LibationWinForms.csproj b/Source/LibationWinForms/LibationWinForms.csproj index b15b714c..340aecd7 100644 --- a/Source/LibationWinForms/LibationWinForms.csproj +++ b/Source/LibationWinForms/LibationWinForms.csproj @@ -6,6 +6,7 @@ net6.0-windows true libation.ico + True Libation true diff --git a/Source/LibationWinForms/Properties/PublishProfiles/FolderProfile.pubxml b/Source/LibationWinForms/Properties/PublishProfiles/FolderProfile.pubxml index 3ed14ad3..806982d7 100644 --- a/Source/LibationWinForms/Properties/PublishProfiles/FolderProfile.pubxml +++ b/Source/LibationWinForms/Properties/PublishProfiles/FolderProfile.pubxml @@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release - Any CPU + x64 ..\bin\publish\ FileSystem net6.0-windows diff --git a/Source/publish.bat b/Source/publish.bat new file mode 100644 index 00000000..e03f315d --- /dev/null +++ b/Source/publish.bat @@ -0,0 +1,4 @@ +rmdir bin\Publish /S /Q +dotnet publish LibationWinForms\LibationWinForms.csproj -p:PublishProfile=LibationWinForms\Properties\PublishProfiles\FolderProfile.pubxml +dotnet publish LibationCli\LibationCli.csproj -p:PublishProfile=LibationCli\Properties\PublishProfiles\FolderProfile.pubxml +dotnet publish Hangover\Hangover.csproj -p:PublishProfile=Hangover\Properties\PublishProfiles\FolderProfile.pubxml \ No newline at end of file From a8987cf1d3afb554f26f65536077deacd225650f Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sat, 25 Jun 2022 17:06:28 -0600 Subject: [PATCH 06/14] Only increment build number on debug builds --- Source/AaxDecrypter/AaxDecrypter.csproj | 1 - Source/AppScaffolding/AppScaffolding.csproj | 4 ++-- .../AudibleUtilities.Tests/AudibleUtilities.Tests.csproj | 1 + .../_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj | 1 + Source/publish.bat | 6 +++--- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/AaxDecrypter/AaxDecrypter.csproj b/Source/AaxDecrypter/AaxDecrypter.csproj index bb56f3ef..84bfe99c 100644 --- a/Source/AaxDecrypter/AaxDecrypter.csproj +++ b/Source/AaxDecrypter/AaxDecrypter.csproj @@ -2,7 +2,6 @@ net6.0-windows - true diff --git a/Source/AppScaffolding/AppScaffolding.csproj b/Source/AppScaffolding/AppScaffolding.csproj index 497bd40a..1af8a597 100644 --- a/Source/AppScaffolding/AppScaffolding.csproj +++ b/Source/AppScaffolding/AppScaffolding.csproj @@ -3,7 +3,7 @@ net6.0-windows True - 8.1.4.16 + 8.1.4.30 @@ -19,6 +19,6 @@ embedded - + \ No newline at end of file diff --git a/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj b/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj index ef046649..ea2b8e86 100644 --- a/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj +++ b/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj @@ -2,6 +2,7 @@ net6.0-windows + True false diff --git a/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj b/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj index 61822f5e..8e349d08 100644 --- a/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj +++ b/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj @@ -2,6 +2,7 @@ net6.0-windows + True false diff --git a/Source/publish.bat b/Source/publish.bat index e03f315d..3b9e523b 100644 --- a/Source/publish.bat +++ b/Source/publish.bat @@ -1,4 +1,4 @@ rmdir bin\Publish /S /Q -dotnet publish LibationWinForms\LibationWinForms.csproj -p:PublishProfile=LibationWinForms\Properties\PublishProfiles\FolderProfile.pubxml -dotnet publish LibationCli\LibationCli.csproj -p:PublishProfile=LibationCli\Properties\PublishProfiles\FolderProfile.pubxml -dotnet publish Hangover\Hangover.csproj -p:PublishProfile=Hangover\Properties\PublishProfiles\FolderProfile.pubxml \ No newline at end of file +dotnet publish -c Release LibationWinForms\LibationWinForms.csproj -p:PublishProfile=LibationWinForms\Properties\PublishProfiles\FolderProfile.pubxml +dotnet publish -c Release LibationCli\LibationCli.csproj -p:PublishProfile=LibationCli\Properties\PublishProfiles\FolderProfile.pubxml +dotnet publish -c Release Hangover\Hangover.csproj -p:PublishProfile=Hangover\Properties\PublishProfiles\FolderProfile.pubxml \ No newline at end of file From 6826237657899deb6afdd22c69b203ef7656b294 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sun, 26 Jun 2022 01:16:17 -0600 Subject: [PATCH 07/14] Use powershell script to publish and zip libation --- Source/AppScaffolding/AppScaffolding.csproj | 2 +- Source/publish.bat | 4 ---- Source/publish.ps1 | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) delete mode 100644 Source/publish.bat create mode 100644 Source/publish.ps1 diff --git a/Source/AppScaffolding/AppScaffolding.csproj b/Source/AppScaffolding/AppScaffolding.csproj index 1af8a597..6be592b1 100644 --- a/Source/AppScaffolding/AppScaffolding.csproj +++ b/Source/AppScaffolding/AppScaffolding.csproj @@ -3,7 +3,7 @@ net6.0-windows True - 8.1.4.30 + 8.1.4.31 diff --git a/Source/publish.bat b/Source/publish.bat deleted file mode 100644 index 3b9e523b..00000000 --- a/Source/publish.bat +++ /dev/null @@ -1,4 +0,0 @@ -rmdir bin\Publish /S /Q -dotnet publish -c Release LibationWinForms\LibationWinForms.csproj -p:PublishProfile=LibationWinForms\Properties\PublishProfiles\FolderProfile.pubxml -dotnet publish -c Release LibationCli\LibationCli.csproj -p:PublishProfile=LibationCli\Properties\PublishProfiles\FolderProfile.pubxml -dotnet publish -c Release Hangover\Hangover.csproj -p:PublishProfile=Hangover\Properties\PublishProfiles\FolderProfile.pubxml \ No newline at end of file diff --git a/Source/publish.ps1 b/Source/publish.ps1 new file mode 100644 index 00000000..42526049 --- /dev/null +++ b/Source/publish.ps1 @@ -0,0 +1,15 @@ +<# You must enable running powershell scripts. + + Set-ExecutionPolicy -Scope CurrentUser Unrestricted +#> + +$pubDir = "bin\Publish" +Remove-Item $pubDir -Recurse -Force + +dotnet publish -c Release LibationWinForms\LibationWinForms.csproj -p:PublishProfile=LibationWinForms\Properties\PublishProfiles\FolderProfile.pubxml +dotnet publish -c Release LibationCli\LibationCli.csproj -p:PublishProfile=LibationCli\Properties\PublishProfiles\FolderProfile.pubxml +dotnet publish -c Release Hangover\Hangover.csproj -p:PublishProfile=Hangover\Properties\PublishProfiles\FolderProfile.pubxml + +$verMatch = Select-String -Path 'AppScaffolding\AppScaffolding.csproj' -Pattern '(\d{0,3}\.\d{0,3}\.\d{0,3})\.\d{0,3}' +$archiveName = "bin\Libation."+$verMatch.Matches.Groups[1].Value+".zip" +Compress-Archive -Path $pubDir -DestinationPath $archiveName -Force \ No newline at end of file From 888967be316ddd8c9172d328084e2861299c187c Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sun, 26 Jun 2022 01:22:46 -0600 Subject: [PATCH 08/14] Pack files, not folder. --- Source/publish.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/publish.ps1 b/Source/publish.ps1 index 42526049..23fba050 100644 --- a/Source/publish.ps1 +++ b/Source/publish.ps1 @@ -12,4 +12,5 @@ dotnet publish -c Release Hangover\Hangover.csproj -p:PublishProfile=Hangover\Pr $verMatch = Select-String -Path 'AppScaffolding\AppScaffolding.csproj' -Pattern '(\d{0,3}\.\d{0,3}\.\d{0,3})\.\d{0,3}' $archiveName = "bin\Libation."+$verMatch.Matches.Groups[1].Value+".zip" -Compress-Archive -Path $pubDir -DestinationPath $archiveName -Force \ No newline at end of file +Get-ChildItem -Path $pubDir -Recurse | + Compress-Archive -DestinationPath $archiveName -Force \ No newline at end of file From 3ce1f94f871b85d7ccb2af366f0fb2fe2e0f406a Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sun, 26 Jun 2022 10:42:52 -0600 Subject: [PATCH 09/14] Revert preview feature --- Source/AppScaffolding/AppScaffolding.csproj | 1 - .../ApplicationServices.csproj | 1 - Source/AudibleUtilities/ApiExtended.cs | 28 ++++++++++++------- .../AudibleUtilities/AudibleApiValidators.cs | 15 ++++------ .../AudibleUtilities/AudibleUtilities.csproj | 1 - Source/DtoImporterService/BookImporter.cs | 4 ++- Source/DtoImporterService/CategoryImporter.cs | 4 ++- .../DtoImporterService/ContributorImporter.cs | 10 ++++--- .../DtoImporterService.csproj | 1 - Source/DtoImporterService/ImporterBase.cs | 20 +++++++++---- .../DtoImporterService/LibraryBookImporter.cs | 6 ++-- Source/DtoImporterService/SeriesImporter.cs | 4 ++- Source/FileLiberator/FileLiberator.csproj | 1 - Source/Hangover/Hangover.csproj | 1 - Source/LibationCli/LibationCli.csproj | 1 - .../LibationWinForms/LibationWinForms.csproj | 1 - .../AudibleUtilities.Tests.csproj | 2 -- .../FileLiberator.Tests.csproj | 2 -- 18 files changed, 58 insertions(+), 45 deletions(-) diff --git a/Source/AppScaffolding/AppScaffolding.csproj b/Source/AppScaffolding/AppScaffolding.csproj index 6be592b1..67f36a31 100644 --- a/Source/AppScaffolding/AppScaffolding.csproj +++ b/Source/AppScaffolding/AppScaffolding.csproj @@ -2,7 +2,6 @@ net6.0-windows - True 8.1.4.31 diff --git a/Source/ApplicationServices/ApplicationServices.csproj b/Source/ApplicationServices/ApplicationServices.csproj index 87a0fb18..cb4528e5 100644 --- a/Source/ApplicationServices/ApplicationServices.csproj +++ b/Source/ApplicationServices/ApplicationServices.csproj @@ -2,7 +2,6 @@ net6.0-windows - True diff --git a/Source/AudibleUtilities/ApiExtended.cs b/Source/AudibleUtilities/ApiExtended.cs index 9a8c0254..33e5f41a 100644 --- a/Source/AudibleUtilities/ApiExtended.cs +++ b/Source/AudibleUtilities/ApiExtended.cs @@ -154,19 +154,27 @@ namespace AudibleUtilities #if DEBUG //System.IO.File.WriteAllText(library_json, AudibleApi.Common.Converter.ToJson(items)); #endif - var exceptions = new List(); - - exceptions.AddRange(IValidator.Validate(items)); - exceptions.AddRange(IValidator.Validate(items)); - exceptions.AddRange(IValidator.Validate(items)); - exceptions.AddRange(IValidator.Validate(items)); - exceptions.AddRange(IValidator.Validate(items)); - - if (exceptions.Any()) - throw new AggregateException(exceptions); + var validators = new List(); + validators.AddRange(getValidators()); + foreach (var v in validators) + { + var exceptions = v.Validate(items); + if (exceptions is not null && exceptions.Any()) + throw new AggregateException(exceptions); + } return items; } + private static List getValidators() + { + var type = typeof(IValidator); + var types = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(s => s.GetTypes()) + .Where(p => type.IsAssignableFrom(p) && !p.IsInterface); + + return types.Select(t => Activator.CreateInstance(t) as IValidator).ToList(); + } + #region episodes and podcasts private async Task> getChildEpisodesAsync(SemaphoreSlim concurrencySemaphore, Item parent) diff --git a/Source/AudibleUtilities/AudibleApiValidators.cs b/Source/AudibleUtilities/AudibleApiValidators.cs index c0b4af43..cae6e812 100644 --- a/Source/AudibleUtilities/AudibleApiValidators.cs +++ b/Source/AudibleUtilities/AudibleApiValidators.cs @@ -7,14 +7,11 @@ namespace AudibleUtilities { public interface IValidator { - public static abstract IEnumerable Validate(IEnumerable items); - public static IEnumerable Validate(IEnumerable items) - where T : IValidator - => T.Validate(items); + IEnumerable Validate(IEnumerable items); } public class LibraryValidator : IValidator { - public static IEnumerable Validate(IEnumerable items) + public IEnumerable Validate(IEnumerable items) { var exceptions = new List(); @@ -28,7 +25,7 @@ namespace AudibleUtilities } public class BookValidator : IValidator { - public static IEnumerable Validate(IEnumerable items) + public IEnumerable Validate(IEnumerable items) { var exceptions = new List(); @@ -46,7 +43,7 @@ namespace AudibleUtilities } public class CategoryValidator : IValidator { - public static IEnumerable Validate(IEnumerable items) + public IEnumerable Validate(IEnumerable items) { var exceptions = new List(); @@ -61,7 +58,7 @@ namespace AudibleUtilities } public class ContributorValidator : IValidator { - public static IEnumerable Validate(IEnumerable items) + public IEnumerable Validate(IEnumerable items) { var exceptions = new List(); @@ -75,7 +72,7 @@ namespace AudibleUtilities } public class SeriesValidator : IValidator { - public static IEnumerable Validate(IEnumerable items) + public IEnumerable Validate(IEnumerable items) { var exceptions = new List(); diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj index 191fbd40..42a54f46 100644 --- a/Source/AudibleUtilities/AudibleUtilities.csproj +++ b/Source/AudibleUtilities/AudibleUtilities.csproj @@ -2,7 +2,6 @@ net6.0-windows - True diff --git a/Source/DtoImporterService/BookImporter.cs b/Source/DtoImporterService/BookImporter.cs index ed5d7cde..3e05db63 100644 --- a/Source/DtoImporterService/BookImporter.cs +++ b/Source/DtoImporterService/BookImporter.cs @@ -8,8 +8,10 @@ using Dinah.Core.Collections.Generic; namespace DtoImporterService { - public class BookImporter : ImporterBase + public class BookImporter : ItemsImporterBase { + protected override IValidator Validator => new BookValidator(); + public Dictionary Cache { get; private set; } = new(); private ContributorImporter contributorImporter { get; } diff --git a/Source/DtoImporterService/CategoryImporter.cs b/Source/DtoImporterService/CategoryImporter.cs index 99dda82f..5a3434c6 100644 --- a/Source/DtoImporterService/CategoryImporter.cs +++ b/Source/DtoImporterService/CategoryImporter.cs @@ -8,8 +8,10 @@ using Dinah.Core.Collections.Generic; namespace DtoImporterService { - public class CategoryImporter : ImporterBase + public class CategoryImporter : ItemsImporterBase { + protected override IValidator Validator => new CategoryValidator(); + public Dictionary Cache { get; private set; } = new(); public CategoryImporter(LibationContext context) : base(context) { } diff --git a/Source/DtoImporterService/ContributorImporter.cs b/Source/DtoImporterService/ContributorImporter.cs index f7fa41c5..2f6d255f 100644 --- a/Source/DtoImporterService/ContributorImporter.cs +++ b/Source/DtoImporterService/ContributorImporter.cs @@ -8,8 +8,10 @@ using Dinah.Core.Collections.Generic; namespace DtoImporterService { - public class ContributorImporter : ImporterBase + public class ContributorImporter : ItemsImporterBase { + protected override IValidator Validator => new ContributorValidator(); + public Dictionary Cache { get; private set; } = new(); public ContributorImporter(LibationContext context) : base(context) { } @@ -89,7 +91,7 @@ namespace DtoImporterService return hash.Count; } - private Contributor addContributor(string name, string id = null) + private Contributor addContributor(string name, string id = null) { try { @@ -106,6 +108,6 @@ namespace DtoImporterService Serilog.Log.Logger.Error(ex, "Error adding contributor. {@DebugInfo}", new { name, id }); throw; } - } - } + } + } } diff --git a/Source/DtoImporterService/DtoImporterService.csproj b/Source/DtoImporterService/DtoImporterService.csproj index 749d1a5b..d784be6f 100644 --- a/Source/DtoImporterService/DtoImporterService.csproj +++ b/Source/DtoImporterService/DtoImporterService.csproj @@ -2,7 +2,6 @@ net6.0-windows - True diff --git a/Source/DtoImporterService/ImporterBase.cs b/Source/DtoImporterService/ImporterBase.cs index bb5142c0..5f3298b9 100644 --- a/Source/DtoImporterService/ImporterBase.cs +++ b/Source/DtoImporterService/ImporterBase.cs @@ -7,7 +7,7 @@ using Dinah.Core; namespace DtoImporterService { - public abstract class ImporterBase where TValidate : IValidator + public abstract class ImporterBase { protected LibationContext DbContext { get; } @@ -18,13 +18,13 @@ namespace DtoImporterService } /// LONG RUNNING. call with await Task.Run - public int Import(IEnumerable param) => Run(DoImport, param); + public int Import(T param) => Run(DoImport, param); - public TResult Run(Func, TResult> func, IEnumerable param) + public TResult Run(Func func, T param) { try { - var exceptions = TValidate.Validate(param.Select(i => i.DtoItem)); + var exceptions = Validate(param); if (exceptions is not null && exceptions.Any()) throw new AggregateException($"Importer validation failed", exceptions); } @@ -46,6 +46,16 @@ namespace DtoImporterService } } - protected abstract int DoImport(IEnumerable elements); + protected abstract int DoImport(T elements); + public abstract IEnumerable Validate(T param); + } + + public abstract class ItemsImporterBase : ImporterBase> + { + protected ItemsImporterBase(LibationContext context) : base(context) { } + + protected abstract IValidator Validator { get; } + public sealed override IEnumerable Validate(IEnumerable importItems) + => Validator.Validate(importItems.Select(i => i.DtoItem)); } } diff --git a/Source/DtoImporterService/LibraryBookImporter.cs b/Source/DtoImporterService/LibraryBookImporter.cs index 9590393b..38581b7c 100644 --- a/Source/DtoImporterService/LibraryBookImporter.cs +++ b/Source/DtoImporterService/LibraryBookImporter.cs @@ -7,8 +7,10 @@ using Dinah.Core.Collections.Generic; namespace DtoImporterService { - public class LibraryBookImporter : ImporterBase + public class LibraryBookImporter : ItemsImporterBase { + protected override IValidator Validator => new LibraryValidator(); + private BookImporter bookImporter { get; } public LibraryBookImporter(LibationContext context) : base(context) @@ -47,7 +49,7 @@ namespace DtoImporterService // just use the first var hash = newItems.ToDictionarySafe(dto => dto.DtoItem.ProductId); foreach (var kvp in hash) - { + { var newItem = kvp.Value; var libraryBook = new LibraryBook( diff --git a/Source/DtoImporterService/SeriesImporter.cs b/Source/DtoImporterService/SeriesImporter.cs index e4541d01..67f5d487 100644 --- a/Source/DtoImporterService/SeriesImporter.cs +++ b/Source/DtoImporterService/SeriesImporter.cs @@ -8,8 +8,10 @@ using Dinah.Core.Collections.Generic; namespace DtoImporterService { - public class SeriesImporter : ImporterBase + public class SeriesImporter : ItemsImporterBase { + protected override IValidator Validator => new SeriesValidator(); + public Dictionary Cache { get; private set; } = new(); public SeriesImporter(LibationContext context) : base(context) { } diff --git a/Source/FileLiberator/FileLiberator.csproj b/Source/FileLiberator/FileLiberator.csproj index 5d8093fa..65b461a1 100644 --- a/Source/FileLiberator/FileLiberator.csproj +++ b/Source/FileLiberator/FileLiberator.csproj @@ -2,7 +2,6 @@ net6.0-windows - True diff --git a/Source/Hangover/Hangover.csproj b/Source/Hangover/Hangover.csproj index b421f3e5..d75c4de4 100644 --- a/Source/Hangover/Hangover.csproj +++ b/Source/Hangover/Hangover.csproj @@ -6,7 +6,6 @@ true hangover.ico enable - True true win-x64 false diff --git a/Source/LibationCli/LibationCli.csproj b/Source/LibationCli/LibationCli.csproj index b1edb68b..e3b1fa09 100644 --- a/Source/LibationCli/LibationCli.csproj +++ b/Source/LibationCli/LibationCli.csproj @@ -5,7 +5,6 @@ Exe net6.0-windows true - True win-x64 false false diff --git a/Source/LibationWinForms/LibationWinForms.csproj b/Source/LibationWinForms/LibationWinForms.csproj index 340aecd7..b15b714c 100644 --- a/Source/LibationWinForms/LibationWinForms.csproj +++ b/Source/LibationWinForms/LibationWinForms.csproj @@ -6,7 +6,6 @@ net6.0-windows true libation.ico - True Libation true diff --git a/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj b/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj index ea2b8e86..f77a9580 100644 --- a/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj +++ b/Source/_Tests/AudibleUtilities.Tests/AudibleUtilities.Tests.csproj @@ -2,8 +2,6 @@ net6.0-windows - True - false diff --git a/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj b/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj index 8e349d08..4e1d1373 100644 --- a/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj +++ b/Source/_Tests/FileLiberator.Tests/FileLiberator.Tests.csproj @@ -2,8 +2,6 @@ net6.0-windows - True - false From 50651339ec9b8c065ff3603be63369ba922fa55e Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sun, 26 Jun 2022 11:40:48 -0600 Subject: [PATCH 10/14] Don't throw on unidentified series. --- Source/AudibleUtilities/ApiExtended.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/AudibleUtilities/ApiExtended.cs b/Source/AudibleUtilities/ApiExtended.cs index 33e5f41a..35568c55 100644 --- a/Source/AudibleUtilities/ApiExtended.cs +++ b/Source/AudibleUtilities/ApiExtended.cs @@ -206,7 +206,8 @@ namespace AudibleUtilities if (numSeriesParents != 1) { //There should only ever be 1 top-level parent per episode. If not, log - //and throw so we can figure out what to do about those special cases. + //so we can figure out what to do about those special cases, and don't + //import the episode. JsonSerializerSettings Settings = new() { MetadataPropertyHandling = MetadataPropertyHandling.Ignore, @@ -216,9 +217,8 @@ namespace AudibleUtilities new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal } }, }; - var ex = new ApplicationException($"Found {numSeriesParents} parents for {parent.Asin}"); - Serilog.Log.Logger.Error(ex, $"Episode Product:\r\n{JsonConvert.SerializeObject(parent, Formatting.None, Settings)}"); - throw ex; + Serilog.Log.Logger.Error($"Found {numSeriesParents} parents for {parent.Asin}\r\nEpisode Product:\r\n{JsonConvert.SerializeObject(parent, Formatting.None, Settings)}"); + return new List(); } var realParent = seriesParents.Single(p => p.IsSeriesParent); From 38dcb10a6ec759424d33079bcd7378c7f7aecca3 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sun, 26 Jun 2022 12:59:02 -0600 Subject: [PATCH 11/14] Update reference --- Source/AudibleUtilities/AudibleUtilities.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj index 42a54f46..abf5db43 100644 --- a/Source/AudibleUtilities/AudibleUtilities.csproj +++ b/Source/AudibleUtilities/AudibleUtilities.csproj @@ -5,7 +5,7 @@ - + From 9d93a98a589a9cb02a04d4eba5735b6722be8d1f Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sun, 26 Jun 2022 13:01:40 -0600 Subject: [PATCH 12/14] Update reference --- Source/AudibleUtilities/AudibleUtilities.csproj | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj index abf5db43..277b26fa 100644 --- a/Source/AudibleUtilities/AudibleUtilities.csproj +++ b/Source/AudibleUtilities/AudibleUtilities.csproj @@ -5,20 +5,10 @@ - + - - - embedded - - - - embedded - - - - + From 0a1cefdb76fc933164f66b7949849b1cfaa0a1ec Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sun, 26 Jun 2022 13:16:27 -0600 Subject: [PATCH 13/14] Update audible version --- Source/AudibleUtilities/AudibleUtilities.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj index 277b26fa..1342b852 100644 --- a/Source/AudibleUtilities/AudibleUtilities.csproj +++ b/Source/AudibleUtilities/AudibleUtilities.csproj @@ -5,7 +5,7 @@ - + From cb60a97b9177f1b0045a3fad0e571310e87d1fa9 Mon Sep 17 00:00:00 2001 From: Michael Bucari-Tovo Date: Sun, 26 Jun 2022 13:26:36 -0600 Subject: [PATCH 14/14] Embed PDBs --- Source/AudibleUtilities/AudibleUtilities.csproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/AudibleUtilities/AudibleUtilities.csproj b/Source/AudibleUtilities/AudibleUtilities.csproj index 1342b852..3ebae93c 100644 --- a/Source/AudibleUtilities/AudibleUtilities.csproj +++ b/Source/AudibleUtilities/AudibleUtilities.csproj @@ -11,5 +11,13 @@ + + + embedded + + + + embedded +