mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-01-09 22:38:53 -05:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15ad753fa1 | ||
|
|
75b984bdb2 | ||
|
|
f586d1d59f | ||
|
|
cb91a591f0 | ||
|
|
0c0c556c6a | ||
|
|
ff63b73c09 | ||
|
|
c1d56adbd2 | ||
|
|
bcd99fd208 | ||
|
|
d1df10d060 | ||
|
|
1fa415628f | ||
|
|
a83fe9e532 | ||
|
|
f85462ffec | ||
|
|
156349c293 | ||
|
|
5976706e40 | ||
|
|
1e40180f0c | ||
|
|
7d09728e6b | ||
|
|
4899ef3007 | ||
|
|
296c2b43eb | ||
|
|
932472cb91 | ||
|
|
1bf86b05ec | ||
|
|
5d5e3a6671 | ||
|
|
9720a573c7 | ||
|
|
1cf01aa92a | ||
|
|
4df9e5abbf | ||
|
|
9243aa47e7 | ||
|
|
c69f41a2a6 | ||
|
|
27c74e52ca | ||
|
|
bfa7f5cca9 | ||
|
|
22a3dcbc1f | ||
|
|
ec9d11cf52 | ||
|
|
fbc29dfb0a | ||
|
|
03d30ff6af | ||
|
|
ecfe0dc033 | ||
|
|
f2d475a9b0 | ||
|
|
86124fc609 | ||
|
|
db2b10d2a4 | ||
|
|
83402028fd | ||
|
|
423b5312f7 | ||
|
|
3be7d8e825 | ||
|
|
29803c6ba0 | ||
|
|
bb05847b25 |
1
.github/workflows/build-windows.yml
vendored
1
.github/workflows/build-windows.yml
vendored
@@ -75,6 +75,7 @@ jobs:
|
||||
LibationCli/LibationCli.csproj `
|
||||
--configuration ${{ env.DOTNET_CONFIGURATION }} `
|
||||
--output bin/Publish/${{ matrix.os }}-${{ matrix.release_name }} `
|
||||
-p:DefineConstants="${{ matrix.release_name }}" `
|
||||
-p:PublishProfile=LibationCli/Properties/PublishProfiles/${{ matrix.os }}Profile.pubxml
|
||||
dotnet publish `
|
||||
Hangover${{ matrix.ui }}/Hangover${{ matrix.ui }}.csproj `
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AAXClean.Codecs" Version="1.0.4" />
|
||||
<PackageReference Include="AAXClean.Codecs" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -51,6 +51,34 @@ namespace AaxDecrypter
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(AaxFile.AppleTags.Copyright))
|
||||
AaxFile.AppleTags.Copyright = AaxFile.AppleTags.Copyright.Replace("(P)", "℗").Replace("©", "©");
|
||||
|
||||
//Add audiobook shelf tags
|
||||
//https://github.com/advplyr/audiobookshelf/issues/1794#issuecomment-1565050213
|
||||
const string tagDomain = "com.pilabor.tone";
|
||||
|
||||
AaxFile.AppleTags.Title = DownloadOptions.Title;
|
||||
|
||||
if (DownloadOptions.Subtitle is string subtitle)
|
||||
AaxFile.AppleTags.AppleListBox.EditOrAddFreeformTag(tagDomain, "SUBTITLE", subtitle);
|
||||
|
||||
if (DownloadOptions.Publisher is string publisher)
|
||||
AaxFile.AppleTags.AppleListBox.EditOrAddFreeformTag(tagDomain, "PUBLISHER", publisher);
|
||||
|
||||
if (DownloadOptions.Language is string language)
|
||||
AaxFile.AppleTags.AppleListBox.EditOrAddFreeformTag(tagDomain, "LANGUAGE", language);
|
||||
|
||||
if (DownloadOptions.AudibleProductId is string asin)
|
||||
{
|
||||
AaxFile.AppleTags.Asin = asin;
|
||||
AaxFile.AppleTags.AppleListBox.EditOrAddTag("asin", asin);
|
||||
AaxFile.AppleTags.AppleListBox.EditOrAddFreeformTag(tagDomain, "AUDIBLE_ASIN", asin);
|
||||
}
|
||||
|
||||
if (DownloadOptions.SeriesName is string series)
|
||||
AaxFile.AppleTags.AppleListBox.EditOrAddFreeformTag(tagDomain, "SERIES", series);
|
||||
|
||||
if (DownloadOptions.SeriesNumber is float part)
|
||||
AaxFile.AppleTags.AppleListBox.EditOrAddFreeformTag(tagDomain, "PART", part.ToString());
|
||||
}
|
||||
|
||||
//Finishing configuring lame encoder.
|
||||
|
||||
@@ -118,11 +118,7 @@ namespace AaxDecrypter
|
||||
public abstract Task CancelAsync();
|
||||
protected abstract Task<bool> Step_DownloadAndDecryptAudiobookAsync();
|
||||
|
||||
public virtual void SetCoverArt(byte[] coverArt)
|
||||
{
|
||||
if (coverArt is not null)
|
||||
OnRetrievedCoverArt(coverArt);
|
||||
}
|
||||
public virtual void SetCoverArt(byte[] coverArt) { }
|
||||
|
||||
protected void OnRetrievedTitle(string title)
|
||||
=> RetrievedTitle?.Invoke(this, title);
|
||||
|
||||
@@ -21,7 +21,14 @@ namespace AaxDecrypter
|
||||
long DownloadSpeedBps { get; }
|
||||
ChapterInfo ChapterInfo { get; }
|
||||
bool FixupFile { get; }
|
||||
NAudio.Lame.LameConfig LameConfig { get; }
|
||||
string AudibleProductId { get; }
|
||||
string Title { get; }
|
||||
string Subtitle { get; }
|
||||
string Publisher { get; }
|
||||
string Language { get; }
|
||||
string SeriesName { get; }
|
||||
float? SeriesNumber { get; }
|
||||
NAudio.Lame.LameConfig LameConfig { get; }
|
||||
bool Downsample { get; }
|
||||
bool MatchSourceBitrate { get; }
|
||||
bool MoveMoovToBeginning { get; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AAXClean;
|
||||
using AAXClean.Codecs;
|
||||
using NAudio.Lame;
|
||||
using System;
|
||||
|
||||
@@ -6,6 +7,7 @@ namespace AaxDecrypter
|
||||
{
|
||||
public static class MpegUtil
|
||||
{
|
||||
private const string TagDomain = "com.pilabor.tone";
|
||||
public static void ConfigureLameOptions(Mp4File mp4File, LameConfig lameConfig, bool downsample, bool matchSourceBitrate)
|
||||
{
|
||||
double bitrateMultiple = 1;
|
||||
@@ -36,6 +38,21 @@ namespace AaxDecrypter
|
||||
else if (lameConfig.VBR == VBRMode.ABR)
|
||||
lameConfig.ABRRateKbps = kbps;
|
||||
}
|
||||
|
||||
//Setup metadata tags
|
||||
lameConfig.ID3 = mp4File.AppleTags.ToIDTags();
|
||||
|
||||
if (mp4File.AppleTags.AppleListBox.GetFreeformTagString(TagDomain, "SUBTITLE") is string subtitle)
|
||||
lameConfig.ID3.Subtitle = subtitle;
|
||||
|
||||
if (mp4File.AppleTags.AppleListBox.GetFreeformTagString(TagDomain, "LANGUAGE") is string lang)
|
||||
lameConfig.ID3.UserDefinedText.Add("LANGUAGE", lang);
|
||||
|
||||
if (mp4File.AppleTags.AppleListBox.GetFreeformTagString(TagDomain, "SERIES") is string series)
|
||||
lameConfig.ID3.UserDefinedText.Add("SERIES", series);
|
||||
|
||||
if (mp4File.AppleTags.AppleListBox.GetFreeformTagString(TagDomain, "PART") is string part)
|
||||
lameConfig.ID3.UserDefinedText.Add("PART", part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace AaxDecrypter
|
||||
public class NetworkFileStream : Stream, IUpdatable
|
||||
{
|
||||
public event EventHandler Updated;
|
||||
public event EventHandler DownloadCompleted;
|
||||
|
||||
#region Public Properties
|
||||
|
||||
@@ -41,6 +40,9 @@ namespace AaxDecrypter
|
||||
[JsonIgnore]
|
||||
public bool IsCancelled => _cancellationSource.IsCancellationRequested;
|
||||
|
||||
[JsonIgnore]
|
||||
public Task DownloadTask { get; private set; }
|
||||
|
||||
private long _speedLimit = 0;
|
||||
/// <summary>bytes per second</summary>
|
||||
public long SpeedLimit { get => _speedLimit; set => _speedLimit = value <= 0 ? 0 : Math.Max(value, MIN_BYTES_PER_SECOND); }
|
||||
@@ -52,7 +54,6 @@ namespace AaxDecrypter
|
||||
private FileStream _readFile { get; }
|
||||
private CancellationTokenSource _cancellationSource { get; } = new();
|
||||
private EventWaitHandle _downloadedPiece { get; set; }
|
||||
private Task _backgroundDownloadTask { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -126,9 +127,11 @@ namespace AaxDecrypter
|
||||
{
|
||||
ArgumentValidator.EnsureNotNullOrWhiteSpace(uriToSameFile?.AbsoluteUri, nameof(uriToSameFile));
|
||||
|
||||
if (Path.GetFileName(uriToSameFile.LocalPath) != Path.GetFileName(Uri.LocalPath))
|
||||
throw new ArgumentException($"New uri to the same file must have the same file name.");
|
||||
if (uriToSameFile.Host != Uri.Host)
|
||||
throw new ArgumentException($"New uri to the same file must have the same host.\r\n Old Host :{Uri.Host}\r\nNew Host: {uriToSameFile.Host}");
|
||||
if (_backgroundDownloadTask is not null)
|
||||
if (DownloadTask is not null)
|
||||
throw new InvalidOperationException("Cannot change Uri after download has started.");
|
||||
|
||||
Uri = uriToSameFile;
|
||||
@@ -141,7 +144,7 @@ namespace AaxDecrypter
|
||||
{
|
||||
if (ContentLength != 0 && WritePosition == ContentLength)
|
||||
{
|
||||
_backgroundDownloadTask = Task.CompletedTask;
|
||||
DownloadTask = Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -167,7 +170,8 @@ namespace AaxDecrypter
|
||||
_downloadedPiece = new EventWaitHandle(false, EventResetMode.AutoReset);
|
||||
|
||||
//Download the file in the background.
|
||||
_backgroundDownloadTask = Task.Run(() => DownloadFile(networkStream), _cancellationSource.Token);
|
||||
|
||||
DownloadTask = Task.Run(() => DownloadFile(networkStream), _cancellationSource.Token);
|
||||
}
|
||||
|
||||
/// <summary> Download <see cref="Uri"/> to <see cref="SaveFilePath"/>.</summary>
|
||||
@@ -234,7 +238,6 @@ namespace AaxDecrypter
|
||||
_writeFile.Close();
|
||||
_downloadedPiece.Set();
|
||||
OnUpdate();
|
||||
DownloadCompleted?.Invoke(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +259,7 @@ namespace AaxDecrypter
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_backgroundDownloadTask is null)
|
||||
if (DownloadTask is null)
|
||||
throw new InvalidOperationException($"Background downloader must first be started by calling {nameof(BeginDownloadingAsync)}");
|
||||
return ContentLength;
|
||||
}
|
||||
@@ -280,7 +283,7 @@ namespace AaxDecrypter
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_backgroundDownloadTask is null)
|
||||
if (DownloadTask is null)
|
||||
throw new InvalidOperationException($"Background downloader must first be started by calling {nameof(BeginDownloadingAsync)}");
|
||||
|
||||
var toRead = Math.Min(count, Length - Position);
|
||||
@@ -306,7 +309,7 @@ namespace AaxDecrypter
|
||||
private void WaitToPosition(long requiredPosition)
|
||||
{
|
||||
while (WritePosition < requiredPosition
|
||||
&& _backgroundDownloadTask?.IsCompleted is false
|
||||
&& DownloadTask?.IsCompleted is false
|
||||
&& !IsCancelled)
|
||||
{
|
||||
_downloadedPiece.WaitOne(50);
|
||||
@@ -326,7 +329,7 @@ namespace AaxDecrypter
|
||||
if (disposing && !disposed)
|
||||
{
|
||||
_cancellationSource.Cancel();
|
||||
_backgroundDownloadTask?.GetAwaiter().GetResult();
|
||||
DownloadTask?.GetAwaiter().GetResult();
|
||||
_downloadedPiece?.Dispose();
|
||||
_cancellationSource?.Dispose();
|
||||
_readFile.Dispose();
|
||||
|
||||
@@ -26,11 +26,7 @@ namespace AaxDecrypter
|
||||
|
||||
protected override async Task<bool> Step_DownloadAndDecryptAudiobookAsync()
|
||||
{
|
||||
TaskCompletionSource completionSource = new();
|
||||
|
||||
InputFileStream.DownloadCompleted += (_, _) => completionSource.SetResult();
|
||||
|
||||
await completionSource.Task;
|
||||
await InputFileStream.DownloadTask;
|
||||
|
||||
if (IsCanceled)
|
||||
return false;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Version>10.4.3.1</Version>
|
||||
<Version>10.6.2.1</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Octokit" Version="6.0.0" />
|
||||
|
||||
@@ -43,21 +43,6 @@ namespace AppScaffolding
|
||||
public static ReleaseIdentifier ReleaseIdentifier { get; private set; }
|
||||
public static Variety Variety { get; private set; }
|
||||
|
||||
public static void SetReleaseIdentifier(Variety varietyType)
|
||||
{
|
||||
Variety = Enum.IsDefined(varietyType) ? varietyType : Variety.None;
|
||||
|
||||
var releaseID = (ReleaseIdentifier)((int)varietyType | (int)Configuration.OS | (int)RuntimeInformation.ProcessArchitecture);
|
||||
|
||||
if (Enum.IsDefined(releaseID))
|
||||
ReleaseIdentifier = releaseID;
|
||||
else
|
||||
{
|
||||
ReleaseIdentifier = ReleaseIdentifier.None;
|
||||
Serilog.Log.Logger.Warning("Unknown release identifier @{DebugInfo}", new { Variety = varietyType, Configuration.OS, RuntimeInformation.ProcessArchitecture });
|
||||
}
|
||||
}
|
||||
|
||||
// AppScaffolding
|
||||
private static Assembly _executingAssembly;
|
||||
private static Assembly ExecutingAssembly
|
||||
@@ -105,8 +90,14 @@ namespace AppScaffolding
|
||||
}
|
||||
|
||||
/// <summary>Initialize logging. Wire-up events. Run after migration</summary>
|
||||
public static void RunPostMigrationScaffolding(Configuration config)
|
||||
public static void RunPostMigrationScaffolding(Variety variety, Configuration config)
|
||||
{
|
||||
Variety = Enum.IsDefined(variety) ? variety : Variety.None;
|
||||
|
||||
var releaseID = (ReleaseIdentifier)((int)variety | (int)Configuration.OS | (int)RuntimeInformation.ProcessArchitecture);
|
||||
|
||||
ReleaseIdentifier = Enum.IsDefined(releaseID) ? releaseID : ReleaseIdentifier.None;
|
||||
|
||||
ensureSerilogConfig(config);
|
||||
configureLogging(config);
|
||||
logStartupState(config);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||
<PackageReference Include="NPOI" Version="2.6.0" />
|
||||
<PackageReference Include="NPOI" Version="2.6.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AudibleApi" Version="8.4.1.1" />
|
||||
<PackageReference Include="AudibleApi" Version="8.4.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dinah.Core" Version="7.2.2.1" />
|
||||
<PackageReference Include="Dinah.Core" Version="7.2.3.1" />
|
||||
<PackageReference Include="Dinah.EntityFrameworkCore" Version="7.1.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -13,7 +13,11 @@ namespace DataLayer
|
||||
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,
|
||||
}
|
||||
AAX_22_32 = LC_32_22050_stereo,
|
||||
AAX_22_64 = LC_64_22050_stereo,
|
||||
AAX_44_64 = LC_64_44100_stereo,
|
||||
AAX_44_128 = LC_128_44100_stereo
|
||||
}
|
||||
|
||||
public class AudioFormat : IComparable<AudioFormat>, IComparable
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AaxDecrypter;
|
||||
using ApplicationServices;
|
||||
using AudibleApi.Common;
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using Dinah.Core.ErrorHandling;
|
||||
@@ -121,14 +122,15 @@ namespace FileLiberator
|
||||
|
||||
downloadValidation(libraryBook);
|
||||
|
||||
var quality = (AudibleApi.DownloadQuality)config.FileDownloadQuality;
|
||||
var api = await libraryBook.GetApiAsync();
|
||||
var contentLic = await api.GetDownloadLicenseAsync(libraryBook.Book.AudibleProductId);
|
||||
using var dlOptions = BuildDownloadOptions(libraryBook, config, contentLic);
|
||||
var contentLic = await api.GetDownloadLicenseAsync(libraryBook.Book.AudibleProductId, quality);
|
||||
using var dlOptions = BuildDownloadOptions(libraryBook, config, contentLic);
|
||||
|
||||
var outFileName = AudibleFileStorage.Audio.GetInProgressFilename(libraryBook, dlOptions.OutputFormat.ToString().ToLower());
|
||||
var cacheDir = AudibleFileStorage.DownloadsInProgressDirectory;
|
||||
|
||||
if (contentLic.DrmType != AudibleApi.Common.DrmType.Adrm)
|
||||
if (contentLic.DrmType != DrmType.Adrm)
|
||||
abDownloader = new UnencryptedAudiobookDownloader(outFileName, cacheDir, dlOptions);
|
||||
else
|
||||
{
|
||||
@@ -151,16 +153,34 @@ namespace FileLiberator
|
||||
abDownloader.RetrievedCoverArt += AaxcDownloader_RetrievedCoverArt;
|
||||
abDownloader.FileCreated += (_, path) => OnFileCreated(libraryBook, path);
|
||||
|
||||
// REAL WORK DONE HERE
|
||||
return await abDownloader.RunAsync();
|
||||
// REAL WORK DONE HERE
|
||||
var success = await abDownloader.RunAsync();
|
||||
|
||||
if (success && config.SaveMetadataToFile)
|
||||
{
|
||||
var metadataFile = Templates.File.GetFilename(dlOptions.LibraryBookDto, Path.GetDirectoryName(outFileName), ".metadata.json");
|
||||
|
||||
saveMetadata(libraryBook, contentLic.ContentMetadata, metadataFile);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private DownloadOptions BuildDownloadOptions(LibraryBook libraryBook, Configuration config, AudibleApi.Common.ContentLicense contentLic)
|
||||
private void saveMetadata(LibraryBook libraryBook, ContentMetadata contentMetadata, string fileName)
|
||||
{
|
||||
var export = Newtonsoft.Json.Linq.JObject.FromObject(LibToDtos.ToDtos(new[] { libraryBook })[0]);
|
||||
export.Add(nameof(contentMetadata.ChapterInfo), Newtonsoft.Json.Linq.JObject.FromObject(contentMetadata.ChapterInfo));
|
||||
export.Add(nameof(contentMetadata.ContentReference), Newtonsoft.Json.Linq.JObject.FromObject(contentMetadata.ContentReference));
|
||||
|
||||
File.WriteAllText(fileName, export.ToString());
|
||||
OnFileCreated(libraryBook, fileName);
|
||||
}
|
||||
|
||||
private DownloadOptions BuildDownloadOptions(LibraryBook libraryBook, Configuration config, ContentLicense contentLic)
|
||||
{
|
||||
//If DrmType != Adrm the delivered file is an unencrypted mp3.
|
||||
|
||||
var outputFormat
|
||||
= contentLic.DrmType != AudibleApi.Common.DrmType.Adrm || (config.AllowLibationFixup && config.DecryptToLossy)
|
||||
= contentLic.DrmType != DrmType.Adrm || (config.AllowLibationFixup && config.DecryptToLossy)
|
||||
? OutputFormat.Mp3
|
||||
: OutputFormat.M4b;
|
||||
|
||||
@@ -169,7 +189,10 @@ namespace FileLiberator
|
||||
? contentLic.ContentMetadata.ChapterInfo.BrandIntroDurationMs
|
||||
: 0;
|
||||
|
||||
var dlOptions = new DownloadOptions(config, libraryBook, contentLic?.ContentMetadata?.ContentUrl?.OfflineUrl)
|
||||
//Set the requested AudioFormat for use in file naming templates
|
||||
libraryBook.Book.AudioFormat = AudioFormat.FromString(contentLic.ContentMetadata.ContentReference.ContentFormat);
|
||||
|
||||
var dlOptions = new DownloadOptions(config, libraryBook, contentLic?.ContentMetadata?.ContentUrl?.OfflineUrl)
|
||||
{
|
||||
AudibleKey = contentLic?.Voucher?.Key,
|
||||
AudibleIV = contentLic?.Voucher?.Iv,
|
||||
@@ -179,7 +202,11 @@ namespace FileLiberator
|
||||
RuntimeLength = TimeSpan.FromMilliseconds(contentLic?.ContentMetadata?.ChapterInfo?.RuntimeLengthMs ?? 0),
|
||||
};
|
||||
|
||||
var chapters = flattenChapters(contentLic.ContentMetadata.ChapterInfo.Chapters).OrderBy(c => c.StartOffsetMs).ToList();
|
||||
var titleConcat = config.CombineNestedChapterTitles ? ": " : null;
|
||||
var chapters
|
||||
= flattenChapters(contentLic.ContentMetadata.ChapterInfo.Chapters, titleConcat)
|
||||
.OrderBy(c => c.StartOffsetMs)
|
||||
.ToList();
|
||||
|
||||
if (config.MergeOpeningAndEndCredits)
|
||||
combineCredits(chapters);
|
||||
@@ -276,14 +303,19 @@ namespace FileLiberator
|
||||
|
||||
*/
|
||||
|
||||
public static List<AudibleApi.Common.Chapter> flattenChapters(IList<AudibleApi.Common.Chapter> chapters, string titleConcat = ": ")
|
||||
public static List<Chapter> flattenChapters(IList<Chapter> chapters, string titleConcat = ": ")
|
||||
{
|
||||
List<AudibleApi.Common.Chapter> chaps = new();
|
||||
List<Chapter> chaps = new();
|
||||
|
||||
foreach (var c in chapters)
|
||||
{
|
||||
if (c.Chapters is null)
|
||||
chaps.Add(c);
|
||||
else if (titleConcat is null)
|
||||
{
|
||||
chaps.Add(c);
|
||||
chaps.AddRange(flattenChapters(c.Chapters));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c.LengthMs < 10000)
|
||||
@@ -301,13 +333,12 @@ namespace FileLiberator
|
||||
child.Title = $"{c.Title}{titleConcat}{child.Title}";
|
||||
|
||||
chaps.AddRange(children);
|
||||
c.Chapters = null;
|
||||
}
|
||||
}
|
||||
return chaps;
|
||||
}
|
||||
|
||||
public static void combineCredits(IList<AudibleApi.Common.Chapter> chapters)
|
||||
public static void combineCredits(IList<Chapter> chapters)
|
||||
{
|
||||
if (chapters.Count > 1 && chapters[0].Title == "Opening Credits")
|
||||
{
|
||||
@@ -347,11 +378,15 @@ namespace FileLiberator
|
||||
|
||||
private void AaxcDownloader_RetrievedCoverArt(object _, byte[] e)
|
||||
{
|
||||
if (Configuration.Instance.AllowLibationFixup)
|
||||
{
|
||||
e = OnRequestCoverArt();
|
||||
abDownloader.SetCoverArt(e);
|
||||
}
|
||||
|
||||
if (e is not null)
|
||||
OnCoverImageDiscovered(e);
|
||||
else if (Configuration.Instance.AllowLibationFixup)
|
||||
abDownloader.SetCoverArt(OnRequestCoverArt());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Move new files to 'Books' directory</summary>
|
||||
/// <returns>Return directory if audiobook file(s) were successfully created and can be located on disk. Else null.</returns>
|
||||
|
||||
@@ -21,6 +21,13 @@ namespace FileLiberator
|
||||
public TimeSpan RuntimeLength { get; init; }
|
||||
public OutputFormat OutputFormat { get; init; }
|
||||
public ChapterInfo ChapterInfo { get; init; }
|
||||
public string Title => LibraryBook.Book.Title;
|
||||
public string Subtitle => LibraryBook.Book.Subtitle;
|
||||
public string Publisher => LibraryBook.Book.Publisher;
|
||||
public string Language => LibraryBook.Book.Language;
|
||||
public string AudibleProductId => LibraryBookDto.AudibleProductId;
|
||||
public string SeriesName => LibraryBookDto.SeriesName;
|
||||
public float? SeriesNumber => LibraryBookDto.SeriesNumber;
|
||||
public NAudio.Lame.LameConfig LameConfig { get; init; }
|
||||
public string UserAgent => AudibleApi.Resources.Download_User_Agent;
|
||||
public bool TrimOutputToChapterLength => config.AllowLibationFixup && config.StripAudibleBrandAudio;
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dinah.Core" Version="7.2.2.1" />
|
||||
<PackageReference Include="Polly" Version="7.2.3" />
|
||||
<PackageReference Include="Dinah.Core" Version="7.2.3.1" />
|
||||
<PackageReference Include="Polly" Version="7.2.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
||||
@@ -163,6 +163,11 @@ namespace FileManager
|
||||
|
||||
public override string ToString() => Path;
|
||||
|
||||
public override int GetHashCode() => Path.GetHashCode();
|
||||
public override bool Equals(object obj) => obj is LongPath other && Path == other.Path;
|
||||
public static bool operator ==(LongPath path1, LongPath path2) => path1.Equals(path2);
|
||||
public static bool operator !=(LongPath path1, LongPath path2) => !path1.Equals(path2);
|
||||
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern int GetShortPathName([MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder shortPath, int shortPathLength);
|
||||
|
||||
@@ -131,6 +131,35 @@ namespace FileManager
|
||||
writeFile(propertyName, parsedNewValue);
|
||||
}
|
||||
|
||||
public bool RemoveProperty(string propertyName)
|
||||
{
|
||||
if (IsReadOnly)
|
||||
return false;
|
||||
|
||||
var success = false;
|
||||
try
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
var jObject = readFile();
|
||||
|
||||
if (!jObject.ContainsKey(propertyName))
|
||||
return false;
|
||||
|
||||
jObject.Remove(propertyName);
|
||||
|
||||
var endContents = JsonConvert.SerializeObject(jObject, Formatting.Indented);
|
||||
|
||||
File.WriteAllText(Filepath, endContents);
|
||||
success = true;
|
||||
}
|
||||
Serilog.Log.Logger.Information("Removed property. {@DebugInfo}", propertyName);
|
||||
}
|
||||
catch { }
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private void writeFile(string propertyName, JToken newValue)
|
||||
{
|
||||
if (IsReadOnly)
|
||||
|
||||
@@ -67,13 +67,13 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
<PackageReference Include="Avalonia" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia" Version="11.0.0" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.0" />
|
||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.0" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0" />
|
||||
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.0" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\HangoverBase\HangoverBase.csproj" />
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace HangoverAvalonia.Views
|
||||
|
||||
var config = LibationScaffolding.RunPreConfigMigrations();
|
||||
LibationScaffolding.RunPostConfigMigrations(config);
|
||||
LibationScaffolding.RunPostMigrationScaffolding(config);
|
||||
LibationScaffolding.RunPostMigrationScaffolding(Variety.Chardonnay, config);
|
||||
}
|
||||
|
||||
public void OnLoad()
|
||||
|
||||
4
Source/HangoverWinForms/Form1.Designer.cs
generated
4
Source/HangoverWinForms/Form1.Designer.cs
generated
@@ -219,8 +219,8 @@
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(800, 450);
|
||||
this.Controls.Add(this.tabControl1);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace HangoverWinForms
|
||||
|
||||
var config = LibationScaffolding.RunPreConfigMigrations();
|
||||
LibationScaffolding.RunPostConfigMigrations(config);
|
||||
LibationScaffolding.RunPostMigrationScaffolding(config);
|
||||
LibationScaffolding.RunPostMigrationScaffolding(Variety.Classic, config);
|
||||
|
||||
databaseTab.VisibleChanged += databaseTab_VisibleChanged;
|
||||
cliTab.VisibleChanged += cliTab_VisibleChanged;
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace LibationAvalonia
|
||||
await MessageBox.VerboseLoggingWarning_ShowIfTrue();
|
||||
|
||||
// logging is init'd here
|
||||
AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(config);
|
||||
AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(AppScaffolding.Variety.Chardonnay, config);
|
||||
}
|
||||
|
||||
private void ShowLibationFilesDialog(IClassicDesktopStyleApplicationLifetime desktop, Configuration config, Action<IClassicDesktopStyleApplicationLifetime, LibationFilesDialog, Configuration> OnClose)
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
<Panel Background="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid Name="ratingsGrid" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="3,0,0,0" ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto,Auto">
|
||||
<Grid.Styles>
|
||||
<Style Selector="TextBlock">
|
||||
<Setter Property="FontSize" Value="11" />
|
||||
</Style>
|
||||
<Style Selector="StackPanel > TextBlock">
|
||||
<Setter Property="Padding" Value="0,0,-2,0" />
|
||||
</Style>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="750" d:DesignHeight="600"
|
||||
mc:Ignorable="d" d:DesignWidth="750" d:DesignHeight="650"
|
||||
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
|
||||
xmlns:vm="clr-namespace:LibationAvalonia.ViewModels.Settings"
|
||||
x:DataType="vm:AudioSettingsVM"
|
||||
@@ -32,6 +32,18 @@
|
||||
Grid.Row="0"
|
||||
Grid.Column="0">
|
||||
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="{CompiledBinding FileDownloadQualityText}" />
|
||||
|
||||
<controls:WheelComboBox
|
||||
Margin="5,0,0,0"
|
||||
Grid.Column="1"
|
||||
ItemsSource="{CompiledBinding DownloadQualities}"
|
||||
SelectedItem="{CompiledBinding FileDownloadQuality}"/>
|
||||
</Grid>
|
||||
|
||||
<CheckBox IsChecked="{CompiledBinding CreateCueSheet, Mode=TwoWay}">
|
||||
<TextBlock Text="{CompiledBinding CreateCueSheetText}" />
|
||||
</CheckBox>
|
||||
@@ -61,7 +73,15 @@
|
||||
<TextBlock Text="{CompiledBinding MergeOpeningEndCreditsText}" />
|
||||
</CheckBox>
|
||||
|
||||
<CheckBox IsChecked="{CompiledBinding AllowLibationFixup, Mode=TwoWay}">
|
||||
<CheckBox
|
||||
ToolTip.Tip="{CompiledBinding CombineNestedChapterTitlesTip}"
|
||||
IsChecked="{CompiledBinding CombineNestedChapterTitles, Mode=TwoWay}">
|
||||
<TextBlock Text="{CompiledBinding CombineNestedChapterTitlesText}" />
|
||||
</CheckBox>
|
||||
|
||||
<CheckBox
|
||||
ToolTip.Tip="{CompiledBinding AllowLibationFixupTip}"
|
||||
IsChecked="{CompiledBinding AllowLibationFixup, Mode=TwoWay}">
|
||||
<TextBlock Text="{CompiledBinding AllowLibationFixupText}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
|
||||
@@ -165,18 +165,32 @@
|
||||
</StackPanel>
|
||||
</controls:GroupBox>
|
||||
|
||||
<CheckBox
|
||||
<StackPanel
|
||||
Grid.Row="3"
|
||||
Margin="5"
|
||||
VerticalAlignment="Top"
|
||||
IsVisible="{CompiledBinding !Config.IsLinux}"
|
||||
IsChecked="{CompiledBinding UseCoverAsFolderIcon, Mode=TwoWay}">
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBlock
|
||||
TextWrapping="Wrap"
|
||||
Text="{CompiledBinding UseCoverAsFolderIconText}" />
|
||||
<CheckBox
|
||||
Margin="5"
|
||||
VerticalAlignment="Top"
|
||||
IsVisible="{CompiledBinding !Config.IsLinux}"
|
||||
IsChecked="{CompiledBinding UseCoverAsFolderIcon, Mode=TwoWay}">
|
||||
|
||||
</CheckBox>
|
||||
<TextBlock
|
||||
TextWrapping="Wrap"
|
||||
Text="{CompiledBinding UseCoverAsFolderIconText}" />
|
||||
|
||||
</CheckBox>
|
||||
|
||||
<CheckBox
|
||||
Margin="5"
|
||||
VerticalAlignment="Top"
|
||||
IsChecked="{CompiledBinding SaveMetadataToFile, Mode=TwoWay}">
|
||||
|
||||
<TextBlock
|
||||
TextWrapping="Wrap"
|
||||
Text="{CompiledBinding SaveMetadataToFileText}" />
|
||||
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="450"
|
||||
mc:Ignorable="d" d:DesignWidth="700" d:DesignHeight="600"
|
||||
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
|
||||
xmlns:vm="clr-namespace:LibationAvalonia.ViewModels.Settings"
|
||||
x:DataType="vm:ImportantSettingsVM"
|
||||
x:Class="LibationAvalonia.Controls.Settings.Important">
|
||||
|
||||
<Grid RowDefinitions="Auto,Auto,*">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,*">
|
||||
<controls:GroupBox
|
||||
Grid.Row="0"
|
||||
Margin="5"
|
||||
Label="Books Location">
|
||||
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="5"
|
||||
@@ -35,7 +35,7 @@
|
||||
<Grid
|
||||
RowDefinitions="Auto,Auto"
|
||||
ColumnDefinitions="Auto,*">
|
||||
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,10,0"
|
||||
@@ -95,8 +95,63 @@
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<Grid
|
||||
<controls:GroupBox
|
||||
Grid.Row="2"
|
||||
Margin="5"
|
||||
Label="Display Settings">
|
||||
<Grid
|
||||
RowDefinitions="Auto,Auto"
|
||||
ColumnDefinitions="Auto,Auto,*">
|
||||
|
||||
<TextBlock
|
||||
Margin="0,0,10,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{CompiledBinding GridScaleFactorText}"/>
|
||||
|
||||
<Slider
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Value="{CompiledBinding GridScaleFactor, Mode=TwoWay}"
|
||||
VerticalAlignment="Center"
|
||||
Minimum="-100"
|
||||
Maximum="100"
|
||||
IsSnapToTickEnabled="False"
|
||||
TickFrequency="25"
|
||||
TickPlacement="BottomRight">
|
||||
</Slider>
|
||||
|
||||
<TextBlock
|
||||
Margin="0,0,10,0"
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Center"
|
||||
Text="{CompiledBinding GridFontScaleFactorText}"/>
|
||||
|
||||
<Slider
|
||||
Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Width="200"
|
||||
Value="{CompiledBinding GridFontScaleFactor, Mode=TwoWay}"
|
||||
VerticalAlignment="Center"
|
||||
Minimum="-100"
|
||||
Maximum="100"
|
||||
IsSnapToTickEnabled="False"
|
||||
TickFrequency="25"
|
||||
TickPlacement="BottomRight">
|
||||
</Slider>
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,5"
|
||||
Padding="20,0"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="Apply Display Settings"
|
||||
Command="{CompiledBinding ApplyDisplaySettings}"/>
|
||||
</Grid>
|
||||
</controls:GroupBox>
|
||||
|
||||
<Grid
|
||||
Grid.Row="3"
|
||||
ColumnDefinitions="Auto,Auto,*"
|
||||
Margin="10"
|
||||
VerticalAlignment="Bottom">
|
||||
@@ -111,7 +166,7 @@
|
||||
MinWidth="80"
|
||||
SelectedItem="{CompiledBinding ThemeVariant, Mode=TwoWay}"
|
||||
ItemsSource="{CompiledBinding Themes}"/>
|
||||
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
FontSize="16"
|
||||
|
||||
@@ -70,13 +70,13 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.0-rc1.1" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
|
||||
<PackageReference Include="Avalonia" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-rc1.1" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.0" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
|
||||
<PackageReference Include="Avalonia" Version="11.0.0" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.0" />
|
||||
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.0" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.0" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ApplicationServices;
|
||||
using AppScaffolding;
|
||||
@@ -35,36 +34,45 @@ namespace LibationAvalonia
|
||||
$"\"{Configuration.ProcessDirectory}\"");
|
||||
return;
|
||||
}
|
||||
AppDomain.CurrentDomain.UnhandledException += (o, e) => LogError(e.ExceptionObject);
|
||||
|
||||
bool loggingEnabled = false;
|
||||
//***********************************************//
|
||||
// //
|
||||
// do not use Configuration before this line //
|
||||
// //
|
||||
//***********************************************//
|
||||
// Migrations which must occur before configuration is loaded for the first time. Usually ones which alter the Configuration
|
||||
var config = LibationScaffolding.RunPreConfigMigrations();
|
||||
|
||||
//Start as much work in parallel as possible.
|
||||
var classicLifetimeTask = Task.Run(() => new ClassicDesktopStyleApplicationLifetime());
|
||||
var appBuilderTask = Task.Run(BuildAvaloniaApp);
|
||||
|
||||
LibationScaffolding.SetReleaseIdentifier(Variety.Chardonnay);
|
||||
|
||||
if (LibationScaffolding.ReleaseIdentifier is ReleaseIdentifier.None)
|
||||
return;
|
||||
|
||||
|
||||
if (config.LibationSettingsAreValid)
|
||||
try
|
||||
{
|
||||
if (!RunDbMigrations(config))
|
||||
return;
|
||||
var config = LibationScaffolding.RunPreConfigMigrations();
|
||||
|
||||
App.LibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true));
|
||||
//Start as much work in parallel as possible.
|
||||
var classicLifetimeTask = Task.Run(() => new ClassicDesktopStyleApplicationLifetime());
|
||||
var appBuilderTask = Task.Run(BuildAvaloniaApp);
|
||||
|
||||
if (config.LibationSettingsAreValid)
|
||||
{
|
||||
// most migrations go in here
|
||||
LibationScaffolding.RunPostConfigMigrations(config);
|
||||
LibationScaffolding.RunPostMigrationScaffolding(Variety.Chardonnay, config);
|
||||
loggingEnabled = true;
|
||||
|
||||
//Start loading the library before loading the main form
|
||||
App.LibraryTask = Task.Run(() => DbContexts.GetLibrary_Flat_NoTracking(includeParents: true));
|
||||
}
|
||||
|
||||
appBuilderTask.GetAwaiter().GetResult().SetupWithLifetime(classicLifetimeTask.GetAwaiter().GetResult());
|
||||
|
||||
classicLifetimeTask.Result.Start(null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (loggingEnabled)
|
||||
Serilog.Log.Logger.Error(ex, "CRASH");
|
||||
else
|
||||
LogError(ex);
|
||||
}
|
||||
|
||||
appBuilderTask.GetAwaiter().GetResult().SetupWithLifetime(classicLifetimeTask.GetAwaiter().GetResult());
|
||||
|
||||
classicLifetimeTask.Result.Start(null);
|
||||
}
|
||||
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
@@ -73,20 +81,35 @@ namespace LibationAvalonia
|
||||
.LogToTrace()
|
||||
.UseReactiveUI();
|
||||
|
||||
public static bool RunDbMigrations(Configuration config)
|
||||
private static void LogError(object exceptionObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
// most migrations go in here
|
||||
LibationScaffolding.RunPostConfigMigrations(config);
|
||||
LibationScaffolding.RunPostMigrationScaffolding(config);
|
||||
var logError = $"""
|
||||
{DateTime.Now} - Libation Crash
|
||||
OS {Configuration.OS}
|
||||
Version {LibationScaffolding.BuildVersion}
|
||||
ReleaseIdentifier {LibationScaffolding.ReleaseIdentifier}
|
||||
InteropFunctionsType {InteropFactory.InteropFunctionsType}
|
||||
LibationFiles {getConfigValue(c => c.LibationFiles)}
|
||||
Books Folder {getConfigValue(c => c.Books)}
|
||||
=== EXCEPTION ===
|
||||
{exceptionObject}
|
||||
""";
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception exDebug)
|
||||
var crashLog = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "LibationCrash.log");
|
||||
|
||||
using var sw = new StreamWriter(crashLog, true);
|
||||
sw.WriteLine(logError);
|
||||
|
||||
static string getConfigValue(Func<Configuration, string> selector)
|
||||
{
|
||||
Serilog.Log.Logger.Debug(exDebug, "Silent failure");
|
||||
return false;
|
||||
try
|
||||
{
|
||||
return selector(Configuration.Instance);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ex.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using ApplicationServices;
|
||||
using Avalonia.Threading;
|
||||
using DataLayer;
|
||||
using LibationFileManager;
|
||||
using ReactiveUI;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationAvalonia.ViewModels
|
||||
@@ -41,16 +44,17 @@ namespace LibationAvalonia.ViewModels
|
||||
|
||||
private void Configure_BackupCounts()
|
||||
{
|
||||
MainWindow.Loaded += setBackupCounts;
|
||||
LibraryCommands.LibrarySizeChanged += setBackupCounts;
|
||||
LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts;
|
||||
MainWindow.LibraryLoaded += (_, e) => setBackupCounts(e.Where(l => !l.Book.IsEpisodeParent()));
|
||||
LibraryCommands.LibrarySizeChanged += (_,_) => setBackupCounts();
|
||||
LibraryCommands.BookUserDefinedItemCommitted += (_, _) => setBackupCounts();
|
||||
}
|
||||
|
||||
private async void setBackupCounts(object _, object __)
|
||||
private async void setBackupCounts(IEnumerable<LibraryBook> libraryBooks = null)
|
||||
{
|
||||
if (updateCountsTask?.IsCompleted ?? true)
|
||||
{
|
||||
updateCountsTask = Task.Run(() => LibraryCommands.GetCounts());
|
||||
libraryBooks ??= DbContexts.GetLibrary_Flat_NoTracking();
|
||||
updateCountsTask = Task.Run(() => LibraryCommands.GetCounts(libraryBooks));
|
||||
var stats = await updateCountsTask;
|
||||
await Dispatcher.UIThread.InvokeAsync(() => LibraryStats = stats);
|
||||
|
||||
|
||||
@@ -264,9 +264,12 @@ namespace LibationAvalonia.ViewModels
|
||||
|
||||
private byte[] AudioDecodable_RequestCoverArt(object sender, EventArgs e)
|
||||
{
|
||||
byte[] coverData = PictureStorage
|
||||
.GetPictureSynchronously(
|
||||
new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500));
|
||||
var quality
|
||||
= Configuration.Instance.FileDownloadQuality == Configuration.DownloadQuality.High
|
||||
? new PictureDefinition(LibraryBook.Book.PictureLarge, PictureSize.Native)
|
||||
: new PictureDefinition(LibraryBook.Book.PictureId, PictureSize._500x500);
|
||||
|
||||
byte[] coverData = PictureStorage.GetPictureSynchronously(quality);
|
||||
|
||||
AudioDecodable_CoverImageDiscovered(this, coverData);
|
||||
return coverData;
|
||||
|
||||
@@ -91,37 +91,21 @@ namespace LibationAvalonia.ViewModels
|
||||
|
||||
#region Display Functions
|
||||
|
||||
internal void BindToGrid(List<LibraryBook> dbBooks)
|
||||
internal async Task BindToGridAsync(List<LibraryBook> dbBooks)
|
||||
{
|
||||
GridEntries = new(SOURCE) { Filter = CollectionFilter };
|
||||
|
||||
var geList = dbBooks
|
||||
.Where(lb => lb.Book.IsProduct())
|
||||
.Select(b => new LibraryBookEntry<AvaloniaEntryStatus>(b))
|
||||
.ToList<IGridEntry>();
|
||||
var geList = await LibraryBookEntry<AvaloniaEntryStatus>.GetAllProductsAsync(dbBooks);
|
||||
|
||||
var episodes = dbBooks.Where(lb => lb.Book.IsEpisodeChild()).ToList();
|
||||
|
||||
var seriesBooks = dbBooks.Where(lb => lb.Book.IsEpisodeParent()).ToList();
|
||||
|
||||
foreach (var parent in seriesBooks)
|
||||
{
|
||||
var seriesEpisodes = episodes.FindChildren(parent);
|
||||
|
||||
if (!seriesEpisodes.Any()) continue;
|
||||
|
||||
var seriesEntry = new SeriesEntry<AvaloniaEntryStatus>(parent, seriesEpisodes);
|
||||
seriesEntry.Liberate.Expanded = false;
|
||||
|
||||
geList.Add(seriesEntry);
|
||||
}
|
||||
var seriesEntries = await SeriesEntry<AvaloniaEntryStatus>.GetAllSeriesEntriesAsync(dbBooks);
|
||||
|
||||
//Create the filtered-in list before adding entries to avoid a refresh
|
||||
FilteredInGridEntries = geList.Union(geList.OfType<ISeriesEntry>().SelectMany(s => s.Children)).FilterEntries(FilterString);
|
||||
SOURCE.AddRange(geList.OrderDescending(new RowComparer(null)));
|
||||
FilteredInGridEntries = geList.Union(seriesEntries.SelectMany(s => s.Children)).FilterEntries(FilterString);
|
||||
//Adding entries to the Source list will invoke CollectionFilter
|
||||
SOURCE.AddRange(geList.Concat(seriesEntries).OrderDescending(new RowComparer(null)));
|
||||
|
||||
//Add all children beneath their parent
|
||||
foreach (var series in SOURCE.OfType<ISeriesEntry>().ToList())
|
||||
foreach (var series in seriesEntries)
|
||||
{
|
||||
var seriesIndex = SOURCE.IndexOf(series);
|
||||
foreach (var child in series.Children)
|
||||
|
||||
@@ -44,10 +44,12 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
public void LoadSettings(Configuration config)
|
||||
{
|
||||
CreateCueSheet = config.CreateCueSheet;
|
||||
CombineNestedChapterTitles = config.CombineNestedChapterTitles;
|
||||
AllowLibationFixup = config.AllowLibationFixup;
|
||||
DownloadCoverArt = config.DownloadCoverArt;
|
||||
RetainAaxFile = config.RetainAaxFile;
|
||||
DownloadClipsBookmarks = config.DownloadClipsBookmarks;
|
||||
FileDownloadQuality = config.FileDownloadQuality;
|
||||
ClipBookmarkFormat = config.ClipsBookmarksFileFormat;
|
||||
SplitFilesByChapter = config.SplitFilesByChapter;
|
||||
MergeOpeningAndEndCredits = config.MergeOpeningAndEndCredits;
|
||||
@@ -70,10 +72,12 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
public void SaveSettings(Configuration config)
|
||||
{
|
||||
config.CreateCueSheet = CreateCueSheet;
|
||||
config.CombineNestedChapterTitles = CombineNestedChapterTitles;
|
||||
config.AllowLibationFixup = AllowLibationFixup;
|
||||
config.DownloadCoverArt = DownloadCoverArt;
|
||||
config.RetainAaxFile = RetainAaxFile;
|
||||
config.DownloadClipsBookmarks = DownloadClipsBookmarks;
|
||||
config.FileDownloadQuality = FileDownloadQuality;
|
||||
config.ClipsBookmarksFileFormat = ClipBookmarkFormat;
|
||||
config.SplitFilesByChapter = SplitFilesByChapter;
|
||||
config.MergeOpeningAndEndCredits = MergeOpeningAndEndCredits;
|
||||
@@ -93,9 +97,14 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
config.MaxSampleRate = SelectedSampleRate?.Value ?? config.MaxSampleRate;
|
||||
}
|
||||
|
||||
public AvaloniaList<Configuration.DownloadQuality> DownloadQualities { get; } = new(Enum<Configuration.DownloadQuality>.GetValues());
|
||||
public AvaloniaList<Configuration.ClipBookmarkFormat> ClipBookmarkFormats { get; } = new(Enum<Configuration.ClipBookmarkFormat>.GetValues());
|
||||
public string FileDownloadQualityText { get; } = Configuration.GetDescription(nameof(Configuration.FileDownloadQuality));
|
||||
public string CreateCueSheetText { get; } = Configuration.GetDescription(nameof(Configuration.CreateCueSheet));
|
||||
public string CombineNestedChapterTitlesText { get; } = Configuration.GetDescription(nameof(Configuration.CombineNestedChapterTitles));
|
||||
public string CombineNestedChapterTitlesTip => Configuration.GetHelpText(nameof(CombineNestedChapterTitles));
|
||||
public string AllowLibationFixupText { get; } = Configuration.GetDescription(nameof(Configuration.AllowLibationFixup));
|
||||
public string AllowLibationFixupTip => Configuration.GetHelpText(nameof(AllowLibationFixup));
|
||||
public string DownloadCoverArtText { get; } = Configuration.GetDescription(nameof(Configuration.DownloadCoverArt));
|
||||
public string RetainAaxFileText { get; } = Configuration.GetDescription(nameof(Configuration.RetainAaxFile));
|
||||
public string SplitFilesByChapterText { get; } = Configuration.GetDescription(nameof(Configuration.SplitFilesByChapter));
|
||||
@@ -106,9 +115,11 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
public string MoveMoovToBeginningText { get; } = Configuration.GetDescription(nameof(Configuration.MoveMoovToBeginning));
|
||||
|
||||
public bool CreateCueSheet { get; set; }
|
||||
public bool CombineNestedChapterTitles { get; set; }
|
||||
public bool DownloadCoverArt { get; set; }
|
||||
public bool RetainAaxFile { get; set; }
|
||||
public bool DownloadClipsBookmarks { get => _downloadClipsBookmarks; set => this.RaiseAndSetIfChanged(ref _downloadClipsBookmarks, value); }
|
||||
public Configuration.DownloadQuality FileDownloadQuality { get; set; }
|
||||
public Configuration.ClipBookmarkFormat ClipBookmarkFormat { get; set; }
|
||||
public bool MergeOpeningAndEndCredits { get; set; }
|
||||
public bool StripAudibleBrandAudio { get; set; }
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
ChapterFileTemplate = config.ChapterFileTemplate;
|
||||
InProgressDirectory = config.InProgress;
|
||||
UseCoverAsFolderIcon = config.UseCoverAsFolderIcon;
|
||||
SaveMetadataToFile = config.SaveMetadataToFile;
|
||||
}
|
||||
|
||||
public void SaveSettings(Configuration config)
|
||||
@@ -54,9 +55,11 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
config.InProgress = InProgressDirectory;
|
||||
|
||||
config.UseCoverAsFolderIcon = UseCoverAsFolderIcon;
|
||||
config.SaveMetadataToFile = SaveMetadataToFile;
|
||||
}
|
||||
|
||||
public string UseCoverAsFolderIconText { get; } = Configuration.GetDescription(nameof(Configuration.UseCoverAsFolderIcon));
|
||||
public string SaveMetadataToFileText { get; } = Configuration.GetDescription(nameof(Configuration.SaveMetadataToFile));
|
||||
public string BadBookGroupboxText { get; } = Configuration.GetDescription(nameof(Configuration.BadBook));
|
||||
public string BadBookAskText { get; } = Configuration.BadBookAction.Ask.GetDescription();
|
||||
public string BadBookAbortText { get; } = Configuration.BadBookAction.Abort.GetDescription();
|
||||
@@ -72,6 +75,7 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
public string FileTemplate { get => _fileTemplate; set { this.RaiseAndSetIfChanged(ref _fileTemplate, value); } }
|
||||
public string ChapterFileTemplate { get => _chapterFileTemplate; set { this.RaiseAndSetIfChanged(ref _chapterFileTemplate, value); } }
|
||||
public bool UseCoverAsFolderIcon { get; set; }
|
||||
public bool SaveMetadataToFile { get; set; }
|
||||
|
||||
public bool BadBookAsk { get; set; }
|
||||
public bool BadBookAbort { get; set; }
|
||||
|
||||
@@ -13,9 +13,11 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
{
|
||||
private string themeVariant;
|
||||
private string initialThemeVariant;
|
||||
private readonly Configuration config;
|
||||
|
||||
public ImportantSettingsVM(Configuration config)
|
||||
{
|
||||
this.config = config;
|
||||
LoadSettings(config);
|
||||
}
|
||||
|
||||
@@ -27,6 +29,8 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
CreationTime = DateTimeSources.SingleOrDefault(v => v.Value == config.CreationTime) ?? DateTimeSources[0];
|
||||
LastWriteTime = DateTimeSources.SingleOrDefault(v => v.Value == config.LastWriteTime) ?? DateTimeSources[0];
|
||||
LoggingLevel = config.LogLevel;
|
||||
GridScaleFactor = scaleFactorToLinearRange(config.GridScaleFactor);
|
||||
GridFontScaleFactor = scaleFactorToLinearRange(config.GridFontScaleFactor);
|
||||
ThemeVariant = initialThemeVariant
|
||||
= Configuration.Instance.GetString(propertyName: nameof(ThemeVariant)) is nameof(Avalonia.Styling.ThemeVariant.Dark)
|
||||
? nameof(Avalonia.Styling.ThemeVariant.Dark)
|
||||
@@ -47,6 +51,16 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
Configuration.Instance.SetString(ThemeVariant, nameof(ThemeVariant));
|
||||
}
|
||||
|
||||
private static float scaleFactorToLinearRange(float scaleFactor)
|
||||
=> float.Round(100 * MathF.Log2(scaleFactor));
|
||||
private static float linearRangeToScaleFactor(float value)
|
||||
=> MathF.Pow(2, value / 100f);
|
||||
|
||||
public void ApplyDisplaySettings()
|
||||
{
|
||||
config.GridFontScaleFactor = linearRangeToScaleFactor(GridFontScaleFactor);
|
||||
config.GridScaleFactor = linearRangeToScaleFactor(GridScaleFactor);
|
||||
}
|
||||
public void OpenLogFolderButton() => Go.To.Folder(((LongPath)Configuration.Instance.LibationFiles).ShortPathName);
|
||||
|
||||
public List<Configuration.KnownDirectories> KnownDirectories { get; } = new()
|
||||
@@ -66,12 +80,16 @@ namespace LibationAvalonia.ViewModels.Settings
|
||||
.Select(v => new EnumDiaplay<Configuration.DateTimeSource>(v))
|
||||
.ToArray();
|
||||
public Serilog.Events.LogEventLevel[] LoggingLevels { get; } = Enum.GetValues<Serilog.Events.LogEventLevel>();
|
||||
public string GridScaleFactorText { get; } = Configuration.GetDescription(nameof(Configuration.GridScaleFactor));
|
||||
public string GridFontScaleFactorText { get; } = Configuration.GetDescription(nameof(Configuration.GridFontScaleFactor));
|
||||
public string BetaOptInText { get; } = Configuration.GetDescription(nameof(Configuration.BetaOptIn));
|
||||
public string[] Themes { get; } = { nameof(Avalonia.Styling.ThemeVariant.Light), nameof(Avalonia.Styling.ThemeVariant.Dark) };
|
||||
|
||||
public string BooksDirectory { get; set; }
|
||||
public bool SavePodcastsToParentFolder { get; set; }
|
||||
public bool OverwriteExisting { get; set; }
|
||||
public float GridScaleFactor { get; set; }
|
||||
public float GridFontScaleFactor { get; set; }
|
||||
public EnumDiaplay<Configuration.DateTimeSource> CreationTime { get; set; }
|
||||
public EnumDiaplay<Configuration.DateTimeSource> LastWriteTime { get; set; }
|
||||
public Serilog.Events.LogEventLevel LoggingLevel { get; set; }
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:LibationAvalonia.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="200" MinWidth="64" MinHeight="64"
|
||||
mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="200" MinWidth="37" MinHeight="40"
|
||||
Background="Transparent"
|
||||
x:DataType="vm:LiberateStatusButtonViewModel"
|
||||
x:Class="LibationAvalonia.Views.LiberateStatusButton">
|
||||
@@ -35,48 +35,51 @@
|
||||
Name="button"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsEnabled="{CompiledBinding IsButtonEnabled}" Padding="0" Click="Button_Click" >
|
||||
<Panel>
|
||||
|
||||
<Panel
|
||||
Width="64" Height="64"
|
||||
IsVisible="{CompiledBinding !IsError}">
|
||||
Padding="0"
|
||||
IsEnabled="{CompiledBinding IsButtonEnabled}" Click="Button_Click" >
|
||||
|
||||
<Panel IsVisible="{CompiledBinding IsSeries}">
|
||||
<Path IsVisible="{CompiledBinding Expanded}" Data="{StaticResource CollapseIcon}" />
|
||||
<Path IsVisible="{CompiledBinding !Expanded}" Data="{StaticResource ExpandIcon}" />
|
||||
<Grid RowDefinitions="*,8*,*">
|
||||
<Viewbox
|
||||
Grid.Row="1"
|
||||
Stretch="Uniform"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Panel>
|
||||
<Panel IsVisible="{CompiledBinding !IsError}">
|
||||
|
||||
<Panel IsVisible="{CompiledBinding IsSeries}">
|
||||
<Path IsVisible="{CompiledBinding Expanded}" Data="{StaticResource CollapseIcon}" />
|
||||
<Path IsVisible="{CompiledBinding !Expanded}" Data="{StaticResource ExpandIcon}" />
|
||||
</Panel>
|
||||
|
||||
<Grid
|
||||
IsVisible="{CompiledBinding !IsSeries}"
|
||||
HorizontalAlignment="Center"
|
||||
ColumnDefinitions="Auto,Auto">
|
||||
<Canvas Width="29.44" Height="64">
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="5" IsVisible="{CompiledBinding RedVisible}" Fill="{DynamicResource StoplightRed}" />
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="23" IsVisible="{CompiledBinding YellowVisible}" Fill="{DynamicResource StoplightYellow}" />
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="42" IsVisible="{CompiledBinding GreenVisible}" Fill="{DynamicResource StoplightGreen}" />
|
||||
<Path Height="64" Stretch="Uniform" Data="{StaticResource StoplightBodyIcon}"/>
|
||||
</Canvas>
|
||||
<Path Grid.Column="1" IsVisible="{CompiledBinding PdfDownloadedVisible}" Data="{StaticResource PdfDownloadedIcon}"/>
|
||||
<Path Grid.Column="1" IsVisible="{CompiledBinding PdfNotDownloadedVisible}" Data="{StaticResource PdfNotDownloadedIcon}"/>
|
||||
</Grid>
|
||||
</Panel>
|
||||
|
||||
<Path
|
||||
Stretch="None" Width="64"
|
||||
IsVisible="{CompiledBinding IsError}"
|
||||
Fill="{DynamicResource CancelRed}"
|
||||
Data="{StaticResource BookErrorIcon}" />
|
||||
|
||||
<Path
|
||||
Stretch="Fill"
|
||||
IsVisible="{CompiledBinding !IsButtonEnabled}"
|
||||
Fill="{DynamicResource DisabledGrayBrush}"
|
||||
Data="M0,0 H1 V1 H0" />
|
||||
</Panel>
|
||||
|
||||
<Grid
|
||||
IsVisible="{CompiledBinding !IsSeries}"
|
||||
HorizontalAlignment="Center"
|
||||
ColumnDefinitions="Auto,Auto">
|
||||
|
||||
<Canvas Width="29.44" Height="64">
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="5" IsVisible="{CompiledBinding RedVisible}" Fill="{DynamicResource StoplightRed}" />
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="23" IsVisible="{CompiledBinding YellowVisible}" Fill="{DynamicResource StoplightYellow}" />
|
||||
<Rectangle Canvas.Left="5" Canvas.Top="42" IsVisible="{CompiledBinding GreenVisible}" Fill="{DynamicResource StoplightGreen}" />
|
||||
<Path Height="64" Stretch="Uniform" Data="{StaticResource StoplightBodyIcon}"/>
|
||||
</Canvas>
|
||||
|
||||
<Path Grid.Column="1" IsVisible="{CompiledBinding PdfDownloadedVisible}" Data="{StaticResource PdfDownloadedIcon}"/>
|
||||
<Path Grid.Column="1" IsVisible="{CompiledBinding PdfNotDownloadedVisible}" Data="{StaticResource PdfNotDownloadedIcon}"/>
|
||||
</Grid>
|
||||
|
||||
</Panel>
|
||||
|
||||
<Path
|
||||
Stretch="None" Width="64"
|
||||
IsVisible="{CompiledBinding IsError}"
|
||||
Fill="{DynamicResource CancelRed}"
|
||||
Data="{StaticResource BookErrorIcon}" />
|
||||
|
||||
<Path
|
||||
Stretch="Fill"
|
||||
IsVisible="{CompiledBinding !IsButtonEnabled}"
|
||||
Fill="{DynamicResource DisabledGrayBrush}"
|
||||
Data="M0,0 H1 V1 H0" />
|
||||
</Panel>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace LibationAvalonia.Views
|
||||
if (QuickFilters.UseDefault)
|
||||
await ViewModel.PerformFilter(QuickFilters.Filters.FirstOrDefault());
|
||||
|
||||
ViewModel.ProductsDisplay.BindToGrid(dbBooks);
|
||||
await ViewModel.ProductsDisplay.BindToGridAsync(dbBooks);
|
||||
}
|
||||
|
||||
private void selectAndFocusSearchBox()
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
CanUserReorderColumns="True">
|
||||
|
||||
<DataGrid.Styles>
|
||||
<Style Selector="DataGridCell">
|
||||
<Setter Property="Height" Value="80"/>
|
||||
</Style>
|
||||
<Style Selector="DataGridCell > Panel">
|
||||
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
||||
</Style>
|
||||
@@ -31,7 +28,6 @@
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="TextWrapping" Value="Wrap"/>
|
||||
<Setter Property="Padding" Value="4"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
</Style>
|
||||
<Style Selector="DataGridCell Path">
|
||||
<Setter Property="Stretch" Value="Uniform" />
|
||||
@@ -69,7 +65,7 @@
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<controls:DataGridTemplateColumnExt CanUserSort="True" Width="75" Header="Liberate" SortMemberPath="Liberate" ClipboardContentBinding="{Binding Liberate.ToolTip}">
|
||||
<controls:DataGridTemplateColumnExt CanUserSort="True" Header="Liberate" SortMemberPath="Liberate" ClipboardContentBinding="{Binding Liberate.ToolTip}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<views:LiberateStatusButton
|
||||
@@ -84,19 +80,19 @@
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</controls:DataGridTemplateColumnExt>
|
||||
|
||||
<DataGridTemplateColumn CanUserSort="False" Width="80" Header="Cover" SortMemberPath="Cover" ClipboardContentBinding="{Binding LibraryBook.Book.PictureLarge}">
|
||||
<controls:DataGridTemplateColumnExt CanUserSort="False" Header="Cover" SortMemberPath="Cover" ClipboardContentBinding="{Binding LibraryBook.Book.PictureLarge}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Image Opacity="{CompiledBinding Liberate.Opacity}" Tapped="Cover_Click" Height="80" Source="{CompiledBinding Cover}" ToolTip.Tip="Click to see full size" />
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Image Opacity="{CompiledBinding Liberate.Opacity}" Tapped="Cover_Click" Source="{CompiledBinding Cover}" ToolTip.Tip="Click to see full size" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</controls:DataGridTemplateColumnExt>
|
||||
|
||||
<controls:DataGridTemplateColumnExt MinWidth="150" Width="2*" Header="Title" CanUserSort="True" SortMemberPath="Title" ClipboardContentBinding="{Binding Title}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||
<TextBlock FontSize="14" Text="{CompiledBinding Title}" />
|
||||
<TextBlock Classes="h1" Text="{CompiledBinding Title}" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
@@ -156,7 +152,7 @@
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
|
||||
<TextBlock Text="{CompiledBinding Description}" FontSize="11" VerticalAlignment="Top" />
|
||||
<TextBlock Text="{CompiledBinding Description}" VerticalAlignment="Top" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
@@ -208,7 +204,7 @@
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}">
|
||||
<TextBlock Text="{CompiledBinding Misc}" TextWrapping="WrapWithOverflow" FontSize="10" />
|
||||
<TextBlock Text="{CompiledBinding Misc}" TextWrapping="WrapWithOverflow" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
@@ -218,7 +214,7 @@
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Background="{CompiledBinding Liberate.BackgroundBrush}" ToolTip.Tip="{CompiledBinding LastDownload.ToolTipText}" DoubleTapped="Version_DoubleClick">
|
||||
<TextBlock Text="{CompiledBinding LastDownload}" TextWrapping="WrapWithOverflow" FontSize="10" />
|
||||
<TextBlock Text="{CompiledBinding LastDownload}" TextWrapping="WrapWithOverflow" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
@@ -227,13 +223,30 @@
|
||||
<controls:DataGridTemplateColumnExt CanUserSort="True" Width="100" Header="Tags" SortMemberPath="BookTags" ClipboardContentBinding="{Binding BookTags}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="uibase:IGridEntry">
|
||||
<Button IsVisible="{CompiledBinding !Liberate.IsSeries}" Width="100" Height="80" Click="OnTagsButtonClick" ToolTip.Tip="Click to edit tags" >
|
||||
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
|
||||
<Panel Width="24" Height="24" IsVisible="{CompiledBinding BookTags, Converter={x:Static StringConverters.IsNullOrEmpty}}">
|
||||
<Path Stretch="Uniform" Fill="{DynamicResource IconFill}" Data="{StaticResource EditTagsIcon}" />
|
||||
</Panel>
|
||||
<TextBlock IsVisible="{CompiledBinding BookTags, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" FontSize="12" TextWrapping="WrapWithOverflow" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{CompiledBinding BookTags}"/>
|
||||
</Panel>
|
||||
<Button
|
||||
IsVisible="{CompiledBinding !Liberate.IsSeries}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Click="OnTagsButtonClick"
|
||||
ToolTip.Tip="Click to edit tags">
|
||||
<Grid
|
||||
RowDefinitions="*,*,*"
|
||||
Opacity="{CompiledBinding Liberate.Opacity}">
|
||||
<Viewbox
|
||||
Grid.Row="1"
|
||||
Stretch="Uniform"
|
||||
IsVisible="{CompiledBinding BookTags, Converter={x:Static StringConverters.IsNullOrEmpty}}">
|
||||
|
||||
<Path Fill="{DynamicResource IconFill}" Data="{StaticResource EditTagsIcon}" />
|
||||
</Viewbox>
|
||||
<TextBlock
|
||||
Classes="h2"
|
||||
Grid.RowSpan="3"
|
||||
IsVisible="{CompiledBinding BookTags, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" TextWrapping="WrapWithOverflow" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{CompiledBinding BookTags}"/>
|
||||
|
||||
</Grid>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
|
||||
@@ -2,7 +2,9 @@ using ApplicationServices;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Styling;
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using FileLiberator;
|
||||
using LibationAvalonia.Controls;
|
||||
using LibationAvalonia.Dialogs;
|
||||
@@ -30,6 +32,25 @@ namespace LibationAvalonia.Views
|
||||
InitializeComponent();
|
||||
DataGridContextMenus.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded;
|
||||
|
||||
var cellSelector = Selectors.Is<DataGridCell>(null);
|
||||
rowHeightStyle = new Style(_ => cellSelector);
|
||||
rowHeightStyle.Setters.Add(rowHeightSetter);
|
||||
|
||||
var tboxSelector = cellSelector.Descendant().Is<TextBlock>();
|
||||
fontSizeStyle = new Style(_ => tboxSelector);
|
||||
fontSizeStyle.Setters.Add(fontSizeSetter);
|
||||
|
||||
var tboxH1Selector = cellSelector.Child().Is<Panel>().Child().Is<TextBlock>().Class("h1");
|
||||
fontSizeH1Style = new Style(_ => tboxH1Selector);
|
||||
fontSizeH1Style.Setters.Add(fontSizeH1Setter);
|
||||
|
||||
var tboxH2Selector = cellSelector.Child().Is<Panel>().Child().Is<TextBlock>().Class("h2");
|
||||
fontSizeH2Style = new Style(_ => tboxH2Selector);
|
||||
fontSizeH2Style.Setters.Add(fontSizeH2Setter);
|
||||
|
||||
Configuration.Instance.PropertyChanged += Configuration_GridScaleChanged;
|
||||
Configuration.Instance.PropertyChanged += Configuration_FontChanged;
|
||||
|
||||
if (Design.IsDesignMode)
|
||||
{
|
||||
using var context = DbContexts.GetContext();
|
||||
@@ -51,12 +72,16 @@ namespace LibationAvalonia.Views
|
||||
catch { sampleEntries = new(); }
|
||||
|
||||
var pdvm = new ProductsDisplayViewModel();
|
||||
pdvm.BindToGrid(sampleEntries);
|
||||
_ = pdvm.BindToGridAsync(sampleEntries);
|
||||
DataContext = pdvm;
|
||||
|
||||
setGridScale(1);
|
||||
setFontScale(1);
|
||||
return;
|
||||
}
|
||||
|
||||
setGridScale(Configuration.Instance.GridScaleFactor);
|
||||
setFontScale(Configuration.Instance.GridFontScaleFactor);
|
||||
Configure_ColumnCustomization();
|
||||
|
||||
foreach (var column in productsGrid.Columns)
|
||||
@@ -67,174 +92,257 @@ namespace LibationAvalonia.Views
|
||||
|
||||
private void RemoveColumn_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
if (sender is DataGridColumn col && e.Property.Name == nameof(DataGridColumn.IsVisible))
|
||||
if (sender is DataGridColumn col && e.Property == DataGridColumn.IsVisibleProperty)
|
||||
{
|
||||
col.DisplayIndex = 0;
|
||||
col.CanUserReorder = false;
|
||||
}
|
||||
}
|
||||
|
||||
#region Scaling
|
||||
|
||||
[PropertyChangeFilter(nameof(Configuration.GridScaleFactor))]
|
||||
private void Configuration_GridScaleChanged(object sender, Dinah.Core.PropertyChangedEventArgsEx e)
|
||||
{
|
||||
setGridScale((float)e.NewValue);
|
||||
}
|
||||
|
||||
[PropertyChangeFilter(nameof(Configuration.GridFontScaleFactor))]
|
||||
private void Configuration_FontChanged(object sender, Dinah.Core.PropertyChangedEventArgsEx e)
|
||||
{
|
||||
setFontScale((float)e.NewValue);
|
||||
}
|
||||
|
||||
private readonly Style rowHeightStyle;
|
||||
private readonly Setter rowHeightSetter = new() { Property = DataGridCell.HeightProperty };
|
||||
|
||||
private readonly Style fontSizeStyle;
|
||||
private readonly Setter fontSizeSetter = new() { Property = TextBlock.FontSizeProperty };
|
||||
|
||||
private readonly Style fontSizeH1Style;
|
||||
private readonly Setter fontSizeH1Setter = new() { Property = TextBlock.FontSizeProperty };
|
||||
|
||||
private readonly Style fontSizeH2Style;
|
||||
private readonly Setter fontSizeH2Setter = new() { Property = TextBlock.FontSizeProperty };
|
||||
|
||||
private void setFontScale(double scaleFactor)
|
||||
{
|
||||
const double TextBlockFontSize = 11;
|
||||
const double H1FontSize = 14;
|
||||
const double H2FontSize = 12;
|
||||
|
||||
fontSizeSetter.Value = TextBlockFontSize * scaleFactor;
|
||||
fontSizeH1Setter.Value = H1FontSize * scaleFactor;
|
||||
fontSizeH2Setter.Value = H2FontSize * scaleFactor;
|
||||
|
||||
productsGrid.Styles.Remove(fontSizeStyle);
|
||||
productsGrid.Styles.Remove(fontSizeH1Style);
|
||||
productsGrid.Styles.Remove(fontSizeH2Style);
|
||||
productsGrid.Styles.Add(fontSizeStyle);
|
||||
productsGrid.Styles.Add(fontSizeH1Style);
|
||||
productsGrid.Styles.Add(fontSizeH2Style);
|
||||
}
|
||||
|
||||
private void setGridScale(double scaleFactor)
|
||||
{
|
||||
const float BaseRowHeight = 80;
|
||||
const float BaseLiberateWidth = 75;
|
||||
const float BaseCoverWidth = 80;
|
||||
|
||||
foreach (var column in productsGrid.Columns)
|
||||
{
|
||||
switch (column.SortMemberPath)
|
||||
{
|
||||
case nameof(IGridEntry.Liberate):
|
||||
column.Width = new DataGridLength(BaseLiberateWidth * scaleFactor);
|
||||
break;
|
||||
case nameof(IGridEntry.Cover):
|
||||
column.Width = new DataGridLength(BaseCoverWidth * scaleFactor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
rowHeightSetter.Value = BaseRowHeight * scaleFactor;
|
||||
productsGrid.Styles.Remove(rowHeightStyle);
|
||||
productsGrid.Styles.Add(rowHeightStyle);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cell Context Menu
|
||||
|
||||
public void ProductsGrid_CellContextMenuStripNeeded(object sender, DataGridCellContextMenuStripNeededEventArgs args)
|
||||
{
|
||||
// stop light
|
||||
if (args.Column.SortMemberPath == "Liberate")
|
||||
if (args.Column.SortMemberPath is not "Liberate" and not "Cover")
|
||||
{
|
||||
var entry = args.GridEntry;
|
||||
|
||||
#region Liberate all Episodes
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
{
|
||||
var liberateEpisodesMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "_Liberate All Episodes",
|
||||
IsEnabled = ((ISeriesEntry)entry).Children.Any(c => c.Liberate.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload)
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(liberateEpisodesMenuItem);
|
||||
|
||||
liberateEpisodesMenuItem.Click += (_, _) => LiberateSeriesClicked?.Invoke(this, ((ISeriesEntry)entry));
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Set Download status to Downloaded
|
||||
|
||||
var setDownloadMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "Set Download status to '_Downloaded'",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated || entry.Liberate.IsSeries
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(setDownloadMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
setDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.Liberated);
|
||||
else
|
||||
setDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.Liberated);
|
||||
|
||||
#endregion
|
||||
#region Set Download status to Not Downloaded
|
||||
|
||||
var setNotDownloadMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "Set Download status to '_Not Downloaded'",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated || entry.Liberate.IsSeries
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(setNotDownloadMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
setNotDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||
else
|
||||
setNotDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||
|
||||
#endregion
|
||||
#region Remove from library
|
||||
|
||||
var removeMenuItem = new MenuItem() { Header = "_Remove from library" };
|
||||
|
||||
args.ContextMenuItems.Add(removeMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
removeMenuItem.Click += async (_, __) => await ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).RemoveBooksAsync();
|
||||
else
|
||||
removeMenuItem.Click += async (_, __) => await Task.Run(entry.LibraryBook.RemoveBook);
|
||||
|
||||
#endregion
|
||||
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
#region Locate file
|
||||
var locateFileMenuItem = new MenuItem() { Header = "_Locate file..." };
|
||||
|
||||
args.ContextMenuItems.Add(locateFileMenuItem);
|
||||
|
||||
locateFileMenuItem.Click += async (_, __) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var window = this.GetParentWindow();
|
||||
|
||||
var openFileDialogOptions = new FilePickerOpenOptions
|
||||
{
|
||||
Title = $"Locate the audio file for '{entry.Book.TitleWithSubtitle}'",
|
||||
AllowMultiple = false,
|
||||
SuggestedStartLocation = await window.StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books.PathWithoutPrefix),
|
||||
FileTypeFilter = new FilePickerFileType[]
|
||||
{
|
||||
new("All files (*.*)") { Patterns = new[] { "*" } },
|
||||
}
|
||||
};
|
||||
|
||||
var selectedFiles = await window.StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
|
||||
var selectedFile = selectedFiles.SingleOrDefault()?.TryGetLocalPath();
|
||||
|
||||
if (selectedFile is not null)
|
||||
FilePathCache.Insert(entry.AudibleProductId, selectedFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var msg = "Error saving book's location";
|
||||
await MessageBox.ShowAdminAlert(null, msg, msg, ex);
|
||||
}
|
||||
};
|
||||
|
||||
#endregion
|
||||
#region Convert to Mp3
|
||||
var convertToMp3MenuItem = new MenuItem
|
||||
{
|
||||
Header = "_Convert to Mp3",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
||||
};
|
||||
args.ContextMenuItems.Add(convertToMp3MenuItem);
|
||||
|
||||
convertToMp3MenuItem.Click += (_, _) => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
args.ContextMenuItems.Add(new Separator());
|
||||
|
||||
#region View Bookmarks/Clips
|
||||
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
|
||||
var bookRecordMenuItem = new MenuItem { Header = "View _Bookmarks/Clips" };
|
||||
|
||||
args.ContextMenuItems.Add(bookRecordMenuItem);
|
||||
|
||||
bookRecordMenuItem.Click += async (_, _) => await new BookRecordsDialog(entry.LibraryBook).ShowDialog(VisualRoot as Window);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region View All Series
|
||||
|
||||
if (entry.Book.SeriesLink.Any())
|
||||
{
|
||||
var header = entry.Liberate.IsSeries ? "View All Episodes in Series" : "View All Books in Series";
|
||||
var viewSeriesMenuItem = new MenuItem { Header = header };
|
||||
|
||||
args.ContextMenuItems.Add(viewSeriesMenuItem);
|
||||
|
||||
viewSeriesMenuItem.Click += (_, _) => new SeriesViewDialog(entry.LibraryBook).Show();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
// any non-stop light column
|
||||
// (except for the Cover column which does not have a context menu)
|
||||
var menuItem = new MenuItem { Header = "_Copy Cell Contents" };
|
||||
|
||||
menuItem.Click += async (s, e)
|
||||
=> await App.MainWindow.Clipboard.SetTextAsync(args.CellClipboardContents);
|
||||
|
||||
args.ContextMenuItems.Add(menuItem);
|
||||
args.ContextMenuItems.Add(new Separator());
|
||||
}
|
||||
var entry = args.GridEntry;
|
||||
|
||||
#region Liberate all Episodes
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
{
|
||||
var liberateEpisodesMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "_Liberate All Episodes",
|
||||
IsEnabled = ((ISeriesEntry)entry).Children.Any(c => c.Liberate.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload)
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(liberateEpisodesMenuItem);
|
||||
|
||||
liberateEpisodesMenuItem.Click += (_, _) => LiberateSeriesClicked?.Invoke(this, ((ISeriesEntry)entry));
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Set Download status to Downloaded
|
||||
|
||||
var setDownloadMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "Set Download status to '_Downloaded'",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated || entry.Liberate.IsSeries
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(setDownloadMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
setDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.Liberated);
|
||||
else
|
||||
setDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.Liberated);
|
||||
|
||||
#endregion
|
||||
#region Set Download status to Not Downloaded
|
||||
|
||||
var setNotDownloadMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "Set Download status to '_Not Downloaded'",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated || entry.Liberate.IsSeries
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(setNotDownloadMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
setNotDownloadMenuItem.Click += (_, __) => ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||
else
|
||||
setNotDownloadMenuItem.Click += (_, __) => entry.LibraryBook.UpdateBookStatus(LiberatedStatus.NotLiberated);
|
||||
|
||||
#endregion
|
||||
#region Remove from library
|
||||
|
||||
var removeMenuItem = new MenuItem() { Header = "_Remove from library" };
|
||||
|
||||
args.ContextMenuItems.Add(removeMenuItem);
|
||||
|
||||
if (entry.Liberate.IsSeries)
|
||||
removeMenuItem.Click += async (_, __) => await ((ISeriesEntry)entry).Children.Select(c => c.LibraryBook).RemoveBooksAsync();
|
||||
else
|
||||
removeMenuItem.Click += async (_, __) => await Task.Run(entry.LibraryBook.RemoveBook);
|
||||
|
||||
#endregion
|
||||
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
#region Locate file
|
||||
var locateFileMenuItem = new MenuItem() { Header = "_Locate file..." };
|
||||
|
||||
args.ContextMenuItems.Add(locateFileMenuItem);
|
||||
|
||||
locateFileMenuItem.Click += async (_, __) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var window = this.GetParentWindow();
|
||||
|
||||
var openFileDialogOptions = new FilePickerOpenOptions
|
||||
{
|
||||
Title = $"Locate the audio file for '{entry.Book.TitleWithSubtitle}'",
|
||||
AllowMultiple = false,
|
||||
SuggestedStartLocation = await window.StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books.PathWithoutPrefix),
|
||||
FileTypeFilter = new FilePickerFileType[]
|
||||
{
|
||||
new("All files (*.*)") { Patterns = new[] { "*" } },
|
||||
}
|
||||
};
|
||||
|
||||
var selectedFiles = await window.StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
|
||||
var selectedFile = selectedFiles.SingleOrDefault()?.TryGetLocalPath();
|
||||
|
||||
if (selectedFile is not null)
|
||||
FilePathCache.Insert(entry.AudibleProductId, selectedFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var msg = "Error saving book's location";
|
||||
await MessageBox.ShowAdminAlert(null, msg, msg, ex);
|
||||
}
|
||||
};
|
||||
|
||||
#endregion
|
||||
#region Convert to Mp3
|
||||
var convertToMp3MenuItem = new MenuItem
|
||||
{
|
||||
Header = "_Convert to Mp3",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
||||
};
|
||||
args.ContextMenuItems.Add(convertToMp3MenuItem);
|
||||
|
||||
convertToMp3MenuItem.Click += (_, _) => ConvertToMp3Clicked?.Invoke(this, entry.LibraryBook);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region Force Re-Download
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
var reDownloadMenuItem = new MenuItem()
|
||||
{
|
||||
Header = "Re-download this audiobook",
|
||||
IsEnabled = entry.Book.UserDefinedItem.BookStatus is LiberatedStatus.Liberated
|
||||
};
|
||||
|
||||
args.ContextMenuItems.Add(reDownloadMenuItem);
|
||||
reDownloadMenuItem.Click += (s, _) =>
|
||||
{
|
||||
//No need to persist this change. It only needs to last long for the file to start downloading
|
||||
entry.Book.UserDefinedItem.BookStatus = LiberatedStatus.NotLiberated;
|
||||
LiberateClicked?.Invoke(s, entry.LibraryBook);
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
args.ContextMenuItems.Add(new Separator());
|
||||
|
||||
#region View Bookmarks/Clips
|
||||
|
||||
if (!entry.Liberate.IsSeries)
|
||||
{
|
||||
|
||||
var bookRecordMenuItem = new MenuItem { Header = "View _Bookmarks/Clips" };
|
||||
|
||||
args.ContextMenuItems.Add(bookRecordMenuItem);
|
||||
|
||||
bookRecordMenuItem.Click += async (_, _) => await new BookRecordsDialog(entry.LibraryBook).ShowDialog(VisualRoot as Window);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region View All Series
|
||||
|
||||
if (entry.Book.SeriesLink.Any())
|
||||
{
|
||||
var header = entry.Liberate.IsSeries ? "View All Episodes in Series" : "View All Books in Series";
|
||||
var viewSeriesMenuItem = new MenuItem { Header = header };
|
||||
|
||||
args.ContextMenuItems.Add(viewSeriesMenuItem);
|
||||
|
||||
viewSeriesMenuItem.Click += (_, _) => new SeriesViewDialog(entry.LibraryBook).Show();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
76
Source/LibationCli/ConsoleProgressBar.cs
Normal file
76
Source/LibationCli/ConsoleProgressBar.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace LibationCli;
|
||||
|
||||
internal class ConsoleProgressBar
|
||||
{
|
||||
public TextWriter Output { get; }
|
||||
public int MaxWidth { get; }
|
||||
public char ProgressChar { get; }
|
||||
public char NoProgressChar { get; }
|
||||
|
||||
public double? Progress
|
||||
{
|
||||
get => m_Progress;
|
||||
set
|
||||
{
|
||||
m_Progress = value ?? 0;
|
||||
WriteProgress();
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan RemainingTime
|
||||
{
|
||||
get => m_RemainingTime;
|
||||
set
|
||||
{
|
||||
m_RemainingTime = value;
|
||||
WriteProgress();
|
||||
}
|
||||
}
|
||||
|
||||
private double m_Progress;
|
||||
private TimeSpan m_RemainingTime;
|
||||
private int m_LastWriteLength = 0;
|
||||
private const int MAX_ETA_LEN = 10;
|
||||
private readonly int m_NumProgressPieces;
|
||||
|
||||
public ConsoleProgressBar(
|
||||
TextWriter output,
|
||||
int maxWidth = 80,
|
||||
char progressCharr = '#',
|
||||
char noProgressChar = '.')
|
||||
{
|
||||
Output = output;
|
||||
MaxWidth = maxWidth;
|
||||
ProgressChar = progressCharr;
|
||||
NoProgressChar = noProgressChar;
|
||||
m_NumProgressPieces = MaxWidth - MAX_ETA_LEN - 4;
|
||||
}
|
||||
|
||||
private void WriteProgress()
|
||||
{
|
||||
var numCompleted = (int)Math.Round(double.Min(100, m_Progress) * m_NumProgressPieces / 100);
|
||||
var numRemaining = m_NumProgressPieces - numCompleted;
|
||||
var progressBar = $"[{new string(ProgressChar, numCompleted)}{new string(NoProgressChar, numRemaining)}] ";
|
||||
|
||||
progressBar += RemainingTime.TotalMinutes > 1000
|
||||
? "ETA ∞"
|
||||
: $"ETA {(int)RemainingTime.TotalMinutes}:{RemainingTime.Seconds:D2}";
|
||||
|
||||
Output.Write(new string('\b', m_LastWriteLength) + progressBar);
|
||||
if (progressBar.Length < m_LastWriteLength)
|
||||
{
|
||||
var extra = m_LastWriteLength - progressBar.Length;
|
||||
Output.Write(new string(' ', extra) + new string('\b', extra));
|
||||
}
|
||||
m_LastWriteLength = progressBar.Length;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
=> Output.Write(
|
||||
new string('\b', m_LastWriteLength) +
|
||||
new string(' ', m_LastWriteLength) +
|
||||
new string('\b', m_LastWriteLength));
|
||||
}
|
||||
48
Source/LibationCli/HelpVerb.cs
Normal file
48
Source/LibationCli/HelpVerb.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using AppScaffolding;
|
||||
using CommandLine;
|
||||
using CommandLine.Text;
|
||||
|
||||
namespace LibationCli;
|
||||
|
||||
[Verb("help", HelpText = "Display more information on a specific command.")]
|
||||
internal class HelpVerb
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the verb to get help about
|
||||
/// </summary>
|
||||
[Value(0, Default = "")]
|
||||
public string HelpType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a base <see cref="HelpText"/> for <see cref="LibationCli"/>
|
||||
/// </summary>
|
||||
public static HelpText CreateHelpText() => new HelpText
|
||||
{
|
||||
AutoVersion = false,
|
||||
AutoHelp = false,
|
||||
Heading = $"LibationCli v{LibationScaffolding.BuildVersion.ToString(3)}",
|
||||
AdditionalNewLineAfterOption = true,
|
||||
MaximumDisplayWidth = 80
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="HelpType"/>'s <see cref="HelpText"/>
|
||||
/// </summary>
|
||||
public HelpText GetHelpText()
|
||||
{
|
||||
var helpText = CreateHelpText();
|
||||
var result = new Parser().ParseArguments(new string[] { HelpType }, Program.VerbTypes);
|
||||
if (result.TypeInfo.Current == typeof(NullInstance))
|
||||
{
|
||||
//HelpType is not a defined verb so get LibationCli usage
|
||||
helpText.AddVerbs(Program.VerbTypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
helpText.AutoHelp = true;
|
||||
helpText.AddDashesToOption = true;
|
||||
helpText.AddOptions(result);
|
||||
}
|
||||
return helpText;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<PublishReadyToRun>true</PublishReadyToRun>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CommandLine;
|
||||
using System.Threading.Tasks;
|
||||
using CommandLine;
|
||||
|
||||
namespace LibationCli
|
||||
{
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ApplicationServices;
|
||||
using AudibleUtilities;
|
||||
using ApplicationServices;
|
||||
using CommandLine;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationCli
|
||||
{
|
||||
@@ -29,26 +27,38 @@ namespace LibationCli
|
||||
}
|
||||
*/
|
||||
#endregion
|
||||
[Option(shortName: 'x', longName: "xlsx", SetName = "xlsx", Required = true)]
|
||||
[Option(shortName: 'x', longName: "xlsx", HelpText = "Microsoft Excel Spreadsheet", SetName = "xlsx")]
|
||||
public bool xlsx { get; set; }
|
||||
|
||||
[Option(shortName: 'c', longName: "csv", SetName = "csv", Required = true)]
|
||||
[Option(shortName: 'c', longName: "csv", HelpText = "Comma-separated values", SetName = "csv")]
|
||||
public bool csv { get; set; }
|
||||
|
||||
[Option(shortName: 'j', longName: "json", SetName = "json", Required = true)]
|
||||
[Option(shortName: 'j', longName: "json", HelpText = "JavaScript Object Notation", SetName = "json")]
|
||||
public bool json { get; set; }
|
||||
|
||||
protected override Task ProcessAsync()
|
||||
{
|
||||
if (xlsx)
|
||||
LibraryExporter.ToXlsx(FilePath);
|
||||
if (csv)
|
||||
LibraryExporter.ToCsv(FilePath);
|
||||
if (json)
|
||||
LibraryExporter.ToJson(FilePath);
|
||||
|
||||
Console.WriteLine($"Library exported to: {FilePath}");
|
||||
Action<string> exporter
|
||||
= csv ? LibraryExporter.ToCsv
|
||||
: json ? LibraryExporter.ToJson
|
||||
: xlsx ? LibraryExporter.ToXlsx
|
||||
: Path.GetExtension(FilePath)?.ToLower() switch
|
||||
{
|
||||
".xlsx" => LibraryExporter.ToXlsx,
|
||||
".csv" => LibraryExporter.ToCsv,
|
||||
".json" => LibraryExporter.ToJson,
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (exporter is null)
|
||||
{
|
||||
PrintVerbUsage($"Undefined export format for file type \"{Path.GetExtension(FilePath)}\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
exporter(FilePath);
|
||||
Console.WriteLine($"Library exported to: {FilePath}");
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommandLine;
|
||||
using CommandLine;
|
||||
using DataLayer;
|
||||
using FileLiberator;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationCli
|
||||
{
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
using System;
|
||||
using ApplicationServices;
|
||||
using AudibleUtilities;
|
||||
using CommandLine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ApplicationServices;
|
||||
using AudibleUtilities;
|
||||
using CommandLine;
|
||||
|
||||
namespace LibationCli
|
||||
{
|
||||
[Verb("scan", HelpText = "Scan library. Default: scan all accounts. Optional: use 'account' flag to specify a single account.")]
|
||||
public class ScanOptions : OptionsBase
|
||||
{
|
||||
[Value(0, MetaName = "Accounts", HelpText = "Optional: nicknames of accounts to scan.", Required = false)]
|
||||
public IEnumerable<string> AccountNicknames { get; set; }
|
||||
[Value(0, MetaName = "Accounts", HelpText = "Optional: user ID or nicknames of accounts to scan.", Required = false)]
|
||||
public IEnumerable<string> AccountNames { get; set; }
|
||||
|
||||
protected override async Task ProcessAsync()
|
||||
{
|
||||
@@ -42,13 +42,19 @@ namespace LibationCli
|
||||
private Account[] getAccounts()
|
||||
{
|
||||
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
|
||||
var accounts = persister.AccountsSettings.GetAll().ToArray();
|
||||
var allAccounts = persister.AccountsSettings.GetAll().ToArray();
|
||||
|
||||
if (!AccountNicknames.Any())
|
||||
return accounts;
|
||||
if (!AccountNames.Any())
|
||||
return allAccounts;
|
||||
|
||||
var found = accounts.Where(acct => AccountNicknames.Contains(acct.AccountName)).ToArray();
|
||||
var notFound = AccountNicknames.Except(found.Select(f => f.AccountName)).ToArray();
|
||||
var accountNames = AccountNames.Select(n => n.ToLower()).ToArray();
|
||||
|
||||
var found
|
||||
= allAccounts
|
||||
.Where(acct => accountNames.Contains(acct.AccountName.ToLower()) || accountNames.Contains(acct.AccountId.ToLower()))
|
||||
.ToArray();
|
||||
|
||||
var notFound = allAccounts.Except(found).ToArray();
|
||||
|
||||
// no accounts found. do not continue
|
||||
if (!found.Any())
|
||||
|
||||
56
Source/LibationCli/Options/SearchOptions.cs
Normal file
56
Source/LibationCli/Options/SearchOptions.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using ApplicationServices;
|
||||
using CommandLine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationCli.Options;
|
||||
|
||||
[Verb("search", HelpText = "Search for books in your library")]
|
||||
internal class SearchOptions : OptionsBase
|
||||
{
|
||||
[Option('n', Default = 10, HelpText = "Number of search results per page")]
|
||||
public int NumResultsPerPage { get; set; }
|
||||
|
||||
[Value(0, MetaName = "query", Required = true, HelpText = "Lucene search string")]
|
||||
public IEnumerable<string> Query { get; set; }
|
||||
|
||||
protected override Task ProcessAsync()
|
||||
{
|
||||
var query = string.Join(" ", Query).Trim('\"');
|
||||
var results = SearchEngineCommands.Search(query).Docs.ToList();
|
||||
|
||||
Console.WriteLine($"Found {results.Count} matching results.");
|
||||
|
||||
string nextPrompt = "Press any key for the next " + NumResultsPerPage + " results or Esc for all results";
|
||||
bool waitForNextBatch = true;
|
||||
|
||||
for (int i = 0; i < results.Count; i += NumResultsPerPage)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (int j = i; j < int.Min(results.Count, i + NumResultsPerPage); j++)
|
||||
sb.AppendLine(getDocDisplay(results[j].Doc));
|
||||
|
||||
Console.Write(sb.ToString());
|
||||
|
||||
if (waitForNextBatch)
|
||||
{
|
||||
Console.Write(nextPrompt);
|
||||
waitForNextBatch = Console.ReadKey(intercept: true).Key != ConsoleKey.Escape;
|
||||
ReplaceConsoleText(Console.Out, nextPrompt.Length, "");
|
||||
Console.CursorLeft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static string getDocDisplay(Lucene.Net.Documents.Document doc)
|
||||
{
|
||||
var title = doc.GetField("title");
|
||||
var id = doc.GetField("_ID_");
|
||||
return $"[{id.StringValue}] - {title.StringValue}";
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,70 @@
|
||||
using System;
|
||||
using ApplicationServices;
|
||||
using CommandLine;
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ApplicationServices;
|
||||
using AudibleUtilities;
|
||||
using CommandLine;
|
||||
|
||||
namespace LibationCli
|
||||
{
|
||||
[Verb("set-status", HelpText = """
|
||||
Set download statuses throughout library based on whether each book's audio file can be found.
|
||||
Must include at least one flag: --downloaded , --not-downloaded.
|
||||
Downloaded: If the audio file can be found, set download status to 'Downloaded'.
|
||||
Not Downloaded: If the audio file cannot be found, set download status to 'Not Downloaded'
|
||||
[Verb("set-status", HelpText = """
|
||||
Set download statuses throughout library based on whether each book's audio file can be found.
|
||||
""")]
|
||||
public class SetDownloadStatusOptions : OptionsBase
|
||||
{
|
||||
[Option(shortName: 'd', longName: "downloaded", Required = true)]
|
||||
public bool SetDownloaded { get; set; }
|
||||
public class SetDownloadStatusOptions : OptionsBase
|
||||
{
|
||||
//https://github.com/commandlineparser/commandline/wiki/Option-Groups
|
||||
[Option(shortName: 'd', longName: "downloaded", Group = "Download Status", HelpText = "set download status to 'Downloaded'")]
|
||||
public bool SetDownloaded { get; set; }
|
||||
|
||||
[Option(shortName: 'n', longName: "not-downloaded", Required = true)]
|
||||
public bool SetNotDownloaded { get; set; }
|
||||
[Option(shortName: 'n', longName: "not-downloaded", Group = "Download Status", HelpText = "set download status to 'Not Downloaded'")]
|
||||
public bool SetNotDownloaded { get; set; }
|
||||
|
||||
protected override async Task ProcessAsync()
|
||||
{
|
||||
var libraryBooks = DbContexts.GetLibrary_Flat_NoTracking();
|
||||
[Option("force", HelpText = "Set the download status regardless of whether the book's audio file can be found. Only one download status option may be used with this option.")]
|
||||
public bool Force { get; set; }
|
||||
|
||||
var bulkSetStatus = new BulkSetDownloadStatus(libraryBooks, SetDownloaded, SetNotDownloaded);
|
||||
await Task.Run(() => bulkSetStatus.Discover());
|
||||
bulkSetStatus.Execute();
|
||||
[Value(0, MetaName = "[asins]", HelpText = "Optional product IDs of books on which to set download status.")]
|
||||
public IEnumerable<string> Asins { get; set; }
|
||||
|
||||
foreach (var msg in bulkSetStatus.Messages)
|
||||
Console.WriteLine(msg);
|
||||
}
|
||||
}
|
||||
protected override async Task ProcessAsync()
|
||||
{
|
||||
if (Force && SetDownloaded && SetNotDownloaded)
|
||||
{
|
||||
PrintVerbUsage("ERROR:\nWhen run with --force option, only one download status option may be used.");
|
||||
return;
|
||||
}
|
||||
|
||||
var libraryBooks = DbContexts.GetLibrary_Flat_NoTracking();
|
||||
|
||||
if (Asins.Any())
|
||||
{
|
||||
var asins = Asins.Select(a => a.TrimStart('[').TrimEnd(']').ToLower()).ToArray();
|
||||
libraryBooks = libraryBooks.Where(lb => lb.Book.AudibleProductId.ToLower().In(asins)).ToList();
|
||||
|
||||
if (libraryBooks.Count == 0)
|
||||
{
|
||||
Console.Error.WriteLine("Could not find any books matching asins");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (Force)
|
||||
{
|
||||
var status = SetDownloaded ? LiberatedStatus.Liberated : LiberatedStatus.NotLiberated;
|
||||
|
||||
var num = libraryBooks.UpdateBookStatus(status);
|
||||
Console.WriteLine($"Set LiberatedStatus to '{status}' on {"book".PluralizeWithCount(num)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var bulkSetStatus = new BulkSetDownloadStatus(libraryBooks, SetDownloaded, SetNotDownloaded);
|
||||
await Task.Run(() => bulkSetStatus.Discover());
|
||||
bulkSetStatus.Execute();
|
||||
|
||||
foreach (var msg in bulkSetStatus.Messages)
|
||||
Console.WriteLine(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
59
Source/LibationCli/Options/VersionOptions.cs
Normal file
59
Source/LibationCli/Options/VersionOptions.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using AppScaffolding;
|
||||
using CommandLine;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationCli.Options;
|
||||
|
||||
[Verb("version", HelpText = "Display version information.")]
|
||||
internal class VersionOptions : OptionsBase
|
||||
{
|
||||
[Option('c', "check", Required = false, HelpText = "Check if an upgrade is available")]
|
||||
public bool CheckForUpgrade { get; set; }
|
||||
|
||||
protected override Task ProcessAsync()
|
||||
{
|
||||
const string checkingForUpgrade = "Checking for upgrade...";
|
||||
Console.WriteLine($"Libation {LibationScaffolding.Variety} v{LibationScaffolding.BuildVersion.ToString(3)}");
|
||||
|
||||
if (CheckForUpgrade)
|
||||
{
|
||||
Console.Write(checkingForUpgrade);
|
||||
|
||||
var origColor = Console.ForegroundColor;
|
||||
try
|
||||
{
|
||||
var upgradeProperties = LibationScaffolding.GetLatestRelease();
|
||||
|
||||
if (upgradeProperties is null)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
ReplaceConsoleText(Console.Out, checkingForUpgrade.Length, "No available upgrade");
|
||||
Console.WriteLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
ReplaceConsoleText(Console.Out, checkingForUpgrade.Length, $"Upgrade Available: v{upgradeProperties.LatestRelease.ToString(3)}");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(upgradeProperties.ZipUrl);
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Release Notes");
|
||||
Console.WriteLine("=============");
|
||||
Console.WriteLine(upgradeProperties.Notes);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.Error.WriteLine("ERROR CHECKING FOR UPGRADE");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.ForegroundColor = origColor;
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CommandLine;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using CommandLine;
|
||||
|
||||
namespace LibationCli
|
||||
{
|
||||
@@ -17,15 +17,34 @@ namespace LibationCli
|
||||
catch (Exception ex)
|
||||
{
|
||||
Environment.ExitCode = (int)ExitCode.RunTimeError;
|
||||
|
||||
Console.Error.WriteLine("ERROR");
|
||||
Console.Error.WriteLine("=====");
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
Console.Error.WriteLine();
|
||||
Console.Error.WriteLine(ex.StackTrace);
|
||||
PrintVerbUsage(new string[]
|
||||
{
|
||||
"ERROR",
|
||||
"=====",
|
||||
ex.Message,
|
||||
"",
|
||||
ex.StackTrace
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void PrintVerbUsage(params string[] linesBeforeUsage)
|
||||
{
|
||||
var verb = GetType().GetCustomAttribute<VerbAttribute>().Name;
|
||||
var helpText = new HelpVerb { HelpType = verb }.GetHelpText();
|
||||
helpText.AddPreOptionsLines(linesBeforeUsage);
|
||||
helpText.AddPreOptionsLine("");
|
||||
helpText.AddPreOptionsLine($"{verb} Usage:");
|
||||
Console.Error.WriteLine(helpText);
|
||||
}
|
||||
|
||||
protected static void ReplaceConsoleText(TextWriter writer, int previousLength, string newText)
|
||||
{
|
||||
writer.Write(new string('\b', previousLength));
|
||||
writer.Write(newText);
|
||||
writer.Write(new string(' ', int.Max(0, previousLength - newText.Length)));
|
||||
}
|
||||
|
||||
protected abstract Task ProcessAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,34 @@
|
||||
using System;
|
||||
using ApplicationServices;
|
||||
using CommandLine;
|
||||
using DataLayer;
|
||||
using Dinah.Core;
|
||||
using FileLiberator;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ApplicationServices;
|
||||
using CommandLine;
|
||||
using DataLayer;
|
||||
using FileLiberator;
|
||||
|
||||
namespace LibationCli
|
||||
{
|
||||
public abstract class ProcessableOptionsBase : OptionsBase
|
||||
{
|
||||
|
||||
[Value(0, MetaName = "[asins]", HelpText = "Optional product IDs of books to process.")]
|
||||
public IEnumerable<string> Asins { get; set; }
|
||||
|
||||
protected static TProcessable CreateProcessable<TProcessable>(EventHandler<LibraryBook> completedAction = null)
|
||||
where TProcessable : Processable, new()
|
||||
{
|
||||
var progressBar = new ConsoleProgressBar(Console.Out);
|
||||
var strProc = new TProcessable();
|
||||
|
||||
strProc.Begin += (o, e) => Console.WriteLine($"{typeof(TProcessable).Name} Begin: {e}");
|
||||
strProc.Completed += (o, e) => Console.WriteLine($"{typeof(TProcessable).Name} Completed: {e}");
|
||||
|
||||
strProc.Completed += (o, e) =>
|
||||
{
|
||||
progressBar.Clear();
|
||||
Console.WriteLine($"{typeof(TProcessable).Name} Completed: {e}");
|
||||
};
|
||||
|
||||
strProc.Completed += (s, e) =>
|
||||
{
|
||||
@@ -32,13 +43,28 @@ namespace LibationCli
|
||||
}
|
||||
};
|
||||
|
||||
strProc.StreamingTimeRemaining += (_, e) => progressBar.RemainingTime = e;
|
||||
strProc.StreamingProgressChanged += (_, e) => progressBar.Progress = e.ProgressPercentage;
|
||||
|
||||
return strProc;
|
||||
}
|
||||
|
||||
protected static async Task RunAsync(Processable Processable)
|
||||
protected async Task RunAsync(Processable Processable)
|
||||
{
|
||||
foreach (var libraryBook in Processable.GetValidLibraryBooks(DbContexts.GetLibrary_Flat_NoTracking()))
|
||||
await ProcessOneAsync(Processable, libraryBook, false);
|
||||
var libraryBooks = DbContexts.GetLibrary_Flat_NoTracking();
|
||||
|
||||
if (Asins.Any())
|
||||
{
|
||||
var asinsLower = Asins.Select(a => a.TrimStart('[').TrimEnd(']').ToLower()).ToArray();
|
||||
|
||||
foreach (var lb in libraryBooks.Where(lb => lb.Book.AudibleProductId.ToLower().In(asinsLower)))
|
||||
await ProcessOneAsync(Processable, lb, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var lb in Processable.GetValidLibraryBooks(libraryBooks))
|
||||
await ProcessOneAsync(Processable, lb, false);
|
||||
}
|
||||
|
||||
var done = "Done. All books have been processed";
|
||||
Console.WriteLine(done);
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommandLine;
|
||||
using CommandLine;
|
||||
using CommandLine.Text;
|
||||
using Dinah.Core;
|
||||
using Dinah.Core.Collections;
|
||||
using Dinah.Core.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationCli
|
||||
{
|
||||
@@ -19,47 +16,63 @@ namespace LibationCli
|
||||
}
|
||||
class Program
|
||||
{
|
||||
static async Task<int> Main(string[] args)
|
||||
public readonly static Type[] VerbTypes = Setup.LoadVerbs();
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
//***********************************************//
|
||||
// //
|
||||
// do not use Configuration before this line //
|
||||
// //
|
||||
//***********************************************//
|
||||
Setup.Initialize();
|
||||
|
||||
var types = Setup.LoadVerbs();
|
||||
|
||||
#if DEBUG
|
||||
string input = null;
|
||||
string input = "";
|
||||
|
||||
//input = " set-status -n --force B017V4IM1G";
|
||||
//input = " liberate B017V4IM1G";
|
||||
//input = " convert B017V4IM1G";
|
||||
//input = " search \"-liberated\"";
|
||||
//input = " export --help";
|
||||
//input = " version --check";
|
||||
//input = " scan rmcrackan";
|
||||
//input = " help set-status";
|
||||
//input = " liberate ";
|
||||
|
||||
|
||||
// note: this hack will fail for quoted file paths with spaces because it will break on those spaces
|
||||
if (!string.IsNullOrWhiteSpace(input))
|
||||
args = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
var setBreakPointHere = args;
|
||||
#endif
|
||||
|
||||
var result = Parser.Default.ParseArguments(args, types);
|
||||
var result = new Parser(ConfigureParser).ParseArguments(args, VerbTypes);
|
||||
|
||||
// if successfully parsed
|
||||
// async: run parsed options
|
||||
await result.WithParsedAsync<OptionsBase>(opt => opt.Run());
|
||||
if (result.Value is HelpVerb helper)
|
||||
Console.Error.WriteLine(helper.GetHelpText());
|
||||
else if (result.TypeInfo.Current == typeof(HelpVerb))
|
||||
{
|
||||
//Error parsing the command, but the verb type was identified as HelpVerb
|
||||
//Print LibationCli usage
|
||||
var helpText = HelpVerb.CreateHelpText();
|
||||
helpText.AddVerbs(VerbTypes);
|
||||
Console.Error.WriteLine(helpText);
|
||||
}
|
||||
else if (result.Errors.Any())
|
||||
HandleErrors(result);
|
||||
else
|
||||
{
|
||||
//Everything parsed correctly, so execute the command
|
||||
|
||||
// if not successfully parsed
|
||||
// sync: handle parse errors
|
||||
result.WithNotParsed(errors => HandleErrors(result, errors));
|
||||
//***********************************************//
|
||||
// //
|
||||
// do not use Configuration before this line //
|
||||
// //
|
||||
//***********************************************//
|
||||
Setup.Initialize();
|
||||
|
||||
return Environment.ExitCode;
|
||||
// if successfully parsed
|
||||
// async: run parsed options
|
||||
await result.WithParsedAsync<OptionsBase>(opt => opt.Run());
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleErrors(ParserResult<object> result, IEnumerable<Error> errors)
|
||||
private static void HandleErrors(ParserResult<object> result)
|
||||
{
|
||||
var errorsList = errors.ToList();
|
||||
var errorsList = result.Errors.ToList();
|
||||
if (errorsList.Any(e => e.Tag.In(ErrorType.HelpRequestedError, ErrorType.VersionRequestedError, ErrorType.HelpVerbRequestedError)))
|
||||
{
|
||||
Environment.ExitCode = (int)ExitCode.NonRunNonError;
|
||||
@@ -67,17 +80,36 @@ namespace LibationCli
|
||||
}
|
||||
|
||||
Environment.ExitCode = (int)ExitCode.ParseError;
|
||||
var helpText = HelpVerb.CreateHelpText();
|
||||
|
||||
if (errorsList.Any(e => e.Tag.In(ErrorType.NoVerbSelectedError)))
|
||||
if (errorsList.OfType<NoVerbSelectedError>().Any())
|
||||
{
|
||||
Console.Error.WriteLine("No verb selected");
|
||||
return;
|
||||
//Print LibationCli usage
|
||||
helpText.AddPreOptionsLine("No verb selected");
|
||||
helpText.AddVerbs(VerbTypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
//print the specified verb's usage
|
||||
helpText.AddDashesToOption = true;
|
||||
helpText.AutoHelp = true;
|
||||
|
||||
var helpText = HelpText.AutoBuild(result,
|
||||
h => HelpText.DefaultParsingErrorsHandler(result, h),
|
||||
e => e);
|
||||
Console.WriteLine(helpText);
|
||||
if (!errorsList.OfType<UnknownOptionError>().Any(o => o.Token.ToLower() == "help"))
|
||||
{
|
||||
//verb was not executed with the "--help" option,
|
||||
//so print verb option parsing error info.
|
||||
helpText = HelpText.DefaultParsingErrorsHandler(result, helpText);
|
||||
}
|
||||
|
||||
helpText.AddOptions(result);
|
||||
}
|
||||
Console.Error.WriteLine(helpText);
|
||||
}
|
||||
|
||||
private static void ConfigureParser(ParserSettings settings)
|
||||
{
|
||||
settings.AutoVersion = false;
|
||||
settings.AutoHelp = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AppScaffolding;
|
||||
using CommandLine;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using AppScaffolding;
|
||||
using CommandLine;
|
||||
using CommandLine.Text;
|
||||
using Dinah.Core;
|
||||
using Dinah.Core.Collections;
|
||||
using Dinah.Core.Collections.Generic;
|
||||
|
||||
namespace LibationCli
|
||||
{
|
||||
@@ -23,33 +17,15 @@ namespace LibationCli
|
||||
//***********************************************//
|
||||
var config = LibationScaffolding.RunPreConfigMigrations();
|
||||
|
||||
|
||||
LibationScaffolding.RunPostConfigMigrations(config);
|
||||
LibationScaffolding.RunPostMigrationScaffolding(config);
|
||||
|
||||
#if !DEBUG
|
||||
checkForUpdate();
|
||||
#if classic
|
||||
LibationScaffolding.RunPostMigrationScaffolding(Variety.Classic, config);
|
||||
#else
|
||||
LibationScaffolding.RunPostMigrationScaffolding(Variety.Chardonnay, config);
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void checkForUpdate()
|
||||
{
|
||||
var upgradeProperties = LibationScaffolding.GetLatestRelease();
|
||||
if (upgradeProperties is null)
|
||||
return;
|
||||
|
||||
var origColor = Console.ForegroundColor;
|
||||
try
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"UPDATE AVAILABLE @ {upgradeProperties.ZipUrl}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.ForegroundColor = origColor;
|
||||
}
|
||||
}
|
||||
|
||||
public static Type[] LoadVerbs() => Assembly.GetExecutingAssembly()
|
||||
.GetTypes()
|
||||
.Where(t => t.GetCustomAttribute<VerbAttribute>() is not null)
|
||||
|
||||
@@ -126,7 +126,16 @@ namespace LibationFileManager
|
||||
BookDirectoryFiles = new BackgroundFileSystem(BooksDirectory, "*.*", SearchOption.AllDirectories);
|
||||
|
||||
var regex = GetBookSearchRegex(productId);
|
||||
return BookDirectoryFiles.FindFiles(regex);
|
||||
|
||||
//Find all extant files matching the productId
|
||||
//using both the file system and the file path cache
|
||||
return
|
||||
FilePathCache
|
||||
.GetFiles(productId)
|
||||
.Where(c => c.fileType == FileType.Audio && File.Exists(c.path))
|
||||
.Select(c => c.path)
|
||||
.Union(BookDirectoryFiles.FindFiles(regex))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public void Refresh() => BookDirectoryFiles.RefreshFiles();
|
||||
|
||||
36
Source/LibationFileManager/Configuration.HelpText.cs
Normal file
36
Source/LibationFileManager/Configuration.HelpText.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace LibationFileManager
|
||||
{
|
||||
public partial class Configuration
|
||||
{
|
||||
public static ReadOnlyDictionary<string, string> HelpText { get; } = new Dictionary<string, string>
|
||||
{
|
||||
{ nameof(CombineNestedChapterTitles),"""
|
||||
If the book has nested chapters, e.g. a chapter named "Part 1"
|
||||
that contains chapters "Chapter 1" and "Chapter 2", then combine
|
||||
the chapter titles like the following example:
|
||||
|
||||
Part 1: Chapter 1
|
||||
Part 1: Chapter 2
|
||||
"""},
|
||||
{nameof(AllowLibationFixup), """
|
||||
In addition to the options that are enabled if you allow
|
||||
"fixing up" the audiobook, it does the following:
|
||||
|
||||
* Sets the ©gen metadata tag for the genres.
|
||||
* Adds the TCOM (@wrt in M4B files) metadata tag for the narrators.
|
||||
* Unescapes the copyright symbol (replace © with ©)
|
||||
* Replaces the recording copyright (P) string with ℗
|
||||
* Adds various other metadata tags recognized by AudiobookShelf
|
||||
* Sets the embedded cover art image with cover art retrieved from Audible
|
||||
""" },
|
||||
}
|
||||
.AsReadOnly();
|
||||
|
||||
public static string GetHelpText(string settingName)
|
||||
=> HelpText.TryGetValue(settingName, out var value) ? value : null;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ namespace LibationFileManager
|
||||
|
||||
private PersistentDictionary persistentDictionary;
|
||||
|
||||
public bool RemoveProperty(string propertyName) => persistentDictionary.RemoveProperty(propertyName);
|
||||
|
||||
public T GetNonString<T>(T defaultValue, [CallerMemberName] string propertyName = "") => persistentDictionary.GetNonString(propertyName, defaultValue);
|
||||
public object GetObject([CallerMemberName] string propertyName = "") => persistentDictionary.GetObject(propertyName);
|
||||
public string GetString(string defaultValue = null, [CallerMemberName] string propertyName = "") => persistentDictionary.GetString(propertyName, defaultValue);
|
||||
@@ -73,9 +75,18 @@ namespace LibationFileManager
|
||||
|
||||
public bool Exists(string propertyName) => persistentDictionary.Exists(propertyName);
|
||||
|
||||
[Description("Set cover art as the folder's icon. (Windows and macOS only)")]
|
||||
[Description("Set cover art as the folder's icon.")]
|
||||
public bool UseCoverAsFolderIcon { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
[Description("Save audiobook metadata to metadata.json")]
|
||||
public bool SaveMetadataToFile { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
[Description("Book display grid size")]
|
||||
public float GridScaleFactor { get => float.Min(2, float.Max(0.5f, GetNonString(defaultValue: 1f))); set => SetNonString(value); }
|
||||
|
||||
[Description("Book display font size")]
|
||||
public float GridFontScaleFactor { get => float.Min(2, float.Max(0.5f, GetNonString(defaultValue: 1f))); set => SetNonString(value); }
|
||||
|
||||
[Description("Use the beta version of Libation\r\nNew and experimental features, but probably buggy.\r\n(requires restart to take effect)")]
|
||||
public bool BetaOptIn { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
@@ -164,6 +175,9 @@ namespace LibationFileManager
|
||||
[Description("Save cover image alongside audiobook?")]
|
||||
public bool DownloadCoverArt { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
[Description("Combine nested chapter titles")]
|
||||
public bool CombineNestedChapterTitles { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
[Description("Download clips and bookmarks?")]
|
||||
public bool DownloadClipsBookmarks { get => GetNonString(defaultValue: false); set => SetNonString(value); }
|
||||
|
||||
@@ -205,6 +219,16 @@ namespace LibationFileManager
|
||||
Added
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum DownloadQuality
|
||||
{
|
||||
High,
|
||||
Normal
|
||||
}
|
||||
|
||||
[Description("Audio quality to request from Audible:")]
|
||||
public DownloadQuality FileDownloadQuality { get => GetNonString(defaultValue: DownloadQuality.High); set => SetNonString(value); }
|
||||
|
||||
[Description("Set file \"created\" timestamp to:")]
|
||||
public DateTimeSource CreationTime { get => GetNonString(defaultValue: DateTimeSource.File); set => SetNonString(value); }
|
||||
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
using Lucene.Net.Analysis.Tokenattributes;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace LibationSearchEngine
|
||||
{
|
||||
internal static class QuerySanitizer
|
||||
internal static partial class QuerySanitizer
|
||||
{
|
||||
private static readonly HashSet<string> idTerms
|
||||
= SearchEngine.FieldIndexRules.IdFieldNames
|
||||
@@ -23,11 +24,17 @@ namespace LibationSearchEngine
|
||||
.Select(n => n.ToLowerInvariant())
|
||||
.ToHashSet();
|
||||
|
||||
private static readonly Regex tagRegex = TagRegex();
|
||||
|
||||
internal static string Sanitize(string searchString, StandardAnalyzer analyzer)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(searchString))
|
||||
return SearchEngine.ALL_QUERY;
|
||||
|
||||
//Replace a block tags with tags with proper tag query syntax
|
||||
//eg: [foo] -> tags:foo
|
||||
searchString = tagRegex.Replace(searchString, $"{SearchEngine.TAGS}:$1 ");
|
||||
|
||||
// range operator " TO " and bool operators " AND " and " OR " must be uppercase
|
||||
searchString
|
||||
= searchString
|
||||
@@ -76,11 +83,6 @@ namespace LibationSearchEngine
|
||||
addUnalteredToken(offset);
|
||||
previousIsTags = false;
|
||||
}
|
||||
else if (tryParseBlockTag(offset, partList, searchString, out var tagName))
|
||||
{
|
||||
//The term is a block tag. add it to the part list
|
||||
partList.Add($"{SearchEngine.TAGS}:{tagName}");
|
||||
}
|
||||
else if (double.TryParse(term, out var num))
|
||||
{
|
||||
//Term is a number so pad it with zeros
|
||||
@@ -117,35 +119,7 @@ namespace LibationSearchEngine
|
||||
partList.Add(searchString.Substring(offset.StartOffset, offset.EndOffset - offset.StartOffset));
|
||||
}
|
||||
|
||||
private static bool tryParseBlockTag(IOffsetAttribute offset, List<string> partList, string searchString, out string tagName)
|
||||
{
|
||||
tagName = null;
|
||||
if (partList.Count == 0) return false;
|
||||
|
||||
var previous = partList[^1].TrimEnd();
|
||||
|
||||
//cannot be preceeded by an escaping \
|
||||
if (previous.Length == 0) return false;
|
||||
if (previous[^1] != '[' || (previous.Length > 1 && previous[^2] == '\\')) return false;
|
||||
|
||||
var next = searchString.Substring(offset.EndOffset);
|
||||
if (next.Length == 0 || !next.TrimStart().StartsWith(']')) return false;
|
||||
|
||||
tagName = searchString.Substring(offset.StartOffset, offset.EndOffset - offset.StartOffset);
|
||||
|
||||
//Only legal tag characters are letters, numbers and underscores
|
||||
//Per DataLayer.UserDefinedItem.IllegalCharacterRegex()
|
||||
foreach (var c in tagName)
|
||||
{
|
||||
if (!char.IsLetterOrDigit(c) && c != '_')
|
||||
return false;
|
||||
}
|
||||
|
||||
//Remove the leading '['
|
||||
partList[^1] = previous[..^1];
|
||||
//Ignore the trailing ']'
|
||||
offset.SetOffset(offset.StartOffset, searchString.IndexOf(']', offset.EndOffset) + 1);
|
||||
return true;
|
||||
}
|
||||
[GeneratedRegex(@"(?<!\\)\[\u0020*(\w+)\u0020*\]", RegexOptions.Compiled)]
|
||||
private static partial Regex TagRegex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace LibationUiBase.GridView
|
||||
Misc = GetMiscDisplay(libraryBook);
|
||||
LastDownload = new(Book.UserDefinedItem);
|
||||
LongDescription = GetDescriptionDisplay(Book);
|
||||
Description = TrimTextToWord(LongDescription, 62);
|
||||
Description = LongDescription;// TrimTextToWord(LongDescription, 62);
|
||||
SeriesIndex = Book.SeriesLink.FirstOrDefault()?.Index ?? 0;
|
||||
BookTags = GetBookTags();
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
using DataLayer;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibationUiBase.GridView
|
||||
{
|
||||
@@ -29,6 +33,41 @@ namespace LibationUiBase.GridView
|
||||
LoadCover();
|
||||
}
|
||||
|
||||
|
||||
public static async Task<List<IGridEntry>> GetAllProductsAsync(IEnumerable<LibraryBook> libraryBooks)
|
||||
{
|
||||
var products = libraryBooks.Where(lb => lb.Book.IsProduct()).ToArray();
|
||||
|
||||
int parallelism = int.Max(1, Environment.ProcessorCount - 1);
|
||||
|
||||
(int numPer, int rem) = int.DivRem(products.Length, parallelism);
|
||||
if (rem != 0) numPer++;
|
||||
|
||||
var tasks = new Task<IGridEntry[]>[parallelism];
|
||||
var syncContext = SynchronizationContext.Current;
|
||||
|
||||
for (int i = 0; i < parallelism; i++)
|
||||
{
|
||||
int start = i * numPer;
|
||||
tasks[i] = Task.Run(() =>
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(syncContext);
|
||||
|
||||
int length = int.Min(numPer, products.Length - start);
|
||||
if (length < 1) return Array.Empty<IGridEntry>();
|
||||
|
||||
var result = new IGridEntry[length];
|
||||
|
||||
for (int j = 0; j < length; j++)
|
||||
result[j] = new LibraryBookEntry<TStatus>(products[start + j]);
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
return (await Task.WhenAll(tasks)).SelectMany(a => a).ToList();
|
||||
}
|
||||
|
||||
protected override string GetBookTags() => string.Join("\r\n", Book.UserDefinedItem.TagsEnumerated);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using DataLayer;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibationUiBase.GridView
|
||||
{
|
||||
@@ -54,6 +57,60 @@ namespace LibationUiBase.GridView
|
||||
LoadCover();
|
||||
}
|
||||
|
||||
public static async Task<List<ISeriesEntry>> GetAllSeriesEntriesAsync(IEnumerable<LibraryBook> libraryBooks)
|
||||
{
|
||||
var seriesBooks = libraryBooks.Where(lb => lb.Book.IsEpisodeParent()).ToArray();
|
||||
var allEpisodes = libraryBooks.Where(lb => lb.Book.IsEpisodeChild()).ToArray();
|
||||
|
||||
int parallelism = int.Max(1, Environment.ProcessorCount - 1);
|
||||
|
||||
var tasks = new Task[parallelism];
|
||||
var syncContext = SynchronizationContext.Current;
|
||||
|
||||
var q = new BlockingCollection<(int, LibraryBook episode)>();
|
||||
|
||||
var seriesEntries = new ISeriesEntry[seriesBooks.Length];
|
||||
var seriesEpisodes = new ConcurrentBag<ILibraryBookEntry>[seriesBooks.Length];
|
||||
|
||||
for (int i = 0; i < parallelism; i++)
|
||||
{
|
||||
tasks[i] = Task.Run(() =>
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(syncContext);
|
||||
|
||||
while (q.TryTake(out var entry, -1))
|
||||
{
|
||||
var parent = seriesEntries[entry.Item1];
|
||||
var episodeBag = seriesEpisodes[entry.Item1];
|
||||
episodeBag.Add(new LibraryBookEntry<TStatus>(entry.episode, parent));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i <seriesBooks.Length; i++)
|
||||
{
|
||||
var series = seriesBooks[i];
|
||||
seriesEntries[i] = new SeriesEntry<TStatus>(series, Enumerable.Empty<LibraryBook>());
|
||||
seriesEpisodes[i] = new ConcurrentBag<ILibraryBookEntry>();
|
||||
|
||||
foreach (var ep in allEpisodes.FindChildren(series))
|
||||
q.Add((i, ep));
|
||||
}
|
||||
|
||||
q.CompleteAdding();
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
for (int i = 0; i < seriesBooks.Length; i++)
|
||||
{
|
||||
var series = seriesEntries[i];
|
||||
series.Children.AddRange(seriesEpisodes[i].OrderByDescending(c => c.SeriesOrder));
|
||||
series.UpdateLibraryBook(series.LibraryBook);
|
||||
}
|
||||
|
||||
return seriesEntries.Where(s => s.Children.Count != 0).ToList();
|
||||
}
|
||||
|
||||
public void RemoveChild(ILibraryBookEntry lbe)
|
||||
{
|
||||
Children.Remove(lbe);
|
||||
|
||||
73
Source/LibationWinForms/ClearableTextBox.Designer.cs
generated
Normal file
73
Source/LibationWinForms/ClearableTextBox.Designer.cs
generated
Normal file
@@ -0,0 +1,73 @@
|
||||
namespace LibationWinForms
|
||||
{
|
||||
partial class ClearableTextBox
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
textBox1 = new System.Windows.Forms.TextBox();
|
||||
button1 = new System.Windows.Forms.Button();
|
||||
SuspendLayout();
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
textBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
textBox1.Location = new System.Drawing.Point(0, 0);
|
||||
textBox1.Margin = new System.Windows.Forms.Padding(0);
|
||||
textBox1.Name = "textBox1";
|
||||
textBox1.Size = new System.Drawing.Size(625, 23);
|
||||
textBox1.TabIndex = 0;
|
||||
//
|
||||
// button1
|
||||
//
|
||||
button1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
|
||||
button1.Location = new System.Drawing.Point(623, 0);
|
||||
button1.Margin = new System.Windows.Forms.Padding(0);
|
||||
button1.Name = "button1";
|
||||
button1.Size = new System.Drawing.Size(20, 20);
|
||||
button1.TabIndex = 1;
|
||||
button1.Text = "X";
|
||||
button1.UseVisualStyleBackColor = true;
|
||||
button1.Click += button1_Click;
|
||||
//
|
||||
// ClearableTextBox
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
Controls.Add(button1);
|
||||
Controls.Add(textBox1);
|
||||
Name = "ClearableTextBox";
|
||||
Size = new System.Drawing.Size(642, 20);
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox textBox1;
|
||||
private System.Windows.Forms.Button button1;
|
||||
}
|
||||
}
|
||||
44
Source/LibationWinForms/ClearableTextBox.cs
Normal file
44
Source/LibationWinForms/ClearableTextBox.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
public partial class ClearableTextBox : UserControl
|
||||
{
|
||||
public event EventHandler TextCleared;
|
||||
public override string Text { get => textBox1.Text; set => textBox1.Text = value; }
|
||||
public override Font Font
|
||||
{
|
||||
get => textBox1.Font;
|
||||
set
|
||||
{
|
||||
base.Font = textBox1.Font = button1.Font = value;
|
||||
OnSizeChanged(EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public ClearableTextBox()
|
||||
{
|
||||
InitializeComponent();
|
||||
textBox1.KeyDown += (_, e) => OnKeyDown(e);
|
||||
textBox1.KeyUp += (_, e) => OnKeyUp(e);
|
||||
textBox1.KeyPress += (_, e) => OnKeyPress(e);
|
||||
textBox1.TextChanged += (_, e) => OnTextChanged(e);
|
||||
}
|
||||
|
||||
protected override void OnSizeChanged(EventArgs e)
|
||||
{
|
||||
base.OnSizeChanged(e);
|
||||
Height = button1.Width = button1.Height = textBox1.Height;
|
||||
textBox1.Width = Width - button1.Width;
|
||||
button1.Location = new Point(textBox1.Width, 0);
|
||||
}
|
||||
|
||||
private void button1_Click(object sender, System.EventArgs e)
|
||||
{
|
||||
textBox1.Clear();
|
||||
TextCleared?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
120
Source/LibationWinForms/ClearableTextBox.resx
Normal file
120
Source/LibationWinForms/ClearableTextBox.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -286,8 +286,8 @@
|
||||
//
|
||||
// AboutDialog
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
ClientSize = new System.Drawing.Size(434, 491);
|
||||
Controls.Add(groupBox1);
|
||||
Controls.Add(getLibationLbl);
|
||||
|
||||
@@ -143,8 +143,8 @@
|
||||
// AccountsDialog
|
||||
//
|
||||
this.AcceptButton = this.saveBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.CancelButton = this.cancelBtn;
|
||||
this.ClientSize = new System.Drawing.Size(933, 519);
|
||||
this.Controls.Add(this.dataGridView1);
|
||||
|
||||
@@ -202,8 +202,8 @@
|
||||
// BookDetailsDialog
|
||||
//
|
||||
this.AcceptButton = this.saveBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.CancelButton = this.cancelBtn;
|
||||
this.ClientSize = new System.Drawing.Size(594, 466);
|
||||
this.Controls.Add(this.audibleLink);
|
||||
|
||||
@@ -201,8 +201,8 @@
|
||||
//
|
||||
// BookRecordsDialog
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(491, 361);
|
||||
this.Controls.Add(this.reloadAllBtn);
|
||||
this.Controls.Add(this.exportCheckedBtn);
|
||||
|
||||
@@ -29,77 +29,76 @@ namespace LibationWinForms.Dialogs
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.knownDirectoryRb = new System.Windows.Forms.RadioButton();
|
||||
this.customDirectoryRb = new System.Windows.Forms.RadioButton();
|
||||
this.customTb = new System.Windows.Forms.TextBox();
|
||||
this.customBtn = new System.Windows.Forms.Button();
|
||||
this.directorySelectControl = new LibationWinForms.Dialogs.DirectorySelectControl();
|
||||
this.SuspendLayout();
|
||||
knownDirectoryRb = new System.Windows.Forms.RadioButton();
|
||||
customDirectoryRb = new System.Windows.Forms.RadioButton();
|
||||
customTb = new System.Windows.Forms.TextBox();
|
||||
customBtn = new System.Windows.Forms.Button();
|
||||
directorySelectControl = new DirectorySelectControl();
|
||||
SuspendLayout();
|
||||
//
|
||||
// knownDirectoryRb
|
||||
//
|
||||
this.knownDirectoryRb.AutoSize = true;
|
||||
this.knownDirectoryRb.Location = new System.Drawing.Point(3, 3);
|
||||
this.knownDirectoryRb.Name = "knownDirectoryRb";
|
||||
this.knownDirectoryRb.Size = new System.Drawing.Size(14, 13);
|
||||
this.knownDirectoryRb.TabIndex = 0;
|
||||
this.knownDirectoryRb.UseVisualStyleBackColor = true;
|
||||
this.knownDirectoryRb.CheckedChanged += new System.EventHandler(this.radioButton_CheckedChanged);
|
||||
knownDirectoryRb.AutoSize = true;
|
||||
knownDirectoryRb.Location = new System.Drawing.Point(3, 3);
|
||||
knownDirectoryRb.Name = "knownDirectoryRb";
|
||||
knownDirectoryRb.Size = new System.Drawing.Size(14, 13);
|
||||
knownDirectoryRb.TabIndex = 0;
|
||||
knownDirectoryRb.UseVisualStyleBackColor = true;
|
||||
knownDirectoryRb.CheckedChanged += radioButton_CheckedChanged;
|
||||
//
|
||||
// customDirectoryRb
|
||||
//
|
||||
this.customDirectoryRb.AutoSize = true;
|
||||
this.customDirectoryRb.Location = new System.Drawing.Point(2, 62);
|
||||
this.customDirectoryRb.Name = "customDirectoryRb";
|
||||
this.customDirectoryRb.Size = new System.Drawing.Size(14, 13);
|
||||
this.customDirectoryRb.TabIndex = 2;
|
||||
this.customDirectoryRb.UseVisualStyleBackColor = true;
|
||||
this.customDirectoryRb.CheckedChanged += new System.EventHandler(this.radioButton_CheckedChanged);
|
||||
customDirectoryRb.AutoSize = true;
|
||||
customDirectoryRb.Location = new System.Drawing.Point(2, 62);
|
||||
customDirectoryRb.Name = "customDirectoryRb";
|
||||
customDirectoryRb.Size = new System.Drawing.Size(14, 13);
|
||||
customDirectoryRb.TabIndex = 2;
|
||||
customDirectoryRb.UseVisualStyleBackColor = true;
|
||||
customDirectoryRb.CheckedChanged += radioButton_CheckedChanged;
|
||||
//
|
||||
// customTb
|
||||
//
|
||||
this.customTb.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.customTb.Location = new System.Drawing.Point(22, 58);
|
||||
this.customTb.Name = "customTb";
|
||||
this.customTb.Size = new System.Drawing.Size(588, 23);
|
||||
this.customTb.TabIndex = 3;
|
||||
customTb.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
customTb.Location = new System.Drawing.Point(22, 58);
|
||||
customTb.Name = "customTb";
|
||||
customTb.Size = new System.Drawing.Size(588, 23);
|
||||
customTb.TabIndex = 3;
|
||||
//
|
||||
// customBtn
|
||||
//
|
||||
this.customBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.customBtn.Location = new System.Drawing.Point(616, 58);
|
||||
this.customBtn.Name = "customBtn";
|
||||
this.customBtn.Size = new System.Drawing.Size(41, 27);
|
||||
this.customBtn.TabIndex = 4;
|
||||
this.customBtn.Text = "...";
|
||||
this.customBtn.UseVisualStyleBackColor = true;
|
||||
this.customBtn.Click += new System.EventHandler(this.customBtn_Click);
|
||||
customBtn.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||
customBtn.Location = new System.Drawing.Point(616, 58);
|
||||
customBtn.Name = "customBtn";
|
||||
customBtn.Size = new System.Drawing.Size(41, 27);
|
||||
customBtn.TabIndex = 4;
|
||||
customBtn.Text = "...";
|
||||
customBtn.UseVisualStyleBackColor = true;
|
||||
customBtn.Click += customBtn_Click;
|
||||
//
|
||||
// directorySelectControl
|
||||
//
|
||||
this.directorySelectControl.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.directorySelectControl.Location = new System.Drawing.Point(23, 0);
|
||||
this.directorySelectControl.Name = "directorySelectControl";
|
||||
this.directorySelectControl.Size = new System.Drawing.Size(635, 52);
|
||||
this.directorySelectControl.TabIndex = 5;
|
||||
directorySelectControl.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
directorySelectControl.AutoSize = true;
|
||||
directorySelectControl.Location = new System.Drawing.Point(23, 0);
|
||||
directorySelectControl.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6);
|
||||
directorySelectControl.Name = "directorySelectControl";
|
||||
directorySelectControl.Size = new System.Drawing.Size(635, 55);
|
||||
directorySelectControl.TabIndex = 5;
|
||||
//
|
||||
// DirectoryOrCustomSelectControl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.directorySelectControl);
|
||||
this.Controls.Add(this.customBtn);
|
||||
this.Controls.Add(this.customTb);
|
||||
this.Controls.Add(this.customDirectoryRb);
|
||||
this.Controls.Add(this.knownDirectoryRb);
|
||||
this.Name = "DirectoryOrCustomSelectControl";
|
||||
this.Size = new System.Drawing.Size(660, 87);
|
||||
this.Load += new System.EventHandler(this.DirectoryOrCustomSelectControl_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
Controls.Add(directorySelectControl);
|
||||
Controls.Add(customBtn);
|
||||
Controls.Add(customTb);
|
||||
Controls.Add(customDirectoryRb);
|
||||
Controls.Add(knownDirectoryRb);
|
||||
Name = "DirectoryOrCustomSelectControl";
|
||||
Size = new System.Drawing.Size(660, 88);
|
||||
Load += DirectoryOrCustomSelectControl_Load;
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -37,6 +37,12 @@ namespace LibationWinForms.Dialogs
|
||||
if (directory != Configuration.KnownDirectories.None)
|
||||
selectDir(directory, null);
|
||||
}
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
//For some reason anchors don't work when the parent form scales up, even with AutoScale
|
||||
directorySelectControl.Width = customTb.Width = Width;
|
||||
}
|
||||
|
||||
/// <summary>set selection</summary>
|
||||
public void SelectDirectory(string directory)
|
||||
|
||||
@@ -1,5 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
@@ -29,44 +29,42 @@ namespace LibationWinForms.Dialogs
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.directoryComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.textBox1 = new System.Windows.Forms.TextBox();
|
||||
this.SuspendLayout();
|
||||
directoryComboBox = new System.Windows.Forms.ComboBox();
|
||||
textBox1 = new System.Windows.Forms.TextBox();
|
||||
SuspendLayout();
|
||||
//
|
||||
// directoryComboBox
|
||||
//
|
||||
this.directoryComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.directoryComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.directoryComboBox.FormattingEnabled = true;
|
||||
this.directoryComboBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.directoryComboBox.Name = "directoryComboBox";
|
||||
this.directoryComboBox.Size = new System.Drawing.Size(407, 23);
|
||||
this.directoryComboBox.TabIndex = 0;
|
||||
this.directoryComboBox.SelectedIndexChanged += new System.EventHandler(this.directoryComboBox_SelectedIndexChanged);
|
||||
directoryComboBox.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
directoryComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
directoryComboBox.FormattingEnabled = true;
|
||||
directoryComboBox.Location = new System.Drawing.Point(0, 0);
|
||||
directoryComboBox.Name = "directoryComboBox";
|
||||
directoryComboBox.Size = new System.Drawing.Size(814, 23);
|
||||
directoryComboBox.TabIndex = 0;
|
||||
directoryComboBox.SelectedIndexChanged += directoryComboBox_SelectedIndexChanged;
|
||||
//
|
||||
// textBox1
|
||||
//
|
||||
this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.textBox1.Location = new System.Drawing.Point(0, 29);
|
||||
this.textBox1.Name = "textBox1";
|
||||
this.textBox1.ReadOnly = true;
|
||||
this.textBox1.Size = new System.Drawing.Size(407, 23);
|
||||
this.textBox1.TabIndex = 1;
|
||||
textBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
textBox1.Location = new System.Drawing.Point(0, 29);
|
||||
textBox1.Name = "textBox1";
|
||||
textBox1.ReadOnly = true;
|
||||
textBox1.Size = new System.Drawing.Size(814, 23);
|
||||
textBox1.TabIndex = 1;
|
||||
//
|
||||
// DirectorySelectControl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.textBox1);
|
||||
this.Controls.Add(this.directoryComboBox);
|
||||
this.Name = "DirectorySelectControl";
|
||||
this.Size = new System.Drawing.Size(407, 52);
|
||||
this.Load += new System.EventHandler(this.DirectorySelectControl_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
AutoSize = true;
|
||||
Controls.Add(textBox1);
|
||||
Controls.Add(directoryComboBox);
|
||||
Name = "DirectorySelectControl";
|
||||
Size = new System.Drawing.Size(814, 55);
|
||||
Load += DirectorySelectControl_Load;
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -50,6 +50,12 @@ namespace LibationWinForms.Dialogs
|
||||
|
||||
return path;
|
||||
}
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
//For some reason anchors don't work when the parent form scales up, even with AutoScale
|
||||
directoryComboBox.Width = textBox1.Width = Width;
|
||||
}
|
||||
|
||||
private DirectoryComboBoxItem selectedItem => (DirectoryComboBoxItem)this.directoryComboBox.SelectedItem;
|
||||
|
||||
|
||||
@@ -1,4 +1,64 @@
|
||||
<root>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
@@ -126,8 +126,8 @@
|
||||
// EditQuickFilters
|
||||
//
|
||||
this.AcceptButton = this.saveBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.CancelButton = this.cancelBtn;
|
||||
this.ClientSize = new System.Drawing.Size(800, 450);
|
||||
this.Controls.Add(this.dataGridView1);
|
||||
|
||||
@@ -144,8 +144,8 @@
|
||||
//
|
||||
// EditReplacementChars
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(522, 467);
|
||||
this.Controls.Add(this.minDefaultBtn);
|
||||
this.Controls.Add(this.loFiDefaultsBtn);
|
||||
|
||||
@@ -160,8 +160,8 @@
|
||||
// EditTemplateDialog
|
||||
//
|
||||
this.AcceptButton = this.saveBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.CancelButton = this.cancelBtn;
|
||||
this.ClientSize = new System.Drawing.Size(933, 388);
|
||||
this.Controls.Add(this.exampleLbl);
|
||||
|
||||
@@ -28,74 +28,74 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.libationFilesDescLbl = new System.Windows.Forms.Label();
|
||||
this.cancelBtn = new System.Windows.Forms.Button();
|
||||
this.saveBtn = new System.Windows.Forms.Button();
|
||||
this.libationFilesSelectControl = new LibationWinForms.Dialogs.DirectoryOrCustomSelectControl();
|
||||
this.SuspendLayout();
|
||||
libationFilesDescLbl = new System.Windows.Forms.Label();
|
||||
cancelBtn = new System.Windows.Forms.Button();
|
||||
saveBtn = new System.Windows.Forms.Button();
|
||||
libationFilesSelectControl = new DirectoryOrCustomSelectControl();
|
||||
SuspendLayout();
|
||||
//
|
||||
// libationFilesDescLbl
|
||||
//
|
||||
this.libationFilesDescLbl.AutoSize = true;
|
||||
this.libationFilesDescLbl.Location = new System.Drawing.Point(14, 10);
|
||||
this.libationFilesDescLbl.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.libationFilesDescLbl.Name = "libationFilesDescLbl";
|
||||
this.libationFilesDescLbl.Size = new System.Drawing.Size(39, 15);
|
||||
this.libationFilesDescLbl.TabIndex = 0;
|
||||
this.libationFilesDescLbl.Text = "[desc]";
|
||||
libationFilesDescLbl.AutoSize = true;
|
||||
libationFilesDescLbl.Location = new System.Drawing.Point(14, 10);
|
||||
libationFilesDescLbl.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
libationFilesDescLbl.Name = "libationFilesDescLbl";
|
||||
libationFilesDescLbl.Size = new System.Drawing.Size(39, 15);
|
||||
libationFilesDescLbl.TabIndex = 0;
|
||||
libationFilesDescLbl.Text = "[desc]";
|
||||
//
|
||||
// cancelBtn
|
||||
//
|
||||
this.cancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelBtn.Location = new System.Drawing.Point(832, 118);
|
||||
this.cancelBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.cancelBtn.Name = "cancelBtn";
|
||||
this.cancelBtn.Size = new System.Drawing.Size(88, 27);
|
||||
this.cancelBtn.TabIndex = 3;
|
||||
this.cancelBtn.Text = "Cancel";
|
||||
this.cancelBtn.UseVisualStyleBackColor = true;
|
||||
this.cancelBtn.Click += new System.EventHandler(this.cancelBtn_Click);
|
||||
cancelBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
|
||||
cancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
cancelBtn.Location = new System.Drawing.Point(832, 118);
|
||||
cancelBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
cancelBtn.Name = "cancelBtn";
|
||||
cancelBtn.Size = new System.Drawing.Size(88, 27);
|
||||
cancelBtn.TabIndex = 3;
|
||||
cancelBtn.Text = "Cancel";
|
||||
cancelBtn.UseVisualStyleBackColor = true;
|
||||
cancelBtn.Click += cancelBtn_Click;
|
||||
//
|
||||
// saveBtn
|
||||
//
|
||||
this.saveBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.saveBtn.Location = new System.Drawing.Point(714, 118);
|
||||
this.saveBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.saveBtn.Name = "saveBtn";
|
||||
this.saveBtn.Size = new System.Drawing.Size(88, 27);
|
||||
this.saveBtn.TabIndex = 2;
|
||||
this.saveBtn.Text = "Save";
|
||||
this.saveBtn.UseVisualStyleBackColor = true;
|
||||
this.saveBtn.Click += new System.EventHandler(this.saveBtn_Click);
|
||||
saveBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
|
||||
saveBtn.Location = new System.Drawing.Point(714, 118);
|
||||
saveBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
saveBtn.Name = "saveBtn";
|
||||
saveBtn.Size = new System.Drawing.Size(88, 27);
|
||||
saveBtn.TabIndex = 2;
|
||||
saveBtn.Text = "Save";
|
||||
saveBtn.UseVisualStyleBackColor = true;
|
||||
saveBtn.Click += saveBtn_Click;
|
||||
//
|
||||
// libationFilesSelectControl
|
||||
//
|
||||
this.libationFilesSelectControl.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.libationFilesSelectControl.Location = new System.Drawing.Point(14, 28);
|
||||
this.libationFilesSelectControl.Name = "libationFilesSelectControl";
|
||||
this.libationFilesSelectControl.Size = new System.Drawing.Size(909, 87);
|
||||
this.libationFilesSelectControl.TabIndex = 1;
|
||||
libationFilesSelectControl.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
libationFilesSelectControl.Location = new System.Drawing.Point(14, 28);
|
||||
libationFilesSelectControl.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6);
|
||||
libationFilesSelectControl.Name = "libationFilesSelectControl";
|
||||
libationFilesSelectControl.Size = new System.Drawing.Size(906, 88);
|
||||
libationFilesSelectControl.TabIndex = 1;
|
||||
//
|
||||
// LibationFilesDialog
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(933, 164);
|
||||
this.Controls.Add(this.libationFilesSelectControl);
|
||||
this.Controls.Add(this.cancelBtn);
|
||||
this.Controls.Add(this.saveBtn);
|
||||
this.Controls.Add(this.libationFilesDescLbl);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.Name = "LibationFilesDialog";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Libation Files location";
|
||||
this.Load += new System.EventHandler(this.LibationFilesDialog_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
AutoSize = true;
|
||||
ClientSize = new System.Drawing.Size(933, 164);
|
||||
Controls.Add(libationFilesSelectControl);
|
||||
Controls.Add(cancelBtn);
|
||||
Controls.Add(saveBtn);
|
||||
Controls.Add(libationFilesDescLbl);
|
||||
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
Name = "LibationFilesDialog";
|
||||
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
Text = "Libation Files location";
|
||||
Load += LibationFilesDialog_Load;
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,5 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
@@ -78,8 +78,8 @@
|
||||
// LiberatedStatusBatchAutoDialog
|
||||
//
|
||||
this.AcceptButton = this.okBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.CancelButton = this.cancelBtn;
|
||||
this.ClientSize = new System.Drawing.Size(564, 118);
|
||||
this.Controls.Add(this.cancelBtn);
|
||||
|
||||
@@ -88,8 +88,8 @@
|
||||
// LiberatedStatusBatchManualDialog
|
||||
//
|
||||
this.AcceptButton = this.saveBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.CancelButton = this.cancelBtn;
|
||||
this.ClientSize = new System.Drawing.Size(564, 118);
|
||||
this.Controls.Add(this.cancelBtn);
|
||||
|
||||
@@ -82,8 +82,8 @@
|
||||
//
|
||||
// LocateAudiobooksDialog
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(345, 306);
|
||||
this.Controls.Add(this.booksFoundLbl);
|
||||
this.Controls.Add(this.foundAudiobooksLV);
|
||||
|
||||
@@ -58,8 +58,8 @@
|
||||
// ApprovalNeededDialog
|
||||
//
|
||||
this.AcceptButton = this.approvedBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(345, 115);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.approvedBtn);
|
||||
|
||||
@@ -97,8 +97,8 @@
|
||||
// CaptchaDialog
|
||||
//
|
||||
AcceptButton = submitBtn;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
ClientSize = new System.Drawing.Size(261, 210);
|
||||
Controls.Add(passwordTb);
|
||||
Controls.Add(label1);
|
||||
|
||||
@@ -89,8 +89,8 @@
|
||||
// LoginCallbackDialog
|
||||
//
|
||||
this.AcceptButton = this.submitBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(330, 114);
|
||||
this.Controls.Add(this.usernameLbl);
|
||||
this.Controls.Add(this.localeLbl);
|
||||
|
||||
@@ -121,8 +121,8 @@
|
||||
// LoginChoiceEagerDialog
|
||||
//
|
||||
AcceptButton = submitBtn;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
ClientSize = new System.Drawing.Size(394, 216);
|
||||
Controls.Add(externalLoginLbl2);
|
||||
Controls.Add(externalLoginLbl1);
|
||||
|
||||
@@ -151,8 +151,8 @@
|
||||
// LoginExternalDialog
|
||||
//
|
||||
this.AcceptButton = this.submitBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(766, 498);
|
||||
this.Controls.Add(this.tldrLbl);
|
||||
this.Controls.Add(this.responseUrlTb);
|
||||
|
||||
@@ -84,8 +84,8 @@ namespace LibationWinForms.Dialogs.Login
|
||||
// MfaDialog
|
||||
//
|
||||
this.AcceptButton = this.submitBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(398, 129);
|
||||
this.Controls.Add(this.radioButton3);
|
||||
this.Controls.Add(this.radioButton2);
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
//
|
||||
// WebLoginDialog
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
ClientSize = new System.Drawing.Size(484, 761);
|
||||
Name = "WebLoginDialog";
|
||||
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
|
||||
@@ -76,8 +76,8 @@
|
||||
// _2faCodeDialog
|
||||
//
|
||||
AcceptButton = submitBtn;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
ClientSize = new System.Drawing.Size(222, 147);
|
||||
Controls.Add(promptLbl);
|
||||
Controls.Add(label1);
|
||||
|
||||
@@ -118,8 +118,8 @@ namespace LibationWinForms.Dialogs
|
||||
// MessageBoxAlertAdminDialog
|
||||
//
|
||||
this.AcceptButton = this.okBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(584, 382);
|
||||
this.Controls.Add(this.exceptionTb);
|
||||
this.Controls.Add(this.logsLink);
|
||||
|
||||
@@ -93,8 +93,8 @@
|
||||
// ScanAccountsDialog
|
||||
//
|
||||
this.AcceptButton = this.importBtn;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.CancelButton = this.cancelBtn;
|
||||
this.ClientSize = new System.Drawing.Size(584, 160);
|
||||
this.Controls.Add(this.editBtn);
|
||||
|
||||
@@ -103,8 +103,8 @@
|
||||
// SearchSyntaxDialog
|
||||
//
|
||||
AcceptButton = closeBtn;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
CancelButton = closeBtn;
|
||||
ClientSize = new System.Drawing.Size(1140, 577);
|
||||
Controls.Add(closeBtn);
|
||||
|
||||
@@ -9,16 +9,28 @@ namespace LibationWinForms.Dialogs
|
||||
{
|
||||
private void Load_AudioSettings(Configuration config)
|
||||
{
|
||||
this.fileDownloadQualityLbl.Text = desc(nameof(config.FileDownloadQuality));
|
||||
this.allowLibationFixupCbox.Text = desc(nameof(config.AllowLibationFixup));
|
||||
this.createCueSheetCbox.Text = desc(nameof(config.CreateCueSheet));
|
||||
this.downloadCoverArtCbox.Text = desc(nameof(config.DownloadCoverArt));
|
||||
this.retainAaxFileCbox.Text = desc(nameof(config.RetainAaxFile));
|
||||
this.combineNestedChapterTitlesCbox.Text = desc(nameof(config.CombineNestedChapterTitles));
|
||||
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));
|
||||
this.moveMoovAtomCbox.Text = desc(nameof(config.MoveMoovToBeginning));
|
||||
|
||||
toolTip.SetToolTip(combineNestedChapterTitlesCbox, Configuration.GetHelpText(nameof(config.CombineNestedChapterTitles)));
|
||||
toolTip.SetToolTip(allowLibationFixupCbox, Configuration.GetHelpText(nameof(config.AllowLibationFixup)));
|
||||
|
||||
fileDownloadQualityCb.Items.AddRange(
|
||||
new object[]
|
||||
{
|
||||
Configuration.DownloadQuality.Normal,
|
||||
Configuration.DownloadQuality.High
|
||||
});
|
||||
|
||||
clipsBookmarksFormatCb.Items.AddRange(
|
||||
new object[]
|
||||
{
|
||||
@@ -44,8 +56,10 @@ namespace LibationWinForms.Dialogs
|
||||
createCueSheetCbox.Checked = config.CreateCueSheet;
|
||||
downloadCoverArtCbox.Checked = config.DownloadCoverArt;
|
||||
downloadClipsBookmarksCbox.Checked = config.DownloadClipsBookmarks;
|
||||
fileDownloadQualityCb.SelectedItem = config.FileDownloadQuality;
|
||||
clipsBookmarksFormatCb.SelectedItem = config.ClipsBookmarksFileFormat;
|
||||
retainAaxFileCbox.Checked = config.RetainAaxFile;
|
||||
combineNestedChapterTitlesCbox.Checked = config.CombineNestedChapterTitles;
|
||||
splitFilesByChapterCbox.Checked = config.SplitFilesByChapter;
|
||||
mergeOpeningEndCreditsCbox.Checked = config.MergeOpeningAndEndCredits;
|
||||
stripUnabridgedCbox.Checked = config.StripUnabridged;
|
||||
@@ -87,8 +101,10 @@ namespace LibationWinForms.Dialogs
|
||||
config.CreateCueSheet = createCueSheetCbox.Checked;
|
||||
config.DownloadCoverArt = downloadCoverArtCbox.Checked;
|
||||
config.DownloadClipsBookmarks = downloadClipsBookmarksCbox.Checked;
|
||||
config.FileDownloadQuality = (Configuration.DownloadQuality)fileDownloadQualityCb.SelectedItem;
|
||||
config.ClipsBookmarksFileFormat = (Configuration.ClipBookmarkFormat)clipsBookmarksFormatCb.SelectedItem;
|
||||
config.RetainAaxFile = retainAaxFileCbox.Checked;
|
||||
config.CombineNestedChapterTitles = combineNestedChapterTitlesCbox.Checked;
|
||||
config.SplitFilesByChapter = splitFilesByChapterCbox.Checked;
|
||||
config.MergeOpeningAndEndCredits = mergeOpeningEndCreditsCbox.Checked;
|
||||
config.StripUnabridged = stripUnabridgedCbox.Checked;
|
||||
@@ -98,7 +114,6 @@ namespace LibationWinForms.Dialogs
|
||||
config.LameTargetBitrate = lameTargetBitrateRb.Checked;
|
||||
config.MaxSampleRate = ((EnumDiaplay<AAXClean.SampleRate>)maxSampleRateCb.SelectedItem).Value;
|
||||
config.LameEncoderQuality = (NAudio.Lame.EncoderQuality)encoderQualityCb.SelectedItem;
|
||||
encoderQualityCb.SelectedItem = config.LameEncoderQuality;
|
||||
config.LameDownsampleMono = lameDownsampleMonoCbox.Checked;
|
||||
config.LameBitrate = lameBitrateTb.Value;
|
||||
config.LameConstantBitrate = lameConstantBitrateCbox.Checked;
|
||||
|
||||
@@ -51,7 +51,12 @@
|
||||
loggingLevelCb = new System.Windows.Forms.ComboBox();
|
||||
tabControl = new System.Windows.Forms.TabControl();
|
||||
tab1ImportantSettings = new System.Windows.Forms.TabPage();
|
||||
betaOptInCbox = new System.Windows.Forms.CheckBox();
|
||||
groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
applyDisplaySettingsBtn = new System.Windows.Forms.Button();
|
||||
gridScaleFactorLbl = new System.Windows.Forms.Label();
|
||||
gridScaleFactorTbar = new System.Windows.Forms.TrackBar();
|
||||
gridFontScaleFactorLbl = new System.Windows.Forms.Label();
|
||||
gridFontScaleFactorTbar = new System.Windows.Forms.TrackBar();
|
||||
booksGb = new System.Windows.Forms.GroupBox();
|
||||
lastWriteTimeCb = new System.Windows.Forms.ComboBox();
|
||||
creationTimeCb = new System.Windows.Forms.ComboBox();
|
||||
@@ -64,6 +69,7 @@
|
||||
autoScanCb = new System.Windows.Forms.CheckBox();
|
||||
showImportedStatsCb = new System.Windows.Forms.CheckBox();
|
||||
tab3DownloadDecrypt = new System.Windows.Forms.TabPage();
|
||||
saveMetadataToFileCbox = new System.Windows.Forms.CheckBox();
|
||||
useCoverAsFolderIconCb = new System.Windows.Forms.CheckBox();
|
||||
inProgressFilesGb = new System.Windows.Forms.GroupBox();
|
||||
customFileNamingGb = new System.Windows.Forms.GroupBox();
|
||||
@@ -78,6 +84,9 @@
|
||||
folderTemplateTb = new System.Windows.Forms.TextBox();
|
||||
folderTemplateLbl = new System.Windows.Forms.Label();
|
||||
tab4AudioFileOptions = new System.Windows.Forms.TabPage();
|
||||
fileDownloadQualityCb = new System.Windows.Forms.ComboBox();
|
||||
fileDownloadQualityLbl = new System.Windows.Forms.Label();
|
||||
combineNestedChapterTitlesCbox = new System.Windows.Forms.CheckBox();
|
||||
clipsBookmarksFormatCb = new System.Windows.Forms.ComboBox();
|
||||
downloadClipsBookmarksCbox = new System.Windows.Forms.CheckBox();
|
||||
audiobookFixupsGb = new System.Windows.Forms.GroupBox();
|
||||
@@ -127,6 +136,9 @@
|
||||
badBookGb.SuspendLayout();
|
||||
tabControl.SuspendLayout();
|
||||
tab1ImportantSettings.SuspendLayout();
|
||||
groupBox1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)gridScaleFactorTbar).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)gridFontScaleFactorTbar).BeginInit();
|
||||
booksGb.SuspendLayout();
|
||||
tab2ImportLibrary.SuspendLayout();
|
||||
tab3DownloadDecrypt.SuspendLayout();
|
||||
@@ -166,7 +178,7 @@
|
||||
// saveBtn
|
||||
//
|
||||
saveBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
|
||||
saveBtn.Location = new System.Drawing.Point(667, 491);
|
||||
saveBtn.Location = new System.Drawing.Point(668, 499);
|
||||
saveBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
saveBtn.Name = "saveBtn";
|
||||
saveBtn.Size = new System.Drawing.Size(88, 27);
|
||||
@@ -179,7 +191,7 @@
|
||||
//
|
||||
cancelBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
|
||||
cancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
cancelBtn.Location = new System.Drawing.Point(785, 491);
|
||||
cancelBtn.Location = new System.Drawing.Point(786, 499);
|
||||
cancelBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
cancelBtn.Name = "cancelBtn";
|
||||
cancelBtn.Size = new System.Drawing.Size(88, 27);
|
||||
@@ -217,7 +229,7 @@
|
||||
badBookGb.Controls.Add(badBookAskRb);
|
||||
badBookGb.Location = new System.Drawing.Point(7, 6);
|
||||
badBookGb.Name = "badBookGb";
|
||||
badBookGb.Size = new System.Drawing.Size(834, 76);
|
||||
badBookGb.Size = new System.Drawing.Size(836, 76);
|
||||
badBookGb.TabIndex = 13;
|
||||
badBookGb.TabStop = false;
|
||||
badBookGb.Text = "[bad book desc]";
|
||||
@@ -292,7 +304,7 @@
|
||||
allowLibationFixupCbox.AutoSize = true;
|
||||
allowLibationFixupCbox.Checked = true;
|
||||
allowLibationFixupCbox.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
allowLibationFixupCbox.Location = new System.Drawing.Point(19, 143);
|
||||
allowLibationFixupCbox.Location = new System.Drawing.Point(19, 181);
|
||||
allowLibationFixupCbox.Name = "allowLibationFixupCbox";
|
||||
allowLibationFixupCbox.Size = new System.Drawing.Size(163, 19);
|
||||
allowLibationFixupCbox.TabIndex = 10;
|
||||
@@ -303,7 +315,7 @@
|
||||
// convertLossyRb
|
||||
//
|
||||
convertLossyRb.AutoSize = true;
|
||||
convertLossyRb.Location = new System.Drawing.Point(13, 158);
|
||||
convertLossyRb.Location = new System.Drawing.Point(13, 159);
|
||||
convertLossyRb.Name = "convertLossyRb";
|
||||
convertLossyRb.Size = new System.Drawing.Size(329, 19);
|
||||
convertLossyRb.TabIndex = 12;
|
||||
@@ -315,7 +327,7 @@
|
||||
//
|
||||
convertLosslessRb.AutoSize = true;
|
||||
convertLosslessRb.Checked = true;
|
||||
convertLosslessRb.Location = new System.Drawing.Point(13, 111);
|
||||
convertLosslessRb.Location = new System.Drawing.Point(13, 112);
|
||||
convertLosslessRb.Name = "convertLosslessRb";
|
||||
convertLosslessRb.Size = new System.Drawing.Size(335, 19);
|
||||
convertLosslessRb.TabIndex = 11;
|
||||
@@ -327,15 +339,16 @@
|
||||
// inProgressSelectControl
|
||||
//
|
||||
inProgressSelectControl.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
inProgressSelectControl.AutoSize = true;
|
||||
inProgressSelectControl.Location = new System.Drawing.Point(7, 68);
|
||||
inProgressSelectControl.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
inProgressSelectControl.Name = "inProgressSelectControl";
|
||||
inProgressSelectControl.Size = new System.Drawing.Size(828, 52);
|
||||
inProgressSelectControl.Size = new System.Drawing.Size(830, 55);
|
||||
inProgressSelectControl.TabIndex = 19;
|
||||
//
|
||||
// logsBtn
|
||||
//
|
||||
logsBtn.Location = new System.Drawing.Point(256, 261);
|
||||
logsBtn.Location = new System.Drawing.Point(256, 424);
|
||||
logsBtn.Name = "logsBtn";
|
||||
logsBtn.Size = new System.Drawing.Size(132, 23);
|
||||
logsBtn.TabIndex = 5;
|
||||
@@ -346,16 +359,17 @@
|
||||
// booksSelectControl
|
||||
//
|
||||
booksSelectControl.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
booksSelectControl.Location = new System.Drawing.Point(7, 37);
|
||||
booksSelectControl.AutoSize = true;
|
||||
booksSelectControl.Location = new System.Drawing.Point(7, 23);
|
||||
booksSelectControl.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
booksSelectControl.Name = "booksSelectControl";
|
||||
booksSelectControl.Size = new System.Drawing.Size(829, 87);
|
||||
booksSelectControl.Size = new System.Drawing.Size(830, 102);
|
||||
booksSelectControl.TabIndex = 2;
|
||||
//
|
||||
// loggingLevelLbl
|
||||
//
|
||||
loggingLevelLbl.AutoSize = true;
|
||||
loggingLevelLbl.Location = new System.Drawing.Point(6, 264);
|
||||
loggingLevelLbl.Location = new System.Drawing.Point(6, 427);
|
||||
loggingLevelLbl.Name = "loggingLevelLbl";
|
||||
loggingLevelLbl.Size = new System.Drawing.Size(78, 15);
|
||||
loggingLevelLbl.TabIndex = 3;
|
||||
@@ -365,7 +379,7 @@
|
||||
//
|
||||
loggingLevelCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
loggingLevelCb.FormattingEnabled = true;
|
||||
loggingLevelCb.Location = new System.Drawing.Point(90, 261);
|
||||
loggingLevelCb.Location = new System.Drawing.Point(90, 424);
|
||||
loggingLevelCb.Name = "loggingLevelCb";
|
||||
loggingLevelCb.Size = new System.Drawing.Size(129, 23);
|
||||
loggingLevelCb.TabIndex = 4;
|
||||
@@ -380,12 +394,12 @@
|
||||
tabControl.Location = new System.Drawing.Point(12, 12);
|
||||
tabControl.Name = "tabControl";
|
||||
tabControl.SelectedIndex = 0;
|
||||
tabControl.Size = new System.Drawing.Size(862, 473);
|
||||
tabControl.Size = new System.Drawing.Size(864, 481);
|
||||
tabControl.TabIndex = 100;
|
||||
//
|
||||
// tab1ImportantSettings
|
||||
//
|
||||
tab1ImportantSettings.Controls.Add(betaOptInCbox);
|
||||
tab1ImportantSettings.Controls.Add(groupBox1);
|
||||
tab1ImportantSettings.Controls.Add(booksGb);
|
||||
tab1ImportantSettings.Controls.Add(logsBtn);
|
||||
tab1ImportantSettings.Controls.Add(loggingLevelCb);
|
||||
@@ -393,22 +407,76 @@
|
||||
tab1ImportantSettings.Location = new System.Drawing.Point(4, 24);
|
||||
tab1ImportantSettings.Name = "tab1ImportantSettings";
|
||||
tab1ImportantSettings.Padding = new System.Windows.Forms.Padding(3);
|
||||
tab1ImportantSettings.Size = new System.Drawing.Size(854, 445);
|
||||
tab1ImportantSettings.Size = new System.Drawing.Size(856, 453);
|
||||
tab1ImportantSettings.TabIndex = 0;
|
||||
tab1ImportantSettings.Text = "Important settings";
|
||||
tab1ImportantSettings.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// betaOptInCbox
|
||||
// groupBox1
|
||||
//
|
||||
betaOptInCbox.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
|
||||
betaOptInCbox.AutoSize = true;
|
||||
betaOptInCbox.Enabled = false;
|
||||
betaOptInCbox.Location = new System.Drawing.Point(13, 399);
|
||||
betaOptInCbox.Name = "betaOptInCbox";
|
||||
betaOptInCbox.Size = new System.Drawing.Size(107, 19);
|
||||
betaOptInCbox.TabIndex = 6;
|
||||
betaOptInCbox.Text = "[Opt in to Beta]";
|
||||
betaOptInCbox.UseVisualStyleBackColor = true;
|
||||
groupBox1.Controls.Add(applyDisplaySettingsBtn);
|
||||
groupBox1.Controls.Add(gridScaleFactorLbl);
|
||||
groupBox1.Controls.Add(gridScaleFactorTbar);
|
||||
groupBox1.Controls.Add(gridFontScaleFactorLbl);
|
||||
groupBox1.Controls.Add(gridFontScaleFactorTbar);
|
||||
groupBox1.Location = new System.Drawing.Point(6, 261);
|
||||
groupBox1.Name = "groupBox1";
|
||||
groupBox1.Size = new System.Drawing.Size(844, 83);
|
||||
groupBox1.TabIndex = 9;
|
||||
groupBox1.TabStop = false;
|
||||
groupBox1.Text = "Display Settings";
|
||||
//
|
||||
// applyDisplaySettingsBtn
|
||||
//
|
||||
applyDisplaySettingsBtn.Location = new System.Drawing.Point(698, 34);
|
||||
applyDisplaySettingsBtn.Name = "applyDisplaySettingsBtn";
|
||||
applyDisplaySettingsBtn.Size = new System.Drawing.Size(140, 23);
|
||||
applyDisplaySettingsBtn.TabIndex = 9;
|
||||
applyDisplaySettingsBtn.Text = "Apply Display Settings";
|
||||
applyDisplaySettingsBtn.UseVisualStyleBackColor = true;
|
||||
applyDisplaySettingsBtn.Click += applyDisplaySettingsBtn_Click;
|
||||
//
|
||||
// gridScaleFactorLbl
|
||||
//
|
||||
gridScaleFactorLbl.AutoSize = true;
|
||||
gridScaleFactorLbl.Location = new System.Drawing.Point(6, 36);
|
||||
gridScaleFactorLbl.Name = "gridScaleFactorLbl";
|
||||
gridScaleFactorLbl.Size = new System.Drawing.Size(124, 15);
|
||||
gridScaleFactorLbl.TabIndex = 8;
|
||||
gridScaleFactorLbl.Text = "[GridScaleFactor desc]";
|
||||
//
|
||||
// gridScaleFactorTbar
|
||||
//
|
||||
gridScaleFactorTbar.AutoSize = false;
|
||||
gridScaleFactorTbar.LargeChange = 25;
|
||||
gridScaleFactorTbar.Location = new System.Drawing.Point(136, 36);
|
||||
gridScaleFactorTbar.Maximum = 100;
|
||||
gridScaleFactorTbar.Minimum = -100;
|
||||
gridScaleFactorTbar.Name = "gridScaleFactorTbar";
|
||||
gridScaleFactorTbar.Size = new System.Drawing.Size(160, 20);
|
||||
gridScaleFactorTbar.TabIndex = 7;
|
||||
gridScaleFactorTbar.TickFrequency = 25;
|
||||
//
|
||||
// gridFontScaleFactorLbl
|
||||
//
|
||||
gridFontScaleFactorLbl.AutoSize = true;
|
||||
gridFontScaleFactorLbl.Location = new System.Drawing.Point(320, 36);
|
||||
gridFontScaleFactorLbl.Name = "gridFontScaleFactorLbl";
|
||||
gridFontScaleFactorLbl.Size = new System.Drawing.Size(124, 15);
|
||||
gridFontScaleFactorLbl.TabIndex = 8;
|
||||
gridFontScaleFactorLbl.Text = "[GridScaleFactor desc]";
|
||||
//
|
||||
// gridFontScaleFactorTbar
|
||||
//
|
||||
gridFontScaleFactorTbar.AutoSize = false;
|
||||
gridFontScaleFactorTbar.LargeChange = 25;
|
||||
gridFontScaleFactorTbar.Location = new System.Drawing.Point(450, 36);
|
||||
gridFontScaleFactorTbar.Maximum = 100;
|
||||
gridFontScaleFactorTbar.Minimum = -100;
|
||||
gridFontScaleFactorTbar.Name = "gridFontScaleFactorTbar";
|
||||
gridFontScaleFactorTbar.Size = new System.Drawing.Size(160, 20);
|
||||
gridFontScaleFactorTbar.TabIndex = 7;
|
||||
gridFontScaleFactorTbar.TickFrequency = 25;
|
||||
//
|
||||
// booksGb
|
||||
//
|
||||
@@ -423,7 +491,7 @@
|
||||
booksGb.Controls.Add(booksLocationDescLbl);
|
||||
booksGb.Location = new System.Drawing.Point(6, 6);
|
||||
booksGb.Name = "booksGb";
|
||||
booksGb.Size = new System.Drawing.Size(842, 249);
|
||||
booksGb.Size = new System.Drawing.Size(844, 249);
|
||||
booksGb.TabIndex = 0;
|
||||
booksGb.TabStop = false;
|
||||
booksGb.Text = "Books location";
|
||||
@@ -432,7 +500,7 @@
|
||||
//
|
||||
lastWriteTimeCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
lastWriteTimeCb.FormattingEnabled = true;
|
||||
lastWriteTimeCb.Location = new System.Drawing.Point(188, 214);
|
||||
lastWriteTimeCb.Location = new System.Drawing.Point(211, 214);
|
||||
lastWriteTimeCb.Name = "lastWriteTimeCb";
|
||||
lastWriteTimeCb.Size = new System.Drawing.Size(272, 23);
|
||||
lastWriteTimeCb.TabIndex = 5;
|
||||
@@ -441,7 +509,7 @@
|
||||
//
|
||||
creationTimeCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
creationTimeCb.FormattingEnabled = true;
|
||||
creationTimeCb.Location = new System.Drawing.Point(188, 185);
|
||||
creationTimeCb.Location = new System.Drawing.Point(211, 185);
|
||||
creationTimeCb.Name = "creationTimeCb";
|
||||
creationTimeCb.Size = new System.Drawing.Size(272, 23);
|
||||
creationTimeCb.TabIndex = 5;
|
||||
@@ -496,7 +564,7 @@
|
||||
tab2ImportLibrary.Location = new System.Drawing.Point(4, 24);
|
||||
tab2ImportLibrary.Name = "tab2ImportLibrary";
|
||||
tab2ImportLibrary.Padding = new System.Windows.Forms.Padding(3);
|
||||
tab2ImportLibrary.Size = new System.Drawing.Size(854, 445);
|
||||
tab2ImportLibrary.Size = new System.Drawing.Size(856, 453);
|
||||
tab2ImportLibrary.TabIndex = 1;
|
||||
tab2ImportLibrary.Text = "Import library";
|
||||
tab2ImportLibrary.UseVisualStyleBackColor = true;
|
||||
@@ -533,6 +601,7 @@
|
||||
//
|
||||
// tab3DownloadDecrypt
|
||||
//
|
||||
tab3DownloadDecrypt.Controls.Add(saveMetadataToFileCbox);
|
||||
tab3DownloadDecrypt.Controls.Add(useCoverAsFolderIconCb);
|
||||
tab3DownloadDecrypt.Controls.Add(inProgressFilesGb);
|
||||
tab3DownloadDecrypt.Controls.Add(customFileNamingGb);
|
||||
@@ -540,11 +609,21 @@
|
||||
tab3DownloadDecrypt.Location = new System.Drawing.Point(4, 24);
|
||||
tab3DownloadDecrypt.Name = "tab3DownloadDecrypt";
|
||||
tab3DownloadDecrypt.Padding = new System.Windows.Forms.Padding(3);
|
||||
tab3DownloadDecrypt.Size = new System.Drawing.Size(854, 445);
|
||||
tab3DownloadDecrypt.Size = new System.Drawing.Size(856, 453);
|
||||
tab3DownloadDecrypt.TabIndex = 2;
|
||||
tab3DownloadDecrypt.Text = "Download/Decrypt";
|
||||
tab3DownloadDecrypt.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// saveMetadataToFileCbox
|
||||
//
|
||||
saveMetadataToFileCbox.AutoSize = true;
|
||||
saveMetadataToFileCbox.Location = new System.Drawing.Point(482, 415);
|
||||
saveMetadataToFileCbox.Name = "saveMetadataToFileCbox";
|
||||
saveMetadataToFileCbox.Size = new System.Drawing.Size(165, 19);
|
||||
saveMetadataToFileCbox.TabIndex = 22;
|
||||
saveMetadataToFileCbox.Text = "[SaveMetadataToFile desc]";
|
||||
saveMetadataToFileCbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// useCoverAsFolderIconCb
|
||||
//
|
||||
useCoverAsFolderIconCb.AutoSize = true;
|
||||
@@ -562,7 +641,7 @@
|
||||
inProgressFilesGb.Controls.Add(inProgressSelectControl);
|
||||
inProgressFilesGb.Location = new System.Drawing.Point(6, 281);
|
||||
inProgressFilesGb.Name = "inProgressFilesGb";
|
||||
inProgressFilesGb.Size = new System.Drawing.Size(841, 128);
|
||||
inProgressFilesGb.Size = new System.Drawing.Size(842, 128);
|
||||
inProgressFilesGb.TabIndex = 21;
|
||||
inProgressFilesGb.TabStop = false;
|
||||
inProgressFilesGb.Text = "In progress files";
|
||||
@@ -582,7 +661,7 @@
|
||||
customFileNamingGb.Controls.Add(folderTemplateLbl);
|
||||
customFileNamingGb.Location = new System.Drawing.Point(7, 88);
|
||||
customFileNamingGb.Name = "customFileNamingGb";
|
||||
customFileNamingGb.Size = new System.Drawing.Size(841, 187);
|
||||
customFileNamingGb.Size = new System.Drawing.Size(842, 187);
|
||||
customFileNamingGb.TabIndex = 20;
|
||||
customFileNamingGb.TabStop = false;
|
||||
customFileNamingGb.Text = "Custom file naming";
|
||||
@@ -601,7 +680,7 @@
|
||||
// chapterFileTemplateBtn
|
||||
//
|
||||
chapterFileTemplateBtn.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||
chapterFileTemplateBtn.Location = new System.Drawing.Point(761, 124);
|
||||
chapterFileTemplateBtn.Location = new System.Drawing.Point(762, 124);
|
||||
chapterFileTemplateBtn.Name = "chapterFileTemplateBtn";
|
||||
chapterFileTemplateBtn.Size = new System.Drawing.Size(75, 23);
|
||||
chapterFileTemplateBtn.TabIndex = 8;
|
||||
@@ -615,7 +694,7 @@
|
||||
chapterFileTemplateTb.Location = new System.Drawing.Point(6, 125);
|
||||
chapterFileTemplateTb.Name = "chapterFileTemplateTb";
|
||||
chapterFileTemplateTb.ReadOnly = true;
|
||||
chapterFileTemplateTb.Size = new System.Drawing.Size(749, 23);
|
||||
chapterFileTemplateTb.Size = new System.Drawing.Size(750, 23);
|
||||
chapterFileTemplateTb.TabIndex = 7;
|
||||
//
|
||||
// chapterFileTemplateLbl
|
||||
@@ -630,7 +709,7 @@
|
||||
// fileTemplateBtn
|
||||
//
|
||||
fileTemplateBtn.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||
fileTemplateBtn.Location = new System.Drawing.Point(761, 80);
|
||||
fileTemplateBtn.Location = new System.Drawing.Point(762, 80);
|
||||
fileTemplateBtn.Name = "fileTemplateBtn";
|
||||
fileTemplateBtn.Size = new System.Drawing.Size(75, 23);
|
||||
fileTemplateBtn.TabIndex = 5;
|
||||
@@ -644,7 +723,7 @@
|
||||
fileTemplateTb.Location = new System.Drawing.Point(6, 81);
|
||||
fileTemplateTb.Name = "fileTemplateTb";
|
||||
fileTemplateTb.ReadOnly = true;
|
||||
fileTemplateTb.Size = new System.Drawing.Size(749, 23);
|
||||
fileTemplateTb.Size = new System.Drawing.Size(750, 23);
|
||||
fileTemplateTb.TabIndex = 4;
|
||||
//
|
||||
// fileTemplateLbl
|
||||
@@ -659,7 +738,7 @@
|
||||
// folderTemplateBtn
|
||||
//
|
||||
folderTemplateBtn.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||
folderTemplateBtn.Location = new System.Drawing.Point(760, 36);
|
||||
folderTemplateBtn.Location = new System.Drawing.Point(762, 36);
|
||||
folderTemplateBtn.Name = "folderTemplateBtn";
|
||||
folderTemplateBtn.Size = new System.Drawing.Size(75, 23);
|
||||
folderTemplateBtn.TabIndex = 2;
|
||||
@@ -673,7 +752,7 @@
|
||||
folderTemplateTb.Location = new System.Drawing.Point(5, 37);
|
||||
folderTemplateTb.Name = "folderTemplateTb";
|
||||
folderTemplateTb.ReadOnly = true;
|
||||
folderTemplateTb.Size = new System.Drawing.Size(749, 23);
|
||||
folderTemplateTb.Size = new System.Drawing.Size(750, 23);
|
||||
folderTemplateTb.TabIndex = 1;
|
||||
//
|
||||
// folderTemplateLbl
|
||||
@@ -687,6 +766,9 @@
|
||||
//
|
||||
// tab4AudioFileOptions
|
||||
//
|
||||
tab4AudioFileOptions.Controls.Add(fileDownloadQualityCb);
|
||||
tab4AudioFileOptions.Controls.Add(fileDownloadQualityLbl);
|
||||
tab4AudioFileOptions.Controls.Add(combineNestedChapterTitlesCbox);
|
||||
tab4AudioFileOptions.Controls.Add(clipsBookmarksFormatCb);
|
||||
tab4AudioFileOptions.Controls.Add(downloadClipsBookmarksCbox);
|
||||
tab4AudioFileOptions.Controls.Add(audiobookFixupsGb);
|
||||
@@ -700,16 +782,46 @@
|
||||
tab4AudioFileOptions.Location = new System.Drawing.Point(4, 24);
|
||||
tab4AudioFileOptions.Name = "tab4AudioFileOptions";
|
||||
tab4AudioFileOptions.Padding = new System.Windows.Forms.Padding(3);
|
||||
tab4AudioFileOptions.Size = new System.Drawing.Size(854, 445);
|
||||
tab4AudioFileOptions.Size = new System.Drawing.Size(856, 453);
|
||||
tab4AudioFileOptions.TabIndex = 3;
|
||||
tab4AudioFileOptions.Text = "Audio File Options";
|
||||
tab4AudioFileOptions.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// fileDownloadQualityCb
|
||||
//
|
||||
fileDownloadQualityCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
fileDownloadQualityCb.FormattingEnabled = true;
|
||||
fileDownloadQualityCb.Location = new System.Drawing.Point(264, 8);
|
||||
fileDownloadQualityCb.Margin = new System.Windows.Forms.Padding(3, 3, 5, 3);
|
||||
fileDownloadQualityCb.Name = "fileDownloadQualityCb";
|
||||
fileDownloadQualityCb.Size = new System.Drawing.Size(88, 23);
|
||||
fileDownloadQualityCb.TabIndex = 23;
|
||||
//
|
||||
// fileDownloadQualityLbl
|
||||
//
|
||||
fileDownloadQualityLbl.AutoSize = true;
|
||||
fileDownloadQualityLbl.Location = new System.Drawing.Point(19, 9);
|
||||
fileDownloadQualityLbl.Margin = new System.Windows.Forms.Padding(0, 0, 2, 0);
|
||||
fileDownloadQualityLbl.Name = "fileDownloadQualityLbl";
|
||||
fileDownloadQualityLbl.Size = new System.Drawing.Size(152, 15);
|
||||
fileDownloadQualityLbl.TabIndex = 22;
|
||||
fileDownloadQualityLbl.Text = "[FileDownloadQuality desc]";
|
||||
//
|
||||
// combineNestedChapterTitlesCbox
|
||||
//
|
||||
combineNestedChapterTitlesCbox.AutoSize = true;
|
||||
combineNestedChapterTitlesCbox.Location = new System.Drawing.Point(19, 157);
|
||||
combineNestedChapterTitlesCbox.Name = "combineNestedChapterTitlesCbox";
|
||||
combineNestedChapterTitlesCbox.Size = new System.Drawing.Size(216, 19);
|
||||
combineNestedChapterTitlesCbox.TabIndex = 13;
|
||||
combineNestedChapterTitlesCbox.Text = "[CombineNestedChapterTitles desc]";
|
||||
combineNestedChapterTitlesCbox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// clipsBookmarksFormatCb
|
||||
//
|
||||
clipsBookmarksFormatCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
clipsBookmarksFormatCb.FormattingEnabled = true;
|
||||
clipsBookmarksFormatCb.Location = new System.Drawing.Point(269, 64);
|
||||
clipsBookmarksFormatCb.Location = new System.Drawing.Point(285, 81);
|
||||
clipsBookmarksFormatCb.Name = "clipsBookmarksFormatCb";
|
||||
clipsBookmarksFormatCb.Size = new System.Drawing.Size(67, 23);
|
||||
clipsBookmarksFormatCb.TabIndex = 21;
|
||||
@@ -717,7 +829,7 @@
|
||||
// downloadClipsBookmarksCbox
|
||||
//
|
||||
downloadClipsBookmarksCbox.AutoSize = true;
|
||||
downloadClipsBookmarksCbox.Location = new System.Drawing.Point(19, 68);
|
||||
downloadClipsBookmarksCbox.Location = new System.Drawing.Point(19, 82);
|
||||
downloadClipsBookmarksCbox.Name = "downloadClipsBookmarksCbox";
|
||||
downloadClipsBookmarksCbox.Size = new System.Drawing.Size(248, 19);
|
||||
downloadClipsBookmarksCbox.TabIndex = 20;
|
||||
@@ -733,9 +845,9 @@
|
||||
audiobookFixupsGb.Controls.Add(convertLosslessRb);
|
||||
audiobookFixupsGb.Controls.Add(convertLossyRb);
|
||||
audiobookFixupsGb.Controls.Add(stripAudibleBrandingCbox);
|
||||
audiobookFixupsGb.Location = new System.Drawing.Point(6, 169);
|
||||
audiobookFixupsGb.Location = new System.Drawing.Point(6, 200);
|
||||
audiobookFixupsGb.Name = "audiobookFixupsGb";
|
||||
audiobookFixupsGb.Size = new System.Drawing.Size(403, 185);
|
||||
audiobookFixupsGb.Size = new System.Drawing.Size(403, 182);
|
||||
audiobookFixupsGb.TabIndex = 19;
|
||||
audiobookFixupsGb.TabStop = false;
|
||||
audiobookFixupsGb.Text = "Audiobook Fix-ups";
|
||||
@@ -743,7 +855,7 @@
|
||||
// moveMoovAtomCbox
|
||||
//
|
||||
moveMoovAtomCbox.AutoSize = true;
|
||||
moveMoovAtomCbox.Location = new System.Drawing.Point(23, 133);
|
||||
moveMoovAtomCbox.Location = new System.Drawing.Point(23, 134);
|
||||
moveMoovAtomCbox.Name = "moveMoovAtomCbox";
|
||||
moveMoovAtomCbox.Size = new System.Drawing.Size(188, 19);
|
||||
moveMoovAtomCbox.TabIndex = 14;
|
||||
@@ -764,9 +876,9 @@
|
||||
//
|
||||
chapterTitleTemplateGb.Controls.Add(chapterTitleTemplateBtn);
|
||||
chapterTitleTemplateGb.Controls.Add(chapterTitleTemplateTb);
|
||||
chapterTitleTemplateGb.Location = new System.Drawing.Point(6, 360);
|
||||
chapterTitleTemplateGb.Location = new System.Drawing.Point(3, 388);
|
||||
chapterTitleTemplateGb.Name = "chapterTitleTemplateGb";
|
||||
chapterTitleTemplateGb.Size = new System.Drawing.Size(842, 54);
|
||||
chapterTitleTemplateGb.Size = new System.Drawing.Size(847, 54);
|
||||
chapterTitleTemplateGb.TabIndex = 18;
|
||||
chapterTitleTemplateGb.TabStop = false;
|
||||
chapterTitleTemplateGb.Text = "[chapter title template desc]";
|
||||
@@ -774,7 +886,7 @@
|
||||
// chapterTitleTemplateBtn
|
||||
//
|
||||
chapterTitleTemplateBtn.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||
chapterTitleTemplateBtn.Location = new System.Drawing.Point(764, 22);
|
||||
chapterTitleTemplateBtn.Location = new System.Drawing.Point(769, 22);
|
||||
chapterTitleTemplateBtn.Name = "chapterTitleTemplateBtn";
|
||||
chapterTitleTemplateBtn.Size = new System.Drawing.Size(75, 23);
|
||||
chapterTitleTemplateBtn.TabIndex = 17;
|
||||
@@ -788,7 +900,7 @@
|
||||
chapterTitleTemplateTb.Location = new System.Drawing.Point(6, 22);
|
||||
chapterTitleTemplateTb.Name = "chapterTitleTemplateTb";
|
||||
chapterTitleTemplateTb.ReadOnly = true;
|
||||
chapterTitleTemplateTb.Size = new System.Drawing.Size(752, 23);
|
||||
chapterTitleTemplateTb.Size = new System.Drawing.Size(757, 23);
|
||||
chapterTitleTemplateTb.TabIndex = 16;
|
||||
//
|
||||
// lameOptionsGb
|
||||
@@ -804,7 +916,7 @@
|
||||
lameOptionsGb.Controls.Add(groupBox2);
|
||||
lameOptionsGb.Location = new System.Drawing.Point(415, 6);
|
||||
lameOptionsGb.Name = "lameOptionsGb";
|
||||
lameOptionsGb.Size = new System.Drawing.Size(433, 348);
|
||||
lameOptionsGb.Size = new System.Drawing.Size(433, 376);
|
||||
lameOptionsGb.TabIndex = 14;
|
||||
lameOptionsGb.TabStop = false;
|
||||
lameOptionsGb.Text = "Mp3 Encoding Options";
|
||||
@@ -812,7 +924,7 @@
|
||||
// label20
|
||||
//
|
||||
label20.AutoSize = true;
|
||||
label20.Location = new System.Drawing.Point(12, 78);
|
||||
label20.Location = new System.Drawing.Point(12, 89);
|
||||
label20.Name = "label20";
|
||||
label20.Size = new System.Drawing.Size(101, 15);
|
||||
label20.TabIndex = 3;
|
||||
@@ -821,7 +933,7 @@
|
||||
// label21
|
||||
//
|
||||
label21.AutoSize = true;
|
||||
label21.Location = new System.Drawing.Point(239, 78);
|
||||
label21.Location = new System.Drawing.Point(239, 89);
|
||||
label21.Name = "label21";
|
||||
label21.Size = new System.Drawing.Size(94, 15);
|
||||
label21.TabIndex = 3;
|
||||
@@ -831,7 +943,7 @@
|
||||
//
|
||||
encoderQualityCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
encoderQualityCb.FormattingEnabled = true;
|
||||
encoderQualityCb.Location = new System.Drawing.Point(337, 75);
|
||||
encoderQualityCb.Location = new System.Drawing.Point(337, 86);
|
||||
encoderQualityCb.Name = "encoderQualityCb";
|
||||
encoderQualityCb.Size = new System.Drawing.Size(90, 23);
|
||||
encoderQualityCb.TabIndex = 2;
|
||||
@@ -840,7 +952,7 @@
|
||||
//
|
||||
maxSampleRateCb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
maxSampleRateCb.FormattingEnabled = true;
|
||||
maxSampleRateCb.Location = new System.Drawing.Point(119, 75);
|
||||
maxSampleRateCb.Location = new System.Drawing.Point(119, 86);
|
||||
maxSampleRateCb.Name = "maxSampleRateCb";
|
||||
maxSampleRateCb.Size = new System.Drawing.Size(101, 23);
|
||||
maxSampleRateCb.TabIndex = 2;
|
||||
@@ -865,9 +977,9 @@
|
||||
lameBitrateGb.Controls.Add(label11);
|
||||
lameBitrateGb.Controls.Add(label3);
|
||||
lameBitrateGb.Controls.Add(lameBitrateTb);
|
||||
lameBitrateGb.Location = new System.Drawing.Point(6, 104);
|
||||
lameBitrateGb.Location = new System.Drawing.Point(6, 116);
|
||||
lameBitrateGb.Name = "lameBitrateGb";
|
||||
lameBitrateGb.Size = new System.Drawing.Size(421, 102);
|
||||
lameBitrateGb.Size = new System.Drawing.Size(421, 113);
|
||||
lameBitrateGb.TabIndex = 0;
|
||||
lameBitrateGb.TabStop = false;
|
||||
lameBitrateGb.Text = "Bitrate";
|
||||
@@ -972,7 +1084,7 @@
|
||||
label1.AutoSize = true;
|
||||
label1.Enabled = false;
|
||||
label1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point);
|
||||
label1.Location = new System.Drawing.Point(6, 325);
|
||||
label1.Location = new System.Drawing.Point(6, 355);
|
||||
label1.Name = "label1";
|
||||
label1.Size = new System.Drawing.Size(172, 15);
|
||||
label1.TabIndex = 1;
|
||||
@@ -993,9 +1105,9 @@
|
||||
lameQualityGb.Controls.Add(label14);
|
||||
lameQualityGb.Controls.Add(label2);
|
||||
lameQualityGb.Controls.Add(lameVBRQualityTb);
|
||||
lameQualityGb.Location = new System.Drawing.Point(6, 212);
|
||||
lameQualityGb.Location = new System.Drawing.Point(6, 235);
|
||||
lameQualityGb.Name = "lameQualityGb";
|
||||
lameQualityGb.Size = new System.Drawing.Size(421, 103);
|
||||
lameQualityGb.Size = new System.Drawing.Size(421, 109);
|
||||
lameQualityGb.TabIndex = 0;
|
||||
lameQualityGb.TabStop = false;
|
||||
lameQualityGb.Text = "Quality";
|
||||
@@ -1125,7 +1237,7 @@
|
||||
groupBox2.Controls.Add(lameTargetBitrateRb);
|
||||
groupBox2.Location = new System.Drawing.Point(6, 22);
|
||||
groupBox2.Name = "groupBox2";
|
||||
groupBox2.Size = new System.Drawing.Size(214, 47);
|
||||
groupBox2.Size = new System.Drawing.Size(214, 58);
|
||||
groupBox2.TabIndex = 0;
|
||||
groupBox2.TabStop = false;
|
||||
groupBox2.Text = "Target";
|
||||
@@ -1157,7 +1269,7 @@
|
||||
// mergeOpeningEndCreditsCbox
|
||||
//
|
||||
mergeOpeningEndCreditsCbox.AutoSize = true;
|
||||
mergeOpeningEndCreditsCbox.Location = new System.Drawing.Point(19, 118);
|
||||
mergeOpeningEndCreditsCbox.Location = new System.Drawing.Point(19, 133);
|
||||
mergeOpeningEndCreditsCbox.Name = "mergeOpeningEndCreditsCbox";
|
||||
mergeOpeningEndCreditsCbox.Size = new System.Drawing.Size(198, 19);
|
||||
mergeOpeningEndCreditsCbox.TabIndex = 13;
|
||||
@@ -1167,7 +1279,7 @@
|
||||
// retainAaxFileCbox
|
||||
//
|
||||
retainAaxFileCbox.AutoSize = true;
|
||||
retainAaxFileCbox.Location = new System.Drawing.Point(19, 93);
|
||||
retainAaxFileCbox.Location = new System.Drawing.Point(19, 107);
|
||||
retainAaxFileCbox.Name = "retainAaxFileCbox";
|
||||
retainAaxFileCbox.Size = new System.Drawing.Size(132, 19);
|
||||
retainAaxFileCbox.TabIndex = 10;
|
||||
@@ -1180,7 +1292,7 @@
|
||||
downloadCoverArtCbox.AutoSize = true;
|
||||
downloadCoverArtCbox.Checked = true;
|
||||
downloadCoverArtCbox.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
downloadCoverArtCbox.Location = new System.Drawing.Point(19, 43);
|
||||
downloadCoverArtCbox.Location = new System.Drawing.Point(19, 58);
|
||||
downloadCoverArtCbox.Name = "downloadCoverArtCbox";
|
||||
downloadCoverArtCbox.Size = new System.Drawing.Size(162, 19);
|
||||
downloadCoverArtCbox.TabIndex = 10;
|
||||
@@ -1193,7 +1305,7 @@
|
||||
createCueSheetCbox.AutoSize = true;
|
||||
createCueSheetCbox.Checked = true;
|
||||
createCueSheetCbox.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
createCueSheetCbox.Location = new System.Drawing.Point(19, 18);
|
||||
createCueSheetCbox.Location = new System.Drawing.Point(19, 32);
|
||||
createCueSheetCbox.Name = "createCueSheetCbox";
|
||||
createCueSheetCbox.Size = new System.Drawing.Size(145, 19);
|
||||
createCueSheetCbox.TabIndex = 10;
|
||||
@@ -1204,10 +1316,10 @@
|
||||
// SettingsDialog
|
||||
//
|
||||
AcceptButton = saveBtn;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
CancelButton = cancelBtn;
|
||||
ClientSize = new System.Drawing.Size(886, 534);
|
||||
ClientSize = new System.Drawing.Size(888, 538);
|
||||
Controls.Add(tabControl);
|
||||
Controls.Add(cancelBtn);
|
||||
Controls.Add(saveBtn);
|
||||
@@ -1224,6 +1336,10 @@
|
||||
tabControl.ResumeLayout(false);
|
||||
tab1ImportantSettings.ResumeLayout(false);
|
||||
tab1ImportantSettings.PerformLayout();
|
||||
groupBox1.ResumeLayout(false);
|
||||
groupBox1.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)gridScaleFactorTbar).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)gridFontScaleFactorTbar).EndInit();
|
||||
booksGb.ResumeLayout(false);
|
||||
booksGb.PerformLayout();
|
||||
tab2ImportLibrary.ResumeLayout(false);
|
||||
@@ -1336,7 +1452,6 @@
|
||||
private System.Windows.Forms.Button editCharreplacementBtn;
|
||||
private System.Windows.Forms.CheckBox mergeOpeningEndCreditsCbox;
|
||||
private System.Windows.Forms.GroupBox audiobookFixupsGb;
|
||||
private System.Windows.Forms.CheckBox betaOptInCbox;
|
||||
private System.Windows.Forms.CheckBox useCoverAsFolderIconCb;
|
||||
private System.Windows.Forms.ComboBox clipsBookmarksFormatCb;
|
||||
private System.Windows.Forms.CheckBox downloadClipsBookmarksCbox;
|
||||
@@ -1350,5 +1465,15 @@
|
||||
private System.Windows.Forms.ComboBox lastWriteTimeCb;
|
||||
private System.Windows.Forms.ComboBox creationTimeCb;
|
||||
private System.Windows.Forms.Label lastWriteTimeLbl;
|
||||
private System.Windows.Forms.ComboBox fileDownloadQualityCb;
|
||||
private System.Windows.Forms.Label fileDownloadQualityLbl;
|
||||
private System.Windows.Forms.CheckBox combineNestedChapterTitlesCbox;
|
||||
private System.Windows.Forms.CheckBox saveMetadataToFileCbox;
|
||||
private System.Windows.Forms.TrackBar gridScaleFactorTbar;
|
||||
private System.Windows.Forms.TrackBar gridFontScaleFactorTbar;
|
||||
private System.Windows.Forms.Label gridScaleFactorLbl;
|
||||
private System.Windows.Forms.Label gridFontScaleFactorLbl;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.Button applyDisplaySettingsBtn;
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ namespace LibationWinForms.Dialogs
|
||||
badBookRetryRb.Text = Configuration.BadBookAction.Retry.GetDescription();
|
||||
badBookIgnoreRb.Text = Configuration.BadBookAction.Ignore.GetDescription();
|
||||
useCoverAsFolderIconCb.Text = desc(nameof(config.UseCoverAsFolderIcon));
|
||||
saveMetadataToFileCbox.Text = desc(nameof(config.SaveMetadataToFile));
|
||||
|
||||
inProgressSelectControl.SetDirectoryItems(new()
|
||||
{
|
||||
@@ -60,6 +61,7 @@ namespace LibationWinForms.Dialogs
|
||||
fileTemplateTb.Text = config.FileTemplate;
|
||||
chapterFileTemplateTb.Text = config.ChapterFileTemplate;
|
||||
useCoverAsFolderIconCb.Checked = config.UseCoverAsFolderIcon;
|
||||
saveMetadataToFileCbox.Checked = config.SaveMetadataToFile;
|
||||
}
|
||||
|
||||
private void Save_DownloadDecrypt(Configuration config)
|
||||
@@ -77,6 +79,7 @@ namespace LibationWinForms.Dialogs
|
||||
config.FileTemplate = fileTemplateTb.Text;
|
||||
config.ChapterFileTemplate = chapterFileTemplateTb.Text;
|
||||
config.UseCoverAsFolderIcon = useCoverAsFolderIconCb.Checked;
|
||||
config.SaveMetadataToFile = saveMetadataToFileCbox.Checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,15 +14,6 @@ namespace LibationWinForms.Dialogs
|
||||
this.importEpisodesCb.Text = desc(nameof(config.ImportEpisodes));
|
||||
this.downloadEpisodesCb.Text = desc(nameof(config.DownloadEpisodes));
|
||||
this.autoDownloadEpisodesCb.Text = desc(nameof(config.AutoDownloadEpisodes));
|
||||
creationTimeLbl.Text = desc(nameof(config.CreationTime));
|
||||
lastWriteTimeLbl.Text = desc(nameof(config.LastWriteTime));
|
||||
|
||||
var dateTimeSources = Enum.GetValues<Configuration.DateTimeSource>().Select(v => new EnumDiaplay<Configuration.DateTimeSource>(v)).ToArray();
|
||||
creationTimeCb.Items.AddRange(dateTimeSources);
|
||||
lastWriteTimeCb.Items.AddRange(dateTimeSources);
|
||||
|
||||
creationTimeCb.SelectedItem = dateTimeSources.SingleOrDefault(v => v.Value == config.CreationTime) ?? dateTimeSources[0];
|
||||
lastWriteTimeCb.SelectedItem = dateTimeSources.SingleOrDefault(v => v.Value == config.LastWriteTime) ?? dateTimeSources[0];
|
||||
|
||||
autoScanCb.Checked = config.AutoScan;
|
||||
showImportedStatsCb.Checked = config.ShowImportedStats;
|
||||
@@ -32,9 +23,6 @@ namespace LibationWinForms.Dialogs
|
||||
}
|
||||
private void Save_ImportLibrary(Configuration config)
|
||||
{
|
||||
config.CreationTime = ((EnumDiaplay<Configuration.DateTimeSource>)creationTimeCb.SelectedItem).Value;
|
||||
config.LastWriteTime = ((EnumDiaplay<Configuration.DateTimeSource>)lastWriteTimeCb.SelectedItem).Value;
|
||||
|
||||
config.AutoScan = autoScanCb.Checked;
|
||||
config.ShowImportedStats = showImportedStatsCb.Checked;
|
||||
config.ImportEpisodes = importEpisodesCb.Checked;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Dinah.Core;
|
||||
using FileManager;
|
||||
using LibationFileManager;
|
||||
using LibationUiBase;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -22,9 +23,20 @@ namespace LibationWinForms.Dialogs
|
||||
}
|
||||
|
||||
booksLocationDescLbl.Text = desc(nameof(config.Books));
|
||||
betaOptInCbox.Text = desc(nameof(config.BetaOptIn));
|
||||
saveEpisodesToSeriesFolderCbox.Text = desc(nameof(config.SavePodcastsToParentFolder));
|
||||
overwriteExistingCbox.Text = desc(nameof(config.OverwriteExisting));
|
||||
creationTimeLbl.Text = desc(nameof(config.CreationTime));
|
||||
lastWriteTimeLbl.Text = desc(nameof(config.LastWriteTime));
|
||||
gridScaleFactorLbl.Text = desc(nameof(config.GridScaleFactor));
|
||||
gridFontScaleFactorLbl.Text = desc(nameof(config.GridFontScaleFactor));
|
||||
|
||||
var dateTimeSources = Enum.GetValues<Configuration.DateTimeSource>().Select(v => new EnumDiaplay<Configuration.DateTimeSource>(v)).ToArray();
|
||||
creationTimeCb.Items.AddRange(dateTimeSources);
|
||||
lastWriteTimeCb.Items.AddRange(dateTimeSources);
|
||||
|
||||
creationTimeCb.SelectedItem = dateTimeSources.SingleOrDefault(v => v.Value == config.CreationTime) ?? dateTimeSources[0];
|
||||
lastWriteTimeCb.SelectedItem = dateTimeSources.SingleOrDefault(v => v.Value == config.LastWriteTime) ?? dateTimeSources[0];
|
||||
|
||||
|
||||
booksSelectControl.SetSearchTitle("books location");
|
||||
booksSelectControl.SetDirectoryItems(
|
||||
@@ -40,11 +52,8 @@ namespace LibationWinForms.Dialogs
|
||||
|
||||
saveEpisodesToSeriesFolderCbox.Checked = config.SavePodcastsToParentFolder;
|
||||
overwriteExistingCbox.Checked = config.OverwriteExisting;
|
||||
|
||||
betaOptInCbox.Checked = config.BetaOptIn;
|
||||
|
||||
if (!betaOptInCbox.Checked)
|
||||
betaOptInCbox.CheckedChanged += betaOptInCbox_CheckedChanged;
|
||||
gridScaleFactorTbar.Value = scaleFactorToLinearRange(config.GridScaleFactor);
|
||||
gridFontScaleFactorTbar.Value = scaleFactorToLinearRange(config.GridFontScaleFactor);
|
||||
}
|
||||
|
||||
private void Save_Important(Configuration config)
|
||||
@@ -81,34 +90,20 @@ namespace LibationWinForms.Dialogs
|
||||
config.SavePodcastsToParentFolder = saveEpisodesToSeriesFolderCbox.Checked;
|
||||
config.OverwriteExisting = overwriteExistingCbox.Checked;
|
||||
|
||||
config.BetaOptIn = betaOptInCbox.Checked;
|
||||
|
||||
config.CreationTime = ((EnumDiaplay<Configuration.DateTimeSource>)creationTimeCb.SelectedItem).Value;
|
||||
config.LastWriteTime = ((EnumDiaplay<Configuration.DateTimeSource>)lastWriteTimeCb.SelectedItem).Value;
|
||||
}
|
||||
|
||||
private static int scaleFactorToLinearRange(float scaleFactor)
|
||||
=> (int)float.Round(100 * MathF.Log2(scaleFactor));
|
||||
private static float linearRangeToScaleFactor(int value)
|
||||
=> MathF.Pow(2, value / 100f);
|
||||
|
||||
private void betaOptInCbox_CheckedChanged(object sender, EventArgs e)
|
||||
private void applyDisplaySettingsBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!betaOptInCbox.Checked)
|
||||
return;
|
||||
|
||||
var result = MessageBox.Show(this, @"
|
||||
|
||||
|
||||
You've chosen to opt-in to Libation's beta releases. Thank you! We need all the testers we can get.
|
||||
|
||||
These features are works in progress and potentially very buggy. Libation may crash unexpectedly, and your library database may even be corruted. We suggest you back up your LibationContext.db file before proceding.
|
||||
|
||||
If bad/weird things happen, please report them at getlibation.com.
|
||||
|
||||
".Trim(), "A word of warning...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
betaOptInCbox.CheckedChanged -= betaOptInCbox_CheckedChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
betaOptInCbox.Checked = false;
|
||||
}
|
||||
config.GridFontScaleFactor = linearRangeToScaleFactor(gridFontScaleFactorTbar.Value);
|
||||
config.GridScaleFactor = linearRangeToScaleFactor(gridScaleFactorTbar.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,12 @@ namespace LibationWinForms.Dialogs
|
||||
{
|
||||
private Configuration config { get; } = Configuration.Instance;
|
||||
private Func<string, string> desc { get; } = Configuration.GetDescription;
|
||||
private readonly ToolTip toolTip = new ToolTip
|
||||
{
|
||||
InitialDelay = 300,
|
||||
AutoPopDelay = 10000,
|
||||
ReshowDelay = 0
|
||||
};
|
||||
|
||||
public SettingsDialog()
|
||||
{
|
||||
|
||||
@@ -71,8 +71,8 @@
|
||||
//
|
||||
// SetupDialog
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
ClientSize = new System.Drawing.Size(493, 308);
|
||||
Controls.Add(returningUserBtn);
|
||||
Controls.Add(newUserBtn);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user