diff --git a/Source/DataLayer/EfClasses/Book.cs b/Source/DataLayer/EfClasses/Book.cs
index 8b253411..47c2442b 100644
--- a/Source/DataLayer/EfClasses/Book.cs
+++ b/Source/DataLayer/EfClasses/Book.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Dinah.Core;
using Microsoft.EntityFrameworkCore;
@@ -33,7 +34,8 @@ namespace DataLayer
// immutable
public string AudibleProductId { get; private set; }
- public string Title { get; private set; }
+ public string Title { get; set; }
+ public string Subtitle { get; set; }
public string Description { get; private set; }
public int LengthInMinutes { get; private set; }
public ContentType ContentType { get; private set; }
@@ -70,6 +72,7 @@ namespace DataLayer
public Book(
AudibleProductId audibleProductId,
string title,
+ string subtitle,
string description,
int lengthInMinutes,
ContentType contentType,
@@ -99,6 +102,7 @@ namespace DataLayer
// simple assigns
Title = title.Trim() ?? "";
+ Subtitle = subtitle?.Trim() ?? "";
Description = description?.Trim() ?? "";
LengthInMinutes = lengthInMinutes;
ContentType = contentType;
diff --git a/Source/DataLayer/Migrations/20230626171442_AddBookSubtitle.Designer.cs b/Source/DataLayer/Migrations/20230626171442_AddBookSubtitle.Designer.cs
new file mode 100644
index 00000000..911c0b20
--- /dev/null
+++ b/Source/DataLayer/Migrations/20230626171442_AddBookSubtitle.Designer.cs
@@ -0,0 +1,416 @@
+//
+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("20230626171442_AddBookSubtitle")]
+ partial class AddBookSubtitle
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "7.0.5");
+
+ 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("Language")
+ .HasColumnType("TEXT");
+
+ b.Property("LengthInMinutes")
+ .HasColumnType("INTEGER");
+
+ b.Property("Locale")
+ .HasColumnType("TEXT");
+
+ b.Property("PictureId")
+ .HasColumnType("TEXT");
+
+ b.Property("PictureLarge")
+ .HasColumnType("TEXT");
+
+ b.Property("Subtitle")
+ .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("AbsentFromLastScan")
+ .HasColumnType("INTEGER");
+
+ b.Property("Account")
+ .HasColumnType("TEXT");
+
+ b.Property("DateAdded")
+ .HasColumnType("TEXT");
+
+ b.Property("IsDeleted")
+ .HasColumnType("INTEGER");
+
+ 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("LastDownloaded")
+ .HasColumnType("TEXT");
+
+ b1.Property("LastDownloadedVersion")
+ .HasColumnType("TEXT");
+
+ 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/20230626171442_AddBookSubtitle.cs b/Source/DataLayer/Migrations/20230626171442_AddBookSubtitle.cs
new file mode 100644
index 00000000..bd815674
--- /dev/null
+++ b/Source/DataLayer/Migrations/20230626171442_AddBookSubtitle.cs
@@ -0,0 +1,28 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace DataLayer.Migrations
+{
+ ///
+ public partial class AddBookSubtitle : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "Subtitle",
+ table: "Books",
+ type: "TEXT",
+ nullable: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "Subtitle",
+ table: "Books");
+ }
+ }
+}
diff --git a/Source/DataLayer/Migrations/LibationContextModelSnapshot.cs b/Source/DataLayer/Migrations/LibationContextModelSnapshot.cs
index 2a0a1869..65d792b1 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", "7.0.3");
+ modelBuilder.HasAnnotation("ProductVersion", "7.0.5");
modelBuilder.Entity("DataLayer.Book", b =>
{
@@ -56,6 +56,9 @@ namespace DataLayer.Migrations
b.Property("PictureLarge")
.HasColumnType("TEXT");
+ b.Property("Subtitle")
+ .HasColumnType("TEXT");
+
b.Property("Title")
.HasColumnType("TEXT");
diff --git a/Source/DtoImporterService/BookImporter.cs b/Source/DtoImporterService/BookImporter.cs
index 700ad7d4..2cb3b875 100644
--- a/Source/DtoImporterService/BookImporter.cs
+++ b/Source/DtoImporterService/BookImporter.cs
@@ -118,7 +118,8 @@ namespace DtoImporterService
{
book = DbContext.Books.Add(new Book(
new AudibleProductId(item.ProductId),
- item.TitleWithSubtitle,
+ item.Title,
+ item.Subtitle,
item.Description,
item.LengthInMinutes,
contentType,
@@ -164,6 +165,10 @@ namespace DtoImporterService
{
var item = importItem.DtoItem;
+ // Update the book titles, since formatting can change
+ book.Title = item.Title;
+ book.Subtitle = item.Subtitle;
+
var codec = item.AvailableCodecs?.Max(f => AudioFormat.FromString(f.EnhancedCodec)) ?? new AudioFormat();
book.AudioFormat = codec;
diff --git a/Source/FileLiberator/UtilityExtensions.cs b/Source/FileLiberator/UtilityExtensions.cs
index 358cdd60..14e818f9 100644
--- a/Source/FileLiberator/UtilityExtensions.cs
+++ b/Source/FileLiberator/UtilityExtensions.cs
@@ -41,6 +41,7 @@ namespace FileLiberator
AudibleProductId = libraryBook.Book.AudibleProductId,
Title = libraryBook.Book.Title ?? "",
+ Subtitle = libraryBook.Book.Subtitle ?? "",
Locale = libraryBook.Book.Locale,
YearPublished = libraryBook.Book.DatePublished?.Year,
DatePublished = libraryBook.Book.DatePublished,
diff --git a/Source/LibationFileManager/LibraryBookDto.cs b/Source/LibationFileManager/LibraryBookDto.cs
index a4e7456e..cb3a022f 100644
--- a/Source/LibationFileManager/LibraryBookDto.cs
+++ b/Source/LibationFileManager/LibraryBookDto.cs
@@ -8,7 +8,22 @@ namespace LibationFileManager
{
public string AudibleProductId { get; set; }
public string Title { get; set; }
- public string Locale { get; set; }
+ public string Subtitle { get; set; }
+ public string TitleWithSubtitle
+ {
+ get
+ {
+ string text = Title?.Trim();
+ string text2 = Subtitle?.Trim();
+ if (string.IsNullOrWhiteSpace(text2))
+ {
+ return text;
+ }
+
+ return text + ": " + text2;
+ }
+ }
+ public string Locale { get; set; }
public int? YearPublished { get; set; }
public IEnumerable Authors { get; set; }
diff --git a/Source/LibationFileManager/TemplateEditor[T].cs b/Source/LibationFileManager/TemplateEditor[T].cs
index 5ee16095..e3d68dc1 100644
--- a/Source/LibationFileManager/TemplateEditor[T].cs
+++ b/Source/LibationFileManager/TemplateEditor[T].cs
@@ -57,7 +57,8 @@ namespace LibationFileManager
DateAdded = new DateTime(2022, 6, 9, 0, 0, 0),
DatePublished = new DateTime(2017, 2, 27, 0, 0, 0),
AudibleProductId = "123456789",
- Title = "A Study in Scarlet: A Sherlock Holmes Novel",
+ Title = "A Study in Scarlet",
+ Subtitle = "A Sherlock Holmes Novel",
Locale = "us",
YearPublished = 2017,
Authors = new List { "Arthur Conan Doyle", "Stephen Fry - introductions" },
diff --git a/Source/LibationFileManager/Templates.cs b/Source/LibationFileManager/Templates.cs
index 97146032..6b8be956 100644
--- a/Source/LibationFileManager/Templates.cs
+++ b/Source/LibationFileManager/Templates.cs
@@ -247,8 +247,8 @@ namespace LibationFileManager
{
//Don't allow formatting of Id
{ TemplateTags.Id, lb => lb.AudibleProductId, v => v },
- { TemplateTags.Title, lb => lb.Title },
- { TemplateTags.TitleShort, lb => getTitleShort(lb.Title) },
+ { TemplateTags.Title, lb => lb.TitleWithSubtitle },
+ { TemplateTags.TitleShort, lb => lb.Title },
{ TemplateTags.Author, lb => lb.Authors, NameListFormat.Formatter },
{ TemplateTags.FirstAuthor, lb => lb.FirstAuthor },
{ TemplateTags.Narrator, lb => lb.Narrators, NameListFormat.Formatter },
@@ -274,8 +274,8 @@ namespace LibationFileManager
{
new PropertyTagCollection(caseSensative: true, StringFormatter)
{
- { TemplateTags.Title, lb => lb.Title },
- { TemplateTags.TitleShort, lb => getTitleShort(lb.Title) },
+ { TemplateTags.Title, lb => lb.TitleWithSubtitle },
+ { TemplateTags.TitleShort, lb => lb.Title },
{ TemplateTags.Series, lb => lb.SeriesName },
},
new PropertyTagCollection(caseSensative: true, StringFormatter, IntegerFormatter, DateTimeFormatter)