Compare commits

...

23 Commits

Author SHA1 Message Date
Robert McRackan
0503ee1404 incr ver 2024-09-18 08:17:35 -04:00
rmcrackan
303192c6c3 Merge pull request #978 from muchtall/allow-UseCoverAsFolderIcon-on-linux
Allow Non-Windows installations to populate Windows folder artwork
2024-09-18 08:15:05 -04:00
muchtall
6e21e96aa2 Allow Non-Windows installations to populate Windows folder artwork (https://github.com/rmcrackan/Libation/issues/977) 2024-09-16 19:42:26 +00:00
Robert McRackan
d1d0a7e487 db migration for IsFinished 2024-09-11 07:56:18 -04:00
Robert McRackan
2fd8ea91e1 New search field: Finished/IsFinished.
All work complete except db migration
2024-09-11 07:45:37 -04:00
Robert McRackan
92ee0b2e6d update dependencies 2024-09-11 07:20:54 -04:00
Robert McRackan
f0b5ae1cdc New filter option: IsInSeries, InSeries 2024-09-09 14:22:05 -04:00
Robert McRackan
eb659cc7d7 typo 2024-09-09 08:31:55 -04:00
Robert McRackan
cdd5f229d3 incr ver 2024-09-05 09:12:19 -04:00
Robert McRackan
29edfb7c3f Merge branch 'master' of https://github.com/rmcrackan/Libation 2024-09-05 09:07:54 -04:00
Robert McRackan
c0cb454d45 Make recursive file enumerations safer 2024-09-05 09:07:47 -04:00
rmcrackan
970a77c9e9 Merge pull request #946 from rmcrackan/dependabot/nuget/Source/LibationUiBase/SixLabors.ImageSharp-3.1.5
Bump SixLabors.ImageSharp from 3.1.4 to 3.1.5 in /Source/LibationUiBase
2024-07-22 14:05:40 -04:00
dependabot[bot]
3488c8e0f5 Bump SixLabors.ImageSharp from 3.1.4 to 3.1.5 in /Source/LibationUiBase
Bumps [SixLabors.ImageSharp](https://github.com/SixLabors/ImageSharp) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/SixLabors/ImageSharp/releases)
- [Commits](https://github.com/SixLabors/ImageSharp/compare/v3.1.4...v3.1.5)

---
updated-dependencies:
- dependency-name: SixLabors.ImageSharp
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-22 17:45:08 +00:00
rmcrackan
5133720cc8 InstallOnMac.md updated instructions 2024-06-30 07:22:38 -04:00
rmcrackan
4150746f45 InstallOnMac.md typo 2024-06-29 08:08:57 -04:00
Robert McRackan
3a95e1e72f incr ver 2024-06-26 08:00:48 -04:00
rmcrackan
c74e26e1af Update release.yml
Release titles: don't include "v" in front of version number
2024-06-26 07:54:11 -04:00
rmcrackan
ae54c95d46 Update docker.yml
Rolling back docker build push action to attempt to fix build
2024-06-26 07:51:00 -04:00
Robert McRackan
56e6bd164b By user request, other Serilog.Sink packages are included for experimental use 2024-06-26 07:07:49 -04:00
rmcrackan
9b28bdceaa Merge pull request #923 from rmcrackan/dependabot/github_actions/docker/build-push-action-6
Bump docker/build-push-action from 5 to 6
2024-06-17 16:33:34 -04:00
dependabot[bot]
b7f7d9004d Bump docker/build-push-action from 5 to 6
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 14:23:33 +00:00
rmcrackan
1be0991e62 Add Audibly to FAQ 2024-06-07 13:27:18 -04:00
rmcrackan
ff8a2e59c5 Update FrequentlyAskedQuestions.md 2024-05-27 11:48:48 -04:00
26 changed files with 634 additions and 49 deletions

View File

@@ -47,7 +47,7 @@ jobs:
id: release
uses: softprops/action-gh-release@v2
with:
name: Libation v${{ needs.prerelease.outputs.version }}
name: Libation ${{ needs.prerelease.outputs.version }}
body: <Put a body here>
draft: true
prerelease: false

View File

@@ -22,7 +22,14 @@
* iOS: [BookPlayer](https://apps.apple.com/us/app/bookplayer/id1138219998)
* iOS: [Bound](https://apps.apple.com/us/app/bound-audiobook-player/id1041727137)
* Android: [Smart AudioBook Player](https://play.google.com/store/apps/details?id=ak.alizandro.smartaudiobookplayer&hl=en_US&gl=US)
* Android: [Listen](https://play.google.com/store/apps/details?id=ru.litres.android.audio&hl=en_US&gl=US)
* Desktop: [VLC](https://www.videolan.org/)
* Windows Desktop: [Audibly](https://github.com/rstewa/Audibly) -- a desktop player build specifically for audiobooks
Self-hosting online:
* [audiobookshelf](https://www.audiobookshelf.org). On [reddit](https://www.reddit.com/r/audiobookshelf/)
* [plex](https://www.plex.tv/). Listen with [Prologue](https://prologue.audio/) (iOS)
## Q: How do I use Libation with a South Africa account?

View File

@@ -16,13 +16,29 @@ This walkthrough should get you up and running with Libation on your Mac.
- Apple Silicon (M1, M2, ...): `Libation.9.4.2-macOS-chardonnay-`**arm64**`.tgz`
- Intel: `Libation.x.x.x-macOS-chardonnay-`**x64**`.tgz`
- Move the extracted Libation app bundle to your applications folder.
- Open a terminal (Go > Utilities > Terminal)
- Copy/paste/run the following command (you'll be prompted to enter your password)
- Right-click on Libation and then click on open
- The first time, it will not immediately show you an option to open it. Just dismiss the dialog and do the same thing again (right-click -> open) then you will get an option to run the unsigned application. This takes about 10 seconds.
## If this doesn't work
You can add Libation as a safe app without touching Gatekeeper.
- Copy/paste/run the following command. Adjust the file path to the Libation.app on your computer if necessary.
```Console
xattr -r -d com.apple.quarantine ~/Downloads/Libation.app
```
- Close the terminal and use Libation!
## If this still doesn't work
- Copy/paste/run the following command (you'll be prompted to enter your Mac password)
```Console
sudo spctl --master-disable && sudo spctl --add --label "Libation" /Applications/Libation.app && open /Applications/Libation.app && sudo spctl --master-enable
```
- Close the terminal and use Libation!
```
* Close the terminal and use Libation!
## Troubleshooting
@@ -42,7 +58,7 @@ Libation comes with a recovery app called Hangover. You can start it by running
open /Applications/Libation.app --args hangover
```
## Runnign LibationCli
## Running LibationCli
Libation comes with a command-line interface. Unfortunately, due to the way apps are sandboxed on mac, its use is somewhat limited. To open a new sandboxed terminal in LibationCli's directory, run the following command:
```Console

View File

@@ -2,10 +2,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Version>11.3.13.1</Version>
<Version>11.4.1.1</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Octokit" Version="11.0.1" />
<!-- Do not remove unused Serilog.Sinks -->
<!-- Only ZipFile sink is currently used. By user request (June 2024) others packages are included for experimental use. -->
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.ZipFile" Version="3.1.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -9,9 +9,9 @@ using Dinah.Core;
using Dinah.Core.IO;
using Dinah.Core.Logging;
using LibationFileManager;
using System.Runtime.InteropServices;
using Newtonsoft.Json.Linq;
using Serilog;
using System.Runtime.InteropServices;
namespace AppScaffolding
{
@@ -124,6 +124,9 @@ namespace AppScaffolding
{ "MinimumLevel", "Information" },
{ "WriteTo", new JArray
{
// ABOUT SINKS
// Only ZipFile sink is currently used. By user request (June 2024) others packages are included for experimental use.
// new JObject { {"Name", "Console" } }, // this has caused more problems than it's solved
new JObject
{
@@ -227,7 +230,14 @@ namespace AppScaffolding
// begin logging session with a form feed
Log.Logger.Information("\r\n\f");
Log.Logger.Information("Begin. {@DebugInfo}", new
static int fileCount(FileManager.LongPath longPath)
{
try { return FileManager.FileUtility.SaferEnumerateFiles(longPath).Count(); }
catch { return -1; }
}
Log.Logger.Information("Begin. {@DebugInfo}", new
{
AppName = EntryAssembly.GetName().Name,
Version = BuildVersion.ToString(),
@@ -252,10 +262,10 @@ namespace AppScaffolding
config.InProgress,
AudibleFileStorage.DownloadsInProgressDirectory,
DownloadsInProgressFiles = FileManager.FileUtility.SaferEnumerateFiles(AudibleFileStorage.DownloadsInProgressDirectory).Count(),
DownloadsInProgressFiles = fileCount(AudibleFileStorage.DownloadsInProgressDirectory),
AudibleFileStorage.DecryptInProgressDirectory,
DecryptInProgressFiles = FileManager.FileUtility.SaferEnumerateFiles(AudibleFileStorage.DecryptInProgressDirectory).Count(),
DecryptInProgressFiles = fileCount(AudibleFileStorage.DecryptInProgressDirectory),
disableIPv6 = AppContext.TryGetSwitch("System.Net.DisableIPv6", out bool disableIPv6Value),
});

View File

@@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CsvHelper" Version="32.0.3" />
<PackageReference Include="CsvHelper" Version="33.0.1" />
<PackageReference Include="NPOI" Version="2.7.0" />
</ItemGroup>

View File

@@ -126,7 +126,8 @@ namespace ApplicationServices
| LibraryOptions.ResponseGroupOptions.Contributors | LibraryOptions.ResponseGroupOptions.ProvidedReview
| LibraryOptions.ResponseGroupOptions.ProductPlans | LibraryOptions.ResponseGroupOptions.Series
| LibraryOptions.ResponseGroupOptions.CategoryLadders | LibraryOptions.ResponseGroupOptions.ProductExtendedAttrs
| LibraryOptions.ResponseGroupOptions.PdfUrl | LibraryOptions.ResponseGroupOptions.OriginAsin,
| LibraryOptions.ResponseGroupOptions.PdfUrl | LibraryOptions.ResponseGroupOptions.OriginAsin
| LibraryOptions.ResponseGroupOptions.IsFinished,
ImageSizes = LibraryOptions.ImageSizeOptions._500 | LibraryOptions.ImageSizeOptions._1215
};
var importItems = await scanAccountsAsync(apiExtendedfunc, accounts, libraryOptions);

View File

@@ -115,6 +115,9 @@ namespace ApplicationServices
[Name("LastDownloadedVersion")]
public string LastDownloadedVersion { get; set; }
[Name("IsFinished")]
public bool IsFinished { get; set; }
}
public static class LibToDtos
{
@@ -153,8 +156,8 @@ namespace ApplicationServices
Language = a.Book.Language,
LastDownloaded = a.Book.UserDefinedItem.LastDownloaded,
LastDownloadedVersion = a.Book.UserDefinedItem.LastDownloadedVersion?.ToString() ?? "",
}).ToList();
IsFinished = a.Book.UserDefinedItem.IsFinished
}).ToList();
}
public static class LibraryExporter
{
@@ -229,6 +232,7 @@ namespace ApplicationServices
nameof(ExportDto.Language),
nameof(ExportDto.LastDownloaded),
nameof(ExportDto.LastDownloadedVersion),
nameof(ExportDto.IsFinished)
};
var col = 0;
foreach (var c in columns)
@@ -306,6 +310,7 @@ namespace ApplicationServices
}
row.CreateCell(++col).SetCellValue(dto.LastDownloadedVersion);
row.CreateCell(++col).SetCellValue(dto.IsFinished);
rowIndex++;
}

View File

@@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AudibleApi" Version="9.1.2.1" />
<PackageReference Include="AudibleApi" Version="9.2.0.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -195,7 +195,23 @@ namespace DataLayer
}
}
}
#endregion
#endregion
#region IsFinished
private bool _isFinished;
public bool IsFinished
{
get => _isFinished;
set
{
if (value != _isFinished)
{
_isFinished = value;
OnItemChanged(nameof(IsFinished));
}
}
}
#endregion
public override string ToString() => $"{Book} {Rating} {Tags}";
}

View File

@@ -0,0 +1,468 @@
// <auto-generated />
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("20240911114741_MyComment")]
partial class MyComment
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.5");
modelBuilder.Entity("CategoryCategoryLadder", b =>
{
b.Property<int>("_categoriesCategoryId")
.HasColumnType("INTEGER");
b.Property<int>("_categoryLaddersCategoryLadderId")
.HasColumnType("INTEGER");
b.HasKey("_categoriesCategoryId", "_categoryLaddersCategoryLadderId");
b.HasIndex("_categoryLaddersCategoryLadderId");
b.ToTable("CategoryCategoryLadder");
});
modelBuilder.Entity("DataLayer.Book", b =>
{
b.Property<int>("BookId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AudibleProductId")
.HasColumnType("TEXT");
b.Property<int>("ContentType")
.HasColumnType("INTEGER");
b.Property<DateTime?>("DatePublished")
.HasColumnType("TEXT");
b.Property<string>("Description")
.HasColumnType("TEXT");
b.Property<bool>("IsAbridged")
.HasColumnType("INTEGER");
b.Property<string>("Language")
.HasColumnType("TEXT");
b.Property<int>("LengthInMinutes")
.HasColumnType("INTEGER");
b.Property<string>("Locale")
.HasColumnType("TEXT");
b.Property<string>("PictureId")
.HasColumnType("TEXT");
b.Property<string>("PictureLarge")
.HasColumnType("TEXT");
b.Property<string>("Subtitle")
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.Property<long>("_audioFormat")
.HasColumnType("INTEGER");
b.HasKey("BookId");
b.HasIndex("AudibleProductId");
b.ToTable("Books");
});
modelBuilder.Entity("DataLayer.BookCategory", b =>
{
b.Property<int>("BookId")
.HasColumnType("INTEGER");
b.Property<int>("CategoryLadderId")
.HasColumnType("INTEGER");
b.HasKey("BookId", "CategoryLadderId");
b.HasIndex("BookId");
b.HasIndex("CategoryLadderId");
b.ToTable("BookCategory");
});
modelBuilder.Entity("DataLayer.BookContributor", b =>
{
b.Property<int>("BookId")
.HasColumnType("INTEGER");
b.Property<int>("ContributorId")
.HasColumnType("INTEGER");
b.Property<int>("Role")
.HasColumnType("INTEGER");
b.Property<byte>("Order")
.HasColumnType("INTEGER");
b.HasKey("BookId", "ContributorId", "Role");
b.HasIndex("BookId");
b.HasIndex("ContributorId");
b.ToTable("BookContributor");
});
modelBuilder.Entity("DataLayer.Category", b =>
{
b.Property<int>("CategoryId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AudibleCategoryId")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.HasKey("CategoryId");
b.HasIndex("AudibleCategoryId");
b.ToTable("Categories");
});
modelBuilder.Entity("DataLayer.CategoryLadder", b =>
{
b.Property<int>("CategoryLadderId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.HasKey("CategoryLadderId");
b.ToTable("CategoryLadders");
});
modelBuilder.Entity("DataLayer.Contributor", b =>
{
b.Property<int>("ContributorId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AudibleContributorId")
.HasColumnType("TEXT");
b.Property<string>("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<int>("BookId")
.HasColumnType("INTEGER");
b.Property<bool>("AbsentFromLastScan")
.HasColumnType("INTEGER");
b.Property<string>("Account")
.HasColumnType("TEXT");
b.Property<DateTime>("DateAdded")
.HasColumnType("TEXT");
b.Property<bool>("IsDeleted")
.HasColumnType("INTEGER");
b.HasKey("BookId");
b.ToTable("LibraryBooks");
});
modelBuilder.Entity("DataLayer.Series", b =>
{
b.Property<int>("SeriesId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AudibleSeriesId")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.HasKey("SeriesId");
b.HasIndex("AudibleSeriesId");
b.ToTable("Series");
});
modelBuilder.Entity("DataLayer.SeriesBook", b =>
{
b.Property<int>("SeriesId")
.HasColumnType("INTEGER");
b.Property<int>("BookId")
.HasColumnType("INTEGER");
b.Property<string>("Order")
.HasColumnType("TEXT");
b.HasKey("SeriesId", "BookId");
b.HasIndex("BookId");
b.HasIndex("SeriesId");
b.ToTable("SeriesBook");
});
modelBuilder.Entity("CategoryCategoryLadder", b =>
{
b.HasOne("DataLayer.Category", null)
.WithMany()
.HasForeignKey("_categoriesCategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("DataLayer.CategoryLadder", null)
.WithMany()
.HasForeignKey("_categoryLaddersCategoryLadderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("DataLayer.Book", b =>
{
b.OwnsOne("DataLayer.Rating", "Rating", b1 =>
{
b1.Property<int>("BookId")
.HasColumnType("INTEGER");
b1.Property<float>("OverallRating")
.HasColumnType("REAL");
b1.Property<float>("PerformanceRating")
.HasColumnType("REAL");
b1.Property<float>("StoryRating")
.HasColumnType("REAL");
b1.HasKey("BookId");
b1.ToTable("Books");
b1.WithOwner()
.HasForeignKey("BookId");
});
b.OwnsMany("DataLayer.Supplement", "Supplements", b1 =>
{
b1.Property<int>("SupplementId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b1.Property<int>("BookId")
.HasColumnType("INTEGER");
b1.Property<string>("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<int>("BookId")
.HasColumnType("INTEGER");
b1.Property<int>("BookStatus")
.HasColumnType("INTEGER");
b1.Property<bool>("IsFinished")
.HasColumnType("INTEGER");
b1.Property<DateTime?>("LastDownloaded")
.HasColumnType("TEXT");
b1.Property<string>("LastDownloadedVersion")
.HasColumnType("TEXT");
b1.Property<int?>("PdfStatus")
.HasColumnType("INTEGER");
b1.Property<string>("Tags")
.HasColumnType("TEXT");
b1.HasKey("BookId");
b1.ToTable("UserDefinedItem", (string)null);
b1.WithOwner("Book")
.HasForeignKey("BookId");
b1.OwnsOne("DataLayer.Rating", "Rating", b2 =>
{
b2.Property<int>("UserDefinedItemBookId")
.HasColumnType("INTEGER");
b2.Property<float>("OverallRating")
.HasColumnType("REAL");
b2.Property<float>("PerformanceRating")
.HasColumnType("REAL");
b2.Property<float>("StoryRating")
.HasColumnType("REAL");
b2.HasKey("UserDefinedItemBookId");
b2.ToTable("UserDefinedItem");
b2.WithOwner()
.HasForeignKey("UserDefinedItemBookId");
});
b1.Navigation("Book");
b1.Navigation("Rating");
});
b.Navigation("Rating");
b.Navigation("Supplements");
b.Navigation("UserDefinedItem");
});
modelBuilder.Entity("DataLayer.BookCategory", b =>
{
b.HasOne("DataLayer.Book", "Book")
.WithMany("CategoriesLink")
.HasForeignKey("BookId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("DataLayer.CategoryLadder", "CategoryLadder")
.WithMany("BooksLink")
.HasForeignKey("CategoryLadderId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Book");
b.Navigation("CategoryLadder");
});
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.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("CategoriesLink");
b.Navigation("ContributorsLink");
b.Navigation("SeriesLink");
});
modelBuilder.Entity("DataLayer.CategoryLadder", b =>
{
b.Navigation("BooksLink");
});
modelBuilder.Entity("DataLayer.Contributor", b =>
{
b.Navigation("BooksLink");
});
modelBuilder.Entity("DataLayer.Series", b =>
{
b.Navigation("BooksLink");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DataLayer.Migrations
{
/// <inheritdoc />
public partial class MyComment : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsFinished",
table: "UserDefinedItem",
type: "INTEGER",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsFinished",
table: "UserDefinedItem");
}
}
}

View File

@@ -15,7 +15,7 @@ namespace DataLayer.Migrations
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.5");
modelBuilder.HasAnnotation("ProductVersion", "8.0.5");
modelBuilder.Entity("CategoryCategoryLadder", b =>
{
@@ -312,6 +312,9 @@ namespace DataLayer.Migrations
b1.Property<int>("BookStatus")
.HasColumnType("INTEGER");
b1.Property<bool>("IsFinished")
.HasColumnType("INTEGER");
b1.Property<DateTime?>("LastDownloaded")
.HasColumnType("TEXT");

View File

@@ -164,6 +164,9 @@ namespace DtoImporterService
if (item.PictureLarge is not null)
book.PictureLarge = item.PictureLarge;
if (item.IsFinished is not null)
book.UserDefinedItem.IsFinished = item.IsFinished.Value;
// 2023-02-01
// updateBook must update language on books which were imported before the migration which added language.
// Can eventually delete this

View File

@@ -50,7 +50,7 @@ namespace FileManager
lock (fsCacheLocker)
{
fsCache.Clear();
fsCache.AddRange(FileUtility.SaferEnumerateFiles(RootDirectory, SearchPattern, SearchOption));
fsCache.AddRange(SafestEnumerateFiles(RootDirectory));
}
}
@@ -59,7 +59,7 @@ namespace FileManager
Stop();
lock (fsCacheLocker)
fsCache.AddRange(FileUtility.SaferEnumerateFiles(RootDirectory, SearchPattern, SearchOption));
fsCache.AddRange(SafestEnumerateFiles(RootDirectory));
directoryChangesEvents = new BlockingCollection<FileSystemEventArgs>();
fileSystemWatcher = new FileSystemWatcher(RootDirectory)
@@ -152,11 +152,23 @@ namespace FileManager
if (Path.GetFileName(path).Contains("LibationContext.db") || !File.Exists(path) && !Directory.Exists(path))
return;
if (File.GetAttributes(path).HasFlag(FileAttributes.Directory))
AddUniqueFiles(FileUtility.SaferEnumerateFiles(path, SearchPattern, SearchOption));
AddUniqueFiles(SafestEnumerateFiles(path));
else
AddUniqueFile(path);
}
private IEnumerable<LongPath> SafestEnumerateFiles(string path)
{
try
{
return FileUtility.SaferEnumerateFiles(path, SearchPattern, SearchOption);
}
catch
{
return [];
}
}
private void AddUniqueFiles(IEnumerable<LongPath> newFiles)
{
foreach (var file in newFiles)

View File

@@ -6,7 +6,7 @@
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="8.0.0.1" />
<PackageReference Include="Polly" Version="8.4.0" />
<PackageReference Include="Polly" Version="8.4.1" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -25,9 +25,18 @@ namespace LibationFileManager
static AudibleFileStorage()
{
//Clean up any partially-decrypted files from previous Libation instances.
//Do no clean DownloadsInProgressDirectory because those files are resumable
foreach (var tempFile in Directory.EnumerateFiles(DecryptInProgressDirectory))
FileUtility.SaferDelete(tempFile);
//Do not clean DownloadsInProgressDirectory. Those files are resumable.
try
{
foreach (var tempFile in FileUtility.SaferEnumerateFiles(DecryptInProgressDirectory))
FileUtility.SaferDelete(tempFile);
}
catch (Exception ex)
{
// since this is a static constructor which may be called very early, do not assume Serilog is initialized
try { Serilog.Log.Error(ex, "Error cleaning up partially-decrypted files"); }
catch { }
}
}

View File

@@ -321,7 +321,7 @@ namespace LibationFileManager
set => setTemplate<Templates.ChapterFileTemplate>(value);
}
[Description("How to format the file's Tile stored in metadata")]
[Description("How to format the file's Title stored in metadata")]
public string ChapterTitleTemplate
{
get => getTemplate<Templates.ChapterTitleTemplate>();

View File

@@ -15,7 +15,7 @@ namespace LibationFileManager
try
{
//Currently only works for Windows and macOS
if (!Configuration.Instance.UseCoverAsFolderIcon || Configuration.IsLinux)
if (!Configuration.Instance.UseCoverAsFolderIcon)
return;
// get path of cover art in Images dir. Download first if not exists

View File

@@ -54,6 +54,8 @@ namespace LibationSearchEngine
{ FieldType.Bool, lb => (lb.Book.UserDefinedItem.BookStatus == LiberatedStatus.Error).ToString(), "LiberatedError" },
{ FieldType.Bool, lb => lb.Book.IsEpisodeChild().ToString(), "Podcast", "Podcasts", "IsPodcast", "Episode", "Episodes", "IsEpisode" },
{ FieldType.Bool, lb => lb.AbsentFromLastScan.ToString(), "AbsentFromLastScan", "Absent" },
{ FieldType.Bool, lb => (!string.IsNullOrWhiteSpace(lb.Book.SeriesNames())).ToString(), "IsInSeries", "InSeries" },
{ FieldType.Bool, lb => lb.Book.UserDefinedItem.IsFinished.ToString(), nameof(UserDefinedItem.IsFinished), "Finished", "IsFinished" },
// all numbers are padded to 8 char.s
// This will allow a single method to auto-pad numbers. The method will match these as well as date: yyyymmdd
{ FieldType.Number, lb => lb.Book.LengthInMinutes.ToLuceneString(), nameof(Book.LengthInMinutes), "Length", "Minutes" },

View File

@@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
</ItemGroup>
<ItemGroup>

View File

@@ -6,10 +6,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="FluentAssertions" Version="6.12.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.6.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.6.0" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -6,10 +6,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="FluentAssertions" Version="6.12.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.6.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.6.0" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -7,10 +7,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="FluentAssertions" Version="6.12.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.6.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.6.0" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -7,10 +7,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="FluentAssertions" Version="6.12.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.6.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.6.0" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -7,10 +7,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="FluentAssertions" Version="6.12.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.6.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.6.0" />
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>